<p>lynxis lazus has uploaded this change for <strong>review</strong>.</p><p><a href="https://gerrit.osmocom.org/c/libosmocore/+/22872">View Change</a></p><pre style="font-family: monospace,monospace; white-space: pre-wrap;">gprs_ns2: rework IP-SNS binds<br><br>Introduce a `ip-sns-bind BINDID` vty command within a `nse` vty object.<br>The ip-sns-bind defines the binds which will be used by the dynamic<br>configuration with IP-SNS.<br>This is only the first part which only use the binds when doing a<br>new SNS configuration.<br>The outgoing add procedure will be supported in a later patch<br>when the SNS fsm support outgoing procedures.<br><br>Change-Id: I9ab8092bf286e7d90e92f5702a5404425e959c84<br>---<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_vty.c<br>4 files changed, 420 insertions(+), 25 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">git pull ssh://gerrit.osmocom.org:29418/libosmocore refs/changes/72/22872/1</pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/src/gb/gprs_ns2.c b/src/gb/gprs_ns2.c</span><br><span>index 39bbbef..f63c0ad 100644</span><br><span>--- a/src/gb/gprs_ns2.c</span><br><span>+++ b/src/gb/gprs_ns2.c</span><br><span>@@ -1267,6 +1267,7 @@</span><br><span> void gprs_ns2_free_bind(struct gprs_ns2_vc_bind *bind)</span><br><span> {</span><br><span> struct gprs_ns2_vc *nsvc, *tmp;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct gprs_ns2_nse *nse;</span><br><span> if (!bind)</span><br><span> return;</span><br><span> </span><br><span>@@ -1274,6 +1275,12 @@</span><br><span> gprs_ns2_free_nsvc(nsvc);</span><br><span> }</span><br><span> </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%);">+ llist_for_each_entry(nse, &bind->nsi->nse, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ns2_sns_remove_bind(nse, 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> if (bind->driver->free_bind)</span><br><span> bind->driver->free_bind(bind);</span><br><span> </span><br><span>diff --git a/src/gb/gprs_ns2_internal.h b/src/gb/gprs_ns2_internal.h</span><br><span>index 9dd9421..7da4a7c 100644</span><br><span>--- a/src/gb/gprs_ns2_internal.h</span><br><span>+++ b/src/gb/gprs_ns2_internal.h</span><br><span>@@ -365,6 +365,10 @@</span><br><span> void ns2_sns_replace_nsvc(struct gprs_ns2_vc *nsvc);</span><br><span> void ns2_sns_notify_alive(struct gprs_ns2_nse *nse, struct gprs_ns2_vc *nsvc, bool alive);</span><br><span> void ns2_update_weights(struct gprs_ns2_vc_bind *bind);</span><br><span style="color: hsl(120, 100%, 40%);">+int ns2_sns_add_bind(struct gprs_ns2_nse *nse,</span><br><span style="color: hsl(120, 100%, 40%);">+ struct gprs_ns2_vc_bind *bind);</span><br><span style="color: hsl(120, 100%, 40%);">+int ns2_sns_remove_bind(struct gprs_ns2_nse *nse,</span><br><span style="color: hsl(120, 100%, 40%);">+ struct gprs_ns2_vc_bind *bind);</span><br><span> </span><br><span> /* vc */</span><br><span> struct osmo_fsm_inst *ns2_vc_fsm_alloc(struct gprs_ns2_vc *nsvc,</span><br><span>diff --git a/src/gb/gprs_ns2_sns.c b/src/gb/gprs_ns2_sns.c</span><br><span>index 9e77f2a..7e0d5d9 100644</span><br><span>--- a/src/gb/gprs_ns2_sns.c</span><br><span>+++ b/src/gb/gprs_ns2_sns.c</span><br><span>@@ -103,6 +103,11 @@</span><br><span> struct osmo_sockaddr saddr;</span><br><span> };</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+struct ns2_sns_bind {</span><br><span style="color: hsl(120, 100%, 40%);">+ struct llist_head list;</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%);">+</span><br><span> struct ns2_sns_state {</span><br><span> struct gprs_ns2_nse *nse;</span><br><span> </span><br><span>@@ -110,6 +115,10 @@</span><br><span> </span><br><span> /* holds the list of initial SNS endpoints */</span><br><span> struct llist_head sns_endpoints;</span><br><span style="color: hsl(120, 100%, 40%);">+ /* list of used struct ns2_sns_bind */</span><br><span style="color: hsl(120, 100%, 40%);">+ struct llist_head binds;</span><br><span style="color: hsl(120, 100%, 40%);">+ /* pointer to the bind which was used to initiate the SNS connection */</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ns2_sns_bind *current_bind;</span><br><span> /* prevent recursive reselection */</span><br><span> bool reselection_running;</span><br><span> </span><br><span>@@ -120,8 +129,6 @@</span><br><span> 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 style="color: hsl(0, 100%, 40%);">- /* iterate over the binds after all remote has been tested */</span><br><span style="color: hsl(0, 100%, 40%);">- int bind_offset;</span><br><span> /* timer N */</span><br><span> int N;</span><br><span> /* true if at least one nsvc is alive */</span><br><span>@@ -741,23 +748,25 @@</span><br><span> remote = &gss->initial->saddr;</span><br><span> </span><br><span> /* count how many bindings are available (only UDP binds) */</span><br><span style="color: hsl(0, 100%, 40%);">- count = ns2_ip_count_bind(nsi, remote);</span><br><span style="color: hsl(120, 100%, 40%);">+ count = llist_count(&gss->binds);</span><br><span> if (count == 0) {</span><br><span> /* TODO: logging */</span><br><span> return;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- bind = ns2_ip_get_bind_by_index(nsi, remote, gss->bind_offset);</span><br><span style="color: hsl(0, 100%, 40%);">- if (!bind) {</span><br><span style="color: hsl(0, 100%, 40%);">- if (gss->bind_offset) {</span><br><span style="color: hsl(0, 100%, 40%);">- gss->bind_offset = 0;</span><br><span style="color: hsl(0, 100%, 40%);">- bind = ns2_ip_get_bind_by_index(nsi, remote, gss->bind_offset);</span><br><span style="color: hsl(120, 100%, 40%);">+ /* take the first bind or take the next bind */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!gss->current_bind) {</span><br><span style="color: hsl(120, 100%, 40%);">+ gss->current_bind = llist_first_entry(&gss->binds, struct ns2_sns_bind, list);</span><br><span style="color: hsl(120, 100%, 40%);">+ } else {</span><br><span style="color: hsl(120, 100%, 40%);">+ if (gss->current_bind->list.next != &gss->binds) {</span><br><span style="color: hsl(120, 100%, 40%);">+ gss->current_bind = llist_entry(gss->current_bind->list.next, struct ns2_sns_bind, list);</span><br><span style="color: hsl(120, 100%, 40%);">+ } else {</span><br><span style="color: hsl(120, 100%, 40%);">+ gss->current_bind = llist_first_entry(&gss->binds, struct ns2_sns_bind, list);</span><br><span> }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- if (!bind)</span><br><span style="color: hsl(0, 100%, 40%);">- return;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ bind = gss->current_bind->bind;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /* setup the NSVC */</span><br><span> if (!gss->sns_nsvc) {</span><br><span> gss->sns_nsvc = ns2_ip_bind_connect(bind, gss->nse, remote);</span><br><span>@@ -1435,12 +1444,9 @@</span><br><span> return;</span><br><span> } else if (!gss->initial) {</span><br><span> gss->initial = llist_first_entry(&gss->sns_endpoints, struct sns_endpoint, list);</span><br><span style="color: hsl(0, 100%, 40%);">- gss->bind_offset = 0;</span><br><span> } else if (gss->initial->list.next == &gss->sns_endpoints) {</span><br><span> /* last entry, continue with first */</span><br><span> gss->initial = llist_first_entry(&gss->sns_endpoints, struct sns_endpoint, list);</span><br><span style="color: hsl(0, 100%, 40%);">- gss->bind_offset++;</span><br><span style="color: hsl(0, 100%, 40%);">- gss->bind_offset %= ns2_ip_count_bind(nse->nsi, &gss->initial->saddr);</span><br><span> } else {</span><br><span> /* next element is an entry */</span><br><span> gss->initial = llist_entry(gss->initial->list.next, struct sns_endpoint, list);</span><br><span>@@ -1488,6 +1494,7 @@</span><br><span> fi->priv = gss;</span><br><span> gss->nse = nse;</span><br><span> INIT_LLIST_HEAD(&gss->sns_endpoints);</span><br><span style="color: hsl(120, 100%, 40%);">+ INIT_LLIST_HEAD(&gss->binds);</span><br><span> </span><br><span> return fi;</span><br><span> err:</span><br><span>@@ -1810,6 +1817,88 @@</span><br><span> }</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+int ns2_sns_add_bind(struct gprs_ns2_nse *nse,</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%);">+ struct ns2_sns_state *gss;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ns2_sns_bind *tmp;</span><br><span style="color: hsl(120, 100%, 40%);">+ bool trigger_reselection = false;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(nse->bss_sns_fi);</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 (!gprs_ns2_is_ip_bind(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%);">+ if (!llist_empty(&gss->binds)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ llist_for_each_entry(tmp, &gss->binds, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+ if (tmp->bind == bind)</span><br><span style="color: hsl(120, 100%, 40%);">+ return -EALREADY;</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%);">+ trigger_reselection = 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%);">+ tmp = talloc_zero(gss, struct ns2_sns_bind);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!tmp)</span><br><span style="color: hsl(120, 100%, 40%);">+ return -ENOMEM;</span><br><span style="color: hsl(120, 100%, 40%);">+ tmp->bind = bind;</span><br><span style="color: hsl(120, 100%, 40%);">+ llist_add_tail(&tmp->list, &gss->binds);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (trigger_reselection) {</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%);">+ } else {</span><br><span style="color: hsl(120, 100%, 40%);">+ /* TODO: do a add SNS-IP procedure & add 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 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 bind from the SNS. All assosiated NSVC must be removed. */</span><br><span style="color: hsl(120, 100%, 40%);">+int ns2_sns_remove_bind(struct gprs_ns2_nse *nse,</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%);">+ struct ns2_sns_state *gss;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ns2_sns_bind *tmp, *tmp2;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct gprs_ns2_vc *nsvc, *nsvc2;</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%);">+ if (!nse->bss_sns_fi)</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%);">+ gss = nse->bss_sns_fi->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+ if (gss->current_bind && gss->current_bind->bind == bind) {</span><br><span style="color: hsl(120, 100%, 40%);">+ if (gss->current_bind->list.prev == &gss->binds)</span><br><span style="color: hsl(120, 100%, 40%);">+ gss->current_bind = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+ else</span><br><span style="color: hsl(120, 100%, 40%);">+ gss->current_bind = llist_entry(gss->current_bind->list.prev, struct ns2_sns_bind, list);</span><br><span 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(tmp, tmp2, &gss->binds, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+ if (tmp->bind == bind) {</span><br><span style="color: hsl(120, 100%, 40%);">+ llist_del(&tmp->list);</span><br><span style="color: hsl(120, 100%, 40%);">+ found = true;</span><br><span style="color: hsl(120, 100%, 40%);">+ talloc_free(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%);">+ if (!found)</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%);">+ llist_for_each_entry_safe(nsvc, nsvc2, &nse->nsvc, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+ if (nsvc->bind == bind) {</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%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (llist_count(&gss->binds)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ /* TODO: do a remove SNS-IP 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%);">+ return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /* Update SNS weights</span><br><span> * \param[in] nsvc the NSVC which should be updated</span><br><span> */</span><br><span>diff --git a/src/gb/gprs_ns2_vty.c b/src/gb/gprs_ns2_vty.c</span><br><span>index 53e5572..881761b 100644</span><br><span>--- a/src/gb/gprs_ns2_vty.c</span><br><span>+++ b/src/gb/gprs_ns2_vty.c</span><br><span>@@ -58,6 +58,7 @@</span><br><span> static struct gprs_ns2_inst *vty_nsi = NULL;</span><br><span> static struct osmo_fr_network *vty_fr_network = NULL;</span><br><span> static struct llist_head binds;</span><br><span style="color: hsl(120, 100%, 40%);">+static struct llist_head nses;</span><br><span> </span><br><span> struct vty_bind {</span><br><span> struct llist_head list;</span><br><span>@@ -70,6 +71,21 @@</span><br><span> uint8_t ip_sns_data_weight;</span><br><span> };</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+struct vty_nse {</span><br><span style="color: hsl(120, 100%, 40%);">+ struct llist_head list;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint16_t nsei;</span><br><span style="color: hsl(120, 100%, 40%);">+ /* list of binds which are valid for this nse. Only IP-SNS uses this</span><br><span style="color: hsl(120, 100%, 40%);">+ * to allow `no listen ..` in the bind context. So "half" created binds are valid for</span><br><span style="color: hsl(120, 100%, 40%);">+ * IP-SNS. This allows changing the bind ip without modifying all NSEs afterwards */</span><br><span style="color: hsl(120, 100%, 40%);">+ struct llist_head binds;</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* used by IP-SNS to connect multiple vty_nse_bind to a vty_nse */</span><br><span style="color: hsl(120, 100%, 40%);">+struct vty_nse_bind {</span><br><span style="color: hsl(120, 100%, 40%);">+ struct llist_head list;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct vty_bind *vbind;</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /* TODO: this should into osmo timer */</span><br><span> static const struct value_string gprs_ns_timer_strs[] = {</span><br><span> { 0, "tns-block" },</span><br><span>@@ -135,6 +151,93 @@</span><br><span> talloc_free(vbind);</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+static struct vty_nse *vty_nse_by_nsei(uint16_t nsei)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct vty_nse *vnse;</span><br><span style="color: hsl(120, 100%, 40%);">+ llist_for_each_entry(vnse, &nses, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+ if (vnse->nsei == nsei)</span><br><span style="color: hsl(120, 100%, 40%);">+ return vnse;</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 vty_nse *vty_nse_alloc(uint16_t nsei)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct vty_nse *vnse = talloc_zero(vty_nsi, struct vty_nse);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!vnse)</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%);">+ vnse->nsei = nsei;</span><br><span style="color: hsl(120, 100%, 40%);">+ INIT_LLIST_HEAD(&vnse->binds);</span><br><span style="color: hsl(120, 100%, 40%);">+ llist_add(&vnse->list, &nses);</span><br><span style="color: hsl(120, 100%, 40%);">+ return vnse;</span><br><span 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 vty_nse_free(struct vty_nse *vnse)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!vnse)</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(&vnse->list);</span><br><span style="color: hsl(120, 100%, 40%);">+ talloc_free(vnse);</span><br><span 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 vty_nse_add_vbind(struct vty_nse *vnse, struct vty_bind *vbind)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct vty_nse_bind *vnse_bind;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (vbind->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%);">+ llist_for_each_entry(vnse_bind, &vnse->binds, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+ if (vnse_bind->vbind == vbind)</span><br><span style="color: hsl(120, 100%, 40%);">+ return -EALREADY;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ vnse_bind = talloc(vnse, struct vty_nse_bind);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!vnse_bind)</span><br><span style="color: hsl(120, 100%, 40%);">+ return -ENOMEM;</span><br><span style="color: hsl(120, 100%, 40%);">+ vnse_bind->vbind = vbind;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ llist_add_tail(&vnse->list, &vnse->binds);</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 vty_nse_remove_vbind(struct vty_nse *vnse, struct vty_bind *vbind)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct vty_nse_bind *vnse_bind, *tmp;</span><br><span style="color: hsl(120, 100%, 40%);">+ if (vbind->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%);">+ llist_for_each_entry_safe(vnse_bind, tmp, &vnse->binds, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+ if (vnse_bind->vbind == vbind) {</span><br><span style="color: hsl(120, 100%, 40%);">+ llist_del(&vnse_bind->list);</span><br><span style="color: hsl(120, 100%, 40%);">+ talloc_free(vnse_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%);">+ return -ENOENT;</span><br><span 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 the NSE still has SNS configuration */</span><br><span style="color: hsl(120, 100%, 40%);">+static bool vty_nse_check_sns(struct gprs_ns2_nse *nse) {</span><br><span style="color: hsl(120, 100%, 40%);">+ struct vty_nse *vnse = vty_nse_by_nsei(nse->nsei);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ int count = gprs_ns2_sns_count(nse);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (count > 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+ /* there are other sns endpoints */</span><br><span style="color: hsl(120, 100%, 40%);">+ return true;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!vnse)</span><br><span style="color: hsl(120, 100%, 40%);">+ return false;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (llist_empty(&vnse->binds))</span><br><span style="color: hsl(120, 100%, 40%);">+ return false;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ return true;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> static struct cmd_node ns_node = {</span><br><span> L_NS_NODE,</span><br><span> "%s(config-ns)# ",</span><br><span>@@ -172,14 +275,26 @@</span><br><span> )</span><br><span> {</span><br><span> struct gprs_ns2_nse *nse;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct vty_nse *vnse;</span><br><span> uint16_t nsei = atoi(argv[0]);</span><br><span style="color: hsl(120, 100%, 40%);">+ bool free_vnse = false;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ vnse = vty_nse_by_nsei(nsei);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!vnse) {</span><br><span style="color: hsl(120, 100%, 40%);">+ vnse = vty_nse_alloc(nsei);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!vnse) {</span><br><span style="color: hsl(120, 100%, 40%);">+ vty_out(vty, "Failed to create vty NSE!%s", VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+ return CMD_ERR_INCOMPLETE;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ free_vnse = true;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span> </span><br><span> nse = gprs_ns2_nse_by_nsei(vty_nsi, nsei);</span><br><span> if (!nse) {</span><br><span> nse = gprs_ns2_create_nse(vty_nsi, nsei, GPRS_NS2_LL_UNDEF, GPRS_NS2_DIALECT_UNDEF);</span><br><span> if (!nse) {</span><br><span> vty_out(vty, "Failed to create NSE!%s", VTY_NEWLINE);</span><br><span style="color: hsl(0, 100%, 40%);">- return CMD_ERR_INCOMPLETE;</span><br><span style="color: hsl(120, 100%, 40%);">+ goto err;</span><br><span> }</span><br><span> nse->persistent = true;</span><br><span> }</span><br><span>@@ -187,13 +302,19 @@</span><br><span> if (!nse->persistent) {</span><br><span> /* TODO: should the dynamic NSE removed? */</span><br><span> vty_out(vty, "A dynamic NSE with the specified NSEI already exists%s", VTY_NEWLINE);</span><br><span style="color: hsl(0, 100%, 40%);">- return CMD_ERR_INCOMPLETE;</span><br><span style="color: hsl(120, 100%, 40%);">+ goto err;</span><br><span> }</span><br><span> </span><br><span> vty->node = L_NS_NSE_NODE;</span><br><span> vty->index = nse;</span><br><span> </span><br><span> return CMD_SUCCESS;</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%);">+ if (free_vnse)</span><br><span style="color: hsl(120, 100%, 40%);">+ talloc_free(vnse);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ return CMD_ERR_INCOMPLETE;</span><br><span> }</span><br><span> </span><br><span> DEFUN(cfg_no_ns_nsei, cfg_no_ns_nsei_cmd,</span><br><span>@@ -204,6 +325,7 @@</span><br><span> )</span><br><span> {</span><br><span> struct gprs_ns2_nse *nse;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct vty_nse *vnse;</span><br><span> uint16_t nsei = atoi(argv[0]);</span><br><span> </span><br><span> nse = gprs_ns2_nse_by_nsei(vty_nsi, nsei);</span><br><span>@@ -219,6 +341,10 @@</span><br><span> </span><br><span> vty_out(vty, "Deleting NS Entity %u%s", nse->nsei, VTY_NEWLINE);</span><br><span> gprs_ns2_free_nse(nse);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ vnse = vty_nse_by_nsei(nsei);</span><br><span style="color: hsl(120, 100%, 40%);">+ vty_nse_free(vnse);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> return CMD_SUCCESS;</span><br><span> }</span><br><span> </span><br><span>@@ -472,7 +598,7 @@</span><br><span> {</span><br><span> struct vty_bind *vbind = vty->index;</span><br><span> struct gprs_ns2_vc_bind *bind;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(120, 100%, 40%);">+ int rc;</span><br><span> const char *addr_str = argv[0];</span><br><span> unsigned int port = atoi(argv[1]);</span><br><span> struct osmo_sockaddr_str sockaddr_str;</span><br><span>@@ -494,8 +620,9 @@</span><br><span> return CMD_WARNING;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- if (gprs_ns2_ip_bind(vty_nsi, vbind->name, &sockaddr, vbind->dscp, &bind) != 0) {</span><br><span style="color: hsl(0, 100%, 40%);">- vty_out(vty, "Failed to create the bind!%s", VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+ rc = gprs_ns2_ip_bind(vty_nsi, vbind->name, &sockaddr, vbind->dscp, &bind);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (rc != 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+ vty_out(vty, "Failed to create the bind (rc %d)!%s", rc, VTY_NEWLINE);</span><br><span> return CMD_WARNING;</span><br><span> }</span><br><span> </span><br><span>@@ -1320,7 +1447,6 @@</span><br><span> struct osmo_sockaddr_str remote_str; /* argv[0] */</span><br><span> struct osmo_sockaddr remote;</span><br><span> uint16_t port = atoi(argv[1]);</span><br><span style="color: hsl(0, 100%, 40%);">- int count;</span><br><span> </span><br><span> if (nse->ll != GPRS_NS2_LL_UDP) {</span><br><span> vty_out(vty, "This NSE doesn't support UDP.%s", VTY_NEWLINE);</span><br><span>@@ -1347,12 +1473,9 @@</span><br><span> return CMD_WARNING;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- count = gprs_ns2_sns_count(nse);</span><br><span style="color: hsl(0, 100%, 40%);">- if (count > 0) {</span><br><span style="color: hsl(0, 100%, 40%);">- /* there are other sns endpoints */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (vty_nse_check_sns(nse)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ /* there is still sns configuration valid */</span><br><span> return CMD_SUCCESS;</span><br><span style="color: hsl(0, 100%, 40%);">- } else if (count < 0) {</span><br><span style="color: hsl(0, 100%, 40%);">- OSMO_ASSERT(0);</span><br><span> } else {</span><br><span> /* clean up nse to allow other nsvc commands */</span><br><span> osmo_fsm_inst_term(nse->bss_sns_fi, OSMO_FSM_TERM_REQUEST, NULL);</span><br><span>@@ -1364,6 +1487,175 @@</span><br><span> return CMD_SUCCESS;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+DEFUN(cfg_ns_nse_ip_sns_bind, cfg_ns_nse_ip_sns_bind_cmd,</span><br><span style="color: hsl(120, 100%, 40%);">+ "ip-sns-bind BINDID",</span><br><span style="color: hsl(120, 100%, 40%);">+ "IP SNS binds\n"</span><br><span style="color: hsl(120, 100%, 40%);">+ "A udp bind which this SNS will be used. The bind must be already exists. Can be given multiple times.\n")</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct gprs_ns2_nse *nse = vty->index;</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 vty_bind *vbind;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct vty_nse *vnse;</span><br><span style="color: hsl(120, 100%, 40%);">+ const char *name = argv[0];</span><br><span style="color: hsl(120, 100%, 40%);">+ bool ll_modified = false;</span><br><span style="color: hsl(120, 100%, 40%);">+ bool dialect_modified = false;</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 (nse->ll == GPRS_NS2_LL_UNDEF) {</span><br><span style="color: hsl(120, 100%, 40%);">+ nse->ll = GPRS_NS2_LL_UDP;</span><br><span style="color: hsl(120, 100%, 40%);">+ ll_modified = 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%);">+ if (nse->dialect == GPRS_NS2_DIALECT_UNDEF) {</span><br><span style="color: hsl(120, 100%, 40%);">+ char sns[16];</span><br><span style="color: hsl(120, 100%, 40%);">+ snprintf(sns, sizeof(sns), "NSE%05u-SNS", nse->nsei);</span><br><span style="color: hsl(120, 100%, 40%);">+ nse->bss_sns_fi = ns2_sns_bss_fsm_alloc(nse, sns);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!nse->bss_sns_fi)</span><br><span style="color: hsl(120, 100%, 40%);">+ goto err;</span><br><span style="color: hsl(120, 100%, 40%);">+ nse->dialect = GPRS_NS2_DIALECT_SNS;</span><br><span style="color: hsl(120, 100%, 40%);">+ dialect_modified = 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%);">+ if (nse->ll != GPRS_NS2_LL_UDP) {</span><br><span style="color: hsl(120, 100%, 40%);">+ vty_out(vty, "Can not mix NS-VC with different link layer%s", VTY_NEWLINE);</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%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (nse->dialect != GPRS_NS2_DIALECT_SNS) {</span><br><span style="color: hsl(120, 100%, 40%);">+ vty_out(vty, "Can not mix NS-VC with different dialects%s", VTY_NEWLINE);</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%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ vbind = vty_bind_by_name(name);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!vbind) {</span><br><span style="color: hsl(120, 100%, 40%);">+ vty_out(vty, "Can not find the given bind '%s'%s", name, VTY_NEWLINE);</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%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (vbind->ll != GPRS_NS2_LL_UDP) {</span><br><span style="color: hsl(120, 100%, 40%);">+ vty_out(vty, "ip-sns-bind can only be used with UDP bind%s",</span><br><span style="color: hsl(120, 100%, 40%);">+ VTY_NEWLINE);</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%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* the vnse has been created together when creating the nse node. The parent node should check this already! */</span><br><span style="color: hsl(120, 100%, 40%);">+ vnse = vty_nse_by_nsei(nse->nsei);</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(vnse);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ rc = vty_nse_add_vbind(vnse, vbind);</span><br><span style="color: hsl(120, 100%, 40%);">+ switch (rc) {</span><br><span style="color: hsl(120, 100%, 40%);">+ case 0:</span><br><span style="color: hsl(120, 100%, 40%);">+ break;</span><br><span style="color: hsl(120, 100%, 40%);">+ case -EALREADY:</span><br><span style="color: hsl(120, 100%, 40%);">+ vty_out(vty, "Failed to add ip-sns-bind %s already present%s", name, VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+ goto err;</span><br><span style="color: hsl(120, 100%, 40%);">+ case -ENOMEM:</span><br><span style="color: hsl(120, 100%, 40%);">+ vty_out(vty, "Failed to add ip-sns-bind %s out of memory%s", name, VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+ goto err;</span><br><span style="color: hsl(120, 100%, 40%);">+ default:</span><br><span style="color: hsl(120, 100%, 40%);">+ vty_out(vty, "Failed to add ip-sns-bind %s! %d%s", name, rc, VTY_NEWLINE);</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%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* the bind might not yet created because "listen" is missing. */</span><br><span style="color: hsl(120, 100%, 40%);">+ bind = gprs_ns2_bind_by_name(vty_nsi, name);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!bind)</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%);">+ rc = ns2_sns_add_bind(nse, bind);</span><br><span style="color: hsl(120, 100%, 40%);">+ switch (rc) {</span><br><span style="color: hsl(120, 100%, 40%);">+ case 0:</span><br><span style="color: hsl(120, 100%, 40%);">+ break;</span><br><span style="color: hsl(120, 100%, 40%);">+ case -EALREADY:</span><br><span style="color: hsl(120, 100%, 40%);">+ vty_out(vty, "Failed to add ip-sns-bind %s already present%s", name, VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+ goto err;</span><br><span style="color: hsl(120, 100%, 40%);">+ case -ENOMEM:</span><br><span style="color: hsl(120, 100%, 40%);">+ vty_out(vty, "Failed to add ip-sns-bind %s out of memory%s", name, VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+ goto err;</span><br><span style="color: hsl(120, 100%, 40%);">+ default:</span><br><span style="color: hsl(120, 100%, 40%);">+ vty_out(vty, "Failed to add ip-sns-bind %s! %d%s", name, rc, VTY_NEWLINE);</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%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ return CMD_SUCCESS;</span><br><span style="color: hsl(120, 100%, 40%);">+err:</span><br><span style="color: hsl(120, 100%, 40%);">+ if (ll_modified)</span><br><span style="color: hsl(120, 100%, 40%);">+ nse->ll = GPRS_NS2_LL_UNDEF;</span><br><span style="color: hsl(120, 100%, 40%);">+ if (dialect_modified)</span><br><span style="color: hsl(120, 100%, 40%);">+ nse->dialect = GPRS_NS2_DIALECT_UNDEF;</span><br><span style="color: hsl(120, 100%, 40%);">+</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%);">+DEFUN(cfg_no_ns_nse_ip_sns_bind, cfg_no_ns_nse_ip_sns_bind_cmd,</span><br><span style="color: hsl(120, 100%, 40%);">+ "no ip-sns-bind BINDID",</span><br><span style="color: hsl(120, 100%, 40%);">+ NO_STR</span><br><span style="color: hsl(120, 100%, 40%);">+ "IP SNS binds\n"</span><br><span style="color: hsl(120, 100%, 40%);">+ "A udp bind which this SNS will be used.\n")</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct gprs_ns2_nse *nse = vty->index;</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 vty_bind *vbind;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct vty_nse *vnse;</span><br><span style="color: hsl(120, 100%, 40%);">+ const char *name = argv[0];</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 (nse->ll != GPRS_NS2_LL_UDP) {</span><br><span style="color: hsl(120, 100%, 40%);">+ vty_out(vty, "This NSE doesn't support UDP.%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 (nse->dialect != GPRS_NS2_DIALECT_SNS) {</span><br><span style="color: hsl(120, 100%, 40%);">+ vty_out(vty, "This NSE doesn't support UDP with dialect ip-sns.%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%);">+ vbind = vty_bind_by_name(name);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!vbind) {</span><br><span style="color: hsl(120, 100%, 40%);">+ vty_out(vty, "Can not find the given bind '%s'%s", name, 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 (vbind->ll != GPRS_NS2_LL_UDP) {</span><br><span style="color: hsl(120, 100%, 40%);">+ vty_out(vty, "no ip-sns-bind can only be used with UDP bind%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%);">+ /* the vnse has been created together when creating the nse node. The parent node should check this already! */</span><br><span style="color: hsl(120, 100%, 40%);">+ vnse = vty_nse_by_nsei(nse->nsei);</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(vnse);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ rc = vty_nse_remove_vbind(vnse, vbind);</span><br><span style="color: hsl(120, 100%, 40%);">+ switch(rc) {</span><br><span style="color: hsl(120, 100%, 40%);">+ case 0:</span><br><span style="color: hsl(120, 100%, 40%);">+ break;</span><br><span style="color: hsl(120, 100%, 40%);">+ case -ENOENT:</span><br><span style="color: hsl(120, 100%, 40%);">+ vty_out(vty, "Bind %s is not part of this NSE%s", name, VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+ return CMD_WARNING;</span><br><span style="color: hsl(120, 100%, 40%);">+ case -EINVAL:</span><br><span style="color: hsl(120, 100%, 40%);">+ vty_out(vty, "no ip-sns-bind can only be used with UDP bind%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%);">+ default:</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%);">+ /* the bind might not exists yet */</span><br><span style="color: hsl(120, 100%, 40%);">+ bind = gprs_ns2_bind_by_name(vty_nsi, name);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (bind)</span><br><span style="color: hsl(120, 100%, 40%);">+ ns2_sns_remove_bind(nse, bind);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!vty_nse_check_sns(nse)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ /* clean up nse to allow other nsvc commands */</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%);">+ nse->bss_sns_fi = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+ nse->ll = GPRS_NS2_LL_UNDEF;</span><br><span style="color: hsl(120, 100%, 40%);">+ nse->dialect = GPRS_NS2_DIALECT_UNDEF;</span><br><span 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> </span><br><span> /* non-config commands */</span><br><span> static void dump_nsvc(struct vty *vty, struct gprs_ns2_vc *nsvc, bool stats)</span><br><span>@@ -1676,6 +1968,7 @@</span><br><span> {</span><br><span> vty_nsi = nsi;</span><br><span> INIT_LLIST_HEAD(&binds);</span><br><span style="color: hsl(120, 100%, 40%);">+ INIT_LLIST_HEAD(&nses);</span><br><span> </span><br><span> vty_fr_network = osmo_fr_network_alloc(nsi);</span><br><span> if (!vty_fr_network)</span><br><span>@@ -1737,6 +2030,8 @@</span><br><span> install_lib_element(L_NS_NSE_NODE, &cfg_no_ns_nse_nsvc_ipa_cmd);</span><br><span> install_lib_element(L_NS_NSE_NODE, &cfg_ns_nse_ip_sns_remote_cmd);</span><br><span> install_lib_element(L_NS_NSE_NODE, &cfg_no_ns_nse_ip_sns_remote_cmd);</span><br><span style="color: hsl(120, 100%, 40%);">+ install_lib_element(L_NS_NSE_NODE, &cfg_ns_nse_ip_sns_bind_cmd);</span><br><span style="color: hsl(120, 100%, 40%);">+ install_lib_element(L_NS_NSE_NODE, &cfg_no_ns_nse_ip_sns_bind_cmd);</span><br><span> </span><br><span> return 0;</span><br><span> }</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.osmocom.org/c/libosmocore/+/22872">change 22872</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/+/22872"/><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: I9ab8092bf286e7d90e92f5702a5404425e959c84 </div>
<div style="display:none"> Gerrit-Change-Number: 22872 </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>