mirror of
https://gitea.osmocom.org/cellular-infrastructure/osmo-sgsn.git
synced 2025-11-02 13:13:16 +00:00
Re-introduce Iu/UTRAN support
Add support for UTRAN routing areas. Change-Id: I1b1aedd2a7c358bd388aa3d8a9f3c6a0011b4889
This commit is contained in:
@@ -56,6 +56,12 @@ struct sgsn_ra {
|
||||
* 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 @@ struct sgsn_ra_cell {
|
||||
} 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_lai(const struct osmo_location_ar
|
||||
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 @@ int sgsn_ra_geran_page_ra(const struct osmo_routing_area_id *rai, struct sgsn_mm
|
||||
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);
|
||||
|
||||
@@ -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 @@ static int sgsn_ranap_iu_event_mmctx(struct ranap_ue_conn_ctx *ctx, enum ranap_i
|
||||
|
||||
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;
|
||||
|
||||
@@ -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 @@ struct sgsn_ra_cell *sgsn_ra_geran_get_cell_by_gb(uint16_t nsei, uint16_t bvci)
|
||||
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 @@ int sgsn_ra_geran_page_ra(const struct osmo_routing_area_id *rai, struct sgsn_mm
|
||||
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);
|
||||
|
||||
@@ -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 @@ void test_routing_area_geran_geran_bvci_change(void)
|
||||
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 @@ int main(int argc, char **argv)
|
||||
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);
|
||||
|
||||
Reference in New Issue
Block a user