<p>lynxis lazus has uploaded this change for <strong>review</strong>.</p><p><a href="https://gerrit.osmocom.org/c/libosmocore/+/19417">View Change</a></p><pre style="font-family: monospace,monospace; white-space: pre-wrap;">Gb: add a second NS implementation<br><br>Change-Id: I3525beef205588dfab9d3880a34115f1a2676e48<br>---<br>M include/Makefile.am<br>M include/osmocom/core/logging.h<br>A include/osmocom/gprs/gprs_ns2.h<br>A include/osmocom/gprs/gprs_ns_common.h<br>M src/gb/Makefile.am<br>A src/gb/gprs_ns2.c<br>A src/gb/gprs_ns2_driver.c<br>A src/gb/gprs_ns2_driver.h<br>A src/gb/gprs_ns2_internal.h<br>A src/gb/gprs_ns2_sns.c<br>A src/gb/gprs_ns2_vc_fsm.c<br>A src/gb/gprs_ns2_vc_fsm.h<br>A src/gb/gprs_ns2_vty.c<br>M src/gb/libosmogb.map<br>14 files changed, 4,251 insertions(+), 1 deletion(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">git pull ssh://gerrit.osmocom.org:29418/libosmocore refs/changes/17/19417/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 7af7e01..f961bb4 100644</span><br><span>--- a/include/Makefile.am</span><br><span>+++ b/include/Makefile.am</span><br><span>@@ -65,6 +65,8 @@</span><br><span>                        osmocom/gprs/gprs_msgb.h \</span><br><span>                        osmocom/gprs/gprs_ns.h \</span><br><span>                        osmocom/gprs/gprs_ns_frgre.h \</span><br><span style="color: hsl(120, 100%, 40%);">+                       osmocom/gprs/gprs_ns2.h \</span><br><span style="color: hsl(120, 100%, 40%);">+                       osmocom/gprs/gprs_ns_common.h \</span><br><span>                        osmocom/gprs/gprs_rlc.h \</span><br><span>                        osmocom/gprs/protocol/gsm_04_60.h \</span><br><span>                        osmocom/gprs/protocol/gsm_08_16.h \</span><br><span>diff --git a/include/osmocom/core/logging.h b/include/osmocom/core/logging.h</span><br><span>index 79eec10..00d4a68 100644</span><br><span>--- a/include/osmocom/core/logging.h</span><br><span>+++ b/include/osmocom/core/logging.h</span><br><span>@@ -187,6 +187,7 @@</span><br><span>       LOG_FLT_BSC_SUBSCR,</span><br><span>  LOG_FLT_VLR_SUBSCR,</span><br><span>  LOG_FLT_L1_SAPI,</span><br><span style="color: hsl(120, 100%, 40%);">+      LOG_FLT_GB_NSE,</span><br><span>      _LOG_FLT_COUNT</span><br><span> };</span><br><span> </span><br><span>diff --git a/include/osmocom/gprs/gprs_ns2.h b/include/osmocom/gprs/gprs_ns2.h</span><br><span>new file mode 100644</span><br><span>index 0000000..4db34c0</span><br><span>--- /dev/null</span><br><span>+++ b/include/osmocom/gprs/gprs_ns2.h</span><br><span>@@ -0,0 +1,131 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/*! \file gprs_ns2.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%);">+#ifndef OSMO_GPRS_NS2_H</span><br><span style="color: hsl(120, 100%, 40%);">+#define OSMO_GPRS_NS2_H</span><br><span style="color: hsl(120, 100%, 40%);">+</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%);">+/* Our Implementation */</span><br><span style="color: hsl(120, 100%, 40%);">+#include <netinet/in.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/linuxlist.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/msgb.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/timer.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/select.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/socket.h></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_ns_common.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_ns2_nse;</span><br><span style="color: hsl(120, 100%, 40%);">+struct gprs_ns2_vc;</span><br><span style="color: hsl(120, 100%, 40%);">+struct gprs_ns2_vc_bind;</span><br><span style="color: hsl(120, 100%, 40%);">+struct gprs_ns2_vc_driver;</span><br><span style="color: hsl(120, 100%, 40%);">+struct gprs_ns_ie_ip4_elem;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* callbacks for messages transfer */</span><br><span style="color: hsl(120, 100%, 40%);">+/*! Osmocom GPRS callback function type */</span><br><span style="color: hsl(120, 100%, 40%);">+typedef int gprs_ns2_cb_t(enum gprs_ns_evt event, struct msgb *msg,</span><br><span style="color: hsl(120, 100%, 40%);">+                        uint16_t nsei, uint16_t bvci);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* instance */</span><br><span style="color: hsl(120, 100%, 40%);">+struct gprs_ns2_inst *gprs_ns2_instantiate(gprs_ns2_cb_t *cb, void *ctx);</span><br><span style="color: hsl(120, 100%, 40%);">+void gprs_ns2_free(struct gprs_ns2_inst *inst);</span><br><span style="color: hsl(120, 100%, 40%);">+int gprs_ns2_dynamic_create_nse(struct gprs_ns2_inst *nsi, bool create_nse);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* NSE */</span><br><span style="color: hsl(120, 100%, 40%);">+/*! Send a UNIT DATA over an NSE. Should be used by higher layers */</span><br><span style="color: hsl(120, 100%, 40%);">+int gprs_ns2_send(struct gprs_ns2_inst *inst,struct msgb *msg);</span><br><span style="color: hsl(120, 100%, 40%);">+int gprs_ns2_send_nse(struct gprs_ns2_nse *nse, struct msgb *msg);</span><br><span style="color: hsl(120, 100%, 40%);">+int gprs_ns2_send_nsei(struct gprs_ns2_inst *nsi, uint16_t nsei, struct msgb *msg);</span><br><span style="color: hsl(120, 100%, 40%);">+int gprs_ns2_recv_vc(struct gprs_ns2_inst *nsi,</span><br><span style="color: hsl(120, 100%, 40%);">+                 struct gprs_ns2_vc *nsvc,</span><br><span style="color: hsl(120, 100%, 40%);">+                     struct msgb *msg);</span><br><span style="color: hsl(120, 100%, 40%);">+struct gprs_ns2_nse *gprs_ns2_nse_by_nsei(struct gprs_ns2_inst *nsi, uint16_t nsei);</span><br><span style="color: hsl(120, 100%, 40%);">+struct gprs_ns2_nse *gprs_ns2_create_nse(struct gprs_ns2_inst *nsi, uint16_t nsei);</span><br><span style="color: hsl(120, 100%, 40%);">+void gprs_ns2_free_nse(struct gprs_ns2_nse *nse);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* create vc */</span><br><span style="color: hsl(120, 100%, 40%);">+void gprs_ns2_free_nsvc(struct gprs_ns2_vc *nsvc);</span><br><span style="color: hsl(120, 100%, 40%);">+struct gprs_ns2_vc *gprs_ns2_nsvc_by_nsvci(struct gprs_ns2_inst *nsi, uint16_t nsvci);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* transmit message over a VC */</span><br><span style="color: hsl(120, 100%, 40%);">+int gprs_ns2_tx_block(struct gprs_ns2_vc *nsvc, uint8_t cause);</span><br><span style="color: hsl(120, 100%, 40%);">+int gprs_ns2_tx_block_ack(struct gprs_ns2_vc *nsvc);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int gprs_ns2_tx_reset(struct gprs_ns2_vc *nsvc, uint8_t cause);</span><br><span style="color: hsl(120, 100%, 40%);">+int gprs_ns2_tx_reset_ack(struct gprs_ns2_vc *nsvc);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int gprs_ns2_tx_unblock(struct gprs_ns2_vc *nsvc);</span><br><span style="color: hsl(120, 100%, 40%);">+int gprs_ns2_tx_unblock_ack(struct gprs_ns2_vc *nsvc);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int gprs_ns2_tx_alive(struct gprs_ns2_vc *nsvc);</span><br><span style="color: hsl(120, 100%, 40%);">+int gprs_ns2_tx_alive_ack(struct gprs_ns2_vc *nsvc);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int gprs_ns2_tx_unit_data(struct gprs_ns2_vc *nsvc, struct msgb *msg);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int gprs_ns2_tx_status(struct gprs_ns2_vc *nsvc, uint8_t cause,</span><br><span style="color: hsl(120, 100%, 40%);">+                uint16_t bvci, struct msgb *orig_msg);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* SNS messages */</span><br><span style="color: hsl(120, 100%, 40%);">+int gprs_ns2_tx_sns_ack(struct gprs_ns2_vc *nsvc, uint8_t trans_id, uint8_t *cause,</span><br><span style="color: hsl(120, 100%, 40%);">+                      const struct gprs_ns_ie_ip4_elem *ip4_elems,</span><br><span style="color: hsl(120, 100%, 40%);">+                  unsigned int num_ip4_elems);</span><br><span style="color: hsl(120, 100%, 40%);">+int gprs_ns2_tx_sns_config(struct gprs_ns2_vc *nsvc, bool end_flag,</span><br><span style="color: hsl(120, 100%, 40%);">+                        const struct gprs_ns_ie_ip4_elem *ip4_elems,</span><br><span style="color: hsl(120, 100%, 40%);">+                          unsigned int num_ip4_elems);</span><br><span style="color: hsl(120, 100%, 40%);">+int gprs_ns2_tx_sns_config_ack(struct gprs_ns2_vc *nsvc, uint8_t *cause);</span><br><span style="color: hsl(120, 100%, 40%);">+int gprs_ns2_tx_sns_size(struct gprs_ns2_vc *nsvc, bool reset_flag, uint16_t max_nr_nsvc,</span><br><span style="color: hsl(120, 100%, 40%);">+                  uint16_t *ip4_ep_nr, uint16_t *ip6_ep_nr);</span><br><span style="color: hsl(120, 100%, 40%);">+int gprs_ns2_tx_sns_size_ack(struct gprs_ns2_vc *nsvc, uint8_t *cause);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* IP VL driver */</span><br><span style="color: hsl(120, 100%, 40%);">+int gprs_ns2_ip_bind(struct gprs_ns2_inst *nsi,</span><br><span style="color: hsl(120, 100%, 40%);">+                struct osmo_sockaddr *local,</span><br><span style="color: hsl(120, 100%, 40%);">+                  int dscp,</span><br><span style="color: hsl(120, 100%, 40%);">+                     struct gprs_ns2_vc_bind **result);</span><br><span style="color: hsl(120, 100%, 40%);">+void gprs_ns2_bind_set_mode(struct gprs_ns2_vc_bind *bind, enum gprs_ns2_vc_mode mode);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* create a VC connection */</span><br><span style="color: hsl(120, 100%, 40%);">+struct gprs_ns2_vc *gprs_ns2_ip_connect(struct gprs_ns2_vc_bind *bind,</span><br><span style="color: hsl(120, 100%, 40%);">+                                      struct osmo_sockaddr *remote,</span><br><span style="color: hsl(120, 100%, 40%);">+                                 struct gprs_ns2_nse *nse,</span><br><span style="color: hsl(120, 100%, 40%);">+                                     uint16_t nsvci);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct gprs_ns2_vc *gprs_ns2_ip_connect2(struct gprs_ns2_vc_bind *bind,</span><br><span style="color: hsl(120, 100%, 40%);">+                                    struct osmo_sockaddr *remote,</span><br><span style="color: hsl(120, 100%, 40%);">+                                         uint16_t nsei,</span><br><span style="color: hsl(120, 100%, 40%);">+                                        uint16_t nsvci);</span><br><span style="color: hsl(120, 100%, 40%);">+/* TODO: should the inactive prviate */</span><br><span style="color: hsl(120, 100%, 40%);">+struct gprs_ns2_vc *gprs_ns2_ip_connect_inactive(struct gprs_ns2_vc_bind *bind,</span><br><span style="color: hsl(120, 100%, 40%);">+                                   struct osmo_sockaddr *remote,</span><br><span style="color: hsl(120, 100%, 40%);">+                                 struct gprs_ns2_nse *nse,</span><br><span style="color: hsl(120, 100%, 40%);">+                                     uint16_t nsvci);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void gprs_ns2_free_bind(struct gprs_ns2_vc_bind *bind);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* create a VC SNS connection */</span><br><span style="color: hsl(120, 100%, 40%);">+int gprs_ns2_ip_connect_sns(struct gprs_ns2_vc_bind *bind,</span><br><span style="color: hsl(120, 100%, 40%);">+                       struct osmo_sockaddr *remote,</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%);">+struct osmo_sockaddr *gprs_ns2_ip_vc_sockaddr(struct gprs_ns2_vc *nsvc);</span><br><span style="color: hsl(120, 100%, 40%);">+struct osmo_sockaddr *gprs_ns2_ip_bind_sockaddr(struct gprs_ns2_vc_bind *bind);</span><br><span style="color: hsl(120, 100%, 40%);">+int gprs_ns2_is_ip_bind(struct gprs_ns2_vc_bind *bind);</span><br><span style="color: hsl(120, 100%, 40%);">+int gprs_ns2_ip_bind_set_dscp(struct gprs_ns2_vc_bind *bind, int dscp);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct gprs_ns2_vc *gprs_ns2_nsvc_by_sockaddr(struct gprs_ns2_nse *nsei,</span><br><span style="color: hsl(120, 100%, 40%);">+                                              struct osmo_sockaddr *sockaddr);</span><br><span style="color: hsl(120, 100%, 40%);">+void gprs_ns2_start_alive_all_nsvcs(struct gprs_ns2_nse *nse);</span><br><span style="color: hsl(120, 100%, 40%);">+void gprs_ns2_set_log_ss(int ss);</span><br><span style="color: hsl(120, 100%, 40%);">+const char *gprs_ns2_cause_str(int cause);</span><br><span style="color: hsl(120, 100%, 40%);">+const char *gprs_ns2_ll_str(const struct gprs_ns2_vc *nsvc);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* vty */</span><br><span style="color: hsl(120, 100%, 40%);">+int gprs_ns2_vty_init(struct gprs_ns2_inst *nsi);</span><br><span style="color: hsl(120, 100%, 40%);">+int gprs_ns2_vty_create();</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%);">+#endif /* OSMO_GPRS_NS2_H */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! @} */</span><br><span>diff --git a/include/osmocom/gprs/gprs_ns_common.h b/include/osmocom/gprs/gprs_ns_common.h</span><br><span>new file mode 100644</span><br><span>index 0000000..7bc7492</span><br><span>--- /dev/null</span><br><span>+++ b/include/osmocom/gprs/gprs_ns_common.h</span><br><span>@@ -0,0 +1,104 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/*! \file gprs_ns_common.h */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#ifndef OSMO_GPRS_NS_COMMON_H</span><br><span style="color: hsl(120, 100%, 40%);">+#define OSMO_GPRS_NS_COMMON_H</span><br><span style="color: hsl(120, 100%, 40%);">+</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_nse;</span><br><span style="color: hsl(120, 100%, 40%);">+struct gprs_ns2_vc;</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%);">+#define NS_TIMERS_COUNT 8</span><br><span style="color: hsl(120, 100%, 40%);">+#define NS_TIMERS "(tns-block|tns-block-retries|tns-reset|tns-reset-retries|tns-test|tns-alive|tns-alive-retries|tsns-prov)"</span><br><span style="color: hsl(120, 100%, 40%);">+#define NS_TIMERS_HELP       \</span><br><span style="color: hsl(120, 100%, 40%);">+     "(un)blocking Timer (Tns-block) timeout\n"            \</span><br><span style="color: hsl(120, 100%, 40%);">+     "(un)blocking Timer (Tns-block) number of retries\n"  \</span><br><span style="color: hsl(120, 100%, 40%);">+     "Reset Timer (Tns-reset) timeout\n"                   \</span><br><span style="color: hsl(120, 100%, 40%);">+     "Reset Timer (Tns-reset) number of retries\n"         \</span><br><span style="color: hsl(120, 100%, 40%);">+     "Test Timer (Tns-test) timeout\n"                     \</span><br><span style="color: hsl(120, 100%, 40%);">+     "Alive Timer (Tns-alive) timeout\n"                   \</span><br><span style="color: hsl(120, 100%, 40%);">+     "Alive Timer (Tns-alive) number of retries\n"         \</span><br><span style="color: hsl(120, 100%, 40%);">+     "SNS Provision Timer (Tsns-prov) timeout\n"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* Educated guess - LLC user payload is 1500 bytes plus possible headers */</span><br><span style="color: hsl(120, 100%, 40%);">+#define NS_ALLOC_SIZE     3072</span><br><span style="color: hsl(120, 100%, 40%);">+#define NS_ALLOC_HEADROOM 20</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+enum ns2_timeout {</span><br><span style="color: hsl(120, 100%, 40%);">+      NS_TOUT_TNS_BLOCK,</span><br><span style="color: hsl(120, 100%, 40%);">+    NS_TOUT_TNS_BLOCK_RETRIES,</span><br><span style="color: hsl(120, 100%, 40%);">+    NS_TOUT_TNS_RESET,</span><br><span style="color: hsl(120, 100%, 40%);">+    NS_TOUT_TNS_RESET_RETRIES,</span><br><span style="color: hsl(120, 100%, 40%);">+    NS_TOUT_TNS_TEST,</span><br><span style="color: hsl(120, 100%, 40%);">+     NS_TOUT_TNS_ALIVE,</span><br><span style="color: hsl(120, 100%, 40%);">+    NS_TOUT_TNS_ALIVE_RETRIES,</span><br><span style="color: hsl(120, 100%, 40%);">+    NS_TOUT_TSNS_PROV,</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%);">+#define NSE_S_BLOCKED 0x0001</span><br><span style="color: hsl(120, 100%, 40%);">+#define NSE_S_ALIVE     0x0002</span><br><span style="color: hsl(120, 100%, 40%);">+#define NSE_S_RESET     0x0004</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define NS_DESC_B(st) ((st) & NSE_S_BLOCKED ? "BLOCKED" : "UNBLOCKED")</span><br><span style="color: hsl(120, 100%, 40%);">+#define NS_DESC_A(st) ((st) & NSE_S_ALIVE ? "ALIVE" : "DEAD")</span><br><span style="color: hsl(120, 100%, 40%);">+#define NS_DESC_R(st) ((st) & NSE_S_RESET ? "RESET" : "UNRESET")</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! Osmocom NS link layer types */</span><br><span style="color: hsl(120, 100%, 40%);">+enum gprs_ns_ll {</span><br><span style="color: hsl(120, 100%, 40%);">+    GPRS_NS_LL_UDP,         /*!< NS/UDP/IP */</span><br><span style="color: hsl(120, 100%, 40%);">+  GPRS_NS_LL_E1,          /*!< NS/E1 */</span><br><span style="color: hsl(120, 100%, 40%);">+      GPRS_NS_LL_FR_GRE,      /*!< NS/FR/GRE/IP */</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%);">+/*! Osmoco NS events */</span><br><span style="color: hsl(120, 100%, 40%);">+enum gprs_ns_evt {</span><br><span style="color: hsl(120, 100%, 40%);">+    GPRS_NS_EVT_UNIT_DATA,</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%);">+/*! Osmocom NS VC create status */</span><br><span style="color: hsl(120, 100%, 40%);">+enum gprs_ns_cs {</span><br><span style="color: hsl(120, 100%, 40%);">+   GPRS_NS_CS_CREATED,     /*!< A NSVC object has been created */</span><br><span style="color: hsl(120, 100%, 40%);">+     GPRS_NS_CS_FOUND,       /*!< A NSVC object has been found */</span><br><span style="color: hsl(120, 100%, 40%);">+       GPRS_NS_CS_REJECTED,    /*!< Rejected and answered message */</span><br><span style="color: hsl(120, 100%, 40%);">+      GPRS_NS_CS_SKIPPED,     /*!< Skipped message */</span><br><span style="color: hsl(120, 100%, 40%);">+    GPRS_NS_CS_ERROR,       /*!< Failed to process message */</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 nsvc_timer_mode {</span><br><span style="color: hsl(120, 100%, 40%);">+    /* standard timers */</span><br><span style="color: hsl(120, 100%, 40%);">+ NSVC_TIMER_TNS_TEST,</span><br><span style="color: hsl(120, 100%, 40%);">+  NSVC_TIMER_TNS_ALIVE,</span><br><span style="color: hsl(120, 100%, 40%);">+ NSVC_TIMER_TNS_RESET,</span><br><span style="color: hsl(120, 100%, 40%);">+ _NSVC_TIMER_NR,</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 gprs_ns2_signal_ns {</span><br><span style="color: hsl(120, 100%, 40%);">+      S_NS_RESET,</span><br><span style="color: hsl(120, 100%, 40%);">+   S_NS_BLOCK,</span><br><span style="color: hsl(120, 100%, 40%);">+   S_NS_UNBLOCK,</span><br><span style="color: hsl(120, 100%, 40%);">+ S_NS_ALIVE_EXP, /* Tns-alive expired more than N times */</span><br><span style="color: hsl(120, 100%, 40%);">+     S_NS_REPLACED, /* nsvc object is replaced (sets old_nsvc) */</span><br><span style="color: hsl(120, 100%, 40%);">+  S_NS_MISMATCH, /* got an unexpected IE (sets msg, pdu_type, ie_type) */</span><br><span style="color: hsl(120, 100%, 40%);">+       S_SNS_CONFIGURED, /* IP-SNS configuration completed */</span><br><span style="color: hsl(120, 100%, 40%);">+        S_NSE_AVAILABLE, /* NS2 NSE came alive */</span><br><span style="color: hsl(120, 100%, 40%);">+     S_NSE_UNAVAILABLE, /* */</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 gprs_ns2_signal_data {</span><br><span style="color: hsl(120, 100%, 40%);">+ struct gprs_ns2_nse *nse;</span><br><span style="color: hsl(120, 100%, 40%);">+     uint16_t nsei;</span><br><span style="color: hsl(120, 100%, 40%);">+        struct gprs_ns2_vc *nsvc;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct gprs_ns2_vc *old_nsvc;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t cause;</span><br><span style="color: hsl(120, 100%, 40%);">+        uint8_t pdu_type;</span><br><span style="color: hsl(120, 100%, 40%);">+     uint8_t ie_type;</span><br><span style="color: hsl(120, 100%, 40%);">+      struct msgb *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%);">+enum gprs_ns2_vc_mode {</span><br><span style="color: hsl(120, 100%, 40%);">+      NS2_VC_MODE_ALIVE, /* The VC will use RESET/BLOCK/UNBLOCK to start the connection and do ALIVE/ACK */</span><br><span style="color: hsl(120, 100%, 40%);">+ NS2_VC_MODE_BLOCKRESET, /* The will only use ALIVE/ACK no initiation */</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%);">+#endif /* OSMO_GPRS_NS_COMMON_H */</span><br><span>diff --git a/src/gb/Makefile.am b/src/gb/Makefile.am</span><br><span>index 7248413..40df58e 100644</span><br><span>--- a/src/gb/Makefile.am</span><br><span>+++ b/src/gb/Makefile.am</span><br><span>@@ -20,7 +20,10 @@</span><br><span> </span><br><span> libosmogb_la_SOURCES = gprs_ns.c gprs_ns_frgre.c gprs_ns_vty.c gprs_ns_sns.c \</span><br><span>              gprs_bssgp.c gprs_bssgp_util.c gprs_bssgp_vty.c \</span><br><span style="color: hsl(0, 100%, 40%);">-               gprs_bssgp_bss.c common_vty.c</span><br><span style="color: hsl(120, 100%, 40%);">+                 gprs_bssgp_bss.c \</span><br><span style="color: hsl(120, 100%, 40%);">+            gprs_ns2.c gprs_ns2_driver.c gprs_ns2_vc_fsm.c gprs_ns2_sns.c \</span><br><span style="color: hsl(120, 100%, 40%);">+               gprs_ns2_message.c gprs_ns2_vty.c \</span><br><span style="color: hsl(120, 100%, 40%);">+           common_vty.c</span><br><span> endif</span><br><span> </span><br><span> EXTRA_DIST = libosmogb.map</span><br><span>diff --git a/src/gb/gprs_ns2.c b/src/gb/gprs_ns2.c</span><br><span>new file mode 100644</span><br><span>index 0000000..583ca24</span><br><span>--- /dev/null</span><br><span>+++ b/src/gb/gprs_ns2.c</span><br><span>@@ -0,0 +1,933 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/*! \file gprs_ns.c</span><br><span style="color: hsl(120, 100%, 40%);">+ * GPRS Networks Service (NS) messages on the Gb interface.</span><br><span style="color: hsl(120, 100%, 40%);">+ * 3GPP TS 08.16 version 8.0.1 Release 1999 / ETSI TS 101 299 V8.0.1 (2002-05)</span><br><span style="color: hsl(120, 100%, 40%);">+ * as well as its successor 3GPP TS 48.016 */</span><br><span style="color: hsl(120, 100%, 40%);">+/*</span><br><span style="color: hsl(120, 100%, 40%);">+ * (C) 2009-2018 by Harald Welte <laforge@gnumonks.org></span><br><span style="color: hsl(120, 100%, 40%);">+ * (C) 2016-2017,2020 sysmocom - s.f.m.c. GmbH</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * All Rights Reserved</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * SPDX-License-Identifier: GPL-2.0+</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This program is free software; you can redistribute it and/or modify</span><br><span style="color: hsl(120, 100%, 40%);">+ * it under the terms of the GNU General Public License as published by</span><br><span style="color: hsl(120, 100%, 40%);">+ * the Free Software Foundation; either version 2 of the License, or</span><br><span style="color: hsl(120, 100%, 40%);">+ * (at your option) any later version.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This program is distributed in the hope that it will be useful,</span><br><span style="color: hsl(120, 100%, 40%);">+ * but WITHOUT ANY WARRANTY; without even the implied warranty of</span><br><span style="color: hsl(120, 100%, 40%);">+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the</span><br><span style="color: hsl(120, 100%, 40%);">+ * GNU General Public License for more details.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * You should have received a copy of the GNU General Public License</span><br><span style="color: hsl(120, 100%, 40%);">+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.</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%);">+/*! \addtogroup libgb</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%);">+ * GPRS Networks Service (NS) messages on the Gb interface</span><br><span style="color: hsl(120, 100%, 40%);">+ * 3GPP TS 08.16 version 8.0.1 Release 1999 / ETSI TS 101 299 V8.0.1 (2002-05) </span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * Some introduction into NS:  NS is used typically on top of frame relay,</span><br><span style="color: hsl(120, 100%, 40%);">+ * but in the ip.access world it is encapsulated in UDP packets.  It serves</span><br><span style="color: hsl(120, 100%, 40%);">+ * as an intermediate shim betwen BSSGP and the underlying medium.  It doesn't</span><br><span style="color: hsl(120, 100%, 40%);">+ * do much, apart from providing congestion notification and status indication.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * Terms:</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ *  NS              Network Service</span><br><span style="color: hsl(120, 100%, 40%);">+ *     NSVC            NS Virtual Connection</span><br><span style="color: hsl(120, 100%, 40%);">+ *       NSEI            NS Entity Identifier</span><br><span style="color: hsl(120, 100%, 40%);">+ *        NSVL            NS Virtual Link</span><br><span style="color: hsl(120, 100%, 40%);">+ *     NSVLI           NS Virtual Link Identifier</span><br><span style="color: hsl(120, 100%, 40%);">+ *  BVC             BSSGP Virtual Connection</span><br><span style="color: hsl(120, 100%, 40%);">+ *    BVCI            BSSGP Virtual Connection Identifier</span><br><span style="color: hsl(120, 100%, 40%);">+ *         NSVCG           NS Virtual Connection Goup</span><br><span style="color: hsl(120, 100%, 40%);">+ *  Blocked         NS-VC cannot be used for user traffic</span><br><span style="color: hsl(120, 100%, 40%);">+ *       Alive           Ability of a NS-VC to provide communication</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * There can be multiple BSSGP virtual connections over one (group of) NSVC's.  BSSGP will</span><br><span style="color: hsl(120, 100%, 40%);">+ * therefore identify the BSSGP virtual connection by a BVCI passed down to NS.</span><br><span style="color: hsl(120, 100%, 40%);">+ * NS then has to figure out which NSVC's are responsible for this BVCI.</span><br><span style="color: hsl(120, 100%, 40%);">+ * Those mappings are administratively configured.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This implementation has the following limitations:</span><br><span style="color: hsl(120, 100%, 40%);">+ * - Only one NS-VC for each NSE: No load-sharing function</span><br><span style="color: hsl(120, 100%, 40%);">+ * - NSVCI 65535 and 65534 are reserved for internal use</span><br><span style="color: hsl(120, 100%, 40%);">+ * - Only UDP is supported as of now, no frame relay support</span><br><span style="color: hsl(120, 100%, 40%);">+ * - There are no BLOCK and UNBLOCK timers (yet?)</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \file gprs_ns.c */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <stdlib.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <unistd.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <errno.h></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 <sys/types.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <sys/socket.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <arpa/inet.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/msgb.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/gsm/tlv.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/talloc.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/select.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/rate_ctr.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/stat_item.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/stats.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/socket.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/signal.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_msgb.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%);">+#include "gprs_ns2_internal.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "gprs_ns2_vc_fsm.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "gprs_ns2_driver.h"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define ns_set_state(ns_, st_) ns_set_state_with_log(ns_, st_, false, __FILE__, __LINE__)</span><br><span style="color: hsl(120, 100%, 40%);">+#define ns_set_remote_state(ns_, st_) ns_set_state_with_log(ns_, st_, true, __FILE__, __LINE__)</span><br><span style="color: hsl(120, 100%, 40%);">+#define ns_mark_blocked(ns_) ns_set_state(ns_, (ns_)->state | NSE_S_BLOCKED)</span><br><span style="color: hsl(120, 100%, 40%);">+#define ns_mark_unblocked(ns_) ns_set_state(ns_, (ns_)->state & (~NSE_S_BLOCKED));</span><br><span style="color: hsl(120, 100%, 40%);">+#define ns_mark_alive(ns_) ns_set_state(ns_, (ns_)->state | NSE_S_ALIVE)</span><br><span style="color: hsl(120, 100%, 40%);">+#define ns_mark_dead(ns_) ns_set_state(ns_, (ns_)->state & (~NSE_S_ALIVE));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static const struct tlv_definition ns_att_tlvdef = {</span><br><span style="color: hsl(120, 100%, 40%);">+     .def = {</span><br><span style="color: hsl(120, 100%, 40%);">+              [NS_IE_CAUSE]   = { TLV_TYPE_TvLV, 0 },</span><br><span style="color: hsl(120, 100%, 40%);">+               [NS_IE_VCI]     = { TLV_TYPE_TvLV, 0 },</span><br><span style="color: hsl(120, 100%, 40%);">+               [NS_IE_PDU]     = { TLV_TYPE_TvLV, 0 },</span><br><span style="color: hsl(120, 100%, 40%);">+               [NS_IE_BVCI]    = { TLV_TYPE_TvLV, 0 },</span><br><span style="color: hsl(120, 100%, 40%);">+               [NS_IE_NSEI]    = { TLV_TYPE_TvLV, 0 },</span><br><span style="color: hsl(120, 100%, 40%);">+               [NS_IE_IPv4_LIST] = { TLV_TYPE_TvLV, 0 },</span><br><span style="color: hsl(120, 100%, 40%);">+             [NS_IE_IPv6_LIST] = { TLV_TYPE_TvLV, 0 },</span><br><span style="color: hsl(120, 100%, 40%);">+             [NS_IE_MAX_NR_NSVC] = { TLV_TYPE_FIXED, 2 },</span><br><span style="color: hsl(120, 100%, 40%);">+          [NS_IE_IPv4_EP_NR] = { TLV_TYPE_FIXED, 2 },</span><br><span style="color: hsl(120, 100%, 40%);">+           [NS_IE_IPv6_EP_NR] = { TLV_TYPE_FIXED, 2 },</span><br><span style="color: hsl(120, 100%, 40%);">+           [ NS_IE_RESET_FLAG] = { TLV_TYPE_TV, 0 },</span><br><span style="color: hsl(120, 100%, 40%);">+             /* TODO: IP_ADDR can be 5 or 17 bytes long, depending on first byte. This</span><br><span style="color: hsl(120, 100%, 40%);">+              * cannot be expressed in our TLV parser.  However, we don't do IPv6 anyway */</span><br><span style="color: hsl(120, 100%, 40%);">+            [NS_IE_IP_ADDR] = { TLV_TYPE_FIXED, 5 },</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%);">+/* TODO: move into common part */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* Section 10.3.2, Table 13 */</span><br><span style="color: hsl(120, 100%, 40%);">+static const struct value_string ns2_cause_str[] = {</span><br><span style="color: hsl(120, 100%, 40%);">+   { NS_CAUSE_TRANSIT_FAIL,        "Transit network failure" },</span><br><span style="color: hsl(120, 100%, 40%);">+        { NS_CAUSE_OM_INTERVENTION,     "O&M intervention" },</span><br><span style="color: hsl(120, 100%, 40%);">+   { NS_CAUSE_EQUIP_FAIL,          "Equipment failure" },</span><br><span style="color: hsl(120, 100%, 40%);">+      { NS_CAUSE_NSVC_BLOCKED,        "NS-VC blocked" },</span><br><span style="color: hsl(120, 100%, 40%);">+  { NS_CAUSE_NSVC_UNKNOWN,        "NS-VC unknown" },</span><br><span style="color: hsl(120, 100%, 40%);">+  { NS_CAUSE_BVCI_UNKNOWN,        "BVCI unknown" },</span><br><span style="color: hsl(120, 100%, 40%);">+   { NS_CAUSE_SEM_INCORR_PDU,      "Semantically incorrect PDU" },</span><br><span style="color: hsl(120, 100%, 40%);">+     { NS_CAUSE_PDU_INCOMP_PSTATE,   "PDU not compatible with protocol state" },</span><br><span style="color: hsl(120, 100%, 40%);">+ { NS_CAUSE_PROTO_ERR_UNSPEC,    "Protocol error, unspecified" },</span><br><span style="color: hsl(120, 100%, 40%);">+    { NS_CAUSE_INVAL_ESSENT_IE,     "Invalid essential IE" },</span><br><span style="color: hsl(120, 100%, 40%);">+   { NS_CAUSE_MISSING_ESSENT_IE,   "Missing essential IE" },</span><br><span style="color: hsl(120, 100%, 40%);">+   { NS_CAUSE_INVAL_NR_IPv4_EP,    "Invalid Number of IPv4 Endpoints" },</span><br><span style="color: hsl(120, 100%, 40%);">+       { NS_CAUSE_INVAL_NR_IPv6_EP,    "Invalid Number of IPv6 Endpoints" },</span><br><span style="color: hsl(120, 100%, 40%);">+       { NS_CAUSE_INVAL_NR_NS_VC,      "Invalid Number of NS-VCs" },</span><br><span style="color: hsl(120, 100%, 40%);">+       { NS_CAUSE_INVAL_WEIGH,         "Invalid Weights" },</span><br><span style="color: hsl(120, 100%, 40%);">+        { NS_CAUSE_UNKN_IP_EP,          "Unknown IP Endpoint" },</span><br><span style="color: hsl(120, 100%, 40%);">+    { NS_CAUSE_UNKN_IP_ADDR,        "Unknown IP Address" },</span><br><span style="color: hsl(120, 100%, 40%);">+     { NS_CAUSE_UNKN_IP_TEST_FAILED, "IP Test Failed" },</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%);">+/*! Obtain a human-readable string for NS cause value */</span><br><span style="color: hsl(120, 100%, 40%);">+const char *gprs_ns2_cause_str(int cause)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     enum ns_cause _cause = cause;</span><br><span style="color: hsl(120, 100%, 40%);">+ return get_value_string(ns2_cause_str, _cause);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static const struct rate_ctr_desc nsvc_ctr_description[] = {</span><br><span style="color: hsl(120, 100%, 40%);">+    { "packets:in", "Packets at NS Level  ( In)" },</span><br><span style="color: hsl(120, 100%, 40%);">+   { "packets:out","Packets at NS Level  (Out)" },</span><br><span style="color: hsl(120, 100%, 40%);">+   { "bytes:in", "Bytes at NS Level    ( In)" },</span><br><span style="color: hsl(120, 100%, 40%);">+     { "bytes:out",        "Bytes at NS Level    (Out)" },</span><br><span style="color: hsl(120, 100%, 40%);">+     { "blocked",  "NS-VC Block count         " },</span><br><span style="color: hsl(120, 100%, 40%);">+     { "dead",     "NS-VC gone dead count     " },</span><br><span style="color: hsl(120, 100%, 40%);">+     { "replaced", "NS-VC replaced other count" },</span><br><span style="color: hsl(120, 100%, 40%);">+     { "nsei-chg", "NS-VC changed NSEI count  " },</span><br><span style="color: hsl(120, 100%, 40%);">+     { "inv-nsvci",        "NS-VCI was invalid count  " },</span><br><span style="color: hsl(120, 100%, 40%);">+     { "inv-nsei", "NSEI was invalid count    " },</span><br><span style="color: hsl(120, 100%, 40%);">+     { "lost:alive",       "ALIVE ACK missing count   " },</span><br><span style="color: hsl(120, 100%, 40%);">+     { "lost:reset",       "RESET ACK missing count   " },</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 rate_ctr_group_desc nsvc_ctrg_desc = {</span><br><span style="color: hsl(120, 100%, 40%);">+   .group_name_prefix = "ns:nsvc",</span><br><span style="color: hsl(120, 100%, 40%);">+     .group_description = "NSVC Peer Statistics",</span><br><span style="color: hsl(120, 100%, 40%);">+        .num_ctr = ARRAY_SIZE(nsvc_ctr_description),</span><br><span style="color: hsl(120, 100%, 40%);">+  .ctr_desc = nsvc_ctr_description,</span><br><span style="color: hsl(120, 100%, 40%);">+     .class_id = OSMO_STATS_CLASS_PEER,</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 ns_stat {</span><br><span style="color: hsl(120, 100%, 40%);">+      NS_STAT_ALIVE_DELAY,</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_stat_item_desc nsvc_stat_description[] = {</span><br><span style="color: hsl(120, 100%, 40%);">+       { "alive.delay", "ALIVE response time        ", "ms", 16, 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 const struct osmo_stat_item_group_desc nsvc_statg_desc = {</span><br><span style="color: hsl(120, 100%, 40%);">+ .group_name_prefix = "ns.nsvc",</span><br><span style="color: hsl(120, 100%, 40%);">+     .group_description = "NSVC Peer Statistics",</span><br><span style="color: hsl(120, 100%, 40%);">+        .num_items = ARRAY_SIZE(nsvc_stat_description),</span><br><span style="color: hsl(120, 100%, 40%);">+       .item_desc = nsvc_stat_description,</span><br><span style="color: hsl(120, 100%, 40%);">+   .class_id = OSMO_STATS_CLASS_PEER,</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+const struct value_string gprs_ns2_signal_ns_names[] = {</span><br><span style="color: hsl(120, 100%, 40%);">+    { S_NS_RESET,           "NS-RESET" },</span><br><span style="color: hsl(120, 100%, 40%);">+       { S_NS_BLOCK,           "NS-BLOCK" },</span><br><span style="color: hsl(120, 100%, 40%);">+       { S_NS_UNBLOCK,         "NS-UNBLOCK" },</span><br><span style="color: hsl(120, 100%, 40%);">+     { S_NS_ALIVE_EXP,       "NS-ALIVE expired" },</span><br><span style="color: hsl(120, 100%, 40%);">+       { S_NS_REPLACED,        "NSVC replaced" },</span><br><span style="color: hsl(120, 100%, 40%);">+  { S_NS_MISMATCH,        "Unexpected IE" },</span><br><span style="color: hsl(120, 100%, 40%);">+  { S_SNS_CONFIGURED,     "SNS Configured" },</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%);">+void gprs_ns2_set_log_ss(int ss)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        DNS = ss;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+const char *gprs_ns2_ll_str(const struct gprs_ns2_vc *nsvc)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        static __thread char buf[80] = "";</span><br><span style="color: hsl(120, 100%, 40%);">+  /* TODO ns2_ll_str */</span><br><span style="color: hsl(120, 100%, 40%);">+//       return gprs_ns_ll_str_buf(buf, sizeof(buf), nsvc);</span><br><span style="color: hsl(120, 100%, 40%);">+    return &buf[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%);">+ * \brief gprs_ns2_send_nse send PDU for a NSE</span><br><span style="color: hsl(120, 100%, 40%);">+ * The bvci is encoded in the message. See msg_bvci()</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param nse</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param msg</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%);">+int gprs_ns2_send_nse(struct gprs_ns2_nse *nse, struct msgb *msg)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     /* TODO: do loadbalancing in here and bvci stickyness */</span><br><span style="color: hsl(120, 100%, 40%);">+      struct gprs_ns2_vc *nsvc = NULL, *tmp;</span><br><span style="color: hsl(120, 100%, 40%);">+        uint16_t bvci = msgb_bvci(msg);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     llist_for_each_entry(tmp, &nse->vc, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+            if (!gprs_ns2_vc_is_unblocked(tmp))</span><br><span style="color: hsl(120, 100%, 40%);">+                   continue;</span><br><span style="color: hsl(120, 100%, 40%);">+             if (bvci == 0 && tmp->sig_weight == 0)</span><br><span style="color: hsl(120, 100%, 40%);">+                     continue;</span><br><span style="color: hsl(120, 100%, 40%);">+             if (bvci != 0 && tmp->data_weight == 0)</span><br><span style="color: hsl(120, 100%, 40%);">+                    continue;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           nsvc = tmp;</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 (!nsvc)</span><br><span style="color: hsl(120, 100%, 40%);">+            return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  return gprs_ns2_tx_unit_data(nsvc, 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%);">+int gprs_ns2_send_nsei(struct gprs_ns2_inst *nsi, uint16_t nsei, struct msgb *msg)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  struct gprs_ns2_nse *nse;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   nse = gprs_ns2_nse_by_nsei(nsi, nsei);</span><br><span style="color: hsl(120, 100%, 40%);">+        if (!nse)</span><br><span style="color: hsl(120, 100%, 40%);">+             return -ENOENT;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     return gprs_ns2_send_nse(nse, 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%);">+int gprs_ns2_send(struct gprs_ns2_inst *nsi, struct msgb *msg)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   struct gprs_ns2_nse *nse;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   nse = gprs_ns2_nse_by_nsei(nsi, msgb_nsei(msg));</span><br><span style="color: hsl(120, 100%, 40%);">+      if (!nse)</span><br><span style="color: hsl(120, 100%, 40%);">+             return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  return gprs_ns2_send_nse(nse, 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%);">+/*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief ns2_vc_alloc</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param bind</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param nse</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param initiater - if this is an incoming remote (!initiater) or a local outgoing connection (initater)</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%);">+struct gprs_ns2_vc *ns2_vc_alloc(struct gprs_ns2_vc_bind *bind, struct gprs_ns2_nse *nse, bool initiater)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       struct gprs_ns2_vc *vc = talloc_zero(bind, struct gprs_ns2_vc);</span><br><span style="color: hsl(120, 100%, 40%);">+       int nsvci = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      if (!vc)</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%);">+        vc->bind = bind;</span><br><span style="color: hsl(120, 100%, 40%);">+   vc->nse = nse;</span><br><span style="color: hsl(120, 100%, 40%);">+     vc->mode = bind->use_reset_block_unblock ? NS2_VC_MODE_BLOCKRESET : NS2_VC_MODE_ALIVE;</span><br><span style="color: hsl(120, 100%, 40%);">+  vc->sig_weight = 1;</span><br><span style="color: hsl(120, 100%, 40%);">+        vc->data_weight = 1;</span><br><span style="color: hsl(120, 100%, 40%);">+       llist_add(&vc->list, &nse->vc);</span><br><span style="color: hsl(120, 100%, 40%);">+ llist_add(&vc->blist, &bind->vc);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     /* TODO: fix ctrg index. It must be != 0. Maybe use a integer at nsi level? */</span><br><span style="color: hsl(120, 100%, 40%);">+        vc->ctrg = rate_ctr_group_alloc(vc, &nsvc_ctrg_desc, nsvci);</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!vc->ctrg) {</span><br><span style="color: hsl(120, 100%, 40%);">+           goto err;</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+     /* TODO: fix statg index. It must be != 0 */</span><br><span style="color: hsl(120, 100%, 40%);">+  vc->statg = osmo_stat_item_group_alloc(vc, &nsvc_statg_desc, nsvci);</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!vc->statg)</span><br><span style="color: hsl(120, 100%, 40%);">+            goto err_group;</span><br><span style="color: hsl(120, 100%, 40%);">+       if (!gprs_ns2_vc_fsm_alloc(vc, NULL, initiater))</span><br><span style="color: hsl(120, 100%, 40%);">+              goto err_statg;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     return vc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+err_statg:</span><br><span style="color: hsl(120, 100%, 40%);">+      osmo_stat_item_group_free(vc->statg);</span><br><span style="color: hsl(120, 100%, 40%);">+err_group:</span><br><span style="color: hsl(120, 100%, 40%);">+  rate_ctr_group_free(vc->ctrg);</span><br><span style="color: hsl(120, 100%, 40%);">+err:</span><br><span style="color: hsl(120, 100%, 40%);">+       llist_del(&vc->list);</span><br><span style="color: hsl(120, 100%, 40%);">+  llist_del(&vc->blist);</span><br><span style="color: hsl(120, 100%, 40%);">+ talloc_free(vc);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void gprs_ns2_free_nsvc(struct gprs_ns2_vc *nsvc)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     if (!nsvc)</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%);">+     llist_del(&nsvc->list);</span><br><span style="color: hsl(120, 100%, 40%);">+        llist_del(&nsvc->blist);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     /* TODO: signal to the user the removal of this vc */</span><br><span style="color: hsl(120, 100%, 40%);">+ /* TODO: communicate to the NSE the loss, e.g. if all VCs are freed, the user space might want to know */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* notify nse this nsvc is unavailable */</span><br><span style="color: hsl(120, 100%, 40%);">+     ns2_nse_notify_unblocked(nsvc, false);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      /* check if sns is using this VC */</span><br><span style="color: hsl(120, 100%, 40%);">+   ns2_sns_free_nsvc(nsvc);</span><br><span style="color: hsl(120, 100%, 40%);">+      osmo_fsm_inst_term(nsvc->fi, OSMO_FSM_TERM_REQUEST, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       /* let the driver/bind clean up it's internal state */</span><br><span style="color: hsl(120, 100%, 40%);">+    if (nsvc->priv && nsvc->bind->free_vc) {</span><br><span style="color: hsl(120, 100%, 40%);">+             nsvc->bind->free_vc(nsvc);</span><br><span style="color: hsl(120, 100%, 40%);">+      }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   talloc_free(nsvc);</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 msgb *gprs_ns2_msgb_alloc(void)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    struct msgb *msg = msgb_alloc_headroom(NS_ALLOC_SIZE, NS_ALLOC_HEADROOM,</span><br><span style="color: hsl(120, 100%, 40%);">+              "GPRS/NS");</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!msg) {</span><br><span style="color: hsl(120, 100%, 40%);">+           LOGP(DNS, LOGL_ERROR, "Failed to allocate NS message of size %d\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                 NS_ALLOC_SIZE);</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%);">+/*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief gprs_ns2_cerate_status_msg create a status message to be sent over a new connection.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[in] orig_msg the original message</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[in] tp TLVP parsed of the original message</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[out] result</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[in] cause</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%);">+static int reject_status_msg(struct msgb *orig_msg, struct tlv_parsed *tp, struct msgb **reject, enum ns_cause cause)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       /* TODO has to create all messages. It might append NSVCI */</span><br><span style="color: hsl(120, 100%, 40%);">+  struct msgb *msg = gprs_ns2_msgb_alloc();</span><br><span style="color: hsl(120, 100%, 40%);">+     struct gprs_ns_hdr *nsh;</span><br><span style="color: hsl(120, 100%, 40%);">+      bool have_vci = false;</span><br><span style="color: hsl(120, 100%, 40%);">+        uint8_t _cause = cause;</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 -ENOMEM;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+//   LOGP(DNS, LOGL_NOTICE, "NSEI=%u Tx NS STATUS (NSVCI=%u, cause=%s)\n",</span><br><span style="color: hsl(120, 100%, 40%);">+//             nsvc->nsei, nsvc->nsvci, gprs_ns_cause_str(cause));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   msg->l2h = msgb_put(msg, sizeof(*nsh));</span><br><span style="color: hsl(120, 100%, 40%);">+    nsh = (struct gprs_ns_hdr *) msg->l2h;</span><br><span style="color: hsl(120, 100%, 40%);">+     nsh->pdu_type = NS_PDUT_STATUS;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  msgb_tvlv_put(msg, NS_IE_CAUSE, 1, &_cause);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    have_vci = TLVP_PRESENT(tp, NS_IE_VCI);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     /* Section 9.2.7.1: Static conditions for NS-VCI */</span><br><span style="color: hsl(120, 100%, 40%);">+   if (cause == NS_CAUSE_NSVC_BLOCKED ||</span><br><span style="color: hsl(120, 100%, 40%);">+     cause == NS_CAUSE_NSVC_UNKNOWN) {</span><br><span style="color: hsl(120, 100%, 40%);">+         if (!have_vci) {</span><br><span style="color: hsl(120, 100%, 40%);">+                      msgb_free(msg);</span><br><span style="color: hsl(120, 100%, 40%);">+                       return -EINVAL;</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%);">+           msgb_tvlv_put(msg, NS_IE_VCI, 2, TLVP_VAL(tp, NS_IE_VCI));</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%);">+   /* Section 9.2.7.2: Static conditions for NS PDU */</span><br><span style="color: hsl(120, 100%, 40%);">+   switch (cause) {</span><br><span style="color: hsl(120, 100%, 40%);">+      case NS_CAUSE_SEM_INCORR_PDU:</span><br><span style="color: hsl(120, 100%, 40%);">+ case NS_CAUSE_PDU_INCOMP_PSTATE:</span><br><span style="color: hsl(120, 100%, 40%);">+      case NS_CAUSE_PROTO_ERR_UNSPEC:</span><br><span style="color: hsl(120, 100%, 40%);">+       case NS_CAUSE_INVAL_ESSENT_IE:</span><br><span style="color: hsl(120, 100%, 40%);">+        case NS_CAUSE_MISSING_ESSENT_IE:</span><br><span style="color: hsl(120, 100%, 40%);">+              msgb_tvlv_put(msg, NS_IE_PDU, msgb_l2len(orig_msg),</span><br><span style="color: hsl(120, 100%, 40%);">+                         orig_msg->l2h);</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%);">+              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%);">+   *reject = 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%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct gprs_ns2_nse *gprs_ns2_nse_by_nsei(struct gprs_ns2_inst *nsi, uint16_t nsei)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      struct gprs_ns2_nse *nse;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   llist_for_each_entry(nse, &nsi->nse, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+           if (nse->nsei == nsei)</span><br><span style="color: hsl(120, 100%, 40%);">+                     return nse;</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct gprs_ns2_vc *gprs_ns2_nsvc_by_nsvci(struct gprs_ns2_inst *nsi, uint16_t nsvci)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   struct gprs_ns2_nse *nse;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct gprs_ns2_vc *nsvc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   llist_for_each_entry(nse, &nsi->nse, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+           llist_for_each_entry(nsvc, &nse->vc, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+                   if (nsvc->nsvci_is_valid && nsvc->nsvci == nsvci)</span><br><span style="color: hsl(120, 100%, 40%);">+                               return nsvc;</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%);">+   return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct gprs_ns2_nse *gprs_ns2_create_nse(struct gprs_ns2_inst *nsi, uint16_t nsei)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      struct gprs_ns2_nse *nse = talloc_zero(nsi, struct gprs_ns2_nse);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   OSMO_ASSERT(nsi);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!nse)</span><br><span style="color: hsl(120, 100%, 40%);">+             return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        /* TODO: check if nsei already taken! */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    nse->nsei = nsei;</span><br><span style="color: hsl(120, 100%, 40%);">+  nse->nsi = nsi;</span><br><span style="color: hsl(120, 100%, 40%);">+    llist_add(&nse->list, &nsi->nse);</span><br><span style="color: hsl(120, 100%, 40%);">+       INIT_LLIST_HEAD(&nse->vc);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   nse->bss_sns_fi = ns2_sns_bss_fsm_alloc(nse, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+        if (!nse->bss_sns_fi) {</span><br><span style="color: hsl(120, 100%, 40%);">+            llist_del(&nse->list);</span><br><span style="color: hsl(120, 100%, 40%);">+         return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return nse;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void gprs_ns2_free_nse(struct gprs_ns2_nse *nse)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct gprs_ns2_vc *vc, *tmp;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct gprs_ns2_signal_data nssd = {0};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     if (!nse)</span><br><span style="color: hsl(120, 100%, 40%);">+             return;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     /* inform the user */</span><br><span style="color: hsl(120, 100%, 40%);">+ nssd.nse = nse;</span><br><span style="color: hsl(120, 100%, 40%);">+       nssd.nsei = nse->nsei;</span><br><span style="color: hsl(120, 100%, 40%);">+     nse->unblocked = false;</span><br><span style="color: hsl(120, 100%, 40%);">+    osmo_signal_dispatch(SS_L_NS, S_NSE_UNAVAILABLE, &nssd);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        llist_for_each_entry_safe(vc, tmp, &nse->vc, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+           gprs_ns2_free_nsvc(vc);</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%);">+   llist_del(&nse->list);</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_fsm_inst_term(nse->bss_sns_fi, OSMO_FSM_TERM_REQUEST, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+  talloc_free(nse);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief gprs_ns2_create_vc create a new VC from a message. might also create a new NSEI</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[in] nsi</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[in] msg</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[in] logname A name to describe the VC. E.g. ip address pair</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[in] do_block_reset If the VC is doing BLOCK/UNBLOCK/RESET.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[out] reject A message filled to be sent back. Only used in failure cases.</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%);">+int ns2_create_vc(struct gprs_ns2_vc_bind *bind,</span><br><span style="color: hsl(120, 100%, 40%);">+                  struct msgb *msg,</span><br><span style="color: hsl(120, 100%, 40%);">+                     const char *logname,</span><br><span style="color: hsl(120, 100%, 40%);">+                  enum gprs_ns2_vc_mode mode,</span><br><span style="color: hsl(120, 100%, 40%);">+                   struct msgb **reject,</span><br><span style="color: hsl(120, 100%, 40%);">+                 struct gprs_ns2_vc **success)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       struct gprs_ns_hdr *nsh = (struct gprs_ns_hdr *)msg->l2h;</span><br><span style="color: hsl(120, 100%, 40%);">+  struct tlv_parsed tp;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct gprs_ns2_vc *vc;</span><br><span style="color: hsl(120, 100%, 40%);">+       struct gprs_ns2_nse *nse;</span><br><span style="color: hsl(120, 100%, 40%);">+     uint16_t nsvci;</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%);">+      int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     /* TODO: length check on msgb */</span><br><span style="color: hsl(120, 100%, 40%);">+      if (nsh->pdu_type == NS_PDUT_STATUS) {</span><br><span style="color: hsl(120, 100%, 40%);">+             /* Do not respond, see 3GPP TS 08.16, 7.5.1 */</span><br><span style="color: hsl(120, 100%, 40%);">+                LOGP(DNS, LOGL_INFO, "Ignoring NS STATUS from %s "</span><br><span style="color: hsl(120, 100%, 40%);">+               "for non-existing NS-VC\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                 logname);</span><br><span style="color: hsl(120, 100%, 40%);">+                return GPRS_NS2_CS_SKIPPED;</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 (nsh->pdu_type == NS_PDUT_ALIVE_ACK) {</span><br><span style="color: hsl(120, 100%, 40%);">+          /* Ignore this, see 3GPP TS 08.16, 7.4.1 */</span><br><span style="color: hsl(120, 100%, 40%);">+           LOGP(DNS, LOGL_INFO, "Ignoring NS ALIVE ACK from %s "</span><br><span style="color: hsl(120, 100%, 40%);">+                    "for non-existing NS-VC\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                 logname);</span><br><span style="color: hsl(120, 100%, 40%);">+                return GPRS_NS2_CS_SKIPPED;</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 (nsh->pdu_type == NS_PDUT_RESET_ACK) {</span><br><span style="color: hsl(120, 100%, 40%);">+          /* Ignore this, see 3GPP TS 08.16, 7.3.1 */</span><br><span style="color: hsl(120, 100%, 40%);">+           LOGP(DNS, LOGL_INFO, "Ignoring NS RESET ACK from %s "</span><br><span style="color: hsl(120, 100%, 40%);">+                    "for non-existing NS-VC\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                 logname);</span><br><span style="color: hsl(120, 100%, 40%);">+                return GPRS_NS2_CS_SKIPPED;</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%);">+   /* Only the RESET procedure creates a new NSVC */</span><br><span style="color: hsl(120, 100%, 40%);">+     if (nsh->pdu_type != NS_PDUT_RESET) {</span><br><span style="color: hsl(120, 100%, 40%);">+              rc = reject_status_msg(msg, &tp, reject, NS_CAUSE_PDU_INCOMP_PSTATE);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           if (rc < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                      LOGP(DNS, LOGL_ERROR, "Failed to generate reject message (%d)\n", rc);</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%);">+             return GPRS_NS2_CS_REJECTED;</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%);">+   rc = tlv_parse(&tp, &ns_att_tlvdef, nsh->data,</span><br><span style="color: hsl(120, 100%, 40%);">+                    msgb_l2len(msg) - sizeof(*nsh), 0, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (rc < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+              LOGP(DNS, LOGL_ERROR, "Rx NS RESET Error %d during "</span><br><span style="color: hsl(120, 100%, 40%);">+                     "TLV Parse\n", rc);</span><br><span style="color: hsl(120, 100%, 40%);">+            /* TODO: send invalid message back */</span><br><span style="color: hsl(120, 100%, 40%);">+         return GPRS_NS2_CS_REJECTED;</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 (!TLVP_PRESENT(&tp, NS_IE_CAUSE) ||</span><br><span style="color: hsl(120, 100%, 40%);">+        !TLVP_PRESENT(&tp, NS_IE_VCI) || !TLVP_PRESENT(&tp, NS_IE_NSEI)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                LOGP(DNS, LOGL_ERROR, "NS RESET Missing mandatory IE\n");</span><br><span style="color: hsl(120, 100%, 40%);">+           rc = reject_status_msg(msg, &tp, reject, NS_CAUSE_MISSING_ESSENT_IE);</span><br><span style="color: hsl(120, 100%, 40%);">+             return GPRS_NS2_CS_REJECTED;</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* find or create NSE */</span><br><span style="color: hsl(120, 100%, 40%);">+      nsei  = tlvp_val16be(&tp, NS_IE_NSEI);</span><br><span style="color: hsl(120, 100%, 40%);">+    nse = gprs_ns2_nse_by_nsei(bind->nsi, nsei);</span><br><span style="color: hsl(120, 100%, 40%);">+       if (!nse) {</span><br><span style="color: hsl(120, 100%, 40%);">+           if (!bind->nsi->create_nse) {</span><br><span style="color: hsl(120, 100%, 40%);">+                   return GPRS_NS2_CS_SKIPPED;</span><br><span style="color: hsl(120, 100%, 40%);">+           }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           nse = gprs_ns2_create_nse(bind->nsi, nsei);</span><br><span style="color: hsl(120, 100%, 40%);">+                if (!nse) {</span><br><span style="color: hsl(120, 100%, 40%);">+                   return GPRS_NS_CS_ERROR;</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%);">+   vc = ns2_vc_alloc(bind, nse, false);</span><br><span style="color: hsl(120, 100%, 40%);">+  if (!vc)</span><br><span style="color: hsl(120, 100%, 40%);">+              return GPRS_NS_CS_SKIPPED;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  vc->mode = mode;</span><br><span style="color: hsl(120, 100%, 40%);">+   vc->ll = GPRS_NS_LL_UDP;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ nsvci = tlvp_val16be(&tp, NS_IE_VCI);</span><br><span style="color: hsl(120, 100%, 40%);">+     vc->nsvci = nsvci;</span><br><span style="color: hsl(120, 100%, 40%);">+ vc->nsvci_is_valid = true;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       *success = vc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      return GPRS_NS2_CS_CREATED;</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 gprs_ns2_vc *gprs_ns2_ip_connect_inactive(struct gprs_ns2_vc_bind *bind,</span><br><span style="color: hsl(120, 100%, 40%);">+                                     struct osmo_sockaddr *remote,</span><br><span style="color: hsl(120, 100%, 40%);">+                                 struct gprs_ns2_nse *nse,</span><br><span style="color: hsl(120, 100%, 40%);">+                                     uint16_t nsvci)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    struct gprs_ns2_vc *nsvc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   nsvc = gprs_ns2_ip_bind_connect(bind, nse, remote);</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!nsvc)</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%);">+        if (nsvc->mode == NS2_VC_MODE_BLOCKRESET) {</span><br><span style="color: hsl(120, 100%, 40%);">+                nsvc->nsvci = nsvci;</span><br><span style="color: hsl(120, 100%, 40%);">+               nsvc->nsvci_is_valid = true;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return nsvc;</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%);">+ * \brief gprs_ns2_ip_connect</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param bind</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param remote</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param nse</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param nsvci only required when mode == NS2_VC_MODE_BLOCKRESET</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param mode</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%);">+struct gprs_ns2_vc *gprs_ns2_ip_connect(struct gprs_ns2_vc_bind *bind,</span><br><span style="color: hsl(120, 100%, 40%);">+                                    struct osmo_sockaddr *remote,</span><br><span style="color: hsl(120, 100%, 40%);">+                                 struct gprs_ns2_nse *nse,</span><br><span style="color: hsl(120, 100%, 40%);">+                                     uint16_t nsvci)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    struct gprs_ns2_vc *nsvc;</span><br><span style="color: hsl(120, 100%, 40%);">+     nsvc = gprs_ns2_ip_connect_inactive(bind, remote, nse, nsvci);</span><br><span style="color: hsl(120, 100%, 40%);">+        if (!nsvc)</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%);">+        gprs_ns2_vc_fsm_start(nsvc);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        return nsvc;</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%);">+ * \brief gprs_ns2_ip_connect2</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param bind</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param remote</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param nsei</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param nsvci only required when mode == NS2_VC_MODE_BLOCKRESET</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param mode</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%);">+struct gprs_ns2_vc *gprs_ns2_ip_connect2(struct gprs_ns2_vc_bind *bind,</span><br><span style="color: hsl(120, 100%, 40%);">+                                  struct osmo_sockaddr *remote,</span><br><span style="color: hsl(120, 100%, 40%);">+                                         uint16_t nsei,</span><br><span style="color: hsl(120, 100%, 40%);">+                                        uint16_t nsvci)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   struct gprs_ns2_nse *nse = gprs_ns2_nse_by_nsei(bind->nsi, nsei);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        if (!nse) {</span><br><span style="color: hsl(120, 100%, 40%);">+           nse = gprs_ns2_create_nse(bind->nsi, nsei);</span><br><span style="color: hsl(120, 100%, 40%);">+                if (!nse)</span><br><span style="color: hsl(120, 100%, 40%);">+                     return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return gprs_ns2_ip_connect(bind, remote, nse, nsvci);</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%);">+int gprs_ns2_ip_connect_sns(struct gprs_ns2_vc_bind *bind,</span><br><span style="color: hsl(120, 100%, 40%);">+                            struct osmo_sockaddr *remote,</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%);">+ struct gprs_ns2_nse *nse = gprs_ns2_nse_by_nsei(bind->nsi, nsei);</span><br><span style="color: hsl(120, 100%, 40%);">+  struct gprs_ns2_vc *nsvc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!nse) {</span><br><span style="color: hsl(120, 100%, 40%);">+           nse = gprs_ns2_create_nse(bind->nsi, nsei);</span><br><span style="color: hsl(120, 100%, 40%);">+                if (!nse)</span><br><span style="color: hsl(120, 100%, 40%);">+                     return -1;</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%);">+   nsvc = gprs_ns2_ip_bind_connect(bind, nse, remote);</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!nsvc)</span><br><span style="color: hsl(120, 100%, 40%);">+            return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  ns2_sns_bss_fsm_start(nse, nsvc, remote);</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%);">+/* TODO: vc start */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct gprs_ns2_vc *gprs_ns2_nsvc_by_sockaddr(struct gprs_ns2_nse *nse,</span><br><span style="color: hsl(120, 100%, 40%);">+                                             struct osmo_sockaddr *sockaddr)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      struct gprs_ns2_vc *nsvc;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct osmo_sockaddr *remote;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       OSMO_ASSERT(nse);</span><br><span style="color: hsl(120, 100%, 40%);">+     OSMO_ASSERT(sockaddr);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      llist_for_each_entry(nsvc, &nse->vc, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+           remote = gprs_ns2_ip_vc_sockaddr(nsvc);</span><br><span style="color: hsl(120, 100%, 40%);">+               if (!osmo_sockaddr_cmp(sockaddr, remote))</span><br><span style="color: hsl(120, 100%, 40%);">+                     return nsvc;</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief gprs_ns2_recv_vc entrypoint of received NS PDU from the driver/bind</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param nsi</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param vc</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param msg the received message. Must not be freeded.</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%);">+int ns2_recv_vc(struct gprs_ns2_inst *nsi,</span><br><span style="color: hsl(120, 100%, 40%);">+           struct gprs_ns2_vc *vc,</span><br><span style="color: hsl(120, 100%, 40%);">+               struct msgb *msg)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  struct gprs_ns_hdr *nsh = (struct gprs_ns_hdr *) msg->l2h;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct tlv_parsed tp;</span><br><span style="color: hsl(120, 100%, 40%);">+ int rc = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (msg->len < sizeof(struct gprs_ns_hdr))</span><br><span style="color: hsl(120, 100%, 40%);">+              return -EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     switch (nsh->pdu_type) {</span><br><span style="color: hsl(120, 100%, 40%);">+   case SNS_PDUT_CONFIG:</span><br><span style="color: hsl(120, 100%, 40%);">+         /* TODO */</span><br><span style="color: hsl(120, 100%, 40%);">+//          if (!nsi->bss_sns_fi)</span><br><span style="color: hsl(120, 100%, 40%);">+//                    goto unexpected_sns;</span><br><span style="color: hsl(120, 100%, 40%);">+          /* one additional byte ('end flag') before the TLV part starts */</span><br><span style="color: hsl(120, 100%, 40%);">+             rc = tlv_parse(&tp, &ns_att_tlvdef, nsh->data+1,</span><br><span style="color: hsl(120, 100%, 40%);">+                           msgb_l2len(msg) - sizeof(*nsh)-1, 0, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+              if (rc < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                      LOGPC(DNS, LOGL_NOTICE, "Error during TLV Parse in %s\n", msgb_hexdump(msg));</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%);">+             /* All sub-network service related message types */</span><br><span style="color: hsl(120, 100%, 40%);">+           rc = gprs_ns2_sns_rx(vc, msg, &tp);</span><br><span style="color: hsl(120, 100%, 40%);">+               break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case SNS_PDUT_ACK:</span><br><span style="color: hsl(120, 100%, 40%);">+    case SNS_PDUT_ADD:</span><br><span style="color: hsl(120, 100%, 40%);">+    case SNS_PDUT_CHANGE_WEIGHT:</span><br><span style="color: hsl(120, 100%, 40%);">+  case SNS_PDUT_DELETE:</span><br><span style="color: hsl(120, 100%, 40%);">+         /* TODO */</span><br><span style="color: hsl(120, 100%, 40%);">+//          if (!nsi->bss_sns_fi)</span><br><span style="color: hsl(120, 100%, 40%);">+//                    goto unexpected_sns;</span><br><span style="color: hsl(120, 100%, 40%);">+          /* weird layout: NSEI TLV, then value-only transaction IE, then TLV again */</span><br><span style="color: hsl(120, 100%, 40%);">+          rc = tlv_parse(&tp, &ns_att_tlvdef, nsh->data+5,</span><br><span style="color: hsl(120, 100%, 40%);">+                           msgb_l2len(msg) - sizeof(*nsh)-5, 0, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+              if (rc < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                      LOGPC(DNS, LOGL_NOTICE, "Error during TLV Parse in %s\n", msgb_hexdump(msg));</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%);">+             tp.lv[NS_IE_NSEI].val = nsh->data+2;</span><br><span style="color: hsl(120, 100%, 40%);">+               tp.lv[NS_IE_NSEI].len = 2;</span><br><span style="color: hsl(120, 100%, 40%);">+            tp.lv[NS_IE_TRANS_ID].val = nsh->data+4;</span><br><span style="color: hsl(120, 100%, 40%);">+           tp.lv[NS_IE_TRANS_ID].len = 1;</span><br><span style="color: hsl(120, 100%, 40%);">+                rc = gprs_ns2_sns_rx(vc, msg, &tp);</span><br><span style="color: hsl(120, 100%, 40%);">+               break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case SNS_PDUT_CONFIG_ACK:</span><br><span style="color: hsl(120, 100%, 40%);">+     case SNS_PDUT_SIZE:</span><br><span style="color: hsl(120, 100%, 40%);">+   case SNS_PDUT_SIZE_ACK:</span><br><span style="color: hsl(120, 100%, 40%);">+               /* TODO */</span><br><span style="color: hsl(120, 100%, 40%);">+//          if (!nsi->bss_sns_fi)</span><br><span style="color: hsl(120, 100%, 40%);">+//                    goto unexpected_sns;</span><br><span style="color: hsl(120, 100%, 40%);">+          rc = tlv_parse(&tp, &ns_att_tlvdef, nsh->data,</span><br><span style="color: hsl(120, 100%, 40%);">+                             msgb_l2len(msg) - sizeof(*nsh), 0, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+                if (rc < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                      LOGPC(DNS, LOGL_NOTICE, "Error during TLV Parse in %s\n", msgb_hexdump(msg));</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%);">+             /* All sub-network service related message types */</span><br><span style="color: hsl(120, 100%, 40%);">+           rc = gprs_ns2_sns_rx(vc, msg, &tp);</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%);">+      case NS_PDUT_UNITDATA:</span><br><span style="color: hsl(120, 100%, 40%);">+                rc = gprs_ns2_vc_rx(vc, msg, NULL);</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%);">+              rc = tlv_parse(&tp, &ns_att_tlvdef, nsh->data,</span><br><span style="color: hsl(120, 100%, 40%);">+                            msgb_l2len(msg) - sizeof(*nsh), 0, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+         if (rc < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                      LOGPC(DNS, LOGL_NOTICE, "Error during TLV Parse\n");</span><br><span style="color: hsl(120, 100%, 40%);">+                        if (nsh->pdu_type != NS_PDUT_STATUS)</span><br><span style="color: hsl(120, 100%, 40%);">+                               gprs_ns2_tx_status(vc, NS_CAUSE_PROTO_ERR_UNSPEC, 0, msg);</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%);">+             rc = gprs_ns2_vc_rx(vc, msg, &tp);</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 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%);">+void ns2_nse_notify_unblocked(struct gprs_ns2_vc *nsvc, bool unblocked)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   struct gprs_ns2_nse *nse = nsvc->nse;</span><br><span style="color: hsl(120, 100%, 40%);">+      struct gprs_ns2_vc *tmp;</span><br><span style="color: hsl(120, 100%, 40%);">+      struct gprs_ns2_signal_data nssd = {0};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     if (nse->unblocked == unblocked)</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%);">+     nssd.nse = nse;</span><br><span style="color: hsl(120, 100%, 40%);">+       nssd.nsei = nse->nsei;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* this is the first unblocked NSVC on a unavaiable NSE */</span><br><span style="color: hsl(120, 100%, 40%);">+    if (!nse->unblocked) {</span><br><span style="color: hsl(120, 100%, 40%);">+             nse->unblocked = true;</span><br><span style="color: hsl(120, 100%, 40%);">+             osmo_signal_dispatch(SS_L_NS, S_NSE_AVAILABLE, &nssd);</span><br><span style="color: hsl(120, 100%, 40%);">+            return;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* check if there are any remaining alive vcs */</span><br><span style="color: hsl(120, 100%, 40%);">+      llist_for_each_entry(tmp, &nse->vc, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+            if (gprs_ns2_vc_is_unblocked(tmp)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                  return;</span><br><span style="color: hsl(120, 100%, 40%);">+               }</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* nse became unavailable */</span><br><span style="color: hsl(120, 100%, 40%);">+  nse->unblocked = false;</span><br><span style="color: hsl(120, 100%, 40%);">+    osmo_signal_dispatch(SS_L_NS, S_NSE_UNAVAILABLE, &nssd);</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%);">+/* TODO: remove this global, why the hell do I use it */</span><br><span style="color: hsl(120, 100%, 40%);">+static bool gprs_fsm_vc_registered = false;</span><br><span style="color: hsl(120, 100%, 40%);">+static bool gprs_fsm_sns_registered = false;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! Create a new GPRS NS instance</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] cb Call-back function for incoming BSSGP data</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \returns dynamically allocated gprs_ns_inst</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+struct gprs_ns2_inst *gprs_ns2_instantiate(gprs_ns2_cb_t *cb, void *ctx)</span><br><span style="color: hsl(120, 100%, 40%);">+{</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%);">+  if (!gprs_fsm_vc_registered) {</span><br><span style="color: hsl(120, 100%, 40%);">+                if (gprs_ns2_vc_fsm_init() < 0)</span><br><span style="color: hsl(120, 100%, 40%);">+                    return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+          gprs_fsm_vc_registered = true;</span><br><span style="color: hsl(120, 100%, 40%);">+        }</span><br><span style="color: hsl(120, 100%, 40%);">+     if (!gprs_fsm_sns_registered) {</span><br><span style="color: hsl(120, 100%, 40%);">+               if (gprs_ns2_sns_init() < 0)</span><br><span style="color: hsl(120, 100%, 40%);">+                       return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+          gprs_fsm_sns_registered = true;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   nsi = talloc_zero(ctx, struct gprs_ns2_inst);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!nsi)</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%);">+        nsi->cb = cb;</span><br><span style="color: hsl(120, 100%, 40%);">+      INIT_LLIST_HEAD(&nsi->binding);</span><br><span style="color: hsl(120, 100%, 40%);">+        INIT_LLIST_HEAD(&nsi->nse);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  nsi->timeout[NS_TOUT_TNS_BLOCK] = 3;</span><br><span style="color: hsl(120, 100%, 40%);">+       nsi->timeout[NS_TOUT_TNS_BLOCK_RETRIES] = 3;</span><br><span style="color: hsl(120, 100%, 40%);">+       nsi->timeout[NS_TOUT_TNS_RESET] = 3;</span><br><span style="color: hsl(120, 100%, 40%);">+       nsi->timeout[NS_TOUT_TNS_RESET_RETRIES] = 3;</span><br><span style="color: hsl(120, 100%, 40%);">+       nsi->timeout[NS_TOUT_TNS_TEST] = 30;</span><br><span style="color: hsl(120, 100%, 40%);">+       nsi->timeout[NS_TOUT_TNS_ALIVE] = 3;</span><br><span style="color: hsl(120, 100%, 40%);">+       nsi->timeout[NS_TOUT_TNS_ALIVE_RETRIES] = 10;</span><br><span style="color: hsl(120, 100%, 40%);">+      nsi->timeout[NS_TOUT_TSNS_PROV] = 3; /* 1..10 */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ return nsi;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void gprs_ns2_free(struct gprs_ns2_inst *nsi)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    struct gprs_ns2_vc_bind *bind, *tbind;</span><br><span style="color: hsl(120, 100%, 40%);">+        struct gprs_ns2_nse *nse, *ntmp;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    if (!nsi)</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%);">+     llist_for_each_entry_safe(nse, ntmp, &nsi->nse, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+                gprs_ns2_free_nse(nse);</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   llist_for_each_entry_safe(bind, tbind, &nsi->binding, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+          gprs_ns2_free_bind(bind);</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%);">+ * \brief gprs_ns2_dynamic_create_nse</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param nsi the instance to modify</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param create_nse if NSE can be created on receiving package. SGSN set this.</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%);">+int gprs_ns2_dynamic_create_nse(struct gprs_ns2_inst *nsi, bool create_nse)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    nsi->create_nse = create_nse;</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%);">+void gprs_ns2_start_alive_all_nsvcs(struct gprs_ns2_nse *nse)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      struct gprs_ns2_vc *nsvc;</span><br><span style="color: hsl(120, 100%, 40%);">+     OSMO_ASSERT(nse);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   llist_for_each_entry(nsvc, &nse->vc, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+           if (nsvc->sns_only)</span><br><span style="color: hsl(120, 100%, 40%);">+                        continue;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           gprs_ns2_vc_fsm_start(nsvc);</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%);">+void gprs_ns2_bind_set_mode(struct gprs_ns2_vc_bind *bind, enum gprs_ns2_vc_mode mode)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     bind->use_reset_block_unblock = mode == NS2_VC_MODE_BLOCKRESET ? true : false;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void gprs_ns2_free_bind(struct gprs_ns2_vc_bind *bind)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     struct gprs_ns2_vc *nsvc, *tmp;</span><br><span style="color: hsl(120, 100%, 40%);">+       if (!bind)</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%);">+     llist_for_each_entry_safe(nsvc, tmp, &bind->vc, blist) {</span><br><span style="color: hsl(120, 100%, 40%);">+               gprs_ns2_free_nsvc(nsvc);</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 (bind->driver->free_bind)</span><br><span style="color: hsl(120, 100%, 40%);">+            bind->driver->free_bind(bind);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        llist_del(&bind->list);</span><br><span style="color: hsl(120, 100%, 40%);">+        talloc_free(bind);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+/*! @} */</span><br><span>diff --git a/src/gb/gprs_ns2_driver.c b/src/gb/gprs_ns2_driver.c</span><br><span>new file mode 100644</span><br><span>index 0000000..e576550</span><br><span>--- /dev/null</span><br><span>+++ b/src/gb/gprs_ns2_driver.c</span><br><span>@@ -0,0 +1,372 @@</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <errno.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/sockaddr_str.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/socket.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%);">+#include "common_vty.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "gprs_ns2_internal.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "gprs_ns2_driver.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "gprs_ns2_vc_fsm.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%);">+static void free_bind(struct gprs_ns2_vc_bind *bind);</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 gprs_ns2_vc_driver vc_driver_ip = {</span><br><span style="color: hsl(120, 100%, 40%);">+      .name = "GB UDP IPv4/IPv6",</span><br><span style="color: hsl(120, 100%, 40%);">+ .free_bind = free_bind,</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 priv_bind {</span><br><span style="color: hsl(120, 100%, 40%);">+     struct osmo_fd fd;</span><br><span style="color: hsl(120, 100%, 40%);">+    struct osmo_sockaddr addr;</span><br><span style="color: hsl(120, 100%, 40%);">+    int dscp;</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 priv_vc {</span><br><span style="color: hsl(120, 100%, 40%);">+     struct osmo_sockaddr remote;</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%);">+/*! clean up all private driver state. Should be only called by gprs_ns2_free_bind() */</span><br><span style="color: hsl(120, 100%, 40%);">+static void free_bind(struct gprs_ns2_vc_bind *bind)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  struct priv_bind *priv;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     if (!bind)</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%);">+     priv = bind->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       OSMO_ASSERT(llist_empty(&bind->vc));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_fd_close(&priv->fd);</span><br><span style="color: hsl(120, 100%, 40%);">+      talloc_free(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 free_vc(struct gprs_ns2_vc *vc)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       OSMO_ASSERT(vc);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    if (!vc->priv)</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%);">+     talloc_free(vc->priv);</span><br><span style="color: hsl(120, 100%, 40%);">+     vc->priv = 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%);">+int gprs_ns2_find_vc_by_sockaddr(struct gprs_ns2_vc_bind *bind, struct osmo_sockaddr *saddr, struct gprs_ns2_vc **result)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        struct gprs_ns2_vc *vc1;</span><br><span style="color: hsl(120, 100%, 40%);">+      struct priv_vc *vcpriv;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     if (!result)</span><br><span style="color: hsl(120, 100%, 40%);">+          return -EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     llist_for_each_entry(vc1, &bind->vc, blist) {</span><br><span style="color: hsl(120, 100%, 40%);">+          vcpriv = vc1->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+                if (vcpriv->remote.u.sa.sa_family != saddr->u.sa.sa_family)</span><br><span style="color: hsl(120, 100%, 40%);">+                     continue;</span><br><span style="color: hsl(120, 100%, 40%);">+             if (osmo_sockaddr_cmp(&vcpriv->remote, saddr))</span><br><span style="color: hsl(120, 100%, 40%);">+                 continue;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           *result = vc1;</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%);">+   return 1;</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 inline int nsip_sendmsg(struct gprs_ns2_vc_bind *bind,</span><br><span style="color: hsl(120, 100%, 40%);">+                        struct msgb *msg,</span><br><span style="color: hsl(120, 100%, 40%);">+                             struct osmo_sockaddr *dest)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+       struct priv_bind *priv = bind->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     rc = sendto(priv->fd.fd, msg->data, msg->len, 0,</span><br><span style="color: hsl(120, 100%, 40%);">+                 &dest->u.sa, sizeof(*dest));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     msgb_free(msg);</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%);">+/*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief nsip_vc_sendmsg will send the msg and free msgb afterwards.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param vc</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param msg</span><br><span style="color: hsl(120, 100%, 40%);">+ * \return < 0 on erros, otherwise the bytes sent.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+static int nsip_vc_sendmsg(struct gprs_ns2_vc *vc, struct msgb *msg)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+       struct gprs_ns2_vc_bind *bind = vc->bind;</span><br><span style="color: hsl(120, 100%, 40%);">+  struct priv_vc *priv = vc->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ rc = nsip_sendmsg(bind, msg, &priv->remote);</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%);">+/* Read a single NS-over-IP message */</span><br><span style="color: hsl(120, 100%, 40%);">+static struct msgb *read_nsip_msg(struct osmo_fd *bfd, int *error,</span><br><span style="color: hsl(120, 100%, 40%);">+                             struct osmo_sockaddr *saddr)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     struct msgb *msg = gprs_ns2_msgb_alloc();</span><br><span style="color: hsl(120, 100%, 40%);">+     int ret = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+  socklen_t saddr_len = sizeof(*saddr);</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%);">+           *error = -ENOMEM;</span><br><span style="color: hsl(120, 100%, 40%);">+             return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   ret = recvfrom(bfd->fd, msg->data, NS_ALLOC_SIZE - NS_ALLOC_HEADROOM, 0,</span><br><span style="color: hsl(120, 100%, 40%);">+                        &saddr->u.sa, &saddr_len);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (ret < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+             LOGP(DNS, LOGL_ERROR, "recv error %s during NSIP recvfrom %s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                 strerror(errno), osmo_sock_get_name2(bfd->fd));</span><br><span style="color: hsl(120, 100%, 40%);">+               msgb_free(msg);</span><br><span style="color: hsl(120, 100%, 40%);">+               *error = ret;</span><br><span style="color: hsl(120, 100%, 40%);">+         return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  } else if (ret == 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                msgb_free(msg);</span><br><span style="color: hsl(120, 100%, 40%);">+               *error = ret;</span><br><span style="color: hsl(120, 100%, 40%);">+         return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   msg->l2h = msg->data;</span><br><span style="color: hsl(120, 100%, 40%);">+   msgb_put(msg, ret);</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%);">+static struct priv_vc *ns2_driver_alloc_vc(struct gprs_ns2_vc_bind *bind, struct gprs_ns2_vc *vc, struct osmo_sockaddr *remote)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  struct priv_vc *priv = talloc_zero(bind, struct priv_vc);</span><br><span style="color: hsl(120, 100%, 40%);">+     if (!priv)</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%);">+        vc->priv = priv;</span><br><span style="color: hsl(120, 100%, 40%);">+   priv->remote = *remote;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  return 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 handle_nsip_read(struct osmo_fd *bfd)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+       int error = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+        struct gprs_ns2_vc_bind *bind = bfd->data;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_sockaddr saddr;</span><br><span style="color: hsl(120, 100%, 40%);">+   struct gprs_ns2_vc *vc;</span><br><span style="color: hsl(120, 100%, 40%);">+       struct msgb *msg = read_nsip_msg(bfd, &error, &saddr);</span><br><span style="color: hsl(120, 100%, 40%);">+        struct msgb *reject;</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 -EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     /* check if a vc is available */</span><br><span style="color: hsl(120, 100%, 40%);">+      rc = gprs_ns2_find_vc_by_sockaddr(bind, &saddr, &vc);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (rc) {</span><br><span style="color: hsl(120, 100%, 40%);">+             /* VC not found */</span><br><span style="color: hsl(120, 100%, 40%);">+            rc = ns2_create_vc(bind, msg, "newconnection", true, &reject, &vc);</span><br><span style="color: hsl(120, 100%, 40%);">+         switch (rc) {</span><br><span style="color: hsl(120, 100%, 40%);">+         case GPRS_NS2_CS_FOUND:</span><br><span style="color: hsl(120, 100%, 40%);">+                       rc = ns2_recv_vc(bind->nsi, vc, msg);</span><br><span style="color: hsl(120, 100%, 40%);">+                      break;</span><br><span style="color: hsl(120, 100%, 40%);">+                case GPRS_NS2_CS_ERROR:</span><br><span style="color: hsl(120, 100%, 40%);">+               case GPRS_NS2_CS_SKIPPED:</span><br><span style="color: hsl(120, 100%, 40%);">+                     rc = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+                       break;</span><br><span style="color: hsl(120, 100%, 40%);">+                case GPRS_NS2_CS_REJECTED:</span><br><span style="color: hsl(120, 100%, 40%);">+                    /* nsip_sendmsg will free reject */</span><br><span style="color: hsl(120, 100%, 40%);">+                   nsip_sendmsg(bind, reject, &saddr);</span><br><span style="color: hsl(120, 100%, 40%);">+                       return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+             case GPRS_NS2_CS_CREATED:</span><br><span style="color: hsl(120, 100%, 40%);">+                     /* TODO: check if we need to call recv_vc(). It might be already enough to be parsed by create_vc() */</span><br><span style="color: hsl(120, 100%, 40%);">+                        ns2_driver_alloc_vc(bind, vc, &saddr);</span><br><span style="color: hsl(120, 100%, 40%);">+                    gprs_ns2_vc_fsm_start(vc);</span><br><span style="color: hsl(120, 100%, 40%);">+                    rc = ns2_recv_vc(bind->nsi, vc, msg);</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%);">+     } else {</span><br><span style="color: hsl(120, 100%, 40%);">+              /* VC found */</span><br><span style="color: hsl(120, 100%, 40%);">+                rc = ns2_recv_vc(bind->nsi, vc, 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%);">+   msgb_free(msg);</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%);">+static int handle_nsip_write(struct osmo_fd *bfd)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ /* FIXME: actually send the data here instead of nsip_sendmsg() */</span><br><span style="color: hsl(120, 100%, 40%);">+    return -EIO;</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 nsip_fd_cb(struct osmo_fd *bfd, unsigned int what)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   int rc = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (what & OSMO_FD_READ)</span><br><span style="color: hsl(120, 100%, 40%);">+          rc = handle_nsip_read(bfd);</span><br><span style="color: hsl(120, 100%, 40%);">+   if (what & OSMO_FD_WRITE)</span><br><span style="color: hsl(120, 100%, 40%);">+         rc = handle_nsip_write(bfd);</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%);">+/*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief bind to an IPv4/IPv6 address</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[in] nsi NS Instance in which to create the NSVC</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[in] address the address to bind to</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[out] result if set, returns the bind object</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%);">+int gprs_ns2_ip_bind(struct gprs_ns2_inst *nsi,</span><br><span style="color: hsl(120, 100%, 40%);">+                     struct osmo_sockaddr *local,</span><br><span style="color: hsl(120, 100%, 40%);">+                  int dscp,</span><br><span style="color: hsl(120, 100%, 40%);">+                     struct gprs_ns2_vc_bind **result)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     struct gprs_ns2_vc_bind *bind = talloc_zero(nsi, struct gprs_ns2_vc_bind);</span><br><span style="color: hsl(120, 100%, 40%);">+    struct priv_bind *priv;</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 (!bind)</span><br><span style="color: hsl(120, 100%, 40%);">+            return -ENOSPC;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     if (local->u.sa.sa_family != AF_INET && local->u.sa.sa_family != AF_INET6) {</span><br><span style="color: hsl(120, 100%, 40%);">+            talloc_free(bind);</span><br><span style="color: hsl(120, 100%, 40%);">+            return -EINVAL;</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%);">+   bind->driver = &vc_driver_ip;</span><br><span style="color: hsl(120, 100%, 40%);">+  bind->send_vc = nsip_vc_sendmsg;</span><br><span style="color: hsl(120, 100%, 40%);">+   bind->free_vc = free_vc;</span><br><span style="color: hsl(120, 100%, 40%);">+   bind->nsi = nsi;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ priv = bind->priv = talloc_zero(bind, struct priv_bind);</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!priv) {</span><br><span style="color: hsl(120, 100%, 40%);">+          talloc_free(bind);</span><br><span style="color: hsl(120, 100%, 40%);">+            return -ENOSPC;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+     priv->fd.cb = nsip_fd_cb;</span><br><span style="color: hsl(120, 100%, 40%);">+  priv->fd.data = bind;</span><br><span style="color: hsl(120, 100%, 40%);">+      priv->addr = *local;</span><br><span style="color: hsl(120, 100%, 40%);">+       INIT_LLIST_HEAD(&bind->vc);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  llist_add(&bind->list, &nsi->binding);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        rc = osmo_sock_init3_ofd(&priv->fd, SOCK_DGRAM, IPPROTO_UDP,</span><br><span style="color: hsl(120, 100%, 40%);">+                            local, NULL,</span><br><span style="color: hsl(120, 100%, 40%);">+                          OSMO_SOCK_F_BIND);</span><br><span style="color: hsl(120, 100%, 40%);">+   if (rc < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+              talloc_free(priv);</span><br><span style="color: hsl(120, 100%, 40%);">+            talloc_free(bind);</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%);">+   if (dscp > 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+            priv->dscp = dscp;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+               rc = setsockopt(priv->fd.fd, IPPROTO_IP, IP_TOS,</span><br><span style="color: hsl(120, 100%, 40%);">+                           &dscp, sizeof(dscp));</span><br><span style="color: hsl(120, 100%, 40%);">+             if (rc < 0)</span><br><span style="color: hsl(120, 100%, 40%);">+                        LOGP(DNS, LOGL_ERROR,</span><br><span style="color: hsl(120, 100%, 40%);">+                         "Failed to set the DSCP to %d with ret(%d) errno(%d)\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                            dscp, rc, errno);</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%);">+   ns2_vty_bind_apply(bind);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (result)</span><br><span style="color: hsl(120, 100%, 40%);">+           *result = bind;</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%);">+struct gprs_ns2_vc *gprs_ns2_ip_bind_connect(struct gprs_ns2_vc_bind *bind,</span><br><span style="color: hsl(120, 100%, 40%);">+                                        struct gprs_ns2_nse *nse,</span><br><span style="color: hsl(120, 100%, 40%);">+                                             struct osmo_sockaddr *remote)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct gprs_ns2_vc *nsvc;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct priv_vc *priv;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       OSMO_ASSERT(bind);</span><br><span style="color: hsl(120, 100%, 40%);">+    OSMO_ASSERT(nse);</span><br><span style="color: hsl(120, 100%, 40%);">+     OSMO_ASSERT(remote);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        nsvc = ns2_vc_alloc(bind, nse, true);</span><br><span style="color: hsl(120, 100%, 40%);">+ nsvc->priv = talloc_zero(bind, struct priv_vc);</span><br><span style="color: hsl(120, 100%, 40%);">+    if (!nsvc->priv) {</span><br><span style="color: hsl(120, 100%, 40%);">+         gprs_ns2_free_nsvc(nsvc);</span><br><span style="color: hsl(120, 100%, 40%);">+             return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   priv = nsvc->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+ priv->remote = *remote;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  nsvc->ll = GPRS_NS_LL_UDP;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       return nsvc;</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_sockaddr *gprs_ns2_ip_vc_sockaddr(struct gprs_ns2_vc *nsvc)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct priv_vc *priv;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       if (nsvc->ll != GPRS_NS_LL_UDP)</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%);">+        priv = nsvc->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+ return &priv->remote;</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_sockaddr *gprs_ns2_ip_bind_sockaddr(struct gprs_ns2_vc_bind *bind)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  struct priv_bind *priv;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     OSMO_ASSERT(bind);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  priv = bind->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+ return &priv->addr;</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%);">+int gprs_ns2_is_ip_bind(struct gprs_ns2_vc_bind *bind)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    return (bind->driver == &vc_driver_ip);</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%);">+int gprs_ns2_ip_bind_set_dscp(struct gprs_ns2_vc_bind *bind, int dscp)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        struct priv_bind *priv;</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%);">+     OSMO_ASSERT(bind);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  priv = bind->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       if (dscp != priv->dscp) {</span><br><span style="color: hsl(120, 100%, 40%);">+          priv->dscp = dscp;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+               rc = setsockopt(priv->fd.fd, IPPROTO_IP, IP_TOS,</span><br><span style="color: hsl(120, 100%, 40%);">+                           &dscp, sizeof(dscp));</span><br><span style="color: hsl(120, 100%, 40%);">+             if (rc < 0)</span><br><span style="color: hsl(120, 100%, 40%);">+                        LOGP(DNS, LOGL_ERROR,</span><br><span style="color: hsl(120, 100%, 40%);">+                      "Failed to set the DSCP to %d with ret(%d) errno(%d)\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                            dscp, rc, errno);</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 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%);">+void gprs_ns2_ip_bind_reset_block_unblock(</span><br><span style="color: hsl(120, 100%, 40%);">+           struct gprs_ns2_vc_bind *bind,</span><br><span style="color: hsl(120, 100%, 40%);">+                bool use_reset_block_unblock)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      bind->use_reset_block_unblock = use_reset_block_unblock;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span>diff --git a/src/gb/gprs_ns2_driver.h b/src/gb/gprs_ns2_driver.h</span><br><span>new file mode 100644</span><br><span>index 0000000..339f16b</span><br><span>--- /dev/null</span><br><span>+++ b/src/gb/gprs_ns2_driver.h</span><br><span>@@ -0,0 +1,9 @@</span><br><span style="color: hsl(120, 100%, 40%);">+#pragma once</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <stdbool.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct osmo_sockaddr;</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_ns2_nse;</span><br><span style="color: hsl(120, 100%, 40%);">+struct gprs_ns2_vc_bind;</span><br><span>diff --git a/src/gb/gprs_ns2_internal.h b/src/gb/gprs_ns2_internal.h</span><br><span>new file mode 100644</span><br><span>index 0000000..f226788</span><br><span>--- /dev/null</span><br><span>+++ b/src/gb/gprs_ns2_internal.h</span><br><span>@@ -0,0 +1,199 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/*! \file gprs_ns2_internal.h */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#pragma once</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <stdbool.h></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_16.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/gprs/gprs_ns_common.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_vc_driver;</span><br><span style="color: hsl(120, 100%, 40%);">+struct gprs_ns2_vc_bind;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct tlv_parsed;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! An instance of the NS protocol stack */</span><br><span style="color: hsl(120, 100%, 40%);">+struct gprs_ns2_inst {</span><br><span style="color: hsl(120, 100%, 40%);">+    /*! callback to the user for incoming UNIT DATA IND */</span><br><span style="color: hsl(120, 100%, 40%);">+        gprs_ns2_cb_t *cb;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  /*! linked lists of all NSVC binds (e.g. IPv4 bind, but could be also E1 */</span><br><span style="color: hsl(120, 100%, 40%);">+   struct llist_head binding;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  /*! linked lists of all NSVC in this instance */</span><br><span style="color: hsl(120, 100%, 40%);">+      struct llist_head nse;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      /*! create dynamic NSE on receiving packages */</span><br><span style="color: hsl(120, 100%, 40%);">+       bool create_nse;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    uint16_t timeout[NS_TIMERS_COUNT];</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%);">+/*! Structure repesenting a NSE. The BSS/PCU will only have a single NSE, while SGSN has one for each BSS/PCU */</span><br><span style="color: hsl(120, 100%, 40%);">+struct gprs_ns2_nse {</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%);">+      /*! entry back to ns2_inst */</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%);">+  /*! llist entry for gprs_ns2_inst */</span><br><span style="color: hsl(120, 100%, 40%);">+  struct llist_head list;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     /*! llist head to hold all nsvc */</span><br><span style="color: hsl(120, 100%, 40%);">+    struct llist_head vc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       /*! true if this NS was created by VTY or pcu socket) */</span><br><span style="color: hsl(120, 100%, 40%);">+      bool persistant;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    /*! true if this NS has at an alive VC */</span><br><span style="color: hsl(120, 100%, 40%);">+     bool unblocked;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     struct osmo_fsm_inst *bss_sns_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%);">+/*! Structure representing a single NS-VC */</span><br><span style="color: hsl(120, 100%, 40%);">+struct gprs_ns2_vc {</span><br><span style="color: hsl(120, 100%, 40%);">+   /*! list of NS-VCs within NSE */</span><br><span style="color: hsl(120, 100%, 40%);">+      struct llist_head list;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     /*! list of NS-VCs within bind, bind is the owner! */</span><br><span style="color: hsl(120, 100%, 40%);">+ struct llist_head blist;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    /*! pointer to NS Instance */</span><br><span style="color: hsl(120, 100%, 40%);">+ struct gprs_ns2_nse *nse;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /*! pointer to NS VL bind. bind own the memory of this instance */</span><br><span style="color: hsl(120, 100%, 40%);">+    struct gprs_ns2_vc_bind *bind;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      /*! true if this NS was created by VTY or pcu socket) */</span><br><span style="color: hsl(120, 100%, 40%);">+      bool persistant;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    /*! uniquely identifies NS-VC if VC contains nsvci */</span><br><span style="color: hsl(120, 100%, 40%);">+ uint16_t nsvci;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     /*! signalling weight. 0 = don't use for signalling (BVCI == 0)*/</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t sig_weight;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /*! signaling weight. 0 = don't use for user data (BVCI != 0) */</span><br><span style="color: hsl(120, 100%, 40%);">+  uint8_t data_weight;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        /*! can be used by the bind/driver of the virtual circuit. e.g. ipv4/ipv6/frgre/e1 */</span><br><span style="color: hsl(120, 100%, 40%);">+ void *priv;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ uint32_t state;</span><br><span style="color: hsl(120, 100%, 40%);">+       uint32_t remote_state;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      struct osmo_timer_list timer;</span><br><span style="color: hsl(120, 100%, 40%);">+ enum nsvc_timer_mode timer_mode;</span><br><span style="color: hsl(120, 100%, 40%);">+      struct timeval timer_started;</span><br><span style="color: hsl(120, 100%, 40%);">+ int alive_retries;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  unsigned int remote_end_is_sgsn:1;</span><br><span style="color: hsl(120, 100%, 40%);">+    unsigned int persistent:1;</span><br><span style="color: hsl(120, 100%, 40%);">+    unsigned int nsvci_is_valid:1;</span><br><span style="color: hsl(120, 100%, 40%);">+        unsigned int sns_only:1;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    struct rate_ctr_group *ctrg;</span><br><span style="color: hsl(120, 100%, 40%);">+  struct osmo_stat_item_group *statg;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /*! which link-layer are we based on? */</span><br><span style="color: hsl(120, 100%, 40%);">+      enum gprs_ns_ll ll;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ enum gprs_ns2_vc_mode mode;</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%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! Structure repesenting a bind instance. E.g. IPv4 listen port. */</span><br><span style="color: hsl(120, 100%, 40%);">+struct gprs_ns2_vc_bind {</span><br><span style="color: hsl(120, 100%, 40%);">+      /*! list entry in nsi */</span><br><span style="color: hsl(120, 100%, 40%);">+      struct llist_head list;</span><br><span style="color: hsl(120, 100%, 40%);">+       /*! list of all VC */</span><br><span style="color: hsl(120, 100%, 40%);">+ struct llist_head vc;</span><br><span style="color: hsl(120, 100%, 40%);">+ /*! driver private structure */</span><br><span style="color: hsl(120, 100%, 40%);">+       void *priv;</span><br><span style="color: hsl(120, 100%, 40%);">+   /*! a pointer back to the nsi */</span><br><span style="color: hsl(120, 100%, 40%);">+      struct gprs_ns2_inst *nsi;</span><br><span style="color: hsl(120, 100%, 40%);">+    struct gprs_ns2_vc_driver *driver;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  /*! if VCs use reset/block/unblock method. IP shall not use this */</span><br><span style="color: hsl(120, 100%, 40%);">+   bool use_reset_block_unblock;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       /*! send a msg over a VC */</span><br><span style="color: hsl(120, 100%, 40%);">+   int (*send_vc)(struct gprs_ns2_vc *vc, struct msgb *msg);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /*! free the vc priv data */</span><br><span style="color: hsl(120, 100%, 40%);">+  void (*free_vc)(struct gprs_ns2_vc *vc);</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%);">+/*! Osmocom NS VC create status */</span><br><span style="color: hsl(120, 100%, 40%);">+enum gprs_ns2_cs {</span><br><span style="color: hsl(120, 100%, 40%);">+        GPRS_NS2_CS_CREATED,     /*!< A NSVC object has been created */</span><br><span style="color: hsl(120, 100%, 40%);">+    GPRS_NS2_CS_FOUND,       /*!< A NSVC object has been found */</span><br><span style="color: hsl(120, 100%, 40%);">+      GPRS_NS2_CS_REJECTED,    /*!< Rejected and answered message */</span><br><span style="color: hsl(120, 100%, 40%);">+     GPRS_NS2_CS_SKIPPED,     /*!< Skipped message */</span><br><span style="color: hsl(120, 100%, 40%);">+   GPRS_NS2_CS_ERROR,       /*!< Failed to process message */</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 gprs_ns2_vc_driver {</span><br><span style="color: hsl(120, 100%, 40%);">+      const char *name;</span><br><span style="color: hsl(120, 100%, 40%);">+     void *priv;</span><br><span style="color: hsl(120, 100%, 40%);">+   void (*free_bind)(struct gprs_ns2_vc_bind *driver);</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%);">+int ns2_create_vc(struct gprs_ns2_vc_bind *bind,</span><br><span style="color: hsl(120, 100%, 40%);">+             struct msgb *msg,</span><br><span style="color: hsl(120, 100%, 40%);">+             const char *logname,</span><br><span style="color: hsl(120, 100%, 40%);">+                  enum gprs_ns2_vc_mode mode,</span><br><span style="color: hsl(120, 100%, 40%);">+           struct msgb **reject,</span><br><span style="color: hsl(120, 100%, 40%);">+                 struct gprs_ns2_vc **success);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int ns2_recv_vc(struct gprs_ns2_inst *nsi,</span><br><span style="color: hsl(120, 100%, 40%);">+                struct gprs_ns2_vc *vc,</span><br><span style="color: hsl(120, 100%, 40%);">+               struct msgb *msg);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct gprs_ns2_vc *ns2_vc_alloc(struct gprs_ns2_vc_bind *bind,</span><br><span style="color: hsl(120, 100%, 40%);">+                          struct gprs_ns2_nse *nse,</span><br><span style="color: hsl(120, 100%, 40%);">+                             bool initiater);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct msgb *gprs_ns2_msgb_alloc(void);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static inline int ns2_is_sns(uint8_t pdu_type)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     return pdu_type >= SNS_PDUT_ACK && pdu_type <= SNS_PDUT_SIZE_ACK;</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 inline int ns2_is_ns(uint8_t pdu_type)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        return pdu_type < SNS_PDUT_ACK || pdu_type > SNS_PDUT_SIZE_ACK;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void gprs_ns2_dump_vty(struct vty *vty, const struct gprs_ns2_nse *nse, bool stats);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void ns2_nse_notify_alive(struct gprs_ns2_vc *vc, bool alive);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* driver */</span><br><span style="color: hsl(120, 100%, 40%);">+struct gprs_ns2_vc *gprs_ns2_ip_bind_connect(struct gprs_ns2_vc_bind *bind,</span><br><span style="color: hsl(120, 100%, 40%);">+                                            struct gprs_ns2_nse *nse,</span><br><span style="color: hsl(120, 100%, 40%);">+                                             struct osmo_sockaddr *remote);</span><br><span style="color: hsl(120, 100%, 40%);">+void gprs_ns2_ip_bind_reset_block_unblock(</span><br><span style="color: hsl(120, 100%, 40%);">+               struct gprs_ns2_vc_bind *bind,</span><br><span style="color: hsl(120, 100%, 40%);">+                bool use_reset_block_unblock);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* sns */</span><br><span style="color: hsl(120, 100%, 40%);">+int gprs_ns2_sns_rx(struct gprs_ns2_vc *vc, struct msgb *msg, struct tlv_parsed *tp);</span><br><span style="color: hsl(120, 100%, 40%);">+int gprs_ns2_sns_init(void);</span><br><span style="color: hsl(120, 100%, 40%);">+struct osmo_fsm_inst *ns2_sns_bss_fsm_alloc(struct gprs_ns2_nse *nse,</span><br><span style="color: hsl(120, 100%, 40%);">+                                            const char *id);</span><br><span style="color: hsl(120, 100%, 40%);">+int ns2_sns_bss_fsm_start(struct gprs_ns2_nse *nse, struct gprs_ns2_vc *nsvc,</span><br><span style="color: hsl(120, 100%, 40%);">+                    struct osmo_sockaddr *remote);</span><br><span style="color: hsl(120, 100%, 40%);">+void ns2_sns_free_nsvc(struct gprs_ns2_vc *nsvc);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* vty.c */</span><br><span style="color: hsl(120, 100%, 40%);">+void ns2_vty_bind_apply(struct gprs_ns2_vc_bind *bind);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* nse */</span><br><span style="color: hsl(120, 100%, 40%);">+void ns2_nse_notify_unblocked(struct gprs_ns2_vc *nsvc, bool unblocked);</span><br><span>diff --git a/src/gb/gprs_ns2_sns.c b/src/gb/gprs_ns2_sns.c</span><br><span>new file mode 100644</span><br><span>index 0000000..8bae68f</span><br><span>--- /dev/null</span><br><span>+++ b/src/gb/gprs_ns2_sns.c</span><br><span>@@ -0,0 +1,924 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/* Implementation of 3GPP TS 48.016 NS IP Sub-Network Service */</span><br><span style="color: hsl(120, 100%, 40%);">+/* (C) 2018 by Harald Welte <laforge@gnumonks.org> */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* The BSS NSE only has one SGSN IP address configured, and it will use the SNS procedures</span><br><span style="color: hsl(120, 100%, 40%);">+ * to communicated its local IPs/ports as well as all the SGSN side IPs/ports and</span><br><span style="color: hsl(120, 100%, 40%);">+ * associated weights.  In theory, the BSS then uses this to establish a full mesh</span><br><span style="color: hsl(120, 100%, 40%);">+ * of NSVCs between all BSS-side IPs/ports and SGSN-side IPs/ports */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <errno.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <netinet/in.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <arpa/inet.h></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/core/fsm.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/msgb.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/signal.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/socket.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/gsm/tlv.h></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/protocol/gsm_08_16.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%);">+#include "gprs_ns2_internal.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "gprs_ns2_vc_fsm.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%);">+struct ns2_sns_state {</span><br><span style="color: hsl(120, 100%, 40%);">+    struct gprs_ns2_nse *nse;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* initial connection. the initial connection will be terminated</span><br><span style="color: hsl(120, 100%, 40%);">+       * in configured state or moved into NSE if valid */</span><br><span style="color: hsl(120, 100%, 40%);">+  struct osmo_sockaddr initial;</span><br><span style="color: hsl(120, 100%, 40%);">+ /* all SNS PDU will be sent over this nsvc */</span><br><span style="color: hsl(120, 100%, 40%);">+ struct gprs_ns2_vc *sns_nsvc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       /* local configuration to send to the remote end */</span><br><span style="color: hsl(120, 100%, 40%);">+   struct gprs_ns_ie_ip4_elem *ip4_local;</span><br><span style="color: hsl(120, 100%, 40%);">+        size_t num_ip4_local;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       /* local configuration to send to the remote end */</span><br><span style="color: hsl(120, 100%, 40%);">+   struct gprs_ns_ie_ip6_elem *ip6_local;</span><br><span style="color: hsl(120, 100%, 40%);">+        size_t num_ip6_local;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       /* local configuration about our capabilities in terms of connections to</span><br><span style="color: hsl(120, 100%, 40%);">+       * remote (SGSN) side */</span><br><span style="color: hsl(120, 100%, 40%);">+      size_t num_max_nsvcs;</span><br><span style="color: hsl(120, 100%, 40%);">+ size_t num_max_ip4_remote;</span><br><span style="color: hsl(120, 100%, 40%);">+    size_t num_max_ip6_remote;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  /* remote configuration as received */</span><br><span style="color: hsl(120, 100%, 40%);">+        struct gprs_ns_ie_ip4_elem *ip4_remote;</span><br><span style="color: hsl(120, 100%, 40%);">+       unsigned int num_ip4_remote;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        /* remote configuration as received */</span><br><span style="color: hsl(120, 100%, 40%);">+        struct gprs_ns_ie_ip6_elem *ip6_remote;</span><br><span style="color: hsl(120, 100%, 40%);">+       unsigned int num_ip6_remote;</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 inline struct gprs_ns2_nse *nse_inst_from_fi(struct osmo_fsm_inst *fi)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+     return gss->nse;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* helper function to compute the sum of all (data or signaling) weights */</span><br><span style="color: hsl(120, 100%, 40%);">+static int ip4_weight_sum(const struct gprs_ns_ie_ip4_elem *ip4, unsigned int num,</span><br><span style="color: hsl(120, 100%, 40%);">+                       bool data_weight)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        unsigned int i;</span><br><span style="color: hsl(120, 100%, 40%);">+       int weight_sum = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ for (i = 0; i < num; i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+                if (data_weight)</span><br><span style="color: hsl(120, 100%, 40%);">+                      weight_sum += ip4[i].data_weight;</span><br><span style="color: hsl(120, 100%, 40%);">+             else</span><br><span style="color: hsl(120, 100%, 40%);">+                  weight_sum += ip4[i].sig_weight;</span><br><span style="color: hsl(120, 100%, 40%);">+      }</span><br><span style="color: hsl(120, 100%, 40%);">+     return weight_sum;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+#define ip4_weight_sum_data(x,y) ip4_weight_sum(x, y, true)</span><br><span style="color: hsl(120, 100%, 40%);">+#define ip4_weight_sum_sig(x,y)             ip4_weight_sum(x, y, false)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static struct gprs_ns2_vc *nsvc_by_ip4_elem(struct gprs_ns2_nse *nse,</span><br><span style="color: hsl(120, 100%, 40%);">+                                      const struct gprs_ns_ie_ip4_elem *ip4)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_sockaddr sa;</span><br><span style="color: hsl(120, 100%, 40%);">+      /* copy over. Both data structures use network byte order */</span><br><span style="color: hsl(120, 100%, 40%);">+  sa.u.sin.sin_addr.s_addr = ip4->ip_addr;</span><br><span style="color: hsl(120, 100%, 40%);">+   sa.u.sin.sin_port = ip4->udp_port;</span><br><span style="color: hsl(120, 100%, 40%);">+ sa.u.sin.sin_family = AF_INET;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      return gprs_ns2_nsvc_by_sockaddr(nse, &sa);</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%);">+/*! called when a nsvc is beeing freed */</span><br><span style="color: hsl(120, 100%, 40%);">+void ns2_sns_free_nsvc(struct gprs_ns2_vc *nsvc)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  struct gprs_ns2_nse *nse;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct gprs_ns2_vc *tmp;</span><br><span style="color: hsl(120, 100%, 40%);">+      struct ns2_sns_state *gss = (struct ns2_sns_state *) nsvc->nse->bss_sns_fi->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  if (nsvc != gss->sns_nsvc)</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 (nsvc->nse->unblocked) {</span><br><span style="color: hsl(120, 100%, 40%);">+             /* choose a different signal nsvc */</span><br><span style="color: hsl(120, 100%, 40%);">+          llist_for_each_entry(tmp, &nse->vc, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+                    if (gprs_ns2_vc_is_unblocked(tmp))</span><br><span style="color: hsl(120, 100%, 40%);">+                            gss->sns_nsvc = tmp;</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%);">+   gss->sns_nsvc = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+      /* TODO: state change */</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 ns2_nsvc_create_ip4(struct osmo_fsm_inst *fi,</span><br><span style="color: hsl(120, 100%, 40%);">+                               struct gprs_ns2_nse *nse,</span><br><span style="color: hsl(120, 100%, 40%);">+                             const struct gprs_ns_ie_ip4_elem *ip4)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    struct ns2_sns_state *gss = (struct ns2_sns_state *) nse->bss_sns_fi->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct gprs_ns2_inst *nsi = nse->nsi;</span><br><span style="color: hsl(120, 100%, 40%);">+      struct gprs_ns2_vc *nsvc;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct gprs_ns2_vc_bind *bind;</span><br><span style="color: hsl(120, 100%, 40%);">+        struct osmo_sockaddr remote;</span><br><span style="color: hsl(120, 100%, 40%);">+  /* copy over. Both data structures use network byte order */</span><br><span style="color: hsl(120, 100%, 40%);">+  remote.u.sin.sin_family = AF_INET;</span><br><span style="color: hsl(120, 100%, 40%);">+    remote.u.sin.sin_addr.s_addr = ip4->ip_addr;</span><br><span style="color: hsl(120, 100%, 40%);">+       remote.u.sin.sin_port = ip4->udp_port;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* for every bind, create a connection if bind type == IP */</span><br><span style="color: hsl(120, 100%, 40%);">+  llist_for_each_entry(bind, &nsi->binding, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+              /* ignore failed connection */</span><br><span style="color: hsl(120, 100%, 40%);">+                nsvc = gprs_ns2_ip_connect_inactive(bind,</span><br><span style="color: hsl(120, 100%, 40%);">+                                        &remote,</span><br><span style="color: hsl(120, 100%, 40%);">+                                          nse, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+           if (!nsvc) {</span><br><span style="color: hsl(120, 100%, 40%);">+                  LOGPFSML(fi, LOGL_ERROR, "SNS-CONFIG: Failed to create NSVC\n");</span><br><span style="color: hsl(120, 100%, 40%);">+                    continue;</span><br><span style="color: hsl(120, 100%, 40%);">+             }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           nsvc->sig_weight = ip4->sig_weight;</span><br><span style="color: hsl(120, 100%, 40%);">+             nsvc->data_weight = ip4->data_weight;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+         /* TODO: check if we have to start the VC FSM here */</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 create_missing_nsvcs(struct osmo_fsm_inst *fi)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);</span><br><span style="color: hsl(120, 100%, 40%);">+      struct gprs_ns2_vc *nsvc;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct gprs_ns2_vc_bind *bind;</span><br><span style="color: hsl(120, 100%, 40%);">+        struct osmo_sockaddr *tmpaddr, remote;</span><br><span style="color: hsl(120, 100%, 40%);">+        unsigned int i;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     for (i = 0; i < gss->num_ip4_remote; i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+             const struct gprs_ns_ie_ip4_elem *ip4 = &gss->ip4_remote[i];</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+         remote.u.sin.sin_family = AF_INET;</span><br><span style="color: hsl(120, 100%, 40%);">+            remote.u.sin.sin_addr.s_addr = ip4->ip_addr;</span><br><span style="color: hsl(120, 100%, 40%);">+               remote.u.sin.sin_port = ip4->udp_port;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           llist_for_each_entry(bind, &nse->nsi->binding, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+                      bool found = false;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                 llist_for_each_entry(nsvc, &nse->vc, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+                           if (nsvc->bind != bind)</span><br><span style="color: hsl(120, 100%, 40%);">+                                    continue;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                           if (!osmo_sockaddr_cmp(&remote, gprs_ns2_ip_vc_sockaddr(nsvc))) {</span><br><span style="color: hsl(120, 100%, 40%);">+                                 found = true;</span><br><span style="color: hsl(120, 100%, 40%);">+                                 break;</span><br><span style="color: hsl(120, 100%, 40%);">+                                }</span><br><span style="color: hsl(120, 100%, 40%);">+                     }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                   if (!found) {</span><br><span style="color: hsl(120, 100%, 40%);">+                         nsvc = gprs_ns2_ip_connect_inactive(bind, &remote, nse, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+                               if (!nsvc) {</span><br><span style="color: hsl(120, 100%, 40%);">+                                  /* TODO: add to a list to send back a NS-STATUS */</span><br><span style="color: hsl(120, 100%, 40%);">+                                    continue;</span><br><span style="color: hsl(120, 100%, 40%);">+                             }</span><br><span style="color: hsl(120, 100%, 40%);">+                     }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                   /* update data / signalling weight */</span><br><span style="color: hsl(120, 100%, 40%);">+                 nsvc->data_weight = ip4->data_weight;</span><br><span style="color: hsl(120, 100%, 40%);">+                   nsvc->sig_weight = ip4->sig_weight;</span><br><span style="color: hsl(120, 100%, 40%);">+                     nsvc->sns_only = 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%);">+   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%);">+/* Add a given remote IPv4 element to gprs_sns_state */</span><br><span style="color: hsl(120, 100%, 40%);">+static int add_remote_ip4_elem(struct ns2_sns_state *gss, const struct gprs_ns_ie_ip4_elem *ip4)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  if (gss->num_ip4_remote >= gss->num_max_ip4_remote)</span><br><span style="color: hsl(120, 100%, 40%);">+          return -E2BIG;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      gss->ip4_remote = talloc_realloc(gss, gss->ip4_remote, struct gprs_ns_ie_ip4_elem,</span><br><span style="color: hsl(120, 100%, 40%);">+                                       gss->num_ip4_remote+1);</span><br><span style="color: hsl(120, 100%, 40%);">+   gss->ip4_remote[gss->num_ip4_remote] = *ip4;</span><br><span style="color: hsl(120, 100%, 40%);">+    gss->num_ip4_remote += 1;</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%);">+/* Remove a given remote IPv4 element from gprs_sns_state */</span><br><span style="color: hsl(120, 100%, 40%);">+static int remove_remote_ip4_elem(struct ns2_sns_state *gss, const struct gprs_ns_ie_ip4_elem *ip4)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  unsigned int i;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     for (i = 0; i < gss->num_ip4_remote; i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+             if (memcmp(&gss->ip4_remote[i], ip4, sizeof(*ip4)))</span><br><span style="color: hsl(120, 100%, 40%);">+                    continue;</span><br><span style="color: hsl(120, 100%, 40%);">+             /* all array elements < i remain as they are; all > i are shifted left by one */</span><br><span style="color: hsl(120, 100%, 40%);">+                memmove(&gss->ip4_remote[i], &gss->ip4_remote[i+1], gss->num_ip4_remote-i-1);</span><br><span style="color: hsl(120, 100%, 40%);">+                gss->num_ip4_remote -= 1;</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%);">+     return -1;</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 weights for specified remote IPv4 */</span><br><span style="color: hsl(120, 100%, 40%);">+static int update_remote_ip4_elem(struct ns2_sns_state *gss, const struct gprs_ns_ie_ip4_elem *ip4)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   unsigned int i;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     for (i = 0; i < gss->num_ip4_remote; i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+             if (gss->ip4_remote[i].ip_addr != ip4->ip_addr ||</span><br><span style="color: hsl(120, 100%, 40%);">+                   gss->ip4_remote[i].udp_port != ip4->udp_port)</span><br><span style="color: hsl(120, 100%, 40%);">+                       continue;</span><br><span style="color: hsl(120, 100%, 40%);">+             gss->ip4_remote[i].sig_weight = ip4->sig_weight;</span><br><span style="color: hsl(120, 100%, 40%);">+                gss->ip4_remote[i].data_weight = ip4->data_weight;</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%);">+     return -1;</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 do_sns_change_weight(struct osmo_fsm_inst *fi, const struct gprs_ns_ie_ip4_elem *ip4)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);</span><br><span style="color: hsl(120, 100%, 40%);">+      struct gprs_ns2_vc *nsvc = nsvc_by_ip4_elem(nse, ip4);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      /* TODO: Upon receiving an SNS-CHANGEWEIGHT PDU, if the resulting sum of the</span><br><span style="color: hsl(120, 100%, 40%);">+   * signalling weights of all the peer IP endpoints configured for this NSE is</span><br><span style="color: hsl(120, 100%, 40%);">+  * equal to zero or if the resulting sum of the data weights of all the peer IP</span><br><span style="color: hsl(120, 100%, 40%);">+        * endpoints configured for this NSE is equal to zero, the BSS/SGSN shall send an</span><br><span style="color: hsl(120, 100%, 40%);">+      * SNS-ACK PDU with a cause code of "Invalid weights". */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ update_remote_ip4_elem(gss, ip4);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!nsvc) {</span><br><span style="color: hsl(120, 100%, 40%);">+          LOGPFSML(fi, LOGL_NOTICE, "Couldn't find NS-VC for SNS-CHANGE_WEIGHT\n");</span><br><span style="color: hsl(120, 100%, 40%);">+               return -NS_CAUSE_NSVC_UNKNOWN;</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%);">+   LOGPFSML(fi, LOGL_INFO, "CHANGE-WEIGHT NS-VC %s data_weight %u->%u, sig_weight %u->%u\n",</span><br><span style="color: hsl(120, 100%, 40%);">+              gprs_ns2_ll_str(nsvc), nsvc->data_weight, ip4->data_weight,</span><br><span style="color: hsl(120, 100%, 40%);">+             nsvc->sig_weight, ip4->sig_weight);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  nsvc->data_weight = ip4->data_weight;</span><br><span style="color: hsl(120, 100%, 40%);">+   nsvc->sig_weight = ip4->sig_weight;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int do_sns_delete(struct osmo_fsm_inst *fi, const struct gprs_ns_ie_ip4_elem *ip4)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);</span><br><span style="color: hsl(120, 100%, 40%);">+      struct gprs_ns2_vc *nsvc = nsvc_by_ip4_elem(nse, ip4);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      if (remove_remote_ip4_elem(gss, ip4) < 0)</span><br><span style="color: hsl(120, 100%, 40%);">+          return -NS_CAUSE_UNKN_IP_EP;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        if (!nsvc) {</span><br><span style="color: hsl(120, 100%, 40%);">+          LOGPFSML(fi, LOGL_NOTICE, "Couldn't find NS-VC for SNS-DELETE\n");</span><br><span style="color: hsl(120, 100%, 40%);">+              return -NS_CAUSE_NSVC_UNKNOWN;</span><br><span style="color: hsl(120, 100%, 40%);">+        }</span><br><span style="color: hsl(120, 100%, 40%);">+     LOGPFSML(fi, LOGL_INFO, "DELETE NS-VC %s\n", gprs_ns2_ll_str(nsvc));</span><br><span style="color: hsl(120, 100%, 40%);">+        gprs_ns2_free_nsvc(nsvc);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int do_sns_add(struct osmo_fsm_inst *fi, const struct gprs_ns_ie_ip4_elem *ip4)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);</span><br><span style="color: hsl(120, 100%, 40%);">+      struct gprs_ns2_vc *nsvc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* Upon receiving an SNS-ADD PDU, if the consequent number of IPv4 endpoints</span><br><span style="color: hsl(120, 100%, 40%);">+   * exceeds the number of IPv4 endpoints supported by the NSE, the NSE shall send</span><br><span style="color: hsl(120, 100%, 40%);">+       * an SNS-ACK PDU with a cause code set to "Invalid number of IP4 Endpoints". */</span><br><span style="color: hsl(120, 100%, 40%);">+    if (add_remote_ip4_elem(gss, ip4) < 0)</span><br><span style="color: hsl(120, 100%, 40%);">+             return -NS_CAUSE_INVAL_NR_NS_VC;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    /* Upon receiving an SNS-ADD PDU containing an already configured IP endpoint the</span><br><span style="color: hsl(120, 100%, 40%);">+      * NSE shall send an SNS-ACK PDU with the cause code "Protocol error -</span><br><span style="color: hsl(120, 100%, 40%);">+    * unspecified" */</span><br><span style="color: hsl(120, 100%, 40%);">+       nsvc = nsvc_by_ip4_elem(nse, ip4);</span><br><span style="color: hsl(120, 100%, 40%);">+    if (nsvc)</span><br><span style="color: hsl(120, 100%, 40%);">+             return -NS_CAUSE_PROTO_ERR_UNSPEC;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  /* TODO: failure case */</span><br><span style="color: hsl(120, 100%, 40%);">+      ns2_nsvc_create_ip4(fi, nse, ip4);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  gprs_ns2_start_alive_all_nsvcs(nse);</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%);">+/***********************************************************************</span><br><span style="color: hsl(120, 100%, 40%);">+ * BSS-side FSM for IP Sub-Network Service</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 gprs_sns_bss_state {</span><br><span style="color: hsl(120, 100%, 40%);">+      GPRS_SNS_ST_UNCONFIGURED,</span><br><span style="color: hsl(120, 100%, 40%);">+     GPRS_SNS_ST_SIZE,               /*!< SNS-SIZE procedure ongoing */</span><br><span style="color: hsl(120, 100%, 40%);">+ GPRS_SNS_ST_CONFIG_BSS,         /*!< SNS-CONFIG procedure (BSS->SGSN) ongoing */</span><br><span style="color: hsl(120, 100%, 40%);">+        GPRS_SNS_ST_CONFIG_SGSN,        /*!< SNS-CONFIG procedure (SGSN->BSS) ongoing */</span><br><span style="color: hsl(120, 100%, 40%);">+        GPRS_SNS_ST_CONFIGURED,</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 gprs_sns_event {</span><br><span style="color: hsl(120, 100%, 40%);">+  GPRS_SNS_EV_START,</span><br><span style="color: hsl(120, 100%, 40%);">+    GPRS_SNS_EV_SIZE,</span><br><span style="color: hsl(120, 100%, 40%);">+     GPRS_SNS_EV_SIZE_ACK,</span><br><span style="color: hsl(120, 100%, 40%);">+ GPRS_SNS_EV_CONFIG,</span><br><span style="color: hsl(120, 100%, 40%);">+   GPRS_SNS_EV_CONFIG_END,         /*!< SNS-CONFIG with end flag received */</span><br><span style="color: hsl(120, 100%, 40%);">+  GPRS_SNS_EV_CONFIG_ACK,</span><br><span style="color: hsl(120, 100%, 40%);">+       GPRS_SNS_EV_ADD,</span><br><span style="color: hsl(120, 100%, 40%);">+      GPRS_SNS_EV_DELETE,</span><br><span style="color: hsl(120, 100%, 40%);">+   GPRS_SNS_EV_CHANGE_WEIGHT,</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 value_string gprs_sns_event_names[] = {</span><br><span style="color: hsl(120, 100%, 40%);">+ { GPRS_SNS_EV_START,            "START" },</span><br><span style="color: hsl(120, 100%, 40%);">+  { GPRS_SNS_EV_SIZE,             "SIZE" },</span><br><span style="color: hsl(120, 100%, 40%);">+   { GPRS_SNS_EV_SIZE_ACK,         "SIZE_ACK" },</span><br><span style="color: hsl(120, 100%, 40%);">+       { GPRS_SNS_EV_CONFIG,           "CONFIG" },</span><br><span style="color: hsl(120, 100%, 40%);">+ { GPRS_SNS_EV_CONFIG_END,       "CONFIG_END" },</span><br><span style="color: hsl(120, 100%, 40%);">+     { GPRS_SNS_EV_CONFIG_ACK,       "CONFIG_ACK" },</span><br><span style="color: hsl(120, 100%, 40%);">+     { GPRS_SNS_EV_ADD,              "ADD" },</span><br><span style="color: hsl(120, 100%, 40%);">+    { GPRS_SNS_EV_DELETE,           "DELETE" },</span><br><span style="color: hsl(120, 100%, 40%);">+ { GPRS_SNS_EV_CHANGE_WEIGHT,    "CHANGE_WEIGHT" },</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%);">+static void ns2_sns_st_unconfigured(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 gprs_ns2_nse *nse = nse_inst_from_fi(fi);</span><br><span style="color: hsl(120, 100%, 40%);">+      struct gprs_ns2_inst *nsi = nse->nsi;</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 GPRS_SNS_EV_START:</span><br><span style="color: hsl(120, 100%, 40%);">+               osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_SIZE, nsi->timeout[NS_TOUT_TSNS_PROV], 1);</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%);">+       }</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 ns2_sns_st_size(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 gprs_ns2_nse *nse = nse_inst_from_fi(fi);</span><br><span style="color: hsl(120, 100%, 40%);">+      struct gprs_ns2_inst *nsi = nse->nsi;</span><br><span style="color: hsl(120, 100%, 40%);">+      struct tlv_parsed *tp = 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 GPRS_SNS_EV_SIZE_ACK:</span><br><span style="color: hsl(120, 100%, 40%);">+            tp = data;</span><br><span style="color: hsl(120, 100%, 40%);">+            if (TLVP_VAL_MINLEN(tp, NS_IE_CAUSE, 1)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                    LOGPFSML(fi, LOGL_ERROR, "SNS-SIZE-ACK with cause %s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                             gprs_ns2_cause_str(*TLVP_VAL(tp, NS_IE_CAUSE)));</span><br><span style="color: hsl(120, 100%, 40%);">+                     /* FIXME: What to do? */</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, GPRS_SNS_ST_CONFIG_BSS,</span><br><span style="color: hsl(120, 100%, 40%);">+                                           nsi->timeout[NS_TOUT_TSNS_PROV], 2);</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%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+static void ns2_sns_st_size_onenter(struct osmo_fsm_inst *fi, uint32_t old_state)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+     uint16_t num_max_ip4_remote = gss->num_max_ip4_remote;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   gprs_ns2_tx_sns_size(gss->sns_nsvc, true, gss->num_max_nsvcs, &num_max_ip4_remote, 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%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void ns2_sns_st_config_bss(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 ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+   //struct gprs_ns2_nse *nse = ns_inst_from_fi(fi);</span><br><span style="color: hsl(120, 100%, 40%);">+     struct tlv_parsed *tp = 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 GPRS_SNS_EV_CONFIG_ACK:</span><br><span style="color: hsl(120, 100%, 40%);">+          tp = data;</span><br><span style="color: hsl(120, 100%, 40%);">+            if (TLVP_VAL_MINLEN(tp, NS_IE_CAUSE, 1)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                    LOGPFSML(fi, LOGL_ERROR, "SNS-CONFIG-ACK with cause %s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                           gprs_ns2_cause_str(*TLVP_VAL(tp, NS_IE_CAUSE)));</span><br><span style="color: hsl(120, 100%, 40%);">+                     /* FIXME: What to do? */</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, GPRS_SNS_ST_CONFIG_SGSN, 0, 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%);">+        default:</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 ns2_sns_st_config_bss_onenter(struct osmo_fsm_inst *fi, uint32_t old_state)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+     /* Transmit SNS-CONFIG */</span><br><span style="color: hsl(120, 100%, 40%);">+     gprs_ns2_tx_sns_config(gss->sns_nsvc, true, gss->ip4_local, gss->num_ip4_local);</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 ns2_sns_st_config_sgsn(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 ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct tlv_parsed *tp = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);</span><br><span style="color: hsl(120, 100%, 40%);">+      const struct gprs_ns_ie_ip4_elem *v4_list;</span><br><span style="color: hsl(120, 100%, 40%);">+    unsigned int num_v4;</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 GPRS_SNS_EV_CONFIG_END:</span><br><span style="color: hsl(120, 100%, 40%);">+  case GPRS_SNS_EV_CONFIG:</span><br><span style="color: hsl(120, 100%, 40%);">+              tp = data;</span><br><span style="color: hsl(120, 100%, 40%);">+#if 0               /* part of incoming SNS-SIZE (doesn't happen on BSS side */</span><br><span style="color: hsl(120, 100%, 40%);">+               if (TLVP_PRESENT(tp, NS_IE_RESET_FLAG)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                     /* reset all existing config */</span><br><span style="color: hsl(120, 100%, 40%);">+                       if (gss->ip4_remote)</span><br><span style="color: hsl(120, 100%, 40%);">+                               talloc_free(gss->ip4_remote);</span><br><span style="color: hsl(120, 100%, 40%);">+                      gss->num_ip4_remote = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+           }</span><br><span style="color: hsl(120, 100%, 40%);">+#endif</span><br><span style="color: hsl(120, 100%, 40%);">+             if (!TLVP_PRESENT(tp, NS_IE_IPv4_LIST)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                     cause = NS_CAUSE_INVAL_NR_IPv4_EP;</span><br><span style="color: hsl(120, 100%, 40%);">+                    gprs_ns2_tx_sns_config_ack(gss->sns_nsvc, &cause);</span><br><span style="color: hsl(120, 100%, 40%);">+                     osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_UNCONFIGURED, 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%);">+             v4_list = (const struct gprs_ns_ie_ip4_elem *) TLVP_VAL(tp, NS_IE_IPv4_LIST);</span><br><span style="color: hsl(120, 100%, 40%);">+         num_v4 = TLVP_LEN(tp, NS_IE_IPv4_LIST) / sizeof(*v4_list);</span><br><span style="color: hsl(120, 100%, 40%);">+            /* realloc to the new size */</span><br><span style="color: hsl(120, 100%, 40%);">+         gss->ip4_remote = talloc_realloc(gss, gss->ip4_remote,</span><br><span style="color: hsl(120, 100%, 40%);">+                                           struct gprs_ns_ie_ip4_elem,</span><br><span style="color: hsl(120, 100%, 40%);">+                                           gss->num_ip4_remote+num_v4);</span><br><span style="color: hsl(120, 100%, 40%);">+              /* append the new entries to the end of the list */</span><br><span style="color: hsl(120, 100%, 40%);">+           memcpy(&gss->ip4_remote[gss->num_ip4_remote], v4_list, num_v4*sizeof(*v4_list));</span><br><span style="color: hsl(120, 100%, 40%);">+            gss->num_ip4_remote += num_v4;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           LOGPFSML(fi, LOGL_INFO, "Rx SNS-CONFIG: Remote IPv4 list now %u entries\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                  gss->num_ip4_remote);</span><br><span style="color: hsl(120, 100%, 40%);">+             if (event == GPRS_SNS_EV_CONFIG_END) {</span><br><span style="color: hsl(120, 100%, 40%);">+                        /* check if sum of data / sig weights == 0 */</span><br><span style="color: hsl(120, 100%, 40%);">+                 if (ip4_weight_sum_data(gss->ip4_remote, gss->num_ip4_remote) == 0 ||</span><br><span style="color: hsl(120, 100%, 40%);">+                       ip4_weight_sum_sig(gss->ip4_remote, gss->num_ip4_remote) == 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                            cause = NS_CAUSE_INVAL_WEIGH;</span><br><span style="color: hsl(120, 100%, 40%);">+                         gprs_ns2_tx_sns_config_ack(gss->sns_nsvc, &cause);</span><br><span style="color: hsl(120, 100%, 40%);">+                             osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_UNCONFIGURED, 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%);">+                     create_missing_nsvcs(fi);</span><br><span style="color: hsl(120, 100%, 40%);">+                     gprs_ns2_tx_sns_config_ack(gss->sns_nsvc, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+                   /* start the test procedure on ALL NSVCs! */</span><br><span style="color: hsl(120, 100%, 40%);">+                  gprs_ns2_start_alive_all_nsvcs(nse);</span><br><span style="color: hsl(120, 100%, 40%);">+                  osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_CONFIGURED, 0, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+            } else {</span><br><span style="color: hsl(120, 100%, 40%);">+                      /* just send CONFIG-ACK */</span><br><span style="color: hsl(120, 100%, 40%);">+                    gprs_ns2_tx_sns_config_ack(gss->sns_nsvc, NULL);</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%);">+       }</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 ns2_sns_st_configured(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 ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct tlv_parsed *tp = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+ const struct gprs_ns_ie_ip4_elem *v4_list = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+     unsigned int num_v4 = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+      uint8_t trans_id;</span><br><span style="color: hsl(120, 100%, 40%);">+     uint8_t cause = 0xff;</span><br><span style="color: hsl(120, 100%, 40%);">+ unsigned int i;</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%);">+     switch (event) {</span><br><span style="color: hsl(120, 100%, 40%);">+      case GPRS_SNS_EV_ADD:</span><br><span style="color: hsl(120, 100%, 40%);">+         tp = data;</span><br><span style="color: hsl(120, 100%, 40%);">+            trans_id = *TLVP_VAL(tp, NS_IE_TRANS_ID);</span><br><span style="color: hsl(120, 100%, 40%);">+             if (TLVP_PRESENT(tp, NS_IE_IPv4_LIST)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                      v4_list = (const struct gprs_ns_ie_ip4_elem *) TLVP_VAL(tp, NS_IE_IPv4_LIST);</span><br><span style="color: hsl(120, 100%, 40%);">+                 num_v4 = TLVP_LEN(tp, NS_IE_IPv4_LIST) / sizeof(*v4_list);</span><br><span style="color: hsl(120, 100%, 40%);">+                    for (i = 0; i < num_v4; i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+                             rc = do_sns_add(fi, &v4_list[i]);</span><br><span style="color: hsl(120, 100%, 40%);">+                         if (rc < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                                      unsigned int j;</span><br><span style="color: hsl(120, 100%, 40%);">+                                       /* rollback/undo to restore previous state */</span><br><span style="color: hsl(120, 100%, 40%);">+                                 for (j = 0; j < i; j++)</span><br><span style="color: hsl(120, 100%, 40%);">+                                            do_sns_delete(fi, &v4_list[j]);</span><br><span style="color: hsl(120, 100%, 40%);">+                                   cause = -rc;</span><br><span style="color: hsl(120, 100%, 40%);">+                                  gprs_ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 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%);">+             } else {</span><br><span style="color: hsl(120, 100%, 40%);">+                      cause = NS_CAUSE_INVAL_NR_IPv4_EP;</span><br><span style="color: hsl(120, 100%, 40%);">+                    gprs_ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 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%);">+             gprs_ns2_tx_sns_ack(gss->sns_nsvc, trans_id, NULL, v4_list, num_v4);</span><br><span style="color: hsl(120, 100%, 40%);">+               break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case GPRS_SNS_EV_DELETE:</span><br><span style="color: hsl(120, 100%, 40%);">+              tp = data;</span><br><span style="color: hsl(120, 100%, 40%);">+            trans_id = *TLVP_VAL(tp, NS_IE_TRANS_ID);</span><br><span style="color: hsl(120, 100%, 40%);">+             if (TLVP_PRESENT(tp, NS_IE_IPv4_LIST)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                      v4_list = (const struct gprs_ns_ie_ip4_elem *) TLVP_VAL(tp, NS_IE_IPv4_LIST);</span><br><span style="color: hsl(120, 100%, 40%);">+                 num_v4 = TLVP_LEN(tp, NS_IE_IPv4_LIST) / sizeof(*v4_list);</span><br><span style="color: hsl(120, 100%, 40%);">+                    for (i = 0; i < num_v4; i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+                             rc = do_sns_delete(fi, &v4_list[i]);</span><br><span style="color: hsl(120, 100%, 40%);">+                              if (rc < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                                      cause = -rc;</span><br><span style="color: hsl(120, 100%, 40%);">+                                  /* continue to delete others */</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 (cause != 0xff) {</span><br><span style="color: hsl(120, 100%, 40%);">+                          /* TODO: create list of not-deleted and return it */</span><br><span style="color: hsl(120, 100%, 40%);">+                          gprs_ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 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%);">+             } else if (TLVP_PRES_LEN(tp, NS_IE_IP_ADDR, 5)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                     /* delete all NS-VCs for given IP address */</span><br><span style="color: hsl(120, 100%, 40%);">+                  const uint8_t *ie = TLVP_VAL(tp, NS_IE_IP_ADDR);</span><br><span style="color: hsl(120, 100%, 40%);">+                      struct gprs_ns_ie_ip4_elem *ip4_remote;</span><br><span style="color: hsl(120, 100%, 40%);">+                       uint32_t ip_addr = *(uint32_t *)(ie+1);</span><br><span style="color: hsl(120, 100%, 40%);">+                       if (ie[0] != 0x01) { /* Address Type != IPv4 */</span><br><span style="color: hsl(120, 100%, 40%);">+                               cause = NS_CAUSE_UNKN_IP_ADDR;</span><br><span style="color: hsl(120, 100%, 40%);">+                                gprs_ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 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%);">+                     /* make a copy as do_sns_delete() will change the array underneath us */</span><br><span style="color: hsl(120, 100%, 40%);">+                      ip4_remote = talloc_memdup(fi, gss->ip4_remote,</span><br><span style="color: hsl(120, 100%, 40%);">+                                               gss->num_ip4_remote*sizeof(*v4_list));</span><br><span style="color: hsl(120, 100%, 40%);">+                  for (i = 0; i < gss->num_ip4_remote; i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+                             if (ip4_remote[i].ip_addr == ip_addr) {</span><br><span style="color: hsl(120, 100%, 40%);">+                                       rc = do_sns_delete(fi, &ip4_remote[i]);</span><br><span style="color: hsl(120, 100%, 40%);">+                                   if (rc < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                                              cause = -rc;</span><br><span style="color: hsl(120, 100%, 40%);">+                                          /* continue to delete others */</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%);">+                     talloc_free(ip4_remote);</span><br><span style="color: hsl(120, 100%, 40%);">+                      if (cause != 0xff) {</span><br><span style="color: hsl(120, 100%, 40%);">+                          /* TODO: create list of not-deleted and return it */</span><br><span style="color: hsl(120, 100%, 40%);">+                          gprs_ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 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%);">+             } else {</span><br><span style="color: hsl(120, 100%, 40%);">+                      cause = NS_CAUSE_INVAL_NR_IPv4_EP;</span><br><span style="color: hsl(120, 100%, 40%);">+                    gprs_ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 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%);">+             gprs_ns2_tx_sns_ack(gss->sns_nsvc, trans_id, NULL, v4_list, num_v4);</span><br><span style="color: hsl(120, 100%, 40%);">+               break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case GPRS_SNS_EV_CHANGE_WEIGHT:</span><br><span style="color: hsl(120, 100%, 40%);">+               tp = data;</span><br><span style="color: hsl(120, 100%, 40%);">+            trans_id = *TLVP_VAL(tp, NS_IE_TRANS_ID);</span><br><span style="color: hsl(120, 100%, 40%);">+             if (TLVP_PRESENT(tp, NS_IE_IPv4_LIST)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                      v4_list = (const struct gprs_ns_ie_ip4_elem *) TLVP_VAL(tp, NS_IE_IPv4_LIST);</span><br><span style="color: hsl(120, 100%, 40%);">+                 num_v4 = TLVP_LEN(tp, NS_IE_IPv4_LIST) / sizeof(*v4_list);</span><br><span style="color: hsl(120, 100%, 40%);">+                    for (i = 0; i < num_v4; i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+                             rc = do_sns_change_weight(fi, &v4_list[i]);</span><br><span style="color: hsl(120, 100%, 40%);">+                               if (rc < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                                      cause = -rc;</span><br><span style="color: hsl(120, 100%, 40%);">+                                  /* continue to others */</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 (cause != 0xff) {</span><br><span style="color: hsl(120, 100%, 40%);">+                          gprs_ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 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%);">+             } else {</span><br><span style="color: hsl(120, 100%, 40%);">+                      cause = NS_CAUSE_INVAL_NR_IPv4_EP;</span><br><span style="color: hsl(120, 100%, 40%);">+                    gprs_ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 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%);">+             gprs_ns2_tx_sns_ack(gss->sns_nsvc, trans_id, NULL, v4_list, num_v4);</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 ns2_sns_st_configured_onenter(struct osmo_fsm_inst *fi, uint32_t old_state)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct gprs_ns2_signal_data nssd = {0};</span><br><span style="color: hsl(120, 100%, 40%);">+//     struct gprs_ns2_nse *nse = gss->nse;</span><br><span style="color: hsl(120, 100%, 40%);">+//     struct gprs_ns2_vc *nsvc;</span><br><span style="color: hsl(120, 100%, 40%);">+//   struct gprs_ns_ie_ip4_elem *ipv4;</span><br><span style="color: hsl(120, 100%, 40%);">+//   struct osmo_sockaddr remote, *tmp;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  nssd.nse = gss->nse;</span><br><span style="color: hsl(120, 100%, 40%);">+       nssd.nsei = gss->nse->nsei;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+// remote.u.sin.sin_family = AF_INET;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+//        /* drop initial connection */</span><br><span style="color: hsl(120, 100%, 40%);">+//       bool found = false;</span><br><span style="color: hsl(120, 100%, 40%);">+// for (int i = 0; i < gss->num_ip4_local; i++)</span><br><span style="color: hsl(120, 100%, 40%);">+//  {</span><br><span style="color: hsl(120, 100%, 40%);">+//           ipv4 = &gss->ip4_remote[i];</span><br><span style="color: hsl(120, 100%, 40%);">+//          remote.u.sin.sin_addr.s_addr = ipv4->ip_addr;</span><br><span style="color: hsl(120, 100%, 40%);">+//            remote.u.sin.sin_port = ipv4->udp_port;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+//                if (!osmo_sockaddr_cmp(&remote, gprs_ns2_ip_vc_sockaddr(gss->sns_nsvc))) {</span><br><span style="color: hsl(120, 100%, 40%);">+//                   found = true;</span><br><span style="color: hsl(120, 100%, 40%);">+//                       break;</span><br><span style="color: hsl(120, 100%, 40%);">+//              }</span><br><span style="color: hsl(120, 100%, 40%);">+//   }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+// if (!found) {</span><br><span style="color: hsl(120, 100%, 40%);">+//               /* it will update the sns by callback from free_nsvc */</span><br><span style="color: hsl(120, 100%, 40%);">+//             gprs_ns2_free_nsvc(gss->sns_nsvc);</span><br><span style="color: hsl(120, 100%, 40%);">+//       }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   osmo_signal_dispatch(SS_L_NS, S_SNS_CONFIGURED, &nssd);</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 ns2_sns_bss_states[] = {</span><br><span style="color: hsl(120, 100%, 40%);">+ [GPRS_SNS_ST_UNCONFIGURED] = {</span><br><span style="color: hsl(120, 100%, 40%);">+                .in_event_mask = S(GPRS_SNS_EV_START),</span><br><span style="color: hsl(120, 100%, 40%);">+                .out_state_mask = S(GPRS_SNS_ST_SIZE),</span><br><span style="color: hsl(120, 100%, 40%);">+                .name = "UNCONFIGURED",</span><br><span style="color: hsl(120, 100%, 40%);">+             .action = ns2_sns_st_unconfigured,</span><br><span style="color: hsl(120, 100%, 40%);">+    },</span><br><span style="color: hsl(120, 100%, 40%);">+    [GPRS_SNS_ST_SIZE] = {</span><br><span style="color: hsl(120, 100%, 40%);">+                .in_event_mask = S(GPRS_SNS_EV_SIZE_ACK),</span><br><span style="color: hsl(120, 100%, 40%);">+             .out_state_mask = S(GPRS_SNS_ST_UNCONFIGURED) |</span><br><span style="color: hsl(120, 100%, 40%);">+                                 S(GPRS_SNS_ST_SIZE) |</span><br><span style="color: hsl(120, 100%, 40%);">+                                 S(GPRS_SNS_ST_CONFIG_BSS),</span><br><span style="color: hsl(120, 100%, 40%);">+          .name = "SIZE",</span><br><span style="color: hsl(120, 100%, 40%);">+             .action = ns2_sns_st_size,</span><br><span style="color: hsl(120, 100%, 40%);">+            .onenter = ns2_sns_st_size_onenter,</span><br><span style="color: hsl(120, 100%, 40%);">+   },</span><br><span style="color: hsl(120, 100%, 40%);">+    [GPRS_SNS_ST_CONFIG_BSS] = {</span><br><span style="color: hsl(120, 100%, 40%);">+          .in_event_mask = S(GPRS_SNS_EV_CONFIG_ACK),</span><br><span style="color: hsl(120, 100%, 40%);">+           .out_state_mask = S(GPRS_SNS_ST_UNCONFIGURED) |</span><br><span style="color: hsl(120, 100%, 40%);">+                                 S(GPRS_SNS_ST_CONFIG_BSS) |</span><br><span style="color: hsl(120, 100%, 40%);">+                           S(GPRS_SNS_ST_CONFIG_SGSN),</span><br><span style="color: hsl(120, 100%, 40%);">+         .name = "CONFIG_BSS",</span><br><span style="color: hsl(120, 100%, 40%);">+               .action = ns2_sns_st_config_bss,</span><br><span style="color: hsl(120, 100%, 40%);">+              .onenter = ns2_sns_st_config_bss_onenter,</span><br><span style="color: hsl(120, 100%, 40%);">+     },</span><br><span style="color: hsl(120, 100%, 40%);">+    [GPRS_SNS_ST_CONFIG_SGSN] = {</span><br><span style="color: hsl(120, 100%, 40%);">+         .in_event_mask = S(GPRS_SNS_EV_CONFIG) |</span><br><span style="color: hsl(120, 100%, 40%);">+                               S(GPRS_SNS_EV_CONFIG_END),</span><br><span style="color: hsl(120, 100%, 40%);">+           .out_state_mask = S(GPRS_SNS_ST_UNCONFIGURED) |</span><br><span style="color: hsl(120, 100%, 40%);">+                                 S(GPRS_SNS_ST_CONFIG_SGSN) |</span><br><span style="color: hsl(120, 100%, 40%);">+                                  S(GPRS_SNS_ST_CONFIGURED),</span><br><span style="color: hsl(120, 100%, 40%);">+          .name = "CONFIG_SGSN",</span><br><span style="color: hsl(120, 100%, 40%);">+              .action = ns2_sns_st_config_sgsn,</span><br><span style="color: hsl(120, 100%, 40%);">+     },</span><br><span style="color: hsl(120, 100%, 40%);">+    [GPRS_SNS_ST_CONFIGURED] = {</span><br><span style="color: hsl(120, 100%, 40%);">+          .in_event_mask = S(GPRS_SNS_EV_ADD) |</span><br><span style="color: hsl(120, 100%, 40%);">+                          S(GPRS_SNS_EV_DELETE) |</span><br><span style="color: hsl(120, 100%, 40%);">+                               S(GPRS_SNS_EV_CHANGE_WEIGHT),</span><br><span style="color: hsl(120, 100%, 40%);">+                .out_state_mask = S(GPRS_SNS_ST_UNCONFIGURED),</span><br><span style="color: hsl(120, 100%, 40%);">+                .name = "CONFIGURED",</span><br><span style="color: hsl(120, 100%, 40%);">+               .action = ns2_sns_st_configured,</span><br><span style="color: hsl(120, 100%, 40%);">+              .onenter = ns2_sns_st_configured_onenter,</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 ns2_sns_fsm_bss_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 gprs_ns2_nse *nse = nse_inst_from_fi(fi);</span><br><span style="color: hsl(120, 100%, 40%);">+      struct gprs_ns2_inst *nsi = nse->nsi;</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 1:</span><br><span style="color: hsl(120, 100%, 40%);">+               osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_SIZE, nsi->timeout[NS_TOUT_TSNS_PROV], 1);</span><br><span style="color: hsl(120, 100%, 40%);">+         break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case 2:</span><br><span style="color: hsl(120, 100%, 40%);">+               osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_CONFIG_BSS, nsi->timeout[NS_TOUT_TSNS_PROV], 2);</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%);">+static struct osmo_fsm gprs_ns2_sns_bss_fsm = {</span><br><span style="color: hsl(120, 100%, 40%);">+       .name = "GPRS-NS2-SNS-BSS",</span><br><span style="color: hsl(120, 100%, 40%);">+ .states = ns2_sns_bss_states,</span><br><span style="color: hsl(120, 100%, 40%);">+ .num_states = ARRAY_SIZE(ns2_sns_bss_states),</span><br><span style="color: hsl(120, 100%, 40%);">+ .allstate_event_mask = 0,</span><br><span style="color: hsl(120, 100%, 40%);">+     .allstate_action = NULL,</span><br><span style="color: hsl(120, 100%, 40%);">+      .cleanup = NULL,</span><br><span style="color: hsl(120, 100%, 40%);">+      .timer_cb = ns2_sns_fsm_bss_timer_cb,</span><br><span style="color: hsl(120, 100%, 40%);">+ /* .log_subsys = DNS, "is not constant" */</span><br><span style="color: hsl(120, 100%, 40%);">+  .event_names = gprs_sns_event_names,</span><br><span style="color: hsl(120, 100%, 40%);">+  .pre_term = 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%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static struct gprs_ns_ie_ip4_elem *alloc_ip4_elem(void *ctx, struct osmo_sockaddr *sockaddr,</span><br><span style="color: hsl(120, 100%, 40%);">+                                          uint8_t sig_weight, uint8_t data_weight)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        struct gprs_ns_ie_ip4_elem *ip4;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    if (sockaddr->u.sa.sa_family != AF_INET)</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%);">+        ip4 = talloc_zero(ctx, struct gprs_ns_ie_ip4_elem);</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!ip4)</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%);">+        ip4->ip_addr = sockaddr->u.sin.sin_addr.s_addr;</span><br><span style="color: hsl(120, 100%, 40%);">+ ip4->udp_port = sockaddr->u.sin.sin_port;</span><br><span style="color: hsl(120, 100%, 40%);">+       ip4->sig_weight = sig_weight;</span><br><span style="color: hsl(120, 100%, 40%);">+      ip4->data_weight = data_weight;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  return ip4;</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 *ns2_sns_bss_fsm_alloc(struct gprs_ns2_nse *nse,</span><br><span style="color: hsl(120, 100%, 40%);">+                                           const char *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 ns2_sns_state *gss;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  fi = osmo_fsm_inst_alloc(&gprs_ns2_sns_bss_fsm, nse, NULL, LOGL_DEBUG, id);</span><br><span style="color: hsl(120, 100%, 40%);">+       if (!fi)</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%);">+  gss = talloc_zero(fi, struct ns2_sns_state);</span><br><span style="color: hsl(120, 100%, 40%);">+  if (!gss)</span><br><span style="color: hsl(120, 100%, 40%);">+             goto err;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   fi->priv = gss;</span><br><span style="color: hsl(120, 100%, 40%);">+    gss->nse = nse;</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%);">+err:</span><br><span style="color: hsl(120, 100%, 40%);">+      osmo_fsm_inst_term(fi, OSMO_FSM_TERM_ERROR, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+    return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int ns2_sns_bss_fsm_start(struct gprs_ns2_nse *nse, struct gprs_ns2_vc *nsvc, struct osmo_sockaddr *remote)</span><br><span style="color: hsl(120, 100%, 40%);">+{       </span><br><span style="color: hsl(120, 100%, 40%);">+      struct osmo_fsm_inst *fi = nse->bss_sns_fi;</span><br><span style="color: hsl(120, 100%, 40%);">+        struct ns2_sns_state *gss = (struct ns2_sns_state *) nse->bss_sns_fi->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct gprs_ns_ie_ip4_elem *ip4;</span><br><span style="color: hsl(120, 100%, 40%);">+      struct gprs_ns2_vc_bind *bind;</span><br><span style="color: hsl(120, 100%, 40%);">+        struct gprs_ns2_inst *nsi = nse->nsi;</span><br><span style="color: hsl(120, 100%, 40%);">+      struct osmo_sockaddr *sa, local;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    gss->initial = *remote;</span><br><span style="color: hsl(120, 100%, 40%);">+    gss->sns_nsvc = nsvc;</span><br><span style="color: hsl(120, 100%, 40%);">+      nsvc->sns_only = 1;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      /* TODO: create IPv4 list from the one IP/port the NS instance has */</span><br><span style="color: hsl(120, 100%, 40%);">+ int count = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+        llist_for_each_entry(bind, &nsi->binding, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+              if (!gprs_ns2_is_ip_bind(bind))</span><br><span style="color: hsl(120, 100%, 40%);">+                       continue;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           sa = gprs_ns2_ip_bind_sockaddr(bind);</span><br><span style="color: hsl(120, 100%, 40%);">+         if (!sa)</span><br><span style="color: hsl(120, 100%, 40%);">+                      continue;</span><br><span style="color: hsl(120, 100%, 40%);">+             count++;</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%);">+   ip4 = talloc_zero_size(fi, sizeof(struct gprs_ns_ie_ip4_elem) * count);</span><br><span style="color: hsl(120, 100%, 40%);">+       if (!ip4)</span><br><span style="color: hsl(120, 100%, 40%);">+             goto err;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   gss->ip4_local = ip4;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    llist_for_each_entry(bind, &nsi->binding, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+              if (!gprs_ns2_is_ip_bind(bind))</span><br><span style="color: hsl(120, 100%, 40%);">+                       continue;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           sa = gprs_ns2_ip_bind_sockaddr(bind);</span><br><span style="color: hsl(120, 100%, 40%);">+         if (!sa)</span><br><span style="color: hsl(120, 100%, 40%);">+                      continue;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           /* check if this is an specific bind */</span><br><span style="color: hsl(120, 100%, 40%);">+               if ((sa->u.sas.ss_family == AF_INET && sa->u.sin.sin_addr.s_addr == 0) ||</span><br><span style="color: hsl(120, 100%, 40%);">+                               (sa->u.sas.ss_family == AF_INET6 && IN6_IS_ADDR_UNSPECIFIED(&sa->u.sin6.sin6_addr) ))</span><br><span style="color: hsl(120, 100%, 40%);">+               {</span><br><span style="color: hsl(120, 100%, 40%);">+                     if (osmo_sockaddr_local_ip(&local, remote))</span><br><span style="color: hsl(120, 100%, 40%);">+                               continue;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                   ip4->ip_addr = local.u.sin.sin_addr.s_addr;</span><br><span style="color: hsl(120, 100%, 40%);">+                } else {</span><br><span style="color: hsl(120, 100%, 40%);">+                      ip4->ip_addr = sa->u.sin.sin_addr.s_addr;</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%);">+           ip4->udp_port = sa->u.sin.sin_port;</span><br><span style="color: hsl(120, 100%, 40%);">+             ip4->sig_weight = 2;</span><br><span style="color: hsl(120, 100%, 40%);">+               ip4->data_weight = 1;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+            ip4++;</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%);">+   gss->num_ip4_local = count;</span><br><span style="color: hsl(120, 100%, 40%);">+        gss->num_max_nsvcs = 8;</span><br><span style="color: hsl(120, 100%, 40%);">+    gss->num_max_ip4_remote = 4;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     return osmo_fsm_inst_dispatch(nse->bss_sns_fi, GPRS_SNS_EV_START, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+err:</span><br><span style="color: hsl(120, 100%, 40%);">+   return -1;</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%);">+/* main entry point for receiving SNS messages from the network */</span><br><span style="color: hsl(120, 100%, 40%);">+int gprs_ns2_sns_rx(struct gprs_ns2_vc *nsvc, struct msgb *msg, struct tlv_parsed *tp)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        struct gprs_ns2_nse *nse = nsvc->nse;</span><br><span style="color: hsl(120, 100%, 40%);">+      struct gprs_ns_hdr *nsh = (struct gprs_ns_hdr *) msg->l2h;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint16_t nsei = msgb_nsei(msg);</span><br><span style="color: hsl(120, 100%, 40%);">+       struct osmo_fsm_inst *fi;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   LOGP(DNS, LOGL_DEBUG, "NSEI=%u Rx SNS PDU type %s\n", nsei,</span><br><span style="color: hsl(120, 100%, 40%);">+         get_value_string(gprs_ns_pdu_strings, nsh->pdu_type));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* FIXME: how to resolve SNS FSM Instance by NSEI (SGSN)? */</span><br><span style="color: hsl(120, 100%, 40%);">+  fi = nse->bss_sns_fi;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    switch (nsh->pdu_type) {</span><br><span style="color: hsl(120, 100%, 40%);">+   case SNS_PDUT_SIZE:</span><br><span style="color: hsl(120, 100%, 40%);">+           osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_SIZE, tp);</span><br><span style="color: hsl(120, 100%, 40%);">+             break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case SNS_PDUT_SIZE_ACK:</span><br><span style="color: hsl(120, 100%, 40%);">+               osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_SIZE_ACK, tp);</span><br><span style="color: hsl(120, 100%, 40%);">+         break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case SNS_PDUT_CONFIG:</span><br><span style="color: hsl(120, 100%, 40%);">+         if (nsh->data[0] & 0x01)</span><br><span style="color: hsl(120, 100%, 40%);">+                       osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_CONFIG_END, tp);</span><br><span style="color: hsl(120, 100%, 40%);">+               else</span><br><span style="color: hsl(120, 100%, 40%);">+                  osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_CONFIG, tp);</span><br><span style="color: hsl(120, 100%, 40%);">+           break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case SNS_PDUT_CONFIG_ACK:</span><br><span style="color: hsl(120, 100%, 40%);">+             osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_CONFIG_ACK, tp);</span><br><span style="color: hsl(120, 100%, 40%);">+               break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case SNS_PDUT_ADD:</span><br><span style="color: hsl(120, 100%, 40%);">+            osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_ADD, tp);</span><br><span style="color: hsl(120, 100%, 40%);">+              break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case SNS_PDUT_DELETE:</span><br><span style="color: hsl(120, 100%, 40%);">+         osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_DELETE, tp);</span><br><span style="color: hsl(120, 100%, 40%);">+           break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case SNS_PDUT_CHANGE_WEIGHT:</span><br><span style="color: hsl(120, 100%, 40%);">+          osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_CHANGE_WEIGHT, tp);</span><br><span style="color: hsl(120, 100%, 40%);">+            break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case SNS_PDUT_ACK:</span><br><span style="color: hsl(120, 100%, 40%);">+            LOGP(DNS, LOGL_NOTICE, "NSEI=%u Rx unsupported SNS PDU type %s\n", nsei,</span><br><span style="color: hsl(120, 100%, 40%);">+                    get_value_string(gprs_ns_pdu_strings, nsh->pdu_type));</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%);">+              LOGP(DNS, LOGL_ERROR, "NSEI=%u Rx unknown SNS PDU type %s\n", nsei,</span><br><span style="color: hsl(120, 100%, 40%);">+                 get_value_string(gprs_ns_pdu_strings, nsh->pdu_type));</span><br><span style="color: hsl(120, 100%, 40%);">+             return -EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int gprs_ns2_sns_init(void)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        /* "DNS" is not a constant/#define, but an integer variable set by the client app */</span><br><span style="color: hsl(120, 100%, 40%);">+        gprs_ns2_sns_bss_fsm.log_subsys = DNS;</span><br><span style="color: hsl(120, 100%, 40%);">+        return osmo_fsm_register(&gprs_ns2_sns_bss_fsm);</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%);">+#include <osmocom/vty/vty.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/vty/misc.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void vty_dump_sns_ip4(struct vty *vty, const struct gprs_ns_ie_ip4_elem *ip4)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct in_addr in = { .s_addr = ip4->ip_addr };</span><br><span style="color: hsl(120, 100%, 40%);">+    vty_out(vty, " %s:%u, Signalling Weight: %u, Data Weight: %u%s",</span><br><span style="color: hsl(120, 100%, 40%);">+            inet_ntoa(in), ntohs(ip4->udp_port), ip4->sig_weight, ip4->data_weight, VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void gprs_ns2_dump_vty(struct vty *vty, const struct gprs_ns2_nse *nse, bool stats)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   struct ns2_sns_state *gss;</span><br><span style="color: hsl(120, 100%, 40%);">+    unsigned int i;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     if (!nse->bss_sns_fi)</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%);">+     vty_out_fsm_inst(vty, nse->bss_sns_fi);</span><br><span style="color: hsl(120, 100%, 40%);">+    gss = (struct ns2_sns_state *) nse->bss_sns_fi->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ vty_out(vty, "Maximum number of remote  NS-VCs: %zu, IPv4 Endpoints: %zu%s",</span><br><span style="color: hsl(120, 100%, 40%);">+                gss->num_max_nsvcs, gss->num_max_ip4_remote, VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    vty_out(vty, "Local IPv4 Endpoints:%s", VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+       for (i = 0; i < gss->num_ip4_local; i++)</span><br><span style="color: hsl(120, 100%, 40%);">+                vty_dump_sns_ip4(vty, &gss->ip4_local[i]);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   vty_out(vty, "Remote IPv4 Endpoints:%s", VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+      for (i = 0; i < gss->num_ip4_remote; i++)</span><br><span style="color: hsl(120, 100%, 40%);">+               vty_dump_sns_ip4(vty, &gss->ip4_remote[i]);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span>diff --git a/src/gb/gprs_ns2_vc_fsm.c b/src/gb/gprs_ns2_vc_fsm.c</span><br><span>new file mode 100644</span><br><span>index 0000000..77806ca</span><br><span>--- /dev/null</span><br><span>+++ b/src/gb/gprs_ns2_vc_fsm.c</span><br><span>@@ -0,0 +1,671 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/* Implementation of 3GPP TS 48.016 NS IP Sub-Network Service</span><br><span style="color: hsl(120, 100%, 40%);">+ * based on gprs_ns_sns.c by Harald Welte <laforge@gnumonks.org></span><br><span style="color: hsl(120, 100%, 40%);">+ * (C) 2020 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de></span><br><span style="color: hsl(120, 100%, 40%);">+ * Author: Alexander Couzens <lynxis@fe80.eu> */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* The BSS NSE only has one SGSN IP address configured, and it will use the SNS procedures</span><br><span style="color: hsl(120, 100%, 40%);">+ * to communicated its local IPs/ports as well as all the SGSN side IPs/ports and</span><br><span style="color: hsl(120, 100%, 40%);">+ * associated weights.  In theory, the BSS then uses this to establish a full mesh</span><br><span style="color: hsl(120, 100%, 40%);">+ * of NSVCs between all BSS-side IPs/ports and SGSN-side IPs/ports */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <errno.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <netinet/in.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <arpa/inet.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/msgb.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/signal.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/socket.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/gsm/tlv.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/gprs/gprs_msgb.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_16.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include "gprs_ns2_internal.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "gprs_ns2_vc_fsm.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "gprs_ns2_message.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%);">+#define DNS 10</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct gprs_ns2_vc_priv {</span><br><span style="color: hsl(120, 100%, 40%);">+       struct gprs_ns2_vc *vc;\</span><br><span style="color: hsl(120, 100%, 40%);">+      /* how often the timer was triggered */</span><br><span style="color: hsl(120, 100%, 40%);">+       int N;</span><br><span style="color: hsl(120, 100%, 40%);">+        /* The initiater is responsible to UNBLOCK the VC. The BSS is usually the initiater.</span><br><span style="color: hsl(120, 100%, 40%);">+   * It can change while runtime. The side which blocks an unblocked side.*/</span><br><span style="color: hsl(120, 100%, 40%);">+    bool initiater;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     /* the alive counter is present in all states */</span><br><span style="color: hsl(120, 100%, 40%);">+      struct {</span><br><span style="color: hsl(120, 100%, 40%);">+              struct osmo_timer_list timer;</span><br><span style="color: hsl(120, 100%, 40%);">+         enum ns2_timeout mode;</span><br><span style="color: hsl(120, 100%, 40%);">+                int N;</span><br><span style="color: hsl(120, 100%, 40%);">+        } alive;</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%);">+/* The FSM covers both the VC with RESET/BLOCK and without RESET/BLOCK procedure..</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * With RESET/BLOCK, the state should follow:</span><br><span style="color: hsl(120, 100%, 40%);">+ * - UNCONFIGURED -> RESET -> BLOCK -> UNBLOCKED</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * Without RESET/BLOCK, the state should follow:</span><br><span style="color: hsl(120, 100%, 40%);">+ * - UNCONFIGURED -> ALIVE -> UNBLOCKED</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * The UNBLOCKED and TEST states are used to send ALIVE PDU using the timeout Tns-test and Tns-alive.</span><br><span style="color: hsl(120, 100%, 40%);">+ * UNBLOCKED -> TEST: on expire of Tns-Test, send Alive PDU.</span><br><span style="color: hsl(120, 100%, 40%);">+ * TEST -> UNBLOCKED: on receive of Alive_Ack PDU, go into UNBLOCKED.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * The ALIVE state is used as intermediate, because a VC is only valid if it received an Alive ACK when</span><br><span style="color: hsl(120, 100%, 40%);">+ * not using RESET/BLOCK procedure.</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 gprs_ns2_vc_state {</span><br><span style="color: hsl(120, 100%, 40%);">+      GPRS_NS2_ST_UNCONFIGURED,</span><br><span style="color: hsl(120, 100%, 40%);">+     GPRS_NS2_ST_RESET,</span><br><span style="color: hsl(120, 100%, 40%);">+    GPRS_NS2_ST_BLOCKED,</span><br><span style="color: hsl(120, 100%, 40%);">+  GPRS_NS2_ST_UNBLOCKED, /* allows sending NS_UNITDATA */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     GPRS_NS2_ST_ALIVE, /* only used when not using RESET/BLOCK procedure */</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 gprs_ns2_vc_event {</span><br><span style="color: hsl(120, 100%, 40%);">+       GPRS_NS2_EV_START,</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  /* received messages */</span><br><span style="color: hsl(120, 100%, 40%);">+       GPRS_NS2_EV_RESET,</span><br><span style="color: hsl(120, 100%, 40%);">+    GPRS_NS2_EV_RESET_ACK,</span><br><span style="color: hsl(120, 100%, 40%);">+        GPRS_NS2_EV_UNBLOCK,</span><br><span style="color: hsl(120, 100%, 40%);">+  GPRS_NS2_EV_UNBLOCK_ACK,</span><br><span style="color: hsl(120, 100%, 40%);">+      GPRS_NS2_EV_BLOCK,</span><br><span style="color: hsl(120, 100%, 40%);">+    GPRS_NS2_EV_BLOCK_ACK,</span><br><span style="color: hsl(120, 100%, 40%);">+        GPRS_NS2_EV_ALIVE,</span><br><span style="color: hsl(120, 100%, 40%);">+    GPRS_NS2_EV_ALIVE_ACK,</span><br><span style="color: hsl(120, 100%, 40%);">+        GPRS_NS2_EV_STATUS,</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ GPRS_NS2_EV_UNITDATA,</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 value_string gprs_ns2_vc_event_names[] = {</span><br><span style="color: hsl(120, 100%, 40%);">+   { GPRS_NS2_EV_START,            "START" },</span><br><span style="color: hsl(120, 100%, 40%);">+  { GPRS_NS2_EV_RESET,            "RESET" },</span><br><span style="color: hsl(120, 100%, 40%);">+  { GPRS_NS2_EV_RESET_ACK,        "RESET_ACK" },</span><br><span style="color: hsl(120, 100%, 40%);">+      { GPRS_NS2_EV_UNBLOCK,          "UNBLOCK" },</span><br><span style="color: hsl(120, 100%, 40%);">+        { GPRS_NS2_EV_UNBLOCK_ACK,      "UNBLOCK_ACK" },</span><br><span style="color: hsl(120, 100%, 40%);">+    { GPRS_NS2_EV_BLOCK,    "BLOCK" },</span><br><span style="color: hsl(120, 100%, 40%);">+  { GPRS_NS2_EV_BLOCK_ACK,                "BLOCK_ACK" },</span><br><span style="color: hsl(120, 100%, 40%);">+      { GPRS_NS2_EV_ALIVE,            "ALIVE" },</span><br><span style="color: hsl(120, 100%, 40%);">+  { GPRS_NS2_EV_ALIVE_ACK,        "ALIVE_ACK" },</span><br><span style="color: hsl(120, 100%, 40%);">+      { GPRS_NS2_EV_STATUS,   "STATUS" },</span><br><span style="color: hsl(120, 100%, 40%);">+ { GPRS_NS2_EV_UNITDATA, "UNITDATA" },</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%);">+static void signal_dispatch(struct gprs_ns2_vc *nsvc, unsigned int signal,</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%);">+ struct gprs_ns2_signal_data nssd = {0};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     nssd.nse = nsvc->nse;</span><br><span style="color: hsl(120, 100%, 40%);">+      nssd.nsei = nsvc->nse->nsei;</span><br><span style="color: hsl(120, 100%, 40%);">+    nssd.nsvc = nsvc;</span><br><span style="color: hsl(120, 100%, 40%);">+     nssd.cause = cause;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_signal_dispatch(SS_L_NS, signal, &nssd);</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 inline struct gprs_ns2_inst *ns_inst_from_fi(struct osmo_fsm_inst *fi)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      struct gprs_ns2_vc_priv *priv = fi->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+  return priv->vc->nse->nsi;</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 start_test_procedure(struct osmo_fsm_inst *fi)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       struct gprs_ns2_vc_priv *priv = fi->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+  struct gprs_ns2_inst *nsi = ns_inst_from_fi(fi);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    if (osmo_timer_pending(&priv->alive.timer))</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%);">+     priv->alive.mode = NS_TOUT_TNS_ALIVE;</span><br><span style="color: hsl(120, 100%, 40%);">+      priv->alive.N = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       gprs_ns2_tx_alive(priv->vc);</span><br><span style="color: hsl(120, 100%, 40%);">+       osmo_timer_schedule(&priv->alive.timer, nsi->timeout[NS_TOUT_TNS_ALIVE], 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 stop_test_procedure(struct osmo_fsm_inst *fi)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     struct gprs_ns2_vc_priv *priv = fi->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        osmo_timer_del(&priv->alive.timer);</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 recv_test_procedure(struct osmo_fsm_inst *fi)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct gprs_ns2_vc_priv *priv = fi->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+  struct gprs_ns2_inst *nsi = ns_inst_from_fi(fi);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    /* ignoring ACKs without sending an ALIVE */</span><br><span style="color: hsl(120, 100%, 40%);">+  if (priv->alive.mode != NS_TOUT_TNS_ALIVE)</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%);">+     priv->alive.mode = NS_TOUT_TNS_TEST;</span><br><span style="color: hsl(120, 100%, 40%);">+       osmo_timer_schedule(&priv->alive.timer, nsi->timeout[NS_TOUT_TNS_TEST], 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%);">+static void alive_timeout_handler(void *data)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        struct osmo_fsm_inst *fi = data;</span><br><span style="color: hsl(120, 100%, 40%);">+      struct gprs_ns2_inst *nsi = ns_inst_from_fi(fi);</span><br><span style="color: hsl(120, 100%, 40%);">+      struct gprs_ns2_vc_priv *priv = fi->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        switch (priv->alive.mode) {</span><br><span style="color: hsl(120, 100%, 40%);">+        case NS_TOUT_TNS_TEST:</span><br><span style="color: hsl(120, 100%, 40%);">+                priv->alive.mode = NS_TOUT_TNS_ALIVE;</span><br><span style="color: hsl(120, 100%, 40%);">+              gprs_ns2_tx_alive(priv->vc);</span><br><span style="color: hsl(120, 100%, 40%);">+               osmo_timer_schedule(&priv->alive.timer, nsi->timeout[NS_TOUT_TNS_ALIVE], 0);</span><br><span style="color: hsl(120, 100%, 40%);">+                break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case NS_TOUT_TNS_ALIVE:</span><br><span style="color: hsl(120, 100%, 40%);">+               priv->alive.N++;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+         if (priv->alive.N <= nsi->timeout[NS_TOUT_TNS_ALIVE_RETRIES]) {</span><br><span style="color: hsl(120, 100%, 40%);">+                      gprs_ns2_tx_alive(priv->vc);</span><br><span style="color: hsl(120, 100%, 40%);">+                       osmo_timer_schedule(&priv->alive.timer, nsi->timeout[NS_TOUT_TNS_ALIVE], 0);</span><br><span style="color: hsl(120, 100%, 40%);">+                } else {</span><br><span style="color: hsl(120, 100%, 40%);">+                      if (priv->vc->mode == NS2_VC_MODE_BLOCKRESET) {</span><br><span style="color: hsl(120, 100%, 40%);">+                         /* lost connection */</span><br><span style="color: hsl(120, 100%, 40%);">+                         osmo_fsm_inst_state_chg(fi, GPRS_NS2_ST_RESET, nsi->timeout[NS_TOUT_TNS_RESET], 0);</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, GPRS_NS2_ST_ALIVE, nsi->timeout[NS_TOUT_TNS_ALIVE], 0);</span><br><span style="color: hsl(120, 100%, 40%);">+                        }</span><br><span style="color: hsl(120, 100%, 40%);">+                     signal_dispatch(priv->vc, S_NS_ALIVE_EXP, 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%);">+        default:</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 gprs_ns2_st_unconfigured(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 gprs_ns2_vc_priv *priv = fi->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+  struct gprs_ns2_inst *nsi = priv->vc->nse->nsi;</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 GPRS_NS2_EV_START:</span><br><span style="color: hsl(120, 100%, 40%);">+               switch (priv->vc->mode) {</span><br><span style="color: hsl(120, 100%, 40%);">+               case NS2_VC_MODE_ALIVE:</span><br><span style="color: hsl(120, 100%, 40%);">+                       osmo_fsm_inst_state_chg(fi, GPRS_NS2_ST_ALIVE, nsi->timeout[NS_TOUT_TNS_ALIVE], NS_TOUT_TNS_ALIVE);</span><br><span style="color: hsl(120, 100%, 40%);">+                        break;</span><br><span style="color: hsl(120, 100%, 40%);">+                case NS2_VC_MODE_BLOCKRESET:</span><br><span style="color: hsl(120, 100%, 40%);">+                  osmo_fsm_inst_state_chg(fi, GPRS_NS2_ST_RESET, nsi->timeout[NS_TOUT_TNS_RESET], NS_TOUT_TNS_RESET);</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%);">+           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%);">+       }</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 gprs_ns2_st_reset_onenter(struct osmo_fsm_inst *fi, uint32_t old_state)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      struct gprs_ns2_vc_priv *priv = fi->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        if (old_state != GPRS_NS2_ST_RESET)</span><br><span style="color: hsl(120, 100%, 40%);">+           priv->N = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     if (priv->initiater)</span><br><span style="color: hsl(120, 100%, 40%);">+               gprs_ns2_tx_reset(priv->vc, NS_CAUSE_OM_INTERVENTION);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   stop_test_procedure(fi);</span><br><span style="color: hsl(120, 100%, 40%);">+      signal_dispatch(priv->vc, S_NS_RESET, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+  ns2_nse_notify_unblocked(priv->vc, false);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void gprs_ns2_st_reset(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 gprs_ns2_inst *nsi = ns_inst_from_fi(fi);</span><br><span style="color: hsl(120, 100%, 40%);">+      struct gprs_ns2_vc_priv *priv = fi->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        if (priv->initiater) {</span><br><span style="color: hsl(120, 100%, 40%);">+             switch (event) {</span><br><span style="color: hsl(120, 100%, 40%);">+              case GPRS_NS2_EV_RESET_ACK:</span><br><span style="color: hsl(120, 100%, 40%);">+                   osmo_fsm_inst_state_chg(fi, GPRS_NS2_ST_BLOCKED,</span><br><span style="color: hsl(120, 100%, 40%);">+                                              nsi->timeout[NS_TOUT_TNS_BLOCK], NS_TOUT_TNS_BLOCK);</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%);">+               }</span><br><span style="color: hsl(120, 100%, 40%);">+     } else {</span><br><span style="color: hsl(120, 100%, 40%);">+              /* we are on the receiving end */</span><br><span style="color: hsl(120, 100%, 40%);">+             switch (event) {</span><br><span style="color: hsl(120, 100%, 40%);">+              case GPRS_NS2_EV_RESET:</span><br><span style="color: hsl(120, 100%, 40%);">+                       gprs_ns2_tx_reset_ack(priv->vc);</span><br><span style="color: hsl(120, 100%, 40%);">+                   osmo_fsm_inst_state_chg(fi, GPRS_NS2_ST_BLOCKED,</span><br><span style="color: hsl(120, 100%, 40%);">+                                              0, 0);</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%);">+               }</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 gprs_ns2_st_blocked_onenter(struct osmo_fsm_inst *fi, uint32_t old_state)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      struct gprs_ns2_vc_priv *priv = fi->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        if (old_state != GPRS_NS2_ST_BLOCKED)</span><br><span style="color: hsl(120, 100%, 40%);">+         priv->N = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     if (priv->initiater)</span><br><span style="color: hsl(120, 100%, 40%);">+               gprs_ns2_tx_unblock(priv->vc);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   start_test_procedure(fi);</span><br><span style="color: hsl(120, 100%, 40%);">+     signal_dispatch(priv->vc, S_NS_BLOCK, 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 gprs_ns2_st_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 gprs_ns2_inst *nsi = ns_inst_from_fi(fi);</span><br><span style="color: hsl(120, 100%, 40%);">+      struct gprs_ns2_vc_priv *priv = fi->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        if (priv->initiater) {</span><br><span style="color: hsl(120, 100%, 40%);">+             switch (event) {</span><br><span style="color: hsl(120, 100%, 40%);">+              case GPRS_NS2_EV_BLOCK:</span><br><span style="color: hsl(120, 100%, 40%);">+                       /* TODO: BLOCK is a BLOCK_NACK */</span><br><span style="color: hsl(120, 100%, 40%);">+                     gprs_ns2_tx_block_ack(priv->vc);</span><br><span style="color: hsl(120, 100%, 40%);">+                   break;</span><br><span style="color: hsl(120, 100%, 40%);">+                case GPRS_NS2_EV_UNBLOCK:</span><br><span style="color: hsl(120, 100%, 40%);">+                     gprs_ns2_tx_unblock_ack(priv->vc);</span><br><span style="color: hsl(120, 100%, 40%);">+                 /* fall through */</span><br><span style="color: hsl(120, 100%, 40%);">+            case GPRS_NS2_EV_UNBLOCK_ACK:</span><br><span style="color: hsl(120, 100%, 40%);">+                 osmo_fsm_inst_state_chg(fi, GPRS_NS2_ST_UNBLOCKED,</span><br><span style="color: hsl(120, 100%, 40%);">+                                            0, NS_TOUT_TNS_TEST);</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%);">+     } else {</span><br><span style="color: hsl(120, 100%, 40%);">+              /* we are on the receiving end. The initiator who sent RESET is responsible to UNBLOCK! */</span><br><span style="color: hsl(120, 100%, 40%);">+            switch (event) {</span><br><span style="color: hsl(120, 100%, 40%);">+              case GPRS_NS2_EV_UNBLOCK:</span><br><span style="color: hsl(120, 100%, 40%);">+                     gprs_ns2_tx_unblock_ack(priv->vc);</span><br><span style="color: hsl(120, 100%, 40%);">+                 osmo_fsm_inst_state_chg(fi, GPRS_NS2_ST_UNBLOCKED,</span><br><span style="color: hsl(120, 100%, 40%);">+                                            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%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void gprs_ns2_st_unblocked_on_enter(struct osmo_fsm_inst *fi, uint32_t old_state)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   struct gprs_ns2_vc_priv *priv = fi->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        signal_dispatch(priv->vc, S_NS_UNBLOCK, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+        ns2_nse_notify_unblocked(priv->vc, true);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void gprs_ns2_st_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 gprs_ns2_vc_priv *priv = fi->priv;</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 GPRS_NS2_EV_BLOCK:</span><br><span style="color: hsl(120, 100%, 40%);">+               priv->initiater = false;</span><br><span style="color: hsl(120, 100%, 40%);">+           gprs_ns2_tx_block_ack(priv->vc);</span><br><span style="color: hsl(120, 100%, 40%);">+           osmo_fsm_inst_state_chg(fi, GPRS_NS2_ST_BLOCKED,</span><br><span style="color: hsl(120, 100%, 40%);">+                                      0, 2);</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%);">+       }</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 gprs_ns2_st_alive(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 gprs_ns2_inst *nsi = ns_inst_from_fi(fi);</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 GPRS_NS2_EV_ALIVE_ACK:</span><br><span style="color: hsl(120, 100%, 40%);">+           osmo_fsm_inst_state_chg(fi, GPRS_NS2_ST_UNBLOCKED,</span><br><span style="color: hsl(120, 100%, 40%);">+                                    0, 0);</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%);">+       }</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 gprs_ns2_st_alive_onenter(struct osmo_fsm_inst *fi, uint32_t old_state)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        struct gprs_ns2_vc_priv *priv = fi->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+  struct gprs_ns2_inst *nsi = ns_inst_from_fi(fi);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    priv->alive.mode = NS_TOUT_TNS_TEST;</span><br><span style="color: hsl(120, 100%, 40%);">+       osmo_timer_schedule(&priv->alive.timer, nsi->timeout[NS_TOUT_TNS_TEST], 0);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       if (old_state != GPRS_NS2_ST_ALIVE)</span><br><span style="color: hsl(120, 100%, 40%);">+           priv->N = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     gprs_ns2_tx_alive(priv->vc);</span><br><span style="color: hsl(120, 100%, 40%);">+       ns2_nse_notify_unblocked(priv->vc, false);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void gprs_ns2_st_alive_onleave(struct osmo_fsm_inst *fi, uint32_t next_state)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   start_test_procedure(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%);">+static const struct osmo_fsm_state gprs_ns2_vc_states[] = {</span><br><span style="color: hsl(120, 100%, 40%);">+   [GPRS_NS2_ST_UNCONFIGURED] = {</span><br><span style="color: hsl(120, 100%, 40%);">+                .in_event_mask = S(GPRS_NS2_EV_START),</span><br><span style="color: hsl(120, 100%, 40%);">+                .out_state_mask = S(GPRS_NS2_ST_RESET) | S(GPRS_NS2_ST_ALIVE),</span><br><span style="color: hsl(120, 100%, 40%);">+                .name = "UNCONFIGURED",</span><br><span style="color: hsl(120, 100%, 40%);">+             .action = gprs_ns2_st_unconfigured,</span><br><span style="color: hsl(120, 100%, 40%);">+   },</span><br><span style="color: hsl(120, 100%, 40%);">+    [GPRS_NS2_ST_RESET] = {</span><br><span style="color: hsl(120, 100%, 40%);">+               .in_event_mask = S(GPRS_NS2_EV_RESET_ACK) | S(GPRS_NS2_EV_RESET),</span><br><span style="color: hsl(120, 100%, 40%);">+             .out_state_mask = S(GPRS_NS2_ST_RESET) |</span><br><span style="color: hsl(120, 100%, 40%);">+                                S(GPRS_NS2_ST_BLOCKED),</span><br><span style="color: hsl(120, 100%, 40%);">+             .name = "RESET",</span><br><span style="color: hsl(120, 100%, 40%);">+            .action = gprs_ns2_st_reset,</span><br><span style="color: hsl(120, 100%, 40%);">+          .onenter = gprs_ns2_st_reset_onenter,</span><br><span style="color: hsl(120, 100%, 40%);">+ },</span><br><span style="color: hsl(120, 100%, 40%);">+    [GPRS_NS2_ST_BLOCKED] = {</span><br><span style="color: hsl(120, 100%, 40%);">+             .in_event_mask = S(GPRS_NS2_EV_BLOCK) | S(GPRS_NS2_EV_BLOCK_ACK) |</span><br><span style="color: hsl(120, 100%, 40%);">+            S(GPRS_NS2_EV_UNBLOCK) | S(GPRS_NS2_EV_UNBLOCK_ACK),</span><br><span style="color: hsl(120, 100%, 40%);">+          .out_state_mask = S(GPRS_NS2_ST_RESET) |</span><br><span style="color: hsl(120, 100%, 40%);">+                                S(GPRS_NS2_ST_UNBLOCKED) |</span><br><span style="color: hsl(120, 100%, 40%);">+                            S(GPRS_NS2_ST_BLOCKED),</span><br><span style="color: hsl(120, 100%, 40%);">+             .name = "BLOCKED",</span><br><span style="color: hsl(120, 100%, 40%);">+          .action = gprs_ns2_st_blocked,</span><br><span style="color: hsl(120, 100%, 40%);">+                .onenter = gprs_ns2_st_blocked_onenter,</span><br><span style="color: hsl(120, 100%, 40%);">+       },</span><br><span style="color: hsl(120, 100%, 40%);">+    [GPRS_NS2_ST_UNBLOCKED] = {</span><br><span style="color: hsl(120, 100%, 40%);">+           .in_event_mask = S(GPRS_NS2_EV_BLOCK),</span><br><span style="color: hsl(120, 100%, 40%);">+                .out_state_mask = S(GPRS_NS2_ST_RESET) | S(GPRS_NS2_ST_ALIVE) |</span><br><span style="color: hsl(120, 100%, 40%);">+                                 S(GPRS_NS2_ST_BLOCKED),</span><br><span style="color: hsl(120, 100%, 40%);">+             .name = "UNBLOCKED",</span><br><span style="color: hsl(120, 100%, 40%);">+                .action = gprs_ns2_st_unblocked,</span><br><span style="color: hsl(120, 100%, 40%);">+              .onenter = gprs_ns2_st_unblocked_on_enter,</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%);">+  /* ST_ALIVE is only used on VC without RESET/BLOCK */</span><br><span style="color: hsl(120, 100%, 40%);">+ [GPRS_NS2_ST_ALIVE] = {</span><br><span style="color: hsl(120, 100%, 40%);">+               .in_event_mask = S(GPRS_NS2_EV_ALIVE_ACK),</span><br><span style="color: hsl(120, 100%, 40%);">+            .out_state_mask = S(GPRS_NS2_ST_RESET) |</span><br><span style="color: hsl(120, 100%, 40%);">+                                S(GPRS_NS2_ST_UNBLOCKED),</span><br><span style="color: hsl(120, 100%, 40%);">+           .name = "ALIVE",</span><br><span style="color: hsl(120, 100%, 40%);">+            .action = gprs_ns2_st_alive,</span><br><span style="color: hsl(120, 100%, 40%);">+          .onenter = gprs_ns2_st_alive_onenter,</span><br><span style="color: hsl(120, 100%, 40%);">+         .onleave = gprs_ns2_st_alive_onleave,</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 gprs_ns2_vc_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 gprs_ns2_inst *nsi = ns_inst_from_fi(fi);</span><br><span style="color: hsl(120, 100%, 40%);">+      struct gprs_ns2_vc_priv *priv = fi->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        if (priv->initiater) {</span><br><span style="color: hsl(120, 100%, 40%);">+             /* PCU timeouts */</span><br><span style="color: hsl(120, 100%, 40%);">+            switch (fi->state) {</span><br><span style="color: hsl(120, 100%, 40%);">+               case GPRS_NS2_ST_RESET:</span><br><span style="color: hsl(120, 100%, 40%);">+                       priv->N++;</span><br><span style="color: hsl(120, 100%, 40%);">+                 if (priv->N <= nsi->timeout[NS_TOUT_TNS_RESET_RETRIES]) {</span><br><span style="color: hsl(120, 100%, 40%);">+                            osmo_fsm_inst_state_chg(fi, GPRS_NS2_ST_RESET, nsi->timeout[NS_TOUT_TNS_RESET], 0);</span><br><span style="color: hsl(120, 100%, 40%);">+                        } else {</span><br><span style="color: hsl(120, 100%, 40%);">+                              priv->N = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+                               osmo_fsm_inst_state_chg(fi, GPRS_NS2_ST_RESET, nsi->timeout[NS_TOUT_TNS_RESET], 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 GPRS_NS2_ST_BLOCKED:</span><br><span style="color: hsl(120, 100%, 40%);">+                     priv->N++;</span><br><span style="color: hsl(120, 100%, 40%);">+                 if (priv->N <= nsi->timeout[NS_TOUT_TNS_BLOCK_RETRIES]) {</span><br><span style="color: hsl(120, 100%, 40%);">+                            osmo_fsm_inst_state_chg(fi, GPRS_NS2_ST_BLOCKED, nsi->timeout[NS_TOUT_TNS_BLOCK], 0);</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, GPRS_NS2_ST_RESET, nsi->timeout[NS_TOUT_TNS_RESET], 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 GPRS_NS2_ST_ALIVE:</span><br><span style="color: hsl(120, 100%, 40%);">+                       priv->N++;</span><br><span style="color: hsl(120, 100%, 40%);">+                 if (priv->N <= nsi->timeout[NS_TOUT_TNS_ALIVE_RETRIES]) {</span><br><span style="color: hsl(120, 100%, 40%);">+                            osmo_fsm_inst_state_chg(fi, GPRS_NS2_ST_ALIVE, 0, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+                 } else {</span><br><span style="color: hsl(120, 100%, 40%);">+                              priv->N = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+                               osmo_fsm_inst_state_chg(fi, GPRS_NS2_ST_ALIVE, 0, 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%);">+                }</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+     return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void gprs_ns2_recv_unitdata(struct osmo_fsm_inst *fi,</span><br><span style="color: hsl(120, 100%, 40%);">+                             struct msgb *msg)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       struct gprs_ns2_inst *nsi = ns_inst_from_fi(fi);</span><br><span style="color: hsl(120, 100%, 40%);">+      struct gprs_ns2_vc_priv *priv = fi->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+  struct gprs_ns_hdr *nsh = (struct gprs_ns_hdr *) msg->l2h;</span><br><span style="color: hsl(120, 100%, 40%);">+</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%);">+      if (msgb_l2len(msg) < sizeof(*nsh) + 3)</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%);">+     /* TODO: 7.1: For an IP sub-network, an NS-UNITDATA PDU for a PTP BVC may indicate a request to change the IP endpoint</span><br><span style="color: hsl(120, 100%, 40%);">+         * and/or a response to a change in the IP endpoint. */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     /* TODO: nsh->data[0] -> C/R only valid in IP SNS */</span><br><span style="color: hsl(120, 100%, 40%);">+    bvci = nsh->data[1] << 8 | nsh->data[2];</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        msgb_bssgph(msg) = &nsh->data[3];</span><br><span style="color: hsl(120, 100%, 40%);">+      msgb_bvci(msg) = bvci;</span><br><span style="color: hsl(120, 100%, 40%);">+        msgb_nsei(msg) = priv->vc->nse->nsei;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      nsi->cb(GPRS_NS_EVT_UNIT_DATA, msg, priv->vc->nse->nsei, 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 void gprs_ns2_vc_fsm_allstate_action(struct osmo_fsm_inst *fi,</span><br><span style="color: hsl(120, 100%, 40%);">+                                           uint32_t event,</span><br><span style="color: hsl(120, 100%, 40%);">+                                       void *data)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    struct gprs_ns2_vc_priv *priv = fi->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+  struct gprs_ns2_inst *nsi = ns_inst_from_fi(fi);</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 GPRS_NS2_EV_RESET:</span><br><span style="color: hsl(120, 100%, 40%);">+               if (priv->vc->mode != NS2_VC_MODE_BLOCKRESET)</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%);">+              /* move the FSM into reset */</span><br><span style="color: hsl(120, 100%, 40%);">+         if (fi->state != GPRS_NS2_ST_RESET) {</span><br><span style="color: hsl(120, 100%, 40%);">+                      priv->initiater = false;</span><br><span style="color: hsl(120, 100%, 40%);">+                   osmo_fsm_inst_state_chg(fi, GPRS_NS2_ST_RESET, nsi->timeout[NS_TOUT_TNS_RESET], NS_TOUT_TNS_RESET);</span><br><span style="color: hsl(120, 100%, 40%);">+                }</span><br><span style="color: hsl(120, 100%, 40%);">+             /* pass the event down into FSM action */</span><br><span style="color: hsl(120, 100%, 40%);">+             gprs_ns2_st_reset(fi, event, data);</span><br><span style="color: hsl(120, 100%, 40%);">+           break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case GPRS_NS2_EV_ALIVE:</span><br><span style="color: hsl(120, 100%, 40%);">+               switch (fi->state) {</span><br><span style="color: hsl(120, 100%, 40%);">+               case GPRS_NS2_ST_UNCONFIGURED:</span><br><span style="color: hsl(120, 100%, 40%);">+                case GPRS_NS2_ST_RESET:</span><br><span style="color: hsl(120, 100%, 40%);">+                       /* ignore ALIVE */</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%);">+                      gprs_ns2_tx_alive_ack(priv->vc);</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 GPRS_NS2_EV_ALIVE_ACK:</span><br><span style="color: hsl(120, 100%, 40%);">+           /* for VCs without RESET/BLOCK/UNBLOCK, the connections comes after ALIVE_ACK unblocked */</span><br><span style="color: hsl(120, 100%, 40%);">+            if (fi->state == GPRS_NS2_ST_ALIVE)</span><br><span style="color: hsl(120, 100%, 40%);">+                        gprs_ns2_st_alive(fi, event, data);</span><br><span style="color: hsl(120, 100%, 40%);">+           else</span><br><span style="color: hsl(120, 100%, 40%);">+                  recv_test_procedure(fi);</span><br><span style="color: hsl(120, 100%, 40%);">+              break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case GPRS_NS2_EV_UNITDATA:</span><br><span style="color: hsl(120, 100%, 40%);">+            switch (fi->state) {</span><br><span style="color: hsl(120, 100%, 40%);">+               case GPRS_NS2_ST_BLOCKED:</span><br><span style="color: hsl(120, 100%, 40%);">+                     /* 7.2.1: the BLOCKED_ACK might be lost */</span><br><span style="color: hsl(120, 100%, 40%);">+                    if (priv->initiater)</span><br><span style="color: hsl(120, 100%, 40%);">+                               gprs_ns2_recv_unitdata(fi, data);</span><br><span style="color: hsl(120, 100%, 40%);">+                     else</span><br><span style="color: hsl(120, 100%, 40%);">+                          gprs_ns2_tx_status(priv->vc,</span><br><span style="color: hsl(120, 100%, 40%);">+                                                  NS_CAUSE_NSVC_BLOCKED,</span><br><span style="color: hsl(120, 100%, 40%);">+                                                0, data);</span><br><span style="color: hsl(120, 100%, 40%);">+                  break;</span><br><span style="color: hsl(120, 100%, 40%);">+                /* ALIVE can receive UNITDATA if the ALIVE_ACK is lost */</span><br><span style="color: hsl(120, 100%, 40%);">+             case GPRS_NS2_ST_ALIVE:</span><br><span style="color: hsl(120, 100%, 40%);">+               case GPRS_NS2_ST_UNBLOCKED:</span><br><span style="color: hsl(120, 100%, 40%);">+                   gprs_ns2_recv_unitdata(fi, data);</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%);">+        }</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 gprs_ns2_vc_fsm = {</span><br><span style="color: hsl(120, 100%, 40%);">+    .name = "GPRS-NS2-VC",</span><br><span style="color: hsl(120, 100%, 40%);">+      .states = gprs_ns2_vc_states,</span><br><span style="color: hsl(120, 100%, 40%);">+ .num_states = ARRAY_SIZE(gprs_ns2_vc_states),</span><br><span style="color: hsl(120, 100%, 40%);">+ .allstate_event_mask = S(GPRS_NS2_EV_UNITDATA) |</span><br><span style="color: hsl(120, 100%, 40%);">+                      S(GPRS_NS2_EV_RESET) |</span><br><span style="color: hsl(120, 100%, 40%);">+                               S(GPRS_NS2_EV_ALIVE) |</span><br><span style="color: hsl(120, 100%, 40%);">+                        S(GPRS_NS2_EV_ALIVE_ACK),</span><br><span style="color: hsl(120, 100%, 40%);">+      .allstate_action = gprs_ns2_vc_fsm_allstate_action,</span><br><span style="color: hsl(120, 100%, 40%);">+   .cleanup = NULL,</span><br><span style="color: hsl(120, 100%, 40%);">+      .timer_cb = gprs_ns2_vc_fsm_timer_cb,</span><br><span style="color: hsl(120, 100%, 40%);">+ /* .log_subsys = DNS, "is not constant" */</span><br><span style="color: hsl(120, 100%, 40%);">+  .event_names = gprs_ns2_vc_event_names,</span><br><span style="color: hsl(120, 100%, 40%);">+       .pre_term = 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%);">+/*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief gprs_ns2_vc_fsm_alloc</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param ctx</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param vc</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param id a char representation of the virtual curcuit</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param initiater initiater is the site which starts the connection. Usually the BSS.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \return NULL on error, otherwise the fsm</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+struct osmo_fsm_inst *gprs_ns2_vc_fsm_alloc(struct gprs_ns2_vc *vc,</span><br><span style="color: hsl(120, 100%, 40%);">+                                     const char *id, bool initiater)</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 gprs_ns2_vc_priv *priv;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      fi = osmo_fsm_inst_alloc(&gprs_ns2_vc_fsm, vc, NULL, LOGL_DEBUG, id);</span><br><span style="color: hsl(120, 100%, 40%);">+     if (!fi)</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%);">+  vc->fi = fi;</span><br><span style="color: hsl(120, 100%, 40%);">+       priv = fi->priv = talloc_zero(fi, struct gprs_ns2_vc_priv);</span><br><span style="color: hsl(120, 100%, 40%);">+        priv->vc = vc;</span><br><span style="color: hsl(120, 100%, 40%);">+     priv->initiater = initiater;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     osmo_timer_setup(&priv->alive.timer, alive_timeout_handler, fi);</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%);">+/*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief gprs_ns2_vc_fsm_start start the FSM</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param vc the virtual circuit</span><br><span style="color: hsl(120, 100%, 40%);">+ * \return 0 on success</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+int gprs_ns2_vc_fsm_start(struct gprs_ns2_vc *nsvc)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   /* allows to call this function even for started nsvc by gprs_ns2_start_alive_all_nsvcs */</span><br><span style="color: hsl(120, 100%, 40%);">+    if (nsvc->fi->state == GPRS_NS2_ST_UNCONFIGURED)</span><br><span style="color: hsl(120, 100%, 40%);">+                return osmo_fsm_inst_dispatch(nsvc->fi, GPRS_NS2_EV_START, NULL);</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%);">+ * \brief gprs_ns2_vc_rx entry point for messages from the driver/VL</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param vc the virtual circuit on which is recived</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param msg the message</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param tp the parsed TLVs</span><br><span style="color: hsl(120, 100%, 40%);">+ * \return 0 on success</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+int gprs_ns2_vc_rx(struct gprs_ns2_vc *vc, struct msgb *msg, struct tlv_parsed *tp)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        struct gprs_ns_hdr *nsh = (struct gprs_ns_hdr *) msg->l2h;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_fsm_inst *fi = vc->fi;</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%);">+      /* TODO: 7.2: on UNBLOCK/BLOCK: check if NS-VCI is correct, if not answer STATUS with "NS-VC unknown" */</span><br><span style="color: hsl(120, 100%, 40%);">+    /* TODO: handle RESET with different VCI */</span><br><span style="color: hsl(120, 100%, 40%);">+   /* TODO: handle BLOCK/UNBLOCK/ALIVE with different VCI */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   OSMO_ASSERT(vc);</span><br><span style="color: hsl(120, 100%, 40%);">+      OSMO_ASSERT(fi);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    if (gprs_ns2_validate(vc, nsh->pdu_type, msg, tp, &cause)) {</span><br><span style="color: hsl(120, 100%, 40%);">+           if (nsh->pdu_type != NS_PDUT_STATUS) {</span><br><span style="color: hsl(120, 100%, 40%);">+                     return gprs_ns2_tx_status(vc, cause, 0, 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%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   switch (nsh->pdu_type) {</span><br><span style="color: hsl(120, 100%, 40%);">+   case NS_PDUT_RESET:</span><br><span style="color: hsl(120, 100%, 40%);">+           osmo_fsm_inst_dispatch(fi, GPRS_NS2_EV_RESET, tp);</span><br><span style="color: hsl(120, 100%, 40%);">+            break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case NS_PDUT_RESET_ACK:</span><br><span style="color: hsl(120, 100%, 40%);">+               osmo_fsm_inst_dispatch(fi, GPRS_NS2_EV_RESET_ACK, tp);</span><br><span style="color: hsl(120, 100%, 40%);">+                break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case NS_PDUT_BLOCK:</span><br><span style="color: hsl(120, 100%, 40%);">+           osmo_fsm_inst_dispatch(fi, GPRS_NS2_EV_BLOCK, tp);</span><br><span style="color: hsl(120, 100%, 40%);">+            break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case NS_PDUT_BLOCK_ACK:</span><br><span style="color: hsl(120, 100%, 40%);">+               osmo_fsm_inst_dispatch(fi, GPRS_NS2_EV_BLOCK_ACK, tp);</span><br><span style="color: hsl(120, 100%, 40%);">+                break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case NS_PDUT_UNBLOCK:</span><br><span style="color: hsl(120, 100%, 40%);">+         osmo_fsm_inst_dispatch(fi, GPRS_NS2_EV_UNBLOCK, tp);</span><br><span style="color: hsl(120, 100%, 40%);">+          break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case NS_PDUT_UNBLOCK_ACK:</span><br><span style="color: hsl(120, 100%, 40%);">+             osmo_fsm_inst_dispatch(fi, GPRS_NS2_EV_UNBLOCK_ACK, tp);</span><br><span style="color: hsl(120, 100%, 40%);">+              break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case NS_PDUT_ALIVE:</span><br><span style="color: hsl(120, 100%, 40%);">+           osmo_fsm_inst_dispatch(fi, GPRS_NS2_EV_ALIVE, tp);</span><br><span style="color: hsl(120, 100%, 40%);">+            break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case NS_PDUT_ALIVE_ACK:</span><br><span style="color: hsl(120, 100%, 40%);">+               osmo_fsm_inst_dispatch(fi, GPRS_NS2_EV_ALIVE_ACK, tp);</span><br><span style="color: hsl(120, 100%, 40%);">+                break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case NS_PDUT_UNITDATA:</span><br><span style="color: hsl(120, 100%, 40%);">+                osmo_fsm_inst_dispatch(fi, GPRS_NS2_EV_UNITDATA, msg);</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%);">+              LOGP(DNS, LOGL_ERROR, "NSEI=%u Rx unknown NS PDU type %s\n", vc->nse->nsei,</span><br><span style="color: hsl(120, 100%, 40%);">+                   get_value_string(gprs_ns_pdu_strings, nsh->pdu_type));</span><br><span style="color: hsl(120, 100%, 40%);">+             return -EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return 0;</span><br><span 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%);">+ * \brief gprs_ns2_vc_fsm_init must be called once in a library/executable</span><br><span style="color: hsl(120, 100%, 40%);">+ * \return 0 on success</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+int gprs_ns2_vc_fsm_init(void)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      /* "DNS" is not a constant/#define, but an integer variable set by the client app */</span><br><span style="color: hsl(120, 100%, 40%);">+        gprs_ns2_vc_fsm.log_subsys = DNS;</span><br><span style="color: hsl(120, 100%, 40%);">+     return osmo_fsm_register(&gprs_ns2_vc_fsm);</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%);">+ * \brief gprs_ns2_vc_is_alive says if this</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param vc</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%);">+int gprs_ns2_vc_is_unblocked(struct gprs_ns2_vc *vc)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        return (vc->fi->state == GPRS_NS2_ST_UNBLOCKED);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span>diff --git a/src/gb/gprs_ns2_vc_fsm.h b/src/gb/gprs_ns2_vc_fsm.h</span><br><span>new file mode 100644</span><br><span>index 0000000..7a67181</span><br><span>--- /dev/null</span><br><span>+++ b/src/gb/gprs_ns2_vc_fsm.h</span><br><span>@@ -0,0 +1,16 @@</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#pragma once</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <stdbool.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct gprs_ns2_vc;</span><br><span style="color: hsl(120, 100%, 40%);">+struct msgb;</span><br><span style="color: hsl(120, 100%, 40%);">+struct tlv_parsed;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int gprs_ns2_vc_fsm_init(void);</span><br><span style="color: hsl(120, 100%, 40%);">+struct osmo_fsm_inst *gprs_ns2_vc_fsm_alloc(struct gprs_ns2_vc *vc,</span><br><span style="color: hsl(120, 100%, 40%);">+                                           const char *id, bool initiate);</span><br><span style="color: hsl(120, 100%, 40%);">+int gprs_ns2_vc_fsm_start(struct gprs_ns2_vc *vc);</span><br><span style="color: hsl(120, 100%, 40%);">+int gprs_ns2_vc_rx(struct gprs_ns2_vc *vc, struct msgb *msg, struct tlv_parsed *tp);</span><br><span style="color: hsl(120, 100%, 40%);">+int gprs_ns2_vc_is_alive(struct gprs_ns2_vc *vc);</span><br><span style="color: hsl(120, 100%, 40%);">+int gprs_ns2_vc_is_unblocked(struct gprs_ns2_vc *vc);</span><br><span>diff --git a/src/gb/gprs_ns2_vty.c b/src/gb/gprs_ns2_vty.c</span><br><span>new file mode 100644</span><br><span>index 0000000..9e6e5b9</span><br><span>--- /dev/null</span><br><span>+++ b/src/gb/gprs_ns2_vty.c</span><br><span>@@ -0,0 +1,851 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/*! \file gprs_ns_vty.c</span><br><span style="color: hsl(120, 100%, 40%);">+ * VTY interface for our GPRS Networks Service (NS) implementation. */</span><br><span style="color: hsl(120, 100%, 40%);">+/*</span><br><span style="color: hsl(120, 100%, 40%);">+ * (C) 2009-2014 by Harald Welte <laforge@gnumonks.org></span><br><span style="color: hsl(120, 100%, 40%);">+ * (C) 2016-2017 by sysmocom - s.f.m.c. GmbH</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%);">+ * All Rights Reserved</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * SPDX-License-Identifier: GPL-2.0+</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This program is free software; you can redistribute it and/or modify</span><br><span style="color: hsl(120, 100%, 40%);">+ * it under the terms of the GNU General Public License as published by</span><br><span style="color: hsl(120, 100%, 40%);">+ * the Free Software Foundation; either version 2 of the License, or</span><br><span style="color: hsl(120, 100%, 40%);">+ * (at your option) any later version.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This program is distributed in the hope that it will be useful,</span><br><span style="color: hsl(120, 100%, 40%);">+ * but WITHOUT ANY WARRANTY; without even the implied warranty of</span><br><span style="color: hsl(120, 100%, 40%);">+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the</span><br><span style="color: hsl(120, 100%, 40%);">+ * GNU General Public License for more details.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * You should have received a copy of the GNU General Public License</span><br><span style="color: hsl(120, 100%, 40%);">+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.</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%);">+#include <stdlib.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <unistd.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <errno.h></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 <arpa/inet.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/msgb.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/gsm/tlv.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/talloc.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/select.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/rate_ctr.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/socket.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/sockaddr_str.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/linuxlist.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/core/socket.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/vty/vty.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/vty/command.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/vty/logging.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/vty/telnet_interface.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/vty/misc.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include "gprs_ns2_internal.h"</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%);">+struct ns2_vty_priv {</span><br><span style="color: hsl(120, 100%, 40%);">+ /* global listen */</span><br><span style="color: hsl(120, 100%, 40%);">+   struct osmo_sockaddr_str udp;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_sockaddr_str frgreaddr;</span><br><span style="color: hsl(120, 100%, 40%);">+   int dscp;</span><br><span style="color: hsl(120, 100%, 40%);">+     bool use_reset_block_unblock;</span><br><span style="color: hsl(120, 100%, 40%);">+ bool frgre;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ struct llist_head vtyvc;</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 ns2_vty_vc {</span><br><span style="color: hsl(120, 100%, 40%);">+   struct llist_head list;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     struct osmo_sockaddr_str remote;</span><br><span style="color: hsl(120, 100%, 40%);">+      enum gprs_ns_ll ll;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* old vty code doesnt support multiple NSVCI per NSEI */</span><br><span style="color: hsl(120, 100%, 40%);">+     uint16_t nsei;</span><br><span style="color: hsl(120, 100%, 40%);">+        uint16_t nsvci;</span><br><span style="color: hsl(120, 100%, 40%);">+       uint16_t frdlci;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    bool remote_end_is_sgsn;</span><br><span style="color: hsl(120, 100%, 40%);">+      bool configured;</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 gprs_ns2_inst *vty_nsi = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+static struct ns2_vty_priv priv;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* FIXME: this should go to some common file as it is copied</span><br><span style="color: hsl(120, 100%, 40%);">+ * in vty_interface.c of the BSC */</span><br><span style="color: hsl(120, 100%, 40%);">+static const struct value_string gprs_ns_timer_strs[] = {</span><br><span style="color: hsl(120, 100%, 40%);">+        { 0, "tns-block" },</span><br><span style="color: hsl(120, 100%, 40%);">+ { 1, "tns-block-retries" },</span><br><span style="color: hsl(120, 100%, 40%);">+ { 2, "tns-reset" },</span><br><span style="color: hsl(120, 100%, 40%);">+ { 3, "tns-reset-retries" },</span><br><span style="color: hsl(120, 100%, 40%);">+ { 4, "tns-test" },</span><br><span style="color: hsl(120, 100%, 40%);">+  { 5, "tns-alive" },</span><br><span style="color: hsl(120, 100%, 40%);">+ { 6, "tns-alive-retries" },</span><br><span style="color: hsl(120, 100%, 40%);">+ { 7, "tsns-prov" },</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%);">+static void log_set_nsvc_filter(struct log_target *target,</span><br><span style="color: hsl(120, 100%, 40%);">+                         struct gprs_ns2_vc *nsvc)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  if (nsvc) {</span><br><span style="color: hsl(120, 100%, 40%);">+           target->filter_map |= (1 << LOG_FLT_GB_NSVC);</span><br><span style="color: hsl(120, 100%, 40%);">+                target->filter_data[LOG_FLT_GB_NSVC] = nsvc;</span><br><span style="color: hsl(120, 100%, 40%);">+       } else if (target->filter_data[LOG_FLT_GB_NSVC]) {</span><br><span style="color: hsl(120, 100%, 40%);">+         target->filter_map = ~(1 << LOG_FLT_GB_NSVC);</span><br><span style="color: hsl(120, 100%, 40%);">+                target->filter_data[LOG_FLT_GB_NSVC] = 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%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static struct cmd_node ns_node = {</span><br><span style="color: hsl(120, 100%, 40%);">+    L_NS_NODE,</span><br><span style="color: hsl(120, 100%, 40%);">+    "%s(config-ns)# ",</span><br><span style="color: hsl(120, 100%, 40%);">+  1,</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 ns2_vty_vc *vtyvc_alloc(uint16_t nsei) {</span><br><span style="color: hsl(120, 100%, 40%);">+      struct ns2_vty_vc *vtyvc = talloc_zero(vty_nsi, struct ns2_vty_vc);</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!vtyvc)</span><br><span style="color: hsl(120, 100%, 40%);">+           return vtyvc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       vtyvc->nsei = nsei;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      llist_add(&vtyvc->list, &priv.vtyvc);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void ns2_vc_free(struct ns2_vty_vc *vtyvc) {</span><br><span style="color: hsl(120, 100%, 40%);">+        if (!vtyvc)</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%);">+     llist_del(&vtyvc->list);</span><br><span style="color: hsl(120, 100%, 40%);">+       talloc_free(vtyvc);</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 ns2_vty_vc *vtyvc_by_nsvci(uint16_t nsvci) {</span><br><span style="color: hsl(120, 100%, 40%);">+  struct ns2_vty_vc *vtyvc;</span><br><span style="color: hsl(120, 100%, 40%);">+     llist_for_each_entry(vtyvc, &priv.vtyvc, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+          if (vtyvc->nsvci == nsvci)</span><br><span style="color: hsl(120, 100%, 40%);">+                 return vtyvc;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static struct ns2_vty_vc *vtyvc_by_nsei(uint16_t nsei, bool alloc_missing) {</span><br><span style="color: hsl(120, 100%, 40%);">+       struct ns2_vty_vc *vtyvc;</span><br><span style="color: hsl(120, 100%, 40%);">+     llist_for_each_entry(vtyvc, &priv.vtyvc, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+          if (vtyvc->nsei == nsei)</span><br><span style="color: hsl(120, 100%, 40%);">+                   return vtyvc;</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 (alloc_missing) {</span><br><span style="color: hsl(120, 100%, 40%);">+          vtyvc = vtyvc_alloc(nsei);</span><br><span style="color: hsl(120, 100%, 40%);">+            if (!vtyvc)</span><br><span style="color: hsl(120, 100%, 40%);">+                   return vtyvc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+               vtyvc->nsei = nsei;</span><br><span style="color: hsl(120, 100%, 40%);">+        }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int config_write_ns(struct vty *vty)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     struct ns2_vty_vc *vtyvc;</span><br><span style="color: hsl(120, 100%, 40%);">+     unsigned int i;</span><br><span style="color: hsl(120, 100%, 40%);">+       struct osmo_sockaddr_str sockstr;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   vty_out(vty, "ns%s", VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        /* global configuration must be written first, as some of it may be</span><br><span style="color: hsl(120, 100%, 40%);">+    * relevant when creating the NSE/NSVC later below */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       vty_out(vty, " encapsulation framerelay-gre enabled %u%s",</span><br><span style="color: hsl(120, 100%, 40%);">+          priv.frgre ? 1 : 0, VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (priv.frgre) {</span><br><span style="color: hsl(120, 100%, 40%);">+             if (strlen(priv.frgreaddr.ip)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                      vty_out(vty, " encapsulation framerelay-gre local-ip %s%s",</span><br><span style="color: hsl(120, 100%, 40%);">+                         sockstr.ip, VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+             }</span><br><span style="color: hsl(120, 100%, 40%);">+     } else {</span><br><span style="color: hsl(120, 100%, 40%);">+              if (strlen(priv.udp.ip)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                    vty_out(vty, " encapsulation udp local-ip %s%s",</span><br><span style="color: hsl(120, 100%, 40%);">+                            priv.udp.ip, VTY_NEWLINE);</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 (priv.udp.port)</span><br><span style="color: hsl(120, 100%, 40%);">+                    vty_out(vty, " encapsulation udp local-port %u%s",</span><br><span style="color: hsl(120, 100%, 40%);">+                          priv.udp.port, VTY_NEWLINE);</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 (priv.dscp)</span><br><span style="color: hsl(120, 100%, 40%);">+                vty_out(vty, " encapsulation udp dscp %d%s",</span><br><span style="color: hsl(120, 100%, 40%);">+                        priv.dscp, VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    vty_out(vty, " encapsulation udp use-reset-block-unblock %s%s",</span><br><span style="color: hsl(120, 100%, 40%);">+             priv.use_reset_block_unblock ? "enabled" : "disabled", VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    llist_for_each_entry(vtyvc, &priv.vtyvc, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+          vty_out(vty, " nse %u nsvci %u%s",</span><br><span style="color: hsl(120, 100%, 40%);">+                  vtyvc->nsei, vtyvc->nsvci, VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+              vty_out(vty, " nse %u remote-role %s%s",</span><br><span style="color: hsl(120, 100%, 40%);">+                    vtyvc->nsei, vtyvc->remote_end_is_sgsn ? "sgsn" : "bss",</span><br><span style="color: hsl(120, 100%, 40%);">+                    VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+               switch (vtyvc->ll) {</span><br><span style="color: hsl(120, 100%, 40%);">+               case GPRS_NS_LL_UDP:</span><br><span style="color: hsl(120, 100%, 40%);">+                  vty_out(vty, " nse %u encapsulation udp%s", vtyvc->nsei, VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+                   vty_out(vty, " nse %u remote-ip %s%s",</span><br><span style="color: hsl(120, 100%, 40%);">+                              vtyvc->nsei,</span><br><span style="color: hsl(120, 100%, 40%);">+                               vtyvc->remote.ip,</span><br><span style="color: hsl(120, 100%, 40%);">+                          VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+                 vty_out(vty, " nse %u remote-port %u%s",</span><br><span style="color: hsl(120, 100%, 40%);">+                            vtyvc->nsei, vtyvc->remote.port,</span><br><span style="color: hsl(120, 100%, 40%);">+                                VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+                 break;</span><br><span style="color: hsl(120, 100%, 40%);">+                case GPRS_NS_LL_FR_GRE:</span><br><span style="color: hsl(120, 100%, 40%);">+                       //                              vty_out(vty, " nse %u encapsulation framerelay-gre%s",</span><br><span style="color: hsl(120, 100%, 40%);">+                      //                                      nse->nsei, VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+                   //                              vty_out(vty, " nse %u remote-ip %s%s",</span><br><span style="color: hsl(120, 100%, 40%);">+                      //                                      nse->nsei,</span><br><span style="color: hsl(120, 100%, 40%);">+                 //                                      inet_ntoa(nsvc->frgre.bts_addr.sin_addr),</span><br><span style="color: hsl(120, 100%, 40%);">+                  //                                      VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+                 //                              vty_out(vty, " nse %u fr-dlci %u%s",</span><br><span style="color: hsl(120, 100%, 40%);">+                        //                                      nsvc->nsei, osmo_ntohs(nsvc->frgre.bts_addr.sin_port),</span><br><span style="color: hsl(120, 100%, 40%);">+                  //                                      VTY_NEWLINE);</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%);">+                      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%);">+   for (i = 0; i < ARRAY_SIZE(vty_nsi->timeout); i++)</span><br><span style="color: hsl(120, 100%, 40%);">+              vty_out(vty, " timer %s %u%s",</span><br><span style="color: hsl(120, 100%, 40%);">+                      get_value_string(gprs_ns_timer_strs, i),</span><br><span style="color: hsl(120, 100%, 40%);">+                      vty_nsi->timeout[i], VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       return CMD_SUCCESS;</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%);">+DEFUN(cfg_ns, cfg_ns_cmd,</span><br><span style="color: hsl(120, 100%, 40%);">+      "ns",</span><br><span style="color: hsl(120, 100%, 40%);">+      "Configure the GPRS Network Service")</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  vty->node = L_NS_NODE;</span><br><span style="color: hsl(120, 100%, 40%);">+     return CMD_SUCCESS;</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 dump_nse(struct vty *vty, const struct gprs_ns2_nse *nse, bool stats, bool persistent_only)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  struct gprs_ns2_vc *nsvc;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct osmo_sockaddr_str remote;</span><br><span style="color: hsl(120, 100%, 40%);">+      struct osmo_sockaddr_str local;</span><br><span style="color: hsl(120, 100%, 40%);">+       struct osmo_sockaddr *sockaddr;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     vty_out(vty, "NSEI %5u%s",</span><br><span style="color: hsl(120, 100%, 40%);">+          nse->nsei, VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ llist_for_each_entry(nsvc, &nse->vc, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+           switch (nsvc->ll) {</span><br><span style="color: hsl(120, 100%, 40%);">+                case GPRS_NS_LL_UDP: {</span><br><span style="color: hsl(120, 100%, 40%);">+                        sockaddr = gprs_ns2_ip_vc_sockaddr(nsvc);</span><br><span style="color: hsl(120, 100%, 40%);">+                     if (!sockaddr) {</span><br><span style="color: hsl(120, 100%, 40%);">+                              vty_out(vty, "unknown");</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%);">+                   if (osmo_sockaddr_str_from_sockaddr(</span><br><span style="color: hsl(120, 100%, 40%);">+                                          &remote,</span><br><span style="color: hsl(120, 100%, 40%);">+                                          &sockaddr->u.sas)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                           vty_out(vty, "unknown");</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%);">+                   vty_out(vty, "%s:%u <> %s:%u", local.ip, local.port, remote.ip, remote.port);</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%);">+             case GPRS_NS_LL_FR_GRE:</span><br><span style="color: hsl(120, 100%, 40%);">+               case GPRS_NS_LL_E1:</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%);">+//         vty_out(vty, "Remote: %-4s, %5s %9s, %s ",</span><br><span style="color: hsl(120, 100%, 40%);">+//                        nsvc->remote_end_is_sgsn ? "SGSN" : "BSS",</span><br><span style="color: hsl(120, 100%, 40%);">+//                   NS_DESC_A(nsvc->remote_state),</span><br><span style="color: hsl(120, 100%, 40%);">+//                   NS_DESC_B(nsvc->remote_state), gprs_ns2_ll_str(nsvc));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+//         vty_out(vty, "%s%s", nsvc->ll == GPRS_NS_LL_UDP ? "UDP" : "FR-GRE", VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+          if (stats) {</span><br><span style="color: hsl(120, 100%, 40%);">+                  vty_out_rate_ctr_group(vty, " ", nsvc->ctrg);</span><br><span style="color: hsl(120, 100%, 40%);">+                    vty_out_stat_item_group(vty, " ", nsvc->statg);</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 void dump_ns(struct vty *vty, const struct gprs_ns2_inst *nsi, bool stats, bool persistent_only)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    struct gprs_ns2_nse *nse;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   llist_for_each_entry(nse, &nsi->nse, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+           gprs_ns2_dump_vty(vty, nse, stats);</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%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+DEFUN(show_ns, show_ns_cmd, "show ns",</span><br><span style="color: hsl(120, 100%, 40%);">+    SHOW_STR "Display information about the NS protocol")</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    dump_ns(vty, vty_nsi, false, false);</span><br><span style="color: hsl(120, 100%, 40%);">+  return CMD_SUCCESS;</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%);">+DEFUN(show_ns_stats, show_ns_stats_cmd, "show ns stats",</span><br><span style="color: hsl(120, 100%, 40%);">+  SHOW_STR</span><br><span style="color: hsl(120, 100%, 40%);">+      "Display information about the NS protocol\n"</span><br><span style="color: hsl(120, 100%, 40%);">+       "Include statistics\n")</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  dump_ns(vty, vty_nsi, true, false);</span><br><span style="color: hsl(120, 100%, 40%);">+   return CMD_SUCCESS;</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%);">+DEFUN(show_ns_pers, show_ns_pers_cmd, "show ns persistent",</span><br><span style="color: hsl(120, 100%, 40%);">+       SHOW_STR</span><br><span style="color: hsl(120, 100%, 40%);">+      "Display information about the NS protocol\n"</span><br><span style="color: hsl(120, 100%, 40%);">+       "Show only persistent NS\n")</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     dump_ns(vty, vty_nsi, true, true);</span><br><span style="color: hsl(120, 100%, 40%);">+    return CMD_SUCCESS;</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%);">+DEFUN(show_nse, show_nse_cmd, "show ns (nsei|nsvc) <0-65535> [stats]",</span><br><span style="color: hsl(120, 100%, 40%);">+      SHOW_STR "Display information about the NS protocol\n"</span><br><span style="color: hsl(120, 100%, 40%);">+      "Select one NSE by its NSE Identifier\n"</span><br><span style="color: hsl(120, 100%, 40%);">+    "Select one NSE by its NS-VC Identifier\n"</span><br><span style="color: hsl(120, 100%, 40%);">+  "The Identifier of selected type\n"</span><br><span style="color: hsl(120, 100%, 40%);">+ "Include Statistics\n")</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  struct gprs_ns2_inst *nsi = vty_nsi;</span><br><span style="color: hsl(120, 100%, 40%);">+  struct gprs_ns2_nse *nse;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct gprs_ns2_vc *nsvc;</span><br><span style="color: hsl(120, 100%, 40%);">+     uint16_t id = atoi(argv[1]);</span><br><span style="color: hsl(120, 100%, 40%);">+  bool show_stats = false;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    if (argc >= 3)</span><br><span style="color: hsl(120, 100%, 40%);">+             show_stats = true;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  if (!strcmp(argv[0], "nsei")) {</span><br><span style="color: hsl(120, 100%, 40%);">+             nse = gprs_ns2_nse_by_nsei(nsi, id);</span><br><span style="color: hsl(120, 100%, 40%);">+          if (!nse) {</span><br><span style="color: hsl(120, 100%, 40%);">+                   return CMD_WARNING;</span><br><span style="color: hsl(120, 100%, 40%);">+           }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           dump_nse(vty, nse, show_stats, false);</span><br><span style="color: hsl(120, 100%, 40%);">+        } else {</span><br><span style="color: hsl(120, 100%, 40%);">+              nsvc = gprs_ns2_nsvc_by_nsvci(nsi, id);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+             if (!nsvc) {</span><br><span style="color: hsl(120, 100%, 40%);">+                  vty_out(vty, "No such NS Entity%s", VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+                   return CMD_WARNING;</span><br><span style="color: hsl(120, 100%, 40%);">+           }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           vty_out(vty, "TODO: dump nsvc%s", VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+             /* TODO: dump nsvc */</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 CMD_SUCCESS;</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%);">+#define NSE_CMD_STR "Persistent NS Entity\n" "NS Entity ID (NSEI)\n"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+DEFUN(cfg_nse_nsvc, cfg_nse_nsvci_cmd,</span><br><span style="color: hsl(120, 100%, 40%);">+  "nse <0-65535> nsvci <0-65535>",</span><br><span style="color: hsl(120, 100%, 40%);">+        NSE_CMD_STR</span><br><span style="color: hsl(120, 100%, 40%);">+   "NS Virtual Connection\n"</span><br><span style="color: hsl(120, 100%, 40%);">+   "NS Virtual Connection ID (NSVCI)\n"</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 ns2_vty_vc *vtyvc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   uint16_t nsei = atoi(argv[0]);</span><br><span style="color: hsl(120, 100%, 40%);">+        uint16_t nsvci = atoi(argv[1]);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     vtyvc = vtyvc_by_nsei(nsei, true);</span><br><span style="color: hsl(120, 100%, 40%);">+    if (!vtyvc) {</span><br><span style="color: hsl(120, 100%, 40%);">+         vty_out(vty, "Can not allocate space %s", VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+             return CMD_WARNING;</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   vtyvc->nsvci = nsvci;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    return CMD_SUCCESS;</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%);">+DEFUN(cfg_nse_remoteip, cfg_nse_remoteip_cmd,</span><br><span style="color: hsl(120, 100%, 40%);">+       "nse <0-65535> remote-ip " VTY_IPV46_CMD,</span><br><span style="color: hsl(120, 100%, 40%);">+     NSE_CMD_STR</span><br><span style="color: hsl(120, 100%, 40%);">+   "Remote IP Address\n"</span><br><span style="color: hsl(120, 100%, 40%);">+       "Remote IP Address\n")</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   uint16_t nsei = atoi(argv[0]);</span><br><span style="color: hsl(120, 100%, 40%);">+        struct ns2_vty_vc *vtyvc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   vtyvc = vtyvc_by_nsei(nsei, true);</span><br><span style="color: hsl(120, 100%, 40%);">+    if (!vtyvc) {</span><br><span style="color: hsl(120, 100%, 40%);">+         vty_out(vty, "Can not allocate space %s", VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+             return CMD_WARNING;</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   osmo_sockaddr_str_from_str2(&vtyvc->remote, argv[1]);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        return CMD_SUCCESS;</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%);">+DEFUN(cfg_nse_remoteport, cfg_nse_remoteport_cmd,</span><br><span style="color: hsl(120, 100%, 40%);">+   "nse <0-65535> remote-port <0-65535>",</span><br><span style="color: hsl(120, 100%, 40%);">+  NSE_CMD_STR</span><br><span style="color: hsl(120, 100%, 40%);">+   "Remote UDP Port\n"</span><br><span style="color: hsl(120, 100%, 40%);">+ "Remote UDP Port Number\n")</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      uint16_t nsei = atoi(argv[0]);</span><br><span style="color: hsl(120, 100%, 40%);">+        uint16_t port = atoi(argv[1]);</span><br><span style="color: hsl(120, 100%, 40%);">+        struct ns2_vty_vc *vtyvc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   vtyvc = vtyvc_by_nsei(nsei, true);</span><br><span style="color: hsl(120, 100%, 40%);">+    if (!vtyvc) {</span><br><span style="color: hsl(120, 100%, 40%);">+         vty_out(vty, "Can not allocate space %s", VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+             return CMD_WARNING;</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   vtyvc->remote.port = port;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       return CMD_SUCCESS;</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%);">+DEFUN(cfg_nse_fr_dlci, cfg_nse_fr_dlci_cmd,</span><br><span style="color: hsl(120, 100%, 40%);">+ "nse <0-65535> fr-dlci <16-1007>",</span><br><span style="color: hsl(120, 100%, 40%);">+      NSE_CMD_STR</span><br><span style="color: hsl(120, 100%, 40%);">+   "Frame Relay DLCI\n"</span><br><span style="color: hsl(120, 100%, 40%);">+        "Frame Relay DLCI Number\n")</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     uint16_t nsei = atoi(argv[0]);</span><br><span style="color: hsl(120, 100%, 40%);">+        uint16_t dlci = atoi(argv[1]);</span><br><span style="color: hsl(120, 100%, 40%);">+        struct ns2_vty_vc *vtyvc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   vtyvc = vtyvc_by_nsei(nsei, true);</span><br><span style="color: hsl(120, 100%, 40%);">+    if (!vtyvc) {</span><br><span style="color: hsl(120, 100%, 40%);">+         vty_out(vty, "Can not allocate space %s", VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+             return CMD_WARNING;</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (vtyvc->ll != GPRS_NS_LL_FR_GRE) {</span><br><span style="color: hsl(120, 100%, 40%);">+              vty_out(vty, "Warning: seting FR DLCI on non-FR NSE%s",</span><br><span style="color: hsl(120, 100%, 40%);">+                     VTY_NEWLINE);</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%);">+   vtyvc->frdlci = dlci;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    return CMD_SUCCESS;</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%);">+DEFUN(cfg_nse_encaps, cfg_nse_encaps_cmd,</span><br><span style="color: hsl(120, 100%, 40%);">+   "nse <0-65535> encapsulation (udp|framerelay-gre)",</span><br><span style="color: hsl(120, 100%, 40%);">+   NSE_CMD_STR</span><br><span style="color: hsl(120, 100%, 40%);">+   "Encapsulation for NS\n"</span><br><span style="color: hsl(120, 100%, 40%);">+    "UDP/IP Encapsulation\n" "Frame-Relay/GRE/IP Encapsulation\n")</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ uint16_t nsei = atoi(argv[0]);</span><br><span style="color: hsl(120, 100%, 40%);">+        struct ns2_vty_vc *vtyvc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   vtyvc = vtyvc_by_nsei(nsei, true);</span><br><span style="color: hsl(120, 100%, 40%);">+    if (!vtyvc) {</span><br><span style="color: hsl(120, 100%, 40%);">+         vty_out(vty, "Can not allocate space %s", VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+             return CMD_WARNING;</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!strcmp(argv[1], "udp"))</span><br><span style="color: hsl(120, 100%, 40%);">+                vtyvc->ll = GPRS_NS_LL_UDP;</span><br><span style="color: hsl(120, 100%, 40%);">+        else</span><br><span style="color: hsl(120, 100%, 40%);">+          vtyvc->ll = GPRS_NS_LL_FR_GRE;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return CMD_SUCCESS;</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%);">+DEFUN(cfg_nse_remoterole, cfg_nse_remoterole_cmd,</span><br><span style="color: hsl(120, 100%, 40%);">+   "nse <0-65535> remote-role (sgsn|bss)",</span><br><span style="color: hsl(120, 100%, 40%);">+       NSE_CMD_STR</span><br><span style="color: hsl(120, 100%, 40%);">+   "Remote NSE Role\n"</span><br><span style="color: hsl(120, 100%, 40%);">+ "Remote Peer is SGSN\n"</span><br><span style="color: hsl(120, 100%, 40%);">+     "Remote Peer is BSS\n")</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  uint16_t nsei = atoi(argv[0]);</span><br><span style="color: hsl(120, 100%, 40%);">+        struct ns2_vty_vc *vtyvc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   vtyvc = vtyvc_by_nsei(nsei, true);</span><br><span style="color: hsl(120, 100%, 40%);">+    if (!vtyvc) {</span><br><span style="color: hsl(120, 100%, 40%);">+         vty_out(vty, "Can not allocate space %s", VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+             return CMD_WARNING;</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!strcmp(argv[1], "sgsn"))</span><br><span style="color: hsl(120, 100%, 40%);">+               vtyvc->remote_end_is_sgsn = 1;</span><br><span style="color: hsl(120, 100%, 40%);">+     else</span><br><span style="color: hsl(120, 100%, 40%);">+          vtyvc->remote_end_is_sgsn = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return CMD_SUCCESS;</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%);">+DEFUN(cfg_no_nse, cfg_no_nse_cmd,</span><br><span style="color: hsl(120, 100%, 40%);">+   "no nse <0-65535>",</span><br><span style="color: hsl(120, 100%, 40%);">+   "Delete Persistent NS Entity\n"</span><br><span style="color: hsl(120, 100%, 40%);">+     "Delete " NSE_CMD_STR)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   uint16_t nsei = atoi(argv[0]);</span><br><span style="color: hsl(120, 100%, 40%);">+        struct ns2_vty_vc *vtyvc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   vtyvc = vtyvc_by_nsei(nsei, false);</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!vtyvc) {</span><br><span style="color: hsl(120, 100%, 40%);">+         vty_out(vty, "The NSE %d does not exists.%s", nsei, VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+           return CMD_WARNING;</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   ns2_vc_free(vtyvc);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ return CMD_SUCCESS;</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%);">+DEFUN(cfg_ns_timer, cfg_ns_timer_cmd,</span><br><span style="color: hsl(120, 100%, 40%);">+       "timer " NS_TIMERS " <0-65535>",</span><br><span style="color: hsl(120, 100%, 40%);">+    "Network Service Timer\n"</span><br><span style="color: hsl(120, 100%, 40%);">+   NS_TIMERS_HELP "Timer Value\n")</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  int idx = get_string_value(gprs_ns_timer_strs, argv[0]);</span><br><span style="color: hsl(120, 100%, 40%);">+      int val = atoi(argv[1]);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    if (idx < 0 || idx >= ARRAY_SIZE(vty_nsi->timeout))</span><br><span style="color: hsl(120, 100%, 40%);">+          return CMD_WARNING;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ vty_nsi->timeout[idx] = val;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     return CMD_SUCCESS;</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%);">+#define ENCAPS_STR "NS encapsulation options\n"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+DEFUN(cfg_nsip_local_ip, cfg_nsip_local_ip_cmd,</span><br><span style="color: hsl(120, 100%, 40%);">+      "encapsulation udp local-ip " VTY_IPV46_CMD,</span><br><span style="color: hsl(120, 100%, 40%);">+  ENCAPS_STR "NS over UDP Encapsulation\n"</span><br><span style="color: hsl(120, 100%, 40%);">+    "Set the IP address on which we listen for NS/UDP\n"</span><br><span style="color: hsl(120, 100%, 40%);">+        "IP Address\n")</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  osmo_sockaddr_str_from_str2(&priv.udp, argv[0]);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        return CMD_SUCCESS;</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%);">+DEFUN(cfg_nsip_local_port, cfg_nsip_local_port_cmd,</span><br><span style="color: hsl(120, 100%, 40%);">+      "encapsulation udp local-port <0-65535>",</span><br><span style="color: hsl(120, 100%, 40%);">+        ENCAPS_STR "NS over UDP Encapsulation\n"</span><br><span style="color: hsl(120, 100%, 40%);">+    "Set the UDP port on which we listen for NS/UDP\n"</span><br><span style="color: hsl(120, 100%, 40%);">+  "UDP port number\n")</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     unsigned int port = atoi(argv[0]);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  priv.udp.port = port;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       return CMD_SUCCESS;</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%);">+DEFUN(cfg_nsip_dscp, cfg_nsip_dscp_cmd,</span><br><span style="color: hsl(120, 100%, 40%);">+      "encapsulation udp dscp <0-255>",</span><br><span style="color: hsl(120, 100%, 40%);">+    ENCAPS_STR "NS over UDP Encapsulation\n"</span><br><span style="color: hsl(120, 100%, 40%);">+    "Set DSCP/TOS on the UDP socket\n" "DSCP Value\n")</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     int dscp = atoi(argv[0]);</span><br><span style="color: hsl(120, 100%, 40%);">+     struct gprs_ns2_vc_bind *bind;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      priv.dscp = dscp;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   llist_for_each_entry(bind, &vty_nsi->binding, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+          if (gprs_ns2_is_ip_bind(bind))</span><br><span style="color: hsl(120, 100%, 40%);">+                        gprs_ns2_ip_bind_set_dscp(bind, dscp);</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 CMD_SUCCESS;</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%);">+DEFUN(cfg_nsip_res_block_unblock, cfg_nsip_res_block_unblock_cmd,</span><br><span style="color: hsl(120, 100%, 40%);">+   "encapsulation udp use-reset-block-unblock (enabled|disabled)",</span><br><span style="color: hsl(120, 100%, 40%);">+     ENCAPS_STR "NS over UDP Encapsulation\n"</span><br><span style="color: hsl(120, 100%, 40%);">+    "Use NS-{RESET,BLOCK,UNBLOCK} procedures in violation of 3GPP TS 48.016\n"</span><br><span style="color: hsl(120, 100%, 40%);">+  "Enable NS-{RESET,BLOCK,UNBLOCK}\n"</span><br><span style="color: hsl(120, 100%, 40%);">+ "Disable NS-{RESET,BLOCK,UNBLOCK}\n")</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    bool use_reset_block_unblock;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct gprs_ns2_vc_bind *bind;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      if (!strcmp(argv[0], "enabled"))</span><br><span style="color: hsl(120, 100%, 40%);">+            use_reset_block_unblock = true;</span><br><span style="color: hsl(120, 100%, 40%);">+       else</span><br><span style="color: hsl(120, 100%, 40%);">+          use_reset_block_unblock = false;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    priv.use_reset_block_unblock = use_reset_block_unblock;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     llist_for_each_entry(bind, &vty_nsi->binding, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+          bind->use_reset_block_unblock = use_reset_block_unblock;</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 CMD_SUCCESS;</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%);">+DEFUN(cfg_frgre_local_ip, cfg_frgre_local_ip_cmd,</span><br><span style="color: hsl(120, 100%, 40%);">+      "encapsulation framerelay-gre local-ip " VTY_IPV46_CMD,</span><br><span style="color: hsl(120, 100%, 40%);">+  ENCAPS_STR "NS over Frame Relay over GRE Encapsulation\n"</span><br><span style="color: hsl(120, 100%, 40%);">+   "Set the IP address on which we listen for NS/FR/GRE\n"</span><br><span style="color: hsl(120, 100%, 40%);">+     "IP Address\n")</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  osmo_sockaddr_str_from_str2(&priv.frgreaddr, argv[0]);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  return CMD_SUCCESS;</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%);">+DEFUN(cfg_frgre_enable, cfg_frgre_enable_cmd,</span><br><span style="color: hsl(120, 100%, 40%);">+      "encapsulation framerelay-gre enabled (1|0)",</span><br><span style="color: hsl(120, 100%, 40%);">+        ENCAPS_STR "NS over Frame Relay over GRE Encapsulation\n"</span><br><span style="color: hsl(120, 100%, 40%);">+   "Enable or disable Frame Relay over GRE\n"</span><br><span style="color: hsl(120, 100%, 40%);">+  "Enable\n" "Disable\n")</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        int enabled = atoi(argv[0]);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        priv.frgre = enabled;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       return CMD_SUCCESS;</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%);">+//DEFUN(nsvc_nsei, nsvc_nsei_cmd,</span><br><span style="color: hsl(120, 100%, 40%);">+//       "nsvc (nsei|nsvci) <0-65535> (block|unblock|reset)",</span><br><span style="color: hsl(120, 100%, 40%);">+//        "Perform an operation on a NSVC\n"</span><br><span style="color: hsl(120, 100%, 40%);">+//        "NSEI to identify NS-VC Identifier (NS-VCI)\n"</span><br><span style="color: hsl(120, 100%, 40%);">+//    "NS-VC Identifier (NS-VCI)\n"</span><br><span style="color: hsl(120, 100%, 40%);">+//     "The NSEI\n"</span><br><span style="color: hsl(120, 100%, 40%);">+//      "Initiate BLOCK procedure\n"</span><br><span style="color: hsl(120, 100%, 40%);">+//      "Initiate UNBLOCK procedure\n"</span><br><span style="color: hsl(120, 100%, 40%);">+//    "Initiate RESET procedure\n")</span><br><span style="color: hsl(120, 100%, 40%);">+//{</span><br><span style="color: hsl(120, 100%, 40%);">+//        const char *id_type = argv[0];</span><br><span style="color: hsl(120, 100%, 40%);">+//      uint16_t id = atoi(argv[1]);</span><br><span style="color: hsl(120, 100%, 40%);">+//        const char *operation = argv[2];</span><br><span style="color: hsl(120, 100%, 40%);">+//    struct gprs_ns2_vc *nsvc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+// if (!strcmp(id_type, "nsei"))</span><br><span style="color: hsl(120, 100%, 40%);">+//             nsvc = gprs_ns2_vc_by_nsei(vty_nsi, id);</span><br><span style="color: hsl(120, 100%, 40%);">+//    else if (!strcmp(id_type, "nsvci"))</span><br><span style="color: hsl(120, 100%, 40%);">+//               nsvc = gprs_ns2_vc_by_nsvci(vty_nsi, id);</span><br><span style="color: hsl(120, 100%, 40%);">+//   else {</span><br><span style="color: hsl(120, 100%, 40%);">+//              vty_out(vty, "%%No such id_type '%s'%s", id_type, VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+//           return CMD_WARNING;</span><br><span style="color: hsl(120, 100%, 40%);">+// }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+// if (!nsvc) {</span><br><span style="color: hsl(120, 100%, 40%);">+//                vty_out(vty, "No such %s (%u)%s", id_type, id, VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+//              return CMD_WARNING;</span><br><span style="color: hsl(120, 100%, 40%);">+// }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+// if (nsvc->nsi->bss_sns_fi) {</span><br><span style="color: hsl(120, 100%, 40%);">+//          vty_out(vty, "A NS Instance using the IP Sub-Network doesn't use BLOCK/UNBLOCK/RESET%s",</span><br><span style="color: hsl(120, 100%, 40%);">+//                      VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+//               return CMD_WARNING;</span><br><span style="color: hsl(120, 100%, 40%);">+// }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+// if (!strcmp(operation, "block"))</span><br><span style="color: hsl(120, 100%, 40%);">+//          gprs_ns_tx_block(nsvc, NS_CAUSE_OM_INTERVENTION);</span><br><span style="color: hsl(120, 100%, 40%);">+//   else if (!strcmp(operation, "unblock"))</span><br><span style="color: hsl(120, 100%, 40%);">+//           gprs_ns_tx_unblock(nsvc);</span><br><span style="color: hsl(120, 100%, 40%);">+//   else if (!strcmp(operation, "reset"))</span><br><span style="color: hsl(120, 100%, 40%);">+//             gprs_ns2_vc_reset(nsvc, NS_CAUSE_OM_INTERVENTION);</span><br><span style="color: hsl(120, 100%, 40%);">+//  else</span><br><span style="color: hsl(120, 100%, 40%);">+//                return CMD_WARNING;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+//       return CMD_SUCCESS;</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%);">+//DEFUN(logging_fltr_nsvc,</span><br><span style="color: hsl(120, 100%, 40%);">+//      logging_fltr_nsvc_cmd,</span><br><span style="color: hsl(120, 100%, 40%);">+//      "logging filter nsvc (nsei|nsvci) <0-65535>",</span><br><span style="color: hsl(120, 100%, 40%);">+//       LOGGING_STR FILTER_STR</span><br><span style="color: hsl(120, 100%, 40%);">+//      "Filter based on NS Virtual Connection\n"</span><br><span style="color: hsl(120, 100%, 40%);">+// "Identify NS-VC by NSEI\n"</span><br><span style="color: hsl(120, 100%, 40%);">+//        "Identify NS-VC by NSVCI\n"</span><br><span style="color: hsl(120, 100%, 40%);">+//       "Numeric identifier\n")</span><br><span style="color: hsl(120, 100%, 40%);">+//{</span><br><span style="color: hsl(120, 100%, 40%);">+//      struct log_target *tgt;</span><br><span style="color: hsl(120, 100%, 40%);">+//     struct gprs_ns2_vc *nsvc;</span><br><span style="color: hsl(120, 100%, 40%);">+//   uint16_t id = atoi(argv[1]);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+//      log_tgt_mutex_lock();</span><br><span style="color: hsl(120, 100%, 40%);">+//       tgt = osmo_log_vty2tgt(vty);</span><br><span style="color: hsl(120, 100%, 40%);">+//        if (!tgt) {</span><br><span style="color: hsl(120, 100%, 40%);">+//         log_tgt_mutex_unlock();</span><br><span style="color: hsl(120, 100%, 40%);">+//             return CMD_WARNING;</span><br><span style="color: hsl(120, 100%, 40%);">+// }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+// if (!strcmp(argv[0], "nsei"))</span><br><span style="color: hsl(120, 100%, 40%);">+//             nsvc = gprs_ns2_vc_by_nsei(vty_nsi, id);</span><br><span style="color: hsl(120, 100%, 40%);">+//    else</span><br><span style="color: hsl(120, 100%, 40%);">+//                nsvc = gprs_ns2_vc_by_nsvci(vty_nsi, id);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+// if (!nsvc) {remote_end_is_sgsn</span><br><span style="color: hsl(120, 100%, 40%);">+//              vty_out(vty, "No NS-VC by that identifier%s", VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+//               log_tgt_mutex_unlock();</span><br><span style="color: hsl(120, 100%, 40%);">+//             return CMD_WARNING;</span><br><span style="color: hsl(120, 100%, 40%);">+// }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+// log_set_nsvc_filter(tgt, nsvc);</span><br><span style="color: hsl(120, 100%, 40%);">+//     log_tgt_mutex_unlock();</span><br><span style="color: hsl(120, 100%, 40%);">+//     return CMD_SUCCESS;</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%);">+int gprs_ns2_vty_init(struct gprs_ns2_inst *nsi)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       static bool vty_elements_installed = false;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ vty_nsi = nsi;</span><br><span style="color: hsl(120, 100%, 40%);">+        memset(&priv, 0, sizeof(struct ns2_vty_priv));</span><br><span style="color: hsl(120, 100%, 40%);">+    INIT_LLIST_HEAD(&priv.vtyvc);</span><br><span style="color: hsl(120, 100%, 40%);">+     priv.use_reset_block_unblock = true;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        /* Regression test code may call this function repeatedly, so make sure</span><br><span style="color: hsl(120, 100%, 40%);">+        * that VTY elements are not duplicated, which would assert. */</span><br><span style="color: hsl(120, 100%, 40%);">+       if (vty_elements_installed)</span><br><span style="color: hsl(120, 100%, 40%);">+           return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+     vty_elements_installed = true;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      install_element_ve(&show_ns_cmd);</span><br><span style="color: hsl(120, 100%, 40%);">+ install_element_ve(&show_ns_stats_cmd);</span><br><span style="color: hsl(120, 100%, 40%);">+   install_element_ve(&show_ns_pers_cmd);</span><br><span style="color: hsl(120, 100%, 40%);">+    install_element_ve(&show_nse_cmd);</span><br><span style="color: hsl(120, 100%, 40%);">+//      install_element_ve(&logging_fltr_nsvc_cmd);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+//   install_element(CFG_LOG_NODE, &logging_fltr_nsvc_cmd);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  install_element(CONFIG_NODE, &cfg_ns_cmd);</span><br><span style="color: hsl(120, 100%, 40%);">+        install_node(&ns_node, config_write_ns);</span><br><span style="color: hsl(120, 100%, 40%);">+  install_element(L_NS_NODE, &cfg_nse_nsvci_cmd);</span><br><span style="color: hsl(120, 100%, 40%);">+   install_element(L_NS_NODE, &cfg_nse_remoteip_cmd);</span><br><span style="color: hsl(120, 100%, 40%);">+        install_element(L_NS_NODE, &cfg_nse_remoteport_cmd);</span><br><span style="color: hsl(120, 100%, 40%);">+      install_element(L_NS_NODE, &cfg_nse_fr_dlci_cmd);</span><br><span style="color: hsl(120, 100%, 40%);">+ install_element(L_NS_NODE, &cfg_nse_encaps_cmd);</span><br><span style="color: hsl(120, 100%, 40%);">+  install_element(L_NS_NODE, &cfg_nse_remoterole_cmd);</span><br><span style="color: hsl(120, 100%, 40%);">+      install_element(L_NS_NODE, &cfg_no_nse_cmd);</span><br><span style="color: hsl(120, 100%, 40%);">+      install_element(L_NS_NODE, &cfg_ns_timer_cmd);</span><br><span style="color: hsl(120, 100%, 40%);">+    install_element(L_NS_NODE, &cfg_nsip_local_ip_cmd);</span><br><span style="color: hsl(120, 100%, 40%);">+       install_element(L_NS_NODE, &cfg_nsip_local_port_cmd);</span><br><span style="color: hsl(120, 100%, 40%);">+     install_element(L_NS_NODE, &cfg_nsip_dscp_cmd);</span><br><span style="color: hsl(120, 100%, 40%);">+   install_element(L_NS_NODE, &cfg_nsip_res_block_unblock_cmd);</span><br><span style="color: hsl(120, 100%, 40%);">+      install_element(L_NS_NODE, &cfg_frgre_enable_cmd);</span><br><span style="color: hsl(120, 100%, 40%);">+        install_element(L_NS_NODE, &cfg_frgre_local_ip_cmd);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+//  install_element(ENABLE_NODE, &nsvc_nsei_cmd);</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%);">+ * \brief gprs_ns2_vty_create parse the vty tree into ns nodes</span><br><span style="color: hsl(120, 100%, 40%);">+ * It has to be in different steps to ensure the bind is created before creating VCs.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \return 0 on success</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+int gprs_ns2_vty_create() {</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ns2_vty_vc *vtyvc;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct gprs_ns2_vc_bind *bind;</span><br><span style="color: hsl(120, 100%, 40%);">+        struct gprs_ns2_nse *nse;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct gprs_ns2_vc *nsvc;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct osmo_sockaddr sockaddr;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      if (!vty_nsi)</span><br><span style="color: hsl(120, 100%, 40%);">+         return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  /* create binds, only support a single bind. either FR or UDP */</span><br><span style="color: hsl(120, 100%, 40%);">+      if (priv.frgre) {</span><br><span style="color: hsl(120, 100%, 40%);">+             /* TODO not yet supported !*/</span><br><span style="color: hsl(120, 100%, 40%);">+         return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+    } else {</span><br><span style="color: hsl(120, 100%, 40%);">+              /* UDP */</span><br><span style="color: hsl(120, 100%, 40%);">+             osmo_sockaddr_str_to_sockaddr(&priv.udp, &sockaddr.u.sas);</span><br><span style="color: hsl(120, 100%, 40%);">+            gprs_ns2_ip_bind(vty_nsi, &sockaddr, priv.dscp, &bind);</span><br><span style="color: hsl(120, 100%, 40%);">+               if (!bind) {</span><br><span style="color: hsl(120, 100%, 40%);">+                  /* TODO: could not bind on the specific address */</span><br><span style="color: hsl(120, 100%, 40%);">+                    return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+            }</span><br><span style="color: hsl(120, 100%, 40%);">+             gprs_ns2_ip_bind_reset_block_unblock(bind,</span><br><span style="color: hsl(120, 100%, 40%);">+                                                 priv.use_reset_block_unblock);</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%);">+   /* create vcs */</span><br><span style="color: hsl(120, 100%, 40%);">+      llist_for_each_entry(vtyvc, &priv.vtyvc, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+          if (strlen(vtyvc->remote.ip) == 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                       /* Invalid IP for VC */</span><br><span style="color: hsl(120, 100%, 40%);">+                       continue;</span><br><span style="color: hsl(120, 100%, 40%);">+             }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           if (!vtyvc->remote.port) {</span><br><span style="color: hsl(120, 100%, 40%);">+                 /* Invalid port for VC */</span><br><span style="color: hsl(120, 100%, 40%);">+                     continue;</span><br><span style="color: hsl(120, 100%, 40%);">+             }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           if (osmo_sockaddr_str_to_sockaddr(&vtyvc->remote, &sockaddr.u.sas)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                      /* Invalid sockaddr for VC */</span><br><span style="color: hsl(120, 100%, 40%);">+                 continue;</span><br><span style="color: hsl(120, 100%, 40%);">+             }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           nse = gprs_ns2_nse_by_nsei(vty_nsi, vtyvc->nsei);</span><br><span style="color: hsl(120, 100%, 40%);">+          if (!nse) {</span><br><span style="color: hsl(120, 100%, 40%);">+                   nse = gprs_ns2_create_nse(vty_nsi, vtyvc->nsei);</span><br><span style="color: hsl(120, 100%, 40%);">+                   if (!nse) {</span><br><span style="color: hsl(120, 100%, 40%);">+                           /* Could not create NSE for VTY */</span><br><span style="color: hsl(120, 100%, 40%);">+                            continue;</span><br><span style="color: hsl(120, 100%, 40%);">+                     }</span><br><span style="color: hsl(120, 100%, 40%);">+             }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           if (bind) {</span><br><span style="color: hsl(120, 100%, 40%);">+                   nsvc = gprs_ns2_ip_connect(bind,</span><br><span style="color: hsl(120, 100%, 40%);">+                                                 &sockaddr,</span><br><span style="color: hsl(120, 100%, 40%);">+                                                nse,</span><br><span style="color: hsl(120, 100%, 40%);">+                                                  vtyvc->nsvci);</span><br><span style="color: hsl(120, 100%, 40%);">+                  if (!nsvc) {</span><br><span style="color: hsl(120, 100%, 40%);">+                          /* Could not create NSVC, connect failed */</span><br><span style="color: hsl(120, 100%, 40%);">+                           continue;</span><br><span style="color: hsl(120, 100%, 40%);">+                     }</span><br><span style="color: hsl(120, 100%, 40%);">+             }</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%);">+ 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%);">+ * \brief ns2_vty_bind_apply will be called when a new bind is created to apply vty settings</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param bind</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%);">+void ns2_vty_bind_apply(struct gprs_ns2_vc_bind *bind)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ gprs_ns2_ip_bind_reset_block_unblock(bind,</span><br><span style="color: hsl(120, 100%, 40%);">+                                         priv.use_reset_block_unblock);</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 0c0c5c4..4137a0b 100644</span><br><span>--- a/src/gb/libosmogb.map</span><br><span>+++ b/src/gb/libosmogb.map</span><br><span>@@ -72,6 +72,40 @@</span><br><span> gprs_ns_ll_clear;</span><br><span> gprs_ns_msgb_alloc;</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+gprs_ns2_bind_set_mode;</span><br><span style="color: hsl(120, 100%, 40%);">+gprs_ns2_close;</span><br><span style="color: hsl(120, 100%, 40%);">+gprs_ns2_instantiate;</span><br><span style="color: hsl(120, 100%, 40%);">+gprs_ns2_create_connect;</span><br><span style="color: hsl(120, 100%, 40%);">+gprs_ns2_dynamic_create_nse;</span><br><span style="color: hsl(120, 100%, 40%);">+gprs_ns2_free;</span><br><span style="color: hsl(120, 100%, 40%);">+gprs_ns2_free_nse;</span><br><span style="color: hsl(120, 100%, 40%);">+gprs_ns2_free_bind;</span><br><span style="color: hsl(120, 100%, 40%);">+gprs_ns2_free_nsvc;</span><br><span style="color: hsl(120, 100%, 40%);">+gprs_ns2_ip_bind;</span><br><span style="color: hsl(120, 100%, 40%);">+gprs_ns2_ip_connect_inactive;</span><br><span style="color: hsl(120, 100%, 40%);">+gprs_ns2_ip_connect;</span><br><span style="color: hsl(120, 100%, 40%);">+gprs_ns2_ip_connect2;</span><br><span style="color: hsl(120, 100%, 40%);">+gprs_ns2_ip_connect_sns;</span><br><span style="color: hsl(120, 100%, 40%);">+gprs_ns2_recv_vc;</span><br><span style="color: hsl(120, 100%, 40%);">+gprs_ns2_send;</span><br><span style="color: hsl(120, 100%, 40%);">+gprs_ns2_send_nse;</span><br><span style="color: hsl(120, 100%, 40%);">+gprs_ns2_send_nsei;</span><br><span style="color: hsl(120, 100%, 40%);">+gprs_ns2_set_log_ss;</span><br><span style="color: hsl(120, 100%, 40%);">+gprs_ns2_nse_by_nsei;</span><br><span style="color: hsl(120, 100%, 40%);">+gprs_ns2_create_nse;</span><br><span style="color: hsl(120, 100%, 40%);">+gprs_ns2_tx_alive;</span><br><span style="color: hsl(120, 100%, 40%);">+gprs_ns2_tx_alive_ack;</span><br><span style="color: hsl(120, 100%, 40%);">+gprs_ns2_tx_block;</span><br><span style="color: hsl(120, 100%, 40%);">+gprs_ns2_tx_block_ack;</span><br><span style="color: hsl(120, 100%, 40%);">+gprs_ns2_tx_reset;</span><br><span style="color: hsl(120, 100%, 40%);">+gprs_ns2_tx_reset_ack;</span><br><span style="color: hsl(120, 100%, 40%);">+gprs_ns2_tx_status;</span><br><span style="color: hsl(120, 100%, 40%);">+gprs_ns2_tx_unblock;</span><br><span style="color: hsl(120, 100%, 40%);">+gprs_ns2_tx_unblock_ack;</span><br><span style="color: hsl(120, 100%, 40%);">+gprs_ns2_tx_unit_data;</span><br><span style="color: hsl(120, 100%, 40%);">+gprs_ns2_vty_create;</span><br><span style="color: hsl(120, 100%, 40%);">+gprs_ns2_vty_init;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> gprs_nsvc_create2;</span><br><span> gprs_nsvc_delete;</span><br><span> gprs_nsvc_reset;</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.osmocom.org/c/libosmocore/+/19417">change 19417</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/+/19417"/><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: I3525beef205588dfab9d3880a34115f1a2676e48 </div>
<div style="display:none"> Gerrit-Change-Number: 19417 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: lynxis lazus <lynxis@fe80.eu> </div>
<div style="display:none"> Gerrit-MessageType: newchange </div>