aboutsummaryrefslogtreecommitdiffstats
path: root/openbsc
diff options
context:
space:
mode:
authorNeels Hofmeyr <nhofmeyr@sysmocom.de>2016-03-22 19:26:52 +0100
committerNeels Hofmeyr <nhofmeyr@sysmocom.de>2016-04-20 11:22:59 +0200
commit9bc1ddc849714bd4f38ce9d40965793ff400606b (patch)
treefc73904f0ba3373799c0222faa9a8908f8c5f81e /openbsc
parent90e2c751e97bfbe7cc18e040aaf60dc5236d8d7b (diff)
iu.c: add registry of RNC-Ids in LACs
Introduce struct gsm_rnc, stored in a global list, static to iu.c. (This list is not part of gsm_network so that the code can be used from both MSC and GPRS code, i.e. both for CS and PS.) Parse RANAP Global RNC Id, add GSM flags to build for gsm48_mcc_mnc_from_bcd() to decode the PLMN Id. Upon every Initial UE message, record/verify RNC Id and LAC for that connection. In case of mismatch, so far just log an error.
Diffstat (limited to 'openbsc')
-rw-r--r--openbsc/include/openbsc/iu.h1
-rw-r--r--openbsc/src/libiu/Makefile.am2
-rw-r--r--openbsc/src/libiu/iu.c129
3 files changed, 130 insertions, 2 deletions
diff --git a/openbsc/include/openbsc/iu.h b/openbsc/include/openbsc/iu.h
index 0f178d74b..4fde62431 100644
--- a/openbsc/include/openbsc/iu.h
+++ b/openbsc/include/openbsc/iu.h
@@ -5,6 +5,7 @@ struct msgb;
struct gprs_ra_id;
struct RANAP_RAB_SetupOrModifiedItemIEs_s;
+struct RANAP_GlobalRNC_ID;
struct ue_conn_ctx {
struct llist_head list;
diff --git a/openbsc/src/libiu/Makefile.am b/openbsc/src/libiu/Makefile.am
index 8e52049a1..7b1ba4d19 100644
--- a/openbsc/src/libiu/Makefile.am
+++ b/openbsc/src/libiu/Makefile.am
@@ -1,6 +1,6 @@
AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include -I$(top_builddir)
AM_CFLAGS=-Wall $(LIBOSMOCORE_CFLAGS) $(LIBOSMOVTY_CFLAGS) \
- $(LIBOSMOABIS_CFLAGS) $(COVERAGE_CFLAGS) $(LIBCRYPTO_CFLAGS) \
+ $(LIBOSMOGSM_CFLAGS) $(LIBOSMOABIS_CFLAGS) $(COVERAGE_CFLAGS) $(LIBCRYPTO_CFLAGS) \
$(LIBASN1C_CFLAGS) \
$(LIBOSMOSIGTRAN_CFLAGS) $(LIBOSMORANAP_CFLAGS)
diff --git a/openbsc/src/libiu/iu.c b/openbsc/src/libiu/iu.c
index 044b831f2..dcc281adb 100644
--- a/openbsc/src/libiu/iu.c
+++ b/openbsc/src/libiu/iu.c
@@ -30,6 +30,31 @@
#include <asn1c/asn1helpers.h>
+/* Parsed global RNC id. See also struct RANAP_GlobalRNC_ID, and note that the
+ * PLMN identity is a BCD representation of the MCC and MNC.
+ * See iu_grnc_id_parse(). */
+struct iu_grnc_id {
+ uint16_t mcc;
+ uint16_t mnc;
+ uint16_t rnc_id;
+};
+
+/* A remote RNC (Radio Network Controller, like BSC but for UMTS) that has
+ * called us and is currently reachable at the given osmo_sua_link. So, when we
+ * know a LAC for a subscriber, we can page it at the RNC matching that LAC or
+ * RAC. An HNB-GW typically presents itself as if it were a single RNC, even
+ * though it may have several RNCs in hNodeBs connected to it. Those will then
+ * share the same RNC id, which they actually receive and adopt from the HNB-GW
+ * in the HNBAP HNB REGISTER ACCEPT message. */
+struct iu_rnc {
+ struct llist_head entry;
+
+ uint16_t rnc_id;
+ uint16_t lac; /* Location Area Code (used for CS and PS) */
+ uint8_t rac; /* Routing Area Code (used for PS only) */
+ struct osmo_sua_link *link;
+};
+
void *talloc_iu_ctx;
int asn1_xer_print = 1;
@@ -39,6 +64,7 @@ iu_recv_cb_t global_iu_recv_cb = NULL;
iu_event_cb_t global_iu_event_cb = NULL;
static LLIST_HEAD(ue_conn_ctx_list);
+static LLIST_HEAD(rnc_list);
struct ue_conn_ctx *ue_conn_ctx_alloc(struct osmo_sua_link *link, uint32_t conn_id)
{
@@ -63,12 +89,72 @@ struct ue_conn_ctx *ue_conn_ctx_find(struct osmo_sua_link *link,
return NULL;
}
-/* Discard/invalidate all ue_conn_ctx entries that reference the
+static struct iu_rnc *iu_rnc_alloc(uint16_t rnc_id, uint16_t lac, uint8_t rac,
+ struct osmo_sua_link *link)
+{
+ struct iu_rnc *rnc = talloc_zero(talloc_iu_ctx, struct iu_rnc);
+
+ rnc->rnc_id = rnc_id;
+ rnc->lac = lac;
+ rnc->rac = rac;
+ rnc->link = link;
+ llist_add(&rnc->entry, &rnc_list);
+
+ LOGP(DRANAP, LOGL_NOTICE, "New RNC %d (LAC=%d RAC=%d)\n",
+ rnc->rnc_id, rnc->lac, rnc->rac);
+
+ return rnc;
+}
+
+static struct iu_rnc *iu_rnc_register(uint16_t rnc_id, uint16_t lac,
+ uint8_t rac, struct osmo_sua_link *link)
+{
+ struct iu_rnc *rnc;
+ llist_for_each_entry(rnc, &rnc_list, entry) {
+ if (rnc->rnc_id != rnc_id)
+ continue;
+
+ /* We have this RNC Id registered already. Make sure that the
+ * details match. */
+
+ /* TODO should a mismatch be an error? */
+ if (rnc->lac != lac || rnc->rac != rac)
+ LOGP(DRANAP, LOGL_NOTICE, "RNC %d changes its details:"
+ " LAC=%d RAC=%d --> LAC=%d RAC=%d\n",
+ rnc->rnc_id, rnc->lac, rnc->rac,
+ lac, rac);
+ rnc->lac = lac;
+ rnc->rac = rac;
+
+ if (link && rnc->link != link)
+ LOGP(DRANAP, LOGL_NOTICE, "RNC %d on new link"
+ " (LAC=%d RAC=%d)\n",
+ rnc->rnc_id, rnc->lac, rnc->rac);
+ rnc->link = link;
+ return rnc;
+ }
+
+ /* Not found, make a new one. */
+ return iu_rnc_alloc(rnc_id, lac, rac, link);
+}
+
+/* Discard/invalidate all ue_conn_ctx and iu_rnc entries that reference the
* given link, since this link is invalid and about to be deallocated. For
* each ue_conn_ctx, invoke the iu_event_cb_t with IU_EVENT_LINK_INVALIDATED.
*/
void iu_link_del(struct osmo_sua_link *link)
{
+ struct iu_rnc *rnc, *rnc_next;
+ llist_for_each_entry_safe(rnc, rnc_next, &rnc_list, entry) {
+ if (!rnc->link)
+ continue;
+ if (rnc->link != link)
+ continue;
+ rnc->link = NULL;
+ llist_del(&rnc->entry);
+ talloc_free(rnc);
+ }
+
struct ue_conn_ctx *uec, *uec_next;
llist_for_each_entry_safe(uec, uec_next, &ue_conn_ctx_list, list) {
if (uec->link != link)
@@ -167,9 +253,40 @@ int iu_tx_sec_mode_cmd(struct ue_conn_ctx *uectx, struct gsm_auth_tuple *tp,
return 0;
}
+static int iu_grnc_id_parse(struct iu_grnc_id *dst,
+ struct RANAP_GlobalRNC_ID *src)
+{
+ /* The size is coming from arbitrary sender, check it gracefully */
+ if (src->pLMNidentity.size != 3) {
+ LOGP(DRANAP, LOGL_ERROR, "Invalid PLMN Identity size:"
+ " should be 3, is %d\n", src->pLMNidentity.size);
+ return -1;
+ }
+ gsm48_mcc_mnc_from_bcd(&src->pLMNidentity.buf[0],
+ &dst->mcc, &dst->mnc);
+ dst->rnc_id = (uint16_t)src->rNC_ID;
+ return 0;
+}
+
+#if 0
+ -- not used at present --
+static int iu_grnc_id_compose(struct iu_grnc_id *src,
+ struct RANAP_GlobalRNC_ID *dst)
+{
+ /* The caller must ensure proper size */
+ OSMO_ASSERT(dst->pLMNidentity.size == 3);
+ gsm48_mcc_mnc_to_bcd(&dst->pLMNidentity.buf[0],
+ src->mcc, src->mnc);
+ dst->rNC_ID = src->rnc_id;
+ return 0;
+}
+#endif
+
static int ranap_handle_co_initial_ue(void *ctx, RANAP_InitialUE_MessageIEs_t *ies)
{
+ struct ue_conn_ctx *ue_conn = ctx;
struct gprs_ra_id ra_id;
+ struct iu_grnc_id grnc_id;
uint16_t sai;
struct msgb *msg = msgb_alloc(256, "RANAP->NAS");
@@ -177,10 +294,20 @@ static int ranap_handle_co_initial_ue(void *ctx, RANAP_InitialUE_MessageIEs_t *i
LOGP(DRANAP, LOGL_ERROR, "Failed to parse RANAP LAI IE\n");
return -1;
}
+
+ if (iu_grnc_id_parse(&grnc_id, &ies->globalRNC_ID) != 0) {
+ LOGP(DRANAP, LOGL_ERROR,
+ "Failed to parse RANAP Global-RNC-ID IE\n");
+ return -1;
+ }
+
sai = asn1str_to_u16(&ies->sai.sAC);
msgb_gmmh(msg) = msgb_put(msg, ies->nas_pdu.size);
memcpy(msgb_gmmh(msg), ies->nas_pdu.buf, ies->nas_pdu.size);
+ /* Make sure we know the RNC Id and LAC+RAC coming in on this connection. */
+ iu_rnc_register(grnc_id.rnc_id, ra_id.lac, ra_id.rac, ue_conn->link);
+
/* Feed into the MM layer */
msg->dst = ctx;
global_iu_recv_cb(msg, &ra_id, &sai);