lynxis lazus submitted this change.

View Change

Approvals: lynxis lazus: Looks good to me, approved Jenkins Builder: Verified osmith: Looks good to me, but someone else must approve
ranap: Take into account RNC availability during paging

Avoid transmitting a RANAP paging message to an RNC if we already know
it's not currently available over SCCP.
Take into account that information when deciding/printing whether the
paging could be sent or not.

Take the chance to clean up the iu paging function helpers inherited
from osmo-iuh iu_client.c to better fit the data domain in osmo-sgsn
(iu_rnc).

Change-Id: I24e5446bcf4c958028577230b231960acea9e5b9
---
M include/osmocom/sgsn/gprs_ranap.h
M include/osmocom/sgsn/iu_rnc.h
M include/osmocom/sgsn/iu_rnc_fsm.h
M src/sgsn/gprs_ranap.c
M src/sgsn/iu_client.c
M src/sgsn/iu_rnc.c
M src/sgsn/iu_rnc_fsm.c
7 files changed, 144 insertions(+), 115 deletions(-)

diff --git a/include/osmocom/sgsn/gprs_ranap.h b/include/osmocom/sgsn/gprs_ranap.h
index 62914ba..b959b57 100644
--- a/include/osmocom/sgsn/gprs_ranap.h
+++ b/include/osmocom/sgsn/gprs_ranap.h
@@ -30,9 +30,6 @@
int sgsn_ranap_iu_tx_sec_mode_cmd(struct ranap_ue_conn_ctx *uectx, struct osmo_auth_vector *vec,
int send_ck, int new_key);
int sgsn_ranap_iu_tx_common_id(struct ranap_ue_conn_ctx *ue_ctx, const char *imsi);
-int sgsn_ranap_iu_tx_paging_cmd(struct osmo_sccp_addr *called_addr,
- const char *imsi, const uint32_t *tmsi,
- bool is_ps, uint32_t paging_cause);

int sgsn_ranap_iu_tx_release(struct ranap_ue_conn_ctx *ctx, const struct RANAP_Cause *cause);
/* Transmit a Iu Release Command and submit event RANAP_IU_EVENT_IU_RELEASE upon
diff --git a/include/osmocom/sgsn/iu_rnc.h b/include/osmocom/sgsn/iu_rnc.h
index b0e5be3..0382b74 100644
--- a/include/osmocom/sgsn/iu_rnc.h
+++ b/include/osmocom/sgsn/iu_rnc.h
@@ -1,6 +1,7 @@
#pragma once

#include <stdbool.h>
+#include <stdint.h>

#include <osmocom/core/defs.h>
#include <osmocom/core/linuxlist.h>
@@ -43,6 +44,12 @@

void iu_rnc_discard_all_ue_ctx(struct ranap_iu_rnc *rnc);

+int iu_rnc_tx_paging_cmd(struct ranap_iu_rnc *rnc,
+ const char *imsi,
+ const uint32_t *tmsi,
+ bool is_ps,
+ uint32_t paging_cause);
+
#define LOG_RNC_CAT(IU_RNC, subsys, loglevel, fmt, args ...) \
LOGPFSMSL((IU_RNC)->fi, subsys, loglevel, fmt, ## args)

diff --git a/include/osmocom/sgsn/iu_rnc_fsm.h b/include/osmocom/sgsn/iu_rnc_fsm.h
index d9be576..f69d82e 100644
--- a/include/osmocom/sgsn/iu_rnc_fsm.h
+++ b/include/osmocom/sgsn/iu_rnc_fsm.h
@@ -29,6 +29,7 @@
IU_RNC_EV_MSG_UP_CO, /* struct iu_rnc_ev_msg_up_co_ctx* */
IU_RNC_EV_RX_RESET, /* no param */
IU_RNC_EV_RX_RESET_ACK, /* no param */
+ IU_RNC_EV_MSG_DOWN_CL, /* struct msgb* */
IU_RNC_EV_AVAILABLE,
IU_RNC_EV_UNAVAILABLE
};
diff --git a/src/sgsn/gprs_ranap.c b/src/sgsn/gprs_ranap.c
index df9cc9e..1cdb72b 100644
--- a/src/sgsn/gprs_ranap.c
+++ b/src/sgsn/gprs_ranap.c
@@ -287,22 +287,6 @@
return sgsn_scu_iups_tx_data_req(uectx->rnc->scu_iups, uectx->conn_id, msg);
}

