diff options
author | Daniel Willmann <dwillmann@sysmocom.de> | 2023-12-13 16:02:38 +0100 |
---|---|---|
committer | Daniel Willmann <dwillmann@sysmocom.de> | 2023-12-13 18:01:37 +0100 |
commit | a99b82b82c19dfe1d72e34c4be0732bd5be851ac (patch) | |
tree | 293d68f579f96bdec21b5fb13133a3e563eda278 | |
parent | 2c909d1e8ba03e9df3e784c441cee23d5bb3f4e8 (diff) |
iu_client: Handle empty CR and InitialUE Message in DATA.ind
Related: OS#6307
Change-Id: I749ede737b9ac15bca37bbb16f3988b0db1125c1
-rw-r--r-- | src/iu_client.c | 75 |
1 files changed, 67 insertions, 8 deletions
diff --git a/src/iu_client.c b/src/iu_client.c index 9da11ea..ea5ebe8 100644 --- a/src/iu_client.c +++ b/src/iu_client.c @@ -55,6 +55,14 @@ struct iu_lac_rac_entry { uint8_t rac; }; +/* Entry to cache conn_id <-> sccp_addr mapping in case we receive an empty CR */ +struct iu_new_ctx_entry { + struct llist_head list; + + uint32_t conn_id; + struct osmo_sccp_addr sccp_addr; +}; + /* A remote RNC (Radio Network Controller, like BSC but for UMTS) that has * called us and is currently reachable at the given osmo_sccp_addr. So, when we * know a LAC for a subscriber, we can page it at the RNC matching that LAC or @@ -94,6 +102,7 @@ int iu_log_subsystem = 0; #define LOGPIUC(level, fmt, args...) \ LOGPC(iu_log_subsystem, level, fmt, ## args) +static LLIST_HEAD(ue_conn_sccp_addr_list); static LLIST_HEAD(ue_conn_ctx_list); static LLIST_HEAD(rnc_list); @@ -168,6 +177,38 @@ void ranap_iu_free_ue(struct ranap_ue_conn_ctx *ue_ctx) talloc_free(ue_ctx); } +static void ue_conn_sccp_addr_add(uint32_t conn_id, const struct osmo_sccp_addr *calling_addr) +{ + struct iu_new_ctx_entry *entry = talloc_zero(talloc_iu_ctx, struct iu_new_ctx_entry); + + entry->conn_id = conn_id; + entry->sccp_addr = *calling_addr; + + llist_add(&entry->list, &ue_conn_sccp_addr_list); +} + +static const struct osmo_sccp_addr *ue_conn_sccp_addr_find(uint32_t conn_id) +{ + struct iu_new_ctx_entry *entry; + llist_for_each_entry(entry, &ue_conn_sccp_addr_list, list) { + if (entry->conn_id == conn_id) + return &entry->sccp_addr; + } + return NULL; +} + +static void ue_conn_sccp_addr_del(uint32_t conn_id) +{ + struct iu_new_ctx_entry *entry; + llist_for_each_entry(entry, &ue_conn_sccp_addr_list, list) { + if (entry->conn_id == conn_id) { + llist_del(&entry->list); + talloc_free(entry); + return; + } + } +} + static struct ranap_iu_rnc *iu_rnc_alloc(uint16_t rnc_id, struct osmo_sccp_addr *addr) { struct ranap_iu_rnc *rnc = talloc_zero(talloc_iu_ctx, struct ranap_iu_rnc); @@ -831,24 +872,29 @@ static int sccp_sap_up(struct osmo_prim_hdr *oph, void *_scu) /* indication of new inbound connection request*/ conn_id = prim->u.connect.conn_id; LOGPIU(LOGL_DEBUG, "N-CONNECT.ind(X->%u)\n", conn_id); - if (/* prim->u.connect.called_addr.ssn != OSMO_SCCP_SSN_RANAP || */ - !msgb_l2(oph->msg) || msgb_l2len(oph->msg) == 0) { - LOGPIU(LOGL_NOTICE, - "Received invalid N-CONNECT.ind\n"); - return 0; - } + new_ctx.sccp_addr = prim->u.connect.calling_addr; new_ctx.conn_id = conn_id; + /* first ensure the local SCCP socket is ACTIVE */ resp = make_conn_resp(&prim->u.connect); osmo_sccp_user_sap_down(scu, resp); /* then handle the RANAP payload */ - rc = ranap_cn_rx_co(cn_ranap_handle_co_initial, &new_ctx, msgb_l2(oph->msg), msgb_l2len(oph->msg)); + if (/* prim->u.connect.called_addr.ssn != OSMO_SCCP_SSN_RANAP || */ + !msgb_l2(oph->msg) || msgb_l2len(oph->msg) == 0) { + LOGPIU(LOGL_DEBUG, + "Received N-CONNECT.ind without data\n"); + ue_conn_sccp_addr_add(conn_id, &prim->u.connect.calling_addr); + } else { + rc = ranap_cn_rx_co(cn_ranap_handle_co_initial, &new_ctx, msgb_l2(oph->msg), msgb_l2len(oph->msg)); + } break; case OSMO_PRIM(OSMO_SCU_PRIM_N_DISCONNECT, PRIM_OP_INDICATION): /* indication of disconnect */ conn_id = prim->u.disconnect.conn_id; LOGPIU(LOGL_DEBUG, "N-DISCONNECT.ind(%u)\n", conn_id); + + ue_conn_sccp_addr_del(conn_id); ue = ue_conn_ctx_find(conn_id); if (!ue) break; @@ -876,10 +922,23 @@ static int sccp_sap_up(struct osmo_prim_hdr *oph, void *_scu) conn_id = prim->u.data.conn_id; LOGPIU(LOGL_DEBUG, "N-DATA.ind(%u, %s)\n", conn_id, osmo_hexdump(msgb_l2(oph->msg), msgb_l2len(oph->msg))); + /* resolve UE context */ ue = ue_conn_ctx_find(conn_id); - if (!ue) + if (!ue) { + /* Could be an InitialUE-Message after an empty CR, recreate new_ctx */ + const struct osmo_sccp_addr *sccp_addr = ue_conn_sccp_addr_find(conn_id); + if (!sccp_addr) { + LOGPIU(LOGL_NOTICE, + "N-DATA.ind for unknown conn_id (%u)\n", conn_id); + break; + } + new_ctx.conn_id = conn_id; + new_ctx.sccp_addr = *sccp_addr; + ue_conn_sccp_addr_del(conn_id); + rc = ranap_cn_rx_co(cn_ranap_handle_co_initial, &new_ctx, msgb_l2(oph->msg), msgb_l2len(oph->msg)); break; + } rc = ranap_cn_rx_co(cn_ranap_handle_co, ue, msgb_l2(oph->msg), msgb_l2len(oph->msg)); break; |