<p>lynxis lazus <strong>submitted</strong> this change.</p><p><a href="https://gerrit.osmocom.org/c/libosmocore/+/22872">View Change</a></p><div style="white-space:pre-wrap">Approvals:
  daniel: Looks good to me, approved
  Jenkins Builder: Verified

</div><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 uses 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 supports outgoing procedures.<br><br>This is a behaviour change of the API and must be synchronized with<br>the osmo-pcu. Otherwise SNS won't work with osmo-pcu.<br><br>Related: SYS#5354<br>Change-Id: I9ab8092bf286e7d90e92f5702a5404425e959c84<br>---<br>M include/osmocom/gprs/gprs_ns2.h<br>M src/gb/gprs_ns2.c<br>M src/gb/gprs_ns2_sns.c<br>M src/gb/gprs_ns2_vty.c<br>M src/gb/libosmogb.map<br>M tests/gb/osmo-ns-dummy.cfg<br>6 files changed, 469 insertions(+), 37 deletions(-)<br><br></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 b406bb0..56a9b4f 100644</span><br><span>--- a/include/osmocom/gprs/gprs_ns2.h</span><br><span>+++ b/include/osmocom/gprs/gprs_ns2.h</span><br><span>@@ -230,6 +230,8 @@</span><br><span>                             const struct osmo_sockaddr *saddr);</span><br><span> int gprs_ns2_sns_del_endpoint(struct gprs_ns2_nse *nse,</span><br><span>                               const struct osmo_sockaddr *saddr);</span><br><span style="color: hsl(120, 100%, 40%);">+int gprs_ns2_sns_add_bind(struct gprs_ns2_nse *nse, struct gprs_ns2_vc_bind *bind);</span><br><span style="color: hsl(120, 100%, 40%);">+int gprs_ns2_sns_del_bind(struct gprs_ns2_nse *nse, struct gprs_ns2_vc_bind *bind);</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 9302a16..bc4db53 100644</span><br><span>--- a/src/gb/gprs_ns2.c</span><br><span>+++ b/src/gb/gprs_ns2.c</span><br><span>@@ -1269,6 +1269,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>@@ -1276,6 +1277,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%);">+                  gprs_ns2_sns_del_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_sns.c b/src/gb/gprs_ns2_sns.c</span><br><span>index ab8415d..dfa9afe 100644</span><br><span>--- a/src/gb/gprs_ns2_sns.c</span><br><span>+++ b/src/gb/gprs_ns2_sns.c</span><br><span>@@ -81,6 +81,8 @@</span><br><span>        GPRS_SNS_EV_CHANGE_WEIGHT,</span><br><span>   GPRS_SNS_EV_NO_NSVC,</span><br><span>         GPRS_SNS_EV_NSVC_ALIVE,         /*!< a NS-VC became alive */</span><br><span style="color: hsl(120, 100%, 40%);">+       GPRS_SNS_EV_REQ_ADD_BIND,</span><br><span style="color: hsl(120, 100%, 40%);">+     GPRS_SNS_EV_REQ_DELETE_BIND,</span><br><span> };</span><br><span> </span><br><span> static const struct value_string gprs_sns_event_names[] = {</span><br><span>@@ -95,6 +97,8 @@</span><br><span>    { GPRS_SNS_EV_CHANGE_WEIGHT,    "CHANGE_WEIGHT" },</span><br><span>         { GPRS_SNS_EV_NO_NSVC,          "NO_NSVC" },</span><br><span>       { GPRS_SNS_EV_NSVC_ALIVE,       "NSVC_ALIVE"},</span><br><span style="color: hsl(120, 100%, 40%);">+      { GPRS_SNS_EV_REQ_ADD_BIND,     "ADD_BIND"},</span><br><span style="color: hsl(120, 100%, 40%);">+        { GPRS_SNS_EV_REQ_DELETE_BIND,  "DELETE_BIND"},</span><br><span>    { 0, NULL }</span><br><span> };</span><br><span> </span><br><span>@@ -103,6 +107,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 +119,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 *initial_bind;</span><br><span>   /* prevent recursive reselection */</span><br><span>  bool reselection_running;</span><br><span> </span><br><span>@@ -120,8 +133,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>@@ -718,7 +729,7 @@</span><br><span>       struct gprs_ns_ie_ip4_elem *ip4_elems;</span><br><span>       struct gprs_ns_ie_ip6_elem *ip6_elems;</span><br><span>       struct gprs_ns2_vc_bind *bind;</span><br><span style="color: hsl(0, 100%, 40%);">-  struct gprs_ns2_inst *nsi = gss->nse->nsi;</span><br><span style="color: hsl(120, 100%, 40%);">+      struct ns2_sns_bind *sbind;</span><br><span>  struct osmo_sockaddr *remote;</span><br><span>        const struct osmo_sockaddr *sa;</span><br><span>      struct osmo_sockaddr local;</span><br><span>@@ -741,23 +752,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->initial_bind) {</span><br><span style="color: hsl(120, 100%, 40%);">+          gss->initial_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->initial_bind->list.next != &gss->binds) {</span><br><span style="color: hsl(120, 100%, 40%);">+                       gss->initial_bind = llist_entry(gss->initial_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->initial_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->initial_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>@@ -773,11 +786,8 @@</span><br><span>                    return;</span><br><span> </span><br><span>          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(120, 100%, 40%);">+             llist_for_each_entry(sbind, &gss->binds, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+                       bind = sbind->bind;</span><br><span>                       sa = gprs_ns2_ip_bind_sockaddr(bind);</span><br><span>                        if (!sa)</span><br><span>                             continue;</span><br><span>@@ -813,10 +823,8 @@</span><br><span> </span><br><span>                 gss->ip6_local = ip6_elems;</span><br><span> </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(120, 100%, 40%);">+             llist_for_each_entry(sbind, &gss->binds, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+                       bind = sbind->bind;</span><br><span>                       sa = gprs_ns2_ip_bind_sockaddr(bind);</span><br><span>                        if (!sa)</span><br><span>                             continue;</span><br><span>@@ -1409,6 +1417,8 @@</span><br><span> {</span><br><span>       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 style="color: hsl(120, 100%, 40%);">+      struct ns2_sns_bind *sbind;</span><br><span style="color: hsl(120, 100%, 40%);">+   struct gprs_ns2_vc *nsvc, *nsvc2;</span><br><span> </span><br><span>        /* reset when receiving GPRS_SNS_EV_NO_NSVC */</span><br><span>       switch (event) {</span><br><span>@@ -1428,19 +1438,16 @@</span><br><span>           ns2_clear_ipv46_entries(gss);</span><br><span> </span><br><span>            /* Choose the next sns endpoint. */</span><br><span style="color: hsl(0, 100%, 40%);">-             if (llist_empty(&gss->sns_endpoints)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                if (llist_empty(&gss->sns_endpoints) || llist_empty(&gss->binds)) {</span><br><span>                    gss->initial = NULL;</span><br><span>                      ns2_prim_status_ind(gss->nse, NULL, 0, GPRS_NS2_AFF_CAUSE_SNS_NO_ENDPOINTS);</span><br><span>                      osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_UNCONFIGURED, 0, 3);</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>@@ -1449,6 +1456,50 @@</span><br><span>            gss->reselection_running = false;</span><br><span>                 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_SIZE, nse->nsi->timeout[NS_TOUT_TSNS_PROV], 1);</span><br><span>                break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case GPRS_SNS_EV_REQ_ADD_BIND:</span><br><span style="color: hsl(120, 100%, 40%);">+                sbind = data;</span><br><span style="color: hsl(120, 100%, 40%);">+         switch (fi->state) {</span><br><span style="color: hsl(120, 100%, 40%);">+               case GPRS_SNS_ST_UNCONFIGURED:</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%);">+                        break;</span><br><span style="color: hsl(120, 100%, 40%);">+                case GPRS_SNS_ST_SIZE:</span><br><span style="color: hsl(120, 100%, 40%);">+                        /* TODO: add the ip4 element to the list */</span><br><span style="color: hsl(120, 100%, 40%);">+                   break;</span><br><span style="color: hsl(120, 100%, 40%);">+                case GPRS_SNS_ST_CONFIG_BSS:</span><br><span style="color: hsl(120, 100%, 40%);">+          case GPRS_SNS_ST_CONFIG_SGSN:</span><br><span style="color: hsl(120, 100%, 40%);">+         case GPRS_SNS_ST_CONFIGURED:</span><br><span style="color: hsl(120, 100%, 40%);">+                  /* TODO: add to SNS-IP procedure queue & add nsvc() */</span><br><span style="color: hsl(120, 100%, 40%);">+                    break;</span><br><span style="color: hsl(120, 100%, 40%);">+                }</span><br><span style="color: hsl(120, 100%, 40%);">+             break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case GPRS_SNS_EV_REQ_DELETE_BIND:</span><br><span style="color: hsl(120, 100%, 40%);">+             sbind = data;</span><br><span style="color: hsl(120, 100%, 40%);">+         switch (fi->state) {</span><br><span style="color: hsl(120, 100%, 40%);">+               case GPRS_SNS_ST_UNCONFIGURED:</span><br><span style="color: hsl(120, 100%, 40%);">+                        break;</span><br><span style="color: hsl(120, 100%, 40%);">+                case GPRS_SNS_ST_SIZE:</span><br><span style="color: hsl(120, 100%, 40%);">+                        /* TODO: remove the ip4 element from the list */</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 == sbind->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%);">+                     break;</span><br><span style="color: hsl(120, 100%, 40%);">+                case GPRS_SNS_ST_CONFIG_BSS:</span><br><span style="color: hsl(120, 100%, 40%);">+          case GPRS_SNS_ST_CONFIG_SGSN:</span><br><span style="color: hsl(120, 100%, 40%);">+         case GPRS_SNS_ST_CONFIGURED:</span><br><span style="color: hsl(120, 100%, 40%);">+                  /* TODO: do an delete SNS-IP procedure */</span><br><span style="color: hsl(120, 100%, 40%);">+                     /* TODO: remove the ip4 element to the list */</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 == sbind->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%);">+                     break;</span><br><span style="color: hsl(120, 100%, 40%);">+                }</span><br><span style="color: hsl(120, 100%, 40%);">+             /* if this is the last bind, the free_nsvc() will trigger a reselection */</span><br><span style="color: hsl(120, 100%, 40%);">+            talloc_free(sbind);</span><br><span style="color: hsl(120, 100%, 40%);">+           break;</span><br><span>       }</span><br><span> }</span><br><span> </span><br><span>@@ -1457,7 +1508,9 @@</span><br><span>   .states = ns2_sns_bss_states,</span><br><span>        .num_states = ARRAY_SIZE(ns2_sns_bss_states),</span><br><span>        .allstate_event_mask = S(GPRS_SNS_EV_NO_NSVC) |</span><br><span style="color: hsl(0, 100%, 40%);">-                        S(GPRS_SNS_EV_SELECT_ENDPOINT),</span><br><span style="color: hsl(120, 100%, 40%);">+                               S(GPRS_SNS_EV_SELECT_ENDPOINT) |</span><br><span style="color: hsl(120, 100%, 40%);">+                              S(GPRS_SNS_EV_REQ_ADD_BIND) |</span><br><span style="color: hsl(120, 100%, 40%);">+                         S(GPRS_SNS_EV_REQ_DELETE_BIND),</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>@@ -1488,6 +1541,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 +1864,69 @@</span><br><span>  }</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+int gprs_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%);">+</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%);">+     }</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%);">+      osmo_fsm_inst_dispatch(nse->bss_sns_fi, GPRS_SNS_EV_REQ_ADD_BIND, tmp);</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 gprs_ns2_sns_del_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%);">+      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 -EINVAL;</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->initial_bind && gss->initial_bind->bind == bind) {</span><br><span style="color: hsl(120, 100%, 40%);">+          if (gss->initial_bind->list.prev == &gss->binds)</span><br><span style="color: hsl(120, 100%, 40%);">+                 gss->initial_bind = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+          else</span><br><span style="color: hsl(120, 100%, 40%);">+                  gss->initial_bind = llist_entry(gss->initial_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%);">+         }</span><br><span 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%);">+     osmo_fsm_inst_dispatch(nse->bss_sns_fi, GPRS_SNS_EV_REQ_DELETE_BIND, tmp);</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 7a6b3ba..01409bb 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,94 @@</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%);">+        /* all vbind of the nse will be freed by talloc */</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_bind->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 +276,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 +303,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 +326,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 +342,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>@@ -394,11 +521,18 @@</span><br><span> static void _config_write_ns_nse(struct vty *vty, struct gprs_ns2_nse *nse)</span><br><span> {</span><br><span>     struct gprs_ns2_vc *nsvc;</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%);">+ struct vty_nse_bind *vbind;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(vnse);</span><br><span> </span><br><span>       vty_out(vty, " nse %u%s", nse->nsei, VTY_NEWLINE);</span><br><span>      switch (nse->dialect) {</span><br><span>   case GPRS_NS2_DIALECT_SNS:</span><br><span>           ns2_sns_write_vty(vty, nse);</span><br><span style="color: hsl(120, 100%, 40%);">+          llist_for_each_entry(vbind, &vnse->binds, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+                      vty_out(vty, "  ip-sns-bind %s%s", vbind->vbind->name, VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+          }</span><br><span>            break;</span><br><span>       default:</span><br><span>             llist_for_each_entry(nsvc, &nse->nsvc, list) {</span><br><span>@@ -472,7 +606,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 +628,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 +1455,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 +1481,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 +1495,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 = gprs_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%);">+             gprs_ns2_sns_del_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 +1976,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 +2038,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>diff --git a/src/gb/libosmogb.map b/src/gb/libosmogb.map</span><br><span>index 699ed1b..588fabf 100644</span><br><span>--- a/src/gb/libosmogb.map</span><br><span>+++ b/src/gb/libosmogb.map</span><br><span>@@ -185,7 +185,9 @@</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_bind;</span><br><span> gprs_ns2_sns_add_endpoint;</span><br><span style="color: hsl(120, 100%, 40%);">+gprs_ns2_sns_del_bind;</span><br><span> gprs_ns2_sns_del_endpoint;</span><br><span> gprs_ns2_vty_init;</span><br><span> gprs_ns2_vty_init_reduced;</span><br><span>diff --git a/tests/gb/osmo-ns-dummy.cfg b/tests/gb/osmo-ns-dummy.cfg</span><br><span>index 1e6dc76..7269618 100644</span><br><span>--- a/tests/gb/osmo-ns-dummy.cfg</span><br><span>+++ b/tests/gb/osmo-ns-dummy.cfg</span><br><span>@@ -21,4 +21,5 @@</span><br><span>  nse 1235</span><br><span>   nsvc udp local 127.0.0.3 23000</span><br><span>  nse 1234</span><br><span style="color: hsl(120, 100%, 40%);">+  ip-sns-bind local</span><br><span>   ip-sns-remote 127.0.0.2 2158</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: 13 </div>
<div style="display:none"> Gerrit-Owner: lynxis lazus <lynxis@fe80.eu> </div>
<div style="display:none"> Gerrit-Reviewer: Jenkins Builder </div>
<div style="display:none"> Gerrit-Reviewer: daniel <dwillmann@sysmocom.de> </div>
<div style="display:none"> Gerrit-Reviewer: laforge <laforge@osmocom.org> </div>
<div style="display:none"> Gerrit-Reviewer: lynxis lazus <lynxis@fe80.eu> </div>
<div style="display:none"> Gerrit-Reviewer: pespin <pespin@sysmocom.de> </div>
<div style="display:none"> Gerrit-MessageType: merged </div>