<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>