lynxis lazus has submitted this change. ( https://gerrit.osmocom.org/c/osmo-sgsn/+/40813?usp=email )
Change subject: Re-introduce Iu/UTRAN support ......................................................................
Re-introduce Iu/UTRAN support
Add support for UTRAN routing areas.
Change-Id: I1b1aedd2a7c358bd388aa3d8a9f3c6a0011b4889 --- M include/osmocom/sgsn/gprs_routing_area.h M src/sgsn/gprs_ranap.c M src/sgsn/gprs_routing_area.c M tests/gprs_routing_area/gprs_routing_area_test.c 4 files changed, 206 insertions(+), 2 deletions(-)
Approvals: Jenkins Builder: Verified pespin: Looks good to me, but someone else must approve daniel: Looks good to me, approved
diff --git a/include/osmocom/sgsn/gprs_routing_area.h b/include/osmocom/sgsn/gprs_routing_area.h index a807227..60dfd71 100644 --- a/include/osmocom/sgsn/gprs_routing_area.h +++ b/include/osmocom/sgsn/gprs_routing_area.h @@ -56,6 +56,12 @@ * For UTRAN only do a LAC/RAC <> RNC relation and don't have a specific cell relation. */ enum sgsn_ra_ran_type ran_type; + union { + struct { + /* the RNC id must be the same for a given Routing Area */ + struct osmo_rnc_id rnc_id; + } utran; + } u;
/* GERAN/UTRAN: cells contains a list of sgsn_ra_cells which are alive */ struct llist_head cells_alive_list; @@ -77,8 +83,7 @@ } geran;
struct { - /* TODO: unused */ - uint16_t rncid; + /* the RNC id must be the same for a given Routing Area */ uint16_t sac; } utran; } u; @@ -107,10 +112,15 @@ struct sgsn_ra_cell *sgsn_ra_geran_get_cell_by_cgi(const struct osmo_cell_global_id *cgi); struct sgsn_ra_cell *sgsn_ra_geran_get_cell_by_ra(const struct sgsn_ra *ra, uint16_t cell_id); struct sgsn_ra_cell *sgsn_ra_geran_get_cell_by_gb(uint16_t nsei, uint16_t bvci); + +/* UTRAN */ +int sgsn_ra_utran_register(const struct osmo_routing_area_id *rai, const struct osmo_rnc_id *rnc_id); + struct sgsn_ra *sgsn_ra_geran_get_ra(const struct osmo_routing_area_id *rai);
/* Page the whole routing area for this mmctx */ int sgsn_ra_geran_page_ra(const struct osmo_routing_area_id *rai, struct sgsn_mm_ctx *mmctx); +struct sgsn_ra *sgsn_ra_utran_get_ra(const struct osmo_routing_area_id *rai);
/* * return value for callbacks. @@ -125,3 +135,6 @@ typedef int (sgsn_ra_cb_t)(struct sgsn_ra_cell *ra_cell, void *cb_data); int sgsn_ra_foreach_cell(struct sgsn_ra *ra, sgsn_ra_cb_t *cb, void *cb_data); int sgsn_ra_foreach_cell2(struct osmo_routing_area_id *rai, sgsn_ra_cb_t *cb, void *cb_data); + +/* Page the whole routing area for this mmctx */ +int sgsn_ra_utran_page_ra(const struct osmo_routing_area_id *rai, const struct sgsn_mm_ctx *mmctx); diff --git a/src/sgsn/gprs_ranap.c b/src/sgsn/gprs_ranap.c index 3e2c891..08fc625 100644 --- a/src/sgsn/gprs_ranap.c +++ b/src/sgsn/gprs_ranap.c @@ -38,6 +38,7 @@ #include <osmocom/sgsn/gprs_ranap.h> #include <osmocom/sgsn/gprs_gmm_attach.h> #include <osmocom/sgsn/gprs_mm_state_iu_fsm.h> +#include <osmocom/sgsn/gprs_routing_area.h> #include <osmocom/sgsn/gtp_ggsn.h> #include <osmocom/sgsn/gtp.h> #include <osmocom/sgsn/pdpctx.h> @@ -202,12 +203,23 @@
int sgsn_ranap_iu_event(struct ranap_ue_conn_ctx *ctx, enum ranap_iu_event_type type, void *data) { + struct ranap_iu_event_new_area *new_area; + switch (type) { case RANAP_IU_EVENT_RAB_ASSIGN: case RANAP_IU_EVENT_IU_RELEASE: case RANAP_IU_EVENT_LINK_INVALIDATED: case RANAP_IU_EVENT_SECURITY_MODE_COMPLETE: return sgsn_ranap_iu_event_mmctx(ctx, type, data); + case RANAP_IU_EVENT_NEW_AREA: + /* inform the Routing Area code about a new RA for Iu */ + new_area = data; + + /* Only interesting in Routing Area changes, but not Location Area */ + if (new_area->cell_type != RANAP_IU_NEW_RAC) + return 0; + + return sgsn_ra_utran_register(new_area->u.rai, new_area->rnc_id); default: LOGP(DRANAP, LOGL_NOTICE, "Iu: Unknown event received: type: %d\n", type); return -1; diff --git a/src/sgsn/gprs_routing_area.c b/src/sgsn/gprs_routing_area.c index 721f0c9..4400d6d 100644 --- a/src/sgsn/gprs_routing_area.c +++ b/src/sgsn/gprs_routing_area.c @@ -24,6 +24,7 @@ #include <osmocom/core/logging.h> #include <osmocom/core/rate_ctr.h> #include <osmocom/core/utils.h> +#include <osmocom/gsm/gsm23003.h> #include <osmocom/gsm/gsm48.h> #include <osmocom/sgsn/debug.h> #include <osmocom/sgsn/gprs_bssgp.h> @@ -181,6 +182,19 @@ return NULL; }
+struct sgsn_ra *sgsn_ra_utran_get_ra(const struct osmo_routing_area_id *ra_id) +{ + struct sgsn_ra *ra = sgsn_ra_get_ra(ra_id); + + if (!ra) + return ra; + + if (ra->ran_type == RA_TYPE_UTRAN_Iu) + return ra; + + return NULL; +} + int sgsn_ra_foreach_cell(struct sgsn_ra *ra, sgsn_ra_cb_t *cb, void *cb_data) { struct sgsn_ra_cell *cell, *tmp; @@ -419,6 +433,74 @@ return ret; }
+#ifdef BUILD_IU +/* Register a new UTRAN Routing Area if possible. + * Return 0 on success and < 0 on failure. */ +int sgsn_ra_utran_register(const struct osmo_routing_area_id *rai, const struct osmo_rnc_id *rnc_id) +{ + struct sgsn_ra *ra = sgsn_ra_get_ra(rai); + if (!ra) { + ra = sgsn_ra_alloc(rai, RA_TYPE_UTRAN_Iu); + if (!ra) { + LOGP(DRA, LOGL_ERROR, "Couldn't create new RA for %s ran type %s\n", + osmo_rai_name2(rai), get_value_string(sgsn_ra_ran_type_names, ra->ran_type)); + return -ENOMEM; + } + ra->u.utran.rnc_id = *rnc_id; + LOGRA(LOGL_INFO, ra, "New UTRAN RA by RNC %s\n", osmo_rnc_id_name(&ra->u.utran.rnc_id)); + return 0; + } + + if (ra->ran_type == RA_TYPE_GERAN_Gb) { + LOGRA(LOGL_ERROR, ra, "rejecting new RA of type %s, because already present RA has ran type %s\n", + get_value_string(sgsn_ra_ran_type_names, RA_TYPE_UTRAN_Iu), + get_value_string(sgsn_ra_ran_type_names, ra->ran_type)); + return -ENOENT; + } + + /* RA already known */ + if (osmo_rnc_id_cmp(&ra->u.utran.rnc_id, rnc_id) == 0) + return 0; + + /* RNC id changed */ + char new_rnc_id_name[32]; + osmo_rnc_id_name_buf(new_rnc_id_name, sizeof(new_rnc_id_name), rnc_id); + LOGRA(LOGL_INFO, ra, "RNC Id changed from %s to %s\n", + osmo_rnc_id_name(&ra->u.utran.rnc_id), new_rnc_id_name); + + ra->u.utran.rnc_id = *rnc_id; + return 0; +} + +int sgsn_ra_utran_page_ra(const struct osmo_routing_area_id *ra_id, const struct sgsn_mm_ctx *mmctx) +{ + struct sgsn_ra *ra; + rate_ctr_inc(rate_ctr_group_get_ctr(mmctx->ctrg, GMM_CTR_PAGING_PS)); + + ra = sgsn_ra_utran_get_ra(ra_id); + if (!ra) + return -ENOENT; + + /* Try to page by TMSI if possible */ + if (mmctx->p_tmsi != GSM_RESERVED_TMSI) + return ranap_iu_page_ps2(mmctx->imsi, &mmctx->p_tmsi, ra_id); + if (mmctx->p_tmsi_old != GSM_RESERVED_TMSI) + return ranap_iu_page_ps2(mmctx->imsi, &mmctx->p_tmsi_old, ra_id); + + /* Page by IMSI */ + return ranap_iu_page_ps2(mmctx->imsi, NULL, ra_id); +} +#else +int sgsn_ra_utran_page_ra(const struct osmo_routing_area_id *ra_id, const struct sgsn_mm_ctx *mmctx) +{ + return -1; +} +int sgsn_ra_utran_register(const struct osmo_routing_area_id *rai, const struct osmo_rnc_id *rnc_id) +{ + return -1; +} +#endif /* BUILD_IU */ + void sgsn_ra_init(struct sgsn_instance *inst) { inst->routing_area = talloc_zero(inst, struct sgsn_ra_global); diff --git a/tests/gprs_routing_area/gprs_routing_area_test.c b/tests/gprs_routing_area/gprs_routing_area_test.c index b9840b9..b4b5b21 100644 --- a/tests/gprs_routing_area/gprs_routing_area_test.c +++ b/tests/gprs_routing_area/gprs_routing_area_test.c @@ -24,6 +24,7 @@ #include <osmocom/core/rate_ctr.h> #include <osmocom/core/utils.h> #include <osmocom/gsm/apn.h> +#include <osmocom/gsm/gsm23003.h> #include <osmocom/gsm/gsm_utils.h> #include <osmocom/gsm/gsup.h> #include <osmocom/gprs/gprs_bssgp.h> @@ -537,6 +538,98 @@ cleanup_test(); }
+/* check if UTRAN RA gets rejected, if a GERAN RA/cell with the same LAC is already registered + * The SGSN does not support the same LAC/RA for GERAN and UTRAN at the same time. + */ +void test_routing_area_mv_utran_geran_reject(void) +{ + int rc; + + /* GERAN */ + struct osmo_routing_area_id geran_rai = { + .lac = { + .plmn = { .mcc = 262, .mnc = 42, .mnc_3_digits = false }, + .lac = 24 + }, + .rac = 43 + }; + struct osmo_cell_global_id_ps cgi_ps = { + .rai = geran_rai, + .cell_identity = 9998, + }; + uint16_t nsei = 2, bvci = 3; + + /* UTRAN */ + struct osmo_routing_area_id utran_rai = { + .lac = { + .plmn = { .mcc = 262, .mnc = 42, .mnc_3_digits = false }, + .lac = 24 + }, + .rac = 43 + }; + struct osmo_rnc_id rnc_id = { + .plmn = utran_rai.lac.plmn, + .rnc_id = 2222 + }; + + sgsn = sgsn_instance_alloc(tall_sgsn_ctx); + + /* Registering UTRAN RA */ + rc = sgsn_ra_utran_register(&utran_rai, &rnc_id); + OSMO_ASSERT(rc == 0); + + /* Registering GERAN RA/cell via BVC Reset Ind (should fail) */ + rc = sgsn_ra_geran_bvc_cell_reset_ind(nsei, bvci, &cgi_ps); + OSMO_ASSERT(rc != 0); + + cleanup_test(); +} + +/* check if a UTRAN RA with the same LAC as an already register GERAN RA gets rejected */ +void test_routing_area_mv_geran_utran_reject(void) +{ + int rc; + + /* GERAN */ + struct osmo_routing_area_id geran_rai = { + .lac = { + .plmn = { .mcc = 262, .mnc = 42, .mnc_3_digits = false }, + .lac = 24 + }, + .rac = 43 + }; + struct osmo_cell_global_id_ps cgi_ps = { + .rai = geran_rai, + .cell_identity = 9998, + }; + uint16_t nsei = 2, bvci = 3; + + /* UTRAN */ + struct osmo_routing_area_id utran_rai = { + .lac = { + .plmn = { .mcc = 262, .mnc = 42, .mnc_3_digits = false }, + .lac = 24 + }, + .rac = 43 + }; + struct osmo_rnc_id rnc_id = { + .plmn = utran_rai.lac.plmn, + .rnc_id = 2222 + }; + + sgsn = sgsn_instance_alloc(tall_sgsn_ctx); + + /* Registering GERAN RA/cell via BVC Reset Ind */ + rc = sgsn_ra_geran_bvc_cell_reset_ind(nsei, bvci, &cgi_ps); + OSMO_ASSERT(rc == 0); + + /* Registering UTRAN RA (should fail) */ + rc = sgsn_ra_utran_register(&utran_rai, &rnc_id); + OSMO_ASSERT(rc != 0); + + cleanup_test(); +} + static struct log_info_cat gprs_categories[] = { [DMM] = { .name = "DMM", @@ -601,6 +694,10 @@ test_routing_area_paging(); test_routing_area_geran_geran_sig_reset(); test_routing_area_geran_geran_bvci_change(); +#ifdef BUILD_IU + test_routing_area_mv_geran_utran_reject(); + test_routing_area_mv_utran_geran_reject(); +#endif printf("Done\n");
talloc_report_full(osmo_sgsn_ctx, stderr);