<p>daniel has uploaded this change for <strong>review</strong>.</p><p><a href="https://gerrit.osmocom.org/c/osmo-sgsn/+/21406">View Change</a></p><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>8 files changed, 315 insertions(+), 114 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">git pull ssh://gerrit.osmocom.org:29418/osmo-sgsn refs/changes/06/21406/1</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..ab9f3f3 100644</span><br><span>--- a/include/osmocom/sgsn/gb_proxy.h</span><br><span>+++ b/include/osmocom/sgsn/gb_proxy.h</span><br><span>@@ -15,6 +15,13 @@</span><br><span> </span><br><span> #define GBPROXY_INIT_VU_GEN_TX 256</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+/* Iterate through all BVCs of all NSEs</span><br><span style="color: hsl(120, 100%, 40%);">+ * Since these are two for loops the break keyword</span><br><span style="color: hsl(120, 100%, 40%);">+ * doesn't work as expected (only breaks out of the inner loop) */</span><br><span style="color: hsl(120, 100%, 40%);">+#define gbproxy_for_each_bvc(cfg, nse, bvc) \</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(bvc, &nse->bts_peers, list)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> struct rate_ctr_group;</span><br><span> struct gprs_gb_parse_context;</span><br><span> struct tlv_parsed;</span><br><span>@@ -99,7 +106,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 +150,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_peer.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 +177,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.bts_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 +349,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 39b9ffd..d313255 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,18 +817,22 @@</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>    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>@@ -1034,6 +1049,14 @@</span><br><span>                  LOGP(DGPRS, LOGL_INFO, "NSEI=%u Rx BVC RESET (BVCI=%u)\n",</span><br><span>                                 nsei, bvci);</span><br><span>                         if (bvci == 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                              struct gbproxy_nse *nse;</span><br><span style="color: hsl(120, 100%, 40%);">+                              /* Ensure the NSE peer is there and clear all PtP BVCs */</span><br><span style="color: hsl(120, 100%, 40%);">+                             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\n");</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                              gbproxy_cleanup_peers(cfg, nsei, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>                               /* FIXME: only do this if SGSN is alive! */</span><br><span>                          LOGP(DGPRS, LOGL_INFO, "NSEI=%u Tx fake "</span><br><span>                                  "BVC RESET ACK of BVCI=0\n", nsei);</span><br><span>@@ -1042,16 +1065,34 @@</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(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_NOTICE, "Got PtP BVC reset before signalling reset for "</span><br><span style="color: hsl(120, 100%, 40%);">+                                           "BVCI=%u NSEI=%u\n", bvci, nsei);</span><br><span style="color: hsl(120, 100%, 40%);">+                                   return bssgp_tx_status(BSSGP_CAUSE_PDU_INCOMP_STATE, 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(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_NOTICE, "Got PtP BVC reset before signalling reset for "</span><br><span style="color: hsl(120, 100%, 40%);">+                                           "BVCI=%u NSEI=%u\n", bvci, nsei);</span><br><span style="color: hsl(120, 100%, 40%);">+                                   return bssgp_tx_status(BSSGP_CAUSE_PDU_INCOMP_STATE, 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%);">+                       }</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>@@ -1098,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>@@ -1119,7 +1163,7 @@</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(120, 100%, 40%);">+            gbproxy_for_each_bvc(cfg, nse, peer) {</span><br><span>                       if (!memcmp(peer->ra, TLVP_VAL(tp, BSSGP_IE_ROUTEING_AREA), 6)) {</span><br><span>                                 LOGPC(DGPRS, LOGL_INFO, "routing by RAI to peer BVCI=%u\n", peer->bvci);</span><br><span>                                gbprox_relay2peer(msg, peer, ns_bvci);</span><br><span>@@ -1129,7 +1173,7 @@</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(120, 100%, 40%);">+            gbproxy_for_each_bvc(cfg, nse, peer) {</span><br><span>                       if (!memcmp(peer->ra, TLVP_VAL(tp, BSSGP_IE_LOCATION_AREA), 5)) {</span><br><span>                                 LOGPC(DGPRS, LOGL_INFO, "routing by LAI to peer BVCI=%u\n", peer->bvci);</span><br><span>                                gbprox_relay2peer(msg, peer, ns_bvci);</span><br><span>@@ -1138,7 +1182,7 @@</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(120, 100%, 40%);">+            gbproxy_for_each_bvc(cfg, nse, peer) {</span><br><span>                       LOGPC(DGPRS, LOGL_INFO, "broadcasting to peer BVCI=%u\n", peer->bvci);</span><br><span>                  gbprox_relay2peer(msg, peer, ns_bvci);</span><br><span>                       n_peers++;</span><br><span>@@ -1165,6 +1209,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>@@ -1195,7 +1240,7 @@</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(120, 100%, 40%);">+      gbproxy_for_each_bvc(cfg, nse, peer)</span><br><span>                 gbprox_relay2peer(msg, peer, ns_bvci);</span><br><span> </span><br><span>   return 0;</span><br><span>@@ -1445,7 +1490,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>@@ -1516,10 +1562,15 @@</span><br><span> </span><br><span> void gbprox_reset(struct gbproxy_config *cfg)</span><br><span> {</span><br><span style="color: hsl(120, 100%, 40%);">+        struct gbproxy_nse *nse, *ntmp;</span><br><span>      struct gbproxy_peer *peer, *tmp;</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%);">+          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>@@ -1529,7 +1580,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..28b36a8 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,16 +83,17 @@</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(120, 100%, 40%);">+    struct gbproxy_nse *nse_peer;</span><br><span>        struct gbproxy_peer *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(120, 100%, 40%);">+    gbproxy_for_each_bvc(cfg, nse_peer, peer) {</span><br><span>          struct gprs_ra_id raid;</span><br><span>              gsm48_parse_ra(&raid, peer->ra);</span><br><span> </span><br><span>          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(120, 100%, 40%);">+                         nse_peer->nsei, peer->bvci,</span><br><span>                            raid.mcc, raid.mnc,</span><br><span>                          raid.lac, raid.rac,</span><br><span>                          peer->blocked ? "BLOCKED" : "UNBLOCKED");</span><br><span>@@ -106,9 +107,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 48482b6..0649d7c 100644</span><br><span>--- a/src/gbproxy/gb_proxy_peer.c</span><br><span>+++ b/src/gbproxy/gb_proxy_peer.c</span><br><span>@@ -20,6 +20,7 @@</span><br><span>  *</span><br><span>  */</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+#include "osmocom/vty/command.h"</span><br><span> #include <osmocom/sgsn/gb_proxy.h></span><br><span> </span><br><span> #include <osmocom/sgsn/debug.h></span><br><span>@@ -81,47 +82,55 @@</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(120, 100%, 40%);">+     struct gbproxy_nse *nse;</span><br><span>     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(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  gbproxy_for_each_bvc(cfg, nse, peer) {</span><br><span>               if (peer->bvci == bvci)</span><br><span>                   return peer;</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> </span><br><span style="color: hsl(0, 100%, 40%);">-/* look-up a peer by its Routeing Area Identification (RAI) */</span><br><span style="color: hsl(120, 100%, 40%);">+/* look-up a peer by its Routeing Area Identification (RAI). There can only be one match */</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(120, 100%, 40%);">+      struct gbproxy_nse *nse;</span><br><span>     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(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  gbproxy_for_each_bvc(cfg, nse, peer) {</span><br><span>               if (!memcmp(peer->ra, ra, 6))</span><br><span>                     return peer;</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> /* look-up a peer by its Location Area Identification (LAI) */</span><br><span style="color: hsl(120, 100%, 40%);">+/* FIXME: Only returns the first matching peer, but there could be multiple with the same LA */</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(120, 100%, 40%);">+      struct gbproxy_nse *nse;</span><br><span>     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(120, 100%, 40%);">+    gbproxy_for_each_bvc(cfg, nse, peer) {</span><br><span>               if (!memcmp(peer->ra, la, 5))</span><br><span>                     return peer;</span><br><span>         }</span><br><span>@@ -129,11 +138,13 @@</span><br><span> }</span><br><span> </span><br><span> /* look-up a peer by its Location Area Code (LAC) */</span><br><span style="color: hsl(120, 100%, 40%);">+/* FIXME: Only returns the first matching peer, but there could be multiple with the same LAC */</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(120, 100%, 40%);">+      struct gbproxy_nse *nse;</span><br><span>     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(120, 100%, 40%);">+    gbproxy_for_each_bvc(cfg, nse, peer) {</span><br><span>               if (!memcmp(peer->ra + 3, la + 3, 2))</span><br><span>                     return peer;</span><br><span>         }</span><br><span>@@ -172,18 +183,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>@@ -195,22 +213,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>@@ -224,17 +244,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..def550e 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,6 +420,7 @@</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(120, 100%, 40%);">+     struct gbproxy_nse *nse;</span><br><span>     struct gbproxy_peer *peer;</span><br><span>   g_cfg->clean_stale_timer_freq = (unsigned int) atoi(argv[0]);</span><br><span> </span><br><span>@@ -427,7 +428,7 @@</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(120, 100%, 40%);">+    gbproxy_for_each_bvc(g_cfg, nse, peer)</span><br><span>               osmo_timer_schedule(&peer->clean_stale_timer,</span><br><span>                                         random() % 5, random() % 1000000);</span><br><span> </span><br><span>@@ -440,10 +441,11 @@</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(120, 100%, 40%);">+  struct gbproxy_nse *nse;</span><br><span>     struct gbproxy_peer *peer;</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(120, 100%, 40%);">+    gbproxy_for_each_bvc(g_cfg, nse, peer)</span><br><span>               osmo_timer_del(&peer->clean_stale_timer);</span><br><span> </span><br><span>         return CMD_SUCCESS;</span><br><span>@@ -536,13 +538,14 @@</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(120, 100%, 40%);">+    struct gbproxy_nse *nse;</span><br><span>     struct gbproxy_peer *peer;</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(120, 100%, 40%);">+  gbproxy_for_each_bvc(g_cfg, nse, peer) {</span><br><span>             gbprox_vty_print_peer(vty, peer);</span><br><span> </span><br><span>                if (show_stats)</span><br><span>@@ -554,6 +557,7 @@</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(120, 100%, 40%);">+     struct gbproxy_nse *nse;</span><br><span>     struct gbproxy_peer *peer;</span><br><span>   time_t now;</span><br><span>  struct timespec ts = {0,};</span><br><span>@@ -561,7 +565,7 @@</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(120, 100%, 40%);">+  gbproxy_for_each_bvc(g_cfg, nse, peer) {</span><br><span>             struct gbproxy_link_info *link_info;</span><br><span>                 struct gbproxy_patch_state *state = &peer->patch_state;</span><br><span> </span><br><span>@@ -651,15 +655,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 76fc000..b3d12c0 100644</span><br><span>--- a/tests/gbproxy/gbproxy_test.c</span><br><span>+++ b/tests/gbproxy/gbproxy_test.c</span><br><span>@@ -118,6 +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(120, 100%, 40%);">+        struct gbproxy_nse *nse;</span><br><span>     struct gbproxy_peer *peer;</span><br><span>   struct gprs_ra_id raid;</span><br><span>      unsigned int i;</span><br><span>@@ -128,14 +129,15 @@</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(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  gbproxy_for_each_bvc(cfg, nse, peer) {</span><br><span>               struct gbproxy_link_info *link_info;</span><br><span>                 struct gbproxy_patch_state *state = &peer->patch_state;</span><br><span>               gsm48_parse_ra(&raid, peer->ra);</span><br><span> </span><br><span>          rc = fprintf(stream, "%*s  NSEI %u, BVCI %u, %sblocked, RAI %s\n",</span><br><span>                              indent, "",</span><br><span style="color: hsl(0, 100%, 40%);">-                           peer->nsei, peer->bvci,</span><br><span style="color: hsl(120, 100%, 40%);">+                         nse->nsei, peer->bvci,</span><br><span>                         peer->blocked ? "" : "not ",</span><br><span>                          osmo_rai_name(&raid));</span><br><span> </span><br><span>@@ -927,6 +929,7 @@</span><br><span>           "NSEI 0x%04x(%d)\n\n",</span><br><span>             nsei, nsei);</span><br><span>  send_ns_avail(nsi, nsei);</span><br><span style="color: hsl(120, 100%, 40%);">+     send_bssgp_reset(nsi, nsei, 0);</span><br><span> }</span><br><span> </span><br><span> static void setup_bssgp(struct gprs_ns2_inst *nsi,</span><br><span>@@ -4249,7 +4252,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>@@ -4298,6 +4301,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>@@ -4312,6 +4316,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>@@ -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>@@ -4366,7 +4371,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>@@ -4406,7 +4411,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>@@ -4444,7 +4449,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>@@ -4482,7 +4487,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></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: 1 </div>
<div style="display:none"> Gerrit-Owner: daniel <dwillmann@sysmocom.de> </div>
<div style="display:none"> Gerrit-MessageType: newchange </div>