<p>lynxis lazus has uploaded this change for <strong>review</strong>.</p><p><a href="https://gerrit.osmocom.org/c/libosmocore/+/21573">View Change</a></p><pre style="font-family: monospace,monospace; white-space: pre-wrap;">gprs_ns2_sns: rework IP-SNS initial remote<br><br>The IP-SNS requires at least one initial remote address of the SGSN.<br>However it should be multiple initial remote address instead of a single<br>in case the interface might fail.<br>Rework the SNS to support multiple initial remote addresses.<br><br>Change-Id: I71cdbfb53e361e6112fed5e2712236d797ef3ab2<br>---<br>M include/osmocom/gprs/gprs_ns2.h<br>M src/gb/gprs_ns2.c<br>M src/gb/gprs_ns2_internal.h<br>M src/gb/gprs_ns2_sns.c<br>M src/gb/gprs_ns2_udp.c<br>M src/gb/libosmogb.map<br>6 files changed, 334 insertions(+), 190 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">git pull ssh://gerrit.osmocom.org:29418/libosmocore refs/changes/73/21573/1</pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/include/osmocom/gprs/gprs_ns2.h b/include/osmocom/gprs/gprs_ns2.h</span><br><span>index 3c3c63a..bc89b6a 100644</span><br><span>--- a/include/osmocom/gprs/gprs_ns2.h</span><br><span>+++ b/include/osmocom/gprs/gprs_ns2.h</span><br><span>@@ -83,6 +83,7 @@</span><br><span> /* osmocom own causes */</span><br><span> NS_AFF_CAUSE_SNS_CONFIGURED,</span><br><span> NS_AFF_CAUSE_SNS_FAILURE,</span><br><span style="color: hsl(120, 100%, 40%);">+ NS_AFF_CAUSE_SNS_NO_ENDPOINTS,</span><br><span> };</span><br><span> </span><br><span> extern const struct value_string gprs_ns2_aff_cause_prim_strs[];</span><br><span>@@ -219,9 +220,10 @@</span><br><span> void gprs_ns2_free_binds(struct gprs_ns2_inst *nsi);</span><br><span> </span><br><span> /* create a VC SNS connection */</span><br><span style="color: hsl(0, 100%, 40%);">-int gprs_ns2_ip_connect_sns(struct gprs_ns2_vc_bind *bind,</span><br><span style="color: hsl(0, 100%, 40%);">- const struct osmo_sockaddr *remote,</span><br><span style="color: hsl(0, 100%, 40%);">- uint16_t nsei);</span><br><span style="color: hsl(120, 100%, 40%);">+int gprs_ns2_sns_add_endpoint(struct gprs_ns2_nse *nse,</span><br><span style="color: hsl(120, 100%, 40%);">+ const struct osmo_sockaddr *saddr);</span><br><span style="color: hsl(120, 100%, 40%);">+int gprs_ns2_sns_del_endpoint(struct gprs_ns2_nse *nse,</span><br><span style="color: hsl(120, 100%, 40%);">+ const struct osmo_sockaddr *saddr);</span><br><span> const struct osmo_sockaddr *gprs_ns2_nse_sns_remote(struct gprs_ns2_nse *nse);</span><br><span> </span><br><span> const struct osmo_sockaddr *gprs_ns2_ip_vc_remote(const struct gprs_ns2_vc *nsvc);</span><br><span>diff --git a/src/gb/gprs_ns2.c b/src/gb/gprs_ns2.c</span><br><span>index 6d4b079..9947e59 100644</span><br><span>--- a/src/gb/gprs_ns2.c</span><br><span>+++ b/src/gb/gprs_ns2.c</span><br><span>@@ -953,42 +953,6 @@</span><br><span> return gprs_ns2_ip_connect(bind, remote, nse, nsvci);</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-/*! Create, connect and activate a new IP-SNS NSE.</span><br><span style="color: hsl(0, 100%, 40%);">- * \param[in] bind bind in which the new NS-VC is to be created</span><br><span style="color: hsl(0, 100%, 40%);">- * \param[in] remote remote address to which to connect</span><br><span style="color: hsl(0, 100%, 40%);">- * \param[in] nsei NSEI of the NS Entity in which the NS-VC is to be created</span><br><span style="color: hsl(0, 100%, 40%);">- * \return 0 on success; negative on error */</span><br><span style="color: hsl(0, 100%, 40%);">-int gprs_ns2_ip_connect_sns(struct gprs_ns2_vc_bind *bind,</span><br><span style="color: hsl(0, 100%, 40%);">- const struct osmo_sockaddr *remote,</span><br><span style="color: hsl(0, 100%, 40%);">- uint16_t nsei)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">- struct gprs_ns2_nse *nse = gprs_ns2_nse_by_nsei(bind->nsi, nsei);</span><br><span style="color: hsl(0, 100%, 40%);">- struct gprs_ns2_vc *nsvc;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- if (!nse) {</span><br><span style="color: hsl(0, 100%, 40%);">- nse = gprs_ns2_create_nse(bind->nsi, nsei, GPRS_NS2_LL_UDP, NS2_DIALECT_SNS);</span><br><span style="color: hsl(0, 100%, 40%);">- if (!nse)</span><br><span style="color: hsl(0, 100%, 40%);">- return -1;</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- if (nse->ll != GPRS_NS2_LL_UDP) {</span><br><span style="color: hsl(0, 100%, 40%);">- return -2;</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- if (nse->dialect != NS2_DIALECT_SNS) {</span><br><span style="color: hsl(0, 100%, 40%);">- return -2;</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- if (!nse->bss_sns_fi)</span><br><span style="color: hsl(0, 100%, 40%);">- return -1;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- nsvc = gprs_ns2_ip_bind_connect(bind, nse, remote);</span><br><span style="color: hsl(0, 100%, 40%);">- if (!nsvc)</span><br><span style="color: hsl(0, 100%, 40%);">- return -1;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- return ns2_sns_bss_fsm_start(nse, nsvc, remote);</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span> /*! Find NS-VC for given socket address.</span><br><span> * \param[in] nse NS Entity in which to search</span><br><span> * \param[in] sockaddr socket address to search for</span><br><span>diff --git a/src/gb/gprs_ns2_internal.h b/src/gb/gprs_ns2_internal.h</span><br><span>index 3ef0906..5a090c2 100644</span><br><span>--- a/src/gb/gprs_ns2_internal.h</span><br><span>+++ b/src/gb/gprs_ns2_internal.h</span><br><span>@@ -290,13 +290,15 @@</span><br><span> struct gprs_ns2_vc *gprs_ns2_ip_bind_connect(struct gprs_ns2_vc_bind *bind,</span><br><span> struct gprs_ns2_nse *nse,</span><br><span> const struct osmo_sockaddr *remote);</span><br><span style="color: hsl(120, 100%, 40%);">+int ns2_ip_count_bind(struct gprs_ns2_inst *nsi, struct osmo_sockaddr *remote);</span><br><span style="color: hsl(120, 100%, 40%);">+struct gprs_ns2_vc_bind *ns2_ip_get_bind_by_offset(struct gprs_ns2_inst *nsi,</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_sockaddr *remote,</span><br><span style="color: hsl(120, 100%, 40%);">+ int offset);</span><br><span> </span><br><span> /* sns */</span><br><span> int gprs_ns2_sns_rx(struct gprs_ns2_vc *nsvc, struct msgb *msg, struct tlv_parsed *tp);</span><br><span> struct osmo_fsm_inst *ns2_sns_bss_fsm_alloc(struct gprs_ns2_nse *nse,</span><br><span> const char *id);</span><br><span style="color: hsl(0, 100%, 40%);">-int ns2_sns_bss_fsm_start(struct gprs_ns2_nse *nse, struct gprs_ns2_vc *nsvc,</span><br><span style="color: hsl(0, 100%, 40%);">- const struct osmo_sockaddr *remote);</span><br><span> void ns2_sns_free_nsvc(struct gprs_ns2_vc *nsvc);</span><br><span> </span><br><span> /* vc */</span><br><span>diff --git a/src/gb/gprs_ns2_sns.c b/src/gb/gprs_ns2_sns.c</span><br><span>index d13d920..718d075 100644</span><br><span>--- a/src/gb/gprs_ns2_sns.c</span><br><span>+++ b/src/gb/gprs_ns2_sns.c</span><br><span>@@ -69,7 +69,7 @@</span><br><span> };</span><br><span> </span><br><span> enum gprs_sns_event {</span><br><span style="color: hsl(0, 100%, 40%);">- GPRS_SNS_EV_START,</span><br><span style="color: hsl(120, 100%, 40%);">+ GPRS_SNS_EV_SELECT_ENDPOINT, /*!< Select a SNS endpoint from the list */</span><br><span> GPRS_SNS_EV_SIZE,</span><br><span> GPRS_SNS_EV_SIZE_ACK,</span><br><span> GPRS_SNS_EV_CONFIG,</span><br><span>@@ -82,7 +82,7 @@</span><br><span> };</span><br><span> </span><br><span> static const struct value_string gprs_sns_event_names[] = {</span><br><span style="color: hsl(0, 100%, 40%);">- { GPRS_SNS_EV_START, "START" },</span><br><span style="color: hsl(120, 100%, 40%);">+ { GPRS_SNS_EV_SELECT_ENDPOINT, "SELECT_ENDPOINT" },</span><br><span> { GPRS_SNS_EV_SIZE, "SIZE" },</span><br><span> { GPRS_SNS_EV_SIZE_ACK, "SIZE_ACK" },</span><br><span> { GPRS_SNS_EV_CONFIG, "CONFIG" },</span><br><span>@@ -95,14 +95,26 @@</span><br><span> { 0, NULL }</span><br><span> };</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+struct sns_endpoint {</span><br><span style="color: hsl(120, 100%, 40%);">+ struct llist_head list;</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%);">+</span><br><span> struct ns2_sns_state {</span><br><span> struct gprs_ns2_nse *nse;</span><br><span> </span><br><span> enum ns2_sns_type ip;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- /* initial connection. the initial connection will be terminated</span><br><span style="color: hsl(0, 100%, 40%);">- * in configured state or moved into NSE if valid */</span><br><span style="color: hsl(0, 100%, 40%);">- struct osmo_sockaddr initial;</span><br><span style="color: hsl(120, 100%, 40%);">+ /* holds the list of initial SNS endpoints */</span><br><span style="color: hsl(120, 100%, 40%);">+ struct llist_head sns_endpoints;</span><br><span style="color: hsl(120, 100%, 40%);">+ /* prevent recursive reselection */</span><br><span style="color: hsl(120, 100%, 40%);">+ bool reselection_running;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* The current initial SNS endpoints.</span><br><span style="color: hsl(120, 100%, 40%);">+ * The initial connection will be moved into the NSE</span><br><span style="color: hsl(120, 100%, 40%);">+ * if configured via SNS. Otherwise it will be removed</span><br><span style="color: hsl(120, 100%, 40%);">+ * in configured state. */</span><br><span style="color: hsl(120, 100%, 40%);">+ struct sns_endpoint *initial;</span><br><span> /* all SNS PDU will be sent over this nsvc */</span><br><span> struct gprs_ns2_vc *sns_nsvc;</span><br><span> </span><br><span>@@ -207,7 +219,7 @@</span><br><span> return NULL;</span><br><span> </span><br><span> gss = (struct ns2_sns_state *) nse->bss_sns_fi->priv;</span><br><span style="color: hsl(0, 100%, 40%);">- return &gss->initial;</span><br><span style="color: hsl(120, 100%, 40%);">+ return &gss->initial->saddr;</span><br><span> }</span><br><span> </span><br><span> /*! called when a nsvc is beeing freed */</span><br><span>@@ -646,16 +658,7 @@</span><br><span> </span><br><span> static void ns2_sns_st_unconfigured(struct osmo_fsm_inst *fi, uint32_t event, void *data)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">- struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);</span><br><span style="color: hsl(0, 100%, 40%);">- struct gprs_ns2_inst *nsi = nse->nsi;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- switch (event) {</span><br><span style="color: hsl(0, 100%, 40%);">- case GPRS_SNS_EV_START:</span><br><span style="color: hsl(0, 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(0, 100%, 40%);">- break;</span><br><span style="color: hsl(0, 100%, 40%);">- default:</span><br><span style="color: hsl(0, 100%, 40%);">- OSMO_ASSERT(0);</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(120, 100%, 40%);">+ /* empty state - SNS Select will start by all action */</span><br><span> }</span><br><span> </span><br><span> static void ns2_sns_st_size(struct osmo_fsm_inst *fi, uint32_t event, void *data)</span><br><span>@@ -681,18 +684,133 @@</span><br><span> }</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+/* setup all dynamic SNS settings, create a new nsvc and send the SIZE */</span><br><span> static void ns2_sns_st_size_onenter(struct osmo_fsm_inst *fi, uint32_t old_state)</span><br><span> {</span><br><span> struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct gprs_ns_ie_ip4_elem *ip4_elems;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct gprs_ns_ie_ip6_elem *ip6_elems;</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 = gss->nse->nsi;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_sockaddr *remote;</span><br><span style="color: hsl(120, 100%, 40%);">+ const struct osmo_sockaddr *sa;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_sockaddr local;</span><br><span style="color: hsl(120, 100%, 40%);">+ int count;</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ /* on a generic failure, the timer callback will recover */</span><br><span> if (old_state != GPRS_SNS_ST_UNCONFIGURED)</span><br><span> ns2_prim_status_ind(gss->nse, NULL, 0, NS_AFF_CAUSE_SNS_FAILURE);</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ /* no initial available */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!gss->initial)</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%);">+ remote = &gss->initial->saddr;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* count how many bindings are available (only UDP binds) */</span><br><span style="color: hsl(120, 100%, 40%);">+ count = ns2_ip_count_bind(nsi, remote);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (count == 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+ /* TODO: logging */</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%);">+ bind = ns2_ip_get_bind_by_offset(nsi, remote, 0);</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%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* setup the NSVC */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!gss->sns_nsvc) {</span><br><span style="color: hsl(120, 100%, 40%);">+ gss->sns_nsvc = gprs_ns2_ip_bind_connect(bind, gss->nse, remote);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!gss->sns_nsvc)</span><br><span style="color: hsl(120, 100%, 40%);">+ return;</span><br><span style="color: hsl(120, 100%, 40%);">+ gss->sns_nsvc->sns_only = 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%);">+ switch (gss->ip) {</span><br><span style="color: hsl(120, 100%, 40%);">+ case IPv4:</span><br><span style="color: hsl(120, 100%, 40%);">+ ip4_elems = talloc_zero_size(fi, sizeof(struct gprs_ns_ie_ip4_elem) * count);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!ip4_elems)</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%);">+ gss->ip4_local = ip4_elems;</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%);">+ if (sa->u.sas.ss_family != AF_INET)</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.sin.sin_addr.s_addr == 0) {</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_elems->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_elems->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_elems->udp_port = sa->u.sin.sin_port;</span><br><span style="color: hsl(120, 100%, 40%);">+ ip4_elems->sig_weight = 2;</span><br><span style="color: hsl(120, 100%, 40%);">+ ip4_elems->data_weight = 1;</span><br><span style="color: hsl(120, 100%, 40%);">+ ip4_elems++;</span><br><span 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_ip4_remote = 4;</span><br><span style="color: hsl(120, 100%, 40%);">+ gss->num_max_nsvcs = OSMO_MAX(gss->num_max_ip4_remote * 4, 8);</span><br><span style="color: hsl(120, 100%, 40%);">+ break;</span><br><span style="color: hsl(120, 100%, 40%);">+ case IPv6:</span><br><span style="color: hsl(120, 100%, 40%);">+ /* IPv6 */</span><br><span style="color: hsl(120, 100%, 40%);">+ ip6_elems = talloc_zero_size(fi, sizeof(struct gprs_ns_ie_ip6_elem) * count);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!ip6_elems)</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%);">+ gss->ip6_local = ip6_elems;</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%);">+ if (sa->u.sas.ss_family != AF_INET6)</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 (IN6_IS_ADDR_UNSPECIFIED(&sa->u.sin6.sin6_addr)) {</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%);">+ ip6_elems->ip_addr = local.u.sin6.sin6_addr;</span><br><span style="color: hsl(120, 100%, 40%);">+ } else {</span><br><span style="color: hsl(120, 100%, 40%);">+ ip6_elems->ip_addr = sa->u.sin6.sin6_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%);">+ ip6_elems->udp_port = sa->u.sin.sin_port;</span><br><span style="color: hsl(120, 100%, 40%);">+ ip6_elems->sig_weight = 2;</span><br><span style="color: hsl(120, 100%, 40%);">+ ip6_elems->data_weight = 1;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ ip6_elems++;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ gss->num_ip6_local = count;</span><br><span style="color: hsl(120, 100%, 40%);">+ gss->num_max_ip6_remote = 4;</span><br><span style="color: hsl(120, 100%, 40%);">+ gss->num_max_nsvcs = OSMO_MAX(gss->num_max_ip6_remote * 4, 8);</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> if (gss->num_max_ip4_remote > 0)</span><br><span> ns2_tx_sns_size(gss->sns_nsvc, true, gss->num_max_nsvcs, gss->num_max_ip4_remote, -1);</span><br><span> else</span><br><span> ns2_tx_sns_size(gss->sns_nsvc, true, gss->num_max_nsvcs, -1, gss->num_max_ip6_remote);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span> }</span><br><span> </span><br><span> static void ns2_sns_st_config_bss(struct osmo_fsm_inst *fi, uint32_t event, void *data)</span><br><span>@@ -1130,7 +1248,7 @@</span><br><span> </span><br><span> static const struct osmo_fsm_state ns2_sns_bss_states[] = {</span><br><span> [GPRS_SNS_ST_UNCONFIGURED] = {</span><br><span style="color: hsl(0, 100%, 40%);">- .in_event_mask = S(GPRS_SNS_EV_START),</span><br><span style="color: hsl(120, 100%, 40%);">+ .in_event_mask = 0,</span><br><span> .out_state_mask = S(GPRS_SNS_ST_SIZE),</span><br><span> .name = "UNCONFIGURED",</span><br><span> .action = ns2_sns_st_unconfigured,</span><br><span>@@ -1194,17 +1312,46 @@</span><br><span> </span><br><span> static void ns2_sns_st_all_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)</span><br><span> {</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;</span><br><span> struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);</span><br><span> </span><br><span> /* reset when receiving GPRS_SNS_EV_NO_NSVC */</span><br><span style="color: hsl(0, 100%, 40%);">- osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_SIZE, nse->nsi->timeout[NS_TOUT_TSNS_PROV], 3);</span><br><span style="color: hsl(120, 100%, 40%);">+ switch (event) {</span><br><span style="color: hsl(120, 100%, 40%);">+ case GPRS_SNS_EV_NO_NSVC:</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!gss->reselection_running)</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_SELECT_ENDPOINT, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+ break;</span><br><span style="color: hsl(120, 100%, 40%);">+ case GPRS_SNS_EV_SELECT_ENDPOINT:</span><br><span style="color: hsl(120, 100%, 40%);">+ /* tear down previous state</span><br><span style="color: hsl(120, 100%, 40%);">+ * gprs_ns2_free_nsvcs() will trigger NO_NSVC, prevent this from triggering a reselection */</span><br><span style="color: hsl(120, 100%, 40%);">+ gss->reselection_running = true;</span><br><span style="color: hsl(120, 100%, 40%);">+ gprs_ns2_free_nsvcs(nse);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Choose the next sns endpoint. */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (llist_empty(&gss->sns_endpoints)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ gss->initial = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+ ns2_prim_status_ind(gss->nse, NULL, 0, NS_AFF_CAUSE_SNS_NO_ENDPOINTS);</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_UNCONFIGURED, 0, 3);</span><br><span style="color: hsl(120, 100%, 40%);">+ return;</span><br><span style="color: hsl(120, 100%, 40%);">+ } else if (!gss->initial)</span><br><span style="color: hsl(120, 100%, 40%);">+ gss->initial = llist_first_entry(&gss->sns_endpoints, struct sns_endpoint, list);</span><br><span style="color: hsl(120, 100%, 40%);">+ else if (gss->initial->list.next == &gss->sns_endpoints) /* last entry, continue with first */</span><br><span style="color: hsl(120, 100%, 40%);">+ gss->initial = llist_first_entry(&gss->sns_endpoints, struct sns_endpoint, list);</span><br><span style="color: hsl(120, 100%, 40%);">+ else /* next element is an entry */</span><br><span style="color: hsl(120, 100%, 40%);">+ gss->initial = llist_entry(gss->initial->list.next, struct sns_endpoint, list);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ gss->reselection_running = false;</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_SIZE, nse->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%);">+ }</span><br><span> }</span><br><span> </span><br><span> static struct osmo_fsm gprs_ns2_sns_bss_fsm = {</span><br><span> .name = "GPRS-NS2-SNS-BSS",</span><br><span> .states = ns2_sns_bss_states,</span><br><span> .num_states = ARRAY_SIZE(ns2_sns_bss_states),</span><br><span style="color: hsl(0, 100%, 40%);">- .allstate_event_mask = S(GPRS_SNS_EV_NO_NSVC),</span><br><span style="color: hsl(120, 100%, 40%);">+ .allstate_event_mask = S(GPRS_SNS_EV_NO_NSVC) |</span><br><span style="color: hsl(120, 100%, 40%);">+ S(GPRS_SNS_EV_SELECT_ENDPOINT),</span><br><span> .allstate_action = ns2_sns_st_all_action,</span><br><span> .cleanup = NULL,</span><br><span> .timer_cb = ns2_sns_fsm_bss_timer_cb,</span><br><span>@@ -1241,134 +1388,6 @@</span><br><span> return NULL;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-/*! Start an IP-SNS FSM.</span><br><span style="color: hsl(0, 100%, 40%);">- * \param[in] nse NS Entity whose IP-SNS FSM shall be started</span><br><span style="color: hsl(0, 100%, 40%);">- * \param[in] nsvc Initial NS-VC</span><br><span style="color: hsl(0, 100%, 40%);">- * \param[in] remote remote (SGSN) address</span><br><span style="color: hsl(0, 100%, 40%);">- * \returns 0 on success; negative on error */</span><br><span style="color: hsl(0, 100%, 40%);">-int ns2_sns_bss_fsm_start(struct gprs_ns2_nse *nse, struct gprs_ns2_vc *nsvc,</span><br><span style="color: hsl(0, 100%, 40%);">- const struct osmo_sockaddr *remote)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">- struct osmo_fsm_inst *fi = nse->bss_sns_fi;</span><br><span style="color: hsl(0, 100%, 40%);">- struct ns2_sns_state *gss = (struct ns2_sns_state *) nse->bss_sns_fi->priv;</span><br><span style="color: hsl(0, 100%, 40%);">- struct gprs_ns_ie_ip4_elem *ip4_elems;</span><br><span style="color: hsl(0, 100%, 40%);">- struct gprs_ns_ie_ip6_elem *ip6_elems;</span><br><span style="color: hsl(0, 100%, 40%);">- struct gprs_ns2_vc_bind *bind;</span><br><span style="color: hsl(0, 100%, 40%);">- struct gprs_ns2_inst *nsi = nse->nsi;</span><br><span style="color: hsl(0, 100%, 40%);">- const struct osmo_sockaddr *sa;</span><br><span style="color: hsl(0, 100%, 40%);">- struct osmo_sockaddr local;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- gss->ip = remote->u.sa.sa_family == AF_INET ? IPv4 : IPv6;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- gss->initial = *remote;</span><br><span style="color: hsl(0, 100%, 40%);">- gss->sns_nsvc = nsvc;</span><br><span style="color: hsl(0, 100%, 40%);">- nsvc->sns_only = true;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- /* count how many bindings are available (only UDP binds) */</span><br><span style="color: hsl(0, 100%, 40%);">- int count = 0;</span><br><span style="color: hsl(0, 100%, 40%);">- llist_for_each_entry(bind, &nsi->binding, list) {</span><br><span style="color: hsl(0, 100%, 40%);">- if (!gprs_ns2_is_ip_bind(bind))</span><br><span style="color: hsl(0, 100%, 40%);">- continue;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- sa = gprs_ns2_ip_bind_sockaddr(bind);</span><br><span style="color: hsl(0, 100%, 40%);">- if (!sa)</span><br><span style="color: hsl(0, 100%, 40%);">- continue;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- if (sa->u.sa.sa_family == remote->u.sa.sa_family)</span><br><span style="color: hsl(0, 100%, 40%);">- count++;</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- if (count == 0) {</span><br><span style="color: hsl(0, 100%, 40%);">- /* TODO: logging */</span><br><span style="color: hsl(0, 100%, 40%);">- goto err;</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- switch (gss->ip) {</span><br><span style="color: hsl(0, 100%, 40%);">- case IPv4:</span><br><span style="color: hsl(0, 100%, 40%);">- ip4_elems = talloc_zero_size(fi, sizeof(struct gprs_ns_ie_ip4_elem) * count);</span><br><span style="color: hsl(0, 100%, 40%);">- if (!ip4_elems)</span><br><span style="color: hsl(0, 100%, 40%);">- goto err;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- gss->ip4_local = ip4_elems;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- llist_for_each_entry(bind, &nsi->binding, list) {</span><br><span style="color: hsl(0, 100%, 40%);">- if (!gprs_ns2_is_ip_bind(bind))</span><br><span style="color: hsl(0, 100%, 40%);">- continue;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- sa = gprs_ns2_ip_bind_sockaddr(bind);</span><br><span style="color: hsl(0, 100%, 40%);">- if (!sa)</span><br><span style="color: hsl(0, 100%, 40%);">- continue;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- if (sa->u.sas.ss_family != AF_INET)</span><br><span style="color: hsl(0, 100%, 40%);">- continue;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- /* check if this is an specific bind */</span><br><span style="color: hsl(0, 100%, 40%);">- if (sa->u.sin.sin_addr.s_addr == 0) {</span><br><span style="color: hsl(0, 100%, 40%);">- if (osmo_sockaddr_local_ip(&local, remote))</span><br><span style="color: hsl(0, 100%, 40%);">- continue;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- ip4_elems->ip_addr = local.u.sin.sin_addr.s_addr;</span><br><span style="color: hsl(0, 100%, 40%);">- } else {</span><br><span style="color: hsl(0, 100%, 40%);">- ip4_elems->ip_addr = sa->u.sin.sin_addr.s_addr;</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- ip4_elems->udp_port = sa->u.sin.sin_port;</span><br><span style="color: hsl(0, 100%, 40%);">- ip4_elems->sig_weight = 2;</span><br><span style="color: hsl(0, 100%, 40%);">- ip4_elems->data_weight = 1;</span><br><span style="color: hsl(0, 100%, 40%);">- ip4_elems++;</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- gss->num_ip4_local = count;</span><br><span style="color: hsl(0, 100%, 40%);">- gss->num_max_ip4_remote = 4;</span><br><span style="color: hsl(0, 100%, 40%);">- gss->num_max_nsvcs = OSMO_MAX(gss->num_max_ip4_remote * 4, 8);</span><br><span style="color: hsl(0, 100%, 40%);">- break;</span><br><span style="color: hsl(0, 100%, 40%);">- case IPv6:</span><br><span style="color: hsl(0, 100%, 40%);">- /* IPv6 */</span><br><span style="color: hsl(0, 100%, 40%);">- ip6_elems = talloc_zero_size(fi, sizeof(struct gprs_ns_ie_ip6_elem) * count);</span><br><span style="color: hsl(0, 100%, 40%);">- if (!ip6_elems)</span><br><span style="color: hsl(0, 100%, 40%);">- goto err;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- gss->ip6_local = ip6_elems;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- llist_for_each_entry(bind, &nsi->binding, list) {</span><br><span style="color: hsl(0, 100%, 40%);">- if (!gprs_ns2_is_ip_bind(bind))</span><br><span style="color: hsl(0, 100%, 40%);">- continue;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- sa = gprs_ns2_ip_bind_sockaddr(bind);</span><br><span style="color: hsl(0, 100%, 40%);">- if (!sa)</span><br><span style="color: hsl(0, 100%, 40%);">- continue;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- if (sa->u.sas.ss_family != AF_INET6)</span><br><span style="color: hsl(0, 100%, 40%);">- continue;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- /* check if this is an specific bind */</span><br><span style="color: hsl(0, 100%, 40%);">- if (IN6_IS_ADDR_UNSPECIFIED(&sa->u.sin6.sin6_addr)) {</span><br><span style="color: hsl(0, 100%, 40%);">- if (osmo_sockaddr_local_ip(&local, remote))</span><br><span style="color: hsl(0, 100%, 40%);">- continue;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- ip6_elems->ip_addr = local.u.sin6.sin6_addr;</span><br><span style="color: hsl(0, 100%, 40%);">- } else {</span><br><span style="color: hsl(0, 100%, 40%);">- ip6_elems->ip_addr = sa->u.sin6.sin6_addr;</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- ip6_elems->udp_port = sa->u.sin.sin_port;</span><br><span style="color: hsl(0, 100%, 40%);">- ip6_elems->sig_weight = 2;</span><br><span style="color: hsl(0, 100%, 40%);">- ip6_elems->data_weight = 1;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- ip6_elems++;</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">- gss->num_ip6_local = count;</span><br><span style="color: hsl(0, 100%, 40%);">- gss->num_max_ip6_remote = 4;</span><br><span style="color: hsl(0, 100%, 40%);">- gss->num_max_nsvcs = OSMO_MAX(gss->num_max_ip6_remote * 4, 8);</span><br><span style="color: hsl(0, 100%, 40%);">- break;</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- return osmo_fsm_inst_dispatch(nse->bss_sns_fi, GPRS_SNS_EV_START, NULL);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-err:</span><br><span style="color: hsl(0, 100%, 40%);">- return -1;</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span> /*! main entry point for receiving SNS messages from the network.</span><br><span> * \param[in] nsvc NS-VC on which the message was received</span><br><span> * \param[in] msg message buffer of the IP-SNS message</span><br><span>@@ -1490,6 +1509,113 @@</span><br><span> }</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+static struct sns_endpoint *ns2_get_sns_endpoint(struct ns2_sns_state *state,</span><br><span style="color: hsl(120, 100%, 40%);">+ const struct osmo_sockaddr *saddr)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct sns_endpoint *endpoint;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ llist_for_each_entry(endpoint, &state->sns_endpoints, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!osmo_sockaddr_cmp(saddr, &endpoint->saddr))</span><br><span style="color: hsl(120, 100%, 40%);">+ return endpoint;</span><br><span 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%);">+/*! gprs_ns2_sns_add_endpoint</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[in] nse</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[in] sockaddr</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_sns_add_endpoint(struct gprs_ns2_nse *nse,</span><br><span style="color: hsl(120, 100%, 40%);">+ const struct osmo_sockaddr *saddr)</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%);">+ struct sns_endpoint *endpoint;</span><br><span style="color: hsl(120, 100%, 40%);">+ bool do_selection = false;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (nse->ll != GPRS_NS2_LL_UDP) {</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%);">+ if (nse->dialect != NS2_DIALECT_SNS) {</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%);">+ gss = nse->bss_sns_fi->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (ns2_get_sns_endpoint(gss, saddr))</span><br><span style="color: hsl(120, 100%, 40%);">+ return -EADDRINUSE;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ endpoint = talloc_zero(nse->bss_sns_fi->priv, struct sns_endpoint);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!endpoint)</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%);">+ endpoint->saddr = *saddr;</span><br><span style="color: hsl(120, 100%, 40%);">+ if (llist_empty(&gss->sns_endpoints))</span><br><span style="color: hsl(120, 100%, 40%);">+ do_selection = true;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ llist_add_tail(&endpoint->list, &gss->sns_endpoints);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (do_selection)</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_fsm_inst_dispatch(nse->bss_sns_fi, GPRS_SNS_EV_SELECT_ENDPOINT, NULL);</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%);">+/*! gprs_ns2_sns_del_endpoint</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[in] nse</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[in] sockaddr</span><br><span style="color: hsl(120, 100%, 40%);">+ * \return 0 on success, otherwise < 0</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+int gprs_ns2_sns_del_endpoint(struct gprs_ns2_nse *nse,</span><br><span style="color: hsl(120, 100%, 40%);">+ const struct osmo_sockaddr *saddr)</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%);">+ struct sns_endpoint *endpoint;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (nse->ll != GPRS_NS2_LL_UDP) {</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%);">+ if (nse->dialect != NS2_DIALECT_SNS) {</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%);">+ gss = nse->bss_sns_fi->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+ endpoint = ns2_get_sns_endpoint(gss, saddr);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!endpoint)</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%);">+ /* if this is an unused SNS endpoint it's done */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (gss->initial != endpoint) {</span><br><span style="color: hsl(120, 100%, 40%);">+ llist_del(&endpoint->list);</span><br><span style="color: hsl(120, 100%, 40%);">+ talloc_free(endpoint);</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%);">+ /* gprs_ns2_free_nsvcs() will trigger GPRS_SNS_EV_NO_NSVC on the last NS-VC</span><br><span style="color: hsl(120, 100%, 40%);">+ * and restart SNS SIZE procedure which selects a new initial */</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGP(DLNS, LOGL_INFO, "Current in-use SNS endpoint is being removed."</span><br><span style="color: hsl(120, 100%, 40%);">+ "Closing all NS-VC and restart SNS-SIZE procedure"</span><br><span style="color: hsl(120, 100%, 40%);">+ "with a remaining SNS endpoint.\n");</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Continue with the next endpoint in the list.</span><br><span style="color: hsl(120, 100%, 40%);">+ * Special case if the endpoint is at the start or end of the list */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (endpoint->list.prev == &gss->sns_endpoints ||</span><br><span style="color: hsl(120, 100%, 40%);">+ endpoint->list.next == &gss->sns_endpoints)</span><br><span style="color: hsl(120, 100%, 40%);">+ gss->initial = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+ else</span><br><span style="color: hsl(120, 100%, 40%);">+ gss->initial = llist_entry(endpoint->list.next->prev,</span><br><span style="color: hsl(120, 100%, 40%);">+ struct sns_endpoint,</span><br><span style="color: hsl(120, 100%, 40%);">+ list);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ llist_del(&endpoint->list);</span><br><span style="color: hsl(120, 100%, 40%);">+ gprs_ns2_free_nsvcs(nse);</span><br><span style="color: hsl(120, 100%, 40%);">+ talloc_free(endpoint);</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> /* initialize osmo_ctx on main tread */</span><br><span> static __attribute__((constructor)) void on_dso_load_ctx(void)</span><br><span> {</span><br><span>diff --git a/src/gb/gprs_ns2_udp.c b/src/gb/gprs_ns2_udp.c</span><br><span>index c0ab5f5..69ea83f 100644</span><br><span>--- a/src/gb/gprs_ns2_udp.c</span><br><span>+++ b/src/gb/gprs_ns2_udp.c</span><br><span>@@ -513,3 +513,52 @@</span><br><span> </span><br><span> return rc;</span><br><span> }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! Count UDP binds compatible with remote */</span><br><span style="color: hsl(120, 100%, 40%);">+int ns2_ip_count_bind(struct gprs_ns2_inst *nsi, 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_bind *bind;</span><br><span style="color: hsl(120, 100%, 40%);">+ const struct osmo_sockaddr *sa;</span><br><span style="color: hsl(120, 100%, 40%);">+ int count = 0;</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%);">+ if (sa->u.sa.sa_family == remote->u.sa.sa_family)</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%);">+ return 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%);">+/* return the matching bind by offset */</span><br><span style="color: hsl(120, 100%, 40%);">+struct gprs_ns2_vc_bind *ns2_ip_get_bind_by_offset(struct gprs_ns2_inst *nsi,</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_sockaddr *remote,</span><br><span style="color: hsl(120, 100%, 40%);">+ int offset)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct gprs_ns2_vc_bind *bind;</span><br><span style="color: hsl(120, 100%, 40%);">+ const struct osmo_sockaddr *sa;</span><br><span style="color: hsl(120, 100%, 40%);">+ int i = 0;</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%);">+ if (sa->u.sa.sa_family == remote->u.sa.sa_family) {</span><br><span style="color: hsl(120, 100%, 40%);">+ if (offset == i)</span><br><span style="color: hsl(120, 100%, 40%);">+ return bind;</span><br><span style="color: hsl(120, 100%, 40%);">+ i++;</span><br><span 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>diff --git a/src/gb/libosmogb.map b/src/gb/libosmogb.map</span><br><span>index 7e7971a..7fcac6a 100644</span><br><span>--- a/src/gb/libosmogb.map</span><br><span>+++ b/src/gb/libosmogb.map</span><br><span>@@ -111,7 +111,6 @@</span><br><span> gprs_ns2_ip_connect;</span><br><span> gprs_ns2_ip_connect2;</span><br><span> gprs_ns2_ip_connect_inactive;</span><br><span style="color: hsl(0, 100%, 40%);">-gprs_ns2_ip_connect_sns;</span><br><span> gprs_ns2_ip_vc_local;</span><br><span> gprs_ns2_ip_vc_remote;</span><br><span> gprs_ns2_ip_vc_equal;</span><br><span>@@ -132,6 +131,8 @@</span><br><span> gprs_ns2_recv_prim;</span><br><span> gprs_ns2_reset_persistent_nsvcs;</span><br><span> gprs_ns2_start_alive_all_nsvcs;</span><br><span style="color: hsl(120, 100%, 40%);">+gprs_ns2_sns_add_endpoint;</span><br><span style="color: hsl(120, 100%, 40%);">+gprs_ns2_sns_del_endpoint;</span><br><span> gprs_ns2_vty_create;</span><br><span> gprs_ns2_vty_init;</span><br><span> </span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.osmocom.org/c/libosmocore/+/21573">change 21573</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/+/21573"/><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: I71cdbfb53e361e6112fed5e2712236d797ef3ab2 </div>
<div style="display:none"> Gerrit-Change-Number: 21573 </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>