<p>lynxis lazus has uploaded this change for <strong>review</strong>.</p><p><a href="https://gerrit.osmocom.org/c/libosmocore/+/24123">View Change</a></p><pre style="font-family: monospace,monospace; white-space: pre-wrap;">gprs_ns2: implement outbound ADD/DEL SNS procedures<br><br>When adding or removing a bind, the remote side needs to be<br>informed via the SNS-ADD/SNS-DELETE procedure.<br><br>Related: OS#5036<br>Change-Id: I71c33200bd1f0307ceb943ee958db5ebe3623d36<br>---<br>M src/gb/gprs_ns2_sns.c<br>1 file changed, 246 insertions(+), 43 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">git pull ssh://gerrit.osmocom.org:29418/libosmocore refs/changes/23/24123/1</pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/src/gb/gprs_ns2_sns.c b/src/gb/gprs_ns2_sns.c</span><br><span>index 7131974..accadac 100644</span><br><span>--- a/src/gb/gprs_ns2_sns.c</span><br><span>+++ b/src/gb/gprs_ns2_sns.c</span><br><span>@@ -124,6 +124,8 @@</span><br><span> </span><br><span> enum sns_bind_flag {</span><br><span>      SNS_BIND_CHANGE_REQ,            /*!< request to change weights */</span><br><span style="color: hsl(120, 100%, 40%);">+  SNS_BIND_ADD_REQ,               /*!< request to add */</span><br><span style="color: hsl(120, 100%, 40%);">+     SNS_BIND_DEL_REQ,               /*!< request to delete */</span><br><span> };</span><br><span> </span><br><span> struct sns_endpoint {</span><br><span>@@ -143,7 +145,7 @@</span><br><span> struct ns2_sns_bind {</span><br><span>       struct llist_head list;</span><br><span>      struct gprs_ns2_vc_bind *bind;</span><br><span style="color: hsl(0, 100%, 40%);">-  uint8_t change_weight_state;</span><br><span style="color: hsl(120, 100%, 40%);">+  uint8_t procedure_state;</span><br><span> };</span><br><span> </span><br><span> struct ns2_sns_state {</span><br><span>@@ -213,7 +215,7 @@</span><br><span> </span><br><span>       for (size_t i = 0; i < num; i++) {</span><br><span>                if (ip4[i].ip_addr == saddr->u.sin.sin_addr.s_addr &&</span><br><span style="color: hsl(0, 100%, 40%);">-                                ip4->udp_port == saddr->u.sin.sin_port)</span><br><span style="color: hsl(120, 100%, 40%);">+                         ip4[i].udp_port == saddr->u.sin.sin_port)</span><br><span>                         return &ip4[i];</span><br><span>  }</span><br><span> </span><br><span>@@ -469,6 +471,10 @@</span><br><span>                         if (bind->ll != GPRS_NS2_LL_UDP)</span><br><span>                          continue;</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+                 /* ignore binds which are about to be added or deleted */</span><br><span style="color: hsl(120, 100%, 40%);">+                     if (sbind->procedure_state & (S(SNS_BIND_ADD_REQ) | S(SNS_BIND_DEL_REQ)))</span><br><span style="color: hsl(120, 100%, 40%);">+                              continue;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>                  nsvc = nsvc_for_bind_and_remote(nse, bind, &remote);</span><br><span>                     if (!nsvc) {</span><br><span>                                 nsvc = gprs_ns2_ip_connect_inactive(bind, &remote, nse, 0);</span><br><span>@@ -500,6 +506,10 @@</span><br><span>                       if (bind->ll != GPRS_NS2_LL_UDP)</span><br><span>                          continue;</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+                 /* ignore binds which are about to be added or deleted */</span><br><span style="color: hsl(120, 100%, 40%);">+                     if (sbind->procedure_state & (S(SNS_BIND_ADD_REQ) | S(SNS_BIND_DEL_REQ)))</span><br><span style="color: hsl(120, 100%, 40%);">+                              continue;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>                  /* we only care about UDP binds */</span><br><span>                   nsvc = nsvc_for_bind_and_remote(nse, bind, &remote);</span><br><span>                     if (!nsvc) {</span><br><span>@@ -521,6 +531,49 @@</span><br><span>  return 0;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+/* Add a given local IPv4 element to gprs_sns_state */</span><br><span style="color: hsl(120, 100%, 40%);">+static int add_local_ip4_elem(struct ns2_sns_state *gss, uint32_t ip_addr, uint16_t port, uint16_t sig_weight, uint16_t data_weight)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   unsigned int i;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     if (gss->num_ip4_local + gss->num_ip4_remote >= gss->num_max_nsvcs)</span><br><span style="color: hsl(120, 100%, 40%);">+               return -NS_CAUSE_INVAL_NR_NS_VC;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    /* check for duplicates */</span><br><span style="color: hsl(120, 100%, 40%);">+    for (i = 0; i < gss->num_ip4_local; i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+              if (gss->ip4_local[i].ip_addr != ip_addr || gss->ip4_local[i].udp_port != port)</span><br><span style="color: hsl(120, 100%, 40%);">+                 continue;</span><br><span style="color: hsl(120, 100%, 40%);">+             /* TODO: log message duplicate */</span><br><span style="color: hsl(120, 100%, 40%);">+             /* TODO: check if this is the correct cause code */</span><br><span style="color: hsl(120, 100%, 40%);">+           return -NS_CAUSE_PROTO_ERR_UNSPEC;</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   gss->ip4_local = talloc_realloc(gss, gss->ip4_local, struct gprs_ns_ie_ip4_elem,</span><br><span style="color: hsl(120, 100%, 40%);">+                                         gss->num_ip4_local+1);</span><br><span style="color: hsl(120, 100%, 40%);">+    gss->ip4_local[gss->num_ip4_local].ip_addr = ip_addr;</span><br><span style="color: hsl(120, 100%, 40%);">+   gss->ip4_local[gss->num_ip4_local].udp_port = port;</span><br><span style="color: hsl(120, 100%, 40%);">+     gss->ip4_local[gss->num_ip4_local].sig_weight = sig_weight;</span><br><span style="color: hsl(120, 100%, 40%);">+     gss->ip4_local[gss->num_ip4_local].data_weight = data_weight;</span><br><span style="color: hsl(120, 100%, 40%);">+   gss->num_ip4_local += 1;</span><br><span style="color: hsl(120, 100%, 40%);">+   return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* Remove a given local IPv4 element from gprs_sns_state */</span><br><span style="color: hsl(120, 100%, 40%);">+static int remove_local_ip4_elem(struct ns2_sns_state *gss, const struct gprs_ns_ie_ip4_elem *ip4)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    unsigned int i;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     for (i = 0; i < gss->num_ip4_local; i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+              if (memcmp(&gss->ip4_local[i], ip4, sizeof(*ip4)))</span><br><span style="color: hsl(120, 100%, 40%);">+                     continue;</span><br><span style="color: hsl(120, 100%, 40%);">+             /* all array elements < i remain as they are; all > i are shifted left by one */</span><br><span style="color: hsl(120, 100%, 40%);">+                memmove(&gss->ip4_local[i], &gss->ip4_local[i+1], gss->num_ip4_local-i-1);</span><br><span style="color: hsl(120, 100%, 40%);">+           gss->num_ip4_local -= 1;</span><br><span style="color: hsl(120, 100%, 40%);">+           return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+     return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /* Add a given remote IPv4 element to gprs_sns_state */</span><br><span> static int add_remote_ip4_elem(struct ns2_sns_state *gss, const struct gprs_ns_ie_ip4_elem *ip4)</span><br><span> {</span><br><span>@@ -577,6 +630,49 @@</span><br><span>   return -1;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+/* Add a given local IPv6 element to gprs_sns_state */</span><br><span style="color: hsl(120, 100%, 40%);">+static int add_local_ip6_elem(struct ns2_sns_state *gss, const struct in6_addr *ip_addr, uint16_t port, uint16_t sig_weight, uint16_t data_weight)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    unsigned int i;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     if (gss->num_ip6_local + gss->num_ip6_remote >= gss->num_max_nsvcs)</span><br><span style="color: hsl(120, 100%, 40%);">+               return -NS_CAUSE_INVAL_NR_NS_VC;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    /* check for duplicates */</span><br><span style="color: hsl(120, 100%, 40%);">+    for (i = 0; i < gss->num_ip6_local; i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+              if (memcmp(&gss->ip6_local[i].ip_addr, ip_addr, sizeof(struct in6_addr)) || gss->ip6_local[i].udp_port != port)</span><br><span style="color: hsl(120, 100%, 40%);">+                     continue;</span><br><span style="color: hsl(120, 100%, 40%);">+             /* TODO: log message duplicate */</span><br><span style="color: hsl(120, 100%, 40%);">+             /* TODO: check if this is the correct cause code */</span><br><span style="color: hsl(120, 100%, 40%);">+           return -NS_CAUSE_PROTO_ERR_UNSPEC;</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   gss->ip6_local = talloc_realloc(gss, gss->ip6_local, struct gprs_ns_ie_ip6_elem,</span><br><span style="color: hsl(120, 100%, 40%);">+                                         gss->num_ip6_local+1);</span><br><span style="color: hsl(120, 100%, 40%);">+    memcpy(&gss->ip6_local[gss->num_ip6_local].ip_addr, ip_addr, sizeof(struct in6_addr));</span><br><span style="color: hsl(120, 100%, 40%);">+      gss->ip6_local[gss->num_ip6_local].udp_port = port;</span><br><span style="color: hsl(120, 100%, 40%);">+     gss->ip6_local[gss->num_ip6_local].sig_weight = sig_weight;</span><br><span style="color: hsl(120, 100%, 40%);">+     gss->ip6_local[gss->num_ip6_local].data_weight = data_weight;</span><br><span style="color: hsl(120, 100%, 40%);">+   gss->num_ip6_local += 1;</span><br><span style="color: hsl(120, 100%, 40%);">+   return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* Remove a given local IPv4 element from gprs_sns_state */</span><br><span style="color: hsl(120, 100%, 40%);">+static int remove_local_ip6_elem(struct ns2_sns_state *gss, const struct gprs_ns_ie_ip6_elem *ip6)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    unsigned int i;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     for (i = 0; i < gss->num_ip6_local; i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+              if (memcmp(&gss->ip6_local[i], ip6, sizeof(*ip6)))</span><br><span style="color: hsl(120, 100%, 40%);">+                     continue;</span><br><span style="color: hsl(120, 100%, 40%);">+             /* all array elements < i remain as they are; all > i are shifted left by one */</span><br><span style="color: hsl(120, 100%, 40%);">+                memmove(&gss->ip6_local[i], &gss->ip6_local[i+1], gss->num_ip6_local-i-1);</span><br><span style="color: hsl(120, 100%, 40%);">+           gss->num_ip6_local -= 1;</span><br><span style="color: hsl(120, 100%, 40%);">+           return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+     return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /* Add a given remote IPv6 element to gprs_sns_state */</span><br><span> static int add_remote_ip6_elem(struct ns2_sns_state *gss, const struct gprs_ns_ie_ip6_elem *ip6)</span><br><span> {</span><br><span>@@ -826,6 +922,9 @@</span><br><span>            const struct osmo_sockaddr *sa = gprs_ns2_ip_bind_sockaddr(sbind->bind);</span><br><span>          if (!sa)</span><br><span>                     continue;</span><br><span style="color: hsl(120, 100%, 40%);">+             /* ignore binds which will be added in the future via a procedure */</span><br><span style="color: hsl(120, 100%, 40%);">+          if (sbind->procedure_state & S(SNS_BIND_ADD_REQ))</span><br><span style="color: hsl(120, 100%, 40%);">+                      continue;</span><br><span> </span><br><span>                switch (stype) {</span><br><span>             case IPv4:</span><br><span>@@ -864,7 +963,7 @@</span><br><span>             remote = gprs_ns2_ip_vc_remote(gss->sns_nsvc);</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 = llist_count(&gss->binds);</span><br><span style="color: hsl(120, 100%, 40%);">+      count = ns2_sns_count_num_local_ep(fi, gss->ip);</span><br><span>  if (count == 0) {</span><br><span>            LOGPFSML(fi, LOGL_ERROR, "No local binds for this NSE -> cannot determine IP endpoints\n");</span><br><span>             return;</span><br><span>@@ -879,6 +978,9 @@</span><br><span>                gss->ip4_local = ip4_elems;</span><br><span>               llist_for_each_entry(sbind, &gss->binds, list) {</span><br><span>                      bind = sbind->bind;</span><br><span style="color: hsl(120, 100%, 40%);">+                        if (sbind->procedure_state & S(GPRS_SNS_EV_REQ_ADD_BIND))</span><br><span style="color: hsl(120, 100%, 40%);">+                              continue;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>                  sa = gprs_ns2_ip_bind_sockaddr(bind);</span><br><span>                        if (!sa)</span><br><span>                             continue;</span><br><span>@@ -915,6 +1017,9 @@</span><br><span> </span><br><span>                 llist_for_each_entry(sbind, &gss->binds, list) {</span><br><span>                      bind = sbind->bind;</span><br><span style="color: hsl(120, 100%, 40%);">+                        if (sbind->procedure_state & S(GPRS_SNS_EV_REQ_ADD_BIND))</span><br><span style="color: hsl(120, 100%, 40%);">+                              continue;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>                  sa = gprs_ns2_ip_bind_sockaddr(bind);</span><br><span>                        if (!sa)</span><br><span>                             continue;</span><br><span>@@ -944,16 +1049,29 @@</span><br><span>   }</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+static void ns2_sns_clean_procedures(struct ns2_sns_state *gss)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        struct ns2_sns_bind *sbind, *tmp;</span><br><span style="color: hsl(120, 100%, 40%);">+     llist_for_each_entry_safe(sbind, tmp, &gss->binds, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+             if (sbind->procedure_state & S(SNS_BIND_DEL_REQ))  {</span><br><span style="color: hsl(120, 100%, 40%);">+                   llist_del(&sbind->list);</span><br><span style="color: hsl(120, 100%, 40%);">+                       talloc_free(sbind);</span><br><span style="color: hsl(120, 100%, 40%);">+           } else {</span><br><span style="color: hsl(120, 100%, 40%);">+                      sbind->procedure_state = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+                }</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> static void ns2_sns_choose_next_bind(struct ns2_sns_state *gss)</span><br><span> {</span><br><span>       /* take the first bind or take the next bind */</span><br><span>      if (!gss->initial_bind) {</span><br><span style="color: hsl(0, 100%, 40%);">-            gss->initial_bind = llist_first_entry(&gss->binds, struct ns2_sns_bind, list);</span><br><span style="color: hsl(120, 100%, 40%);">+              gss->initial_bind = llist_first_entry_or_null(&gss->binds, struct ns2_sns_bind, list);</span><br><span>     } else {</span><br><span>             if (gss->initial_bind->list.next != &gss->binds) {</span><br><span>                      gss->initial_bind = llist_entry(gss->initial_bind->list.next, struct ns2_sns_bind, list);</span><br><span>           } else {</span><br><span style="color: hsl(0, 100%, 40%);">-                        gss->initial_bind = llist_first_entry(&gss->binds, struct ns2_sns_bind, list);</span><br><span style="color: hsl(120, 100%, 40%);">+                      gss->initial_bind = llist_first_entry_or_null(&gss->binds, struct ns2_sns_bind, list);</span><br><span>             }</span><br><span>    }</span><br><span> }</span><br><span>@@ -963,6 +1081,7 @@</span><br><span> {</span><br><span>   struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ // TODO: check if bss is even valid ! */</span><br><span>     OSMO_ASSERT(gss->role == GPRS_SNS_ROLE_BSS);</span><br><span> </span><br><span>  /* on a generic failure, the timer callback will recover */</span><br><span>@@ -975,6 +1094,7 @@</span><br><span>   gss->alive = false;</span><br><span> </span><br><span>   ns2_sns_compute_local_ep_from_binds(fi);</span><br><span style="color: hsl(120, 100%, 40%);">+      ns2_sns_clean_procedures(gss);</span><br><span>       ns2_sns_choose_next_bind(gss);</span><br><span> </span><br><span>   /* setup the NSVC */</span><br><span>@@ -1420,9 +1540,11 @@</span><br><span> </span><br><span> static void ns2_sns_st_configured_onenter(struct osmo_fsm_inst *fi, uint32_t old_state)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-       struct gprs_ns2_vc *nsvc;</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 gprs_ns2_inst *nsi = nse->nsi;</span><br><span style="color: hsl(120, 100%, 40%);">+      struct gprs_ns2_vc *nsvc;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct ns2_sns_bind *sbind;</span><br><span>  /* NS-VC status updates are only parsed in ST_CONFIGURED.</span><br><span>     * Do an initial check if there are any nsvc alive atm */</span><br><span>    llist_for_each_entry(nsvc, &nse->nsvc, list) {</span><br><span>@@ -1439,31 +1561,54 @@</span><br><span> </span><br><span>  if (old_state != GPRS_SNS_ST_LOCAL_PROCEDURE)</span><br><span>                ns2_prim_status_ind(nse, NULL, 0, GPRS_NS2_AFF_CAUSE_SNS_CONFIGURED);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       /* check if there are procedure waiting */</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%);">+               if (sbind->procedure_state) {</span><br><span style="color: hsl(120, 100%, 40%);">+                      osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_LOCAL_PROCEDURE,</span><br><span style="color: hsl(120, 100%, 40%);">+                                              nsi->timeout[NS_TOUT_TSNS_PROV], GPRS_SNS_ST_LOCAL_PROCEDURE);</span><br><span style="color: hsl(120, 100%, 40%);">+                     break;</span><br><span style="color: hsl(120, 100%, 40%);">+                }</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span> }</span><br><span> </span><br><span> static void ns2_sns_st_local_procedure_onenter(struct osmo_fsm_inst *fi, uint32_t old_state)</span><br><span> {</span><br><span>      struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);</span><br><span>     struct ns2_sns_bind *sns_bind;</span><br><span> </span><br><span>   if (gss->current_procedure.procedure == SNS_NONE) {</span><br><span>               gss->N = 0;</span><br><span>               /* select the next procedure */</span><br><span style="color: hsl(120, 100%, 40%);">+               // TODO: first check for BIND_ADD_REQ, then UPDATE_WEIGHT, then DELETE</span><br><span>               llist_for_each_entry(sns_bind, &gss->binds, list) {</span><br><span style="color: hsl(0, 100%, 40%);">-                      if (sns_bind->change_weight_state & S(SNS_BIND_CHANGE_REQ)) {</span><br><span style="color: hsl(0, 100%, 40%);">-                            sns_bind->change_weight_state = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+                 if (sns_bind->procedure_state & S(SNS_BIND_ADD_REQ)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                         sns_bind->procedure_state = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+                             gss->current_procedure.procedure = SNS_ADD;</span><br><span>                               gss->current_procedure.bind = sns_bind;</span><br><span style="color: hsl(120, 100%, 40%);">+                            break;</span><br><span style="color: hsl(120, 100%, 40%);">+                        } else if (sns_bind->procedure_state & S(SNS_BIND_CHANGE_REQ)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                               sns_bind->procedure_state = 0;</span><br><span>                            gss->current_procedure.procedure = SNS_CHANGE_WEIGHT;</span><br><span style="color: hsl(0, 100%, 40%);">-                                ns2_procedure_set_endpoint(gss);</span><br><span style="color: hsl(120, 100%, 40%);">+                              gss->current_procedure.bind = sns_bind;</span><br><span style="color: hsl(120, 100%, 40%);">+                            break;</span><br><span style="color: hsl(120, 100%, 40%);">+                        } else if (sns_bind->procedure_state & S(SNS_BIND_DEL_REQ)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                          sns_bind->procedure_state = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+                             gss->current_procedure.procedure = SNS_DEL;</span><br><span style="color: hsl(120, 100%, 40%);">+                                gss->current_procedure.bind = sns_bind;</span><br><span>                           break;</span><br><span>                       }</span><br><span>            }</span><br><span style="color: hsl(120, 100%, 40%);">+             // TODO: when add still set, take care of change weights at the same time (e.g. add a bind and change the weight at the same time)</span><br><span> </span><br><span>               if (gss->current_procedure.procedure == SNS_NONE) {</span><br><span>                       /* nothing to do */</span><br><span>                  osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_CONFIGURED, 0, 0);</span><br><span>                   return;</span><br><span>              }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           ns2_procedure_set_endpoint(gss);</span><br><span>             gss->current_procedure.trans_id++;</span><br><span>                if (gss->current_procedure.trans_id == 0)</span><br><span>                         gss->current_procedure.trans_id = 1;</span><br><span>@@ -1476,6 +1621,8 @@</span><br><span>                      ns2_tx_sns_add(gss->sns_nsvc, gss->current_procedure.trans_id, gss->current_procedure.ip4, 1, NULL, 0);</span><br><span>             else</span><br><span>                         ns2_tx_sns_add(gss->sns_nsvc, gss->current_procedure.trans_id, NULL, 0, gss->current_procedure.ip6, 1);</span><br><span style="color: hsl(120, 100%, 40%);">+              create_missing_nsvcs(fi);</span><br><span style="color: hsl(120, 100%, 40%);">+             gprs_ns2_start_alive_all_nsvcs(nse);</span><br><span>                 break;</span><br><span>       case SNS_CHANGE_WEIGHT:</span><br><span>              if (gss->ip == IPv4)</span><br><span>@@ -1500,7 +1647,7 @@</span><br><span>      struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);</span><br><span>     struct gprs_ns2_inst *nsi = nse->nsi;</span><br><span>     struct tlv_parsed *tp = data;</span><br><span style="color: hsl(0, 100%, 40%);">-   uint8_t trans_id;</span><br><span style="color: hsl(120, 100%, 40%);">+     uint8_t trans_id, cause;</span><br><span> </span><br><span>         switch (event) {</span><br><span>     case GPRS_SNS_EV_RX_ADD:</span><br><span>@@ -1521,16 +1668,26 @@</span><br><span>                   break;</span><br><span>               }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-           if (!TLVP_PRESENT(tp, NS_IE_CAUSE)) {</span><br><span style="color: hsl(0, 100%, 40%);">-                   gss->current_procedure.procedure = SNS_NONE;</span><br><span style="color: hsl(0, 100%, 40%);">-                 /* everything ok, local_procedure_onenter() will check if there are more procedures required */</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_LOCAL_PROCEDURE,</span><br><span style="color: hsl(0, 100%, 40%);">-                                                nsi->timeout[NS_TOUT_TSNS_PROV], GPRS_SNS_ST_LOCAL_PROCEDURE);</span><br><span style="color: hsl(0, 100%, 40%);">-                       return;</span><br><span style="color: hsl(0, 100%, 40%);">-         } else {</span><br><span style="color: hsl(120, 100%, 40%);">+              if (TLVP_PRESENT(tp, NS_IE_CAUSE)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                  cause = tlvp_val8(tp, NS_IE_CAUSE, 0);</span><br><span>                       /* what happend on error cause? return to size? */</span><br><span style="color: hsl(120, 100%, 40%);">+                    LOGPFSML(fi, LOGL_ERROR, "NSEI=%u Rx SNS ACK with cause code %d. Resetting SNS\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                           nse->nsei, cause);</span><br><span style="color: hsl(120, 100%, 40%);">+                        osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_REQ_SELECT_ENDPOINT, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+                    break;</span><br><span>               }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           // TODO: cleanup the bind also on SIZE or other failures</span><br><span style="color: hsl(120, 100%, 40%);">+              if (gss->current_procedure.procedure == SNS_DEL) {</span><br><span style="color: hsl(120, 100%, 40%);">+                 talloc_free(gss->current_procedure.bind);</span><br><span style="color: hsl(120, 100%, 40%);">+                  gss->current_procedure.bind = 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%);">+           gss->current_procedure.procedure = SNS_NONE;</span><br><span style="color: hsl(120, 100%, 40%);">+               /* everything ok, local_procedure_onenter() will check if there are more procedures required */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+             osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_LOCAL_PROCEDURE,</span><br><span style="color: hsl(120, 100%, 40%);">+                                      nsi->timeout[NS_TOUT_TSNS_PROV], GPRS_SNS_ST_LOCAL_PROCEDURE);</span><br><span>            break;</span><br><span>       }</span><br><span> }</span><br><span>@@ -1653,6 +1810,7 @@</span><br><span> /* common allstate-action for both roles */</span><br><span> static void ns2_sns_st_all_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)</span><br><span> {</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;</span><br><span>    struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);</span><br><span>     struct ns2_sns_bind *sbind;</span><br><span>  struct gprs_ns2_vc *nsvc, *nsvc2;</span><br><span>@@ -1662,45 +1820,57 @@</span><br><span>          sbind = data;</span><br><span>                switch (fi->state) {</span><br><span>              case GPRS_SNS_ST_UNCONFIGURED:</span><br><span style="color: hsl(0, 100%, 40%);">-                  osmo_fsm_inst_dispatch(nse->bss_sns_fi, GPRS_SNS_EV_REQ_SELECT_ENDPOINT, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+                    osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_REQ_SELECT_ENDPOINT, NULL);</span><br><span>                   break;</span><br><span>               case GPRS_SNS_ST_BSS_SIZE:</span><br><span style="color: hsl(0, 100%, 40%);">-                      /* TODO: add the ip4 element to the list */</span><br><span style="color: hsl(120, 100%, 40%);">+                   osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_BSS_SIZE, nse->nsi->timeout[NS_TOUT_TSNS_PROV], 1);</span><br><span>                    break;</span><br><span>               case GPRS_SNS_ST_BSS_CONFIG_BSS:</span><br><span>             case GPRS_SNS_ST_BSS_CONFIG_SGSN:</span><br><span style="color: hsl(120, 100%, 40%);">+                     sbind->procedure_state |= S(SNS_BIND_ADD_REQ);</span><br><span style="color: hsl(120, 100%, 40%);">+                     break;</span><br><span>               case GPRS_SNS_ST_CONFIGURED:</span><br><span style="color: hsl(0, 100%, 40%);">-                    /* TODO: add to SNS-IP procedure queue & add nsvc() */</span><br><span style="color: hsl(120, 100%, 40%);">+                    sbind->procedure_state |= S(SNS_BIND_ADD_REQ);</span><br><span style="color: hsl(120, 100%, 40%);">+                     osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_LOCAL_PROCEDURE, nse->nsi->timeout[NS_TOUT_TSNS_PROV], GPRS_SNS_ST_LOCAL_PROCEDURE);</span><br><span style="color: hsl(120, 100%, 40%);">+                    break;</span><br><span style="color: hsl(120, 100%, 40%);">+                case GPRS_SNS_ST_LOCAL_PROCEDURE:</span><br><span>                    break;</span><br><span>               }</span><br><span>            break;</span><br><span>       case GPRS_SNS_EV_REQ_DELETE_BIND:</span><br><span>            sbind = data;</span><br><span style="color: hsl(120, 100%, 40%);">+         sbind->procedure_state |= S(SNS_BIND_DEL_REQ);</span><br><span>            switch (fi->state) {</span><br><span>              case GPRS_SNS_ST_UNCONFIGURED:</span><br><span style="color: hsl(120, 100%, 40%);">+                        llist_del(&sbind->list);</span><br><span style="color: hsl(120, 100%, 40%);">+                       talloc_free(sbind);</span><br><span>                  break;</span><br><span>               case GPRS_SNS_ST_BSS_SIZE:</span><br><span style="color: hsl(0, 100%, 40%);">-                      /* TODO: remove the ip4 element from the list */</span><br><span style="color: hsl(0, 100%, 40%);">-                        llist_for_each_entry_safe(nsvc, nsvc2, &nse->nsvc, list) {</span><br><span style="color: hsl(0, 100%, 40%);">-                               if (nsvc->bind == sbind->bind) {</span><br><span style="color: hsl(0, 100%, 40%);">-                                  gprs_ns2_free_nsvc(nsvc);</span><br><span style="color: hsl(120, 100%, 40%);">+                     if (sbind == gss->initial_bind) {</span><br><span style="color: hsl(120, 100%, 40%);">+                          /* keep the order of binds */</span><br><span style="color: hsl(120, 100%, 40%);">+                         ns2_sns_choose_next_bind(gss);</span><br><span style="color: hsl(120, 100%, 40%);">+                                if (sbind == gss->initial_bind)</span><br><span style="color: hsl(120, 100%, 40%);">+                                    gss->initial_bind = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+                          llist_del(&sbind->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>                            }</span><br><span style="color: hsl(120, 100%, 40%);">+                     } else {</span><br><span style="color: hsl(120, 100%, 40%);">+                              llist_del(&sbind->list);</span><br><span>                      }</span><br><span style="color: hsl(120, 100%, 40%);">+                     talloc_free(sbind);</span><br><span>                  break;</span><br><span>               case GPRS_SNS_ST_BSS_CONFIG_BSS:</span><br><span>             case GPRS_SNS_ST_BSS_CONFIG_SGSN:</span><br><span style="color: hsl(120, 100%, 40%);">+                     break;</span><br><span>               case GPRS_SNS_ST_CONFIGURED:</span><br><span style="color: hsl(0, 100%, 40%);">-                    /* TODO: do an delete SNS-IP procedure */</span><br><span style="color: hsl(0, 100%, 40%);">-                       /* TODO: remove the ip4 element to the list */</span><br><span style="color: hsl(0, 100%, 40%);">-                  llist_for_each_entry_safe(nsvc, nsvc2, &nse->nsvc, list) {</span><br><span style="color: hsl(0, 100%, 40%);">-                               if (nsvc->bind == sbind->bind) {</span><br><span style="color: hsl(0, 100%, 40%);">-                                  gprs_ns2_free_nsvc(nsvc);</span><br><span style="color: hsl(0, 100%, 40%);">-                               }</span><br><span style="color: hsl(0, 100%, 40%);">-                       }</span><br><span style="color: hsl(120, 100%, 40%);">+                     osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_LOCAL_PROCEDURE, nse->nsi->timeout[NS_TOUT_TSNS_PROV], GPRS_SNS_ST_LOCAL_PROCEDURE);</span><br><span style="color: hsl(120, 100%, 40%);">+                    break;</span><br><span style="color: hsl(120, 100%, 40%);">+                case GPRS_SNS_ST_LOCAL_PROCEDURE:</span><br><span>                    break;</span><br><span>               }</span><br><span style="color: hsl(0, 100%, 40%);">-               /* if this is the last bind, the free_nsvc() will trigger a reselection */</span><br><span style="color: hsl(0, 100%, 40%);">-              talloc_free(sbind);</span><br><span>          break;</span><br><span>       case GPRS_SNS_EV_REQ_CHANGE_WEIGHT:</span><br><span>          sbind = data;</span><br><span>@@ -1710,11 +1880,21 @@</span><br><span>                      /* unconfigured or size don't need a procedure */</span><br><span>                        break;</span><br><span>               /* all other states */</span><br><span style="color: hsl(0, 100%, 40%);">-          default:</span><br><span style="color: hsl(0, 100%, 40%);">-                        /* change the flag */</span><br><span style="color: hsl(0, 100%, 40%);">-                   sbind->change_weight_state |= S(SNS_BIND_CHANGE_REQ);</span><br><span style="color: hsl(120, 100%, 40%);">+              case GPRS_SNS_ST_BSS_CONFIG_BSS:</span><br><span style="color: hsl(120, 100%, 40%);">+              case GPRS_SNS_ST_BSS_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%);">+                  /* ignore update weights when the bind hasn't added */</span><br><span style="color: hsl(120, 100%, 40%);">+                    if (sbind->procedure_state & S(SNS_BIND_ADD_REQ))</span><br><span style="color: hsl(120, 100%, 40%);">+                              return;</span><br><span style="color: hsl(120, 100%, 40%);">+                       sbind->procedure_state |= S(SNS_BIND_CHANGE_REQ);</span><br><span>                         osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_LOCAL_PROCEDURE, nse->nsi->timeout[NS_TOUT_TSNS_PROV], GPRS_SNS_ST_LOCAL_PROCEDURE);</span><br><span>                   break;</span><br><span style="color: hsl(120, 100%, 40%);">+                case GPRS_SNS_ST_LOCAL_PROCEDURE:</span><br><span style="color: hsl(120, 100%, 40%);">+                     /* ignore update weights when the bind hasn't added */</span><br><span style="color: hsl(120, 100%, 40%);">+                    if (sbind->procedure_state & S(SNS_BIND_ADD_REQ))</span><br><span style="color: hsl(120, 100%, 40%);">+                              return;</span><br><span style="color: hsl(120, 100%, 40%);">+                       sbind->procedure_state |= S(SNS_BIND_DEL_REQ);</span><br><span style="color: hsl(120, 100%, 40%);">+                     break;</span><br><span>               }</span><br><span>            break;</span><br><span>       }</span><br><span>@@ -1745,7 +1925,9 @@</span><br><span>            ns2_clear_ipv46_entries_remote(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) || llist_empty(&gss->binds)) {</span><br><span style="color: hsl(120, 100%, 40%);">+             ns2_sns_clean_procedures(gss);</span><br><span style="color: hsl(120, 100%, 40%);">+                ns2_sns_choose_next_bind(gss);</span><br><span style="color: hsl(120, 100%, 40%);">+                if (llist_empty(&gss->sns_endpoints) || !gss->initial_bind) {</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>@@ -2167,7 +2349,6 @@</span><br><span>                 return -ENOMEM;</span><br><span>      tmp->bind = bind;</span><br><span>         llist_add_tail(&tmp->list, &gss->binds);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span>       osmo_fsm_inst_dispatch(nse->bss_sns_fi, GPRS_SNS_EV_REQ_ADD_BIND, tmp);</span><br><span>   return 0;</span><br><span> }</span><br><span>@@ -2193,7 +2374,6 @@</span><br><span> </span><br><span>   llist_for_each_entry_safe(tmp, tmp2, &gss->binds, list) {</span><br><span>             if (tmp->bind == bind) {</span><br><span style="color: hsl(0, 100%, 40%);">-                     llist_del(&tmp->list);</span><br><span>                        found = true;</span><br><span>                        break;</span><br><span>               }</span><br><span>@@ -2212,6 +2392,7 @@</span><br><span>    const struct osmo_sockaddr *sa;</span><br><span>      struct gprs_ns_ie_ip4_elem *ip4;</span><br><span>     struct gprs_ns_ie_ip6_elem *ip6;</span><br><span style="color: hsl(120, 100%, 40%);">+      int rc;</span><br><span> </span><br><span>  /* TODO: ensure this bind is already added! */</span><br><span>       OSMO_ASSERT(gss->current_procedure.procedure != SNS_NONE);</span><br><span>@@ -2229,8 +2410,18 @@</span><br><span>                       ip4 = ip4_elem_by_saddr(gss->ip4_local, gss->num_ip4_local, sa);</span><br><span>               }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-           /* TODO: check if this bind is about to be added */</span><br><span style="color: hsl(0, 100%, 40%);">-             OSMO_ASSERT(ip4);</span><br><span style="color: hsl(120, 100%, 40%);">+             if (gss->current_procedure.procedure == SNS_CHANGE_WEIGHT || gss->current_procedure.procedure == SNS_DEL) {</span><br><span style="color: hsl(120, 100%, 40%);">+                     /* for SNS-UPDATE-PROCEDURE we need to find an endpoint */</span><br><span style="color: hsl(120, 100%, 40%);">+                    OSMO_ASSERT(ip4);</span><br><span style="color: hsl(120, 100%, 40%);">+             } else if (gss->current_procedure.procedure == SNS_ADD) {</span><br><span style="color: hsl(120, 100%, 40%);">+                  OSMO_ASSERT(!ip4);</span><br><span style="color: hsl(120, 100%, 40%);">+                    rc = add_local_ip4_elem(gss, sa->u.sin.sin_addr.s_addr, sa->u.sin.sin_port,</span><br><span style="color: hsl(120, 100%, 40%);">+                                        gss->current_procedure.bind->bind->sns_sig_weight,</span><br><span style="color: hsl(120, 100%, 40%);">+                                           gss->current_procedure.bind->bind->sns_data_weight);</span><br><span style="color: hsl(120, 100%, 40%);">+                      OSMO_ASSERT(!rc);</span><br><span style="color: hsl(120, 100%, 40%);">+                     ip4 = &gss->ip4_local[gss->num_ip4_local - 1];</span><br><span style="color: hsl(120, 100%, 40%);">+              }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>          gss->current_procedure.ip4 = ip4;</span><br><span>                 break;</span><br><span>       case AF_INET6:</span><br><span>@@ -2242,7 +2433,19 @@</span><br><span>              } else {</span><br><span>                     ip6 = ip6_elem_by_saddr(gss->ip6_local, gss->num_ip6_local, sa);</span><br><span>               }</span><br><span style="color: hsl(0, 100%, 40%);">-               OSMO_ASSERT(ip6);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           /* for SNS-UPDATE-PROCEDURE we need to find an endpoint */</span><br><span style="color: hsl(120, 100%, 40%);">+            if (gss->current_procedure.procedure == SNS_CHANGE_WEIGHT || gss->current_procedure.procedure == SNS_DEL) {</span><br><span style="color: hsl(120, 100%, 40%);">+                     OSMO_ASSERT(ip6);</span><br><span style="color: hsl(120, 100%, 40%);">+             } else if (gss->current_procedure.procedure == SNS_ADD) {</span><br><span style="color: hsl(120, 100%, 40%);">+                  OSMO_ASSERT(!ip6);</span><br><span style="color: hsl(120, 100%, 40%);">+                    rc = add_local_ip6_elem(gss, &sa->u.sin6.sin6_addr, sa->u.sin6.sin6_port,</span><br><span style="color: hsl(120, 100%, 40%);">+                                      gss->current_procedure.bind->bind->sns_sig_weight,</span><br><span style="color: hsl(120, 100%, 40%);">+                                           gss->current_procedure.bind->bind->sns_data_weight);</span><br><span style="color: hsl(120, 100%, 40%);">+                      OSMO_ASSERT(!rc);</span><br><span style="color: hsl(120, 100%, 40%);">+                     ip6 = &gss->ip6_local[gss->num_ip6_local - 1];</span><br><span style="color: hsl(120, 100%, 40%);">+              }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>          gss->current_procedure.ip6 = ip6;</span><br><span>                 break;</span><br><span>       default:</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.osmocom.org/c/libosmocore/+/24123">change 24123</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/+/24123"/><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: I71c33200bd1f0307ceb943ee958db5ebe3623d36 </div>
<div style="display:none"> Gerrit-Change-Number: 24123 </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>