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