<p>laforge has uploaded this change for <strong>review</strong>.</p><p><a href="https://gerrit.osmocom.org/c/osmo-sgsn/+/21612">View Change</a></p><pre style="font-family: monospace,monospace; white-space: pre-wrap;">WIP: gbproxy rewrite<br><br>Rewrite of a large part of osmo-gbproxy in order to prepare<br>for SGSN pool support.  The amount of changes are of such fundamental<br>nature that it doesn't make sense to try to split this into hundreds<br>of individual changesets.<br><br>Related: OS#4472<br>Change-Id: Ie0746f17927a9509c3806cc80dc1a31d25df7937<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_main.c<br>M src/gbproxy/gb_proxy_peer.c<br>M src/gbproxy/gb_proxy_vty.c<br>6 files changed, 867 insertions(+), 479 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/12/21612/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 ac03a11..e61b991 100644</span><br><span>--- a/include/osmocom/sgsn/gb_proxy.h</span><br><span>+++ b/include/osmocom/sgsn/gb_proxy.h</span><br><span>@@ -4,6 +4,7 @@</span><br><span> </span><br><span> #include <osmocom/core/msgb.h></span><br><span> #include <osmocom/core/timer.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/fsm.h></span><br><span> #include <osmocom/core/hashtable.h></span><br><span> #include <osmocom/gsm/gsm23003.h></span><br><span> </span><br><span>@@ -48,19 +49,43 @@</span><br><span> </span><br><span> /* global gb-proxy configuration */</span><br><span> struct gbproxy_config {</span><br><span style="color: hsl(0, 100%, 40%);">-  /* parsed from config file */</span><br><span style="color: hsl(0, 100%, 40%);">-   uint16_t nsip_sgsn_nsei;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span>     /* NS instance of libosmogb */</span><br><span>       struct gprs_ns2_inst *nsi;</span><br><span> </span><br><span>       /* Linked list of all BSS side Gb peers */</span><br><span>   DECLARE_HASHTABLE(bss_nses, 8);</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+   /* hash table of all SGSN-side Gb peers */</span><br><span style="color: hsl(120, 100%, 40%);">+    DECLARE_HASHTABLE(sgsn_nses, 8);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    /* hash table of all gbproxy_cell */</span><br><span style="color: hsl(120, 100%, 40%);">+  DECLARE_HASHTABLE(cells, 8);</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> </span><br><span style="color: hsl(120, 100%, 40%);">+/* One Cell within the BSS: Links BSS-side BVC to SGSN-side BVCs */</span><br><span style="color: hsl(120, 100%, 40%);">+struct gbproxy_cell {</span><br><span style="color: hsl(120, 100%, 40%);">+    /* linked to gbproxy_config.cells hashtable */</span><br><span style="color: hsl(120, 100%, 40%);">+        struct hlist_node 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%);">+ /*  BVCI of PTP BVCs associated to this cell */</span><br><span style="color: hsl(120, 100%, 40%);">+       uint16_t bvci;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      /* Routing Area that this BVC is part of (raw 04.08 encoding) */</span><br><span style="color: hsl(120, 100%, 40%);">+      uint8_t ra[6];</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      /* pointer to the BSS-side BVC */</span><br><span style="color: hsl(120, 100%, 40%);">+     struct gbproxy_bvc *bss_bvc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        /* pointers to SGSN-side BVC (one for each pool member) */</span><br><span style="color: hsl(120, 100%, 40%);">+    struct gbproxy_bvc *sgsn_bvc[16];</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /* One BVC inside an NSE */</span><br><span> struct gbproxy_bvc {</span><br><span>       /* linked to gbproxy_nse.bvcs */</span><br><span>@@ -75,11 +100,14 @@</span><br><span>      /* Routing Area that this BVC is part of (raw 04.08 encoding) */</span><br><span>     uint8_t ra[6];</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-      /* true if this BVC is blocked */</span><br><span style="color: hsl(0, 100%, 40%);">-       bool blocked;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span>        /* Counter */</span><br><span>        struct rate_ctr_group *ctrg;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        /* the cell to which this BVC belongs */</span><br><span style="color: hsl(120, 100%, 40%);">+      struct gbproxy_cell *cell;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  /* per-BVC FSM instance */</span><br><span style="color: hsl(120, 100%, 40%);">+    struct osmo_fsm_inst *fi;</span><br><span> };</span><br><span> </span><br><span> /* one NS Entity that we interact with (BSS/PCU) */</span><br><span>@@ -93,19 +121,24 @@</span><br><span>    /* NSEI of the NSE */</span><br><span>        uint16_t nsei;</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+    /* Are we facing towards a SGSN (true) or BSS (false) */</span><br><span style="color: hsl(120, 100%, 40%);">+      bool sgsn_facing;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>  /* List of all BVCs in this NSE */</span><br><span>   DECLARE_HASHTABLE(bvcs, 10);</span><br><span> };</span><br><span> </span><br><span> /* Convenience logging macros for NSE/BVC */</span><br><span> #define LOGPNSE_CAT(NSE, SUBSYS, LEVEL, FMT, ARGS...) \</span><br><span style="color: hsl(0, 100%, 40%);">-       LOGP(SUBSYS, LEVEL, "NSE(%05u/BSS) " FMT, (NSE)->nsei, ## ARGS)</span><br><span style="color: hsl(120, 100%, 40%);">+  LOGP(SUBSYS, LEVEL, "NSE(%05u/%s) " FMT, (NSE)->nsei, \</span><br><span style="color: hsl(120, 100%, 40%);">+          (NSE)->sgsn_facing ? "SGSN" : "BSS", ## ARGS)</span><br><span> #define LOGPNSE(NSE, LEVEL, FMT, ARGS...) \</span><br><span>  LOGPNSE_CAT(NSE, DGPRS, LEVEL, FMT, ## ARGS)</span><br><span> </span><br><span> #define LOGPBVC_CAT(BVC, SUBSYS, LEVEL, FMT, ARGS...) \</span><br><span style="color: hsl(0, 100%, 40%);">-     LOGP(SUBSYS, LEVEL, "NSE(%05u/BSS)-BVC(%05u/%s) " FMT, (BVC)->nse->nsei, (BVC)->bvci, \</span><br><span style="color: hsl(0, 100%, 40%);">-              (BVC)->blocked ? "BLOCKED" : "UNBLOCKED", ## ARGS)</span><br><span style="color: hsl(120, 100%, 40%);">+     LOGP(SUBSYS, LEVEL, "NSE(%05u/%s)-BVC(%05u/%s) " FMT, (BVC)->nse->nsei, \</span><br><span style="color: hsl(120, 100%, 40%);">+             (BVC)->nse->sgsn_facing ? "SGSN" : "BSS", (BVC)->bvci, \</span><br><span style="color: hsl(120, 100%, 40%);">+         osmo_fsm_inst_state_name((BVC)->fi), ## ARGS)</span><br><span> #define LOGPBVC(BVC, LEVEL, FMT, ARGS...) \</span><br><span>      LOGPBVC_CAT(BVC, DGPRS, LEVEL, FMT, ## ARGS)</span><br><span> </span><br><span>@@ -133,21 +166,23 @@</span><br><span> void gbprox_reset(struct gbproxy_config *cfg);</span><br><span> </span><br><span> /* Peer handling */</span><br><span style="color: hsl(0, 100%, 40%);">-struct gbproxy_bvc *gbproxy_bvc_by_bvci(</span><br><span style="color: hsl(0, 100%, 40%);">-   struct gbproxy_config *cfg, uint16_t bvci);</span><br><span style="color: hsl(0, 100%, 40%);">-struct gbproxy_bvc *gbproxy_bvc_by_nsei(</span><br><span style="color: hsl(0, 100%, 40%);">-     struct gbproxy_config *cfg, uint16_t nsei);</span><br><span style="color: hsl(0, 100%, 40%);">-struct gbproxy_bvc *gbproxy_bvc_by_rai(</span><br><span style="color: hsl(0, 100%, 40%);">-      struct gbproxy_config *cfg, const uint8_t *ra);</span><br><span style="color: hsl(120, 100%, 40%);">+#define NSE_F_SGSN     0x0001</span><br><span style="color: hsl(120, 100%, 40%);">+#define NSE_F_BSS       0x0002</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct gbproxy_bvc *gbproxy_bvc_by_bvci(struct gbproxy_nse *nse, uint16_t bvci);</span><br><span> struct gbproxy_bvc *gbproxy_bvc_alloc(struct gbproxy_nse *nse, uint16_t bvci);</span><br><span> void gbproxy_bvc_free(struct gbproxy_bvc *bvc);</span><br><span style="color: hsl(0, 100%, 40%);">-void gbproxy_bvc_move(struct gbproxy_bvc *bvc, struct gbproxy_nse *nse);</span><br><span style="color: hsl(0, 100%, 40%);">-int gbproxy_cleanup_bvcs(struct gbproxy_config *cfg, uint16_t nsei, uint16_t bvci);</span><br><span style="color: hsl(120, 100%, 40%);">+int gbproxy_cleanup_bvcs(struct gbproxy_nse *nse, uint16_t bvci);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct gbproxy_cell *gbproxy_cell_alloc(struct gbproxy_config *cfg, uint16_t bvci);</span><br><span style="color: hsl(120, 100%, 40%);">+struct gbproxy_cell *gbproxy_cell_by_bvci(struct gbproxy_config *cfg, uint16_t bvci);</span><br><span style="color: hsl(120, 100%, 40%);">+void gbproxy_cell_free(struct gbproxy_cell *cell);</span><br><span style="color: hsl(120, 100%, 40%);">+bool gbproxy_cell_add_sgsn_bvc(struct gbproxy_cell *cell, struct gbproxy_bvc *bvc);</span><br><span> </span><br><span> /* NSE handling */</span><br><span style="color: hsl(0, 100%, 40%);">-struct gbproxy_nse *gbproxy_nse_alloc(struct gbproxy_config *cfg, uint16_t nsei);</span><br><span style="color: hsl(120, 100%, 40%);">+struct gbproxy_nse *gbproxy_nse_alloc(struct gbproxy_config *cfg, uint16_t nsei, bool sgsn_facing);</span><br><span> void gbproxy_nse_free(struct gbproxy_nse *nse);</span><br><span style="color: hsl(0, 100%, 40%);">-struct gbproxy_nse *gbproxy_nse_by_nsei(struct gbproxy_config *cfg, uint16_t nsei);</span><br><span style="color: hsl(0, 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%);">+struct gbproxy_nse *gbproxy_nse_by_nsei(struct gbproxy_config *cfg, uint16_t nsei, uint32_t flags);</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, bool sgsn_facing);</span><br><span> </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 ecb74c0..a920906 100644</span><br><span>--- a/src/gbproxy/gb_proxy.c</span><br><span>+++ b/src/gbproxy/gb_proxy.c</span><br><span>@@ -1,6 +1,6 @@</span><br><span> /* NS-over-IP proxy */</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-/* (C) 2010 by Harald Welte <laforge@gnumonks.org></span><br><span style="color: hsl(120, 100%, 40%);">+/* (C) 2010-2020 by Harald Welte <laforge@gnumonks.org></span><br><span>  * (C) 2010-2013 by On-Waves</span><br><span>  * (C) 2013 by Holger Hans Peter Freyther</span><br><span>  * All Rights Reserved</span><br><span>@@ -41,6 +41,7 @@</span><br><span> #include <osmocom/gprs/gprs_ns2.h></span><br><span> #include <osmocom/gprs/gprs_bssgp.h></span><br><span> #include <osmocom/gprs/gprs_bssgp_bss.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/gprs/bssgp_bvc_fsm.h></span><br><span> </span><br><span> #include <osmocom/gsm/gsm_utils.h></span><br><span> </span><br><span>@@ -80,30 +81,8 @@</span><br><span> </span><br><span> static int gbprox_relay2peer(struct msgb *old_msg, struct gbproxy_bvc *bvc,</span><br><span>                       uint16_t ns_bvci);</span><br><span style="color: hsl(0, 100%, 40%);">-static int gbprox_relay2sgsn(struct gbproxy_config *cfg, struct msgb *old_msg,</span><br><span style="color: hsl(0, 100%, 40%);">-                        uint16_t ns_bvci, uint16_t sgsn_nsei);</span><br><span> </span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-static int gbproxy_is_sgsn_nsei(struct gbproxy_config *cfg, uint16_t nsei)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-  return nsei == cfg->nsip_sgsn_nsei;</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%);">-static int check_bvc_nsei(struct gbproxy_bvc *bvc, uint16_t nsei)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-       OSMO_ASSERT(bvc);</span><br><span style="color: hsl(0, 100%, 40%);">-       OSMO_ASSERT(bvc->nse);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       if (bvc->nse->nsei != nsei) {</span><br><span style="color: hsl(0, 100%, 40%);">-             LOGPBVC(bvc, LOGL_NOTICE, "Peer entry doesn't match current NSEI "</span><br><span style="color: hsl(0, 100%, 40%);">-                     "via NSE(%05u/BSS)\n", nsei);</span><br><span style="color: hsl(0, 100%, 40%);">-            rate_ctr_inc(&bvc->ctrg->ctr[GBPROX_PEER_CTR_INV_NSEI]);</span><br><span style="color: hsl(0, 100%, 40%);">-              return 0;</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%);">-       return 1;</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span> /* generate BVC-STATUS message with cause value derived from TLV-parser error */</span><br><span> static int tx_status_from_tlvp(enum osmo_tlv_parser_error tlv_p_err, struct msgb *orig_msg)</span><br><span> {</span><br><span>@@ -125,6 +104,7 @@</span><br><span>     msgb_pull(msg, strip_len);</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+#if 0</span><br><span> /* feed a message down the NS-VC associated with the specified bvc */</span><br><span> static int gbprox_relay2sgsn(struct gbproxy_config *cfg, struct msgb *old_msg,</span><br><span>                             uint16_t ns_bvci, uint16_t sgsn_nsei)</span><br><span>@@ -150,6 +130,7 @@</span><br><span>             rate_ctr_inc(&cfg->ctrg->ctr[GBPROX_GLOB_CTR_TX_ERR_SGSN]);</span><br><span>        return rc;</span><br><span> }</span><br><span style="color: hsl(120, 100%, 40%);">+#endif</span><br><span> </span><br><span> /* feed a message down the NSE */</span><br><span> static int gbprox_relay2nse(struct msgb *old_msg, struct gbproxy_nse *nse,</span><br><span>@@ -208,198 +189,456 @@</span><br><span>     return rc;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-static int block_unblock_bvc(struct gbproxy_config *cfg, uint16_t ptp_bvci, uint8_t pdu_type)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-       struct gbproxy_bvc *bvc;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-        bvc = gbproxy_bvc_by_bvci(cfg, ptp_bvci);</span><br><span style="color: hsl(0, 100%, 40%);">-       if (!bvc) {</span><br><span style="color: hsl(0, 100%, 40%);">-             LOGP(DGPRS, LOGL_ERROR, "BVC(%05u/??) Cannot find BSS\n",</span><br><span style="color: hsl(0, 100%, 40%);">-                     ptp_bvci);</span><br><span style="color: hsl(0, 100%, 40%);">-              rate_ctr_inc(&cfg->ctrg->ctr[GBPROX_GLOB_CTR_INV_BVCI]);</span><br><span style="color: hsl(0, 100%, 40%);">-              return -ENOENT;</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%);">-       switch (pdu_type) {</span><br><span style="color: hsl(0, 100%, 40%);">-     case BSSGP_PDUT_BVC_BLOCK_ACK:</span><br><span style="color: hsl(0, 100%, 40%);">-          bvc->blocked = true;</span><br><span style="color: hsl(0, 100%, 40%);">-         rate_ctr_inc(&bvc->ctrg->ctr[GBPROX_PEER_CTR_BLOCKED]);</span><br><span style="color: hsl(0, 100%, 40%);">-               break;</span><br><span style="color: hsl(0, 100%, 40%);">-  case BSSGP_PDUT_BVC_UNBLOCK_ACK:</span><br><span style="color: hsl(0, 100%, 40%);">-                bvc->blocked = false;</span><br><span style="color: hsl(0, 100%, 40%);">-                rate_ctr_inc(&bvc->ctrg->ctr[GBPROX_PEER_CTR_UNBLOCKED]);</span><br><span style="color: hsl(0, 100%, 40%);">-             break;</span><br><span style="color: hsl(0, 100%, 40%);">-  default:</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%);">-       return 0;</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%);">-/* Send a message to a bvc identified by ptp_bvci but using ns_bvci</span><br><span style="color: hsl(0, 100%, 40%);">- * in the NS hdr */</span><br><span style="color: hsl(0, 100%, 40%);">-static int gbprox_relay2bvci(struct gbproxy_config *cfg, struct msgb *msg, uint16_t ptp_bvci,</span><br><span style="color: hsl(0, 100%, 40%);">-                     uint16_t ns_bvci)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-    struct gbproxy_bvc *bvc;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-        bvc = gbproxy_bvc_by_bvci(cfg, ptp_bvci);</span><br><span style="color: hsl(0, 100%, 40%);">-       if (!bvc) {</span><br><span style="color: hsl(0, 100%, 40%);">-             LOGP(DGPRS, LOGL_ERROR, "BVC(%05u/??) Cannot find BSS\n",</span><br><span style="color: hsl(0, 100%, 40%);">-                     ptp_bvci);</span><br><span style="color: hsl(0, 100%, 40%);">-              rate_ctr_inc(&cfg->ctrg->ctr[GBPROX_GLOB_CTR_INV_BVCI]);</span><br><span style="color: hsl(0, 100%, 40%);">-              return -ENOENT;</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%);">-       return gbprox_relay2peer(msg, bvc, ns_bvci);</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span> int bssgp_prim_cb(struct osmo_prim_hdr *oph, void *ctx)</span><br><span> {</span><br><span>        return 0;</span><br><span> }</span><br><span> </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%);">+ * PTP BVC handling</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%);">+/* route an uplink message on a PTP-BVC to a SGSN using the TLLI */</span><br><span style="color: hsl(120, 100%, 40%);">+static int gbprox_bss2sgsn_tlli(struct gbproxy_cell *cell, struct msgb *msg, uint32_t tlli,</span><br><span style="color: hsl(120, 100%, 40%);">+                            bool sig_bvci)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     struct gbproxy_bvc *sgsn_bvc;</span><br><span style="color: hsl(120, 100%, 40%);">+ unsigned int i;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     /* FIXME: derive NRI from TLLI */</span><br><span style="color: hsl(120, 100%, 40%);">+     /* FIXME: find the SGSN for that NRI */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     /* HACK: we currently simply pick the first SGSN we find */</span><br><span style="color: hsl(120, 100%, 40%);">+   for (i = 0; i < ARRAY_SIZE(cell->sgsn_bvc); i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+              sgsn_bvc = cell->sgsn_bvc[i];</span><br><span style="color: hsl(120, 100%, 40%);">+              if (sgsn_bvc)</span><br><span style="color: hsl(120, 100%, 40%);">+                 return gbprox_relay2peer(msg, sgsn_bvc, sig_bvci ? 0 : sgsn_bvc->bvci);</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+     return 0;</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%);">+static int gbprox_bss2sgsn_null_nri(struct gbproxy_cell *cell, struct msgb *msg)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   struct gbproxy_bvc *sgsn_bvc;</span><br><span style="color: hsl(120, 100%, 40%);">+ unsigned int i;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     /* FIXME: find the SGSN for that NRI */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     /* HACK: we currently simply pick the first SGSN we find */</span><br><span style="color: hsl(120, 100%, 40%);">+   for (i = 0; i < ARRAY_SIZE(cell->sgsn_bvc); i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+              sgsn_bvc = cell->sgsn_bvc[i];</span><br><span style="color: hsl(120, 100%, 40%);">+              if (sgsn_bvc)</span><br><span style="color: hsl(120, 100%, 40%);">+                 return gbprox_relay2peer(msg, sgsn_bvc, sgsn_bvc->bvci);</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+     return 0;</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> /* Receive an incoming PTP message from a BSS-side NS-VC */</span><br><span style="color: hsl(0, 100%, 40%);">-static int gbprox_rx_ptp_from_bss(struct gbproxy_config *cfg,</span><br><span style="color: hsl(0, 100%, 40%);">-                              struct msgb *msg, uint16_t nsei,</span><br><span style="color: hsl(0, 100%, 40%);">-                                uint16_t ns_bvci)</span><br><span style="color: hsl(120, 100%, 40%);">+static int gbprox_rx_ptp_from_bss(struct gbproxy_nse *nse, struct msgb *msg, uint16_t ns_bvci)</span><br><span> {</span><br><span>     struct bssgp_normal_hdr *bgph = (struct bssgp_normal_hdr *) msgb_bssgph(msg);</span><br><span style="color: hsl(0, 100%, 40%);">-   struct gbproxy_bvc *bvc;</span><br><span style="color: hsl(120, 100%, 40%);">+      const char *pdut_name = osmo_tlv_prot_msg_name(&osmo_pdef_bssgp, bgph->pdu_type);</span><br><span style="color: hsl(120, 100%, 40%);">+      struct gbproxy_bvc *bss_bvc;</span><br><span style="color: hsl(120, 100%, 40%);">+  struct tlv_parsed tp;</span><br><span style="color: hsl(120, 100%, 40%);">+ char log_pfx[32];</span><br><span style="color: hsl(120, 100%, 40%);">+     uint32_t tlli;</span><br><span style="color: hsl(120, 100%, 40%);">+        int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     snprintf(log_pfx, sizeof(log_pfx), "NSE(%05u/BSS)-BVC(%05u/??)", nse->nsei, ns_bvci);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  LOGP(DGPRS, LOGL_DEBUG, "%s Rx %s\n", log_pfx, pdut_name);</span><br><span> </span><br><span>     if (ns_bvci == 0 && ns_bvci == 1) {</span><br><span style="color: hsl(0, 100%, 40%);">-             LOGP(DGPRS, LOGL_NOTICE, "NSE(%05u/BSS) BVCI=%05u is not PTP\n", nsei, ns_bvci);</span><br><span style="color: hsl(120, 100%, 40%);">+            LOGP(DGPRS, LOGL_NOTICE, "%s BVCI=%05u is not PTP\n", log_pfx, ns_bvci);</span><br><span>           return bssgp_tx_status(BSSGP_CAUSE_PROTO_ERR_UNSPEC, NULL, msg);</span><br><span>     }</span><br><span> </span><br><span>        if (!(bssgp_pdu_type_flags(bgph->pdu_type) & BSSGP_PDUF_PTP)) {</span><br><span style="color: hsl(0, 100%, 40%);">-          LOGP(DGPRS, LOGL_NOTICE, "NSE(%05u/%05u) %s not allowed in PTP BVC\n",</span><br><span style="color: hsl(0, 100%, 40%);">-                     nsei, ns_bvci, osmo_tlv_prot_msg_name(&osmo_pdef_bssgp, bgph->pdu_type));</span><br><span style="color: hsl(120, 100%, 40%);">+         LOGP(DGPRS, LOGL_NOTICE, "%s %s not allowed in PTP BVC\n", log_pfx, pdut_name);</span><br><span>            return bssgp_tx_status(BSSGP_CAUSE_PROTO_ERR_UNSPEC, NULL, msg);</span><br><span>     }</span><br><span> </span><br><span>        if (!(bssgp_pdu_type_flags(bgph->pdu_type) & BSSGP_PDUF_UL)) {</span><br><span style="color: hsl(0, 100%, 40%);">-           LOGP(DGPRS, LOGL_NOTICE, "NSE(%05u/%05u) %s not allowed in uplink direction\n",</span><br><span style="color: hsl(0, 100%, 40%);">-                    nsei, ns_bvci, osmo_tlv_prot_msg_name(&osmo_pdef_bssgp, bgph->pdu_type));</span><br><span style="color: hsl(120, 100%, 40%);">+         LOGP(DGPRS, LOGL_NOTICE, "%s %s not allowed in uplink direction\n", log_pfx, pdut_name);</span><br><span>           return bssgp_tx_status(BSSGP_CAUSE_PROTO_ERR_UNSPEC, NULL, msg);</span><br><span>     }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   bvc = gbproxy_bvc_by_bvci(cfg, ns_bvci);</span><br><span style="color: hsl(0, 100%, 40%);">-        if (!bvc) {</span><br><span style="color: hsl(0, 100%, 40%);">-             LOGP(DGPRS, LOGL_NOTICE, "BVC(%05u/??) Didn't find bvc "</span><br><span style="color: hsl(0, 100%, 40%);">-               "for PTP message from NSE(%05u/BSS), "</span><br><span style="color: hsl(0, 100%, 40%);">-                "discarding message\n",</span><br><span style="color: hsl(0, 100%, 40%);">-               ns_bvci, nsei);</span><br><span style="color: hsl(0, 100%, 40%);">-            return bssgp_tx_status(BSSGP_CAUSE_UNKNOWN_BVCI,</span><br><span style="color: hsl(0, 100%, 40%);">-                                       &ns_bvci, msg);</span><br><span style="color: hsl(120, 100%, 40%);">+    bss_bvc = gbproxy_bvc_by_bvci(nse, ns_bvci);</span><br><span style="color: hsl(120, 100%, 40%);">+  if (!bss_bvc) {</span><br><span style="color: hsl(120, 100%, 40%);">+               LOGP(DGPRS, LOGL_NOTICE, "%s %s - Didn't find BVC for PTP message, discarding\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                    log_pfx, pdut_name);</span><br><span style="color: hsl(120, 100%, 40%);">+             return bssgp_tx_status(BSSGP_CAUSE_UNKNOWN_BVCI, &ns_bvci, msg);</span><br><span>         }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   /* TODO: Should we discard this message if the check fails */</span><br><span style="color: hsl(0, 100%, 40%);">-   check_bvc_nsei(bvc, nsei);</span><br><span style="color: hsl(120, 100%, 40%);">+    /* UL_UNITDATA has a different header than all other uplink PDUs */</span><br><span style="color: hsl(120, 100%, 40%);">+   if (bgph->pdu_type == BSSGP_PDUT_UL_UNITDATA) {</span><br><span style="color: hsl(120, 100%, 40%);">+            const struct bssgp_ud_hdr *budh = (struct bssgp_ud_hdr *) msgb_bssgph(msg);</span><br><span style="color: hsl(120, 100%, 40%);">+           if (msgb_bssgp_len(msg) < sizeof(*budh))</span><br><span style="color: hsl(120, 100%, 40%);">+                   return bssgp_tx_status(BSSGP_CAUSE_INV_MAND_INF, NULL, msg);</span><br><span style="color: hsl(120, 100%, 40%);">+          rc = osmo_tlv_prot_parse(&osmo_pdef_bssgp, &tp, 1, bgph->pdu_type, budh->data,</span><br><span style="color: hsl(120, 100%, 40%);">+                                   msgb_bssgp_len(msg) - sizeof(*budh), 0, 0, DGPRS, log_pfx);</span><br><span style="color: hsl(120, 100%, 40%);">+          /* populate TLLI from the fixed headser into the TLV-parsed array so later code</span><br><span style="color: hsl(120, 100%, 40%);">+                * doesn't have to worry where the TLLI came from */</span><br><span style="color: hsl(120, 100%, 40%);">+              tp.lv[BSSGP_IE_TLLI].len = 4;</span><br><span style="color: hsl(120, 100%, 40%);">+         tp.lv[BSSGP_IE_TLLI].val = (const uint8_t *) &budh->tlli;</span><br><span style="color: hsl(120, 100%, 40%);">+      } else {</span><br><span style="color: hsl(120, 100%, 40%);">+              rc = osmo_tlv_prot_parse(&osmo_pdef_bssgp, &tp, 1, bgph->pdu_type, bgph->data,</span><br><span style="color: hsl(120, 100%, 40%);">+                                   msgb_bssgp_len(msg) - sizeof(*bgph), 0, 0, DGPRS, log_pfx);</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%);">+              rate_ctr_inc(&nse->cfg->ctrg->ctr[GBPROX_GLOB_CTR_PROTO_ERR_BSS]);</span><br><span style="color: hsl(120, 100%, 40%);">+               return tx_status_from_tlvp(rc, msg);</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   return gbprox_relay2sgsn(cfg, msg, ns_bvci, cfg->nsip_sgsn_nsei);</span><br><span style="color: hsl(120, 100%, 40%);">+  switch (bgph->pdu_type) {</span><br><span style="color: hsl(120, 100%, 40%);">+  case BSSGP_PDUT_UL_UNITDATA:</span><br><span style="color: hsl(120, 100%, 40%);">+  case BSSGP_PDUT_RA_CAPA_UPDATE:</span><br><span style="color: hsl(120, 100%, 40%);">+       case BSSGP_PDUT_FLOW_CONTROL_MS:</span><br><span style="color: hsl(120, 100%, 40%);">+      case BSSGP_PDUT_DOWNLOAD_BSS_PFC:</span><br><span style="color: hsl(120, 100%, 40%);">+     case BSSGP_PDUT_CREATE_BSS_PFC_ACK:</span><br><span style="color: hsl(120, 100%, 40%);">+   case BSSGP_PDUT_CREATE_BSS_PFC_NACK:</span><br><span style="color: hsl(120, 100%, 40%);">+  case BSSGP_PDUT_MODIFY_BSS_PFC_ACK:</span><br><span style="color: hsl(120, 100%, 40%);">+   case BSSGP_PDUT_DELETE_BSS_PFC_ACK:</span><br><span style="color: hsl(120, 100%, 40%);">+   case BSSGP_PDUT_FLOW_CONTROL_PFC:</span><br><span style="color: hsl(120, 100%, 40%);">+     case BSSGP_PDUT_DELETE_BSS_PFC_REQ:</span><br><span style="color: hsl(120, 100%, 40%);">+   case BSSGP_PDUT_PS_HO_REQUIRED:</span><br><span style="color: hsl(120, 100%, 40%);">+       case BSSGP_PDUT_PS_HO_REQUEST_ACK:</span><br><span style="color: hsl(120, 100%, 40%);">+    case BSSGP_PDUT_PS_HO_REQUEST_NACK:</span><br><span style="color: hsl(120, 100%, 40%);">+   case BSSGP_PDUT_PS_HO_COMPLETE:</span><br><span style="color: hsl(120, 100%, 40%);">+       case BSSGP_PDUT_PS_HO_CANCEL:</span><br><span style="color: hsl(120, 100%, 40%);">+         /* We can route based on TLLI-NRI */</span><br><span style="color: hsl(120, 100%, 40%);">+          tlli = osmo_load32be(TLVP_VAL(&tp, BSSGP_IE_TLLI));</span><br><span style="color: hsl(120, 100%, 40%);">+               rc = gbprox_bss2sgsn_tlli(bss_bvc->cell, msg, tlli, false);</span><br><span style="color: hsl(120, 100%, 40%);">+                break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case BSSGP_PDUT_RADIO_STATUS:</span><br><span style="color: hsl(120, 100%, 40%);">+         if (TLVP_PRESENT(&tp, BSSGP_IE_TLLI)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                   tlli = osmo_load32be(TLVP_VAL(&tp, BSSGP_IE_TLLI));</span><br><span style="color: hsl(120, 100%, 40%);">+                       rc = gbprox_bss2sgsn_tlli(bss_bvc->cell, msg, tlli, false);</span><br><span style="color: hsl(120, 100%, 40%);">+                } else if (TLVP_PRESENT(&tp, BSSGP_IE_TMSI)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                    /* we treat the TMSI like a TLLI and extract the NRI from it */</span><br><span style="color: hsl(120, 100%, 40%);">+                       tlli = osmo_load32be(TLVP_VAL(&tp, BSSGP_IE_TMSI));</span><br><span style="color: hsl(120, 100%, 40%);">+                       rc = gbprox_bss2sgsn_tlli(bss_bvc->cell, msg, tlli, false);</span><br><span style="color: hsl(120, 100%, 40%);">+                } else if (TLVP_PRESENT(&tp, BSSGP_IE_IMSI)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                    rc = gbprox_bss2sgsn_null_nri(bss_bvc->cell, msg);</span><br><span style="color: hsl(120, 100%, 40%);">+         } else</span><br><span style="color: hsl(120, 100%, 40%);">+                        LOGPBVC(bss_bvc, LOGL_ERROR, "Rx RADIO-STATUS without any of the conditional IEs\n");</span><br><span style="color: hsl(120, 100%, 40%);">+               break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case BSSGP_PDUT_DUMMY_PAGING_PS_RESP:</span><br><span style="color: hsl(120, 100%, 40%);">+ case BSSGP_PDUT_PAGING_PS_REJECT:</span><br><span style="color: hsl(120, 100%, 40%);">+             /* TODO: Implement via state tracking of PAGING-PS + DUMMY_PAGING_PS */</span><br><span style="color: hsl(120, 100%, 40%);">+               LOGPBVC(bss_bvc, LOGL_ERROR, "Rx %s: Implementation missing\n", pdut_name);</span><br><span style="color: hsl(120, 100%, 40%);">+         break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case BSSGP_PDUT_FLOW_CONTROL_BVC:</span><br><span style="color: hsl(120, 100%, 40%);">+             /* TODO: Implement via FSM */</span><br><span style="color: hsl(120, 100%, 40%);">+         //rc = osmo_fsm_inst_dispatch(bss_bvc->fi, FIXME, &tp);</span><br><span style="color: hsl(120, 100%, 40%);">+                LOGPBVC(bss_bvc, LOGL_ERROR, "Rx %s: Implementation missing\n", pdut_name);</span><br><span style="color: hsl(120, 100%, 40%);">+         break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case BSSGP_PDUT_STATUS:</span><br><span style="color: hsl(120, 100%, 40%);">+               /* TODO: Implement by inspecting the contained PDU */</span><br><span style="color: hsl(120, 100%, 40%);">+         if (!TLVP_PRESENT(&tp, BSSGP_IE_PDU_IN_ERROR))</span><br><span style="color: hsl(120, 100%, 40%);">+                    break;</span><br><span style="color: hsl(120, 100%, 40%);">+                LOGPBVC(bss_bvc, LOGL_ERROR, "Rx %s: Implementation missing\n", pdut_name);</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%);">+   return 0;</span><br><span> }</span><br><span> </span><br><span> /* Receive an incoming PTP message from a SGSN-side NS-VC */</span><br><span style="color: hsl(0, 100%, 40%);">-static int gbprox_rx_ptp_from_sgsn(struct gbproxy_config *cfg,</span><br><span style="color: hsl(0, 100%, 40%);">-                                   struct msgb *msg, uint16_t nsei,</span><br><span style="color: hsl(0, 100%, 40%);">-                                uint16_t ns_bvci)</span><br><span style="color: hsl(120, 100%, 40%);">+static int gbprox_rx_ptp_from_sgsn(struct gbproxy_nse *nse, struct msgb *msg, uint16_t ns_bvci)</span><br><span> {</span><br><span>   struct bssgp_normal_hdr *bgph = (struct bssgp_normal_hdr *) msgb_bssgph(msg);</span><br><span style="color: hsl(0, 100%, 40%);">-   struct gbproxy_bvc *bvc;</span><br><span style="color: hsl(120, 100%, 40%);">+      const char *pdut_name = osmo_tlv_prot_msg_name(&osmo_pdef_bssgp, bgph->pdu_type);</span><br><span style="color: hsl(120, 100%, 40%);">+      struct gbproxy_bvc *sgsn_bvc, *bss_bvc;</span><br><span style="color: hsl(120, 100%, 40%);">+       char log_pfx[32];</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   snprintf(log_pfx, sizeof(log_pfx), "NSE(%05u/SGSN)-BVC(%05u/??)", nse->nsei, ns_bvci);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGP(DGPRS, LOGL_DEBUG, "%s Rx %s\n", log_pfx, pdut_name);</span><br><span> </span><br><span>     if (ns_bvci == 0 && ns_bvci == 1) {</span><br><span style="color: hsl(0, 100%, 40%);">-             LOGP(DGPRS, LOGL_NOTICE, "NSE(%05u/BSS) BVCI=%05u is not PTP\n", nsei, ns_bvci);</span><br><span style="color: hsl(120, 100%, 40%);">+            LOGP(DGPRS, LOGL_NOTICE, "%s BVCI is not PTP\n", log_pfx);</span><br><span>                 return bssgp_tx_status(BSSGP_CAUSE_PROTO_ERR_UNSPEC, NULL, msg);</span><br><span>     }</span><br><span> </span><br><span>        if (!(bssgp_pdu_type_flags(bgph->pdu_type) & BSSGP_PDUF_PTP)) {</span><br><span style="color: hsl(0, 100%, 40%);">-          LOGP(DGPRS, LOGL_NOTICE, "NSE(%05u/%05u) %s not allowed in PTP BVC\n",</span><br><span style="color: hsl(0, 100%, 40%);">-                     nsei, ns_bvci, osmo_tlv_prot_msg_name(&osmo_pdef_bssgp, bgph->pdu_type));</span><br><span style="color: hsl(120, 100%, 40%);">+         LOGP(DGPRS, LOGL_NOTICE, "%s %s not allowed in PTP BVC\n", log_pfx, pdut_name);</span><br><span>            return bssgp_tx_status(BSSGP_CAUSE_PROTO_ERR_UNSPEC, NULL, msg);</span><br><span>     }</span><br><span> </span><br><span>        if (!(bssgp_pdu_type_flags(bgph->pdu_type) & BSSGP_PDUF_DL)) {</span><br><span style="color: hsl(0, 100%, 40%);">-           LOGP(DGPRS, LOGL_NOTICE, "NSE(%05u/%05u) %s not allowed in downlink direction\n",</span><br><span style="color: hsl(0, 100%, 40%);">-                  nsei, ns_bvci, osmo_tlv_prot_msg_name(&osmo_pdef_bssgp, bgph->pdu_type));</span><br><span style="color: hsl(120, 100%, 40%);">+         LOGP(DGPRS, LOGL_NOTICE, "%s %s not allowed in downlink direction\n", log_pfx, pdut_name);</span><br><span>                 return bssgp_tx_status(BSSGP_CAUSE_PROTO_ERR_UNSPEC, NULL, msg);</span><br><span>     }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   bvc = gbproxy_bvc_by_bvci(cfg, ns_bvci);</span><br><span style="color: hsl(0, 100%, 40%);">-        if (!bvc) {</span><br><span style="color: hsl(0, 100%, 40%);">-             LOGP(DGPRS, LOGL_INFO, "BVC(%05u/??) Didn't find bvc for "</span><br><span style="color: hsl(0, 100%, 40%);">-                     "for message from NSE(%05u/SGSN)\n",</span><br><span style="color: hsl(0, 100%, 40%);">-                  ns_bvci, nsei);</span><br><span style="color: hsl(0, 100%, 40%);">-            rate_ctr_inc(&cfg->ctrg-></span><br><span style="color: hsl(0, 100%, 40%);">-                          ctr[GBPROX_GLOB_CTR_INV_BVCI]);</span><br><span style="color: hsl(0, 100%, 40%);">-            return bssgp_tx_status(BSSGP_CAUSE_UNKNOWN_BVCI,</span><br><span style="color: hsl(0, 100%, 40%);">-                                       &ns_bvci, msg);</span><br><span style="color: hsl(120, 100%, 40%);">+    sgsn_bvc = gbproxy_bvc_by_bvci(nse, ns_bvci);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!sgsn_bvc) {</span><br><span style="color: hsl(120, 100%, 40%);">+              LOGP(DGPRS, LOGL_NOTICE, "%s %s - Didn't find BVC for for PTP message, discarding\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                log_pfx, pdut_name);</span><br><span style="color: hsl(120, 100%, 40%);">+             rate_ctr_inc(&nse->cfg->ctrg-> ctr[GBPROX_GLOB_CTR_INV_BVCI]);</span><br><span style="color: hsl(120, 100%, 40%);">+           return bssgp_tx_status(BSSGP_CAUSE_UNKNOWN_BVCI, &ns_bvci, msg);</span><br><span>         }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   if (bvc->blocked) {</span><br><span style="color: hsl(0, 100%, 40%);">-          LOGPBVC(bvc, LOGL_NOTICE, "Dropping PDU for "</span><br><span style="color: hsl(0, 100%, 40%);">-              "blocked BVC via NSE(%05u/SGSN)\n", nsei);</span><br><span style="color: hsl(0, 100%, 40%);">-               rate_ctr_inc(&bvc->ctrg->ctr[GBPROX_PEER_CTR_DROPPED]);</span><br><span style="color: hsl(120, 100%, 40%);">+     if (!bssgp_bvc_fsm_is_unblocked(sgsn_bvc->fi)) {</span><br><span style="color: hsl(120, 100%, 40%);">+           LOGPBVC(sgsn_bvc, LOGL_NOTICE, "Rx %s: Dropping on blocked BVC\n", pdut_name);</span><br><span style="color: hsl(120, 100%, 40%);">+              rate_ctr_inc(&sgsn_bvc->ctrg->ctr[GBPROX_PEER_CTR_DROPPED]);</span><br><span>               return bssgp_tx_status(BSSGP_CAUSE_BVCI_BLOCKED, &ns_bvci, msg);</span><br><span>         }</span><br><span style="color: hsl(120, 100%, 40%);">+     OSMO_ASSERT(sgsn_bvc->cell);</span><br><span style="color: hsl(120, 100%, 40%);">+       bss_bvc = sgsn_bvc->cell->bss_bvc;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-    return gbprox_relay2peer(msg, bvc, ns_bvci);</span><br><span style="color: hsl(120, 100%, 40%);">+  return gbprox_relay2peer(msg, bss_bvc, bss_bvc->bvci);</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-/* process a BVC-RESET message from the BSS side */</span><br><span style="color: hsl(0, 100%, 40%);">-static int gbprox_rx_bvc_reset_from_bss(struct gbproxy_config *cfg, struct msgb *msg,</span><br><span style="color: hsl(0, 100%, 40%);">-                                      uint16_t nsei, struct tlv_parsed *tp)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-  struct gbproxy_bvc *from_bvc = NULL;</span><br><span style="color: hsl(0, 100%, 40%);">-    uint16_t bvci;</span><br><span style="color: hsl(120, 100%, 40%);">+/***********************************************************************</span><br><span style="color: hsl(120, 100%, 40%);">+ * BVC FSM call-backs</span><br><span style="color: hsl(120, 100%, 40%);">+ ***********************************************************************/</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-  if (!TLVP_PRES_LEN(tp, BSSGP_IE_BVCI, 2) || !TLVP_PRES_LEN(tp, BSSGP_IE_CAUSE, 1)) {</span><br><span style="color: hsl(0, 100%, 40%);">-            rate_ctr_inc(&cfg->ctrg->ctr[GBPROX_GLOB_CTR_PROTO_ERR_BSS]);</span><br><span style="color: hsl(0, 100%, 40%);">-         return bssgp_tx_status(BSSGP_CAUSE_MISSING_MAND_IE, NULL, msg);</span><br><span style="color: hsl(120, 100%, 40%);">+/* helper function to dispatch a FSM event to all SGSN-side BVC FSMs of a cell */</span><br><span style="color: hsl(120, 100%, 40%);">+static void dispatch_to_all_sgsn_bvc(struct gbproxy_cell *cell, uint32_t event, void *priv)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    unsigned int i;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     for (i = 0; i < ARRAY_SIZE(cell->sgsn_bvc); i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+              struct gbproxy_bvc *sgsn_bvc = cell->sgsn_bvc[i];</span><br><span style="color: hsl(120, 100%, 40%);">+          if (!sgsn_bvc)</span><br><span style="color: hsl(120, 100%, 40%);">+                        continue;</span><br><span style="color: hsl(120, 100%, 40%);">+             osmo_fsm_inst_dispatch(sgsn_bvc->fi, event, priv);</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%);">+/* BVC FSM informs us about a BSS-side reset of the signaling BVC */</span><br><span style="color: hsl(120, 100%, 40%);">+static void bss_sig_bvc_reset_notif(uint16_t nsei, uint16_t bvci, const struct gprs_ra_id *ra_id,</span><br><span style="color: hsl(120, 100%, 40%);">+                                   uint16_t cell_id, uint8_t cause, void *priv)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   struct gbproxy_bvc *sig_bvc = priv;</span><br><span style="color: hsl(120, 100%, 40%);">+   struct gbproxy_nse *nse = sig_bvc->nse;</span><br><span style="color: hsl(120, 100%, 40%);">+    struct gbproxy_bvc *ptp_bvc;</span><br><span style="color: hsl(120, 100%, 40%);">+  unsigned int i;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     /* BLOCK all SGSN-side PTP BVC within this NSE */</span><br><span style="color: hsl(120, 100%, 40%);">+     hash_for_each(nse->bvcs, i, ptp_bvc, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+               if (ptp_bvc == sig_bvc)</span><br><span style="color: hsl(120, 100%, 40%);">+                       continue;</span><br><span style="color: hsl(120, 100%, 40%);">+             OSMO_ASSERT(ptp_bvc->cell);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+              dispatch_to_all_sgsn_bvc(ptp_bvc->cell, BSSGP_BVCFSM_E_REQ_BLOCK, &cause);</span><br><span>    }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   bvci = ntohs(tlvp_val16_unal(tp, BSSGP_IE_BVCI));</span><br><span style="color: hsl(0, 100%, 40%);">-       LOGP(DGPRS, LOGL_INFO, "NSE(%05u) Rx BVC RESET (BVCI=%05u)\n", nsei, bvci);</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Delete all BSS-side PTP BVC within this NSE */</span><br><span style="color: hsl(120, 100%, 40%);">+     gbproxy_cleanup_bvcs(nse, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       /* TODO: we keep the "CELL" around for now, re-connecting it to</span><br><span style="color: hsl(120, 100%, 40%);">+      * any (later) new PTP-BVC for that BVCI. Not sure if that's the</span><br><span style="color: hsl(120, 100%, 40%);">+   * best idea ? */</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%);">+/* forward declaration */</span><br><span style="color: hsl(120, 100%, 40%);">+static const struct bssgp_bvc_fsm_ops sgsn_ptp_bvc_fsm_ops;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static const struct bssgp_bvc_fsm_ops bss_sig_bvc_fsm_ops = {</span><br><span style="color: hsl(120, 100%, 40%);">+       .reset_notification = bss_sig_bvc_reset_notif,</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%);">+/* BVC FSM informs us about a BSS-side reset of a PTP BVC */</span><br><span style="color: hsl(120, 100%, 40%);">+static void bss_ptp_bvc_reset_notif(uint16_t nsei, uint16_t bvci, const struct gprs_ra_id *ra_id,</span><br><span style="color: hsl(120, 100%, 40%);">+                             uint16_t cell_id, uint8_t cause, void *priv)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   struct gbproxy_bvc *bvc = priv;</span><br><span style="color: hsl(120, 100%, 40%);">+       struct gbproxy_config *cfg = bvc->nse->cfg;</span><br><span style="color: hsl(120, 100%, 40%);">+     unsigned int i;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     OSMO_ASSERT(bvci != 0);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     if (!bvc->cell) {</span><br><span style="color: hsl(120, 100%, 40%);">+          /* see if we have a CELL dangling around */</span><br><span style="color: hsl(120, 100%, 40%);">+           bvc->cell = gbproxy_cell_by_bvci(cfg, bvci);</span><br><span style="color: hsl(120, 100%, 40%);">+               if (bvc->cell) {</span><br><span style="color: hsl(120, 100%, 40%);">+                   /* the CELL already exists. This means either it * was created before at an</span><br><span style="color: hsl(120, 100%, 40%);">+                    * earlier PTP BVC-RESET, or that there are non-unique BVCIs and hence a</span><br><span style="color: hsl(120, 100%, 40%);">+                       * malconfiguration */</span><br><span style="color: hsl(120, 100%, 40%);">+                        if (bvc->cell->bss_bvc) {</span><br><span style="color: hsl(120, 100%, 40%);">+                               LOGPBVC(bvc, LOGL_NOTICE, "Rx BVC-RESET via this NSE, but CELL already "</span><br><span style="color: hsl(120, 100%, 40%);">+                                    "has BVC on NSEI=%05u\n", bvc->cell->bss_bvc->nse->nsei);</span><br><span style="color: hsl(120, 100%, 40%);">+                               LOGPBVC(bvc->cell->bss_bvc, LOGL_NOTICE, "Destroying due to conflicting "</span><br><span style="color: hsl(120, 100%, 40%);">+                                     "BVCI configuration (new NSEI=%05u)!\n", bvc->nse->nsei);</span><br><span style="color: hsl(120, 100%, 40%);">+                             gbproxy_bvc_free(bvc->cell->bss_bvc);</span><br><span style="color: hsl(120, 100%, 40%);">+                   }</span><br><span style="color: hsl(120, 100%, 40%);">+                     bvc->cell->bss_bvc = bvc;</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 (!bvc->cell) {</span><br><span style="color: hsl(120, 100%, 40%);">+          struct gbproxy_nse *sgsn_nse;</span><br><span style="color: hsl(120, 100%, 40%);">+         /* if we end up here, it means this is the first time we received a BVC-RESET</span><br><span style="color: hsl(120, 100%, 40%);">+          * for this BVC.  We need to create the 'cell' data structure and the SGSN-side</span><br><span style="color: hsl(120, 100%, 40%);">+                * BVC counterparts */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+              bvc->cell = gbproxy_cell_alloc(cfg, bvci);</span><br><span style="color: hsl(120, 100%, 40%);">+         OSMO_ASSERT(bvc->cell);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+          /* link us to the cell and vice-versa */</span><br><span style="color: hsl(120, 100%, 40%);">+              bvc->cell->bss_bvc = bvc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+             /* allocate the SGSN-side BVCs within the cell, and reset them */</span><br><span style="color: hsl(120, 100%, 40%);">+             hash_for_each(cfg->sgsn_nses, i, sgsn_nse, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+                 struct gbproxy_bvc *sgsn_bvc = gbproxy_bvc_by_bvci(sgsn_nse, bvci);</span><br><span style="color: hsl(120, 100%, 40%);">+                   if (sgsn_bvc)</span><br><span style="color: hsl(120, 100%, 40%);">+                         OSMO_ASSERT(!sgsn_bvc->cell);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                    if (!sgsn_bvc) {</span><br><span style="color: hsl(120, 100%, 40%);">+                              sgsn_bvc = gbproxy_bvc_alloc(sgsn_nse, bvci);</span><br><span style="color: hsl(120, 100%, 40%);">+                         OSMO_ASSERT(sgsn_bvc);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                              sgsn_bvc->cell = bvc->cell;</span><br><span style="color: hsl(120, 100%, 40%);">+                             sgsn_bvc->fi = bssgp_bvc_fsm_alloc_ptp_bss(sgsn_bvc, cfg->nsi, sgsn_nse->nsei,</span><br><span style="color: hsl(120, 100%, 40%);">+                                                                          bvci, ra_id, cell_id);</span><br><span style="color: hsl(120, 100%, 40%);">+                             OSMO_ASSERT(sgsn_bvc->fi);</span><br><span style="color: hsl(120, 100%, 40%);">+                         bssgp_bvc_fsm_set_ops(sgsn_bvc->fi, &sgsn_ptp_bvc_fsm_ops, sgsn_bvc);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                                gbproxy_cell_add_sgsn_bvc(bvc->cell, sgsn_bvc);</span><br><span style="color: hsl(120, 100%, 40%);">+                    } else {</span><br><span style="color: hsl(120, 100%, 40%);">+                              OSMO_ASSERT(sgsn_bvc->cell == bvc->cell);</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%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* Trigger outbound BVC-RESET procedure toward each SGSN */</span><br><span style="color: hsl(120, 100%, 40%);">+   dispatch_to_all_sgsn_bvc(bvc->cell, BSSGP_BVCFSM_E_REQ_RESET, &cause);</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%);">+/* BVC FSM informs us about a BSS-side FSM state change */</span><br><span style="color: hsl(120, 100%, 40%);">+static void bss_ptp_bvc_state_chg_notif(uint16_t nsei, uint16_t bvci, int old_state, int state, void *priv)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        struct gbproxy_bvc *bvc = priv;</span><br><span style="color: hsl(120, 100%, 40%);">+       struct gbproxy_cell *cell = bvc->cell;</span><br><span style="color: hsl(120, 100%, 40%);">+     uint8_t cause = bssgp_bvc_fsm_get_block_cause(bvc->fi);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  /* we have just been created but due to callback ordering the cell is not associated */</span><br><span style="color: hsl(120, 100%, 40%);">+       if (!cell)</span><br><span style="color: hsl(120, 100%, 40%);">+            return;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     switch (state) {</span><br><span style="color: hsl(120, 100%, 40%);">+      case BSSGP_BVCFSM_S_BLOCKED:</span><br><span style="color: hsl(120, 100%, 40%);">+          /* block the corresponding SGSN-side PTP BVCs */</span><br><span style="color: hsl(120, 100%, 40%);">+              dispatch_to_all_sgsn_bvc(cell, BSSGP_BVCFSM_E_REQ_BLOCK, &cause);</span><br><span style="color: hsl(120, 100%, 40%);">+         break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case BSSGP_BVCFSM_S_UNBLOCKED:</span><br><span style="color: hsl(120, 100%, 40%);">+                /* unblock the corresponding SGSN-side PTP BVCs */</span><br><span style="color: hsl(120, 100%, 40%);">+            dispatch_to_all_sgsn_bvc(cell, BSSGP_BVCFSM_E_REQ_UNBLOCK, NULL);</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%);">+static const struct bssgp_bvc_fsm_ops bss_ptp_bvc_fsm_ops = {</span><br><span style="color: hsl(120, 100%, 40%);">+ .reset_notification = bss_ptp_bvc_reset_notif,</span><br><span style="color: hsl(120, 100%, 40%);">+        .state_chg_notification = bss_ptp_bvc_state_chg_notif,</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%);">+/* BVC FSM informs us about a SGSN-side reset of a PTP BVC */</span><br><span style="color: hsl(120, 100%, 40%);">+static void sgsn_ptp_bvc_reset_notif(uint16_t nsei, uint16_t bvci, const struct gprs_ra_id *ra_id,</span><br><span style="color: hsl(120, 100%, 40%);">+                                    uint16_t cell_id, uint8_t cause, void *priv)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  struct gbproxy_bvc *bvc = priv;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     if (!bvc->cell) {</span><br><span style="color: hsl(120, 100%, 40%);">+          LOGPBVC(bvc, LOGL_ERROR, "RESET of PTP BVC on SGSN side for which we have no BSS?\n");</span><br><span style="color: hsl(120, 100%, 40%);">+              return;</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%);">+   OSMO_ASSERT(bvc->cell->bss_bvc);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      /* request reset of BSS-facing PTP-BVC */</span><br><span style="color: hsl(120, 100%, 40%);">+     osmo_fsm_inst_dispatch(bvc->cell->bss_bvc->fi, BSSGP_BVCFSM_E_REQ_RESET, &cause);</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%);">+static const struct bssgp_bvc_fsm_ops sgsn_ptp_bvc_fsm_ops = {</span><br><span style="color: hsl(120, 100%, 40%);">+   .reset_notification = sgsn_ptp_bvc_reset_notif,</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%);">+/* BVC FSM informs us about a SGSN-side reset of the signaling BVC */</span><br><span style="color: hsl(120, 100%, 40%);">+static void sgsn_sig_bvc_reset_notif(uint16_t nsei, uint16_t bvci, const struct gprs_ra_id *ra_id,</span><br><span style="color: hsl(120, 100%, 40%);">+                                   uint16_t cell_id, uint8_t cause, void *priv)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  struct gbproxy_bvc *bvc = priv;</span><br><span style="color: hsl(120, 100%, 40%);">+       struct gbproxy_config *cfg = bvc->nse->cfg;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct gbproxy_nse *bss_nse;</span><br><span style="color: hsl(120, 100%, 40%);">+  unsigned int i;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     /* delete all SGSN-side PTP BVC for this SGSN */</span><br><span style="color: hsl(120, 100%, 40%);">+      gbproxy_cleanup_bvcs(bvc->nse, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+ /* FIXME: what to do about the cells? */</span><br><span style="color: hsl(120, 100%, 40%);">+      /* FIXME: do we really want to RESET all signaling BVC on the BSS and affect all other SGSN? */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     /* we need to trigger generating a reset procedure towards each BSS side signaling BVC */</span><br><span style="color: hsl(120, 100%, 40%);">+     hash_for_each(cfg->bss_nses, i, bss_nse, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+           struct gbproxy_bvc *bss_bvc = gbproxy_bvc_by_bvci(bss_nse, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+                if (!bss_bvc) {</span><br><span style="color: hsl(120, 100%, 40%);">+                       LOGPNSE(bss_nse, LOGL_ERROR, "Doesn't have BVC with BVCI=0 ?!?\n");</span><br><span style="color: hsl(120, 100%, 40%);">+                     continue;</span><br><span style="color: hsl(120, 100%, 40%);">+             }</span><br><span style="color: hsl(120, 100%, 40%);">+             osmo_fsm_inst_dispatch(bss_bvc->fi, BSSGP_BVCFSM_E_REQ_RESET, &cause);</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%);">+const struct bssgp_bvc_fsm_ops sgsn_sig_bvc_fsm_ops = {</span><br><span style="color: hsl(120, 100%, 40%);">+       .reset_notification = sgsn_sig_bvc_reset_notif,</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%);">+ * Signaling BVC handling</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%);">+/* process a BVC-RESET message from the BSS side */</span><br><span style="color: hsl(120, 100%, 40%);">+static int rx_bvc_reset_from_bss(struct gbproxy_nse *nse, struct msgb *msg, struct tlv_parsed *tp)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   struct gbproxy_bvc *from_bvc = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  uint16_t bvci = ntohs(tlvp_val16_unal(tp, BSSGP_IE_BVCI));</span><br><span style="color: hsl(120, 100%, 40%);">+    uint32_t features = 0; // FIXME: make configurable</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  LOGPNSE(nse, LOGL_INFO, "Rx BVC-RESET (BVCI=%05u)\n", bvci);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>     if (bvci == 0) {</span><br><span>             /* If we receive a BVC reset on the signalling endpoint, we</span><br><span>           * don't want the SGSN to reset, as the signalling endpoint</span><br><span>               * is common for all point-to-point BVCs (and thus all BTS) */</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-              /* Ensure the NSE bvc is there and clear all PtP BVCs */</span><br><span style="color: hsl(0, 100%, 40%);">-                struct gbproxy_nse *nse = gbproxy_nse_by_nsei_or_new(cfg, nsei);</span><br><span style="color: hsl(0, 100%, 40%);">-                if (!nse) {</span><br><span style="color: hsl(0, 100%, 40%);">-                     LOGP(DGPRS, LOGL_ERROR, "Could not create NSE(%05u)\n", nsei);</span><br><span style="color: hsl(0, 100%, 40%);">-                        bssgp_tx_status(BSSGP_CAUSE_PROTO_ERR_UNSPEC, 0, msg);</span><br><span style="color: hsl(0, 100%, 40%);">-                  return 0;</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%);">-               gbproxy_cleanup_bvcs(cfg, nsei, 0);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-             /* FIXME: only do this if SGSN is alive! */</span><br><span style="color: hsl(0, 100%, 40%);">-             LOGPNSE(nse, LOGL_INFO, "Tx fake BVC RESET ACK of BVCI=0\n");</span><br><span style="color: hsl(0, 100%, 40%);">-         bssgp_tx_simple_bvci(BSSGP_PDUT_BVC_RESET_ACK, nsei, 0, 0);</span><br><span style="color: hsl(0, 100%, 40%);">-             return 0;</span><br><span style="color: hsl(0, 100%, 40%);">-       } else {</span><br><span style="color: hsl(0, 100%, 40%);">-                from_bvc = gbproxy_bvc_by_bvci(cfg, bvci);</span><br><span style="color: hsl(120, 100%, 40%);">+            from_bvc = gbproxy_bvc_by_bvci(nse, 0);</span><br><span>              if (!from_bvc) {</span><br><span style="color: hsl(0, 100%, 40%);">-                        struct gbproxy_nse *nse = gbproxy_nse_by_nsei(cfg, nsei);</span><br><span style="color: hsl(0, 100%, 40%);">-                       if (!nse) {</span><br><span style="color: hsl(0, 100%, 40%);">-                             LOGP(DGPRS, LOGL_NOTICE, "NSE(%05u) Got PtP BVC reset before signalling reset for "</span><br><span style="color: hsl(0, 100%, 40%);">-                                   "BVCI=%05u\n", nsei, bvci);</span><br><span style="color: hsl(0, 100%, 40%);">-                           bssgp_tx_status(BSSGP_CAUSE_PDU_INCOMP_STATE, NULL, msg);</span><br><span style="color: hsl(0, 100%, 40%);">-                               return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+                     from_bvc = gbproxy_bvc_alloc(nse, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+                 OSMO_ASSERT(from_bvc);</span><br><span style="color: hsl(120, 100%, 40%);">+                        from_bvc->fi = bssgp_bvc_fsm_alloc_sig_sgsn(from_bvc, nse->cfg->nsi, nse->nsei, features);</span><br><span style="color: hsl(120, 100%, 40%);">+                        if (!from_bvc->fi) {</span><br><span style="color: hsl(120, 100%, 40%);">+                               LOGPNSE(nse, LOGL_ERROR, "Cannot allocate SIG-BVC FSM\n");</span><br><span style="color: hsl(120, 100%, 40%);">+                          gbproxy_bvc_free(from_bvc);</span><br><span style="color: hsl(120, 100%, 40%);">+                           return -ENOMEM;</span><br><span>                      }</span><br><span style="color: hsl(120, 100%, 40%);">+                     bssgp_bvc_fsm_set_ops(from_bvc->fi, &bss_sig_bvc_fsm_ops, from_bvc);</span><br><span style="color: hsl(120, 100%, 40%);">+           }</span><br><span style="color: hsl(120, 100%, 40%);">+     } else {</span><br><span style="color: hsl(120, 100%, 40%);">+              from_bvc = gbproxy_bvc_by_bvci(nse, bvci);</span><br><span style="color: hsl(120, 100%, 40%);">+            if (!from_bvc) {</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 bvc */</span><br><span>                     from_bvc = gbproxy_bvc_alloc(nse, bvci);</span><br><span>                     OSMO_ASSERT(from_bvc);</span><br><span style="color: hsl(0, 100%, 40%);">-                  LOGPBVC(from_bvc, LOGL_INFO, "Allocated new bvc\n");</span><br><span style="color: hsl(120, 100%, 40%);">+                        from_bvc->fi = bssgp_bvc_fsm_alloc_ptp_sgsn(from_bvc, nse->cfg->nsi,</span><br><span style="color: hsl(120, 100%, 40%);">+                                                             nse->nsei, bvci);</span><br><span style="color: hsl(120, 100%, 40%);">+                      if (!from_bvc->fi) {</span><br><span style="color: hsl(120, 100%, 40%);">+                               LOGPNSE(nse, LOGL_ERROR, "Cannot allocate SIG-BVC FSM\n");</span><br><span style="color: hsl(120, 100%, 40%);">+                          gbproxy_bvc_free(from_bvc);</span><br><span style="color: hsl(120, 100%, 40%);">+                           return -ENOMEM;</span><br><span style="color: hsl(120, 100%, 40%);">+                       }</span><br><span style="color: hsl(120, 100%, 40%);">+                     bssgp_bvc_fsm_set_ops(from_bvc->fi, &bss_ptp_bvc_fsm_ops, from_bvc);</span><br><span>          }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(120, 100%, 40%);">+#if 0</span><br><span>             /* Could have moved to a different NSE */</span><br><span>            if (!check_bvc_nsei(from_bvc, nsei)) {</span><br><span>                       LOGPBVC(from_bvc, LOGL_NOTICE, "moving bvc to NSE(%05u)\n", nsei);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-                        struct gbproxy_nse *nse_new = gbproxy_nse_by_nsei(cfg, nsei);</span><br><span style="color: hsl(120, 100%, 40%);">+                 struct gbproxy_nse *nse_new = gbproxy_nse_by_nsei(cfg, nsei, false);</span><br><span>                         if (!nse_new) {</span><br><span>                              LOGP(DGPRS, LOGL_NOTICE, "NSE(%05u) Got PtP BVC reset before signalling reset for "</span><br><span>                                        "BVCI=%05u\n", bvci, nsei);</span><br><span>@@ -410,7 +649,8 @@</span><br><span>                  /* Move bvc to different NSE */</span><br><span>                      gbproxy_bvc_move(from_bvc, nse_new);</span><br><span>                 }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(120, 100%, 40%);">+#endif</span><br><span style="color: hsl(120, 100%, 40%);">+             /* FIXME: do we need this, if it happens within FSM? */</span><br><span>              if (TLVP_PRES_LEN(tp, BSSGP_IE_CELL_ID, 8)) {</span><br><span>                        struct gprs_ra_id raid;</span><br><span>                      /* We have a Cell Identifier present in this</span><br><span>@@ -422,126 +662,158 @@</span><br><span>                       LOGPBVC(from_bvc, LOGL_INFO, "Cell ID %s\n", osmo_rai_name(&raid));</span><br><span>            }</span><br><span>    }</span><br><span style="color: hsl(0, 100%, 40%);">-       /* continue processing / relaying to SGSN[s] */</span><br><span style="color: hsl(0, 100%, 40%);">- return 1;</span><br><span style="color: hsl(120, 100%, 40%);">+     /* hand into FSM for further processing */</span><br><span style="color: hsl(120, 100%, 40%);">+    osmo_fsm_inst_dispatch(from_bvc->fi, BSSGP_BVCFSM_E_RX_RESET, msg);</span><br><span style="color: hsl(120, 100%, 40%);">+        return 0;</span><br><span> }</span><br><span> </span><br><span> /* Receive an incoming signalling message from a BSS-side NS-VC */</span><br><span style="color: hsl(0, 100%, 40%);">-static int gbprox_rx_sig_from_bss(struct gbproxy_config *cfg,</span><br><span style="color: hsl(0, 100%, 40%);">-                             struct msgb *msg, uint16_t nsei,</span><br><span style="color: hsl(0, 100%, 40%);">-                                uint16_t ns_bvci)</span><br><span style="color: hsl(120, 100%, 40%);">+static int gbprox_rx_sig_from_bss(struct gbproxy_nse *nse, struct msgb *msg, uint16_t ns_bvci)</span><br><span> {</span><br><span>     struct bssgp_normal_hdr *bgph = (struct bssgp_normal_hdr *) msgb_bssgph(msg);</span><br><span style="color: hsl(0, 100%, 40%);">-   struct tlv_parsed tp;</span><br><span>        uint8_t pdu_type = bgph->pdu_type;</span><br><span style="color: hsl(120, 100%, 40%);">+ const char *pdut_name = osmo_tlv_prot_msg_name(&osmo_pdef_bssgp, bgph->pdu_type);</span><br><span style="color: hsl(120, 100%, 40%);">+      struct tlv_parsed tp;</span><br><span>        int data_len = msgb_bssgp_len(msg) - sizeof(*bgph);</span><br><span>  struct gbproxy_bvc *from_bvc = NULL;</span><br><span style="color: hsl(0, 100%, 40%);">-    struct gprs_ra_id raid;</span><br><span>      char log_pfx[32];</span><br><span style="color: hsl(120, 100%, 40%);">+     uint16_t ptp_bvci;</span><br><span style="color: hsl(120, 100%, 40%);">+    uint32_t tlli;</span><br><span>       int rc;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-     snprintf(log_pfx, sizeof(log_pfx), "NSE(%05u/BSS)", nsei);</span><br><span style="color: hsl(120, 100%, 40%);">+  snprintf(log_pfx, sizeof(log_pfx), "NSE(%05u/BSS)-BVC(%05u/??)", nse->nsei, ns_bvci);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  LOGP(DGPRS, LOGL_DEBUG, "%s Rx %s\n", log_pfx, pdut_name);</span><br><span> </span><br><span>     if (ns_bvci != 0 && ns_bvci != 1) {</span><br><span style="color: hsl(0, 100%, 40%);">-             LOGP(DGPRS, LOGL_NOTICE, "%s BVCI=%05u is not signalling\n", log_pfx, ns_bvci);</span><br><span style="color: hsl(120, 100%, 40%);">+             LOGP(DGPRS, LOGL_NOTICE, "%s %s BVCI=%05u is not signalling\n", log_pfx, pdut_name, ns_bvci);</span><br><span>              return bssgp_tx_status(BSSGP_CAUSE_PROTO_ERR_UNSPEC, NULL, msg);</span><br><span>     }</span><br><span> </span><br><span>        if (!(bssgp_pdu_type_flags(pdu_type) & BSSGP_PDUF_SIG)) {</span><br><span style="color: hsl(0, 100%, 40%);">-           LOGP(DGPRS, LOGL_NOTICE, "%s %s not allowed in signalling BVC\n", log_pfx,</span><br><span style="color: hsl(0, 100%, 40%);">-                 osmo_tlv_prot_msg_name(&osmo_pdef_bssgp, pdu_type));</span><br><span style="color: hsl(120, 100%, 40%);">+         LOGP(DGPRS, LOGL_NOTICE, "%s %s not allowed in signalling BVC\n", log_pfx, pdut_name);</span><br><span>             return bssgp_tx_status(BSSGP_CAUSE_PROTO_ERR_UNSPEC, NULL, msg);</span><br><span>     }</span><br><span> </span><br><span>        if (!(bssgp_pdu_type_flags(pdu_type) & BSSGP_PDUF_UL)) {</span><br><span style="color: hsl(0, 100%, 40%);">-            LOGP(DGPRS, LOGL_NOTICE, "%s %s not allowed in uplink direction\n", log_pfx,</span><br><span style="color: hsl(0, 100%, 40%);">-               osmo_tlv_prot_msg_name(&osmo_pdef_bssgp, pdu_type));</span><br><span style="color: hsl(120, 100%, 40%);">+         LOGP(DGPRS, LOGL_NOTICE, "%s %s not allowed in uplink direction\n", log_pfx, pdut_name);</span><br><span>           return bssgp_tx_status(BSSGP_CAUSE_PROTO_ERR_UNSPEC, NULL, msg);</span><br><span>     }</span><br><span> </span><br><span>        rc = osmo_tlv_prot_parse(&osmo_pdef_bssgp, &tp, 1, pdu_type, bgph->data, data_len, 0, 0,</span><br><span>                           DGPRS, log_pfx);</span><br><span>    if (rc < 0) {</span><br><span style="color: hsl(0, 100%, 40%);">-                rate_ctr_inc(&cfg->ctrg->ctr[GBPROX_GLOB_CTR_PROTO_ERR_BSS]);</span><br><span style="color: hsl(120, 100%, 40%);">+               rate_ctr_inc(&nse->cfg->ctrg->ctr[GBPROX_GLOB_CTR_PROTO_ERR_BSS]);</span><br><span>              return tx_status_from_tlvp(rc, msg);</span><br><span>         }</span><br><span style="color: hsl(120, 100%, 40%);">+     /* hack to get both msg + tlv_parsed passed via osmo_fsm_inst_dispatch */</span><br><span style="color: hsl(120, 100%, 40%);">+     msgb_bcid(msg) = (void *)&tp;</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ /* special case handling for some PDU types */</span><br><span>       switch (pdu_type) {</span><br><span style="color: hsl(0, 100%, 40%);">-     case BSSGP_PDUT_SUSPEND:</span><br><span style="color: hsl(0, 100%, 40%);">-        case BSSGP_PDUT_RESUME:</span><br><span style="color: hsl(0, 100%, 40%);">-         /* We implement RAI snooping during SUSPEND/RESUME, since it</span><br><span style="color: hsl(0, 100%, 40%);">-             * establishes a relationsip between BVCI/bvc and the routeing</span><br><span style="color: hsl(0, 100%, 40%);">-           * area identification.  The snooped information is then used</span><br><span style="color: hsl(0, 100%, 40%);">-            * for routing the {SUSPEND,RESUME}_[N]ACK back to the correct</span><br><span style="color: hsl(0, 100%, 40%);">-           * BSSGP */</span><br><span style="color: hsl(0, 100%, 40%);">-             if (!TLVP_PRES_LEN(&tp, BSSGP_IE_ROUTEING_AREA, 6))</span><br><span style="color: hsl(0, 100%, 40%);">-                 goto err_mand_ie;</span><br><span style="color: hsl(0, 100%, 40%);">-               from_bvc = gbproxy_bvc_by_nsei(cfg, nsei);</span><br><span style="color: hsl(120, 100%, 40%);">+    case BSSGP_PDUT_BVC_RESET:</span><br><span style="color: hsl(120, 100%, 40%);">+            /* resolve or create gbproxy_bvc + handlei n BVC-FSM */</span><br><span style="color: hsl(120, 100%, 40%);">+               ptp_bvci = ntohs(tlvp_val16_unal(&tp, BSSGP_IE_BVCI));</span><br><span style="color: hsl(120, 100%, 40%);">+            return rx_bvc_reset_from_bss(nse, msg, &tp);</span><br><span style="color: hsl(120, 100%, 40%);">+      case BSSGP_PDUT_BVC_RESET_ACK:</span><br><span style="color: hsl(120, 100%, 40%);">+                ptp_bvci = ntohs(tlvp_val16_unal(&tp, BSSGP_IE_BVCI));</span><br><span style="color: hsl(120, 100%, 40%);">+            from_bvc = gbproxy_bvc_by_bvci(nse, ptp_bvci);</span><br><span>               if (!from_bvc)</span><br><span>                       goto err_no_bvc;</span><br><span style="color: hsl(0, 100%, 40%);">-                memcpy(from_bvc->ra, TLVP_VAL(&tp, BSSGP_IE_ROUTEING_AREA),</span><br><span style="color: hsl(0, 100%, 40%);">-                      sizeof(from_bvc->ra));</span><br><span style="color: hsl(120, 100%, 40%);">+             return osmo_fsm_inst_dispatch(from_bvc->fi, BSSGP_BVCFSM_E_RX_RESET_ACK, msg);</span><br><span style="color: hsl(120, 100%, 40%);">+     case BSSGP_PDUT_BVC_BLOCK:</span><br><span style="color: hsl(120, 100%, 40%);">+            ptp_bvci = ntohs(tlvp_val16_unal(&tp, BSSGP_IE_BVCI));</span><br><span style="color: hsl(120, 100%, 40%);">+            from_bvc = gbproxy_bvc_by_bvci(nse, ptp_bvci);</span><br><span style="color: hsl(120, 100%, 40%);">+                if (!from_bvc)</span><br><span style="color: hsl(120, 100%, 40%);">+                        goto err_no_bvc;</span><br><span style="color: hsl(120, 100%, 40%);">+              return osmo_fsm_inst_dispatch(from_bvc->fi, BSSGP_BVCFSM_E_RX_BLOCK, msg);</span><br><span style="color: hsl(120, 100%, 40%);">+ case BSSGP_PDUT_BVC_UNBLOCK:</span><br><span style="color: hsl(120, 100%, 40%);">+          ptp_bvci = ntohs(tlvp_val16_unal(&tp, BSSGP_IE_BVCI));</span><br><span style="color: hsl(120, 100%, 40%);">+            from_bvc = gbproxy_bvc_by_bvci(nse, ptp_bvci);</span><br><span style="color: hsl(120, 100%, 40%);">+                if (!from_bvc)</span><br><span style="color: hsl(120, 100%, 40%);">+                        goto err_no_bvc;</span><br><span style="color: hsl(120, 100%, 40%);">+              return osmo_fsm_inst_dispatch(from_bvc->fi, BSSGP_BVCFSM_E_RX_UNBLOCK, msg);</span><br><span style="color: hsl(120, 100%, 40%);">+       case BSSGP_PDUT_SUSPEND:</span><br><span style="color: hsl(120, 100%, 40%);">+      case BSSGP_PDUT_RESUME:</span><br><span style="color: hsl(120, 100%, 40%);">+               /* FIXME: Implement TLLI Cache.  Every SUSPEND/RESUME we must</span><br><span style="color: hsl(120, 100%, 40%);">+          * take record of the TLLI->BVC mapping so we can map</span><br><span style="color: hsl(120, 100%, 40%);">+               * back from TLLI->BVC when the SUSPEND/RESUME-ACK</span><br><span style="color: hsl(120, 100%, 40%);">+          * arrives.  Cache should have a timeout of 1-3 seconds</span><br><span style="color: hsl(120, 100%, 40%);">+                * and the ACK should explicitly delete entries. */</span><br><span style="color: hsl(120, 100%, 40%);">+#if 0</span><br><span style="color: hsl(120, 100%, 40%);">+            /* TODO: Validate the RAI for consistency with the RAI</span><br><span style="color: hsl(120, 100%, 40%);">+                 * we expect for any of the BVC within this BSS side NSE */</span><br><span style="color: hsl(120, 100%, 40%);">+           memcpy(ra, TLVP_VAL(&tp, BSSGP_IE_ROUTEING_AREA), sizeof(from_bvc->ra));</span><br><span>              gsm48_parse_ra(&raid, from_bvc->ra);</span><br><span style="color: hsl(0, 100%, 40%);">-             LOGPBVC(from_bvc, LOGL_INFO, "BSSGP SUSPEND/RESUME "</span><br><span style="color: hsl(0, 100%, 40%);">-                  "RAI snooping: RAI %s\n",</span><br><span style="color: hsl(0, 100%, 40%);">-                     osmo_rai_name(&raid));</span><br><span style="color: hsl(0, 100%, 40%);">-              /* FIXME: This only supports one BSS per RA */</span><br><span style="color: hsl(120, 100%, 40%);">+#endif</span><br><span>               break;</span><br><span style="color: hsl(0, 100%, 40%);">-  case BSSGP_PDUT_BVC_RESET:</span><br><span style="color: hsl(0, 100%, 40%);">-              rc = gbprox_rx_bvc_reset_from_bss(cfg, msg, nsei, &tp);</span><br><span style="color: hsl(0, 100%, 40%);">-             /* if function retruns 0, we terminate processing here */</span><br><span style="color: hsl(0, 100%, 40%);">-               if (rc == 0)</span><br><span style="color: hsl(0, 100%, 40%);">-                    return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+     case BSSGP_PDUT_STATUS:</span><br><span style="color: hsl(120, 100%, 40%);">+               /* FIXME: inspect the erroneous PDU IE (if any) and check</span><br><span style="color: hsl(120, 100%, 40%);">+              * if we can extract a TLLI/RNI to route it to the correct SGSN */</span><br><span style="color: hsl(120, 100%, 40%);">+            break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case BSSGP_PDUT_RAN_INFO:</span><br><span style="color: hsl(120, 100%, 40%);">+     case BSSGP_PDUT_RAN_INFO_REQ:</span><br><span style="color: hsl(120, 100%, 40%);">+ case BSSGP_PDUT_RAN_INFO_ACK:</span><br><span style="color: hsl(120, 100%, 40%);">+ case BSSGP_PDUT_RAN_INFO_ERROR:</span><br><span style="color: hsl(120, 100%, 40%);">+       case BSSGP_PDUT_RAN_INFO_APP_ERROR:</span><br><span style="color: hsl(120, 100%, 40%);">+           /* FIXME: route based in RIM Routing IE */</span><br><span style="color: hsl(120, 100%, 40%);">+            rc = bssgp_tx_status(BSSGP_CAUSE_PDU_INCOMP_FEAT, NULL, msg);</span><br><span style="color: hsl(120, 100%, 40%);">+         break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case BSSGP_PDUT_LLC_DISCARD:</span><br><span style="color: hsl(120, 100%, 40%);">+  case BSSGP_PDUT_FLUSH_LL_ACK:</span><br><span style="color: hsl(120, 100%, 40%);">+         /* route based on BVCI + TLLI */</span><br><span style="color: hsl(120, 100%, 40%);">+              ptp_bvci = ntohs(tlvp_val16_unal(&tp, BSSGP_IE_BVCI));</span><br><span style="color: hsl(120, 100%, 40%);">+            tlli = osmo_load32be(TLVP_VAL(&tp, BSSGP_IE_TLLI));</span><br><span style="color: hsl(120, 100%, 40%);">+               from_bvc = gbproxy_bvc_by_bvci(nse, ptp_bvci);</span><br><span style="color: hsl(120, 100%, 40%);">+                if (!from_bvc)</span><br><span style="color: hsl(120, 100%, 40%);">+                        goto err_no_bvc;</span><br><span style="color: hsl(120, 100%, 40%);">+              gbprox_bss2sgsn_tlli(from_bvc->cell, msg, tlli, true);</span><br><span style="color: hsl(120, 100%, 40%);">+             break;</span><br><span style="color: hsl(120, 100%, 40%);">+        default:</span><br><span style="color: hsl(120, 100%, 40%);">+              LOGPNSE(nse, LOGL_ERROR, "Rx %s: Implementation missing\n", pdut_name);</span><br><span>            break;</span><br><span>       }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   return gbprox_relay2sgsn(cfg, msg, ns_bvci, cfg->nsip_sgsn_nsei);</span><br><span style="color: hsl(120, 100%, 40%);">+  return rc;</span><br><span> err_no_bvc:</span><br><span style="color: hsl(0, 100%, 40%);">-       LOGP(DGPRS, LOGL_ERROR, "NSE(%05u/BSS) cannot find bvc based on NSEI\n",</span><br><span style="color: hsl(0, 100%, 40%);">-              nsei);</span><br><span style="color: hsl(0, 100%, 40%);">-  rate_ctr_inc(&cfg->ctrg->ctr[GBPROX_GLOB_CTR_INV_NSEI]);</span><br><span style="color: hsl(120, 100%, 40%);">+    LOGPNSE(nse, LOGL_ERROR, "Rx %s: cannot find BVC for BVCI=%05u\n", pdut_name, ptp_bvci);</span><br><span style="color: hsl(120, 100%, 40%);">+    rate_ctr_inc(&nse->cfg->ctrg->ctr[GBPROX_GLOB_CTR_INV_NSEI]);</span><br><span>   return bssgp_tx_status(BSSGP_CAUSE_INV_MAND_INF, NULL, msg);</span><br><span style="color: hsl(0, 100%, 40%);">-err_mand_ie:</span><br><span style="color: hsl(0, 100%, 40%);">-        LOGP(DGPRS, LOGL_ERROR, "NSE(%05u/BSS) missing mandatory RA IE\n",</span><br><span style="color: hsl(0, 100%, 40%);">-            nsei);</span><br><span style="color: hsl(0, 100%, 40%);">-  rate_ctr_inc(&cfg->ctrg->ctr[GBPROX_GLOB_CTR_PROTO_ERR_BSS]);</span><br><span style="color: hsl(0, 100%, 40%);">- return bssgp_tx_status(BSSGP_CAUSE_MISSING_MAND_IE, NULL, msg);</span><br><span> }</span><br><span> </span><br><span> /* Receive paging request from SGSN, we need to relay to proper BSS */</span><br><span style="color: hsl(0, 100%, 40%);">-static int gbprox_rx_paging(struct gbproxy_config *cfg, struct msgb *msg, struct tlv_parsed *tp,</span><br><span style="color: hsl(0, 100%, 40%);">-                          uint32_t nsei, uint16_t ns_bvci)</span><br><span style="color: hsl(120, 100%, 40%);">+static int gbprox_rx_paging(struct gbproxy_nse *nse, struct msgb *msg, const char *pdut_name,</span><br><span style="color: hsl(120, 100%, 40%);">+                       struct tlv_parsed *tp, uint16_t ns_bvci)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-       struct gbproxy_nse *nse;</span><br><span style="color: hsl(0, 100%, 40%);">-        struct gbproxy_bvc *bvc;</span><br><span style="color: hsl(120, 100%, 40%);">+      struct gbproxy_config *cfg = nse->cfg;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct gbproxy_bvc *sgsn_bvc, *bss_bvc;</span><br><span>      unsigned int n_nses = 0;</span><br><span>     int errctr = GBPROX_GLOB_CTR_PROTO_ERR_SGSN;</span><br><span>         int i, j;</span><br><span> </span><br><span>        /* FIXME: Handle paging logic to only page each matching NSE */</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-     LOGP(DGPRS, LOGL_INFO, "NSE(%05u/SGSN) BSSGP PAGING\n",</span><br><span style="color: hsl(0, 100%, 40%);">-               nsei);</span><br><span>       if (TLVP_PRES_LEN(tp, BSSGP_IE_BVCI, 2)) {</span><br><span>           uint16_t bvci = ntohs(tlvp_val16_unal(tp, BSSGP_IE_BVCI));</span><br><span>           errctr = GBPROX_GLOB_CTR_OTHER_ERR;</span><br><span style="color: hsl(0, 100%, 40%);">-             bvc = gbproxy_bvc_by_bvci(cfg, bvci);</span><br><span style="color: hsl(0, 100%, 40%);">-           if (!bvc) {</span><br><span style="color: hsl(0, 100%, 40%);">-                     LOGP(DGPRS, LOGL_NOTICE, "NSE(%05u/SGSN) BSSGP PAGING: "</span><br><span style="color: hsl(0, 100%, 40%);">-                              "unable to route: BVCI=%05u unknown\n", nsei, bvci);</span><br><span style="color: hsl(120, 100%, 40%);">+                sgsn_bvc = gbproxy_bvc_by_bvci(nse, bvci);</span><br><span style="color: hsl(120, 100%, 40%);">+            if (!sgsn_bvc) {</span><br><span style="color: hsl(120, 100%, 40%);">+                      LOGPNSE(nse, LOGL_NOTICE, "Rx %s: unable to route: BVCI=%05u unknown\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                            pdut_name, bvci);</span><br><span>                    rate_ctr_inc(&cfg->ctrg->ctr[errctr]);</span><br><span>                     return -EINVAL;</span><br><span>              }</span><br><span style="color: hsl(0, 100%, 40%);">-               LOGPBVC(bvc, LOGL_INFO, "routing by BVCI\n");</span><br><span style="color: hsl(0, 100%, 40%);">-         return gbprox_relay2peer(msg, bvc, ns_bvci);</span><br><span style="color: hsl(120, 100%, 40%);">+          LOGPBVC(sgsn_bvc, LOGL_INFO, "Rx %s: routing by BVCI\n", pdut_name);</span><br><span style="color: hsl(120, 100%, 40%);">+                return gbprox_relay2peer(msg, sgsn_bvc->cell->bss_bvc, ns_bvci);</span><br><span>       } else if (TLVP_PRES_LEN(tp, BSSGP_IE_ROUTEING_AREA, 6)) {</span><br><span>           errctr = GBPROX_GLOB_CTR_INV_RAI;</span><br><span>            /* iterate over all bvcs and dispatch the paging to each matching one */</span><br><span>             hash_for_each(cfg->bss_nses, i, nse, list) {</span><br><span style="color: hsl(0, 100%, 40%);">-                 hash_for_each(nse->bvcs, j, bvc, list) {</span><br><span style="color: hsl(0, 100%, 40%);">-                             if (!memcmp(bvc->ra, TLVP_VAL(tp, BSSGP_IE_ROUTEING_AREA), 6)) {</span><br><span style="color: hsl(0, 100%, 40%);">-                                     LOGPNSE(nse, LOGL_INFO, "routing to NSE (RAI match)\n");</span><br><span style="color: hsl(0, 100%, 40%);">-                                      gbprox_relay2peer(msg, bvc, ns_bvci);</span><br><span style="color: hsl(120, 100%, 40%);">+                 hash_for_each(nse->bvcs, j, bss_bvc, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+                               if (!memcmp(bss_bvc->ra, TLVP_VAL(tp, BSSGP_IE_ROUTEING_AREA), 6)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                                       LOGPNSE(nse, LOGL_INFO, "Rx %s: routing to NSE (RAI match)\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                                              pdut_name);</span><br><span style="color: hsl(120, 100%, 40%);">+                                   gbprox_relay2peer(msg, bss_bvc, ns_bvci);</span><br><span>                                    n_nses++;</span><br><span>                                    /* Only send it once to each NSE */</span><br><span>                                  break;</span><br><span>@@ -552,10 +824,11 @@</span><br><span>               errctr = GBPROX_GLOB_CTR_INV_LAI;</span><br><span>            /* iterate over all bvcs and dispatch the paging to each matching one */</span><br><span>             hash_for_each(cfg->bss_nses, i, nse, list) {</span><br><span style="color: hsl(0, 100%, 40%);">-                 hash_for_each(nse->bvcs, j, bvc, list) {</span><br><span style="color: hsl(0, 100%, 40%);">-                             if (!memcmp(bvc->ra, TLVP_VAL(tp, BSSGP_IE_LOCATION_AREA), 5)) {</span><br><span style="color: hsl(0, 100%, 40%);">-                                     LOGPNSE(nse, LOGL_INFO, "routing to NSE (LAI match)\n");</span><br><span style="color: hsl(0, 100%, 40%);">-                                      gbprox_relay2peer(msg, bvc, ns_bvci);</span><br><span style="color: hsl(120, 100%, 40%);">+                 hash_for_each(nse->bvcs, j, bss_bvc, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+                               if (!memcmp(bss_bvc->ra, TLVP_VAL(tp, BSSGP_IE_LOCATION_AREA), 5)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                                       LOGPNSE(nse, LOGL_INFO, "Rx %s: routing to NSE (LAI match)\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                                              pdut_name);</span><br><span style="color: hsl(120, 100%, 40%);">+                                   gbprox_relay2peer(msg, bss_bvc, ns_bvci);</span><br><span>                                    n_nses++;</span><br><span>                                    /* Only send it once to each NSE */</span><br><span>                                  break;</span><br><span>@@ -565,23 +838,21 @@</span><br><span>       } else if (TLVP_PRES_LEN(tp, BSSGP_IE_BSS_AREA_ID, 1)) {</span><br><span>             /* iterate over all bvcs and dispatch the paging to each matching one */</span><br><span>             hash_for_each(cfg->bss_nses, i, nse, list) {</span><br><span style="color: hsl(0, 100%, 40%);">-                 hash_for_each(nse->bvcs, j, bvc, list) {</span><br><span style="color: hsl(0, 100%, 40%);">-                             LOGPNSE(nse, LOGL_INFO, "routing to NSE (broadcast)\n");</span><br><span style="color: hsl(0, 100%, 40%);">-                              gbprox_relay2peer(msg, bvc, ns_bvci);</span><br><span style="color: hsl(120, 100%, 40%);">+                 hash_for_each(nse->bvcs, j, bss_bvc, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+                               LOGPNSE(nse, LOGL_INFO, "Rx %s:routing to NSE (broadcast)\n", pdut_name);</span><br><span style="color: hsl(120, 100%, 40%);">+                           gbprox_relay2peer(msg, bss_bvc, ns_bvci);</span><br><span>                            n_nses++;</span><br><span>                            /* Only send it once to each NSE */</span><br><span>                          break;</span><br><span>                       }</span><br><span>            }</span><br><span>    } else {</span><br><span style="color: hsl(0, 100%, 40%);">-                LOGP(DGPRS, LOGL_ERROR, "NSE(%05u/SGSN) BSSGP PAGING: "</span><br><span style="color: hsl(0, 100%, 40%);">-                       "unable to route, missing IE\n", nsei);</span><br><span style="color: hsl(120, 100%, 40%);">+             LOGPNSE(nse, LOGL_ERROR, "BSSGP PAGING: unable to route, missing IE\n");</span><br><span>           rate_ctr_inc(&cfg->ctrg->ctr[errctr]);</span><br><span>     }</span><br><span> </span><br><span>        if (n_nses == 0) {</span><br><span style="color: hsl(0, 100%, 40%);">-              LOGP(DGPRS, LOGL_ERROR, "NSE(%05u/SGSN) BSSGP PAGING: "</span><br><span style="color: hsl(0, 100%, 40%);">-                       "unable to route, no destination found\n", nsei);</span><br><span style="color: hsl(120, 100%, 40%);">+           LOGPNSE(nse, LOGL_ERROR, "BSSGP PAGING: unable to route, no destination found\n");</span><br><span>                 rate_ctr_inc(&cfg->ctrg->ctr[errctr]);</span><br><span>             return -EINVAL;</span><br><span>      }</span><br><span>@@ -589,63 +860,41 @@</span><br><span> }</span><br><span> </span><br><span> /* Receive an incoming BVC-RESET message from the SGSN */</span><br><span style="color: hsl(0, 100%, 40%);">-static int rx_reset_from_sgsn(struct gbproxy_config *cfg,</span><br><span style="color: hsl(0, 100%, 40%);">-                        struct msgb *orig_msg,</span><br><span style="color: hsl(0, 100%, 40%);">-                  struct msgb *msg, struct tlv_parsed *tp,</span><br><span style="color: hsl(0, 100%, 40%);">-                        uint32_t nsei, uint16_t ns_bvci)</span><br><span style="color: hsl(120, 100%, 40%);">+static int rx_bvc_reset_from_sgsn(struct gbproxy_nse *nse, struct msgb *msg, struct tlv_parsed *tp,</span><br><span style="color: hsl(120, 100%, 40%);">+                 uint16_t ns_bvci)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-  struct gbproxy_nse *nse;</span><br><span style="color: hsl(0, 100%, 40%);">-        struct gbproxy_bvc *bvc;</span><br><span style="color: hsl(0, 100%, 40%);">-        uint16_t ptp_bvci;</span><br><span style="color: hsl(0, 100%, 40%);">-      int i, j;</span><br><span style="color: hsl(120, 100%, 40%);">+     uint16_t ptp_bvci = ntohs(tlvp_val16_unal(tp, BSSGP_IE_BVCI));</span><br><span style="color: hsl(120, 100%, 40%);">+        struct gbproxy_bvc *from_bvc;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-       if (!TLVP_PRES_LEN(tp, BSSGP_IE_BVCI, 2)) {</span><br><span style="color: hsl(0, 100%, 40%);">-             rate_ctr_inc(&cfg->ctrg-></span><br><span style="color: hsl(0, 100%, 40%);">-                          ctr[GBPROX_GLOB_CTR_PROTO_ERR_SGSN]);</span><br><span style="color: hsl(0, 100%, 40%);">-              return bssgp_tx_status(BSSGP_CAUSE_MISSING_MAND_IE,</span><br><span style="color: hsl(0, 100%, 40%);">-                                    NULL, orig_msg);</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">-       ptp_bvci = ntohs(tlvp_val16_unal(tp, BSSGP_IE_BVCI));</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGPNSE(nse, LOGL_INFO, "Rx BVC-RESET (BVCI=%05u)\n", ptp_bvci);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-  if (ptp_bvci >= 2) {</span><br><span style="color: hsl(0, 100%, 40%);">-         /* A reset for a PTP BVC was received, forward it to its</span><br><span style="color: hsl(0, 100%, 40%);">-                 * respective bvc */</span><br><span style="color: hsl(0, 100%, 40%);">-            bvc = gbproxy_bvc_by_bvci(cfg, ptp_bvci);</span><br><span style="color: hsl(0, 100%, 40%);">-               if (!bvc) {</span><br><span style="color: hsl(0, 100%, 40%);">-                     LOGP(DGPRS, LOGL_ERROR, "NSE(%05u/SGSN) BVCI=%05u: Cannot find BSS\n",</span><br><span style="color: hsl(0, 100%, 40%);">-                                nsei, ptp_bvci);</span><br><span style="color: hsl(0, 100%, 40%);">-                        rate_ctr_inc(&cfg->ctrg-></span><br><span style="color: hsl(0, 100%, 40%);">-                                  ctr[GBPROX_GLOB_CTR_INV_BVCI]);</span><br><span style="color: hsl(0, 100%, 40%);">-                    return bssgp_tx_status(BSSGP_CAUSE_UNKNOWN_BVCI,</span><br><span style="color: hsl(0, 100%, 40%);">-                                               &ptp_bvci, orig_msg);</span><br><span style="color: hsl(120, 100%, 40%);">+      if (ptp_bvci == 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+          from_bvc = gbproxy_bvc_by_bvci(nse, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+               OSMO_ASSERT(from_bvc);</span><br><span style="color: hsl(120, 100%, 40%);">+                osmo_fsm_inst_dispatch(from_bvc->fi, BSSGP_BVCFSM_E_RX_RESET, msg);</span><br><span style="color: hsl(120, 100%, 40%);">+        } else {</span><br><span style="color: hsl(120, 100%, 40%);">+              from_bvc = gbproxy_bvc_by_bvci(nse, ptp_bvci);</span><br><span style="color: hsl(120, 100%, 40%);">+                if (!from_bvc) {</span><br><span style="color: hsl(120, 100%, 40%);">+                      LOGPNSE(nse, LOGL_ERROR, "Rx BVC-RESET BVCI=%05u: Cannot find BVC\n", ptp_bvci);</span><br><span style="color: hsl(120, 100%, 40%);">+                    rate_ctr_inc(&nse->cfg->ctrg->ctr[GBPROX_GLOB_CTR_INV_BVCI]);</span><br><span style="color: hsl(120, 100%, 40%);">+                    return bssgp_tx_status(BSSGP_CAUSE_UNKNOWN_BVCI, &ptp_bvci, msg);</span><br><span>                }</span><br><span style="color: hsl(0, 100%, 40%);">-               return gbprox_relay2peer(msg, bvc, ns_bvci);</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%);">-       /* A reset for the Signalling entity has been received</span><br><span style="color: hsl(0, 100%, 40%);">-   * from the SGSN.  As the signalling BVCI is shared</span><br><span style="color: hsl(0, 100%, 40%);">-      * among all the BSS's that we multiplex, it needs to</span><br><span style="color: hsl(0, 100%, 40%);">-        * be relayed  */</span><br><span style="color: hsl(0, 100%, 40%);">-       hash_for_each(cfg->bss_nses, i, nse, list) {</span><br><span style="color: hsl(0, 100%, 40%);">-         hash_for_each(nse->bvcs, j, bvc, list)</span><br><span style="color: hsl(0, 100%, 40%);">-                       gbprox_relay2peer(msg, bvc, ns_bvci);</span><br><span style="color: hsl(120, 100%, 40%);">+         osmo_fsm_inst_dispatch(from_bvc->fi, BSSGP_BVCFSM_E_RX_RESET, msg);</span><br><span>       }</span><br><span> </span><br><span>        return 0;</span><br><span> }</span><br><span> </span><br><span> /* Receive an incoming signalling message from the SGSN-side NS-VC */</span><br><span style="color: hsl(0, 100%, 40%);">-static int gbprox_rx_sig_from_sgsn(struct gbproxy_config *cfg,</span><br><span style="color: hsl(0, 100%, 40%);">-                               struct msgb *orig_msg, uint32_t nsei,</span><br><span style="color: hsl(0, 100%, 40%);">-                           uint16_t ns_bvci)</span><br><span style="color: hsl(120, 100%, 40%);">+static int gbprox_rx_sig_from_sgsn(struct gbproxy_nse *nse, struct msgb *orig_msg, uint16_t ns_bvci)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-    struct bssgp_normal_hdr *bgph =</span><br><span style="color: hsl(0, 100%, 40%);">-         (struct bssgp_normal_hdr *) msgb_bssgph(orig_msg);</span><br><span style="color: hsl(0, 100%, 40%);">-      struct tlv_parsed tp;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct bssgp_normal_hdr *bgph = (struct bssgp_normal_hdr *) msgb_bssgph(orig_msg);</span><br><span>   uint8_t pdu_type = bgph->pdu_type;</span><br><span style="color: hsl(120, 100%, 40%);">+ const char *pdut_name = osmo_tlv_prot_msg_name(&osmo_pdef_bssgp, bgph->pdu_type);</span><br><span style="color: hsl(120, 100%, 40%);">+      struct gbproxy_config *cfg = nse->cfg;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct gbproxy_bvc *sgsn_bvc;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct tlv_parsed tp;</span><br><span>        int data_len;</span><br><span style="color: hsl(0, 100%, 40%);">-   struct gbproxy_nse *nse;</span><br><span style="color: hsl(0, 100%, 40%);">-        struct gbproxy_bvc *bvc;</span><br><span>     uint16_t bvci;</span><br><span>       struct msgb *msg;</span><br><span>    char log_pfx[32];</span><br><span>@@ -653,7 +902,9 @@</span><br><span>      int cause;</span><br><span>   int i;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-      snprintf(log_pfx, sizeof(log_pfx), "NSE(%05u/SGSN)", nsei);</span><br><span style="color: hsl(120, 100%, 40%);">+ snprintf(log_pfx, sizeof(log_pfx), "NSE(%05u/SGSN)-BVC(%05u/??)", nse->nsei, ns_bvci);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGP(DGPRS, LOGL_DEBUG, "%s Rx %s\n", log_pfx, pdut_name);</span><br><span> </span><br><span>     if (ns_bvci != 0 && ns_bvci != 1) {</span><br><span>          LOGP(DGPRS, LOGL_NOTICE, "%s BVCI=%05u is not signalling\n", log_pfx, ns_bvci);</span><br><span>@@ -661,14 +912,12 @@</span><br><span>    }</span><br><span> </span><br><span>        if (!(bssgp_pdu_type_flags(pdu_type) & BSSGP_PDUF_SIG)) {</span><br><span style="color: hsl(0, 100%, 40%);">-           LOGP(DGPRS, LOGL_NOTICE, "%s %s not allowed in signalling BVC\n", log_pfx,</span><br><span style="color: hsl(0, 100%, 40%);">-                 osmo_tlv_prot_msg_name(&osmo_pdef_bssgp, pdu_type));</span><br><span style="color: hsl(120, 100%, 40%);">+         LOGP(DGPRS, LOGL_NOTICE, "%s %s not allowed in signalling BVC\n", log_pfx, pdut_name);</span><br><span>             return bssgp_tx_status(BSSGP_CAUSE_PROTO_ERR_UNSPEC, NULL, orig_msg);</span><br><span>        }</span><br><span> </span><br><span>        if (!(bssgp_pdu_type_flags(pdu_type) & BSSGP_PDUF_DL)) {</span><br><span style="color: hsl(0, 100%, 40%);">-            LOGP(DGPRS, LOGL_NOTICE, "%s %s not allowed in downlink direction\n", log_pfx,</span><br><span style="color: hsl(0, 100%, 40%);">-                     osmo_tlv_prot_msg_name(&osmo_pdef_bssgp, pdu_type));</span><br><span style="color: hsl(120, 100%, 40%);">+         LOGP(DGPRS, LOGL_NOTICE, "%s %s not allowed in downlink direction\n", log_pfx, pdut_name);</span><br><span>                 return bssgp_tx_status(BSSGP_CAUSE_PROTO_ERR_UNSPEC, NULL, orig_msg);</span><br><span>        }</span><br><span> </span><br><span>@@ -685,52 +934,62 @@</span><br><span>                rate_ctr_inc(&cfg->ctrg->ctr[GBPROX_GLOB_CTR_PROTO_ERR_SGSN]);</span><br><span>             return rc;</span><br><span>   }</span><br><span style="color: hsl(120, 100%, 40%);">+     /* hack to get both msg + tlv_parsed passed via osmo_fsm_inst_dispatch */</span><br><span style="color: hsl(120, 100%, 40%);">+     msgb_bcid(msg) = (void *)&tp;</span><br><span> </span><br><span>        switch (pdu_type) {</span><br><span>  case BSSGP_PDUT_BVC_RESET:</span><br><span style="color: hsl(0, 100%, 40%);">-              rc = rx_reset_from_sgsn(cfg, msg, orig_msg, &tp, nsei, ns_bvci);</span><br><span style="color: hsl(120, 100%, 40%);">+          /* resolve or create ggbproxy_bvc + handle in BVC-FSM */</span><br><span style="color: hsl(120, 100%, 40%);">+              bvci = ntohs(tlvp_val16_unal(&tp, BSSGP_IE_BVCI));</span><br><span style="color: hsl(120, 100%, 40%);">+                rc = rx_bvc_reset_from_sgsn(nse, msg, &tp, ns_bvci);</span><br><span>             break;</span><br><span>       case BSSGP_PDUT_BVC_RESET_ACK:</span><br><span style="color: hsl(0, 100%, 40%);">-          /* simple case: BVCI IE is mandatory */</span><br><span style="color: hsl(0, 100%, 40%);">-         if (!TLVP_PRES_LEN(&tp, BSSGP_IE_BVCI, 2))</span><br><span style="color: hsl(0, 100%, 40%);">-                  goto err_mand_ie;</span><br><span>            bvci = ntohs(tlvp_val16_unal(&tp, BSSGP_IE_BVCI));</span><br><span style="color: hsl(0, 100%, 40%);">-          if (bvci == BVCI_SIGNALLING) {</span><br><span style="color: hsl(0, 100%, 40%);">-                  /* TODO: Reset all PTP BVCIs */</span><br><span style="color: hsl(0, 100%, 40%);">-         } else {</span><br><span style="color: hsl(0, 100%, 40%);">-                        rc = gbprox_relay2bvci(cfg, msg, bvci, ns_bvci);</span><br><span style="color: hsl(0, 100%, 40%);">-                }</span><br><span style="color: hsl(120, 100%, 40%);">+             sgsn_bvc = gbproxy_bvc_by_bvci(nse, bvci);</span><br><span style="color: hsl(120, 100%, 40%);">+            if (!sgsn_bvc)</span><br><span style="color: hsl(120, 100%, 40%);">+                        goto err_no_bvc;</span><br><span style="color: hsl(120, 100%, 40%);">+              rc = osmo_fsm_inst_dispatch(sgsn_bvc->fi, BSSGP_BVCFSM_E_RX_RESET_ACK, msg);</span><br><span style="color: hsl(120, 100%, 40%);">+               break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case BSSGP_PDUT_BVC_BLOCK_ACK:</span><br><span style="color: hsl(120, 100%, 40%);">+                bvci = ntohs(tlvp_val16_unal(&tp, BSSGP_IE_BVCI));</span><br><span style="color: hsl(120, 100%, 40%);">+                sgsn_bvc = gbproxy_bvc_by_bvci(nse, bvci);</span><br><span style="color: hsl(120, 100%, 40%);">+            if (!sgsn_bvc)</span><br><span style="color: hsl(120, 100%, 40%);">+                        goto err_no_bvc;</span><br><span style="color: hsl(120, 100%, 40%);">+              rc = osmo_fsm_inst_dispatch(sgsn_bvc->fi, BSSGP_BVCFSM_E_RX_BLOCK_ACK, msg);</span><br><span style="color: hsl(120, 100%, 40%);">+               break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case BSSGP_PDUT_BVC_UNBLOCK_ACK:</span><br><span style="color: hsl(120, 100%, 40%);">+              bvci = ntohs(tlvp_val16_unal(&tp, BSSGP_IE_BVCI));</span><br><span style="color: hsl(120, 100%, 40%);">+                sgsn_bvc = gbproxy_bvc_by_bvci(nse, bvci);</span><br><span style="color: hsl(120, 100%, 40%);">+            if (!sgsn_bvc)</span><br><span style="color: hsl(120, 100%, 40%);">+                        goto err_no_bvc;</span><br><span style="color: hsl(120, 100%, 40%);">+              rc = osmo_fsm_inst_dispatch(sgsn_bvc->fi, BSSGP_BVCFSM_E_RX_UNBLOCK_ACK, msg);</span><br><span>            break;</span><br><span>       case BSSGP_PDUT_FLUSH_LL:</span><br><span>            /* simple case: BVCI IE is mandatory */</span><br><span style="color: hsl(0, 100%, 40%);">-         if (!TLVP_PRES_LEN(&tp, BSSGP_IE_BVCI, 2))</span><br><span style="color: hsl(0, 100%, 40%);">-                  goto err_mand_ie;</span><br><span>            bvci = ntohs(tlvp_val16_unal(&tp, BSSGP_IE_BVCI));</span><br><span style="color: hsl(0, 100%, 40%);">-          rc = gbprox_relay2bvci(cfg, msg, bvci, ns_bvci);</span><br><span style="color: hsl(120, 100%, 40%);">+              sgsn_bvc = gbproxy_bvc_by_bvci(nse, bvci);</span><br><span style="color: hsl(120, 100%, 40%);">+            if (!sgsn_bvc)</span><br><span style="color: hsl(120, 100%, 40%);">+                        goto err_no_bvc;</span><br><span style="color: hsl(120, 100%, 40%);">+              if (sgsn_bvc->cell && sgsn_bvc->cell->bss_bvc)</span><br><span style="color: hsl(120, 100%, 40%);">+                       rc = gbprox_relay2peer(msg, sgsn_bvc->cell->bss_bvc, ns_bvci);</span><br><span>                 break;</span><br><span>       case BSSGP_PDUT_PAGING_PS:</span><br><span>   case BSSGP_PDUT_PAGING_CS:</span><br><span>           /* process the paging request (LAI/RAI lookup) */</span><br><span style="color: hsl(0, 100%, 40%);">-               rc = gbprox_rx_paging(cfg, msg, &tp, nsei, ns_bvci);</span><br><span style="color: hsl(120, 100%, 40%);">+              rc = gbprox_rx_paging(nse, msg, pdut_name, &tp, ns_bvci);</span><br><span>                break;</span><br><span>       case BSSGP_PDUT_STATUS:</span><br><span>              /* Some exception has occurred */</span><br><span style="color: hsl(0, 100%, 40%);">-               LOGP(DGPRS, LOGL_NOTICE,</span><br><span style="color: hsl(0, 100%, 40%);">-                        "NSE(%05u/SGSN) BSSGP STATUS ", nsei);</span><br><span style="color: hsl(0, 100%, 40%);">-                if (!TLVP_PRES_LEN(&tp, BSSGP_IE_CAUSE, 1)) {</span><br><span style="color: hsl(0, 100%, 40%);">-                       LOGPC(DGPRS, LOGL_NOTICE, "\n");</span><br><span style="color: hsl(0, 100%, 40%);">-                      goto err_mand_ie;</span><br><span style="color: hsl(0, 100%, 40%);">-               }</span><br><span>            cause = *TLVP_VAL(&tp, BSSGP_IE_CAUSE);</span><br><span style="color: hsl(0, 100%, 40%);">-             LOGPC(DGPRS, LOGL_NOTICE,</span><br><span style="color: hsl(0, 100%, 40%);">-                       "cause=0x%02x(%s) ", *TLVP_VAL(&tp, BSSGP_IE_CAUSE),</span><br><span style="color: hsl(120, 100%, 40%);">+            LOGPNSE(nse, LOGL_NOTICE, "Rx STATUS cause=0x%02x(%s) ", cause,</span><br><span>                    bssgp_cause_str(cause));</span><br><span>             if (TLVP_PRES_LEN(&tp, BSSGP_IE_BVCI, 2)) {</span><br><span>                      bvci = ntohs(tlvp_val16_unal(&tp, BSSGP_IE_BVCI));</span><br><span>                       LOGPC(DGPRS, LOGL_NOTICE, "BVCI=%05u\n", bvci);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                       if (cause == BSSGP_CAUSE_UNKNOWN_BVCI)</span><br><span style="color: hsl(0, 100%, 40%);">-                          rc = gbprox_relay2bvci(cfg, msg, bvci, ns_bvci);</span><br><span style="color: hsl(120, 100%, 40%);">+                      sgsn_bvc = gbproxy_bvc_by_bvci(nse, bvci);</span><br><span style="color: hsl(120, 100%, 40%);">+                    /* don't send STATUS in response to STATUS if !bvc */</span><br><span style="color: hsl(120, 100%, 40%);">+                     if (sgsn_bvc && sgsn_bvc->cell && sgsn_bvc->cell->bss_bvc)</span><br><span style="color: hsl(120, 100%, 40%);">+                           rc = gbprox_relay2peer(msg, sgsn_bvc->cell->bss_bvc, ns_bvci);</span><br><span>                 } else</span><br><span>                       LOGPC(DGPRS, LOGL_NOTICE, "\n");</span><br><span>           break;</span><br><span>@@ -739,46 +998,30 @@</span><br><span>       case BSSGP_PDUT_SUSPEND_NACK:</span><br><span>        case BSSGP_PDUT_RESUME_ACK:</span><br><span>  case BSSGP_PDUT_RESUME_NACK:</span><br><span style="color: hsl(0, 100%, 40%);">-            /* RAI IE is mandatory */</span><br><span style="color: hsl(0, 100%, 40%);">-               if (!TLVP_PRES_LEN(&tp, BSSGP_IE_ROUTEING_AREA, 6))</span><br><span style="color: hsl(0, 100%, 40%);">-                 goto err_mand_ie;</span><br><span style="color: hsl(0, 100%, 40%);">-               bvc = gbproxy_bvc_by_rai(cfg, TLVP_VAL(&tp, BSSGP_IE_ROUTEING_AREA));</span><br><span style="color: hsl(0, 100%, 40%);">-               if (!bvc)</span><br><span style="color: hsl(0, 100%, 40%);">-                       goto err_no_bvc;</span><br><span style="color: hsl(0, 100%, 40%);">-                rc = gbprox_relay2peer(msg, bvc, ns_bvci);</span><br><span style="color: hsl(0, 100%, 40%);">-              break;</span><br><span style="color: hsl(0, 100%, 40%);">-  case BSSGP_PDUT_BVC_BLOCK_ACK:</span><br><span style="color: hsl(0, 100%, 40%);">-  case BSSGP_PDUT_BVC_UNBLOCK_ACK:</span><br><span style="color: hsl(0, 100%, 40%);">-                if (!TLVP_PRES_LEN(&tp, BSSGP_IE_BVCI, 2))</span><br><span style="color: hsl(0, 100%, 40%);">-                  goto err_mand_ie;</span><br><span style="color: hsl(0, 100%, 40%);">-               bvci = ntohs(tlvp_val16_unal(&tp, BSSGP_IE_BVCI));</span><br><span style="color: hsl(0, 100%, 40%);">-          if (bvci == 0) {</span><br><span style="color: hsl(0, 100%, 40%);">-                        LOGP(DGPRS, LOGL_NOTICE, "NSE(%05u/SGSN) BSSGP "</span><br><span style="color: hsl(0, 100%, 40%);">-                           "%sBLOCK_ACK for signalling BVCI ?!?\n", nsei,</span><br><span style="color: hsl(0, 100%, 40%);">-                        pdu_type == BSSGP_PDUT_BVC_UNBLOCK_ACK ? "UN":"");</span><br><span style="color: hsl(0, 100%, 40%);">-                     /* TODO: should we send STATUS ? */</span><br><span style="color: hsl(0, 100%, 40%);">-                     rate_ctr_inc(&cfg->ctrg-></span><br><span style="color: hsl(0, 100%, 40%);">-                                  ctr[GBPROX_GLOB_CTR_INV_BVCI]);</span><br><span style="color: hsl(0, 100%, 40%);">-            } else {</span><br><span style="color: hsl(0, 100%, 40%);">-                        /* Mark BVC as (un)blocked */</span><br><span style="color: hsl(0, 100%, 40%);">-                   block_unblock_bvc(cfg, bvci, pdu_type);</span><br><span style="color: hsl(0, 100%, 40%);">-         }</span><br><span style="color: hsl(0, 100%, 40%);">-               rc = gbprox_relay2bvci(cfg, msg, bvci, ns_bvci);</span><br><span style="color: hsl(120, 100%, 40%);">+              /* FIXME: handle based on TLLI cache. The RA-ID is not a unique</span><br><span style="color: hsl(120, 100%, 40%);">+                * criterion, so we have to rely on the TLLI->BVC state created</span><br><span style="color: hsl(120, 100%, 40%);">+             * while processing the SUSPEND/RESUME in uplink */</span><br><span style="color: hsl(120, 100%, 40%);">+           /* FIXME: route to SGSN baed on NRI derived from TLLI */</span><br><span>             break;</span><br><span>       case BSSGP_PDUT_SGSN_INVOKE_TRACE:</span><br><span>   case BSSGP_PDUT_OVERLOAD:</span><br><span style="color: hsl(0, 100%, 40%);">-               LOGP(DGPRS, LOGL_DEBUG,</span><br><span style="color: hsl(0, 100%, 40%);">-                 "NSE(%05u/SGSN) BSSGP %s: broadcasting\n", nsei, bssgp_pdu_str(pdu_type));</span><br><span style="color: hsl(120, 100%, 40%);">+          LOGPNSE(nse, LOGL_DEBUG, "Rx %s: broadcasting\n", pdut_name);</span><br><span>              /* broadcast to all BSS-side bvcs */</span><br><span>                 hash_for_each(cfg->bss_nses, i, nse, list) {</span><br><span>                      gbprox_relay2nse(msg, nse, 0);</span><br><span>               }</span><br><span>            break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case BSSGP_PDUT_RAN_INFO:</span><br><span style="color: hsl(120, 100%, 40%);">+     case BSSGP_PDUT_RAN_INFO_REQ:</span><br><span style="color: hsl(120, 100%, 40%);">+ case BSSGP_PDUT_RAN_INFO_ACK:</span><br><span style="color: hsl(120, 100%, 40%);">+ case BSSGP_PDUT_RAN_INFO_ERROR:</span><br><span style="color: hsl(120, 100%, 40%);">+       case BSSGP_PDUT_RAN_INFO_APP_ERROR:</span><br><span style="color: hsl(120, 100%, 40%);">+           /* FIXME: route based in RIM Routing IE */</span><br><span style="color: hsl(120, 100%, 40%);">+            rc = bssgp_tx_status(BSSGP_CAUSE_PDU_INCOMP_FEAT, NULL, orig_msg);</span><br><span style="color: hsl(120, 100%, 40%);">+            break;</span><br><span>       default:</span><br><span style="color: hsl(0, 100%, 40%);">-                LOGP(DGPRS, LOGL_NOTICE, "NSE(%05u/SGSN) BSSGP PDU type %s not supported\n", nsei,</span><br><span style="color: hsl(0, 100%, 40%);">-                 bssgp_pdu_str(pdu_type));</span><br><span style="color: hsl(0, 100%, 40%);">-          rate_ctr_inc(&cfg->ctrg-></span><br><span style="color: hsl(0, 100%, 40%);">-                          ctr[GBPROX_GLOB_CTR_PROTO_ERR_SGSN]);</span><br><span style="color: hsl(120, 100%, 40%);">+            LOGPNSE(nse, LOGL_NOTICE, "Rx %s: Not supported\n", pdut_name);</span><br><span style="color: hsl(120, 100%, 40%);">+             rate_ctr_inc(&cfg->ctrg->ctr[GBPROX_GLOB_CTR_PROTO_ERR_SGSN]);</span><br><span>             rc = bssgp_tx_status(BSSGP_CAUSE_PROTO_ERR_UNSPEC, NULL, orig_msg);</span><br><span>          break;</span><br><span>       }</span><br><span>@@ -786,21 +1029,19 @@</span><br><span>   msgb_free(msg);</span><br><span> </span><br><span>  return rc;</span><br><span style="color: hsl(0, 100%, 40%);">-err_mand_ie:</span><br><span style="color: hsl(0, 100%, 40%);">-  LOGP(DGPRS, LOGL_ERROR, "NSE(%05u/SGSN) missing mandatory IE\n",</span><br><span style="color: hsl(0, 100%, 40%);">-              nsei);</span><br><span style="color: hsl(0, 100%, 40%);">-  rate_ctr_inc(&cfg->ctrg-></span><br><span style="color: hsl(0, 100%, 40%);">-                  ctr[GBPROX_GLOB_CTR_PROTO_ERR_SGSN]);</span><br><span style="color: hsl(0, 100%, 40%);">-      msgb_free(msg);</span><br><span style="color: hsl(0, 100%, 40%);">- return bssgp_tx_status(BSSGP_CAUSE_MISSING_MAND_IE, NULL, orig_msg);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> err_no_bvc:</span><br><span style="color: hsl(0, 100%, 40%);">-   LOGP(DGPRS, LOGL_ERROR, "NSE(%05u/SGSN) cannot find bvc based on RAI\n",</span><br><span style="color: hsl(0, 100%, 40%);">-              nsei);</span><br><span style="color: hsl(120, 100%, 40%);">+        LOGPNSE(nse, LOGL_ERROR, "Rx %s: Cannot find BVC\n", pdut_name);</span><br><span>   rate_ctr_inc(&cfg->ctrg-> ctr[GBPROX_GLOB_CTR_INV_RAI]);</span><br><span>   msgb_free(msg);</span><br><span>      return bssgp_tx_status(BSSGP_CAUSE_INV_MAND_INF, NULL, orig_msg);</span><br><span> }</span><br><span> </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%);">+ * libosmogb NS/BSSGP integration</span><br><span style="color: hsl(120, 100%, 40%);">+ ***********************************************************************/</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> int gbprox_bssgp_send_cb(void *ctx, struct msgb *msg)</span><br><span> {</span><br><span>         int rc;</span><br><span>@@ -820,34 +1061,36 @@</span><br><span> /* Main input function for Gb proxy */</span><br><span> int gbprox_rcvmsg(void *ctx, struct msgb *msg)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-       int rc;</span><br><span style="color: hsl(0, 100%, 40%);">- uint16_t nsei = msgb_nsei(msg);</span><br><span style="color: hsl(0, 100%, 40%);">- uint16_t ns_bvci = msgb_bvci(msg);</span><br><span>   struct gbproxy_config *cfg = (struct gbproxy_config *) ctx;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-     int remote_end_is_sgsn = gbproxy_is_sgsn_nsei(cfg, nsei);</span><br><span style="color: hsl(120, 100%, 40%);">+     uint16_t ns_bvci = msgb_bvci(msg);</span><br><span style="color: hsl(120, 100%, 40%);">+    uint16_t nsei = msgb_nsei(msg);</span><br><span style="color: hsl(120, 100%, 40%);">+       struct gbproxy_nse *nse;</span><br><span> </span><br><span>         /* ensure minimum length to decode PCU type */</span><br><span>       if (msgb_bssgp_len(msg) < sizeof(struct bssgp_normal_hdr))</span><br><span>                return bssgp_tx_status(BSSGP_CAUSE_SEM_INCORR_PDU, NULL, msg);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-      /* Only BVCI=0 messages need special treatment */</span><br><span style="color: hsl(0, 100%, 40%);">-       if (ns_bvci == 0 || ns_bvci == 1) {</span><br><span style="color: hsl(0, 100%, 40%);">-             if (remote_end_is_sgsn)</span><br><span style="color: hsl(0, 100%, 40%);">-                 rc = gbprox_rx_sig_from_sgsn(cfg, msg, nsei, ns_bvci);</span><br><span style="color: hsl(120, 100%, 40%);">+        nse = gbproxy_nse_by_nsei(cfg, nsei, NSE_F_SGSN);</span><br><span style="color: hsl(120, 100%, 40%);">+     if (nse) {</span><br><span style="color: hsl(120, 100%, 40%);">+            if (ns_bvci == 0 || ns_bvci == 1)</span><br><span style="color: hsl(120, 100%, 40%);">+                     return gbprox_rx_sig_from_sgsn(nse, msg, ns_bvci);</span><br><span>           else</span><br><span style="color: hsl(0, 100%, 40%);">-                    rc = gbprox_rx_sig_from_bss(cfg, msg, nsei, ns_bvci);</span><br><span style="color: hsl(0, 100%, 40%);">-   } else {</span><br><span style="color: hsl(0, 100%, 40%);">-                /* All other BVCI are PTP */</span><br><span style="color: hsl(0, 100%, 40%);">-            if (remote_end_is_sgsn)</span><br><span style="color: hsl(0, 100%, 40%);">-                 rc = gbprox_rx_ptp_from_sgsn(cfg, msg, nsei,</span><br><span style="color: hsl(0, 100%, 40%);">-                                                 ns_bvci);</span><br><span style="color: hsl(0, 100%, 40%);">-          else</span><br><span style="color: hsl(0, 100%, 40%);">-                    rc = gbprox_rx_ptp_from_bss(cfg, msg, nsei,</span><br><span style="color: hsl(0, 100%, 40%);">-                                                 ns_bvci);</span><br><span style="color: hsl(120, 100%, 40%);">+                 return gbprox_rx_ptp_from_sgsn(nse, msg, ns_bvci);</span><br><span>   }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   return rc;</span><br><span style="color: hsl(120, 100%, 40%);">+    nse = gbproxy_nse_by_nsei(cfg, nsei, NSE_F_BSS);</span><br><span style="color: hsl(120, 100%, 40%);">+      if (!nse) {</span><br><span style="color: hsl(120, 100%, 40%);">+           LOGP(DGPRS, LOGL_NOTICE, "NSE(%05u/BSS) not known -> allocating\n", nsei);</span><br><span style="color: hsl(120, 100%, 40%);">+               nse = gbproxy_nse_alloc(cfg, nsei, false);</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+     if (nse) {</span><br><span style="color: hsl(120, 100%, 40%);">+            if (ns_bvci == 0 || ns_bvci == 1)</span><br><span style="color: hsl(120, 100%, 40%);">+                     return gbprox_rx_sig_from_bss(nse, msg, ns_bvci);</span><br><span style="color: hsl(120, 100%, 40%);">+             else</span><br><span style="color: hsl(120, 100%, 40%);">+                  return gbprox_rx_ptp_from_bss(nse, msg, ns_bvci);</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 0;</span><br><span> }</span><br><span> </span><br><span> /*  TODO: What about handling:</span><br><span>@@ -865,7 +1108,9 @@</span><br><span>  /* TODO: bss nsei available/unavailable  bssgp_tx_simple_bvci(BSSGP_PDUT_BVC_BLOCK, nsvc->nsei, bvc->bvci, 0);</span><br><span>          * TODO: sgsn nsei available/unavailable</span><br><span>      */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>        struct gbproxy_bvc *bvc;</span><br><span style="color: hsl(120, 100%, 40%);">+      struct gbproxy_nse *sgsn_nse;</span><br><span> </span><br><span>    switch (nsp->u.status.cause) {</span><br><span>    case NS_AFF_CAUSE_SNS_FAILURE:</span><br><span>@@ -874,16 +1119,16 @@</span><br><span> </span><br><span>  case NS_AFF_CAUSE_RECOVERY:</span><br><span>          LOGP(DPCU, LOGL_NOTICE, "NS-NSE %d became available\n", nsp->nsei);</span><br><span style="color: hsl(0, 100%, 40%);">-                if (gbproxy_is_sgsn_nsei(cfg, nsp->nsei)) {</span><br><span style="color: hsl(0, 100%, 40%);">-                  /* look-up or create the BTS context for this BVC */</span><br><span style="color: hsl(0, 100%, 40%);">-                    struct bssgp_bvc_ctx *bctx = btsctx_by_bvci_nsei(nsp->bvci, nsp->nsei);</span><br><span style="color: hsl(0, 100%, 40%);">-                   if (!bctx)</span><br><span style="color: hsl(0, 100%, 40%);">-                              bctx = btsctx_alloc(nsp->bvci, nsp->nsei);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                        bssgp_tx_bvc_reset_nsei_bvci(cfg->nsip_sgsn_nsei, 0, BSSGP_CAUSE_OML_INTERV, NULL, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+             sgsn_nse = gbproxy_nse_by_nsei(cfg, nsp->nsei, NSE_F_SGSN);</span><br><span style="color: hsl(120, 100%, 40%);">+                if (sgsn_nse) {</span><br><span style="color: hsl(120, 100%, 40%);">+                       uint8_t cause = BSSGP_CAUSE_OML_INTERV;</span><br><span style="color: hsl(120, 100%, 40%);">+                       bvc = gbproxy_bvc_by_bvci(sgsn_nse, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+                       if (bvc)</span><br><span style="color: hsl(120, 100%, 40%);">+                              osmo_fsm_inst_dispatch(bvc->fi, BSSGP_BVCFSM_E_REQ_RESET, &cause); </span><br><span>           }</span><br><span>            break;</span><br><span>       case NS_AFF_CAUSE_FAILURE:</span><br><span style="color: hsl(120, 100%, 40%);">+#if 0</span><br><span>            if (gbproxy_is_sgsn_nsei(cfg, nsp->nsei)) {</span><br><span>                       /* sgsn */</span><br><span>                   /* TODO: BSVC: block all PtP towards bss */</span><br><span>@@ -902,9 +1147,11 @@</span><br><span> </span><br><span>                      if (!bvc->blocked)</span><br><span>                                break;</span><br><span style="color: hsl(0, 100%, 40%);">-                  bssgp_tx_simple_bvci(BSSGP_PDUT_BVC_BLOCK, cfg->nsip_sgsn_nsei,</span><br><span style="color: hsl(0, 100%, 40%);">-                                           bvc->bvci, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+                        hash_for_each(cfg->sgsn_nses, _sgsn, sgsn_nse, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+                             bssgp_tx_simple_bvci(BSSGP_PDUT_BVC_BLOCK, sgsn_nse->nsei, bvc->bvci, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+                       }</span><br><span>            }</span><br><span style="color: hsl(120, 100%, 40%);">+#endif</span><br><span>            LOGP(DPCU, LOGL_NOTICE, "NS-NSE %d became unavailable\n", nsp->nsei);</span><br><span>           break;</span><br><span>       default:</span><br><span>@@ -973,6 +1220,8 @@</span><br><span> </span><br><span>          gbproxy_nse_free(nse);</span><br><span>       }</span><br><span style="color: hsl(120, 100%, 40%);">+     /* FIXME: cells */</span><br><span style="color: hsl(120, 100%, 40%);">+    /* FIXME: SGSN side BVCs (except signaling) */</span><br><span> </span><br><span>   rate_ctr_group_free(cfg->ctrg);</span><br><span>   gbproxy_init_config(cfg);</span><br><span>diff --git a/src/gbproxy/gb_proxy_ctrl.c b/src/gbproxy/gb_proxy_ctrl.c</span><br><span>index 21e56dd..4561634 100644</span><br><span>--- a/src/gbproxy/gb_proxy_ctrl.c</span><br><span>+++ b/src/gbproxy/gb_proxy_ctrl.c</span><br><span>@@ -61,9 +61,11 @@</span><br><span>      cmd->reply = talloc_strdup(cmd, "");</span><br><span> </span><br><span>        /* NS-VCs for SGSN */</span><br><span style="color: hsl(0, 100%, 40%);">-   nse = gprs_ns2_nse_by_nsei(nsi, cfg->nsip_sgsn_nsei);</span><br><span style="color: hsl(0, 100%, 40%);">-        if (nse)</span><br><span style="color: hsl(0, 100%, 40%);">-                gprs_ns2_nse_foreach_nsvc(nse, &ctrl_nsvc_state_cb, cmd);</span><br><span style="color: hsl(120, 100%, 40%);">+ hash_for_each(cfg->sgsn_nses, i, nse_peer, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+         nse = gprs_ns2_nse_by_nsei(nsi, nse_peer->nsei);</span><br><span style="color: hsl(120, 100%, 40%);">+           if (nse)</span><br><span style="color: hsl(120, 100%, 40%);">+                      gprs_ns2_nse_foreach_nsvc(nse, &ctrl_nsvc_state_cb, cmd);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span> </span><br><span>        /* NS-VCs for BSS peers */</span><br><span>   hash_for_each(cfg->bss_nses, i, nse_peer, list) {</span><br><span>@@ -95,7 +97,7 @@</span><br><span>                                     nse_peer->nsei, bvc->bvci,</span><br><span>                                     raid.mcc, raid.mnc,</span><br><span>                                  raid.lac, raid.rac,</span><br><span style="color: hsl(0, 100%, 40%);">-                                     bvc->blocked ? "BLOCKED" : "UNBLOCKED");</span><br><span style="color: hsl(120, 100%, 40%);">+                                       osmo_fsm_inst_state_name(bvc->fi));</span><br><span>               }</span><br><span>    }</span><br><span> </span><br><span>diff --git a/src/gbproxy/gb_proxy_main.c b/src/gbproxy/gb_proxy_main.c</span><br><span>index c7ff78c..52b1042 100644</span><br><span>--- a/src/gbproxy/gb_proxy_main.c</span><br><span>+++ b/src/gbproxy/gb_proxy_main.c</span><br><span>@@ -320,13 +320,6 @@</span><br><span>                exit(1);</span><br><span>     }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   if (!gprs_ns2_nse_by_nsei(gbcfg->nsi, gbcfg->nsip_sgsn_nsei)) {</span><br><span style="color: hsl(0, 100%, 40%);">-           LOGP(DGPRS, LOGL_FATAL, "You cannot proxy to NSE(%05u) "</span><br><span style="color: hsl(0, 100%, 40%);">-                      "without creating that NSEI before\n",</span><br><span style="color: hsl(0, 100%, 40%);">-                        gbcfg->nsip_sgsn_nsei);</span><br><span style="color: hsl(0, 100%, 40%);">-              exit(2);</span><br><span style="color: hsl(0, 100%, 40%);">-        }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span>    if (daemonize) {</span><br><span>             rc = osmo_daemonize();</span><br><span>               if (rc < 0) {</span><br><span>diff --git a/src/gbproxy/gb_proxy_peer.c b/src/gbproxy/gb_proxy_peer.c</span><br><span>index 052e577..a0586fe 100644</span><br><span>--- a/src/gbproxy/gb_proxy_peer.c</span><br><span>+++ b/src/gbproxy/gb_proxy_peer.c</span><br><span>@@ -55,56 +55,13 @@</span><br><span> </span><br><span> </span><br><span> /* Find the gbproxy_bvc by its BVCI. There can only be one match */</span><br><span style="color: hsl(0, 100%, 40%);">-struct gbproxy_bvc *gbproxy_bvc_by_bvci(struct gbproxy_config *cfg, uint16_t bvci)</span><br><span style="color: hsl(120, 100%, 40%);">+struct gbproxy_bvc *gbproxy_bvc_by_bvci(struct gbproxy_nse *nse, uint16_t bvci)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-  struct gbproxy_nse *nse;</span><br><span style="color: hsl(0, 100%, 40%);">-        int i;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-  hash_for_each(cfg->bss_nses, i, nse, list) {</span><br><span style="color: hsl(0, 100%, 40%);">-         struct gbproxy_bvc *bvc;</span><br><span style="color: hsl(0, 100%, 40%);">-                hash_for_each_possible(nse->bvcs, bvc, list, bvci) {</span><br><span style="color: hsl(0, 100%, 40%);">-                 if (bvc->bvci == bvci)</span><br><span style="color: hsl(0, 100%, 40%);">-                               return bvc;</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%);">-       return NULL;</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%);">-/* Find the gbproxy_bvc by its NSEI */</span><br><span style="color: hsl(0, 100%, 40%);">-/* FIXME: Only returns the first bvc, but we could have multiple on this nsei */</span><br><span style="color: hsl(0, 100%, 40%);">-struct gbproxy_bvc *gbproxy_bvc_by_nsei(struct gbproxy_config *cfg,</span><br><span style="color: hsl(0, 100%, 40%);">-                                    uint16_t nsei)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-       struct gbproxy_nse *nse = gbproxy_nse_by_nsei(cfg, nsei);</span><br><span>    struct gbproxy_bvc *bvc;</span><br><span style="color: hsl(0, 100%, 40%);">-        int i;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-  if (!nse || hash_empty(nse->bvcs))</span><br><span style="color: hsl(0, 100%, 40%);">-           return NULL;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-    /* return the first entry we find */</span><br><span style="color: hsl(0, 100%, 40%);">-    hash_for_each(nse->bvcs, i, bvc, list)</span><br><span style="color: hsl(0, 100%, 40%);">-               return bvc;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-     return NULL;</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%);">-/* look-up a bvc by its Routeing Area Identification (RAI) */</span><br><span style="color: hsl(0, 100%, 40%);">-/* FIXME: this doesn't make sense, as RA can span multiple bvcs! */</span><br><span style="color: hsl(0, 100%, 40%);">-struct gbproxy_bvc *gbproxy_bvc_by_rai(struct gbproxy_config *cfg,</span><br><span style="color: hsl(0, 100%, 40%);">-                                      const uint8_t *ra)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-    struct gbproxy_nse *nse;</span><br><span style="color: hsl(0, 100%, 40%);">-        int i, j;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       hash_for_each(cfg->bss_nses, i, nse, list) {</span><br><span style="color: hsl(0, 100%, 40%);">-         struct gbproxy_bvc *bvc;</span><br><span style="color: hsl(0, 100%, 40%);">-                hash_for_each(nse->bvcs, j, bvc, list) {</span><br><span style="color: hsl(0, 100%, 40%);">-                     if (!memcmp(bvc->ra, ra, 6))</span><br><span style="color: hsl(0, 100%, 40%);">-                         return bvc;</span><br><span style="color: hsl(0, 100%, 40%);">-             }</span><br><span style="color: hsl(120, 100%, 40%);">+     hash_for_each_possible(nse->bvcs, bvc, list, bvci) {</span><br><span style="color: hsl(120, 100%, 40%);">+               if (bvc->bvci == bvci)</span><br><span style="color: hsl(120, 100%, 40%);">+                     return bvc;</span><br><span>  }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span>    return NULL;</span><br><span> }</span><br><span> </span><br><span>@@ -129,11 +86,13 @@</span><br><span> </span><br><span>     hash_add(nse->bvcs, &bvc->list, bvc->bvci);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-    return bvc;</span><br><span style="color: hsl(120, 100%, 40%);">+        return bvc;</span><br><span> }</span><br><span> </span><br><span> void gbproxy_bvc_free(struct gbproxy_bvc *bvc)</span><br><span> {</span><br><span style="color: hsl(120, 100%, 40%);">+      struct gbproxy_cell *cell;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>         if (!bvc)</span><br><span>            return;</span><br><span> </span><br><span>@@ -142,45 +101,141 @@</span><br><span>         rate_ctr_group_free(bvc->ctrg);</span><br><span>   bvc->ctrg = NULL;</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+      osmo_fsm_inst_free(bvc->fi);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     cell = bvc->cell;</span><br><span style="color: hsl(120, 100%, 40%);">+  if (cell) {</span><br><span style="color: hsl(120, 100%, 40%);">+           int i;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+              if (cell->bss_bvc == bvc)</span><br><span style="color: hsl(120, 100%, 40%);">+                  cell->bss_bvc = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+            /* we could also be a SGSN-side BVC */</span><br><span style="color: hsl(120, 100%, 40%);">+                for (i = 0; i < ARRAY_SIZE(cell->sgsn_bvc); i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+                      if (cell->sgsn_bvc[i] == bvc)</span><br><span style="color: hsl(120, 100%, 40%);">+                              cell->sgsn_bvc[i] = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+          }</span><br><span style="color: hsl(120, 100%, 40%);">+             bvc->cell = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>  talloc_free(bvc);</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-void gbproxy_bvc_move(struct gbproxy_bvc *bvc, struct gbproxy_nse *nse)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-      hash_del(&bvc->list);</span><br><span style="color: hsl(0, 100%, 40%);">-    hash_add(nse->bvcs, &bvc->list, bvc->bvci);</span><br><span style="color: hsl(0, 100%, 40%);">-        bvc->nse = nse;</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%);">-/*! remove bvcs (BVCs) on NSE specified by NSEI.</span><br><span style="color: hsl(120, 100%, 40%);">+/*! remove BVCs on NSE specified by NSEI.</span><br><span>  *  \param[in] cfg proxy in which we operate</span><br><span>  *  \param[in] nsei NS entity in which we should clean up</span><br><span style="color: hsl(0, 100%, 40%);">- *  \param[in] bvci if 0: remove all BVCs; if != 0: BVCI of the single BVC to clean up */</span><br><span style="color: hsl(0, 100%, 40%);">-int gbproxy_cleanup_bvcs(struct gbproxy_config *cfg, uint16_t nsei, uint16_t bvci)</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] bvci if 0: remove all PTP BVCs; if != 0: BVCI of the single BVC to clean up */</span><br><span style="color: hsl(120, 100%, 40%);">+int gbproxy_cleanup_bvcs(struct gbproxy_nse *nse, uint16_t bvci)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-    int i, j, counter = 0;</span><br><span style="color: hsl(0, 100%, 40%);">-  struct gbproxy_nse *nse;</span><br><span style="color: hsl(0, 100%, 40%);">-        struct hlist_node *ntmp;</span><br><span style="color: hsl(0, 100%, 40%);">-        OSMO_ASSERT(cfg);</span><br><span style="color: hsl(120, 100%, 40%);">+     struct hlist_node *btmp;</span><br><span style="color: hsl(120, 100%, 40%);">+      struct gbproxy_bvc *bvc;</span><br><span style="color: hsl(120, 100%, 40%);">+      int j, counter = 0;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- hash_for_each_safe(cfg->bss_nses, i, ntmp, nse, list) {</span><br><span style="color: hsl(0, 100%, 40%);">-              struct gbproxy_bvc *bvc;</span><br><span style="color: hsl(0, 100%, 40%);">-                struct hlist_node *btmp;</span><br><span style="color: hsl(0, 100%, 40%);">-                if (nse->nsei != nsei)</span><br><span style="color: hsl(120, 100%, 40%);">+     if (!nse)</span><br><span style="color: hsl(120, 100%, 40%);">+             return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   hash_for_each_safe(nse->bvcs, j, btmp, bvc, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+                if (bvci && bvc->bvci != bvci)</span><br><span>                    continue;</span><br><span style="color: hsl(0, 100%, 40%);">-               hash_for_each_safe(nse->bvcs, j, btmp, bvc, list) {</span><br><span style="color: hsl(0, 100%, 40%);">-                  if (bvci && bvc->bvci != bvci)</span><br><span style="color: hsl(0, 100%, 40%);">-                               continue;</span><br><span style="color: hsl(120, 100%, 40%);">+             if (bvci == 0 && bvc->bvci == 0)</span><br><span style="color: hsl(120, 100%, 40%);">+                   continue;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-                   gbproxy_bvc_free(bvc);</span><br><span style="color: hsl(0, 100%, 40%);">-                  counter += 1;</span><br><span style="color: hsl(0, 100%, 40%);">-           }</span><br><span style="color: hsl(120, 100%, 40%);">+             gbproxy_bvc_free(bvc);</span><br><span style="color: hsl(120, 100%, 40%);">+                counter += 1;</span><br><span>        }</span><br><span> </span><br><span>        return counter;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 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%);">+/***********************************************************************</span><br><span style="color: hsl(120, 100%, 40%);">+ * CELL</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%);">+/* Allocate a new 'cell' object */</span><br><span style="color: hsl(120, 100%, 40%);">+struct gbproxy_cell *gbproxy_cell_alloc(struct gbproxy_config *cfg, uint16_t bvci)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct gbproxy_cell *cell;</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%);">+   cell = talloc_zero(cfg, struct gbproxy_cell);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!cell)</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%);">+        cell->cfg = cfg;</span><br><span style="color: hsl(120, 100%, 40%);">+   cell->bvci = bvci;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       hash_add(cfg->cells, &cell->list, cell->bvci);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ return cell;</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%);">+/* Find cell by BVCI */</span><br><span style="color: hsl(120, 100%, 40%);">+struct gbproxy_cell *gbproxy_cell_by_bvci(struct gbproxy_config *cfg, uint16_t bvci)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   struct gbproxy_cell *cell;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  hash_for_each_possible(cfg->cells, cell, list, bvci) {</span><br><span style="color: hsl(120, 100%, 40%);">+             if (cell->bvci == bvci)</span><br><span style="color: hsl(120, 100%, 40%);">+                    return cell;</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_cell *gbproxy_cell_by_bvci_or_new(struct gbproxy_config *cfg, uint16_t bvci)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     struct gbproxy_cell *cell;</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%);">+   cell = gbproxy_cell_by_bvci(cfg, bvci);</span><br><span style="color: hsl(120, 100%, 40%);">+       if (!cell)</span><br><span style="color: hsl(120, 100%, 40%);">+            cell = gbproxy_cell_alloc(cfg, bvci);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       return cell;</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_cell_free(struct gbproxy_cell *cell)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       unsigned int i;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     if (!cell)</span><br><span style="color: hsl(120, 100%, 40%);">+            return;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     /* remove from cfg.cells */</span><br><span style="color: hsl(120, 100%, 40%);">+   hash_del(&cell->list);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       /* remove back-pointers from the BSS side */</span><br><span style="color: hsl(120, 100%, 40%);">+  if (cell->bss_bvc && cell->bss_bvc->cell)</span><br><span style="color: hsl(120, 100%, 40%);">+            cell->bss_bvc->cell = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* remove back-pointers from the SGSN side */</span><br><span style="color: hsl(120, 100%, 40%);">+ for (i = 0; i < ARRAY_SIZE(cell->sgsn_bvc); i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+              if (!cell->sgsn_bvc[i])</span><br><span style="color: hsl(120, 100%, 40%);">+                    continue;</span><br><span style="color: hsl(120, 100%, 40%);">+             if (cell->sgsn_bvc[i]->cell)</span><br><span style="color: hsl(120, 100%, 40%);">+                    cell->sgsn_bvc[i]->cell = 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%);">+   talloc_free(cell);</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%);">+bool gbproxy_cell_add_sgsn_bvc(struct gbproxy_cell *cell, struct gbproxy_bvc *bvc)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        unsigned int i;</span><br><span style="color: hsl(120, 100%, 40%);">+       for (i = 0; i < ARRAY_SIZE(cell->sgsn_bvc); i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+              if (!cell->sgsn_bvc[i]) {</span><br><span style="color: hsl(120, 100%, 40%);">+                  cell->sgsn_bvc[i] = bvc;</span><br><span style="color: hsl(120, 100%, 40%);">+                   return true;</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 false;</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%);">+ * NSE - NS Entity</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_alloc(struct gbproxy_config *cfg, uint16_t nsei, bool sgsn_facing)</span><br><span> {</span><br><span>       struct gbproxy_nse *nse;</span><br><span>     OSMO_ASSERT(cfg);</span><br><span>@@ -191,8 +246,12 @@</span><br><span> </span><br><span>         nse->nsei = nsei;</span><br><span>         nse->cfg = cfg;</span><br><span style="color: hsl(120, 100%, 40%);">+    nse->sgsn_facing = sgsn_facing;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-  hash_add(cfg->bss_nses, &nse->list, nsei);</span><br><span style="color: hsl(120, 100%, 40%);">+  if (sgsn_facing)</span><br><span style="color: hsl(120, 100%, 40%);">+              hash_add(cfg->sgsn_nses, &nse->list, nsei);</span><br><span style="color: hsl(120, 100%, 40%);">+ else</span><br><span style="color: hsl(120, 100%, 40%);">+          hash_add(cfg->bss_nses, &nse->list, nsei);</span><br><span> </span><br><span>     hash_init(nse->bvcs);</span><br><span> </span><br><span>@@ -216,27 +275,36 @@</span><br><span>         talloc_free(nse);</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 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(struct gbproxy_config *cfg, uint16_t nsei, uint32_t flags)</span><br><span> {</span><br><span>        struct gbproxy_nse *nse;</span><br><span>     OSMO_ASSERT(cfg);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   hash_for_each_possible(cfg->bss_nses, nse, list, nsei) {</span><br><span style="color: hsl(0, 100%, 40%);">-             if (nse->nsei == nsei)</span><br><span style="color: hsl(0, 100%, 40%);">-                       return nse;</span><br><span style="color: hsl(120, 100%, 40%);">+   if (flags & NSE_F_SGSN) {</span><br><span style="color: hsl(120, 100%, 40%);">+         hash_for_each_possible(cfg->sgsn_nses, nse, list, nsei) {</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%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (flags & NSE_F_BSS) {</span><br><span style="color: hsl(120, 100%, 40%);">+          hash_for_each_possible(cfg->bss_nses, nse, list, nsei) {</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>    }</span><br><span> </span><br><span>        return NULL;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 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%);">+struct gbproxy_nse *gbproxy_nse_by_nsei_or_new(struct gbproxy_config *cfg, uint16_t nsei, bool sgsn_facing)</span><br><span> {</span><br><span>     struct gbproxy_nse *nse;</span><br><span>     OSMO_ASSERT(cfg);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   nse = gbproxy_nse_by_nsei(cfg, nsei);</span><br><span style="color: hsl(120, 100%, 40%);">+ nse = gbproxy_nse_by_nsei(cfg, nsei, sgsn_facing ? NSE_F_SGSN : NSE_F_BSS);</span><br><span>  if (!nse)</span><br><span style="color: hsl(0, 100%, 40%);">-               nse = gbproxy_nse_alloc(cfg, nsei);</span><br><span style="color: hsl(120, 100%, 40%);">+           nse = gbproxy_nse_alloc(cfg, nsei, sgsn_facing);</span><br><span> </span><br><span>         return nse;</span><br><span> }</span><br><span>diff --git a/src/gbproxy/gb_proxy_vty.c b/src/gbproxy/gb_proxy_vty.c</span><br><span>index da5710a..a9db596 100644</span><br><span>--- a/src/gbproxy/gb_proxy_vty.c</span><br><span>+++ b/src/gbproxy/gb_proxy_vty.c</span><br><span>@@ -31,6 +31,7 @@</span><br><span> #include <osmocom/gsm/gsm48.h></span><br><span> </span><br><span> #include <osmocom/gprs/gprs_ns2.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/gprs/bssgp_bvc_fsm.h></span><br><span> #include <osmocom/gsm/apn.h></span><br><span> </span><br><span> #include <osmocom/sgsn/debug.h></span><br><span>@@ -43,6 +44,7 @@</span><br><span> #include <osmocom/vty/vty.h></span><br><span> #include <osmocom/vty/misc.h></span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> static struct gbproxy_config *g_cfg = NULL;</span><br><span> </span><br><span> /*</span><br><span>@@ -61,7 +63,7 @@</span><br><span> </span><br><span>  vty_out(vty, "NSEI %5u, PTP-BVCI %5u, "</span><br><span>            "RAI %s", bvc->nse->nsei, bvc->bvci, osmo_rai_name(&raid));</span><br><span style="color: hsl(0, 100%, 40%);">-      if (bvc->blocked)</span><br><span style="color: hsl(120, 100%, 40%);">+  if (bssgp_bvc_fsm_is_unblocked(bvc->fi))</span><br><span>          vty_out(vty, " [BVC-BLOCKED]");</span><br><span> </span><br><span>        vty_out(vty, "%s", VTY_NEWLINE);</span><br><span>@@ -69,10 +71,14 @@</span><br><span> </span><br><span> static int config_write_gbproxy(struct vty *vty)</span><br><span> {</span><br><span style="color: hsl(120, 100%, 40%);">+ struct gbproxy_nse *nse;</span><br><span style="color: hsl(120, 100%, 40%);">+      int i;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>     vty_out(vty, "gbproxy%s", VTY_NEWLINE);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   vty_out(vty, " sgsn nsei %u%s", g_cfg->nsip_sgsn_nsei,</span><br><span style="color: hsl(0, 100%, 40%);">-             VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+ hash_for_each(g_cfg->sgsn_nses, i, nse, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+            vty_out(vty, " sgsn nsei %u%s", nse->nsei, VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span> </span><br><span>        return CMD_SUCCESS;</span><br><span> }</span><br><span>@@ -86,6 +92,9 @@</span><br><span>         return CMD_SUCCESS;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+extern const struct bssgp_bvc_fsm_ops sgsn_sig_bvc_fsm_ops;</span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/gprs/protocol/gsm_08_18.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> DEFUN(cfg_nsip_sgsn_nsei,</span><br><span>       cfg_nsip_sgsn_nsei_cmd,</span><br><span>       "sgsn nsei <0-65534>",</span><br><span>@@ -93,10 +102,36 @@</span><br><span>       "NSEI to be used in the connection with the SGSN\n"</span><br><span>       "The NSEI\n")</span><br><span> {</span><br><span style="color: hsl(120, 100%, 40%);">+     uint32_t features = 0; // FIXME: make configurable</span><br><span>   unsigned int nsei = atoi(argv[0]);</span><br><span style="color: hsl(120, 100%, 40%);">+    struct gbproxy_nse *nse;</span><br><span style="color: hsl(120, 100%, 40%);">+      struct gbproxy_bvc *bvc;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-    g_cfg->nsip_sgsn_nsei = nsei;</span><br><span style="color: hsl(120, 100%, 40%);">+      nse = gbproxy_nse_by_nsei_or_new(g_cfg, nsei, true);</span><br><span style="color: hsl(120, 100%, 40%);">+  if (!nse)</span><br><span style="color: hsl(120, 100%, 40%);">+             goto free_nothing;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  if (!gbproxy_bvc_by_bvci(nse, 0)) {</span><br><span style="color: hsl(120, 100%, 40%);">+           uint8_t cause = BSSGP_CAUSE_OML_INTERV;</span><br><span style="color: hsl(120, 100%, 40%);">+               bvc = gbproxy_bvc_alloc(nse, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+              if (!bvc)</span><br><span style="color: hsl(120, 100%, 40%);">+                     goto free_nse;</span><br><span style="color: hsl(120, 100%, 40%);">+                bvc->fi = bssgp_bvc_fsm_alloc_sig_bss(bvc, nse->cfg->nsi, nsei, features);</span><br><span style="color: hsl(120, 100%, 40%);">+           if (!bvc->fi)</span><br><span style="color: hsl(120, 100%, 40%);">+                      goto free_bvc;</span><br><span style="color: hsl(120, 100%, 40%);">+                bssgp_bvc_fsm_set_ops(bvc->fi, &sgsn_sig_bvc_fsm_ops, bvc);</span><br><span style="color: hsl(120, 100%, 40%);">+            osmo_fsm_inst_dispatch(bvc->fi, BSSGP_BVCFSM_E_REQ_RESET, &cause);</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>  return CMD_SUCCESS;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+free_bvc:</span><br><span style="color: hsl(120, 100%, 40%);">+      gbproxy_bvc_free(bvc);</span><br><span style="color: hsl(120, 100%, 40%);">+free_nse:</span><br><span style="color: hsl(120, 100%, 40%);">+     gbproxy_nse_free(nse);</span><br><span style="color: hsl(120, 100%, 40%);">+free_nothing:</span><br><span style="color: hsl(120, 100%, 40%);">+ vty_out(vty, "%% Unable to create NSE for NSEI=%05u%s", nsei, VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+ return CMD_WARNING;</span><br><span> }</span><br><span> </span><br><span> static void log_set_bvc_filter(struct log_target *target,</span><br><span>@@ -181,9 +216,15 @@</span><br><span> {</span><br><span>        const uint16_t nsei = atoi(argv[0]);</span><br><span>         const uint16_t bvci = atoi(argv[1]);</span><br><span style="color: hsl(120, 100%, 40%);">+  struct gbproxy_nse *nse = gbproxy_nse_by_nsei(g_cfg, nsei, NSE_F_BSS);</span><br><span>       int counter;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-        counter = gbproxy_cleanup_bvcs(g_cfg, nsei, bvci);</span><br><span style="color: hsl(120, 100%, 40%);">+    if (!nse) {</span><br><span style="color: hsl(120, 100%, 40%);">+           vty_out(vty, "NSE not found%s", VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+               return CMD_WARNING;</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%);">+   counter = gbproxy_cleanup_bvcs(nse, bvci);</span><br><span> </span><br><span>       if (counter == 0) {</span><br><span>          vty_out(vty, "BVC not found%s", VTY_NEWLINE);</span><br><span>@@ -219,8 +260,8 @@</span><br><span> </span><br><span>    if (delete_bvc) {</span><br><span>            if (!dry_run) {</span><br><span style="color: hsl(0, 100%, 40%);">-                 struct gbproxy_nse *nse = gbproxy_nse_by_nsei(g_cfg, nsei);</span><br><span style="color: hsl(0, 100%, 40%);">-                     counter = gbproxy_cleanup_bvcs(g_cfg, nsei, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+                       struct gbproxy_nse *nse = gbproxy_nse_by_nsei(g_cfg, nsei, NSE_F_BSS);</span><br><span style="color: hsl(120, 100%, 40%);">+                        counter = gbproxy_cleanup_bvcs(nse, 0);</span><br><span>                      gbproxy_nse_free(nse);</span><br><span>               } else {</span><br><span>                     struct gbproxy_nse *nse;</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.osmocom.org/c/osmo-sgsn/+/21612">change 21612</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/+/21612"/><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: Ie0746f17927a9509c3806cc80dc1a31d25df7937 </div>
<div style="display:none"> Gerrit-Change-Number: 21612 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: laforge <laforge@osmocom.org> </div>
<div style="display:none"> Gerrit-MessageType: newchange </div>