<p>laforge has uploaded this change for <strong>review</strong>.</p><p><a href="https://gerrit.osmocom.org/c/libosmocore/+/21598">View Change</a></p><pre style="font-family: monospace,monospace; white-space: pre-wrap;">gb: Add beginnings of a new BSSGP implementation<br><br>Similar to ns2 superseding ns, we now also intoduce a next generation<br>of BSSGP related code to libosmogb.  However, this is not aiming to<br>be a full implementation yet, but simply those parts that we currently<br>need from the revamped osmo-gbproxy.<br><br>The gprs_bssgp2.[ch] differs in two ways from the old code:<br>* it separates message encoding from message transmission<br>* it supports more recent specs / IEs<br><br>bssgp_bvc_fsm.c is a genric implementation of the BSSGP BVC<br>RESET/BLOCK/UNBLOCK logic with support for both PTP and signaling,<br>both on the SGSN side and the BSS side.<br><br>Change-Id: Icbe8e4f03b68fd73b8eae95f6f6cccd4fa9af95a<br>---<br>M include/Makefile.am<br>A include/osmocom/gprs/bssgp_bvc_fsm.h<br>A include/osmocom/gprs/gprs_bssgp2.h<br>M src/gb/Makefile.am<br>A src/gb/bssgp_bvc_fsm.c<br>A src/gb/gprs_bssgp2.c<br>M src/gb/libosmogb.map<br>7 files changed, 1,055 insertions(+), 0 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">git pull ssh://gerrit.osmocom.org:29418/libosmocore refs/changes/98/21598/1</pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/include/Makefile.am b/include/Makefile.am</span><br><span>index f67e1ad..44b04b4 100644</span><br><span>--- a/include/Makefile.am</span><br><span>+++ b/include/Makefile.am</span><br><span>@@ -64,6 +64,7 @@</span><br><span>                     osmocom/ctrl/control_if.h \</span><br><span>                  osmocom/ctrl/ports.h \</span><br><span>                        osmocom/gprs/frame_relay.h \</span><br><span style="color: hsl(120, 100%, 40%);">+                       osmocom/gprs/bssgp_bvc_fsm.h \</span><br><span>                        osmocom/gprs/gprs_bssgp.h \</span><br><span>                        osmocom/gprs/gprs_bssgp_bss.h \</span><br><span>                        osmocom/gprs/gprs_msgb.h \</span><br><span>diff --git a/include/osmocom/gprs/bssgp_bvc_fsm.h b/include/osmocom/gprs/bssgp_bvc_fsm.h</span><br><span>new file mode 100644</span><br><span>index 0000000..7c6fdeb</span><br><span>--- /dev/null</span><br><span>+++ b/include/osmocom/gprs/bssgp_bvc_fsm.h</span><br><span>@@ -0,0 +1,61 @@</span><br><span style="color: hsl(120, 100%, 40%);">+#pragma once</span><br><span style="color: hsl(120, 100%, 40%);">+#include <stdint.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct gprs_ns2_inst;</span><br><span style="color: hsl(120, 100%, 40%);">+struct osmo_fsm_inst;</span><br><span style="color: hsl(120, 100%, 40%);">+struct gprs_ra_id;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+enum bssp_ptp_bvc_fsm_state {</span><br><span style="color: hsl(120, 100%, 40%);">+     BSSGP_BVCFSM_S_NULL,</span><br><span style="color: hsl(120, 100%, 40%);">+  BSSGP_BVCFSM_S_BLOCKED,</span><br><span style="color: hsl(120, 100%, 40%);">+       BSSGP_BVCFSM_S_WAIT_RESET_ACK,</span><br><span style="color: hsl(120, 100%, 40%);">+        BSSGP_BVCFSM_S_UNBLOCKED,</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%);">+enum bssgp_ptp_bvc_fsm_event {</span><br><span style="color: hsl(120, 100%, 40%);">+       /* Rx of BSSGP PDUs from the remote side; 'data' is 'struct tlv_parsed', and</span><br><span style="color: hsl(120, 100%, 40%);">+   * the assumption is that the caller has already validated all mandatory IEs</span><br><span style="color: hsl(120, 100%, 40%);">+   * are present and of sufficient length */</span><br><span style="color: hsl(120, 100%, 40%);">+    BSSGP_BVCFSM_E_RX_BLOCK,</span><br><span style="color: hsl(120, 100%, 40%);">+      BSSGP_BVCFSM_E_RX_BLOCK_ACK,</span><br><span style="color: hsl(120, 100%, 40%);">+  BSSGP_BVCFSM_E_RX_UNBLOCK,</span><br><span style="color: hsl(120, 100%, 40%);">+    BSSGP_BVCFSM_E_RX_UNBLOCK_ACK,</span><br><span style="color: hsl(120, 100%, 40%);">+        BSSGP_BVCFSM_E_RX_RESET,</span><br><span style="color: hsl(120, 100%, 40%);">+      BSSGP_BVCFSM_E_RX_RESET_ACK,</span><br><span style="color: hsl(120, 100%, 40%);">+  /* Requests of the local user */</span><br><span style="color: hsl(120, 100%, 40%);">+      BSSGP_BVCFSM_E_REQ_BLOCK,       /* data: uint8_t *cause */</span><br><span style="color: hsl(120, 100%, 40%);">+    BSSGP_BVCFSM_E_REQ_UNBLOCK,</span><br><span style="color: hsl(120, 100%, 40%);">+   BSSGP_BVCFSM_E_REQ_RESET,       /* data: uint8_t *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%);">+struct bssgp_bvc_fsm_ops {</span><br><span style="color: hsl(120, 100%, 40%);">+  /* call-back notifying the user of a state change */</span><br><span style="color: hsl(120, 100%, 40%);">+  void (*state_chg_notification)(uint16_t nsei, uint16_t bvci, int old_state, int new_state,</span><br><span style="color: hsl(120, 100%, 40%);">+                                    void *priv);</span><br><span style="color: hsl(120, 100%, 40%);">+  /* call-back notifying the user of a BVC-RESET event */</span><br><span style="color: hsl(120, 100%, 40%);">+       void (*reset_notification)(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%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct osmo_fsm_inst *</span><br><span style="color: hsl(120, 100%, 40%);">+bssgp_bvc_fsm_alloc_sig_bss(void *ctx, struct gprs_ns2_inst *nsi, uint16_t nsei, uint32_t features);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct osmo_fsm_inst *</span><br><span style="color: hsl(120, 100%, 40%);">+bssgp_bvc_fsm_alloc_ptp_bss(void *ctx, struct gprs_ns2_inst *nsi, uint16_t nsei, uint16_t bvci,</span><br><span style="color: hsl(120, 100%, 40%);">+                           const struct gprs_ra_id *ra_id, uint16_t cell_id);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct osmo_fsm_inst *</span><br><span style="color: hsl(120, 100%, 40%);">+bssgp_bvc_fsm_alloc_sig_sgsn(void *ctx, struct gprs_ns2_inst *nsi, uint16_t nsei, uint32_t features);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct osmo_fsm_inst *</span><br><span style="color: hsl(120, 100%, 40%);">+bssgp_bvc_fsm_alloc_ptp_sgsn(void *ctx, struct gprs_ns2_inst *nsi, uint16_t nsei, uint16_t bvci);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void bssgp_bvc_fsm_set_ops(struct osmo_fsm_inst *fi, const struct bssgp_bvc_fsm_ops *ops, void *ops_priv);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+bool bssgp_bvc_fsm_is_unblocked(struct osmo_fsm_inst *fi);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+uint8_t bssgp_bvc_fsm_get_block_cause(struct osmo_fsm_inst *fi);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+uint32_t bssgp_bvc_get_features_advertised(struct osmo_fsm_inst *fi);</span><br><span style="color: hsl(120, 100%, 40%);">+uint32_t bssgp_bvc_get_features_received(struct osmo_fsm_inst *fi);</span><br><span style="color: hsl(120, 100%, 40%);">+uint32_t bssgp_bvc_get_features_negotiated(struct osmo_fsm_inst *fi);</span><br><span>diff --git a/include/osmocom/gprs/gprs_bssgp2.h b/include/osmocom/gprs/gprs_bssgp2.h</span><br><span>new file mode 100644</span><br><span>index 0000000..0ab3619</span><br><span>--- /dev/null</span><br><span>+++ b/include/osmocom/gprs/gprs_bssgp2.h</span><br><span>@@ -0,0 +1,31 @@</span><br><span style="color: hsl(120, 100%, 40%);">+#pragma once</span><br><span style="color: hsl(120, 100%, 40%);">+#include <stdint.h></span><br><span style="color: hsl(120, 100%, 40%);">+</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%);">+#include <osmocom/gprs/gprs_ns2.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct gprs_ns2_inst;</span><br><span style="color: hsl(120, 100%, 40%);">+struct gprs_ra_id;</span><br><span style="color: hsl(120, 100%, 40%);">+struct msgb;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int bssgp2_nsi_tx_ptp(struct gprs_ns2_inst *nsi, uint16_t nsei, uint16_t bvci,</span><br><span style="color: hsl(120, 100%, 40%);">+                struct msgb *msg, uint32_t lsp);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int bssgp2_nsi_tx_sig(struct gprs_ns2_inst *nsi, uint16_t nsei, struct msgb *msg, uint32_t lsp);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct msgb *bssgp2_enc_bvc_block(uint16_t bvci, enum gprs_bssgp_cause cause);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct msgb *bssgp2_enc_bvc_block_ack(uint16_t bvci);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct msgb *bssgp2_enc_bvc_unblock(uint16_t bvci);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct msgb *bssgp2_enc_bvc_unblock_ack(uint16_t bvci);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct msgb *bssgp2_enc_bvc_reset(uint16_t bvci, enum gprs_bssgp_cause cause,</span><br><span style="color: hsl(120, 100%, 40%);">+                                const struct gprs_ra_id *ra_id, uint16_t cell_id,</span><br><span style="color: hsl(120, 100%, 40%);">+                             const uint8_t *feat_bm, const uint8_t *ext_feat_bm);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct msgb *bssgp2_enc_bvc_reset_ack(uint16_t bvci, const struct gprs_ra_id *ra_id, uint16_t cell_id,</span><br><span style="color: hsl(120, 100%, 40%);">+                                    const uint8_t *feat_bm, const uint8_t *ext_feat_bm);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct msgb *bssgp2_enc_status(uint8_t cause, const uint16_t *bvci, const struct msgb *orig_msg);</span><br><span>diff --git a/src/gb/Makefile.am b/src/gb/Makefile.am</span><br><span>index b140727..ea1cfde 100644</span><br><span>--- a/src/gb/Makefile.am</span><br><span>+++ b/src/gb/Makefile.am</span><br><span>@@ -26,6 +26,7 @@</span><br><span>               gprs_bssgp_bss.c \</span><br><span>                   gprs_ns2.c gprs_ns2_udp.c gprs_ns2_frgre.c gprs_ns2_fr.c gprs_ns2_vc_fsm.c gprs_ns2_sns.c \</span><br><span>                  gprs_ns2_message.c gprs_ns2_vty.c \</span><br><span style="color: hsl(120, 100%, 40%);">+           gprs_bssgp2.c bssgp_bvc_fsm.c \</span><br><span>              common_vty.c frame_relay.c</span><br><span> endif</span><br><span> </span><br><span>diff --git a/src/gb/bssgp_bvc_fsm.c b/src/gb/bssgp_bvc_fsm.c</span><br><span>new file mode 100644</span><br><span>index 0000000..f54144d</span><br><span>--- /dev/null</span><br><span>+++ b/src/gb/bssgp_bvc_fsm.c</span><br><span>@@ -0,0 +1,719 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/* BSSGP per-BVC Finite State Machine */</span><br><span style="color: hsl(120, 100%, 40%);">+/* (C) 2020 by Harald Welte <laforge@gnumonks.org> */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* FIXME: This should probably be moved to libosmogb? */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <string.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <stdio.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/fsm.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/logging.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/utils.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/gsm/gsm48.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/gsm/tlv.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/gprs/gprs_msgb.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/gprs/gprs_bssgp.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/gprs/gprs_bssgp2.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/gprs/bssgp_bvc_fsm.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include "common_vty.h"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define S(x)      (1 << (x))</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* FIXME: Tdef API */</span><br><span style="color: hsl(120, 100%, 40%);">+#define T1   1</span><br><span style="color: hsl(120, 100%, 40%);">+#define T2   2</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define T1_SECS    5       /* 1s < T1 < 30s */</span><br><span style="color: hsl(120, 100%, 40%);">+#define T2_SECS      10      /* 1s < T2 < 120s */</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 struct osmo_fsm bssgp_bvc_fsm;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static const struct value_string ptp_bvc_event_names[] = {</span><br><span style="color: hsl(120, 100%, 40%);">+  { BSSGP_BVCFSM_E_RX_BLOCK, "RX-BVC-BLOCK" },</span><br><span style="color: hsl(120, 100%, 40%);">+        { BSSGP_BVCFSM_E_RX_BLOCK_ACK, "RX-BVC-BLOCK-ACK" },</span><br><span style="color: hsl(120, 100%, 40%);">+        { BSSGP_BVCFSM_E_RX_UNBLOCK, "RX-BVC-UNBLOCK" },</span><br><span style="color: hsl(120, 100%, 40%);">+    { BSSGP_BVCFSM_E_RX_UNBLOCK_ACK, "RX-BVC-UNBLOCK-ACK" },</span><br><span style="color: hsl(120, 100%, 40%);">+    { BSSGP_BVCFSM_E_RX_RESET, "RX-BVC-RESET" },</span><br><span style="color: hsl(120, 100%, 40%);">+        { BSSGP_BVCFSM_E_RX_RESET_ACK, "RX-BVC-RESET-ACK" },</span><br><span style="color: hsl(120, 100%, 40%);">+        { BSSGP_BVCFSM_E_REQ_BLOCK, "REQ-BLOCK" },</span><br><span style="color: hsl(120, 100%, 40%);">+  { BSSGP_BVCFSM_E_REQ_UNBLOCK, "REQ-UNBLOCK" },</span><br><span style="color: hsl(120, 100%, 40%);">+      { BSSGP_BVCFSM_E_REQ_RESET, "REQ-RESET" },</span><br><span style="color: hsl(120, 100%, 40%);">+  { 0, 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 bvc_fsm_priv {</span><br><span style="color: hsl(120, 100%, 40%);">+      /* NS-instance; defining the scope for NSEI below */</span><br><span style="color: hsl(120, 100%, 40%);">+  struct gprs_ns2_inst *nsi;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  /* NSEI of the underlying NS Entity */</span><br><span style="color: hsl(120, 100%, 40%);">+        uint16_t nsei;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      /* BVCI of this BVC */</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%);">+      /* are we the SGSN (true) or the BSS (false) */</span><br><span style="color: hsl(120, 100%, 40%);">+       bool role_sgsn;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     /* BSS side: are we locally marked blocked? */</span><br><span style="color: hsl(120, 100%, 40%);">+        bool locally_blocked;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t block_cause;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        /* cause value of the last outbound BVC-RESET (for re-transmissions) */</span><br><span style="color: hsl(120, 100%, 40%);">+       uint8_t last_reset_cause;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   struct {</span><br><span style="color: hsl(120, 100%, 40%);">+              /* Bit 0..7: Features; Bit 8..15: Extended Features */</span><br><span style="color: hsl(120, 100%, 40%);">+                uint32_t advertised;</span><br><span style="color: hsl(120, 100%, 40%);">+          uint32_t received;</span><br><span style="color: hsl(120, 100%, 40%);">+            uint32_t negotiated;</span><br><span style="color: hsl(120, 100%, 40%);">+  } features;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Cell Identification used by BSS when</span><br><span style="color: hsl(120, 100%, 40%);">+        * transmitting BVC-RESET / BVC-RESET-ACK, or those received</span><br><span style="color: hsl(120, 100%, 40%);">+   * from BSS in SGSN role */</span><br><span style="color: hsl(120, 100%, 40%);">+   struct gprs_ra_id ra_id;</span><br><span style="color: hsl(120, 100%, 40%);">+      uint16_t cell_id;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* call-backs provided by the user */</span><br><span style="color: hsl(120, 100%, 40%);">+ const struct bssgp_bvc_fsm_ops *ops;</span><br><span style="color: hsl(120, 100%, 40%);">+  /* private data pointer passed to each call-back invocation */</span><br><span style="color: hsl(120, 100%, 40%);">+        void *ops_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%);">+static int fi_tx_ptp(struct osmo_fsm_inst *fi, struct msgb *msg)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    struct bssgp_normal_hdr *bgph = (struct bssgp_normal_hdr *) msgb_bssgph(msg);</span><br><span style="color: hsl(120, 100%, 40%);">+ struct bvc_fsm_priv *bfp = fi->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     OSMO_ASSERT(fi->fsm == &bssgp_bvc_fsm);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      LOGPFSM(fi, "Tx BSSGP %s\n", osmo_tlv_prot_msg_name(&osmo_pdef_bssgp, bgph->pdu_type));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    return bssgp2_nsi_tx_sig(bfp->nsi, bfp->nsei, msg, bfp->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%);">+static int fi_tx_sig(struct osmo_fsm_inst *fi, struct msgb *msg)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     struct bssgp_normal_hdr *bgph = (struct bssgp_normal_hdr *) msgb_bssgph(msg);</span><br><span style="color: hsl(120, 100%, 40%);">+ struct bvc_fsm_priv *bfp = fi->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     OSMO_ASSERT(fi->fsm == &bssgp_bvc_fsm);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      LOGPFSM(fi, "Tx BSSGP %s\n", osmo_tlv_prot_msg_name(&osmo_pdef_bssgp, bgph->pdu_type));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    return bssgp2_nsi_tx_sig(bfp->nsi, bfp->nsei, msg, 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%);">+/* helper function to transmit BVC-RESET with right combination of conditional/optional IEs */</span><br><span style="color: hsl(120, 100%, 40%);">+static void _tx_bvc_reset(struct osmo_fsm_inst *fi, uint8_t cause)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      struct bvc_fsm_priv *bfp = fi->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+       const uint8_t *features = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+       const uint8_t *features_ext = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+   uint8_t _features[2] = {</span><br><span style="color: hsl(120, 100%, 40%);">+              (bfp->features.advertised >> 0) & 0xff,</span><br><span style="color: hsl(120, 100%, 40%);">+          (bfp->features.advertised >> 8) & 0xff,</span><br><span style="color: hsl(120, 100%, 40%);">+  };</span><br><span style="color: hsl(120, 100%, 40%);">+    struct msgb *tx;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    OSMO_ASSERT(fi->fsm == &bssgp_bvc_fsm);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      /* transmit BVC-RESET to peer; RA-ID only present for PTP from BSS */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (bfp->bvci == 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+              features = &_features[0];</span><br><span style="color: hsl(120, 100%, 40%);">+         features_ext = &_features[1];</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+     tx = bssgp2_enc_bvc_reset(bfp->bvci, cause,</span><br><span style="color: hsl(120, 100%, 40%);">+                                  bfp->bvci && !bfp->role_sgsn ? &bfp->ra_id : NULL,</span><br><span style="color: hsl(120, 100%, 40%);">+                               bfp->cell_id, features, features_ext);</span><br><span style="color: hsl(120, 100%, 40%);">+   fi_tx_sig(fi, tx);</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%);">+/* helper function to transmit BVC-RESET-ACK with right combination of conditional/optional IEs */</span><br><span style="color: hsl(120, 100%, 40%);">+static void _tx_bvc_reset_ack(struct osmo_fsm_inst *fi)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       struct bvc_fsm_priv *bfp = fi->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+       const uint8_t *features = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+       const uint8_t *features_ext = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+   uint8_t _features[2] = {</span><br><span style="color: hsl(120, 100%, 40%);">+              (bfp->features.advertised >> 0) & 0xff,</span><br><span style="color: hsl(120, 100%, 40%);">+          (bfp->features.advertised >> 8) & 0xff,</span><br><span style="color: hsl(120, 100%, 40%);">+  };</span><br><span style="color: hsl(120, 100%, 40%);">+    struct msgb *tx;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    OSMO_ASSERT(fi->fsm == &bssgp_bvc_fsm);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      /* transmit BVC-RESET-ACK to peer; RA-ID only present for PTP from BSS -> SGSN */</span><br><span style="color: hsl(120, 100%, 40%);">+  if (bfp->bvci == 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+              features = &_features[0];</span><br><span style="color: hsl(120, 100%, 40%);">+         features_ext = &_features[1];</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+     tx = bssgp2_enc_bvc_reset_ack(bfp->bvci, bfp->bvci && !bfp->role_sgsn ? &bfp->ra_id : NULL,</span><br><span style="color: hsl(120, 100%, 40%);">+                                bfp->cell_id, features, features_ext);</span><br><span style="color: hsl(120, 100%, 40%);">+        fi_tx_sig(fi, tx);</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%);">+/* helper function to transmit BVC-STATUS with right combination of conditional/optional IEs */</span><br><span style="color: hsl(120, 100%, 40%);">+static void _tx_status(struct osmo_fsm_inst *fi, enum gprs_bssgp_cause cause, const struct msgb *rx)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     struct bvc_fsm_priv *bfp = fi->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+       struct msgb *tx;</span><br><span style="color: hsl(120, 100%, 40%);">+      uint16_t *bvci = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      /* GSM 08.18, 10.4.14.1: The BVCI must be included if (and only if) the</span><br><span style="color: hsl(120, 100%, 40%);">+        * cause is either "BVCI blocked" or "BVCI unknown" */</span><br><span style="color: hsl(120, 100%, 40%);">+    if (cause == BSSGP_CAUSE_UNKNOWN_BVCI || cause == BSSGP_CAUSE_BVCI_BLOCKED)</span><br><span style="color: hsl(120, 100%, 40%);">+           bvci = &bfp->bvci;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   tx = bssgp2_enc_status(cause, bvci, rx);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    if (msgb_bvci(rx) == 0)</span><br><span style="color: hsl(120, 100%, 40%);">+               fi_tx_sig(fi, tx);</span><br><span style="color: hsl(120, 100%, 40%);">+    else</span><br><span style="color: hsl(120, 100%, 40%);">+          fi_tx_ptp(fi, tx);</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%);">+/* Update the features by bit-wise AND of advertised + received features */</span><br><span style="color: hsl(120, 100%, 40%);">+static void update_negotiated_features(struct osmo_fsm_inst *fi, const struct tlv_parsed *tp)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        struct bvc_fsm_priv *bfp = fi->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+       uint32_t features_rx = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   OSMO_ASSERT(fi->fsm == &bssgp_bvc_fsm);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      if (TLVP_PRES_LEN(tp, BSSGP_IE_FEATURE_BITMAP, 1))</span><br><span style="color: hsl(120, 100%, 40%);">+            features_rx |= *TLVP_VAL(tp, BSSGP_IE_FEATURE_BITMAP);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      if (TLVP_PRES_LEN(tp, BSSGP_IE_EXT_FEATURE_BITMAP, 1))</span><br><span style="color: hsl(120, 100%, 40%);">+                features_rx |= (*TLVP_VAL(tp, BSSGP_IE_EXT_FEATURE_BITMAP) << 8);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     bfp->features.negotiated = bfp->features.advertised & features_rx;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        LOGPFSML(fi, LOGL_NOTICE, "Updating features: Advertised 0x%04x, Received 0x%04x, Negotiated 0x%04x\n",</span><br><span style="color: hsl(120, 100%, 40%);">+              bfp->features.advertised, features_rx, bfp->features.negotiated);</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%);">+/* "tail" of each onenter() handler: Calling the state change notification call-back */</span><br><span style="color: hsl(120, 100%, 40%);">+static void _onenter_tail(struct osmo_fsm_inst *fi, uint32_t prev_state)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct bvc_fsm_priv *bfp = fi->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     if (prev_state == fi->state)</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%);">+     if (bfp->ops && bfp->ops->state_chg_notification)</span><br><span style="color: hsl(120, 100%, 40%);">+            bfp->ops->state_chg_notification(bfp->nsei, bfp->bvci, prev_state, fi->state, bfp->ops_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%);">+static void bssgp_bvc_fsm_null(struct osmo_fsm_inst *fi, uint32_t event, void *data)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ /* we don't really expect anything in this state; all handled via allstate */</span><br><span style="color: hsl(120, 100%, 40%);">+     OSMO_ASSERT(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 void bssgp_bvc_fsm_blocked_onenter(struct osmo_fsm_inst *fi, uint32_t prev_state)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     struct bvc_fsm_priv *bfp = fi->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+       /* signaling BVC can never be blocked */</span><br><span style="color: hsl(120, 100%, 40%);">+      OSMO_ASSERT(bfp->bvci != 0);</span><br><span style="color: hsl(120, 100%, 40%);">+       _onenter_tail(fi, prev_state);</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 void bssgp_bvc_fsm_blocked(struct osmo_fsm_inst *fi, uint32_t event, void *data)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       struct bvc_fsm_priv *bfp = fi->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+       struct msgb *rx = NULL, *tx;</span><br><span style="color: hsl(120, 100%, 40%);">+  const struct tlv_parsed *tp = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+   uint8_t cause;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      switch (event) {</span><br><span style="color: hsl(120, 100%, 40%);">+      case BSSGP_BVCFSM_E_RX_BLOCK_ACK:</span><br><span style="color: hsl(120, 100%, 40%);">+             rx = data;</span><br><span style="color: hsl(120, 100%, 40%);">+            tp = (const struct tlv_parsed *) msgb_bcid(rx);</span><br><span style="color: hsl(120, 100%, 40%);">+               /* If a BVC-BLOCK-ACK PDU is received by a BSS for the signalling BVC, the PDU is ignored. */</span><br><span style="color: hsl(120, 100%, 40%);">+         if (bfp->bvci == 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                      LOGPFSML(fi, LOGL_ERROR, "Rx BVC-BLOCK-ACK on BVCI=0 is illegal\n");</span><br><span style="color: hsl(120, 100%, 40%);">+                        if (!bfp->role_sgsn)</span><br><span style="color: hsl(120, 100%, 40%);">+                               break;</span><br><span style="color: hsl(120, 100%, 40%);">+                        _tx_status(fi, BSSGP_CAUSE_SEM_INCORR_PDU, rx);</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%);">+             /* stop T1 timer */</span><br><span style="color: hsl(120, 100%, 40%);">+           osmo_fsm_inst_state_chg(fi, BSSGP_BVCFSM_S_BLOCKED, 0, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+            break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case BSSGP_BVCFSM_E_RX_BLOCK:</span><br><span style="color: hsl(120, 100%, 40%);">+         rx = data;</span><br><span style="color: hsl(120, 100%, 40%);">+            tp = (const struct tlv_parsed *) msgb_bcid(rx);</span><br><span style="color: hsl(120, 100%, 40%);">+               cause = *TLVP_VAL(tp, BSSGP_IE_CAUSE);</span><br><span style="color: hsl(120, 100%, 40%);">+                LOGPFSML(fi, LOGL_NOTICE, "Rx BVC-BLOCK (cause=%s)\n", bssgp_cause_str(cause));</span><br><span style="color: hsl(120, 100%, 40%);">+             /* If a BVC-BLOCK PDU is received by an SGSN for a blocked BVC, a BVC-BLOCK-ACK</span><br><span style="color: hsl(120, 100%, 40%);">+                * PDU shall be returned. */</span><br><span style="color: hsl(120, 100%, 40%);">+          if (bfp->role_sgsn) {</span><br><span style="color: hsl(120, 100%, 40%);">+                      /* If a BVC-BLOCK PDU is received by an SGSN for</span><br><span style="color: hsl(120, 100%, 40%);">+                       * the signalling BVC, the PDU is ignored */</span><br><span style="color: hsl(120, 100%, 40%);">+                  if (bfp->bvci == 0)</span><br><span style="color: hsl(120, 100%, 40%);">+                                break;</span><br><span style="color: hsl(120, 100%, 40%);">+                        tx = bssgp2_enc_bvc_block_ack(bfp->bvci);</span><br><span style="color: hsl(120, 100%, 40%);">+                  fi_tx_sig(fi, tx);</span><br><span style="color: hsl(120, 100%, 40%);">+            }</span><br><span style="color: hsl(120, 100%, 40%);">+             break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case BSSGP_BVCFSM_E_RX_UNBLOCK:</span><br><span style="color: hsl(120, 100%, 40%);">+               rx = data;</span><br><span style="color: hsl(120, 100%, 40%);">+            tp = (const struct tlv_parsed *) msgb_bcid(rx);</span><br><span style="color: hsl(120, 100%, 40%);">+               LOGPFSML(fi, LOGL_NOTICE, "Rx BVC-UNBLOCK\n");</span><br><span style="color: hsl(120, 100%, 40%);">+              if (bfp->bvci == 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                      LOGPFSML(fi, LOGL_ERROR, "Rx BVC-UNBLOCK on BVCI=0 is illegal\n");</span><br><span style="color: hsl(120, 100%, 40%);">+                  /* If BVC-UNBLOCK PDU is received by an SGSN for the signalling BVC, the PDU is ignored.*/</span><br><span style="color: hsl(120, 100%, 40%);">+                    if (bfp->role_sgsn)</span><br><span style="color: hsl(120, 100%, 40%);">+                                break;</span><br><span style="color: hsl(120, 100%, 40%);">+                        _tx_status(fi, BSSGP_CAUSE_SEM_INCORR_PDU, rx);</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%);">+             if (!bfp->role_sgsn) {</span><br><span style="color: hsl(120, 100%, 40%);">+                     LOGPFSML(fi, LOGL_ERROR, "Rx BVC-UNBLOCK on BSS is illegal\n");</span><br><span style="color: hsl(120, 100%, 40%);">+                     _tx_status(fi, BSSGP_CAUSE_SEM_INCORR_PDU, rx);</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%);">+             tx = bssgp2_enc_bvc_unblock_ack(bfp->bvci);</span><br><span style="color: hsl(120, 100%, 40%);">+                fi_tx_sig(fi, tx);</span><br><span style="color: hsl(120, 100%, 40%);">+            osmo_fsm_inst_state_chg(fi, BSSGP_BVCFSM_S_UNBLOCKED, T1_SECS, T1);</span><br><span style="color: hsl(120, 100%, 40%);">+           break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case BSSGP_BVCFSM_E_REQ_UNBLOCK:</span><br><span style="color: hsl(120, 100%, 40%);">+              if (bfp->role_sgsn) {</span><br><span style="color: hsl(120, 100%, 40%);">+                      LOGPFSML(fi, LOGL_ERROR, "SGSN side cannot initiate BVC unblock\n");</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%);">+             if (bfp->bvci == 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                      LOGPFSML(fi, LOGL_ERROR, "BVCI 0 cannot be unblocked\n");</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%);">+             bfp->locally_blocked = false;</span><br><span style="color: hsl(120, 100%, 40%);">+              tx = bssgp2_enc_bvc_unblock(bfp->bvci);</span><br><span style="color: hsl(120, 100%, 40%);">+            fi_tx_sig(fi, tx);</span><br><span style="color: hsl(120, 100%, 40%);">+            osmo_fsm_inst_state_chg(fi, BSSGP_BVCFSM_S_UNBLOCKED, 0, 0);</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%);">+/* Waiting for RESET-ACK: Receive PDUs but don't transmit */</span><br><span style="color: hsl(120, 100%, 40%);">+static void bssgp_bvc_fsm_wait_reset_ack(struct osmo_fsm_inst *fi, uint32_t event, void *data)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   struct bvc_fsm_priv *bfp = fi->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+       const struct tlv_parsed *tp = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+   struct msgb *rx = NULL, *tx;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        switch (event) {</span><br><span style="color: hsl(120, 100%, 40%);">+      case BSSGP_BVCFSM_E_RX_RESET_ACK:</span><br><span style="color: hsl(120, 100%, 40%);">+             rx = data;</span><br><span style="color: hsl(120, 100%, 40%);">+            tp = (const struct tlv_parsed *) msgb_bcid(rx);</span><br><span style="color: hsl(120, 100%, 40%);">+               if (bfp->bvci == 0)</span><br><span style="color: hsl(120, 100%, 40%);">+                        update_negotiated_features(fi, tp);</span><br><span style="color: hsl(120, 100%, 40%);">+           if (bfp->role_sgsn && bfp->bvci != 0)</span><br><span style="color: hsl(120, 100%, 40%);">+                   bfp->cell_id = bssgp_parse_cell_id(&bfp->ra_id, TLVP_VAL(tp, BSSGP_IE_CELL_ID));</span><br><span style="color: hsl(120, 100%, 40%);">+            if (!bfp->role_sgsn && bfp->bvci != 0 && bfp->locally_blocked) {</span><br><span style="color: hsl(120, 100%, 40%);">+                     /* initiate the blocking procedure */</span><br><span style="color: hsl(120, 100%, 40%);">+                 /* transmit BVC-BLOCK, transition to BLOCKED state and start re-transmit timer */</span><br><span style="color: hsl(120, 100%, 40%);">+                     tx = bssgp2_enc_bvc_block(bfp->bvci, bfp->block_cause);</span><br><span style="color: hsl(120, 100%, 40%);">+                 fi_tx_sig(fi, tx);</span><br><span style="color: hsl(120, 100%, 40%);">+                    osmo_fsm_inst_state_chg(fi, BSSGP_BVCFSM_S_BLOCKED, T1_SECS, T1);</span><br><span style="color: hsl(120, 100%, 40%);">+             } else</span><br><span style="color: hsl(120, 100%, 40%);">+                        osmo_fsm_inst_state_chg(fi, BSSGP_BVCFSM_S_UNBLOCKED, 0, 0);</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 void bssgp_bvc_fsm_unblocked(struct osmo_fsm_inst *fi, uint32_t event, void *data)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  struct bvc_fsm_priv *bfp = fi->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+       const struct tlv_parsed *tp = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+   struct msgb *rx = NULL, *tx;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        switch (event) {</span><br><span style="color: hsl(120, 100%, 40%);">+      case BSSGP_BVCFSM_E_RX_UNBLOCK_ACK:</span><br><span style="color: hsl(120, 100%, 40%);">+           rx = data;</span><br><span style="color: hsl(120, 100%, 40%);">+            tp = (const struct tlv_parsed *) msgb_bcid(rx);</span><br><span style="color: hsl(120, 100%, 40%);">+               /* If BVC-UNBLOCK-ACK PDU is received by an BSS for the signalling BVC, the PDU is ignored. */</span><br><span style="color: hsl(120, 100%, 40%);">+                LOGPFSML(fi, LOGL_ERROR, "Rx BVC-UNBLOCK-ACK on BVCI=0 is illegal\n");</span><br><span style="color: hsl(120, 100%, 40%);">+              if (bfp->bvci == 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                      if (!bfp->role_sgsn)</span><br><span style="color: hsl(120, 100%, 40%);">+                               break;</span><br><span style="color: hsl(120, 100%, 40%);">+                        _tx_status(fi, BSSGP_CAUSE_SEM_INCORR_PDU, rx);</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%);">+             /* stop T1 timer */</span><br><span style="color: hsl(120, 100%, 40%);">+           osmo_fsm_inst_state_chg(fi, BSSGP_BVCFSM_S_UNBLOCKED, 0, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+          break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case BSSGP_BVCFSM_E_RX_UNBLOCK:</span><br><span style="color: hsl(120, 100%, 40%);">+               rx = data;</span><br><span style="color: hsl(120, 100%, 40%);">+            tp = (const struct tlv_parsed *) msgb_bcid(rx);</span><br><span style="color: hsl(120, 100%, 40%);">+               /* If a BVC-UNBLOCK PDU is received by an SGSN for a blocked BVC, a BVC-UNBLOCK-ACK</span><br><span style="color: hsl(120, 100%, 40%);">+            * PDU shall be returned. */</span><br><span style="color: hsl(120, 100%, 40%);">+          if (bfp->role_sgsn) {</span><br><span style="color: hsl(120, 100%, 40%);">+                      /* If a BVC-UNBLOCK PDU is received by an SGSN for</span><br><span style="color: hsl(120, 100%, 40%);">+                     * the signalling BVC, the PDU is ignored */</span><br><span style="color: hsl(120, 100%, 40%);">+                  if (bfp->bvci == 0)</span><br><span style="color: hsl(120, 100%, 40%);">+                                break;</span><br><span style="color: hsl(120, 100%, 40%);">+                        bssgp_tx_simple_bvci(BSSGP_PDUT_BVC_UNBLOCK_ACK, bfp->nsei, bfp->bvci, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+              }</span><br><span style="color: hsl(120, 100%, 40%);">+             break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case BSSGP_BVCFSM_E_RX_BLOCK:</span><br><span style="color: hsl(120, 100%, 40%);">+         rx = data;</span><br><span style="color: hsl(120, 100%, 40%);">+            tp = (const struct tlv_parsed *) msgb_bcid(rx);</span><br><span style="color: hsl(120, 100%, 40%);">+               LOGPFSML(fi, LOGL_NOTICE, "Rx BVC-BLOCK (cause=%s)\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                       bssgp_cause_str(*TLVP_VAL(tp, BSSGP_IE_CAUSE)));</span><br><span style="color: hsl(120, 100%, 40%);">+             /* If a BVC-BLOCK PDU is received by an SGSN for the signalling BVC, the PDU is ignored */</span><br><span style="color: hsl(120, 100%, 40%);">+            if (bfp->bvci == 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                      LOGPFSML(fi, LOGL_ERROR, "Rx BVC-BLOCK on BVCI=0 is illegal\n");</span><br><span style="color: hsl(120, 100%, 40%);">+                    if (bfp->role_sgsn)</span><br><span style="color: hsl(120, 100%, 40%);">+                                break;</span><br><span style="color: hsl(120, 100%, 40%);">+                        _tx_status(fi, BSSGP_CAUSE_SEM_INCORR_PDU, rx);</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%);">+             if (!bfp->role_sgsn) {</span><br><span style="color: hsl(120, 100%, 40%);">+                     LOGPFSML(fi, LOGL_ERROR, "Rx BVC-BLOCK on BSS is illegal\n");</span><br><span style="color: hsl(120, 100%, 40%);">+                       _tx_status(fi, BSSGP_CAUSE_SEM_INCORR_PDU, rx);</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%);">+             /* transmit BVC-BLOCK-ACK, transition to BLOCKED state */</span><br><span style="color: hsl(120, 100%, 40%);">+             tx = bssgp2_enc_bvc_block_ack(bfp->bvci);</span><br><span style="color: hsl(120, 100%, 40%);">+          fi_tx_sig(fi, tx);</span><br><span style="color: hsl(120, 100%, 40%);">+            osmo_fsm_inst_state_chg(fi, BSSGP_BVCFSM_S_BLOCKED, 0, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+            break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case BSSGP_BVCFSM_E_REQ_BLOCK:</span><br><span style="color: hsl(120, 100%, 40%);">+                if (bfp->role_sgsn) {</span><br><span style="color: hsl(120, 100%, 40%);">+                      LOGPFSML(fi, LOGL_ERROR, "SGSN may not initiate BVC-BLOCK\n");</span><br><span style="color: hsl(120, 100%, 40%);">+                      _tx_status(fi, BSSGP_CAUSE_SEM_INCORR_PDU, rx);</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%);">+             bfp->locally_blocked = true;</span><br><span style="color: hsl(120, 100%, 40%);">+               bfp->block_cause = *(uint8_t *)data;</span><br><span style="color: hsl(120, 100%, 40%);">+               /* transmit BVC-BLOCK, transition to BLOCKED state and start re-transmit timer */</span><br><span style="color: hsl(120, 100%, 40%);">+             tx = bssgp2_enc_bvc_block(bfp->bvci, bfp->block_cause);</span><br><span style="color: hsl(120, 100%, 40%);">+         fi_tx_sig(fi, tx);</span><br><span style="color: hsl(120, 100%, 40%);">+            osmo_fsm_inst_state_chg(fi, BSSGP_BVCFSM_S_BLOCKED, T1_SECS, T1);</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 void bssgp_bvc_fsm_allstate(struct osmo_fsm_inst *fi, uint32_t event, void *data)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   struct bvc_fsm_priv *bfp = fi->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+       uint8_t cause;</span><br><span style="color: hsl(120, 100%, 40%);">+        const struct tlv_parsed *tp = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+   struct msgb *rx = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     switch (event) {</span><br><span style="color: hsl(120, 100%, 40%);">+      case BSSGP_BVCFSM_E_REQ_RESET:</span><br><span style="color: hsl(120, 100%, 40%);">+                bfp->locally_blocked = false;</span><br><span style="color: hsl(120, 100%, 40%);">+              cause = bfp->last_reset_cause = *(uint8_t *) data;</span><br><span style="color: hsl(120, 100%, 40%);">+         _tx_bvc_reset(fi, cause);</span><br><span style="color: hsl(120, 100%, 40%);">+             osmo_fsm_inst_state_chg(fi, BSSGP_BVCFSM_S_WAIT_RESET_ACK, T2_SECS, T2);</span><br><span style="color: hsl(120, 100%, 40%);">+#if 0 /* not sure if we really should notify the application if itself has requested the reset? */</span><br><span style="color: hsl(120, 100%, 40%);">+          if (bfp->ops && bfp->ops->reset_notification)</span><br><span style="color: hsl(120, 100%, 40%);">+                        bfp->ops->reset_notification(bfp->nsei, bfp->bvci, NULL, 0, cause, bfp->ops_priv);</span><br><span style="color: hsl(120, 100%, 40%);">+#endif</span><br><span style="color: hsl(120, 100%, 40%);">+             break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case BSSGP_BVCFSM_E_RX_RESET:</span><br><span style="color: hsl(120, 100%, 40%);">+         rx = data;</span><br><span style="color: hsl(120, 100%, 40%);">+            tp = (const struct tlv_parsed *) msgb_bcid(rx);</span><br><span style="color: hsl(120, 100%, 40%);">+               cause = *TLVP_VAL(tp, BSSGP_IE_CAUSE);</span><br><span style="color: hsl(120, 100%, 40%);">+                if (bfp->role_sgsn && bfp->bvci != 0)</span><br><span style="color: hsl(120, 100%, 40%);">+                   bfp->cell_id = bssgp_parse_cell_id(&bfp->ra_id, TLVP_VAL(tp, BSSGP_IE_CELL_ID));</span><br><span style="color: hsl(120, 100%, 40%);">+            LOGPFSML(fi, LOGL_NOTICE, "Rx BVC-RESET (cause=%s)\n", bssgp_cause_str(cause));</span><br><span style="color: hsl(120, 100%, 40%);">+             if (bfp->bvci == 0)</span><br><span style="color: hsl(120, 100%, 40%);">+                        update_negotiated_features(fi, tp);</span><br><span style="color: hsl(120, 100%, 40%);">+           _tx_bvc_reset_ack(fi);</span><br><span style="color: hsl(120, 100%, 40%);">+                osmo_fsm_inst_state_chg(fi, BSSGP_BVCFSM_S_UNBLOCKED, 0, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+          if (bfp->ops && bfp->ops->reset_notification) {</span><br><span style="color: hsl(120, 100%, 40%);">+                      bfp->ops->reset_notification(bfp->nsei, bfp->bvci, &bfp->ra_id, bfp->cell_id,</span><br><span style="color: hsl(120, 100%, 40%);">+                                                cause, bfp->ops_priv);</span><br><span style="color: hsl(120, 100%, 40%);">+                }</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 int bssgp_bvc_fsm_timer_cb(struct osmo_fsm_inst *fi)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        struct bvc_fsm_priv *bfp = fi->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+       struct msgb *tx;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    switch (fi->T) {</span><br><span style="color: hsl(120, 100%, 40%);">+   case T1:</span><br><span style="color: hsl(120, 100%, 40%);">+              switch (fi->state) {</span><br><span style="color: hsl(120, 100%, 40%);">+               case BSSGP_BVCFSM_S_BLOCKED:</span><br><span style="color: hsl(120, 100%, 40%);">+                  /* re-transmit BVC-BLOCK */</span><br><span style="color: hsl(120, 100%, 40%);">+                   tx = bssgp2_enc_bvc_block(bfp->bvci, bfp->block_cause);</span><br><span style="color: hsl(120, 100%, 40%);">+                 fi_tx_sig(fi, tx);</span><br><span style="color: hsl(120, 100%, 40%);">+                    osmo_fsm_inst_state_chg(fi, BSSGP_BVCFSM_S_BLOCKED, T1_SECS, T1);</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%);">+                        /* re-transmit BVC-UNBLOCK */</span><br><span style="color: hsl(120, 100%, 40%);">+                 tx = bssgp2_enc_bvc_unblock(bfp->bvci);</span><br><span style="color: hsl(120, 100%, 40%);">+                    fi_tx_sig(fi, tx);</span><br><span style="color: hsl(120, 100%, 40%);">+                    osmo_fsm_inst_state_chg(fi, BSSGP_BVCFSM_S_UNBLOCKED, T1_SECS, T1);</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%);">+             break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case T2:</span><br><span style="color: hsl(120, 100%, 40%);">+              switch (fi->state) {</span><br><span style="color: hsl(120, 100%, 40%);">+               case BSSGP_BVCFSM_S_WAIT_RESET_ACK:</span><br><span style="color: hsl(120, 100%, 40%);">+                   /* re-transmit BVC-RESET */</span><br><span style="color: hsl(120, 100%, 40%);">+                   _tx_bvc_reset(fi, bfp->last_reset_cause);</span><br><span style="color: hsl(120, 100%, 40%);">+                  osmo_fsm_inst_state_chg(fi, BSSGP_BVCFSM_S_WAIT_RESET_ACK, T2_SECS, T2);</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%);">+                        /* re-transmit BVC-RESET-ACK */</span><br><span style="color: hsl(120, 100%, 40%);">+                       _tx_bvc_reset_ack(fi);</span><br><span style="color: hsl(120, 100%, 40%);">+                        osmo_fsm_inst_state_chg(fi, BSSGP_BVCFSM_S_UNBLOCKED, T2_SECS, T2);</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%);">+             break;</span><br><span style="color: hsl(120, 100%, 40%);">+        default:</span><br><span style="color: hsl(120, 100%, 40%);">+              OSMO_ASSERT(0);</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%);">+     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 style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static const struct osmo_fsm_state bssgp_bvc_fsm_states[] = {</span><br><span style="color: hsl(120, 100%, 40%);">+     [BSSGP_BVCFSM_S_NULL] = {</span><br><span style="color: hsl(120, 100%, 40%);">+             /* initial state from which we must do a RESET */</span><br><span style="color: hsl(120, 100%, 40%);">+             .name = "NULL",</span><br><span style="color: hsl(120, 100%, 40%);">+             .in_event_mask = 0,</span><br><span style="color: hsl(120, 100%, 40%);">+           .out_state_mask = S(BSSGP_BVCFSM_S_WAIT_RESET_ACK) |</span><br><span style="color: hsl(120, 100%, 40%);">+                            S(BSSGP_BVCFSM_S_UNBLOCKED),</span><br><span style="color: hsl(120, 100%, 40%);">+                .action = bssgp_bvc_fsm_null,</span><br><span style="color: hsl(120, 100%, 40%);">+ },</span><br><span style="color: hsl(120, 100%, 40%);">+    [BSSGP_BVCFSM_S_BLOCKED] = {</span><br><span style="color: hsl(120, 100%, 40%);">+          .name = "BLOCKED",</span><br><span style="color: hsl(120, 100%, 40%);">+          .in_event_mask = S(BSSGP_BVCFSM_E_RX_UNBLOCK) |</span><br><span style="color: hsl(120, 100%, 40%);">+                                S(BSSGP_BVCFSM_E_RX_BLOCK) |</span><br><span style="color: hsl(120, 100%, 40%);">+                          S(BSSGP_BVCFSM_E_RX_BLOCK_ACK) |</span><br><span style="color: hsl(120, 100%, 40%);">+                              S(BSSGP_BVCFSM_E_REQ_UNBLOCK),</span><br><span style="color: hsl(120, 100%, 40%);">+               .out_state_mask = S(BSSGP_BVCFSM_S_WAIT_RESET_ACK) |</span><br><span style="color: hsl(120, 100%, 40%);">+                            S(BSSGP_BVCFSM_S_UNBLOCKED) |</span><br><span style="color: hsl(120, 100%, 40%);">+                                 S(BSSGP_BVCFSM_S_BLOCKED),</span><br><span style="color: hsl(120, 100%, 40%);">+          .action = bssgp_bvc_fsm_blocked,</span><br><span style="color: hsl(120, 100%, 40%);">+              .onenter = bssgp_bvc_fsm_blocked_onenter,</span><br><span style="color: hsl(120, 100%, 40%);">+     },</span><br><span style="color: hsl(120, 100%, 40%);">+    [BSSGP_BVCFSM_S_WAIT_RESET_ACK]= {</span><br><span style="color: hsl(120, 100%, 40%);">+            .name = "WAIT_RESET_ACK",</span><br><span style="color: hsl(120, 100%, 40%);">+           .in_event_mask = S(BSSGP_BVCFSM_E_RX_RESET_ACK),</span><br><span style="color: hsl(120, 100%, 40%);">+              .out_state_mask = S(BSSGP_BVCFSM_S_UNBLOCKED) |</span><br><span style="color: hsl(120, 100%, 40%);">+                                 S(BSSGP_BVCFSM_S_BLOCKED) |</span><br><span style="color: hsl(120, 100%, 40%);">+                           S(BSSGP_BVCFSM_S_WAIT_RESET_ACK),</span><br><span style="color: hsl(120, 100%, 40%);">+           .action = bssgp_bvc_fsm_wait_reset_ack,</span><br><span style="color: hsl(120, 100%, 40%);">+               .onenter = _onenter_tail,</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%);">+  [BSSGP_BVCFSM_S_UNBLOCKED] = {</span><br><span style="color: hsl(120, 100%, 40%);">+                .name = "UNBLOCKED",</span><br><span style="color: hsl(120, 100%, 40%);">+                .in_event_mask = S(BSSGP_BVCFSM_E_RX_BLOCK) |</span><br><span style="color: hsl(120, 100%, 40%);">+                          S(BSSGP_BVCFSM_E_RX_UNBLOCK) |</span><br><span style="color: hsl(120, 100%, 40%);">+                                S(BSSGP_BVCFSM_E_RX_UNBLOCK_ACK) |</span><br><span style="color: hsl(120, 100%, 40%);">+                            S(BSSGP_BVCFSM_E_REQ_BLOCK),</span><br><span style="color: hsl(120, 100%, 40%);">+         .out_state_mask = S(BSSGP_BVCFSM_S_BLOCKED) |</span><br><span style="color: hsl(120, 100%, 40%);">+                           S(BSSGP_BVCFSM_S_WAIT_RESET_ACK) |</span><br><span style="color: hsl(120, 100%, 40%);">+                            S(BSSGP_BVCFSM_S_UNBLOCKED),</span><br><span style="color: hsl(120, 100%, 40%);">+                .action = bssgp_bvc_fsm_unblocked,</span><br><span style="color: hsl(120, 100%, 40%);">+            .onenter = _onenter_tail,</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 struct osmo_fsm bssgp_bvc_fsm = {</span><br><span style="color: hsl(120, 100%, 40%);">+    .name = "BSSGP-BVC",</span><br><span style="color: hsl(120, 100%, 40%);">+        .states = bssgp_bvc_fsm_states,</span><br><span style="color: hsl(120, 100%, 40%);">+       .num_states = ARRAY_SIZE(bssgp_bvc_fsm_states),</span><br><span style="color: hsl(120, 100%, 40%);">+       .allstate_event_mask = S(BSSGP_BVCFSM_E_REQ_RESET) |</span><br><span style="color: hsl(120, 100%, 40%);">+                         S(BSSGP_BVCFSM_E_RX_RESET),</span><br><span style="color: hsl(120, 100%, 40%);">+    .allstate_action = bssgp_bvc_fsm_allstate,</span><br><span style="color: hsl(120, 100%, 40%);">+    .timer_cb = bssgp_bvc_fsm_timer_cb,</span><br><span style="color: hsl(120, 100%, 40%);">+   .log_subsys = DLBSSGP,</span><br><span style="color: hsl(120, 100%, 40%);">+        .event_names = ptp_bvc_event_names,</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 struct osmo_fsm_inst *</span><br><span style="color: hsl(120, 100%, 40%);">+_bvc_fsm_alloc(void *ctx, struct gprs_ns2_inst *nsi, bool role_sgsn, uint16_t nsei, uint16_t bvci)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       struct osmo_fsm_inst *fi;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct bvc_fsm_priv *bfp;</span><br><span style="color: hsl(120, 100%, 40%);">+     char idbuf[64];</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     /* TODO: encode our role in the id string? */</span><br><span style="color: hsl(120, 100%, 40%);">+ snprintf(idbuf, sizeof(idbuf), "NSE%05u-BVC%05u", nsei, bvci);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    fi = osmo_fsm_inst_alloc(&bssgp_bvc_fsm, ctx, NULL, LOGL_INFO, idbuf);</span><br><span style="color: hsl(120, 100%, 40%);">+    if (!fi)</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%);">+        bfp = talloc_zero(fi, struct bvc_fsm_priv);</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!bfp) {</span><br><span style="color: hsl(120, 100%, 40%);">+           osmo_fsm_inst_free(fi);</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%);">+     fi->priv = bfp;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  bfp->nsi = nsi;</span><br><span style="color: hsl(120, 100%, 40%);">+    bfp->role_sgsn = role_sgsn;</span><br><span style="color: hsl(120, 100%, 40%);">+        bfp->nsei = nsei;</span><br><span style="color: hsl(120, 100%, 40%);">+  bfp->bvci = bvci;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        return fi;</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 SIGNALING-BVC FSM for the BSS role (facing a remote SGSN).</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] ctx talloc context from which to allocate</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] nsi NS Instance on which this BVC operates</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] nsei NS Entity Identifier on which this BVC operates</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] features Feature [byte 0] and Extended Feature [byte 1] bitmap</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \returns newly-allocated FSM Instance; NULL in case of error */</span><br><span style="color: hsl(120, 100%, 40%);">+struct osmo_fsm_inst *</span><br><span style="color: hsl(120, 100%, 40%);">+bssgp_bvc_fsm_alloc_sig_bss(void *ctx, struct gprs_ns2_inst *nsi, uint16_t nsei, uint32_t features)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      struct osmo_fsm_inst *fi = _bvc_fsm_alloc(ctx, nsi, false, nsei, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+  struct bvc_fsm_priv *bfp;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!fi)</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%);">+        bfp = fi->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+    bfp->features.advertised = features;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     return fi;</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 PTP-BVC FSM for the BSS role (facing a remote SGSN).</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] ctx talloc context from which to allocate</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] nsi NS Instance on which this BVC operates</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] nsei NS Entity Identifier on which this BVC operates</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] bvci BVCI of this FSM</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] ra_id Routing Area Identity of the cell (reported to SGSN)</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] cell_id Cell Identifier of the cell (reported to SGSN)</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \returns newly-allocated FSM Instance; NULL in case of error */</span><br><span style="color: hsl(120, 100%, 40%);">+struct osmo_fsm_inst *</span><br><span style="color: hsl(120, 100%, 40%);">+bssgp_bvc_fsm_alloc_ptp_bss(void *ctx, struct gprs_ns2_inst *nsi, uint16_t nsei,</span><br><span style="color: hsl(120, 100%, 40%);">+                     uint16_t bvci, const struct gprs_ra_id *ra_id, uint16_t cell_id)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       struct osmo_fsm_inst *fi;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct bvc_fsm_priv *bfp;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   OSMO_ASSERT(bvci >= 2);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  fi = _bvc_fsm_alloc(ctx, nsi, false, nsei, bvci);</span><br><span style="color: hsl(120, 100%, 40%);">+     if (!fi)</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%);">+        bfp = fi->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+    bfp->ra_id = *ra_id;</span><br><span style="color: hsl(120, 100%, 40%);">+       bfp->cell_id = cell_id;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  return fi;</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 SIGNALING-BVC FSM for the SGSN role (facing a remote BSS).</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] ctx talloc context from which to allocate</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] nsi NS Instance on which this BVC operates</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] nsei NS Entity Identifier on which this BVC operates</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] features Feature [byte 0] and Extended Feature [byte 1] bitmap</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \returns newly-allocated FSM Instance; NULL in case of error */</span><br><span style="color: hsl(120, 100%, 40%);">+struct osmo_fsm_inst *</span><br><span style="color: hsl(120, 100%, 40%);">+bssgp_bvc_fsm_alloc_sig_sgsn(void *ctx, struct gprs_ns2_inst *nsi, uint16_t nsei, uint32_t features)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     struct osmo_fsm_inst *fi = _bvc_fsm_alloc(ctx, nsi, true, nsei, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+   struct bvc_fsm_priv *bfp;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!fi)</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%);">+        bfp = fi->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+    bfp->features.advertised = features;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     return fi;</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 PTP-BVC FSM for the SGSN role (facing a remote BSS).</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] ctx talloc context from which to allocate</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] nsi NS Instance on which this BVC operates</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] nsei NS Entity Identifier on which this BVC operates</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] bvci BVCI of this FSM</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \returns newly-allocated FSM Instance; NULL in case of error */</span><br><span style="color: hsl(120, 100%, 40%);">+struct osmo_fsm_inst *</span><br><span style="color: hsl(120, 100%, 40%);">+bssgp_bvc_fsm_alloc_ptp_sgsn(void *ctx, struct gprs_ns2_inst *nsi, uint16_t nsei, uint16_t bvci)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        struct osmo_fsm_inst *fi;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   OSMO_ASSERT(bvci >= 2);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  fi = _bvc_fsm_alloc(ctx, nsi, true, nsei, bvci);</span><br><span style="color: hsl(120, 100%, 40%);">+      if (!fi)</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%);">+        return fi;</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%);">+/*! Set the 'operations' callbacks + private data.</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] fi FSM instance for which the data shall be set</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] ops BSSGP BVC FSM operations (call-back functions) to register</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] ops_priv opaque/private data pointer passed through to call-backs */</span><br><span style="color: hsl(120, 100%, 40%);">+void bssgp_bvc_fsm_set_ops(struct osmo_fsm_inst *fi, const struct bssgp_bvc_fsm_ops *ops, void *ops_priv)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct bvc_fsm_priv *bfp = fi->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     OSMO_ASSERT(fi->fsm == &bssgp_bvc_fsm);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      bfp->ops = ops;</span><br><span style="color: hsl(120, 100%, 40%);">+    bfp->ops_priv = ops_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%);">+/*! Return if the given BVC FSM is in UNBLOCKED state. */</span><br><span style="color: hsl(120, 100%, 40%);">+bool bssgp_bvc_fsm_is_unblocked(struct osmo_fsm_inst *fi)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    return fi->state == BSSGP_BVCFSM_S_UNBLOCKED;</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%);">+/*! Determine the cause value why given BVC FSM is blocked. */</span><br><span style="color: hsl(120, 100%, 40%);">+uint8_t bssgp_bvc_fsm_get_block_cause(struct osmo_fsm_inst *fi)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     struct bvc_fsm_priv *bfp = fi->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     OSMO_ASSERT(fi->fsm == &bssgp_bvc_fsm);</span><br><span style="color: hsl(120, 100%, 40%);">+        return bfp->block_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%);">+/*! Return the advertised features / extended features. */</span><br><span style="color: hsl(120, 100%, 40%);">+uint32_t bssgp_bvc_get_features_advertised(struct osmo_fsm_inst *fi)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct bvc_fsm_priv *bfp = fi->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     OSMO_ASSERT(fi->fsm == &bssgp_bvc_fsm);</span><br><span style="color: hsl(120, 100%, 40%);">+        return bfp->features.advertised;</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 the received features / extended features. */</span><br><span style="color: hsl(120, 100%, 40%);">+uint32_t bssgp_bvc_get_features_received(struct osmo_fsm_inst *fi)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     struct bvc_fsm_priv *bfp = fi->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     OSMO_ASSERT(fi->fsm == &bssgp_bvc_fsm);</span><br><span style="color: hsl(120, 100%, 40%);">+        return bfp->features.received;</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 the negotiated features / extended features. */</span><br><span style="color: hsl(120, 100%, 40%);">+uint32_t bssgp_bvc_get_features_negotiated(struct osmo_fsm_inst *fi)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   struct bvc_fsm_priv *bfp = fi->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     OSMO_ASSERT(fi->fsm == &bssgp_bvc_fsm);</span><br><span style="color: hsl(120, 100%, 40%);">+        return bfp->features.negotiated;</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 __attribute__((constructor)) void on_dso_load_bvc_fsm(void)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       osmo_fsm_register(&bssgp_bvc_fsm);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span>diff --git a/src/gb/gprs_bssgp2.c b/src/gb/gprs_bssgp2.c</span><br><span>new file mode 100644</span><br><span>index 0000000..ec2199a</span><br><span>--- /dev/null</span><br><span>+++ b/src/gb/gprs_bssgp2.c</span><br><span>@@ -0,0 +1,221 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/* BSSGP2 - second generation of BSSGP library */</span><br><span style="color: hsl(120, 100%, 40%);">+/* (C) 2020 by Harald Welte <laforge@gnumonks.org> */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/utils.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/byteswap.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/msgb.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/gsm/gsm48.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/gsm/tlv.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+//#include <osmocom/gprs/gprs_msgb.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/gprs/gprs_ns2.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/gprs/gprs_bssgp.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/gprs/gprs_bssgp2.h></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%);">+/*! transmit BSSGP PDU over NS (PTP BVC)</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] nsi NS Instance through which to transmit</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] nsei NSEI of NSE through which to transmit</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] bvci BVCI through which to transmit</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] msg BSSGP PDU to transmit</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \returns 0 on success; negative on error */</span><br><span style="color: hsl(120, 100%, 40%);">+int bssgp2_nsi_tx_ptp(struct gprs_ns2_inst *nsi, uint16_t nsei, uint16_t bvci,</span><br><span style="color: hsl(120, 100%, 40%);">+                      struct msgb *msg, uint32_t lsp)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      struct osmo_gprs_ns2_prim nsp = {};</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%);">+     if (!msg)</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%);">+   nsp.bvci = bvci;</span><br><span style="color: hsl(120, 100%, 40%);">+      nsp.nsei = nsei;</span><br><span style="color: hsl(120, 100%, 40%);">+      nsp.u.unitdata.link_selector = lsp;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_prim_init(&nsp.oph, SAP_NS, PRIM_NS_UNIT_DATA, PRIM_OP_REQUEST, msg);</span><br><span style="color: hsl(120, 100%, 40%);">+        rc = gprs_ns2_recv_prim(nsi, &nsp.oph);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ return rc;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! transmit BSSGP PDU over NS (SIGNALING BVC)</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] nsi NS Instance through which to transmit</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] nsei NSEI of NSE through which to transmit</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] msg BSSGP PDU to transmit</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \returns 0 on success; negative on error */</span><br><span style="color: hsl(120, 100%, 40%);">+int bssgp2_nsi_tx_sig(struct gprs_ns2_inst *nsi, uint16_t nsei, struct msgb *msg, uint32_t lsp)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   return bssgp2_nsi_tx_ptp(nsi, nsei, 0, msg, lsp);</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%);">+/*! Encode BSSGP BVC-BLOCK PDU as per TS 48.018 Section 10.4.8. */</span><br><span style="color: hsl(120, 100%, 40%);">+struct msgb *bssgp2_enc_bvc_block(uint16_t bvci, enum gprs_bssgp_cause cause)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  struct msgb *msg = bssgp_msgb_alloc();</span><br><span style="color: hsl(120, 100%, 40%);">+        struct bssgp_normal_hdr *bgph;</span><br><span style="color: hsl(120, 100%, 40%);">+        uint16_t _bvci = osmo_htons(bvci);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  if (!msg)</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%);">+        bgph = (struct bssgp_normal_hdr *) msgb_put(msg, sizeof(*bgph));</span><br><span style="color: hsl(120, 100%, 40%);">+      bgph->pdu_type = BSSGP_PDUT_BVC_BLOCK;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   msgb_tvlv_put(msg, BSSGP_IE_BVCI, 2, (uint8_t *) &_bvci);</span><br><span style="color: hsl(120, 100%, 40%);">+ msgb_tvlv_put(msg, BSSGP_IE_CAUSE, 1, (uint8_t *) &cause);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      return msg;</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%);">+/*! Encode BSSGP BVC-BLOCK PDU as per TS 48.018 Section 10.4.9. */</span><br><span style="color: hsl(120, 100%, 40%);">+struct msgb *bssgp2_enc_bvc_block_ack(uint16_t bvci)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct msgb *msg = bssgp_msgb_alloc();</span><br><span style="color: hsl(120, 100%, 40%);">+        struct bssgp_normal_hdr *bgph;</span><br><span style="color: hsl(120, 100%, 40%);">+        uint16_t _bvci = osmo_htons(bvci);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  if (!msg)</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%);">+        bgph = (struct bssgp_normal_hdr *) msgb_put(msg, sizeof(*bgph));</span><br><span style="color: hsl(120, 100%, 40%);">+      bgph->pdu_type = BSSGP_PDUT_BVC_BLOCK_ACK;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       msgb_tvlv_put(msg, BSSGP_IE_BVCI, 2, (uint8_t *) &_bvci);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       return msg;</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%);">+/*! Encode BSSGP BVC-UNBLOCK PDU as per TS 48.018 Section 10.4.10. */</span><br><span style="color: hsl(120, 100%, 40%);">+struct msgb *bssgp2_enc_bvc_unblock(uint16_t bvci)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        struct msgb *msg = bssgp_msgb_alloc();</span><br><span style="color: hsl(120, 100%, 40%);">+        struct bssgp_normal_hdr *bgph;</span><br><span style="color: hsl(120, 100%, 40%);">+        uint16_t _bvci = osmo_htons(bvci);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  if (!msg)</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%);">+        bgph = (struct bssgp_normal_hdr *) msgb_put(msg, sizeof(*bgph));</span><br><span style="color: hsl(120, 100%, 40%);">+      bgph->pdu_type = BSSGP_PDUT_BVC_UNBLOCK;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ msgb_tvlv_put(msg, BSSGP_IE_BVCI, 2, (uint8_t *) &_bvci);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       return msg;</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%);">+/*! Encode BSSGP BVC-UNBLOCK-ACK PDU as per TS 48.018 Section 10.4.11. */</span><br><span style="color: hsl(120, 100%, 40%);">+struct msgb *bssgp2_enc_bvc_unblock_ack(uint16_t bvci)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        struct msgb *msg = bssgp_msgb_alloc();</span><br><span style="color: hsl(120, 100%, 40%);">+        struct bssgp_normal_hdr *bgph;</span><br><span style="color: hsl(120, 100%, 40%);">+        uint16_t _bvci = osmo_htons(bvci);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  if (!msg)</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%);">+        bgph = (struct bssgp_normal_hdr *) msgb_put(msg, sizeof(*bgph));</span><br><span style="color: hsl(120, 100%, 40%);">+      bgph->pdu_type = BSSGP_PDUT_BVC_UNBLOCK_ACK;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     msgb_tvlv_put(msg, BSSGP_IE_BVCI, 2, (uint8_t *) &_bvci);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       return msg;</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%);">+/*! Encode BSSGP BVC-RESET PDU as per TS 48.018 Section 10.4.12.</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] bvci PTP BVCI to encode into the BVCI IE</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] cause BSSGP Cause value (reason for reset)</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] ra_id Routing Area ID to be encoded to CELL_ID IE (optional)</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] cell_id Cell ID to be encoded to CELL_ID IE (only if ra_id is non-NULL)</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] feat_bm Feature Bitmap (optional)</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] ext_feat_bm Extended Feature Bitmap (optional) */</span><br><span style="color: hsl(120, 100%, 40%);">+struct msgb *bssgp2_enc_bvc_reset(uint16_t bvci, enum gprs_bssgp_cause cause,</span><br><span style="color: hsl(120, 100%, 40%);">+                                  const struct gprs_ra_id *ra_id, uint16_t cell_id,</span><br><span style="color: hsl(120, 100%, 40%);">+                             const uint8_t *feat_bm, const uint8_t *ext_feat_bm)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      struct msgb *msg = bssgp_msgb_alloc();</span><br><span style="color: hsl(120, 100%, 40%);">+        struct bssgp_normal_hdr *bgph;</span><br><span style="color: hsl(120, 100%, 40%);">+        uint16_t _bvci = osmo_htons(bvci);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  if (!msg)</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%);">+        bgph = (struct bssgp_normal_hdr *) msgb_put(msg, sizeof(*bgph));</span><br><span style="color: hsl(120, 100%, 40%);">+      bgph->pdu_type = BSSGP_PDUT_BVC_RESET;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   msgb_tvlv_put(msg, BSSGP_IE_BVCI, 2, (uint8_t *) &_bvci);</span><br><span style="color: hsl(120, 100%, 40%);">+ msgb_tvlv_put(msg, BSSGP_IE_CAUSE, 1, (uint8_t *) &cause);</span><br><span style="color: hsl(120, 100%, 40%);">+        if (ra_id) {</span><br><span style="color: hsl(120, 100%, 40%);">+          uint8_t bssgp_cid[8];</span><br><span style="color: hsl(120, 100%, 40%);">+         bssgp_create_cell_id(bssgp_cid, ra_id, cell_id);</span><br><span style="color: hsl(120, 100%, 40%);">+              msgb_tvlv_put(msg, BSSGP_IE_CELL_ID, sizeof(bssgp_cid), bssgp_cid);</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 (feat_bm)</span><br><span style="color: hsl(120, 100%, 40%);">+          msgb_tvlv_put(msg, BSSGP_IE_FEATURE_BITMAP, 1, feat_bm);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    if (ext_feat_bm)</span><br><span style="color: hsl(120, 100%, 40%);">+              msgb_tvlv_put(msg, BSSGP_IE_EXT_FEATURE_BITMAP, 1, feat_bm);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        return msg;</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%);">+/*! Encode BSSGP BVC-RESET-ACK PDU as per TS 48.018 Section 10.4.13.</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] bvci PTP BVCI to encode into the BVCI IE</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] ra_id Routing Area ID to be encoded to CELL_ID IE (optional)</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] cell_id Cell ID to be encoded to CELL_ID IE (only if ra_id is non-NULL)</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] feat_bm Feature Bitmap (optional)</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] ext_feat_bm Extended Feature Bitmap (optional) */</span><br><span style="color: hsl(120, 100%, 40%);">+struct msgb *bssgp2_enc_bvc_reset_ack(uint16_t bvci, const struct gprs_ra_id *ra_id, uint16_t cell_id,</span><br><span style="color: hsl(120, 100%, 40%);">+                                    const uint8_t *feat_bm, const uint8_t *ext_feat_bm)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  struct msgb *msg = bssgp_msgb_alloc();</span><br><span style="color: hsl(120, 100%, 40%);">+        struct bssgp_normal_hdr *bgph;</span><br><span style="color: hsl(120, 100%, 40%);">+        uint16_t _bvci = osmo_htons(bvci);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  if (!msg)</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%);">+        bgph = (struct bssgp_normal_hdr *) msgb_put(msg, sizeof(*bgph));</span><br><span style="color: hsl(120, 100%, 40%);">+      bgph->pdu_type = BSSGP_PDUT_BVC_RESET_ACK;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       msgb_tvlv_put(msg, BSSGP_IE_BVCI, 2, (uint8_t *) &_bvci);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (ra_id) {</span><br><span style="color: hsl(120, 100%, 40%);">+          uint8_t bssgp_cid[8];</span><br><span style="color: hsl(120, 100%, 40%);">+         bssgp_create_cell_id(bssgp_cid, ra_id, cell_id);</span><br><span style="color: hsl(120, 100%, 40%);">+              msgb_tvlv_put(msg, BSSGP_IE_CELL_ID, sizeof(bssgp_cid), bssgp_cid);</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 (feat_bm)</span><br><span style="color: hsl(120, 100%, 40%);">+          msgb_tvlv_put(msg, BSSGP_IE_FEATURE_BITMAP, 1, feat_bm);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    if (ext_feat_bm)</span><br><span style="color: hsl(120, 100%, 40%);">+              msgb_tvlv_put(msg, BSSGP_IE_EXT_FEATURE_BITMAP, 1, feat_bm);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        return msg;</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%);">+/*! Encode BSSGP STATUS PDU as per TS 48.018 Section 10.4.14.</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] cause BSSGP Cause value</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] bvci optional BVCI - only encoded if non-NULL</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] msg optional message buffer containing PDU in error - only encoded if non-NULL */</span><br><span style="color: hsl(120, 100%, 40%);">+struct msgb *bssgp2_enc_status(uint8_t cause, const uint16_t *bvci, const struct msgb *orig_msg)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  struct msgb *msg = bssgp_msgb_alloc();</span><br><span style="color: hsl(120, 100%, 40%);">+        struct bssgp_normal_hdr *bgph;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      if (!msg)</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%);">+        bgph = (struct bssgp_normal_hdr *) msgb_put(msg, sizeof(*bgph));</span><br><span style="color: hsl(120, 100%, 40%);">+      bgph->pdu_type = BSSGP_PDUT_STATUS;</span><br><span style="color: hsl(120, 100%, 40%);">+        msgb_tvlv_put(msg, BSSGP_IE_CAUSE, 1, &cause);</span><br><span style="color: hsl(120, 100%, 40%);">+    if (bvci) {</span><br><span style="color: hsl(120, 100%, 40%);">+           uint16_t _bvci = osmo_htons(*bvci);</span><br><span style="color: hsl(120, 100%, 40%);">+           msgb_tvlv_put(msg, BSSGP_IE_BVCI, 2, (uint8_t *) &_bvci);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+     if (orig_msg)</span><br><span style="color: hsl(120, 100%, 40%);">+         msgb_tvlv_put(msg, BSSGP_IE_PDU_IN_ERROR, msgb_bssgp_len(orig_msg), msgb_bssgph(orig_msg));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ return msg;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span>diff --git a/src/gb/libosmogb.map b/src/gb/libosmogb.map</span><br><span>index 8abac74..e605d27 100644</span><br><span>--- a/src/gb/libosmogb.map</span><br><span>+++ b/src/gb/libosmogb.map</span><br><span>@@ -45,6 +45,27 @@</span><br><span> bssgp_vty_init;</span><br><span> bssgp_nsi;</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+bssgp2_nsi_tx_ptp;</span><br><span style="color: hsl(120, 100%, 40%);">+bssgp2_nsi_tx_sig;</span><br><span style="color: hsl(120, 100%, 40%);">+bssgp2_enc_bvc_block;</span><br><span style="color: hsl(120, 100%, 40%);">+bssgp2_enc_bvc_block_ack;</span><br><span style="color: hsl(120, 100%, 40%);">+bssgp2_enc_bvc_unblock;</span><br><span style="color: hsl(120, 100%, 40%);">+bssgp2_enc_bvc_unblock_ack;</span><br><span style="color: hsl(120, 100%, 40%);">+bssgp2_enc_bvc_reset;</span><br><span style="color: hsl(120, 100%, 40%);">+bssgp2_enc_bvc_reset_ack;</span><br><span style="color: hsl(120, 100%, 40%);">+bssgp2_enc_status;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+bssgp_bvc_fsm_alloc_sig_bss;</span><br><span style="color: hsl(120, 100%, 40%);">+bssgp_bvc_fsm_alloc_ptp_bss;</span><br><span style="color: hsl(120, 100%, 40%);">+bssgp_bvc_fsm_alloc_sig_sgsn;</span><br><span style="color: hsl(120, 100%, 40%);">+bssgp_bvc_fsm_alloc_ptp_sgsn;</span><br><span style="color: hsl(120, 100%, 40%);">+bssgp_bvc_fsm_set_ops;</span><br><span style="color: hsl(120, 100%, 40%);">+bssgp_bvc_fsm_is_unblocked;</span><br><span style="color: hsl(120, 100%, 40%);">+bssgp_bvc_fsm_get_block_cause;</span><br><span style="color: hsl(120, 100%, 40%);">+bssgp_bvc_get_features_advertised;</span><br><span style="color: hsl(120, 100%, 40%);">+bssgp_bvc_get_features_received;</span><br><span style="color: hsl(120, 100%, 40%);">+bssgp_bvc_get_features_negotiated;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> osmo_fr_network_alloc;</span><br><span> osmo_fr_link_alloc;</span><br><span> osmo_fr_link_free;</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.osmocom.org/c/libosmocore/+/21598">change 21598</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/libosmocore/+/21598"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: libosmocore </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-Change-Id: Icbe8e4f03b68fd73b8eae95f6f6cccd4fa9af95a </div>
<div style="display:none"> Gerrit-Change-Number: 21598 </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>