-/* Send a paging command down a given SCCP User. tmsi and paging_cause are
- * optional and may be passed NULL and 0, respectively, to disable their use.
- * See enum RANAP_PagingCause.
- *
- * If TMSI is given, the IMSI is not sent over the air interface. Nevertheless,
- * the IMSI is still required for resolution in the HNB-GW and/or(?) RNC. */
-int sgsn_ranap_iu_tx_paging_cmd(struct osmo_sccp_addr *called_addr,
- const char *imsi, const uint32_t *tmsi,
- bool is_ps, uint32_t paging_cause)
-{
- struct msgb *msg;
- msg = ranap_new_msg_paging_cmd(imsi, tmsi, is_ps ? 1 : 0, paging_cause);
- msg->l2h = msg->data;
- return osmo_sccp_tx_unitdata_msg(sgsn->sccp.scu_iups->scu, &sgsn->sccp.scu_iups->local_sccp_addr, called_addr, msg);
-}
-
int sgsn_ranap_iu_tx(struct msgb *msg_nas, uint8_t sapi)
{
struct ranap_ue_conn_ctx *uectx = msg_nas->dst;
diff --git a/src/sgsn/iu_client.c b/src/sgsn/iu_client.c
index cb5d096..164ff71 100644
--- a/src/sgsn/iu_client.c
+++ b/src/sgsn/iu_client.c
@@ -43,12 +43,6 @@
#include <osmocom/sgsn/sccp.h>
#include <osmocom/sgsn/sgsn.h>

-#define LOGPIU(level, fmt, args...) \
- LOGP(DRANAP, level, fmt, ## args)
-
-#define LOGPIUC(level, fmt, args...) \
- LOGPC(DRANAP, level, fmt, ## args)
-
const struct value_string iu_client_event_type_names[] = {
OSMO_VALUE_STRING(RANAP_IU_EVENT_RAB_ASSIGN),
OSMO_VALUE_STRING(RANAP_IU_EVENT_SECURITY_MODE_COMPLETE),
@@ -66,7 +60,7 @@
if (ue_ctx && !ue_ctx->notification)
return 0;

- LOGPIU(LOGL_DEBUG, "Submit Iu event to upper layer: %s\n", iu_client_event_type_str(type));
+ LOGP(DRANAP, LOGL_DEBUG, "Submit Iu event to upper layer: %s\n", iu_client_event_type_str(type));

return sgsn_ranap_iu_event(ue_ctx, type, data);
}
@@ -126,78 +120,74 @@
***********************************************************************/

/* legacy, do a first match with ignoring PLMN */
-static bool iu_rnc_lac_rac_find_legacy(struct ranap_iu_rnc **rnc, struct iu_lac_rac_entry **lre,
- uint16_t lac, uint8_t rac)
-{
- struct ranap_iu_rnc *r;
- struct iu_lac_rac_entry *e;
-
- if (rnc)
- *rnc = NULL;
- if (lre)
- *lre = NULL;
-
- llist_for_each_entry(r, &sgsn->rnc_list, entry) {
- llist_for_each_entry(e, &r->lac_rac_list, entry) {
- if (e->rai.lac.lac == lac && e->rai.rac == rac) {
- if (rnc)
- *rnc = r;
- if (lre)
- *lre = e;
- return true;
- }
- }
- }
- return false;
-}
-
-static int iu_page(const char *imsi, const uint32_t *tmsi_or_ptmsi,
- uint16_t lac, uint8_t rac, bool is_ps)
+static struct ranap_iu_rnc *iu_rnc_lac_rac_find_legacy(uint16_t lac, uint8_t rac)
{
struct ranap_iu_rnc *rnc;
- const char *log_msg;
- int log_level;
- int paged = 0;
+ struct iu_lac_rac_entry *e;

- iu_rnc_lac_rac_find_legacy(&rnc, NULL, lac, rac);
- if (rnc) {
- if (sgsn_ranap_iu_tx_paging_cmd(&rnc->sccp_addr, imsi, tmsi_or_ptmsi, is_ps, 0) == 0) {
- log_msg = "Paging";
- log_level = LOGL_DEBUG;
- paged = 1;
- } else {
- log_msg = "Paging failed";
- log_level = LOGL_ERROR;
+ llist_for_each_entry(rnc, &sgsn->rnc_list, entry) {
+ llist_for_each_entry(e, &rnc->lac_rac_list, entry) {
+ if (e->rai.lac.lac == lac && e->rai.rac == rac)
+ return rnc;
}
- } else {
- log_msg = "Found no RNC to Page";
- log_level = LOGL_ERROR;
}
-
- if (is_ps)
- LOGPIU(log_level, "IuPS: %s on LAC %d RAC %d", log_msg, lac, rac);
- else
- LOGPIU(log_level, "IuCS: %s on LAC %d", log_msg, lac);
- if (rnc)
- LOGPIUC(log_level, " at SCCP-addr %s", osmo_sccp_addr_dump(&rnc->sccp_addr));
- if (tmsi_or_ptmsi)
- LOGPIUC(log_level, ", for %s %08x\n", is_ps ? "PTMSI" : "TMSI", *tmsi_or_ptmsi);
- else
- LOGPIUC(log_level, ", for IMSI %s\n", imsi);
-
- return paged;
+ return NULL;
}

/*! Old paging() doesn't use PLMN and transmit paging command only to the first RNC */
int ranap_iu_page_cs(const char *imsi, const uint32_t *tmsi, uint16_t lac)
{
- return iu_page(imsi, tmsi, lac, 0, false);
+ struct ranap_iu_rnc *rnc;
+ char log_msg[32] = {};
+ int rc;
+
+ if (tmsi)
+ snprintf(log_msg, sizeof(log_msg), "TMSI %08x\n", *tmsi);
+ else
+ snprintf(log_msg, sizeof(log_msg), "IMSI %s\n", imsi);
+
+ rnc = iu_rnc_lac_rac_find_legacy(lac, 0);
+ if (!rnc) {
+ LOGP(DRANAP, LOGL_INFO, "Found no RNC to Page CS on LAC %u for %s",
+ lac, log_msg);
+ return 0;
+ }
+
+ rc = iu_rnc_tx_paging_cmd(rnc, imsi, tmsi, false, 0);
+ if (rc != 0) {
+ LOG_RNC(rnc, LOGL_ERROR, "Failed to tx Paging CS for LAC %u for %s",
+ lac, log_msg);
+ return 0;
+ }
+ return 1;
}

/*! Old paging() doesn't use PLMN and transmit paging command only to the first RNC */
int ranap_iu_page_ps(const char *imsi, const uint32_t *ptmsi, uint16_t lac, uint8_t rac)
{
- return iu_page(imsi, ptmsi, lac, rac, true);
+ struct ranap_iu_rnc *rnc;
+ char log_msg[32] = {};
+ int rc;
+
+ if (ptmsi)
+ snprintf(log_msg, sizeof(log_msg), "P-TMSI %08x\n", *ptmsi);
+ else
+ snprintf(log_msg, sizeof(log_msg), "IMSI %s\n", imsi);
+
+ rnc = iu_rnc_lac_rac_find_legacy(lac, rac);
+ if (!rnc) {
+ LOGP(DRANAP, LOGL_INFO, "Found no RNC to Page PS on LAC %u RAC %u for %s",
+ lac, rac, log_msg);
+ return 0;
+ }
+
+ rc = iu_rnc_tx_paging_cmd(rnc, imsi, ptmsi, true, 0);
+ if (rc != 0) {
+ LOG_RNC(rnc, LOGL_ERROR, "Failed to tx Paging PS for LAC %u RAC %u for %s",
+ lac, rac, log_msg);
+ return 0;
+ }
+ return 1;
}

/*! Transmit a single page request towards all RNCs serving the specific LAI (no page retransmission).
@@ -212,8 +202,13 @@
struct ranap_iu_rnc *rnc;
struct iu_lac_rac_entry *entry;
char log_msg[32] = {};
- int paged = 0;
- int rc = 0;
+ unsigned int paged = 0;
+ int rc;
+
+ if (tmsi)
+ snprintf(log_msg, sizeof(log_msg), "TMSI %08x\n", *tmsi);
+ else
+ snprintf(log_msg, sizeof(log_msg), "IMSI %s\n", imsi);

/* find all RNCs which are serving this LA */
llist_for_each_entry(rnc, &sgsn->rnc_list, entry) {
@@ -221,27 +216,23 @@
if (osmo_lai_cmp(&entry->rai.lac, lai))
continue;

- rc = sgsn_ranap_iu_tx_paging_cmd(&rnc->sccp_addr, imsi, tmsi, false, 0);
- if (rc > 0) {
- LOGPIU(LOGL_ERROR, "IuCS: Failed to tx Paging RNC %s for LAC %s for IMSI %s / TMSI %08x",
- osmo_rnc_id_name(&rnc->rnc_id),
- osmo_lai_name(lai), imsi, tmsi ? *tmsi : GSM_RESERVED_TMSI);
+ rc = iu_rnc_tx_paging_cmd(rnc, imsi, tmsi, false, 0);
+ if (rc != 0) {
+ LOG_RNC(rnc, LOGL_ERROR, "Failed to tx Paging CS for LAI %s for %s",
+ osmo_lai_name(lai), log_msg);
+ } else {
+ paged++;
}
- paged++;
break;
}
}

- if (tmsi)
- snprintf(log_msg, sizeof(log_msg), "for TMSI %08x\n", *tmsi);
- else
- snprintf(log_msg, sizeof(log_msg) - 1, "for IMSI %s\n", imsi);
-
if (paged)
- LOGPIU(LOGL_DEBUG, "IuPS: Paged %d RNCs on LAI %s for %s", paged, osmo_lai_name(lai), log_msg);
+ LOGP(DRANAP, LOGL_DEBUG, "Paged CS %u RNCs on LAI %s for %s",
+ paged, osmo_lai_name(lai), log_msg);
else
- LOGPIU(LOGL_INFO, "IuPS: Found no RNC to Page on LAI %s for %s", osmo_lai_name(lai), log_msg);
-
+ LOGP(DRANAP, LOGL_INFO, "Found no RNC to Page CS on LAI %s for %s",
+ osmo_lai_name(lai), log_msg);

return paged;
}
@@ -249,7 +240,7 @@
/*! Transmit a single page request towards all RNCs serving the specific RAI (no page retransmission).
*
* \param imsi the imsi as human readable string
- * \param ptmsi NULL or pointer to the tmsi
+ * \param ptmsi NULL or pointer to the ptmsi
* \param rai full Location Area Identifier
* \return amount of paged RNCs. 0 when no RNC found.
*/
@@ -258,8 +249,13 @@
struct ranap_iu_rnc *rnc;
struct iu_lac_rac_entry *entry;
char log_msg[32] = {};
- int paged = 0;
- int rc = 0;
+ unsigned int paged = 0;
+ int rc;
+
+ if (ptmsi)
+ snprintf(log_msg, sizeof(log_msg), "P-TMSI %08x\n", *ptmsi);
+ else
+ snprintf(log_msg, sizeof(log_msg), "IMSI %s\n", imsi);

/* find all RNCs which are serving this RAC */
llist_for_each_entry(rnc, &sgsn->rnc_list, entry) {
@@ -267,26 +263,23 @@
if (osmo_rai_cmp(&entry->rai, rai))
continue;

- rc = sgsn_ranap_iu_tx_paging_cmd(&rnc->sccp_addr, imsi, ptmsi, true, 0);
- if (rc > 0) {
- LOGPIU(LOGL_ERROR, "IuPS: Failed to tx Paging RNC %s for RAC %s for IMSI %s / P-TMSI %08x",
- osmo_rnc_id_name(&rnc->rnc_id),
- osmo_rai_name2(rai), imsi, ptmsi ? *ptmsi : GSM_RESERVED_TMSI);
+ rc = iu_rnc_tx_paging_cmd(rnc, imsi, ptmsi, true, 0);
+ if (rc != 0) {
+ LOG_RNC(rnc, LOGL_ERROR, "Failed to tx Paging PS for RAI %s for %s",
+ osmo_rai_name2(rai), log_msg);
+ } else {
+ paged++;
}
- paged++;
break;
}
}

- if (ptmsi)
- snprintf(log_msg, sizeof(log_msg) - 1, "for PTMSI %08x\n", *ptmsi);
- else
- snprintf(log_msg, sizeof(log_msg) - 1, "for IMSI %s\n", imsi);
-
if (paged)
- LOGPIU(LOGL_DEBUG, "IuPS: Paged %d RNCs on RAI %s for %s", paged, osmo_rai_name2(rai), log_msg);
+ LOGP(DRANAP, LOGL_DEBUG, "Paged PS %u RNCs on RAI %s for %s",
+ paged, osmo_rai_name2(rai), log_msg);
else
- LOGPIU(LOGL_INFO, "IuPS: Found no RNC to Page on RAI %s for %s", osmo_rai_name2(rai), log_msg);
+ LOGP(DRANAP, LOGL_INFO, "Found no RNC to Page PS on RAI %s for %s",
+ osmo_rai_name2(rai), log_msg);

return paged;
}
diff --git a/src/sgsn/iu_rnc.c b/src/sgsn/iu_rnc.c
index 38cddb5..1a15df1 100644
--- a/src/sgsn/iu_rnc.c
+++ b/src/sgsn/iu_rnc.c
@@ -213,3 +213,43 @@
ue_conn_ctx_link_invalidated_free(ue_ctx);
}
}
+
+/* Send a paging command down a given SCCP User. tmsi_or_ptmsi and paging_cause are
+ * optional and may be passed NULL and 0, respectively, to disable their use.
+ * See enum RANAP_PagingCause.
+ *
+ * If tmsi_or_ptmsi is given, the imsi is not sent over the air interface.
+ * Nevertheless, the IMSI is still required for resolution in the HNB-GW
+ * and/or(?) RNC.
+ *
+ * returns negative if paging couldn't be sent (eg. because RNC is currently
+ * unreachable in lower layers).
+ **/
+int iu_rnc_tx_paging_cmd(struct ranap_iu_rnc *rnc,
+ const char *imsi,
+ const uint32_t *tmsi_or_ptmsi,
+ bool is_ps,
+ uint32_t paging_cause)
+{
+ struct msgb *ranap_msg;
+ int rc;
+
+ /* rnc is not ready for paging (link not ready). */
+ if (rnc->fi->state != IU_RNC_ST_READY)
+ return -ENOLINK;
+
+ LOG_RNC(rnc, LOGL_DEBUG, "Paging %s for %s=%08x IMSI=%s\n",
+ is_ps ? "PS" : "CS",
+ is_ps ? "P-TMSI" : "TMSI",
+ tmsi_or_ptmsi ? *tmsi_or_ptmsi : GSM_RESERVED_TMSI,
+ imsi);
+
+ ranap_msg = ranap_new_msg_paging_cmd(imsi, tmsi_or_ptmsi, is_ps ? 1 : 0, paging_cause);
+ if (!ranap_msg)
+ return -EINVAL;
+
+ rc = osmo_fsm_inst_dispatch(rnc->fi, IU_RNC_EV_MSG_DOWN_CL, ranap_msg);
+ if (rc != 0)
+ msgb_free(ranap_msg);
+ return rc;
+}
diff --git a/src/sgsn/iu_rnc_fsm.c b/src/sgsn/iu_rnc_fsm.c
index 6f610b4..6b0ad41 100644
--- a/src/sgsn/iu_rnc_fsm.c
+++ b/src/sgsn/iu_rnc_fsm.c
@@ -57,6 +57,7 @@
OSMO_VALUE_STRING(IU_RNC_EV_MSG_UP_CO),
OSMO_VALUE_STRING(IU_RNC_EV_RX_RESET),
OSMO_VALUE_STRING(IU_RNC_EV_RX_RESET_ACK),
+ OSMO_VALUE_STRING(IU_RNC_EV_MSG_DOWN_CL),
OSMO_VALUE_STRING(IU_RNC_EV_AVAILABLE),
OSMO_VALUE_STRING(IU_RNC_EV_UNAVAILABLE),
{}
@@ -252,6 +253,11 @@
iu_rnc_rx_reset(rnc);
return;

+ case IU_RNC_EV_MSG_DOWN_CL:
+ OSMO_ASSERT(data);
+ sgsn_ranap_iu_tx_cl(rnc->scu_iups, &rnc->sccp_addr, (struct msgb *)data);
+ return;
+
case IU_RNC_EV_AVAILABLE:
/* Do nothing, we were already up. */
return;
@@ -336,6 +342,7 @@
| S(IU_RNC_EV_RX_RESET)
| S(IU_RNC_EV_MSG_UP_CO_INITIAL)
| S(IU_RNC_EV_MSG_UP_CO)
+ | S(IU_RNC_EV_MSG_DOWN_CL)
| S(IU_RNC_EV_AVAILABLE)
| S(IU_RNC_EV_UNAVAILABLE)
,

To view, visit change 41001. To unsubscribe, or for help writing mail filters, visit settings.

Gerrit-MessageType: merged
Gerrit-Project: osmo-sgsn
Gerrit-Branch: master
Gerrit-Change-Id: I24e5446bcf4c958028577230b231960acea9e5b9
Gerrit-Change-Number: 41001
Gerrit-PatchSet: 1
Gerrit-Owner: pespin <pespin@sysmocom.de>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: fixeria <vyanitskiy@sysmocom.de>
Gerrit-Reviewer: lynxis lazus <lynxis@fe80.eu>
Gerrit-Reviewer: osmith <osmith@sysmocom.de>