<p>laforge <strong>submitted</strong> this change.</p><p><a href="https://gerrit.osmocom.org/c/osmo-sgsn/+/21406">View Change</a></p><div style="white-space:pre-wrap">Approvals:
Jenkins Builder: Verified
pespin: Looks good to me, but someone else must approve
laforge: Looks good to me, approved
</div><pre style="font-family: monospace,monospace; white-space: pre-wrap;">gbproxy: Add NSE peer that can have multiple gbproxy_peers<br><br>We want this level of indirection to support multiple BVCs per NSE. The<br>current code assumes that an NSE only has one BVC which breaks messages<br>on the signalling BVC which should only be sent once to an NSE<br>regardless of the number of BVCs it contains.<br><br>Change-Id: I97cc6c8f8c0f1b91577ab8f679c4ae217cc88076<br>Related: SYS#5226<br>---<br>M include/osmocom/sgsn/gb_proxy.h<br>M src/gbproxy/gb_proxy.c<br>M src/gbproxy/gb_proxy_ctrl.c<br>M src/gbproxy/gb_proxy_patch.c<br>M src/gbproxy/gb_proxy_peer.c<br>M src/gbproxy/gb_proxy_tlli.c<br>M src/gbproxy/gb_proxy_vty.c<br>M tests/gbproxy/gbproxy_test.c<br>M tests/gbproxy/gbproxy_test.ok<br>9 files changed, 495 insertions(+), 285 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/include/osmocom/sgsn/gb_proxy.h b/include/osmocom/sgsn/gb_proxy.h</span><br><span>index 4466f15..54d4548 100644</span><br><span>--- a/include/osmocom/sgsn/gb_proxy.h</span><br><span>+++ b/include/osmocom/sgsn/gb_proxy.h</span><br><span>@@ -99,7 +99,7 @@</span><br><span> struct gprs_ns2_inst *nsi;</span><br><span> </span><br><span> /* Linked list of all Gb peers (except SGSN) */</span><br><span style="color: hsl(0, 100%, 40%);">- struct llist_head bts_peers;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct llist_head nse_peers;</span><br><span> </span><br><span> /* Counter */</span><br><span> struct rate_ctr_group *ctrg;</span><br><span>@@ -143,24 +143,23 @@</span><br><span> int logical_link_count;</span><br><span> };</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-/* one peer at NS level that we interact with (BSS/PCU) */</span><br><span style="color: hsl(120, 100%, 40%);">+/* One BVC inside an NSE */</span><br><span> struct gbproxy_peer {</span><br><span style="color: hsl(0, 100%, 40%);">- /* linked to gbproxy_config.bts_peers */</span><br><span style="color: hsl(120, 100%, 40%);">+ /* linked to gbproxy_nse.bts_peers */</span><br><span> struct llist_head list;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- /* point back to the config */</span><br><span style="color: hsl(0, 100%, 40%);">- struct gbproxy_config *cfg;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- /* NSEI of the peer entity */</span><br><span style="color: hsl(0, 100%, 40%);">- uint16_t nsei;</span><br><span style="color: hsl(120, 100%, 40%);">+ /* The peer this BVC belongs to */</span><br><span style="color: hsl(120, 100%, 40%);">+ struct gbproxy_nse *nse;</span><br><span> </span><br><span> /* BVCI used for Point-to-Point to this peer */</span><br><span> uint16_t bvci;</span><br><span style="color: hsl(0, 100%, 40%);">- bool blocked;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- /* Routeing Area that this peer is part of (raw 04.08 encoding) */</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Routing Area that this peer is part of (raw 04.08 encoding) */</span><br><span> uint8_t ra[6];</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ /* true if this BVC is blocked */</span><br><span style="color: hsl(120, 100%, 40%);">+ bool blocked;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /* Counter */</span><br><span> struct rate_ctr_group *ctrg;</span><br><span> </span><br><span>@@ -171,6 +170,21 @@</span><br><span> struct osmo_timer_list clean_stale_timer;</span><br><span> };</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+/* one peer at NS level that we interact with (BSS/PCU) */</span><br><span style="color: hsl(120, 100%, 40%);">+struct gbproxy_nse {</span><br><span style="color: hsl(120, 100%, 40%);">+ /* linked to gbproxy_config.nse_peers */</span><br><span style="color: hsl(120, 100%, 40%);">+ struct llist_head list;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* point back to the config */</span><br><span style="color: hsl(120, 100%, 40%);">+ struct gbproxy_config *cfg;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* NSEI of the peer entity */</span><br><span style="color: hsl(120, 100%, 40%);">+ uint16_t nsei;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* List of all BVCs in this NSE */</span><br><span style="color: hsl(120, 100%, 40%);">+ struct llist_head bts_peers;</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> struct gbproxy_tlli_state {</span><br><span> /* currently active TLLI */</span><br><span> uint32_t current;</span><br><span>@@ -328,8 +342,14 @@</span><br><span> struct gbproxy_config *cfg, const uint8_t *la);</span><br><span> struct gbproxy_peer *gbproxy_peer_by_bssgp_tlv(</span><br><span> struct gbproxy_config *cfg, struct tlv_parsed *tp);</span><br><span style="color: hsl(0, 100%, 40%);">-struct gbproxy_peer *gbproxy_peer_alloc(struct gbproxy_config *cfg, uint16_t bvci);</span><br><span style="color: hsl(120, 100%, 40%);">+struct gbproxy_peer *gbproxy_peer_alloc(struct gbproxy_nse *nse, uint16_t bvci);</span><br><span> void gbproxy_peer_free(struct gbproxy_peer *peer);</span><br><span> int gbproxy_cleanup_peers(struct gbproxy_config *cfg, uint16_t nsei, uint16_t bvci);</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+/* NSE handling */</span><br><span style="color: hsl(120, 100%, 40%);">+struct gbproxy_nse *gbproxy_nse_alloc(struct gbproxy_config *cfg, uint16_t nsei);</span><br><span style="color: hsl(120, 100%, 40%);">+void gbproxy_nse_free(struct gbproxy_nse *nse);</span><br><span style="color: hsl(120, 100%, 40%);">+struct gbproxy_nse *gbproxy_nse_by_nsei(struct gbproxy_config *cfg, uint16_t nsei);</span><br><span style="color: hsl(120, 100%, 40%);">+struct gbproxy_nse *gbproxy_nse_by_nsei_or_new(struct gbproxy_config *cfg, uint16_t nsei);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> #endif</span><br><span>diff --git a/src/gbproxy/gb_proxy.c b/src/gbproxy/gb_proxy.c</span><br><span>index 9009651..736bd7a 100644</span><br><span>--- a/src/gbproxy/gb_proxy.c</span><br><span>+++ b/src/gbproxy/gb_proxy.c</span><br><span>@@ -84,10 +84,12 @@</span><br><span> </span><br><span> static int check_peer_nsei(struct gbproxy_peer *peer, uint16_t nsei)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">- if (peer->nsei != nsei) {</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(peer->nse);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (peer->nse->nsei != nsei) {</span><br><span> LOGP(DGPRS, LOGL_NOTICE, "Peer entry doesn't match current NSEI "</span><br><span> "BVCI=%u via NSEI=%u (expected NSEI=%u)\n",</span><br><span style="color: hsl(0, 100%, 40%);">- peer->bvci, nsei, peer->nsei);</span><br><span style="color: hsl(120, 100%, 40%);">+ peer->bvci, nsei, peer->nse->nsei);</span><br><span> rate_ctr_inc(&peer->ctrg->ctr[GBPROX_PEER_CTR_INV_NSEI]);</span><br><span> return 0;</span><br><span> }</span><br><span>@@ -195,6 +197,9 @@</span><br><span> struct gbproxy_patch_state *state = &peer->patch_state;</span><br><span> const struct osmo_plmn_id old_plmn = state->local_plmn;</span><br><span> struct gprs_ra_id raid;</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(peer->nse);</span><br><span style="color: hsl(120, 100%, 40%);">+ struct gbproxy_config *cfg = peer->nse->cfg;</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(cfg);</span><br><span> </span><br><span> if (!raid_enc)</span><br><span> return;</span><br><span>@@ -202,15 +207,15 @@</span><br><span> gsm48_parse_ra(&raid, raid_enc);</span><br><span> </span><br><span> /* save source side MCC/MNC */</span><br><span style="color: hsl(0, 100%, 40%);">- if (!peer->cfg->core_plmn.mcc || raid.mcc == peer->cfg->core_plmn.mcc) {</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!cfg->core_plmn.mcc || raid.mcc == cfg->core_plmn.mcc) {</span><br><span> state->local_plmn.mcc = 0;</span><br><span> } else {</span><br><span> state->local_plmn.mcc = raid.mcc;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- if (!peer->cfg->core_plmn.mnc</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!cfg->core_plmn.mnc</span><br><span> || !osmo_mnc_cmp(raid.mnc, raid.mnc_3_digits,</span><br><span style="color: hsl(0, 100%, 40%);">- peer->cfg->core_plmn.mnc, peer->cfg->core_plmn.mnc_3_digits)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ cfg->core_plmn.mnc, cfg->core_plmn.mnc_3_digits)) {</span><br><span> state->local_plmn.mnc = 0;</span><br><span> state->local_plmn.mnc_3_digits = false;</span><br><span> } else {</span><br><span>@@ -226,7 +231,7 @@</span><br><span> "" : "de",</span><br><span> log_text,</span><br><span> osmo_plmn_name(&state->local_plmn),</span><br><span style="color: hsl(0, 100%, 40%);">- osmo_plmn_name2(&peer->cfg->core_plmn));</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_plmn_name2(&cfg->core_plmn));</span><br><span> }</span><br><span> </span><br><span> uint32_t gbproxy_make_bss_ptmsi(struct gbproxy_peer *peer,</span><br><span>@@ -234,7 +239,7 @@</span><br><span> {</span><br><span> uint32_t bss_ptmsi;</span><br><span> int max_retries = 23, rc = 0;</span><br><span style="color: hsl(0, 100%, 40%);">- if (!peer->cfg->patch_ptmsi) {</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!peer->nse->cfg->patch_ptmsi) {</span><br><span> bss_ptmsi = sgsn_ptmsi;</span><br><span> } else {</span><br><span> do {</span><br><span>@@ -263,7 +268,7 @@</span><br><span> {</span><br><span> uint32_t sgsn_tlli;</span><br><span> int max_retries = 23, rc = 0;</span><br><span style="color: hsl(0, 100%, 40%);">- if (!peer->cfg->patch_ptmsi) {</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!peer->nse->cfg->patch_ptmsi) {</span><br><span> sgsn_tlli = bss_tlli;</span><br><span> } else if (link_info->sgsn_tlli.ptmsi != GSM_RESERVED_TMSI &&</span><br><span> gprs_tlli_type(bss_tlli) == TLLI_FOREIGN) {</span><br><span>@@ -330,6 +335,9 @@</span><br><span> {</span><br><span> int rc;</span><br><span> struct msgb *stored_msg;</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(peer->nse);</span><br><span style="color: hsl(120, 100%, 40%);">+ struct gbproxy_config *cfg = peer->nse->cfg;</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(cfg);</span><br><span> </span><br><span> /* Patch and flush stored messages towards the SGSN */</span><br><span> while ((stored_msg = msgb_dequeue_count(&link_info->stored_msgs,</span><br><span>@@ -355,7 +363,7 @@</span><br><span> return -1;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- rc = gbprox_relay2sgsn(peer->cfg, stored_msg,</span><br><span style="color: hsl(120, 100%, 40%);">+ rc = gbprox_relay2sgsn(cfg, stored_msg,</span><br><span> msgb_bvci(stored_msg), link_info->sgsn_nsei);</span><br><span> </span><br><span> if (rc < 0)</span><br><span>@@ -425,6 +433,9 @@</span><br><span> struct gprs_gb_parse_context *parse_ctx)</span><br><span> {</span><br><span> struct msgb *stored_msg;</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(peer->nse);</span><br><span style="color: hsl(120, 100%, 40%);">+ struct gbproxy_config *cfg = peer->nse->cfg;</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(cfg);</span><br><span> </span><br><span> if (!link_info)</span><br><span> return 1;</span><br><span>@@ -493,9 +504,9 @@</span><br><span> /* The message cannot be processed since the IMSI is still missing */</span><br><span> </span><br><span> /* If queue is getting too large, drop oldest msgb before adding new one */</span><br><span style="color: hsl(0, 100%, 40%);">- if (peer->cfg->stored_msgs_max_len > 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+ if (cfg->stored_msgs_max_len > 0) {</span><br><span> int exceeded_max_len = link_info->stored_msgs_len</span><br><span style="color: hsl(0, 100%, 40%);">- + 1 - peer->cfg->stored_msgs_max_len;</span><br><span style="color: hsl(120, 100%, 40%);">+ + 1 - cfg->stored_msgs_max_len;</span><br><span> </span><br><span> for (; exceeded_max_len > 0; exceeded_max_len--) {</span><br><span> struct msgb *msgb_drop;</span><br><span>@@ -806,19 +817,23 @@</span><br><span> static int gbprox_relay2peer(struct msgb *old_msg, struct gbproxy_peer *peer,</span><br><span> uint16_t ns_bvci)</span><br><span> {</span><br><span style="color: hsl(120, 100%, 40%);">+ struct gbproxy_nse *nse = peer->nse;</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(nse);</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(nse->cfg);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /* create a copy of the message so the old one can</span><br><span> * be free()d safely when we return from gbprox_rcvmsg() */</span><br><span style="color: hsl(0, 100%, 40%);">- struct gprs_ns2_inst *nsi = peer->cfg->nsi;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct gprs_ns2_inst *nsi = nse->cfg->nsi;</span><br><span> struct osmo_gprs_ns2_prim nsp = {};</span><br><span> struct msgb *msg = bssgp_msgb_copy(old_msg, "msgb_relay2peer");</span><br><span> uint32_t tlli;</span><br><span> int rc;</span><br><span> </span><br><span> DEBUGP(DGPRS, "NSEI=%u proxying SGSN->BSS (NS_BVCI=%u, NSEI=%u)\n",</span><br><span style="color: hsl(0, 100%, 40%);">- msgb_nsei(msg), ns_bvci, peer->nsei);</span><br><span style="color: hsl(120, 100%, 40%);">+ msgb_nsei(msg), ns_bvci, nse->nsei);</span><br><span> </span><br><span> nsp.bvci = ns_bvci;</span><br><span style="color: hsl(0, 100%, 40%);">- nsp.nsei = peer->nsei;</span><br><span style="color: hsl(120, 100%, 40%);">+ nsp.nsei = nse->nsei;</span><br><span> </span><br><span> /* Strip the old NS header, it will be replaced with a new one */</span><br><span> strip_ns_hdr(msg);</span><br><span>@@ -1051,16 +1066,33 @@</span><br><span> }</span><br><span> from_peer = gbproxy_peer_by_bvci(cfg, bvci);</span><br><span> if (!from_peer) {</span><br><span style="color: hsl(120, 100%, 40%);">+ struct gbproxy_nse *nse = gbproxy_nse_by_nsei_or_new(cfg, nsei);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!nse) {</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGP(DGPRS, LOGL_ERROR, "Could not allocate NSE for NSEI=%u\n", nsei);</span><br><span style="color: hsl(120, 100%, 40%);">+ return bssgp_tx_status(BSSGP_CAUSE_PROTO_ERR_UNSPEC, NULL, msg);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span> /* if a PTP-BVC is reset, and we don't know that</span><br><span> * PTP-BVCI yet, we should allocate a new peer */</span><br><span> LOGP(DGPRS, LOGL_INFO, "Allocationg new peer for BVCI=%u via NSEI=%u\n", bvci, nsei);</span><br><span style="color: hsl(0, 100%, 40%);">- from_peer = gbproxy_peer_alloc(cfg, bvci);</span><br><span style="color: hsl(120, 100%, 40%);">+ from_peer = gbproxy_peer_alloc(nse, bvci);</span><br><span> OSMO_ASSERT(from_peer);</span><br><span style="color: hsl(0, 100%, 40%);">- from_peer->nsei = nsei;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- if (!check_peer_nsei(from_peer, nsei))</span><br><span style="color: hsl(0, 100%, 40%);">- from_peer->nsei = nsei;</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Could have moved to a different NSE */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!check_peer_nsei(from_peer, nsei)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ struct gbproxy_nse *nse_old = from_peer->nse;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct gbproxy_nse *nse_new = gbproxy_nse_by_nsei_or_new(cfg, nsei);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!nse_new) {</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGP(DGPRS, LOGL_ERROR, "Could not allocate NSE for NSEI=%u\n", nsei);</span><br><span style="color: hsl(120, 100%, 40%);">+ return bssgp_tx_status(BSSGP_CAUSE_PROTO_ERR_UNSPEC, NULL, msg);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGP(DGPRS, LOGL_NOTICE, "Peer for BVCI=%u moved from NSEI=%u to NSEI=%u\n", bvci, nse_old->nsei, nsei);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Move peer to different NSE */</span><br><span style="color: hsl(120, 100%, 40%);">+ llist_del(&from_peer->list);</span><br><span style="color: hsl(120, 100%, 40%);">+ llist_add(&from_peer->list, &nse_new->bts_peers);</span><br><span style="color: hsl(120, 100%, 40%);">+ from_peer->nse = nse_new;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span> </span><br><span> if (TLVP_PRESENT(&tp, BSSGP_IE_CELL_ID)) {</span><br><span> struct gprs_ra_id raid;</span><br><span>@@ -1107,10 +1139,13 @@</span><br><span> static int gbprox_rx_paging(struct gbproxy_config *cfg, struct msgb *msg, struct tlv_parsed *tp,</span><br><span> uint32_t nsei, uint16_t ns_bvci)</span><br><span> {</span><br><span style="color: hsl(120, 100%, 40%);">+ struct gbproxy_nse *nse;</span><br><span> struct gbproxy_peer *peer;</span><br><span> unsigned int n_peers = 0;</span><br><span> int errctr = GBPROX_GLOB_CTR_PROTO_ERR_SGSN;</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ /* FIXME: Handle paging logic to only page each matching NSE */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> LOGP(DGPRS, LOGL_INFO, "NSEI=%u(SGSN) BSSGP PAGING ",</span><br><span> nsei);</span><br><span> if (TLVP_PRESENT(tp, BSSGP_IE_BVCI)) {</span><br><span>@@ -1128,29 +1163,35 @@</span><br><span> } else if (TLVP_PRESENT(tp, BSSGP_IE_ROUTEING_AREA)) {</span><br><span> errctr = GBPROX_GLOB_CTR_INV_RAI;</span><br><span> /* iterate over all peers and dispatch the paging to each matching one */</span><br><span style="color: hsl(0, 100%, 40%);">- llist_for_each_entry(peer, &cfg->bts_peers, list) {</span><br><span style="color: hsl(0, 100%, 40%);">- if (!memcmp(peer->ra, TLVP_VAL(tp, BSSGP_IE_ROUTEING_AREA), 6)) {</span><br><span style="color: hsl(0, 100%, 40%);">- LOGPC(DGPRS, LOGL_INFO, "routing by RAI to peer BVCI=%u\n", peer->bvci);</span><br><span style="color: hsl(0, 100%, 40%);">- gbprox_relay2peer(msg, peer, ns_bvci);</span><br><span style="color: hsl(0, 100%, 40%);">- n_peers++;</span><br><span style="color: hsl(120, 100%, 40%);">+ llist_for_each_entry(nse, &cfg->nse_peers, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+ llist_for_each_entry(peer, &nse->bts_peers, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!memcmp(peer->ra, TLVP_VAL(tp, BSSGP_IE_ROUTEING_AREA), 6)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGPC(DGPRS, LOGL_INFO, "routing by RAI to peer BVCI=%u\n", peer->bvci);</span><br><span style="color: hsl(120, 100%, 40%);">+ gbprox_relay2peer(msg, peer, ns_bvci);</span><br><span style="color: hsl(120, 100%, 40%);">+ n_peers++;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span> }</span><br><span> }</span><br><span> } else if (TLVP_PRESENT(tp, BSSGP_IE_LOCATION_AREA)) {</span><br><span> errctr = GBPROX_GLOB_CTR_INV_LAI;</span><br><span> /* iterate over all peers and dispatch the paging to each matching one */</span><br><span style="color: hsl(0, 100%, 40%);">- llist_for_each_entry(peer, &cfg->bts_peers, list) {</span><br><span style="color: hsl(0, 100%, 40%);">- if (!memcmp(peer->ra, TLVP_VAL(tp, BSSGP_IE_LOCATION_AREA), 5)) {</span><br><span style="color: hsl(0, 100%, 40%);">- LOGPC(DGPRS, LOGL_INFO, "routing by LAI to peer BVCI=%u\n", peer->bvci);</span><br><span style="color: hsl(0, 100%, 40%);">- gbprox_relay2peer(msg, peer, ns_bvci);</span><br><span style="color: hsl(0, 100%, 40%);">- n_peers++;</span><br><span style="color: hsl(120, 100%, 40%);">+ llist_for_each_entry(nse, &cfg->nse_peers, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+ llist_for_each_entry(peer, &nse->bts_peers, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!memcmp(peer->ra, TLVP_VAL(tp, BSSGP_IE_LOCATION_AREA), 5)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGPC(DGPRS, LOGL_INFO, "routing by LAI to peer BVCI=%u\n", peer->bvci);</span><br><span style="color: hsl(120, 100%, 40%);">+ gbprox_relay2peer(msg, peer, ns_bvci);</span><br><span style="color: hsl(120, 100%, 40%);">+ n_peers++;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span> }</span><br><span> }</span><br><span> } else if (TLVP_PRESENT(tp, BSSGP_IE_BSS_AREA_ID)) {</span><br><span> /* iterate over all peers and dispatch the paging to each matching one */</span><br><span style="color: hsl(0, 100%, 40%);">- llist_for_each_entry(peer, &cfg->bts_peers, list) {</span><br><span style="color: hsl(0, 100%, 40%);">- LOGPC(DGPRS, LOGL_INFO, "broadcasting to peer BVCI=%u\n", peer->bvci);</span><br><span style="color: hsl(0, 100%, 40%);">- gbprox_relay2peer(msg, peer, ns_bvci);</span><br><span style="color: hsl(0, 100%, 40%);">- n_peers++;</span><br><span style="color: hsl(120, 100%, 40%);">+ llist_for_each_entry(nse, &cfg->nse_peers, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+ llist_for_each_entry(peer, &nse->bts_peers, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGPC(DGPRS, LOGL_INFO, "broadcasting to peer BVCI=%u\n", peer->bvci);</span><br><span style="color: hsl(120, 100%, 40%);">+ gbprox_relay2peer(msg, peer, ns_bvci);</span><br><span style="color: hsl(120, 100%, 40%);">+ n_peers++;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span> }</span><br><span> } else {</span><br><span> LOGPC(DGPRS, LOGL_INFO, "\n");</span><br><span>@@ -1174,6 +1215,7 @@</span><br><span> struct msgb *msg, struct tlv_parsed *tp,</span><br><span> uint32_t nsei, uint16_t ns_bvci)</span><br><span> {</span><br><span style="color: hsl(120, 100%, 40%);">+ struct gbproxy_nse *nse;</span><br><span> struct gbproxy_peer *peer;</span><br><span> uint16_t ptp_bvci;</span><br><span> </span><br><span>@@ -1204,8 +1246,10 @@</span><br><span> * from the SGSN. As the signalling BVCI is shared</span><br><span> * among all the BSS's that we multiplex, it needs to</span><br><span> * be relayed */</span><br><span style="color: hsl(0, 100%, 40%);">- llist_for_each_entry(peer, &cfg->bts_peers, list)</span><br><span style="color: hsl(0, 100%, 40%);">- gbprox_relay2peer(msg, peer, ns_bvci);</span><br><span style="color: hsl(120, 100%, 40%);">+ llist_for_each_entry(nse, &cfg->nse_peers, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+ llist_for_each_entry(peer, &nse->bts_peers, list)</span><br><span style="color: hsl(120, 100%, 40%);">+ gbprox_relay2peer(msg, peer, ns_bvci);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span> </span><br><span> return 0;</span><br><span> }</span><br><span>@@ -1454,7 +1498,8 @@</span><br><span> rate_ctr_inc(&cfg->ctrg-></span><br><span> ctr[GBPROX_GLOB_CTR_RESTART_RESET_SGSN]);</span><br><span> } else {</span><br><span style="color: hsl(0, 100%, 40%);">- /* bss became unavailable */</span><br><span style="color: hsl(120, 100%, 40%);">+ /* bss became unavailable</span><br><span style="color: hsl(120, 100%, 40%);">+ * TODO: Block all BVC belonging to that NSE */</span><br><span> peer = gbproxy_peer_by_nsei(cfg, nsp->nsei);</span><br><span> if (!peer) {</span><br><span> /* TODO: use primitive name + status cause name */</span><br><span>@@ -1525,10 +1570,15 @@</span><br><span> </span><br><span> void gbprox_reset(struct gbproxy_config *cfg)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">- struct gbproxy_peer *peer, *tmp;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct gbproxy_nse *nse, *ntmp;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- llist_for_each_entry_safe(peer, tmp, &cfg->bts_peers, list)</span><br><span style="color: hsl(0, 100%, 40%);">- gbproxy_peer_free(peer);</span><br><span style="color: hsl(120, 100%, 40%);">+ llist_for_each_entry_safe(nse, ntmp, &cfg->nse_peers, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+ struct gbproxy_peer *peer, *tmp;</span><br><span style="color: hsl(120, 100%, 40%);">+ llist_for_each_entry_safe(peer, tmp, &nse->bts_peers, list)</span><br><span style="color: hsl(120, 100%, 40%);">+ gbproxy_peer_free(peer);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ gbproxy_nse_free(nse);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span> </span><br><span> rate_ctr_group_free(cfg->ctrg);</span><br><span> gbproxy_init_config(cfg);</span><br><span>@@ -1538,7 +1588,7 @@</span><br><span> {</span><br><span> struct timespec tp;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- INIT_LLIST_HEAD(&cfg->bts_peers);</span><br><span style="color: hsl(120, 100%, 40%);">+ INIT_LLIST_HEAD(&cfg->nse_peers);</span><br><span> cfg->ctrg = rate_ctr_group_alloc(tall_sgsn_ctx, &global_ctrg_desc, 0);</span><br><span> if (!cfg->ctrg) {</span><br><span> LOGP(DGPRS, LOGL_ERROR, "Cannot allocate global counter group!\n");</span><br><span>diff --git a/src/gbproxy/gb_proxy_ctrl.c b/src/gbproxy/gb_proxy_ctrl.c</span><br><span>index 9577383..482bca0 100644</span><br><span>--- a/src/gbproxy/gb_proxy_ctrl.c</span><br><span>+++ b/src/gbproxy/gb_proxy_ctrl.c</span><br><span>@@ -55,7 +55,7 @@</span><br><span> struct gbproxy_config *cfg = data;</span><br><span> struct gprs_ns2_inst *nsi = cfg->nsi;</span><br><span> struct gprs_ns2_nse *nse;</span><br><span style="color: hsl(0, 100%, 40%);">- struct gbproxy_peer *peer;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct gbproxy_nse *nse_peer;</span><br><span> </span><br><span> cmd->reply = talloc_strdup(cmd, "");</span><br><span> </span><br><span>@@ -69,8 +69,8 @@</span><br><span> gprs_ns2_nse_foreach_nsvc(nse, &ctrl_nsvc_state_cb, cmd);</span><br><span> </span><br><span> /* NS-VCs for BSS peers */</span><br><span style="color: hsl(0, 100%, 40%);">- llist_for_each_entry(peer, &cfg->bts_peers, list) {</span><br><span style="color: hsl(0, 100%, 40%);">- nse = gprs_ns2_nse_by_nsei(nsi, peer->nsei);</span><br><span style="color: hsl(120, 100%, 40%);">+ llist_for_each_entry(nse_peer, &cfg->nse_peers, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+ nse = gprs_ns2_nse_by_nsei(nsi, nse_peer->nsei);</span><br><span> if (nse)</span><br><span> gprs_ns2_nse_foreach_nsvc(nse, &ctrl_nsvc_state_cb, cmd);</span><br><span> }</span><br><span>@@ -83,19 +83,22 @@</span><br><span> static int get_gbproxy_state(struct ctrl_cmd *cmd, void *data)</span><br><span> {</span><br><span> struct gbproxy_config *cfg = data;</span><br><span style="color: hsl(0, 100%, 40%);">- struct gbproxy_peer *peer;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct gbproxy_nse *nse_peer;</span><br><span> </span><br><span> cmd->reply = talloc_strdup(cmd, "");</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- llist_for_each_entry(peer, &cfg->bts_peers, list) {</span><br><span style="color: hsl(0, 100%, 40%);">- struct gprs_ra_id raid;</span><br><span style="color: hsl(0, 100%, 40%);">- gsm48_parse_ra(&raid, peer->ra);</span><br><span style="color: hsl(120, 100%, 40%);">+ llist_for_each_entry(nse_peer, &cfg->nse_peers, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+ struct gbproxy_peer *peer;</span><br><span style="color: hsl(120, 100%, 40%);">+ llist_for_each_entry(peer, &nse_peer->bts_peers, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+ struct gprs_ra_id raid;</span><br><span style="color: hsl(120, 100%, 40%);">+ gsm48_parse_ra(&raid, peer->ra);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- cmd->reply = talloc_asprintf_append(cmd->reply, "%u,%u,%u,%u,%u,%u,%s\n",</span><br><span style="color: hsl(0, 100%, 40%);">- peer->nsei, peer->bvci,</span><br><span style="color: hsl(0, 100%, 40%);">- raid.mcc, raid.mnc,</span><br><span style="color: hsl(0, 100%, 40%);">- raid.lac, raid.rac,</span><br><span style="color: hsl(0, 100%, 40%);">- peer->blocked ? "BLOCKED" : "UNBLOCKED");</span><br><span style="color: hsl(120, 100%, 40%);">+ cmd->reply = talloc_asprintf_append(cmd->reply, "%u,%u,%u,%u,%u,%u,%s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+ nse_peer->nsei, peer->bvci,</span><br><span style="color: hsl(120, 100%, 40%);">+ raid.mcc, raid.mnc,</span><br><span style="color: hsl(120, 100%, 40%);">+ raid.lac, raid.rac,</span><br><span style="color: hsl(120, 100%, 40%);">+ peer->blocked ? "BLOCKED" : "UNBLOCKED");</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span> }</span><br><span> </span><br><span> return CTRL_CMD_REPLY;</span><br><span>@@ -106,9 +109,14 @@</span><br><span> static int get_num_peers(struct ctrl_cmd *cmd, void *data)</span><br><span> {</span><br><span> struct gbproxy_config *cfg = data;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct gbproxy_nse *nse_peer;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint32_t count = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ llist_for_each_entry(nse_peer, &cfg->nse_peers, list)</span><br><span style="color: hsl(120, 100%, 40%);">+ count += llist_count(&nse_peer->bts_peers);</span><br><span> </span><br><span> cmd->reply = talloc_strdup(cmd, "");</span><br><span style="color: hsl(0, 100%, 40%);">- cmd->reply = talloc_asprintf_append(cmd->reply, "%u", llist_count(&cfg->bts_peers));</span><br><span style="color: hsl(120, 100%, 40%);">+ cmd->reply = talloc_asprintf_append(cmd->reply, "%u", count);</span><br><span> </span><br><span> return CTRL_CMD_REPLY;</span><br><span> }</span><br><span>diff --git a/src/gbproxy/gb_proxy_patch.c b/src/gbproxy/gb_proxy_patch.c</span><br><span>index 9c70d3f..6601657 100644</span><br><span>--- a/src/gbproxy/gb_proxy_patch.c</span><br><span>+++ b/src/gbproxy/gb_proxy_patch.c</span><br><span>@@ -44,6 +44,10 @@</span><br><span> GBPROX_PEER_CTR_RAID_PATCHED_SGSN :</span><br><span> GBPROX_PEER_CTR_RAID_PATCHED_BSS;</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(peer->nse);</span><br><span style="color: hsl(120, 100%, 40%);">+ struct gbproxy_config *cfg = peer->nse->cfg;</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(cfg);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> if (!state->local_plmn.mcc || !state->local_plmn.mnc)</span><br><span> return;</span><br><span> </span><br><span>@@ -58,11 +62,11 @@</span><br><span> if (!to_bss) {</span><br><span> /* BSS -> SGSN */</span><br><span> if (state->local_plmn.mcc)</span><br><span style="color: hsl(0, 100%, 40%);">- raid.mcc = peer->cfg->core_plmn.mcc;</span><br><span style="color: hsl(120, 100%, 40%);">+ raid.mcc = cfg->core_plmn.mcc;</span><br><span> </span><br><span> if (state->local_plmn.mnc) {</span><br><span style="color: hsl(0, 100%, 40%);">- raid.mnc = peer->cfg->core_plmn.mnc;</span><br><span style="color: hsl(0, 100%, 40%);">- raid.mnc_3_digits = peer->cfg->core_plmn.mnc_3_digits;</span><br><span style="color: hsl(120, 100%, 40%);">+ raid.mnc = cfg->core_plmn.mnc;</span><br><span style="color: hsl(120, 100%, 40%);">+ raid.mnc_3_digits = cfg->core_plmn.mnc_3_digits;</span><br><span> }</span><br><span> } else {</span><br><span> /* SGSN -> BSS */</span><br><span>@@ -100,11 +104,14 @@</span><br><span> </span><br><span> size_t apn_len = hdr->apn_len;</span><br><span> uint8_t *apn = hdr->apn;</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(peer->nse);</span><br><span style="color: hsl(120, 100%, 40%);">+ struct gbproxy_config *cfg = peer->nse->cfg;</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(cfg);</span><br><span> </span><br><span> OSMO_ASSERT(apn_ie_len == apn_len + sizeof(struct apn_ie_hdr));</span><br><span> OSMO_ASSERT(apn_ie_len > 2 && apn_ie_len <= 102);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- if (peer->cfg->core_apn_size == 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+ if (cfg->core_apn_size == 0) {</span><br><span> char str1[110];</span><br><span> /* Remove the IE */</span><br><span> LOGP(DGPRS, LOGL_DEBUG,</span><br><span>@@ -119,20 +126,20 @@</span><br><span> char str1[110];</span><br><span> char str2[110];</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- OSMO_ASSERT(peer->cfg->core_apn_size <= 100);</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(cfg->core_apn_size <= 100);</span><br><span> </span><br><span> LOGP(DGPRS, LOGL_DEBUG,</span><br><span> "Patching %s to SGSN: "</span><br><span> "Replacing APN '%s' -> '%s'\n",</span><br><span> log_text,</span><br><span> osmo_apn_to_str(str1, apn, apn_len),</span><br><span style="color: hsl(0, 100%, 40%);">- osmo_apn_to_str(str2, peer->cfg->core_apn,</span><br><span style="color: hsl(0, 100%, 40%);">- peer->cfg->core_apn_size));</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_apn_to_str(str2, cfg->core_apn,</span><br><span style="color: hsl(120, 100%, 40%);">+ cfg->core_apn_size));</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- *new_apn_ie_len = peer->cfg->core_apn_size + 2;</span><br><span style="color: hsl(0, 100%, 40%);">- msgb_resize_area(msg, apn, apn_len, peer->cfg->core_apn_size);</span><br><span style="color: hsl(0, 100%, 40%);">- memcpy(apn, peer->cfg->core_apn, peer->cfg->core_apn_size);</span><br><span style="color: hsl(0, 100%, 40%);">- hdr->apn_len = peer->cfg->core_apn_size;</span><br><span style="color: hsl(120, 100%, 40%);">+ *new_apn_ie_len = cfg->core_apn_size + 2;</span><br><span style="color: hsl(120, 100%, 40%);">+ msgb_resize_area(msg, apn, apn_len, cfg->core_apn_size);</span><br><span style="color: hsl(120, 100%, 40%);">+ memcpy(apn, cfg->core_apn, cfg->core_apn_size);</span><br><span style="color: hsl(120, 100%, 40%);">+ hdr->apn_len = cfg->core_apn_size;</span><br><span> }</span><br><span> </span><br><span> rate_ctr_inc(&peer->ctrg->ctr[GBPROX_PEER_CTR_APN_PATCHED]);</span><br><span>@@ -207,10 +214,12 @@</span><br><span> struct gprs_llc_hdr_parsed *ghp = &parse_ctx->llc_hdr_parsed;</span><br><span> int have_patched = 0;</span><br><span> int fcs;</span><br><span style="color: hsl(0, 100%, 40%);">- struct gbproxy_config *cfg = peer->cfg;</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(peer->nse);</span><br><span style="color: hsl(120, 100%, 40%);">+ struct gbproxy_config *cfg = peer->nse->cfg;</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(cfg);</span><br><span> </span><br><span> if (parse_ctx->ptmsi_enc && link_info &&</span><br><span style="color: hsl(0, 100%, 40%);">- !parse_ctx->old_raid_is_foreign && peer->cfg->patch_ptmsi) {</span><br><span style="color: hsl(120, 100%, 40%);">+ !parse_ctx->old_raid_is_foreign && cfg->patch_ptmsi) {</span><br><span> uint32_t ptmsi;</span><br><span> if (parse_ctx->to_bss)</span><br><span> ptmsi = link_info->tlli.ptmsi;</span><br><span>@@ -291,13 +300,16 @@</span><br><span> {</span><br><span> const char *err_info = NULL;</span><br><span> int err_ctr = -1;</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(peer->nse);</span><br><span style="color: hsl(120, 100%, 40%);">+ struct gbproxy_config *cfg = peer->nse->cfg;</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(cfg);</span><br><span> </span><br><span> if (parse_ctx->bssgp_raid_enc)</span><br><span> gbproxy_patch_raid((struct gsm48_ra_id *)parse_ctx->bssgp_raid_enc, peer,</span><br><span> parse_ctx->to_bss, "BSSGP");</span><br><span> </span><br><span> if (parse_ctx->need_decryption &&</span><br><span style="color: hsl(0, 100%, 40%);">- (peer->cfg->patch_ptmsi || peer->cfg->core_apn)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ (cfg->patch_ptmsi || cfg->core_apn)) {</span><br><span> /* Patching LLC messages has been requested</span><br><span> * explicitly, but the message (including the</span><br><span> * type) is encrypted, so we possibly fail to</span><br><span>@@ -319,7 +331,7 @@</span><br><span> if (!link_info)</span><br><span> return;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- if (parse_ctx->tlli_enc && peer->cfg->patch_ptmsi) {</span><br><span style="color: hsl(120, 100%, 40%);">+ if (parse_ctx->tlli_enc && cfg->patch_ptmsi) {</span><br><span> uint32_t tlli = gbproxy_map_tlli(parse_ctx->tlli,</span><br><span> link_info, parse_ctx->to_bss);</span><br><span> </span><br><span>@@ -335,7 +347,7 @@</span><br><span> }</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- if (parse_ctx->bssgp_ptmsi_enc && peer->cfg->patch_ptmsi) {</span><br><span style="color: hsl(120, 100%, 40%);">+ if (parse_ctx->bssgp_ptmsi_enc && cfg->patch_ptmsi) {</span><br><span> uint32_t ptmsi;</span><br><span> if (parse_ctx->to_bss)</span><br><span> ptmsi = link_info->tlli.ptmsi;</span><br><span>diff --git a/src/gbproxy/gb_proxy_peer.c b/src/gbproxy/gb_proxy_peer.c</span><br><span>index cb76a59..920547c 100644</span><br><span>--- a/src/gbproxy/gb_proxy_peer.c</span><br><span>+++ b/src/gbproxy/gb_proxy_peer.c</span><br><span>@@ -81,25 +81,30 @@</span><br><span> };</span><br><span> </span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-/* Find the gbprox_peer by its BVCI */</span><br><span style="color: hsl(120, 100%, 40%);">+/* Find the gbproxy_peer by its BVCI. There can only be one match */</span><br><span> struct gbproxy_peer *gbproxy_peer_by_bvci(struct gbproxy_config *cfg, uint16_t bvci)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">- struct gbproxy_peer *peer;</span><br><span style="color: hsl(0, 100%, 40%);">- llist_for_each_entry(peer, &cfg->bts_peers, list) {</span><br><span style="color: hsl(0, 100%, 40%);">- if (peer->bvci == bvci)</span><br><span style="color: hsl(0, 100%, 40%);">- return peer;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct gbproxy_nse *nse;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ llist_for_each_entry(nse, &cfg->nse_peers, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+ struct gbproxy_peer *peer;</span><br><span style="color: hsl(120, 100%, 40%);">+ llist_for_each_entry(peer, &nse->bts_peers, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+ if (peer->bvci == bvci)</span><br><span style="color: hsl(120, 100%, 40%);">+ return peer;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span> }</span><br><span> return NULL;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-/* Find the gbprox_peer by its NSEI */</span><br><span style="color: hsl(120, 100%, 40%);">+/* Find the gbproxy_peer by its NSEI */</span><br><span style="color: hsl(120, 100%, 40%);">+/* FIXME: Only returns the first peer, but we could have multiple on this nsei */</span><br><span> struct gbproxy_peer *gbproxy_peer_by_nsei(struct gbproxy_config *cfg,</span><br><span> uint16_t nsei)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">- struct gbproxy_peer *peer;</span><br><span style="color: hsl(0, 100%, 40%);">- llist_for_each_entry(peer, &cfg->bts_peers, list) {</span><br><span style="color: hsl(0, 100%, 40%);">- if (peer->nsei == nsei)</span><br><span style="color: hsl(0, 100%, 40%);">- return peer;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct gbproxy_nse *nse;</span><br><span style="color: hsl(120, 100%, 40%);">+ llist_for_each_entry(nse, &cfg->nse_peers, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+ if (nse->nsei == nsei && !llist_empty(&nse->bts_peers))</span><br><span style="color: hsl(120, 100%, 40%);">+ return llist_first_entry(&nse->bts_peers, struct gbproxy_peer, list);</span><br><span> }</span><br><span> return NULL;</span><br><span> }</span><br><span>@@ -109,11 +114,16 @@</span><br><span> struct gbproxy_peer *gbproxy_peer_by_rai(struct gbproxy_config *cfg,</span><br><span> const uint8_t *ra)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">- struct gbproxy_peer *peer;</span><br><span style="color: hsl(0, 100%, 40%);">- llist_for_each_entry(peer, &cfg->bts_peers, list) {</span><br><span style="color: hsl(0, 100%, 40%);">- if (!memcmp(peer->ra, ra, 6))</span><br><span style="color: hsl(0, 100%, 40%);">- return peer;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct gbproxy_nse *nse;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ llist_for_each_entry(nse, &cfg->nse_peers, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+ struct gbproxy_peer *peer;</span><br><span style="color: hsl(120, 100%, 40%);">+ llist_for_each_entry(peer, &nse->bts_peers, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!memcmp(peer->ra, ra, 6))</span><br><span style="color: hsl(120, 100%, 40%);">+ return peer;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span> }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> return NULL;</span><br><span> }</span><br><span> </span><br><span>@@ -122,10 +132,14 @@</span><br><span> struct gbproxy_peer *gbproxy_peer_by_lai(struct gbproxy_config *cfg,</span><br><span> const uint8_t *la)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">- struct gbproxy_peer *peer;</span><br><span style="color: hsl(0, 100%, 40%);">- llist_for_each_entry(peer, &cfg->bts_peers, list) {</span><br><span style="color: hsl(0, 100%, 40%);">- if (!memcmp(peer->ra, la, 5))</span><br><span style="color: hsl(0, 100%, 40%);">- return peer;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct gbproxy_nse *nse;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ llist_for_each_entry(nse, &cfg->nse_peers, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+ struct gbproxy_peer *peer;</span><br><span style="color: hsl(120, 100%, 40%);">+ llist_for_each_entry(peer, &nse->bts_peers, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!memcmp(peer->ra, la, 5))</span><br><span style="color: hsl(120, 100%, 40%);">+ return peer;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span> }</span><br><span> return NULL;</span><br><span> }</span><br><span>@@ -135,10 +149,14 @@</span><br><span> struct gbproxy_peer *gbproxy_peer_by_lac(struct gbproxy_config *cfg,</span><br><span> const uint8_t *la)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">- struct gbproxy_peer *peer;</span><br><span style="color: hsl(0, 100%, 40%);">- llist_for_each_entry(peer, &cfg->bts_peers, list) {</span><br><span style="color: hsl(0, 100%, 40%);">- if (!memcmp(peer->ra + 3, la + 3, 2))</span><br><span style="color: hsl(0, 100%, 40%);">- return peer;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct gbproxy_nse *nse;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ llist_for_each_entry(nse, &cfg->nse_peers, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+ struct gbproxy_peer *peer;</span><br><span style="color: hsl(120, 100%, 40%);">+ llist_for_each_entry(peer, &nse->bts_peers, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!memcmp(peer->ra + 3, la + 3, 2))</span><br><span style="color: hsl(120, 100%, 40%);">+ return peer;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span> }</span><br><span> return NULL;</span><br><span> }</span><br><span>@@ -177,18 +195,25 @@</span><br><span> time_t now;</span><br><span> struct timespec ts = {0,};</span><br><span> struct gbproxy_peer *peer = (struct gbproxy_peer *) data;</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(peer);</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(peer->nse);</span><br><span style="color: hsl(120, 100%, 40%);">+ struct gbproxy_config *cfg = peer->nse->cfg;</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(cfg);</span><br><span> </span><br><span> osmo_clock_gettime(CLOCK_MONOTONIC, &ts);</span><br><span> now = ts.tv_sec;</span><br><span> gbproxy_remove_stale_link_infos(peer, now);</span><br><span style="color: hsl(0, 100%, 40%);">- if (peer->cfg->clean_stale_timer_freq != 0)</span><br><span style="color: hsl(120, 100%, 40%);">+ if (cfg->clean_stale_timer_freq != 0)</span><br><span> osmo_timer_schedule(&peer->clean_stale_timer,</span><br><span style="color: hsl(0, 100%, 40%);">- peer->cfg->clean_stale_timer_freq, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+ cfg->clean_stale_timer_freq, 0);</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-struct gbproxy_peer *gbproxy_peer_alloc(struct gbproxy_config *cfg, uint16_t bvci)</span><br><span style="color: hsl(120, 100%, 40%);">+struct gbproxy_peer *gbproxy_peer_alloc(struct gbproxy_nse *nse, uint16_t bvci)</span><br><span> {</span><br><span> struct gbproxy_peer *peer;</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(nse);</span><br><span style="color: hsl(120, 100%, 40%);">+ struct gbproxy_config *cfg = nse->cfg;</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(cfg);</span><br><span> </span><br><span> peer = talloc_zero(tall_sgsn_ctx, struct gbproxy_peer);</span><br><span> if (!peer)</span><br><span>@@ -200,22 +225,24 @@</span><br><span> talloc_free(peer);</span><br><span> return NULL;</span><br><span> }</span><br><span style="color: hsl(0, 100%, 40%);">- peer->cfg = cfg;</span><br><span style="color: hsl(120, 100%, 40%);">+ peer->nse = nse;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- llist_add(&peer->list, &cfg->bts_peers);</span><br><span style="color: hsl(120, 100%, 40%);">+ llist_add(&peer->list, &nse->bts_peers);</span><br><span> </span><br><span> INIT_LLIST_HEAD(&peer->patch_state.logical_links);</span><br><span> </span><br><span> osmo_timer_setup(&peer->clean_stale_timer, clean_stale_timer_cb, peer);</span><br><span style="color: hsl(0, 100%, 40%);">- if (peer->cfg->clean_stale_timer_freq != 0)</span><br><span style="color: hsl(120, 100%, 40%);">+ if (cfg->clean_stale_timer_freq != 0)</span><br><span> osmo_timer_schedule(&peer->clean_stale_timer,</span><br><span style="color: hsl(0, 100%, 40%);">- peer->cfg->clean_stale_timer_freq, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+ cfg->clean_stale_timer_freq, 0);</span><br><span> </span><br><span> return peer;</span><br><span> }</span><br><span> </span><br><span> void gbproxy_peer_free(struct gbproxy_peer *peer)</span><br><span> {</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(peer);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> llist_del(&peer->list);</span><br><span> osmo_timer_del(&peer->clean_stale_timer);</span><br><span> gbproxy_delete_link_infos(peer);</span><br><span>@@ -229,17 +256,78 @@</span><br><span> int gbproxy_cleanup_peers(struct gbproxy_config *cfg, uint16_t nsei, uint16_t bvci)</span><br><span> {</span><br><span> int counter = 0;</span><br><span style="color: hsl(0, 100%, 40%);">- struct gbproxy_peer *peer, *tmp;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct gbproxy_nse *nse, *ntmp;</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(cfg);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- llist_for_each_entry_safe(peer, tmp, &cfg->bts_peers, list) {</span><br><span style="color: hsl(0, 100%, 40%);">- if (peer->nsei != nsei)</span><br><span style="color: hsl(120, 100%, 40%);">+ llist_for_each_entry_safe(nse, ntmp, &cfg->nse_peers, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+ struct gbproxy_peer *peer, *tmp;</span><br><span style="color: hsl(120, 100%, 40%);">+ if (nse->nsei != nsei)</span><br><span> continue;</span><br><span style="color: hsl(0, 100%, 40%);">- if (bvci && peer->bvci != bvci)</span><br><span style="color: hsl(0, 100%, 40%);">- continue;</span><br><span style="color: hsl(120, 100%, 40%);">+ llist_for_each_entry_safe(peer, tmp, &nse->bts_peers, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+ if (bvci && peer->bvci != bvci)</span><br><span style="color: hsl(120, 100%, 40%);">+ continue;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- gbproxy_peer_free(peer);</span><br><span style="color: hsl(0, 100%, 40%);">- counter += 1;</span><br><span style="color: hsl(120, 100%, 40%);">+ gbproxy_peer_free(peer);</span><br><span style="color: hsl(120, 100%, 40%);">+ counter += 1;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span> }</span><br><span> </span><br><span> return counter;</span><br><span> }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct gbproxy_nse *gbproxy_nse_alloc(struct gbproxy_config *cfg, uint16_t nsei)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct gbproxy_nse *nse;</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(cfg);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ nse = talloc_zero(tall_sgsn_ctx, struct gbproxy_nse);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!nse)</span><br><span style="color: hsl(120, 100%, 40%);">+ return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ nse->nsei = nsei;</span><br><span style="color: hsl(120, 100%, 40%);">+ nse->cfg = cfg;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ llist_add(&nse->list, &cfg->nse_peers);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ INIT_LLIST_HEAD(&nse->bts_peers);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ return nse;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void gbproxy_nse_free(struct gbproxy_nse *nse)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct gbproxy_peer *peer, *tmp;</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(nse);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ llist_del(&nse->list);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ llist_for_each_entry_safe(peer, tmp, &nse->bts_peers, list)</span><br><span style="color: hsl(120, 100%, 40%);">+ gbproxy_peer_free(peer);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ talloc_free(nse);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct gbproxy_nse *gbproxy_nse_by_nsei(struct gbproxy_config *cfg, uint16_t nsei)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct gbproxy_nse *nse;</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(cfg);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ llist_for_each_entry(nse, &cfg->nse_peers, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+ if (nse->nsei == nsei)</span><br><span style="color: hsl(120, 100%, 40%);">+ return nse;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct gbproxy_nse *gbproxy_nse_by_nsei_or_new(struct gbproxy_config *cfg, uint16_t nsei)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct gbproxy_nse *nse;</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(cfg);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ nse = gbproxy_nse_by_nsei(cfg, nsei);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!nse)</span><br><span style="color: hsl(120, 100%, 40%);">+ nse = gbproxy_nse_alloc(cfg, nsei);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ return nse;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span>\ No newline at end of file</span><br><span>diff --git a/src/gbproxy/gb_proxy_tlli.c b/src/gbproxy/gb_proxy_tlli.c</span><br><span>index e9271c2..9487459 100644</span><br><span>--- a/src/gbproxy/gb_proxy_tlli.c</span><br><span>+++ b/src/gbproxy/gb_proxy_tlli.c</span><br><span>@@ -183,12 +183,15 @@</span><br><span> int exceeded_max_len = 0;</span><br><span> int deleted_count = 0;</span><br><span> int check_for_age;</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(peer->nse);</span><br><span style="color: hsl(120, 100%, 40%);">+ struct gbproxy_config *cfg = peer->nse->cfg;</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(cfg);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- if (peer->cfg->tlli_max_len > 0)</span><br><span style="color: hsl(120, 100%, 40%);">+ if (cfg->tlli_max_len > 0)</span><br><span> exceeded_max_len =</span><br><span style="color: hsl(0, 100%, 40%);">- state->logical_link_count - peer->cfg->tlli_max_len;</span><br><span style="color: hsl(120, 100%, 40%);">+ state->logical_link_count - cfg->tlli_max_len;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- check_for_age = peer->cfg->tlli_max_age > 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ check_for_age = cfg->tlli_max_age > 0;</span><br><span> </span><br><span> for (; exceeded_max_len > 0; exceeded_max_len--) {</span><br><span> struct gbproxy_link_info *link_info;</span><br><span>@@ -213,7 +216,7 @@</span><br><span> list);</span><br><span> age = now - link_info->timestamp;</span><br><span> /* age < 0 only happens after system time jumps, discard entry */</span><br><span style="color: hsl(0, 100%, 40%);">- if (age <= peer->cfg->tlli_max_age && age >= 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+ if (age <= cfg->tlli_max_age && age >= 0) {</span><br><span> check_for_age = 0;</span><br><span> continue;</span><br><span> }</span><br><span>@@ -395,6 +398,9 @@</span><br><span> int imsi_matches;</span><br><span> struct gbproxy_link_info *other_link_info;</span><br><span> enum gbproxy_match_id match_id;</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(peer->nse);</span><br><span style="color: hsl(120, 100%, 40%);">+ struct gbproxy_config *cfg = peer->nse->cfg;</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(cfg);</span><br><span> </span><br><span> /* Make sure that there is a second entry with the same IMSI */</span><br><span> other_link_info = gbproxy_link_info_by_imsi(</span><br><span>@@ -419,11 +425,11 @@</span><br><span> </span><br><span> /* Check, whether the IMSI matches */</span><br><span> OSMO_ASSERT(ARRAY_SIZE(link_info->is_matching) ==</span><br><span style="color: hsl(0, 100%, 40%);">- ARRAY_SIZE(peer->cfg->matches));</span><br><span style="color: hsl(120, 100%, 40%);">+ ARRAY_SIZE(cfg->matches));</span><br><span> for (match_id = 0; match_id < ARRAY_SIZE(link_info->is_matching);</span><br><span> ++match_id) {</span><br><span> imsi_matches = gbproxy_check_imsi(</span><br><span style="color: hsl(0, 100%, 40%);">- &peer->cfg->matches[match_id],</span><br><span style="color: hsl(120, 100%, 40%);">+ &cfg->matches[match_id],</span><br><span> parse_ctx->imsi, parse_ctx->imsi_len);</span><br><span> if (imsi_matches >= 0)</span><br><span> link_info->is_matching[match_id] = imsi_matches ? true : false;</span><br><span>@@ -590,6 +596,9 @@</span><br><span> struct gprs_gb_parse_context *parse_ctx)</span><br><span> {</span><br><span> struct gbproxy_link_info *link_info = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(peer->nse);</span><br><span style="color: hsl(120, 100%, 40%);">+ struct gbproxy_config *cfg = peer->nse->cfg;</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(cfg);</span><br><span> </span><br><span> link_info = gbproxy_get_link_info_dl(peer, parse_ctx);</span><br><span> </span><br><span>@@ -613,7 +622,7 @@</span><br><span> link_info->sgsn_tlli.ptmsi = new_sgsn_ptmsi;</span><br><span> link_info->tlli.ptmsi = new_bss_ptmsi;</span><br><span> } else if (parse_ctx->tlli_enc && parse_ctx->new_ptmsi_enc && !link_info &&</span><br><span style="color: hsl(0, 100%, 40%);">- !peer->cfg->patch_ptmsi) {</span><br><span style="color: hsl(120, 100%, 40%);">+ !cfg->patch_ptmsi) {</span><br><span> /* A new P-TMSI has been signalled in the message with an unknown</span><br><span> * TLLI, create a new link_info */</span><br><span> /* TODO: Add a test case for this branch */</span><br><span>@@ -631,7 +640,7 @@</span><br><span> link_info->tlli.ptmsi = new_ptmsi;</span><br><span> gbproxy_attach_link_info(peer, now, link_info);</span><br><span> } else if (parse_ctx->tlli_enc && parse_ctx->llc && !link_info &&</span><br><span style="color: hsl(0, 100%, 40%);">- !peer->cfg->patch_ptmsi) {</span><br><span style="color: hsl(120, 100%, 40%);">+ !cfg->patch_ptmsi) {</span><br><span> /* Unknown SGSN TLLI, create a new link_info */</span><br><span> uint32_t new_ptmsi;</span><br><span> link_info = gbproxy_link_info_alloc(peer);</span><br><span>@@ -677,12 +686,16 @@</span><br><span> struct gprs_gb_parse_context *parse_ctx)</span><br><span> {</span><br><span> int rc = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(peer->nse);</span><br><span style="color: hsl(120, 100%, 40%);">+ struct gbproxy_config *cfg = peer->nse->cfg;</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(cfg);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> if (parse_ctx->invalidate_tlli && link_info) {</span><br><span> int keep_info =</span><br><span style="color: hsl(0, 100%, 40%);">- peer->cfg->keep_link_infos == GBPROX_KEEP_ALWAYS ||</span><br><span style="color: hsl(0, 100%, 40%);">- (peer->cfg->keep_link_infos == GBPROX_KEEP_REATTACH &&</span><br><span style="color: hsl(120, 100%, 40%);">+ cfg->keep_link_infos == GBPROX_KEEP_ALWAYS ||</span><br><span style="color: hsl(120, 100%, 40%);">+ (cfg->keep_link_infos == GBPROX_KEEP_REATTACH &&</span><br><span> parse_ctx->await_reattach) ||</span><br><span style="color: hsl(0, 100%, 40%);">- (peer->cfg->keep_link_infos == GBPROX_KEEP_IDENTIFIED &&</span><br><span style="color: hsl(120, 100%, 40%);">+ (cfg->keep_link_infos == GBPROX_KEEP_IDENTIFIED &&</span><br><span> link_info->imsi_len > 0);</span><br><span> if (keep_info) {</span><br><span> LOGP(DGPRS, LOGL_INFO, "Unregistering TLLI %08x\n",</span><br><span>diff --git a/src/gbproxy/gb_proxy_vty.c b/src/gbproxy/gb_proxy_vty.c</span><br><span>index 236d5d3..caad52e 100644</span><br><span>--- a/src/gbproxy/gb_proxy_vty.c</span><br><span>+++ b/src/gbproxy/gb_proxy_vty.c</span><br><span>@@ -73,7 +73,7 @@</span><br><span> gsm48_parse_ra(&raid, peer->ra);</span><br><span> </span><br><span> vty_out(vty, "NSEI %5u, PTP-BVCI %5u, "</span><br><span style="color: hsl(0, 100%, 40%);">- "RAI %s", peer->nsei, peer->bvci, osmo_rai_name(&raid));</span><br><span style="color: hsl(120, 100%, 40%);">+ "RAI %s", peer->nse->nsei, peer->bvci, osmo_rai_name(&raid));</span><br><span> if (peer->blocked)</span><br><span> vty_out(vty, " [BVC-BLOCKED]");</span><br><span> </span><br><span>@@ -420,16 +420,19 @@</span><br><span> GBPROXY_LINK_LIST_STR GBPROXY_CLEAN_STALE_TIMER_STR</span><br><span> "Frequency at which the periodic timer is fired (in seconds)\n")</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">- struct gbproxy_peer *peer;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct gbproxy_nse *nse;</span><br><span> g_cfg->clean_stale_timer_freq = (unsigned int) atoi(argv[0]);</span><br><span> </span><br><span> /* Re-schedule running timers soon in case prev frequency was really big</span><br><span> and new frequency is desired to be lower. After initial run, periodic</span><br><span> time is used. Use random() to avoid firing timers for all peers at</span><br><span> the same time */</span><br><span style="color: hsl(0, 100%, 40%);">- llist_for_each_entry(peer, &g_cfg->bts_peers, list)</span><br><span style="color: hsl(0, 100%, 40%);">- osmo_timer_schedule(&peer->clean_stale_timer,</span><br><span style="color: hsl(0, 100%, 40%);">- random() % 5, random() % 1000000);</span><br><span style="color: hsl(120, 100%, 40%);">+ llist_for_each_entry(nse, &g_cfg->nse_peers, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+ struct gbproxy_peer *peer;</span><br><span style="color: hsl(120, 100%, 40%);">+ llist_for_each_entry(peer, &nse->bts_peers, list)</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_timer_schedule(&peer->clean_stale_timer,</span><br><span style="color: hsl(120, 100%, 40%);">+ random() % 5, random() % 1000000);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span> </span><br><span> return CMD_SUCCESS;</span><br><span> }</span><br><span>@@ -440,11 +443,14 @@</span><br><span> NO_STR GBPROXY_LINK_LIST_STR GBPROXY_CLEAN_STALE_TIMER_STR)</span><br><span> </span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">- struct gbproxy_peer *peer;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct gbproxy_nse *nse;</span><br><span> g_cfg->clean_stale_timer_freq = 0;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- llist_for_each_entry(peer, &g_cfg->bts_peers, list)</span><br><span style="color: hsl(0, 100%, 40%);">- osmo_timer_del(&peer->clean_stale_timer);</span><br><span style="color: hsl(120, 100%, 40%);">+ llist_for_each_entry(nse, &g_cfg->nse_peers, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+ struct gbproxy_peer *peer;</span><br><span style="color: hsl(120, 100%, 40%);">+ llist_for_each_entry(peer, &nse->bts_peers, list)</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_timer_del(&peer->clean_stale_timer);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span> </span><br><span> return CMD_SUCCESS;</span><br><span> }</span><br><span>@@ -536,17 +542,20 @@</span><br><span> DEFUN(show_gbproxy, show_gbproxy_cmd, "show gbproxy [stats]",</span><br><span> SHOW_STR "Display information about the Gb proxy\n" "Show statistics\n")</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">- struct gbproxy_peer *peer;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct gbproxy_nse *nse;</span><br><span> int show_stats = argc >= 1;</span><br><span> </span><br><span> if (show_stats)</span><br><span> vty_out_rate_ctr_group(vty, "", g_cfg->ctrg);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- llist_for_each_entry(peer, &g_cfg->bts_peers, list) {</span><br><span style="color: hsl(0, 100%, 40%);">- gbprox_vty_print_peer(vty, peer);</span><br><span style="color: hsl(120, 100%, 40%);">+ llist_for_each_entry(nse, &g_cfg->nse_peers, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+ struct gbproxy_peer *peer;</span><br><span style="color: hsl(120, 100%, 40%);">+ llist_for_each_entry(peer, &nse->bts_peers, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+ gbprox_vty_print_peer(vty, peer);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- if (show_stats)</span><br><span style="color: hsl(0, 100%, 40%);">- vty_out_rate_ctr_group(vty, " ", peer->ctrg);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (show_stats)</span><br><span style="color: hsl(120, 100%, 40%);">+ vty_out_rate_ctr_group(vty, " ", peer->ctrg);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span> }</span><br><span> return CMD_SUCCESS;</span><br><span> }</span><br><span>@@ -554,49 +563,52 @@</span><br><span> DEFUN(show_gbproxy_links, show_gbproxy_links_cmd, "show gbproxy links",</span><br><span> SHOW_STR "Display information about the Gb proxy\n" "Show logical links\n")</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">- struct gbproxy_peer *peer;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct gbproxy_nse *nse;</span><br><span> time_t now;</span><br><span> struct timespec ts = {0,};</span><br><span> </span><br><span> osmo_clock_gettime(CLOCK_MONOTONIC, &ts);</span><br><span> now = ts.tv_sec;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- llist_for_each_entry(peer, &g_cfg->bts_peers, list) {</span><br><span style="color: hsl(0, 100%, 40%);">- struct gbproxy_link_info *link_info;</span><br><span style="color: hsl(0, 100%, 40%);">- struct gbproxy_patch_state *state = &peer->patch_state;</span><br><span style="color: hsl(120, 100%, 40%);">+ llist_for_each_entry(nse, &g_cfg->nse_peers, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+ struct gbproxy_peer *peer;</span><br><span style="color: hsl(120, 100%, 40%);">+ llist_for_each_entry(peer, &nse->bts_peers, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+ struct gbproxy_link_info *link_info;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct gbproxy_patch_state *state = &peer->patch_state;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- gbprox_vty_print_peer(vty, peer);</span><br><span style="color: hsl(120, 100%, 40%);">+ gbprox_vty_print_peer(vty, peer);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- llist_for_each_entry(link_info, &state->logical_links, list) {</span><br><span style="color: hsl(0, 100%, 40%);">- time_t age = now - link_info->timestamp;</span><br><span style="color: hsl(0, 100%, 40%);">- struct osmo_mobile_identity mi;</span><br><span style="color: hsl(0, 100%, 40%);">- const char *imsi_str;</span><br><span style="color: hsl(120, 100%, 40%);">+ llist_for_each_entry(link_info, &state->logical_links, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+ time_t age = now - link_info->timestamp;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_mobile_identity mi;</span><br><span style="color: hsl(120, 100%, 40%);">+ const char *imsi_str;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- if (link_info->imsi > 0) {</span><br><span style="color: hsl(0, 100%, 40%);">- if (osmo_mobile_identity_decode(&mi, link_info->imsi, link_info->imsi_len, false)</span><br><span style="color: hsl(0, 100%, 40%);">- || mi.type != GSM_MI_TYPE_IMSI)</span><br><span style="color: hsl(0, 100%, 40%);">- imsi_str = "(invalid)";</span><br><span style="color: hsl(0, 100%, 40%);">- else</span><br><span style="color: hsl(0, 100%, 40%);">- imsi_str = mi.imsi;</span><br><span style="color: hsl(0, 100%, 40%);">- } else {</span><br><span style="color: hsl(0, 100%, 40%);">- imsi_str = "(none)";</span><br><span style="color: hsl(120, 100%, 40%);">+ if (link_info->imsi > 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+ if (osmo_mobile_identity_decode(&mi, link_info->imsi, link_info->imsi_len, false)</span><br><span style="color: hsl(120, 100%, 40%);">+ || mi.type != GSM_MI_TYPE_IMSI)</span><br><span style="color: hsl(120, 100%, 40%);">+ imsi_str = "(invalid)";</span><br><span style="color: hsl(120, 100%, 40%);">+ else</span><br><span style="color: hsl(120, 100%, 40%);">+ imsi_str = mi.imsi;</span><br><span style="color: hsl(120, 100%, 40%);">+ } else {</span><br><span style="color: hsl(120, 100%, 40%);">+ imsi_str = "(none)";</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ vty_out(vty, " TLLI %08x, IMSI %s, AGE %d",</span><br><span style="color: hsl(120, 100%, 40%);">+ link_info->tlli.current, imsi_str, (int)age);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (link_info->stored_msgs_len)</span><br><span style="color: hsl(120, 100%, 40%);">+ vty_out(vty, ", STORED %"PRIu32"/%"PRIu32,</span><br><span style="color: hsl(120, 100%, 40%);">+ link_info->stored_msgs_len,</span><br><span style="color: hsl(120, 100%, 40%);">+ g_cfg->stored_msgs_max_len);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (g_cfg->route_to_sgsn2)</span><br><span style="color: hsl(120, 100%, 40%);">+ vty_out(vty, ", SGSN NSEI %d",</span><br><span style="color: hsl(120, 100%, 40%);">+ link_info->sgsn_nsei);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (link_info->is_deregistered)</span><br><span style="color: hsl(120, 100%, 40%);">+ vty_out(vty, ", DE-REGISTERED");</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ vty_out(vty, "%s", VTY_NEWLINE);</span><br><span> }</span><br><span style="color: hsl(0, 100%, 40%);">- vty_out(vty, " TLLI %08x, IMSI %s, AGE %d",</span><br><span style="color: hsl(0, 100%, 40%);">- link_info->tlli.current, imsi_str, (int)age);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- if (link_info->stored_msgs_len)</span><br><span style="color: hsl(0, 100%, 40%);">- vty_out(vty, ", STORED %"PRIu32"/%"PRIu32,</span><br><span style="color: hsl(0, 100%, 40%);">- link_info->stored_msgs_len,</span><br><span style="color: hsl(0, 100%, 40%);">- g_cfg->stored_msgs_max_len);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- if (g_cfg->route_to_sgsn2)</span><br><span style="color: hsl(0, 100%, 40%);">- vty_out(vty, ", SGSN NSEI %d",</span><br><span style="color: hsl(0, 100%, 40%);">- link_info->sgsn_nsei);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- if (link_info->is_deregistered)</span><br><span style="color: hsl(0, 100%, 40%);">- vty_out(vty, ", DE-REGISTERED");</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- vty_out(vty, "%s", VTY_NEWLINE);</span><br><span> }</span><br><span> }</span><br><span> return CMD_SUCCESS;</span><br><span>@@ -651,15 +663,17 @@</span><br><span> if (!dry_run)</span><br><span> counter = gbproxy_cleanup_peers(g_cfg, nsei, 0);</span><br><span> else {</span><br><span style="color: hsl(120, 100%, 40%);">+ struct gbproxy_nse *nse;</span><br><span> struct gbproxy_peer *peer;</span><br><span> counter = 0;</span><br><span style="color: hsl(0, 100%, 40%);">- llist_for_each_entry(peer, &g_cfg->bts_peers, list) {</span><br><span style="color: hsl(0, 100%, 40%);">- if (peer->nsei != nsei)</span><br><span style="color: hsl(120, 100%, 40%);">+ llist_for_each_entry(nse, &g_cfg->nse_peers, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+ if (nse->nsei != nsei)</span><br><span> continue;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- vty_out(vty, "BVC: ");</span><br><span style="color: hsl(0, 100%, 40%);">- gbprox_vty_print_peer(vty, peer);</span><br><span style="color: hsl(0, 100%, 40%);">- counter += 1;</span><br><span style="color: hsl(120, 100%, 40%);">+ llist_for_each_entry(peer, &nse->bts_peers, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+ vty_out(vty, "BVC: ");</span><br><span style="color: hsl(120, 100%, 40%);">+ gbprox_vty_print_peer(vty, peer);</span><br><span style="color: hsl(120, 100%, 40%);">+ counter += 1;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span> }</span><br><span> }</span><br><span> vty_out(vty, "%sDeleted %d BVC%s",</span><br><span>diff --git a/tests/gbproxy/gbproxy_test.c b/tests/gbproxy/gbproxy_test.c</span><br><span>index 78fa8cb..06734b4 100644</span><br><span>--- a/tests/gbproxy/gbproxy_test.c</span><br><span>+++ b/tests/gbproxy/gbproxy_test.c</span><br><span>@@ -118,7 +118,7 @@</span><br><span> static int dump_peers(FILE *stream, int indent, time_t now,</span><br><span> struct gbproxy_config *cfg)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">- struct gbproxy_peer *peer;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct gbproxy_nse *nse;</span><br><span> struct gprs_ra_id raid;</span><br><span> unsigned int i;</span><br><span> const struct rate_ctr_group_desc *desc;</span><br><span>@@ -128,98 +128,101 @@</span><br><span> if (rc < 0)</span><br><span> return rc;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- llist_for_each_entry(peer, &cfg->bts_peers, list) {</span><br><span style="color: hsl(0, 100%, 40%);">- struct gbproxy_link_info *link_info;</span><br><span style="color: hsl(0, 100%, 40%);">- struct gbproxy_patch_state *state = &peer->patch_state;</span><br><span style="color: hsl(0, 100%, 40%);">- gsm48_parse_ra(&raid, peer->ra);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- rc = fprintf(stream, "%*s NSEI %u, BVCI %u, %sblocked, RAI %s\n",</span><br><span style="color: hsl(0, 100%, 40%);">- indent, "",</span><br><span style="color: hsl(0, 100%, 40%);">- peer->nsei, peer->bvci,</span><br><span style="color: hsl(0, 100%, 40%);">- peer->blocked ? "" : "not ",</span><br><span style="color: hsl(0, 100%, 40%);">- osmo_rai_name(&raid));</span><br><span style="color: hsl(120, 100%, 40%);">+ llist_for_each_entry(nse, &cfg->nse_peers, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+ struct gbproxy_peer *peer;</span><br><span style="color: hsl(120, 100%, 40%);">+ llist_for_each_entry(peer, &nse->bts_peers, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+ struct gbproxy_link_info *link_info;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct gbproxy_patch_state *state = &peer->patch_state;</span><br><span style="color: hsl(120, 100%, 40%);">+ gsm48_parse_ra(&raid, peer->ra);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- if (rc < 0)</span><br><span style="color: hsl(0, 100%, 40%);">- return rc;</span><br><span style="color: hsl(120, 100%, 40%);">+ rc = fprintf(stream, "%*s NSEI %u, BVCI %u, %sblocked, RAI %s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+ indent, "",</span><br><span style="color: hsl(120, 100%, 40%);">+ nse->nsei, peer->bvci,</span><br><span style="color: hsl(120, 100%, 40%);">+ peer->blocked ? "" : "not ",</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_rai_name(&raid));</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- desc = peer->ctrg->desc;</span><br><span style="color: hsl(120, 100%, 40%);">+ if (rc < 0)</span><br><span style="color: hsl(120, 100%, 40%);">+ return rc;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- for (i = 0; i < desc->num_ctr; i++) {</span><br><span style="color: hsl(0, 100%, 40%);">- struct rate_ctr *ctr = &peer->ctrg->ctr[i];</span><br><span style="color: hsl(0, 100%, 40%);">- if (ctr->current) {</span><br><span style="color: hsl(0, 100%, 40%);">- rc = fprintf(stream, "%*s %s: %llu\n",</span><br><span style="color: hsl(0, 100%, 40%);">- indent, "",</span><br><span style="color: hsl(0, 100%, 40%);">- desc->ctr_desc[i].description,</span><br><span style="color: hsl(0, 100%, 40%);">- (long long)ctr->current);</span><br><span style="color: hsl(120, 100%, 40%);">+ desc = peer->ctrg->desc;</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ for (i = 0; i < desc->num_ctr; i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+ struct rate_ctr *ctr = &peer->ctrg->ctr[i];</span><br><span style="color: hsl(120, 100%, 40%);">+ if (ctr->current) {</span><br><span style="color: hsl(120, 100%, 40%);">+ rc = fprintf(stream, "%*s %s: %llu\n",</span><br><span style="color: hsl(120, 100%, 40%);">+ indent, "",</span><br><span style="color: hsl(120, 100%, 40%);">+ desc->ctr_desc[i].description,</span><br><span style="color: hsl(120, 100%, 40%);">+ (long long)ctr->current);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (rc < 0)</span><br><span style="color: hsl(120, 100%, 40%);">+ return rc;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ fprintf(stream, "%*s TLLI-Cache: %d\n",</span><br><span style="color: hsl(120, 100%, 40%);">+ indent, "", state->logical_link_count);</span><br><span style="color: hsl(120, 100%, 40%);">+ llist_for_each_entry(link_info, &state->logical_links, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_mobile_identity mi;</span><br><span style="color: hsl(120, 100%, 40%);">+ const char *imsi_str;</span><br><span style="color: hsl(120, 100%, 40%);">+ time_t age = now ? now - link_info->timestamp : 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ int stored_msgs = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct llist_head *iter;</span><br><span style="color: hsl(120, 100%, 40%);">+ enum gbproxy_match_id match_id;</span><br><span style="color: hsl(120, 100%, 40%);">+ llist_for_each(iter, &link_info->stored_msgs)</span><br><span style="color: hsl(120, 100%, 40%);">+ stored_msgs++;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (link_info->imsi > 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+ if (osmo_mobile_identity_decode(&mi, link_info->imsi, link_info->imsi_len, false)</span><br><span style="color: hsl(120, 100%, 40%);">+ || mi.type != GSM_MI_TYPE_IMSI)</span><br><span style="color: hsl(120, 100%, 40%);">+ imsi_str = "(invalid)";</span><br><span style="color: hsl(120, 100%, 40%);">+ else</span><br><span style="color: hsl(120, 100%, 40%);">+ imsi_str = mi.imsi;</span><br><span style="color: hsl(120, 100%, 40%);">+ } else {</span><br><span style="color: hsl(120, 100%, 40%);">+ imsi_str = "(none)";</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ fprintf(stream, "%*s TLLI %08x",</span><br><span style="color: hsl(120, 100%, 40%);">+ indent, "", link_info->tlli.current);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (link_info->tlli.assigned)</span><br><span style="color: hsl(120, 100%, 40%);">+ fprintf(stream, "/%08x", link_info->tlli.assigned);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (link_info->sgsn_tlli.current) {</span><br><span style="color: hsl(120, 100%, 40%);">+ fprintf(stream, " -> %08x",</span><br><span style="color: hsl(120, 100%, 40%);">+ link_info->sgsn_tlli.current);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (link_info->sgsn_tlli.assigned)</span><br><span style="color: hsl(120, 100%, 40%);">+ fprintf(stream, "/%08x",</span><br><span style="color: hsl(120, 100%, 40%);">+ link_info->sgsn_tlli.assigned);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ fprintf(stream, ", IMSI %s, AGE %d",</span><br><span style="color: hsl(120, 100%, 40%);">+ imsi_str, (int)age);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (stored_msgs)</span><br><span style="color: hsl(120, 100%, 40%);">+ fprintf(stream, ", STORED %d", stored_msgs);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ for (match_id = 0; match_id < ARRAY_SIZE(cfg->matches);</span><br><span style="color: hsl(120, 100%, 40%);">+ ++match_id) {</span><br><span style="color: hsl(120, 100%, 40%);">+ if (cfg->matches[match_id].enable &&</span><br><span style="color: hsl(120, 100%, 40%);">+ link_info->is_matching[match_id]) {</span><br><span style="color: hsl(120, 100%, 40%);">+ fprintf(stream, ", IMSI matches");</span><br><span style="color: hsl(120, 100%, 40%);">+ break;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (link_info->imsi_acq_pending)</span><br><span style="color: hsl(120, 100%, 40%);">+ fprintf(stream, ", IMSI acquisition in progress");</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (cfg->route_to_sgsn2)</span><br><span style="color: hsl(120, 100%, 40%);">+ fprintf(stream, ", SGSN NSEI %d",</span><br><span style="color: hsl(120, 100%, 40%);">+ link_info->sgsn_nsei);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (link_info->is_deregistered)</span><br><span style="color: hsl(120, 100%, 40%);">+ fprintf(stream, ", DE-REGISTERED");</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ rc = fprintf(stream, "\n");</span><br><span> if (rc < 0)</span><br><span> return rc;</span><br><span> }</span><br><span> }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- fprintf(stream, "%*s TLLI-Cache: %d\n",</span><br><span style="color: hsl(0, 100%, 40%);">- indent, "", state->logical_link_count);</span><br><span style="color: hsl(0, 100%, 40%);">- llist_for_each_entry(link_info, &state->logical_links, list) {</span><br><span style="color: hsl(0, 100%, 40%);">- struct osmo_mobile_identity mi;</span><br><span style="color: hsl(0, 100%, 40%);">- const char *imsi_str;</span><br><span style="color: hsl(0, 100%, 40%);">- time_t age = now ? now - link_info->timestamp : 0;</span><br><span style="color: hsl(0, 100%, 40%);">- int stored_msgs = 0;</span><br><span style="color: hsl(0, 100%, 40%);">- struct llist_head *iter;</span><br><span style="color: hsl(0, 100%, 40%);">- enum gbproxy_match_id match_id;</span><br><span style="color: hsl(0, 100%, 40%);">- llist_for_each(iter, &link_info->stored_msgs)</span><br><span style="color: hsl(0, 100%, 40%);">- stored_msgs++;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- if (link_info->imsi > 0) {</span><br><span style="color: hsl(0, 100%, 40%);">- if (osmo_mobile_identity_decode(&mi, link_info->imsi, link_info->imsi_len, false)</span><br><span style="color: hsl(0, 100%, 40%);">- || mi.type != GSM_MI_TYPE_IMSI)</span><br><span style="color: hsl(0, 100%, 40%);">- imsi_str = "(invalid)";</span><br><span style="color: hsl(0, 100%, 40%);">- else</span><br><span style="color: hsl(0, 100%, 40%);">- imsi_str = mi.imsi;</span><br><span style="color: hsl(0, 100%, 40%);">- } else {</span><br><span style="color: hsl(0, 100%, 40%);">- imsi_str = "(none)";</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">- fprintf(stream, "%*s TLLI %08x",</span><br><span style="color: hsl(0, 100%, 40%);">- indent, "", link_info->tlli.current);</span><br><span style="color: hsl(0, 100%, 40%);">- if (link_info->tlli.assigned)</span><br><span style="color: hsl(0, 100%, 40%);">- fprintf(stream, "/%08x", link_info->tlli.assigned);</span><br><span style="color: hsl(0, 100%, 40%);">- if (link_info->sgsn_tlli.current) {</span><br><span style="color: hsl(0, 100%, 40%);">- fprintf(stream, " -> %08x",</span><br><span style="color: hsl(0, 100%, 40%);">- link_info->sgsn_tlli.current);</span><br><span style="color: hsl(0, 100%, 40%);">- if (link_info->sgsn_tlli.assigned)</span><br><span style="color: hsl(0, 100%, 40%);">- fprintf(stream, "/%08x",</span><br><span style="color: hsl(0, 100%, 40%);">- link_info->sgsn_tlli.assigned);</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">- fprintf(stream, ", IMSI %s, AGE %d",</span><br><span style="color: hsl(0, 100%, 40%);">- imsi_str, (int)age);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- if (stored_msgs)</span><br><span style="color: hsl(0, 100%, 40%);">- fprintf(stream, ", STORED %d", stored_msgs);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- for (match_id = 0; match_id < ARRAY_SIZE(cfg->matches);</span><br><span style="color: hsl(0, 100%, 40%);">- ++match_id) {</span><br><span style="color: hsl(0, 100%, 40%);">- if (cfg->matches[match_id].enable &&</span><br><span style="color: hsl(0, 100%, 40%);">- link_info->is_matching[match_id]) {</span><br><span style="color: hsl(0, 100%, 40%);">- fprintf(stream, ", IMSI matches");</span><br><span style="color: hsl(0, 100%, 40%);">- break;</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- if (link_info->imsi_acq_pending)</span><br><span style="color: hsl(0, 100%, 40%);">- fprintf(stream, ", IMSI acquisition in progress");</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- if (cfg->route_to_sgsn2)</span><br><span style="color: hsl(0, 100%, 40%);">- fprintf(stream, ", SGSN NSEI %d",</span><br><span style="color: hsl(0, 100%, 40%);">- link_info->sgsn_nsei);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- if (link_info->is_deregistered)</span><br><span style="color: hsl(0, 100%, 40%);">- fprintf(stream, ", DE-REGISTERED");</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- rc = fprintf(stream, "\n");</span><br><span style="color: hsl(0, 100%, 40%);">- if (rc < 0)</span><br><span style="color: hsl(0, 100%, 40%);">- return rc;</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span> }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span> return 0;</span><br><span> }</span><br><span> </span><br><span>@@ -4210,7 +4213,7 @@</span><br><span> struct gbproxy_link_info *link_info;</span><br><span> int imsi_matches = -1;</span><br><span> int tlli_already_known = 0;</span><br><span style="color: hsl(0, 100%, 40%);">- struct gbproxy_config *cfg = peer->cfg;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct gbproxy_config *cfg = peer->nse->cfg;</span><br><span> </span><br><span> /* Check, whether the IMSI matches */</span><br><span> if (gprs_is_mi_imsi(imsi, imsi_len)) {</span><br><span>@@ -4259,6 +4262,7 @@</span><br><span> static void test_gbproxy_tlli_expire(void)</span><br><span> {</span><br><span> struct gbproxy_config cfg = {0};</span><br><span style="color: hsl(120, 100%, 40%);">+ struct gbproxy_nse *nse;</span><br><span> struct gbproxy_peer *peer;</span><br><span> const char *err_msg = NULL;</span><br><span> const uint8_t imsi1[] = { GSM_MI_TYPE_IMSI, 0x23, 0x24, 0x25, 0xf6 };</span><br><span>@@ -4273,6 +4277,7 @@</span><br><span> printf("Test TLLI info expiry\n\n");</span><br><span> </span><br><span> gbproxy_init_config(&cfg);</span><br><span style="color: hsl(120, 100%, 40%);">+ nse = gbproxy_nse_by_nsei_or_new(&cfg, 0);</span><br><span> </span><br><span> if (gbproxy_set_patch_filter(&cfg.matches[GBPROX_MATCH_PATCHING],</span><br><span> filter_re, &err_msg) != 0) {</span><br><span>@@ -4288,7 +4293,7 @@</span><br><span> </span><br><span> cfg.tlli_max_len = 0;</span><br><span> cfg.tlli_max_age = 0;</span><br><span style="color: hsl(0, 100%, 40%);">- peer = gbproxy_peer_alloc(&cfg, 20);</span><br><span style="color: hsl(120, 100%, 40%);">+ peer = gbproxy_peer_alloc(nse, 20);</span><br><span> OSMO_ASSERT(peer->patch_state.logical_link_count == 0);</span><br><span> </span><br><span> printf(" Add TLLI 1, IMSI 1\n");</span><br><span>@@ -4327,7 +4332,7 @@</span><br><span> </span><br><span> cfg.tlli_max_len = 0;</span><br><span> cfg.tlli_max_age = 0;</span><br><span style="color: hsl(0, 100%, 40%);">- peer = gbproxy_peer_alloc(&cfg, 20);</span><br><span style="color: hsl(120, 100%, 40%);">+ peer = gbproxy_peer_alloc(nse, 20);</span><br><span> OSMO_ASSERT(peer->patch_state.logical_link_count == 0);</span><br><span> </span><br><span> printf(" Add TLLI 1, IMSI 1\n");</span><br><span>@@ -4367,7 +4372,7 @@</span><br><span> </span><br><span> cfg.tlli_max_len = 1;</span><br><span> cfg.tlli_max_age = 0;</span><br><span style="color: hsl(0, 100%, 40%);">- peer = gbproxy_peer_alloc(&cfg, 20);</span><br><span style="color: hsl(120, 100%, 40%);">+ peer = gbproxy_peer_alloc(nse, 20);</span><br><span> OSMO_ASSERT(peer->patch_state.logical_link_count == 0);</span><br><span> </span><br><span> printf(" Add TLLI 1, IMSI 1\n");</span><br><span>@@ -4405,7 +4410,7 @@</span><br><span> </span><br><span> cfg.tlli_max_len = 0;</span><br><span> cfg.tlli_max_age = 1;</span><br><span style="color: hsl(0, 100%, 40%);">- peer = gbproxy_peer_alloc(&cfg, 20);</span><br><span style="color: hsl(120, 100%, 40%);">+ peer = gbproxy_peer_alloc(nse, 20);</span><br><span> OSMO_ASSERT(peer->patch_state.logical_link_count == 0);</span><br><span> </span><br><span> printf(" Add TLLI 1, IMSI 1 (should expire after timeout)\n");</span><br><span>@@ -4443,7 +4448,7 @@</span><br><span> </span><br><span> cfg.tlli_max_len = 0;</span><br><span> cfg.tlli_max_age = 1;</span><br><span style="color: hsl(0, 100%, 40%);">- peer = gbproxy_peer_alloc(&cfg, 20);</span><br><span style="color: hsl(120, 100%, 40%);">+ peer = gbproxy_peer_alloc(nse, 20);</span><br><span> OSMO_ASSERT(peer->patch_state.logical_link_count == 0);</span><br><span> </span><br><span> printf(" Add TLLI 1, IMSI 1 (should expire)\n");</span><br><span>diff --git a/tests/gbproxy/gbproxy_test.ok b/tests/gbproxy/gbproxy_test.ok</span><br><span>index 74cedb3..14a2641 100644</span><br><span>--- a/tests/gbproxy/gbproxy_test.ok</span><br><span>+++ b/tests/gbproxy/gbproxy_test.ok</span><br><span>@@ -96,10 +96,10 @@</span><br><span> [L2]> [L3]> 22 04 82 10 12 07 81 08 08 88 11 22 33 40 50 60 10 00 </span><br><span> </span><br><span> Peers:</span><br><span style="color: hsl(0, 100%, 40%);">- NSEI 4096, BVCI 4114, not blocked, RAI 112-332-16464-96</span><br><span style="color: hsl(0, 100%, 40%);">- TLLI-Cache: 0</span><br><span> NSEI 8192, BVCI 8194, not blocked, RAI 112-332-16464-96</span><br><span> TLLI-Cache: 0</span><br><span style="color: hsl(120, 100%, 40%);">+ NSEI 4096, BVCI 4114, not blocked, RAI 112-332-16464-96</span><br><span style="color: hsl(120, 100%, 40%);">+ TLLI-Cache: 0</span><br><span> NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96</span><br><span> TLLI-Cache: 0</span><br><span> PROCESSING BVC_RESET_ACK from NSEI 256</span><br><span>@@ -131,10 +131,10 @@</span><br><span> [L2]> [L3]> 22 04 82 10 02 07 81 08 08 88 11 22 33 40 50 60 10 00 </span><br><span> </span><br><span> Peers:</span><br><span style="color: hsl(0, 100%, 40%);">- NSEI 4096, BVCI 4114, not blocked, RAI 112-332-16464-96</span><br><span style="color: hsl(0, 100%, 40%);">- TLLI-Cache: 0</span><br><span> NSEI 8192, BVCI 8194, not blocked, RAI 112-332-16464-96</span><br><span> TLLI-Cache: 0</span><br><span style="color: hsl(120, 100%, 40%);">+ NSEI 4096, BVCI 4114, not blocked, RAI 112-332-16464-96</span><br><span style="color: hsl(120, 100%, 40%);">+ TLLI-Cache: 0</span><br><span> NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96</span><br><span> TLLI-Cache: 0</span><br><span> PROCESSING BVC_RESET_ACK from NSEI 256</span><br><span>@@ -166,10 +166,10 @@</span><br><span> [L2]> [L3]> 22 04 82 10 02 07 81 08 08 88 11 22 33 40 50 60 10 00 </span><br><span> </span><br><span> Peers:</span><br><span style="color: hsl(0, 100%, 40%);">- NSEI 4096, BVCI 4114, not blocked, RAI 112-332-16464-96</span><br><span style="color: hsl(0, 100%, 40%);">- TLLI-Cache: 0</span><br><span> NSEI 8192, BVCI 8194, not blocked, RAI 112-332-16464-96</span><br><span> TLLI-Cache: 0</span><br><span style="color: hsl(120, 100%, 40%);">+ NSEI 4096, BVCI 4114, not blocked, RAI 112-332-16464-96</span><br><span style="color: hsl(120, 100%, 40%);">+ TLLI-Cache: 0</span><br><span> NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96</span><br><span> TLLI-Cache: 0</span><br><span> PROCESSING BVC_RESET_ACK from NSEI 256</span><br><span>@@ -285,11 +285,11 @@</span><br><span> [L2]> [L3]> 22 04 82 10 02 07 81 08 08 88 11 22 33 40 50 60 10 00 </span><br><span> </span><br><span> Peers:</span><br><span style="color: hsl(0, 100%, 40%);">- NSEI 4096, BVCI 4114, not blocked, RAI 112-332-16464-96</span><br><span style="color: hsl(0, 100%, 40%);">- TLLI-Cache: 0</span><br><span> NSEI 8192, BVCI 8194, not blocked, RAI 112-332-16464-96</span><br><span> NSEI mismatch : 1</span><br><span> TLLI-Cache: 0</span><br><span style="color: hsl(120, 100%, 40%);">+ NSEI 4096, BVCI 4114, not blocked, RAI 112-332-16464-96</span><br><span style="color: hsl(120, 100%, 40%);">+ TLLI-Cache: 0</span><br><span> NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96</span><br><span> TLLI-Cache: 0</span><br><span> Gbproxy global:</span><br><span>@@ -517,11 +517,11 @@</span><br><span> [L2]> [L3]> 23 04 82 10 02 </span><br><span> </span><br><span> Peers:</span><br><span style="color: hsl(0, 100%, 40%);">- NSEI 4096, BVCI 8194, not blocked, RAI 112-332-16464-96</span><br><span style="color: hsl(0, 100%, 40%);">- TLLI-Cache: 0</span><br><span> NSEI 8192, BVCI 4098, not blocked, RAI 112-332-16464-96</span><br><span> NSEI mismatch : 1</span><br><span> TLLI-Cache: 0</span><br><span style="color: hsl(120, 100%, 40%);">+ NSEI 4096, BVCI 8194, not blocked, RAI 112-332-16464-96</span><br><span style="color: hsl(120, 100%, 40%);">+ TLLI-Cache: 0</span><br><span> --- Setup BVCI 3 ---</span><br><span> </span><br><span> Setup BSSGP: BVCI 0x3002(12290)</span><br><span>@@ -553,11 +553,11 @@</span><br><span> Peers:</span><br><span> NSEI 8192, BVCI 12290, not blocked, RAI 112-332-16464-96</span><br><span> TLLI-Cache: 0</span><br><span style="color: hsl(0, 100%, 40%);">- NSEI 4096, BVCI 8194, not blocked, RAI 112-332-16464-96</span><br><span style="color: hsl(0, 100%, 40%);">- TLLI-Cache: 0</span><br><span> NSEI 8192, BVCI 4098, not blocked, RAI 112-332-16464-96</span><br><span> NSEI mismatch : 1</span><br><span> TLLI-Cache: 0</span><br><span style="color: hsl(120, 100%, 40%);">+ NSEI 4096, BVCI 8194, not blocked, RAI 112-332-16464-96</span><br><span style="color: hsl(120, 100%, 40%);">+ TLLI-Cache: 0</span><br><span> --- Send message from BSS 1 to SGSN and back, BVCI 1 ---</span><br><span> </span><br><span> PROCESSING (null) from NSEI 8192</span><br><span>@@ -601,10 +601,10 @@</span><br><span> Peers:</span><br><span> NSEI 8192, BVCI 12290, not blocked, RAI 112-332-16464-96</span><br><span> TLLI-Cache: 0</span><br><span style="color: hsl(0, 100%, 40%);">- NSEI 4096, BVCI 8194, not blocked, RAI 112-332-16464-96</span><br><span style="color: hsl(120, 100%, 40%);">+ NSEI 8192, BVCI 4098, not blocked, RAI 112-332-16464-96</span><br><span> NSEI mismatch : 1</span><br><span> TLLI-Cache: 0</span><br><span style="color: hsl(0, 100%, 40%);">- NSEI 8192, BVCI 4098, not blocked, RAI 112-332-16464-96</span><br><span style="color: hsl(120, 100%, 40%);">+ NSEI 4096, BVCI 8194, not blocked, RAI 112-332-16464-96</span><br><span> NSEI mismatch : 1</span><br><span> TLLI-Cache: 0</span><br><span> PROCESSING (null) from NSEI 256</span><br><span>@@ -622,10 +622,10 @@</span><br><span> Peers:</span><br><span> NSEI 8192, BVCI 12290, not blocked, RAI 112-332-16464-96</span><br><span> TLLI-Cache: 0</span><br><span style="color: hsl(0, 100%, 40%);">- NSEI 4096, BVCI 8194, not blocked, RAI 112-332-16464-96</span><br><span style="color: hsl(120, 100%, 40%);">+ NSEI 8192, BVCI 4098, not blocked, RAI 112-332-16464-96</span><br><span> NSEI mismatch : 1</span><br><span> TLLI-Cache: 0</span><br><span style="color: hsl(0, 100%, 40%);">- NSEI 8192, BVCI 4098, not blocked, RAI 112-332-16464-96</span><br><span style="color: hsl(120, 100%, 40%);">+ NSEI 4096, BVCI 8194, not blocked, RAI 112-332-16464-96</span><br><span> NSEI mismatch : 1</span><br><span> TLLI-Cache: 0</span><br><span> --- Send message from BSS 1 to SGSN and back, BVCI 3 ---</span><br><span>@@ -659,10 +659,10 @@</span><br><span> NSEI 8192, BVCI 12290, not blocked, RAI 112-332-16464-96</span><br><span> NSEI mismatch : 1</span><br><span> TLLI-Cache: 0</span><br><span style="color: hsl(0, 100%, 40%);">- NSEI 4096, BVCI 8194, not blocked, RAI 112-332-16464-96</span><br><span style="color: hsl(120, 100%, 40%);">+ NSEI 8192, BVCI 4098, not blocked, RAI 112-332-16464-96</span><br><span> NSEI mismatch : 1</span><br><span> TLLI-Cache: 0</span><br><span style="color: hsl(0, 100%, 40%);">- NSEI 8192, BVCI 4098, not blocked, RAI 112-332-16464-96</span><br><span style="color: hsl(120, 100%, 40%);">+ NSEI 4096, BVCI 8194, not blocked, RAI 112-332-16464-96</span><br><span> NSEI mismatch : 1</span><br><span> TLLI-Cache: 0</span><br><span> === test_gbproxy_ra_patching ===</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.osmocom.org/c/osmo-sgsn/+/21406">change 21406</a>. To unsubscribe, or for help writing mail filters, visit <a href="https://gerrit.osmocom.org/settings">settings</a>.</p><div itemscope itemtype="http://schema.org/EmailMessage"><div itemscope itemprop="action" itemtype="http://schema.org/ViewAction"><link itemprop="url" href="https://gerrit.osmocom.org/c/osmo-sgsn/+/21406"/><meta itemprop="name" content="View Change"/></div></div>
<div style="display:none"> Gerrit-Project: osmo-sgsn </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-Change-Id: I97cc6c8f8c0f1b91577ab8f679c4ae217cc88076 </div>
<div style="display:none"> Gerrit-Change-Number: 21406 </div>
<div style="display:none"> Gerrit-PatchSet: 6 </div>
<div style="display:none"> Gerrit-Owner: daniel <dwillmann@sysmocom.de> </div>
<div style="display:none"> Gerrit-Reviewer: Jenkins Builder </div>
<div style="display:none"> Gerrit-Reviewer: laforge <laforge@osmocom.org> </div>
<div style="display:none"> Gerrit-Reviewer: lynxis lazus <lynxis@fe80.eu> </div>
<div style="display:none"> Gerrit-Reviewer: pespin <pespin@sysmocom.de> </div>
<div style="display:none"> Gerrit-MessageType: merged </div>