<p>lynxis lazus has uploaded this change for <strong>review</strong>.</p><p><a href="https://gerrit.osmocom.org/c/libosmocore/+/23187">View Change</a></p><pre style="font-family: monospace,monospace; white-space: pre-wrap;">WIP: gprs_ns2: sns: implement local procedure change weight<br><br>Change-Id: Icec4dabb46bc198f68f91bfe09ba279fbe68d454<br>---<br>M src/gb/gprs_ns2.c<br>M src/gb/gprs_ns2_internal.h<br>M src/gb/gprs_ns2_sns.c<br>3 files changed, 422 insertions(+), 19 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">git pull ssh://gerrit.osmocom.org:29418/libosmocore refs/changes/87/23187/1</pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/src/gb/gprs_ns2.c b/src/gb/gprs_ns2.c</span><br><span>index c56b0b5..e3d3298 100644</span><br><span>--- a/src/gb/gprs_ns2.c</span><br><span>+++ b/src/gb/gprs_ns2.c</span><br><span>@@ -1289,6 +1289,7 @@</span><br><span>     nsi->timeout[NS_TOUT_TSNS_PROV] = 3; /* 1..10 */</span><br><span>  nsi->timeout[NS_TOUT_TSNS_SIZE_RETRIES] = 3;</span><br><span>      nsi->timeout[NS_TOUT_TSNS_CONFIG_RETRIES] = 3;</span><br><span style="color: hsl(120, 100%, 40%);">+     nsi->timeout[NS_TOUT_TSNS_PROCEDURES_RETRIES] = 3;</span><br><span> </span><br><span>    return nsi;</span><br><span> }</span><br><span>diff --git a/src/gb/gprs_ns2_internal.h b/src/gb/gprs_ns2_internal.h</span><br><span>index 1bef753..35933aa 100644</span><br><span>--- a/src/gb/gprs_ns2_internal.h</span><br><span>+++ b/src/gb/gprs_ns2_internal.h</span><br><span>@@ -33,8 +33,8 @@</span><br><span> struct gprs_ns2_vc_driver;</span><br><span> struct gprs_ns2_vc_bind;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-#define NS_TIMERS_COUNT 10</span><br><span style="color: hsl(0, 100%, 40%);">-#define NS_TIMERS "(tns-block|tns-block-retries|tns-reset|tns-reset-retries|tns-test|tns-alive|tns-alive-retries|tsns-prov|tsns-size-retries|tsns-config-retries)"</span><br><span style="color: hsl(120, 100%, 40%);">+#define NS_TIMERS_COUNT 11</span><br><span style="color: hsl(120, 100%, 40%);">+#define NS_TIMERS "(tns-block|tns-block-retries|tns-reset|tns-reset-retries|tns-test|tns-alive|tns-alive-retries|tsns-prov|tsns-size-retries|tsns-config-retries|tsns-procedures-retries)"</span><br><span> #define NS_TIMERS_HELP       \</span><br><span>    "(un)blocking Timer (Tns-block) timeout\n"            \</span><br><span>    "(un)blocking Timer (Tns-block) number of retries\n"  \</span><br><span>@@ -46,6 +46,7 @@</span><br><span>        "SNS Provision Timer (Tsns-prov) timeout\n"           \</span><br><span>    "SNS Size number of retries\n"                                \</span><br><span>    "SNS Config number of retries\n"                      \</span><br><span style="color: hsl(120, 100%, 40%);">+     "SNS Procedures number of retries\n"                  \</span><br><span> </span><br><span> /* Educated guess - LLC user payload is 1500 bytes plus possible headers */</span><br><span> #define NS_ALLOC_SIZE   3072</span><br><span>@@ -62,6 +63,7 @@</span><br><span>     NS_TOUT_TSNS_PROV,</span><br><span>   NS_TOUT_TSNS_SIZE_RETRIES,</span><br><span>   NS_TOUT_TSNS_CONFIG_RETRIES,</span><br><span style="color: hsl(120, 100%, 40%);">+  NS_TOUT_TSNS_PROCEDURES_RETRIES,</span><br><span> };</span><br><span> </span><br><span> enum nsvc_timer_mode {</span><br><span>diff --git a/src/gb/gprs_ns2_sns.c b/src/gb/gprs_ns2_sns.c</span><br><span>index 86b4fdf..3517378 100644</span><br><span>--- a/src/gb/gprs_ns2_sns.c</span><br><span>+++ b/src/gb/gprs_ns2_sns.c</span><br><span>@@ -35,6 +35,8 @@</span><br><span>  * - No concurrent dual stack. It supports either IPv4 or IPv6, but not both at the same time.</span><br><span>  * - SNS Add/Change/Delete: Doesn't answer on the same NSVC as received SNS ADD/CHANGE/DELETE PDUs.</span><br><span>  * - SNS Add/Change/Delete: Doesn't communicated the failed IPv4/IPv6 entries on the SNS_ACK.</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> #include <errno.h></span><br><span>@@ -67,6 +69,7 @@</span><br><span>     GPRS_SNS_ST_CONFIG_BSS,         /*!< SNS-CONFIG procedure (BSS->SGSN) ongoing */</span><br><span>       GPRS_SNS_ST_CONFIG_SGSN,        /*!< SNS-CONFIG procedure (SGSN->BSS) ongoing */</span><br><span>       GPRS_SNS_ST_CONFIGURED,</span><br><span style="color: hsl(120, 100%, 40%);">+       GPRS_SNS_ST_LOCAL_PROCEDURE,    /*!< in process of a ADD/DEL/UPDATE procedure towards SGSN (BSS->SGSN) */</span><br><span> };</span><br><span> </span><br><span> enum gprs_sns_event {</span><br><span>@@ -79,10 +82,12 @@</span><br><span>     GPRS_SNS_EV_RX_ADD,</span><br><span>  GPRS_SNS_EV_RX_DELETE,</span><br><span>       GPRS_SNS_EV_RX_CHANGE_WEIGHT,</span><br><span style="color: hsl(120, 100%, 40%);">+ GPRS_SNS_EV_RX_ACK,</span><br><span>  GPRS_SNS_EV_REQ_NO_NSVC,</span><br><span>     GPRS_SNS_EV_REQ_NSVC_ALIVE,             /*!< a NS-VC became alive */</span><br><span>      GPRS_SNS_EV_REQ_ADD_BIND,</span><br><span>    GPRS_SNS_EV_REQ_DELETE_BIND,</span><br><span style="color: hsl(120, 100%, 40%);">+  GPRS_SNS_EV_REQ_CHANGE_WEIGHT,          /*!< a bind changed its weight */</span><br><span> };</span><br><span> </span><br><span> static const struct value_string gprs_sns_event_names[] = {</span><br><span>@@ -95,13 +100,21 @@</span><br><span>         { GPRS_SNS_EV_RX_ADD,                   "RX_ADD" },</span><br><span>        { GPRS_SNS_EV_RX_DELETE,                "RX_DELETE" },</span><br><span>     { GPRS_SNS_EV_RX_CHANGE_WEIGHT,         "RX_CHANGE_WEIGHT" },</span><br><span style="color: hsl(120, 100%, 40%);">+       { GPRS_SNS_EV_RX_ACK,                   "RX_ACK" },</span><br><span>        { GPRS_SNS_EV_REQ_NO_NSVC,              "REQ_NO_NSVC" },</span><br><span>   { GPRS_SNS_EV_REQ_NSVC_ALIVE,           "REQ_NSVC_ALIVE"},</span><br><span>         { GPRS_SNS_EV_REQ_ADD_BIND,             "REQ_ADD_BIND"},</span><br><span>   { GPRS_SNS_EV_REQ_DELETE_BIND,          "REQ_DELETE_BIND"},</span><br><span style="color: hsl(120, 100%, 40%);">+ { GPRS_SNS_EV_REQ_CHANGE_WEIGHT,        "REQ_UPDATE_WEIGHT"},</span><br><span>      { 0, NULL }</span><br><span> };</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+enum sns_procedure {</span><br><span style="color: hsl(120, 100%, 40%);">+   SNS_ADD,</span><br><span style="color: hsl(120, 100%, 40%);">+      SNS_DEL,</span><br><span style="color: hsl(120, 100%, 40%);">+      SNS_CHANGE_WEIGHT,</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> struct sns_endpoint {</span><br><span>    struct llist_head list;</span><br><span>      struct osmo_sockaddr saddr;</span><br><span>@@ -112,6 +125,13 @@</span><br><span>   struct gprs_ns2_vc_bind *bind;</span><br><span> };</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+struct ns2_sns_procedure {</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%);">+        void *endpoint;</span><br><span style="color: hsl(120, 100%, 40%);">+       enum sns_procedure procedure;</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>@@ -133,12 +153,20 @@</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(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       /* all pending local procedures*/</span><br><span style="color: hsl(120, 100%, 40%);">+     struct llist_head procedures;</span><br><span style="color: hsl(120, 100%, 40%);">+ /* all current procedure */</span><br><span style="color: hsl(120, 100%, 40%);">+   struct ns2_sns_procedure *current;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>         /* timer N */</span><br><span>        int N;</span><br><span>       /* true if at least one nsvc is alive */</span><br><span>     bool alive;</span><br><span>  /* alive timeout, to ensure at least one NSVC comes after X online */</span><br><span>        struct osmo_timer_list alive_timeout;</span><br><span style="color: hsl(120, 100%, 40%);">+ /* valid transaction id to use for our procedures */</span><br><span style="color: hsl(120, 100%, 40%);">+  uint8_t trans_id;</span><br><span> </span><br><span>        /* local configuration to send to the remote end */</span><br><span>  struct gprs_ns_ie_ip4_elem *ip4_local;</span><br><span>@@ -163,12 +191,42 @@</span><br><span>       unsigned int num_ip6_remote;</span><br><span> };</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+static void add_local_procedure(struct ns2_sns_state *gss, enum sns_procedure procedure, void *endpoint);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> static inline struct gprs_ns2_nse *nse_inst_from_fi(struct osmo_fsm_inst *fi)</span><br><span> {</span><br><span>    struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;</span><br><span>    return gss->nse;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+static struct gprs_ns_ie_ip4_elem *ip4_elem_by_saddr(struct gprs_ns_ie_ip4_elem *ip4, size_t num, const struct osmo_sockaddr *saddr)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ if (saddr->u.sa.sa_family != AF_INET)</span><br><span style="color: hsl(120, 100%, 40%);">+              return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        for (size_t i = 0; i < num; i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+         if (ip4[i].ip_addr == saddr->u.sin.sin_addr.s_addr &&</span><br><span style="color: hsl(120, 100%, 40%);">+                              ip4->udp_port == saddr->u.sin.sin_port)</span><br><span style="color: hsl(120, 100%, 40%);">+                 return &ip4[i];</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   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 gprs_ns_ie_ip6_elem *ip6_elem_by_saddr(struct gprs_ns_ie_ip6_elem *ip6, size_t num, const struct osmo_sockaddr *saddr)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    if (saddr->u.sa.sa_family != AF_INET6)</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%);">+        for (size_t i = 0; i < num; i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+         if (memcmp(&ip6[i].ip_addr, &saddr->u.sin6.sin6_addr, sizeof(struct in6_addr)) == 0 &&</span><br><span style="color: hsl(120, 100%, 40%);">+                             ip6->udp_port == saddr->u.sin6.sin6_port)</span><br><span style="color: hsl(120, 100%, 40%);">+                       return &ip6[i];</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /* helper function to compute the sum of all (data or signaling) weights */</span><br><span> static int ip4_weight_sum(const struct gprs_ns_ie_ip4_elem *ip4, unsigned int num,</span><br><span>                         bool data_weight)</span><br><span>@@ -283,6 +341,8 @@</span><br><span> </span><br><span> static void ns2_clear_ipv46_entries(struct ns2_sns_state *gss)</span><br><span> {</span><br><span style="color: hsl(120, 100%, 40%);">+  struct ns2_sns_procedure *procedure, *tmp;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>         TALLOC_FREE(gss->ip4_local);</span><br><span>      TALLOC_FREE(gss->ip4_remote);</span><br><span>     TALLOC_FREE(gss->ip6_local);</span><br><span>@@ -292,6 +352,15 @@</span><br><span>       gss->num_ip4_remote = 0;</span><br><span>  gss->num_ip6_local = 0;</span><br><span>   gss->num_ip6_remote = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (gss->current)</span><br><span style="color: hsl(120, 100%, 40%);">+          talloc_free(gss->current);</span><br><span style="color: hsl(120, 100%, 40%);">+ gss->current = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     llist_for_each_entry_safe(procedure, tmp, &gss->procedures, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+            llist_del(&procedure->list);</span><br><span style="color: hsl(120, 100%, 40%);">+           talloc_free(&procedure);</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span> }</span><br><span> </span><br><span> static void ns2_vc_create_ip(struct osmo_fsm_inst *fi, struct gprs_ns2_nse *nse, const struct osmo_sockaddr *remote,</span><br><span>@@ -433,6 +502,47 @@</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)</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 (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%);">+             /* 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] = *ip4;</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 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>@@ -743,7 +853,7 @@</span><br><span>  if (old_state != GPRS_SNS_ST_SIZE)</span><br><span>           gss->N = 0;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(120, 100%, 40%);">+    gss->trans_id = 0;</span><br><span>        gss->alive = false;</span><br><span>       ns2_clear_ipv46_entries(gss);</span><br><span> </span><br><span>@@ -1149,19 +1259,19 @@</span><br><span>          if (TLVP_PRESENT(tp, NS_IE_IPv4_LIST)) {</span><br><span>                     v4_list = (const struct gprs_ns_ie_ip4_elem *) TLVP_VAL(tp, NS_IE_IPv4_LIST);</span><br><span>                        num_v4 = TLVP_LEN(tp, NS_IE_IPv4_LIST) / sizeof(*v4_list);</span><br><span style="color: hsl(0, 100%, 40%);">-                      for ( i = 0; i < num_v4; i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+                    for (i = 0; i < num_v4; i++) {</span><br><span>                            rc = do_sns_delete(fi, &v4_list[i], NULL);</span><br><span>                               if (rc < 0) {</span><br><span>                                     cause = -rc;</span><br><span>                                         /* continue to delete others */</span><br><span>                              }</span><br><span>                    }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>                  if (cause != 0xff) {</span><br><span>                                 /* TODO: create list of not-deleted and return it */</span><br><span>                                 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);</span><br><span>                            return;</span><br><span>                      }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span>            } else if (TLVP_PRESENT(tp, NS_IE_IP_ADDR) && TLVP_LEN(tp, NS_IE_IP_ADDR) == 5) {</span><br><span>                    /* delete all NS-VCs for given IPv4 address */</span><br><span>                       const uint8_t *ie = TLVP_VAL(tp, NS_IE_IP_ADDR);</span><br><span>@@ -1302,6 +1412,7 @@</span><br><span> static void ns2_sns_st_configured(struct osmo_fsm_inst *fi, uint32_t event, void *data)</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_inst *nsi = nse_inst_from_fi(fi)->nsi;</span><br><span>    struct tlv_parsed *tp = data;</span><br><span> </span><br><span>    switch (event) {</span><br><span>@@ -1317,13 +1428,103 @@</span><br><span>  case GPRS_SNS_EV_REQ_NSVC_ALIVE:</span><br><span>             osmo_timer_del(&gss->alive_timeout);</span><br><span>          break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case GPRS_SNS_EV_REQ_CHANGE_WEIGHT:</span><br><span style="color: hsl(120, 100%, 40%);">+           osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_LOCAL_PROCEDURE, nsi->timeout[NS_TOUT_TSNS_PROV], GPRS_SNS_ST_LOCAL_PROCEDURE);</span><br><span style="color: hsl(120, 100%, 40%);">+            break;</span><br><span>       }</span><br><span> }</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>   struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);</span><br><span style="color: hsl(0, 100%, 40%);">-        ns2_prim_status_ind(nse, NULL, 0, GPRS_NS2_AFF_CAUSE_SNS_CONFIGURED);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (old_state != GPRS_SNS_ST_LOCAL_PROCEDURE)</span><br><span style="color: hsl(120, 100%, 40%);">+         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%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void ns2_sns_st_local_procedure_onenter(struct osmo_fsm_inst *fi, uint32_t old_state)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct ns2_sns_procedure *current;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  if (!gss->current) {</span><br><span style="color: hsl(120, 100%, 40%);">+               gss->current = llist_first_entry_or_null(&gss->procedures, struct ns2_sns_procedure, list);</span><br><span style="color: hsl(120, 100%, 40%);">+         if (!gss->current) {</span><br><span style="color: hsl(120, 100%, 40%);">+                       osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_CONFIGURED, 0, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+                    return;</span><br><span style="color: hsl(120, 100%, 40%);">+               }</span><br><span style="color: hsl(120, 100%, 40%);">+             llist_del(&gss->current->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%);">+   current = gss->current;</span><br><span style="color: hsl(120, 100%, 40%);">+    switch (current->procedure) {</span><br><span style="color: hsl(120, 100%, 40%);">+      case SNS_ADD:</span><br><span style="color: hsl(120, 100%, 40%);">+         if (gss->ip == IPv4)</span><br><span style="color: hsl(120, 100%, 40%);">+                       ns2_tx_sns_add(gss->sns_nsvc, gss->trans_id, current->endpoint, 1, NULL, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+         else</span><br><span style="color: hsl(120, 100%, 40%);">+                  ns2_tx_sns_add(gss->sns_nsvc, gss->trans_id, NULL, 0, current->endpoint, 1);</span><br><span style="color: hsl(120, 100%, 40%);">+         break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case SNS_CHANGE_WEIGHT:</span><br><span style="color: hsl(120, 100%, 40%);">+               if (gss->ip == IPv4)</span><br><span style="color: hsl(120, 100%, 40%);">+                       ns2_tx_sns_change_weight(gss->sns_nsvc, gss->trans_id, current->endpoint, 1, NULL, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+               else</span><br><span style="color: hsl(120, 100%, 40%);">+                  ns2_tx_sns_change_weight(gss->sns_nsvc, gss->trans_id, NULL, 0, current->endpoint, 1);</span><br><span style="color: hsl(120, 100%, 40%);">+               break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case SNS_DEL:</span><br><span style="color: hsl(120, 100%, 40%);">+         if (gss->ip == IPv4)</span><br><span style="color: hsl(120, 100%, 40%);">+                       ns2_tx_sns_del(gss->sns_nsvc, gss->trans_id, current->endpoint, 1, NULL, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+         else</span><br><span style="color: hsl(120, 100%, 40%);">+                  ns2_tx_sns_del(gss->sns_nsvc, gss->trans_id, NULL, 0, current->endpoint, 1);</span><br><span style="color: hsl(120, 100%, 40%);">+         break;</span><br><span style="color: hsl(120, 100%, 40%);">+        }</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void ns2_sns_st_local_procedure(struct osmo_fsm_inst *fi, uint32_t event, void *data)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);</span><br><span style="color: hsl(120, 100%, 40%);">+      struct gprs_ns2_inst *nsi = nse->nsi;</span><br><span style="color: hsl(120, 100%, 40%);">+      struct tlv_parsed *tp = data;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t trans_id;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   switch (event) {</span><br><span style="color: hsl(120, 100%, 40%);">+      case GPRS_SNS_EV_RX_ADD:</span><br><span style="color: hsl(120, 100%, 40%);">+              ns2_sns_st_configured_add(fi, gss, tp);</span><br><span style="color: hsl(120, 100%, 40%);">+               break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case GPRS_SNS_EV_RX_DELETE:</span><br><span style="color: hsl(120, 100%, 40%);">+           ns2_sns_st_configured_delete(fi, gss, tp);</span><br><span style="color: hsl(120, 100%, 40%);">+            break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case GPRS_SNS_EV_RX_CHANGE_WEIGHT:</span><br><span style="color: hsl(120, 100%, 40%);">+            ns2_sns_st_configured_change(fi, gss, tp);</span><br><span style="color: hsl(120, 100%, 40%);">+            break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case GPRS_SNS_EV_REQ_NSVC_ALIVE:</span><br><span style="color: hsl(120, 100%, 40%);">+              osmo_timer_del(&gss->alive_timeout);</span><br><span style="color: hsl(120, 100%, 40%);">+           break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case GPRS_SNS_EV_RX_ACK:</span><br><span style="color: hsl(120, 100%, 40%);">+              /* the transaction id has been already checked */</span><br><span style="color: hsl(120, 100%, 40%);">+             trans_id = tlvp_val8(tp, NS_IE_TRANS_ID, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+          if (trans_id != gss->trans_id) {</span><br><span style="color: hsl(120, 100%, 40%);">+                   LOGPFSML(fi, LOGL_DEBUG, "NSEI=%u Rx SNS ACK with invalid transaction id %d. Valid %d\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                            nse->nsei, trans_id, gss->trans_id);</span><br><span style="color: hsl(120, 100%, 40%);">+                   break;</span><br><span style="color: hsl(120, 100%, 40%);">+                }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           if (!TLVP_PRESENT(tp, NS_IE_CAUSE)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                 /* everything ok */</span><br><span style="color: hsl(120, 100%, 40%);">+                   talloc_free(gss->current);</span><br><span style="color: hsl(120, 100%, 40%);">+                 gss->current = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+                       gss->trans_id++;</span><br><span style="color: hsl(120, 100%, 40%);">+                   if (llist_empty(&gss->procedures)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                           osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_CONFIGURED, 0, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+                    } else {</span><br><span style="color: hsl(120, 100%, 40%);">+                              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%);">+                     }</span><br><span style="color: hsl(120, 100%, 40%);">+                     return;</span><br><span style="color: hsl(120, 100%, 40%);">+               }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           /* what happened, when rejected? remove the bind? */</span><br><span style="color: hsl(120, 100%, 40%);">+          break;</span><br><span style="color: hsl(120, 100%, 40%);">+        }</span><br><span> }</span><br><span> </span><br><span> static const struct osmo_fsm_state ns2_sns_bss_states[] = {</span><br><span>@@ -1356,9 +1557,10 @@</span><br><span>           .in_event_mask = S(GPRS_SNS_EV_RX_CONFIG) |</span><br><span>                           S(GPRS_SNS_EV_RX_CONFIG_END),</span><br><span>               .out_state_mask = S(GPRS_SNS_ST_UNCONFIGURED) |</span><br><span style="color: hsl(120, 100%, 40%);">+                                 S(GPRS_SNS_ST_SIZE) |</span><br><span>                                S(GPRS_SNS_ST_CONFIG_SGSN) |</span><br><span>                                 S(GPRS_SNS_ST_CONFIGURED) |</span><br><span style="color: hsl(0, 100%, 40%);">-                             S(GPRS_SNS_ST_SIZE),</span><br><span style="color: hsl(120, 100%, 40%);">+                                  S(GPRS_SNS_ST_LOCAL_PROCEDURE),</span><br><span>            .name = "CONFIG_SGSN",</span><br><span>             .action = ns2_sns_st_config_sgsn,</span><br><span>            .onenter = ns2_sns_st_config_sgsn_onenter,</span><br><span>@@ -1367,13 +1569,30 @@</span><br><span>                 .in_event_mask = S(GPRS_SNS_EV_RX_ADD) |</span><br><span>                              S(GPRS_SNS_EV_RX_DELETE) |</span><br><span>                           S(GPRS_SNS_EV_RX_CHANGE_WEIGHT) |</span><br><span style="color: hsl(120, 100%, 40%);">+                             S(GPRS_SNS_EV_REQ_CHANGE_WEIGHT) |</span><br><span>                           S(GPRS_SNS_EV_REQ_NSVC_ALIVE),</span><br><span>              .out_state_mask = S(GPRS_SNS_ST_UNCONFIGURED) |</span><br><span style="color: hsl(0, 100%, 40%);">-                           S(GPRS_SNS_ST_SIZE),</span><br><span style="color: hsl(120, 100%, 40%);">+                                  S(GPRS_SNS_ST_SIZE) |</span><br><span style="color: hsl(120, 100%, 40%);">+                                 S(GPRS_SNS_ST_LOCAL_PROCEDURE),</span><br><span>            .name = "CONFIGURED",</span><br><span>              .action = ns2_sns_st_configured,</span><br><span>             .onenter = ns2_sns_st_configured_onenter,</span><br><span>    },</span><br><span style="color: hsl(120, 100%, 40%);">+    [GPRS_SNS_ST_LOCAL_PROCEDURE] = {</span><br><span style="color: hsl(120, 100%, 40%);">+             .in_event_mask = S(GPRS_SNS_EV_RX_ADD) |</span><br><span style="color: hsl(120, 100%, 40%);">+                               S(GPRS_SNS_EV_RX_DELETE) |</span><br><span style="color: hsl(120, 100%, 40%);">+                            S(GPRS_SNS_EV_RX_CHANGE_WEIGHT) |</span><br><span style="color: hsl(120, 100%, 40%);">+                             S(GPRS_SNS_EV_RX_ACK) |</span><br><span style="color: hsl(120, 100%, 40%);">+                               S(GPRS_SNS_EV_REQ_CHANGE_WEIGHT) |</span><br><span style="color: hsl(120, 100%, 40%);">+                            S(GPRS_SNS_EV_REQ_NSVC_ALIVE),</span><br><span style="color: hsl(120, 100%, 40%);">+               .out_state_mask = S(GPRS_SNS_ST_UNCONFIGURED) |</span><br><span style="color: hsl(120, 100%, 40%);">+                                 S(GPRS_SNS_ST_SIZE) |</span><br><span style="color: hsl(120, 100%, 40%);">+                                 S(GPRS_SNS_ST_CONFIGURED) |</span><br><span style="color: hsl(120, 100%, 40%);">+                           S(GPRS_SNS_ST_LOCAL_PROCEDURE),</span><br><span style="color: hsl(120, 100%, 40%);">+             .name = "LOCAL_PROCEDURE",</span><br><span style="color: hsl(120, 100%, 40%);">+          .action = ns2_sns_st_local_procedure,</span><br><span style="color: hsl(120, 100%, 40%);">+         .onenter = ns2_sns_st_local_procedure_onenter,</span><br><span style="color: hsl(120, 100%, 40%);">+        },</span><br><span> };</span><br><span> </span><br><span> /* timer to ensure the SNS doesn't configure NSVC, but then no NSVC come alive afterwards */</span><br><span>@@ -1419,16 +1638,93 @@</span><br><span>                   osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_CONFIG_SGSN, nsi->timeout[NS_TOUT_TSNS_PROV], 3);</span><br><span>                 }</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%);">+             if (gss->N >= nsi->timeout[NS_TOUT_TSNS_PROCEDURES_RETRIES]) {</span><br><span style="color: hsl(120, 100%, 40%);">+                       LOGPFSML(fi, LOGL_ERROR, "NSE %d: SNS Procedure retries failed. Selecting next IP-SNS endpoint.\n", nse->nsei);</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%);">+            } else {</span><br><span style="color: hsl(120, 100%, 40%);">+                      osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_LOCAL_PROCEDURE, nsi->timeout[NS_TOUT_TSNS_PROV],</span><br><span style="color: hsl(120, 100%, 40%);">+                                          fi->T);</span><br><span style="color: hsl(120, 100%, 40%);">+            }</span><br><span>    }</span><br><span>    return 0;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+/* create a local endpoint from sns_bind */</span><br><span style="color: hsl(120, 100%, 40%);">+static void *ns2_create_local_endpoint(struct ns2_sns_state *gss, struct ns2_sns_bind *sns_bind)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  struct osmo_sockaddr *local = NULL, *remote = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+   const struct osmo_sockaddr *sa;</span><br><span style="color: hsl(120, 100%, 40%);">+       struct gprs_ns_ie_ip4_elem *ip4;</span><br><span style="color: hsl(120, 100%, 40%);">+      struct gprs_ns_ie_ip6_elem *ip6;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    sa = gprs_ns2_ip_bind_sockaddr(sns_bind->bind);</span><br><span style="color: hsl(120, 100%, 40%);">+    if (!sa)</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%);">+        switch (sa->u.sa.sa_family) {</span><br><span style="color: hsl(120, 100%, 40%);">+      case AF_INET:</span><br><span style="color: hsl(120, 100%, 40%);">+         if (sa->u.sin.sin_addr.s_addr == 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                      if (osmo_sockaddr_local_ip(local, &gss->initial->saddr))</span><br><span style="color: hsl(120, 100%, 40%);">+                            return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+                  sa = local;</span><br><span style="color: hsl(120, 100%, 40%);">+           }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           ip4 = ip4_elem_by_saddr(gss->ip4_local, gss->num_ip4_local, sa);</span><br><span style="color: hsl(120, 100%, 40%);">+                if (ip4) {</span><br><span style="color: hsl(120, 100%, 40%);">+                    return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+          } else {</span><br><span style="color: hsl(120, 100%, 40%);">+                      // TODO: use memmov/realloc</span><br><span style="color: hsl(120, 100%, 40%);">+                   add_local_ip4_elem()</span><br><span style="color: hsl(120, 100%, 40%);">+                  ip4 = talloc_zero(gss, struct gprs_ns_ie_ip4_elem);</span><br><span style="color: hsl(120, 100%, 40%);">+                   if (!ip4)</span><br><span style="color: hsl(120, 100%, 40%);">+                             return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+          }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           ip4->ip_addr = sa->u.sin.sin_addr.s_addr;</span><br><span style="color: hsl(120, 100%, 40%);">+               ip4->udp_port = sa->u.sin.sin_port;</span><br><span style="color: hsl(120, 100%, 40%);">+             ip4->data_weight = sns_bind->bind->sns_data_weight;</span><br><span style="color: hsl(120, 100%, 40%);">+          ip4->sig_weight = sns_bind->bind->sns_sig_weight;</span><br><span style="color: hsl(120, 100%, 40%);">+            // TODO: add to local endpoints</span><br><span style="color: hsl(120, 100%, 40%);">+               return ip4;</span><br><span style="color: hsl(120, 100%, 40%);">+   case AF_INET6:</span><br><span style="color: hsl(120, 100%, 40%);">+                if (IN6_IS_ADDR_UNSPECIFIED(&sa->u.sin6.sin6_addr)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                  if (osmo_sockaddr_local_ip(local, remote))</span><br><span style="color: hsl(120, 100%, 40%);">+                            return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+                  sa = local;</span><br><span style="color: hsl(120, 100%, 40%);">+           }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           ip6 = ip6_elem_by_saddr(gss->ip6_local, gss->num_ip6_local, sa);</span><br><span style="color: hsl(120, 100%, 40%);">+                if (ip6) {</span><br><span style="color: hsl(120, 100%, 40%);">+                    return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+          } else {</span><br><span style="color: hsl(120, 100%, 40%);">+                      ip6 = talloc_zero(gss, struct gprs_ns_ie_ip6_elem);</span><br><span style="color: hsl(120, 100%, 40%);">+                   if (!ip6)</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%);">+           memcpy(&ip6->ip_addr, &sa->u.sin6.sin6_addr, sizeof(struct in6_addr));</span><br><span style="color: hsl(120, 100%, 40%);">+          ip6->udp_port = sa->u.sin6.sin6_port;</span><br><span style="color: hsl(120, 100%, 40%);">+           ip6->data_weight = sns_bind->bind->sns_data_weight;</span><br><span style="color: hsl(120, 100%, 40%);">+          ip6->sig_weight = sns_bind->bind->sns_sig_weight;</span><br><span style="color: hsl(120, 100%, 40%);">+            // TODO: add to local endpoints</span><br><span style="color: hsl(120, 100%, 40%);">+               return ip6;</span><br><span style="color: hsl(120, 100%, 40%);">+   default:</span><br><span style="color: hsl(120, 100%, 40%);">+              OSMO_ASSERT(false);</span><br><span style="color: hsl(120, 100%, 40%);">+           break;</span><br><span style="color: hsl(120, 100%, 40%);">+        }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return NULL;</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_st_all_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)</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>     struct ns2_sns_bind *sbind;</span><br><span>  struct gprs_ns2_vc *nsvc, *nsvc2;</span><br><span style="color: hsl(120, 100%, 40%);">+     const struct osmo_sockaddr *sa;</span><br><span style="color: hsl(120, 100%, 40%);">+       void *endpoint = NULL;</span><br><span> </span><br><span>   /* reset when receiving GPRS_SNS_EV_REQ_NO_NSVC */</span><br><span>   switch (event) {</span><br><span>@@ -1468,17 +1764,30 @@</span><br><span>           break;</span><br><span>       case GPRS_SNS_EV_REQ_ADD_BIND:</span><br><span>               sbind = data;</span><br><span style="color: hsl(120, 100%, 40%);">+         // free sbind or llist_add_tail(&tmp->list, &gss->binds);</span><br><span style="color: hsl(120, 100%, 40%);">+               // bind to remote</span><br><span>            switch (fi->state) {</span><br><span>              case GPRS_SNS_ST_UNCONFIGURED:</span><br><span style="color: hsl(120, 100%, 40%);">+                        llist_add_tail(&sbind->list, &gss->binds);</span><br><span>                     osmo_fsm_inst_dispatch(nse->bss_sns_fi, GPRS_SNS_EV_REQ_SELECT_ENDPOINT, NULL);</span><br><span>                   break;</span><br><span>               case GPRS_SNS_ST_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%);">+                   endpoint = ns2_create_local_endpoint(gss, sbind);</span><br><span style="color: hsl(120, 100%, 40%);">+                     if (!endpoint) {</span><br><span style="color: hsl(120, 100%, 40%);">+                              talloc_free(sbind);</span><br><span style="color: hsl(120, 100%, 40%);">+                           return;</span><br><span style="color: hsl(120, 100%, 40%);">+                       }</span><br><span style="color: hsl(120, 100%, 40%);">+                     // TODO add to endpoints</span><br><span>                     break;</span><br><span>               case GPRS_SNS_ST_CONFIG_BSS:</span><br><span>                 case GPRS_SNS_ST_CONFIG_SGSN:</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%);">+                    endpoint = ns2_create_local_endpoint(gss, sbind);</span><br><span style="color: hsl(120, 100%, 40%);">+                     if (!endpoint) {</span><br><span style="color: hsl(120, 100%, 40%);">+                              talloc_free(sbind);</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%);">+                     add_local_procedure(gss, SNS_ADD, endpoint);</span><br><span>                         break;</span><br><span>               }</span><br><span>            break;</span><br><span>@@ -1552,6 +1861,7 @@</span><br><span>       gss->nse = nse;</span><br><span>   INIT_LLIST_HEAD(&gss->sns_endpoints);</span><br><span>         INIT_LLIST_HEAD(&gss->binds);</span><br><span style="color: hsl(120, 100%, 40%);">+  INIT_LLIST_HEAD(&gss->procedures);</span><br><span>    osmo_timer_setup(&gss->alive_timeout, ns2_sns_timeout_alive_cb, fi);</span><br><span> </span><br><span>      return fi;</span><br><span>@@ -1610,8 +1920,7 @@</span><br><span>           osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_RX_CHANGE_WEIGHT, tp);</span><br><span>                break;</span><br><span>       case SNS_PDUT_ACK:</span><br><span style="color: hsl(0, 100%, 40%);">-              LOGPFSML(fi, LOGL_NOTICE, "NSEI=%u Rx unsupported SNS PDU type %s\n", nsei,</span><br><span style="color: hsl(0, 100%, 40%);">-                    get_value_string(gprs_ns_pdu_strings, nsh->pdu_type));</span><br><span style="color: hsl(120, 100%, 40%);">+            osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_RX_ACK, tp);</span><br><span>          break;</span><br><span>       default:</span><br><span>             LOGPFSML(fi, LOGL_ERROR, "NSEI=%u Rx unknown SNS PDU type %s\n", nsei,</span><br><span>@@ -1844,7 +2153,7 @@</span><br><span>             return;</span><br><span> </span><br><span>  gss = nse->bss_sns_fi->priv;</span><br><span style="color: hsl(0, 100%, 40%);">-      if(nse->bss_sns_fi->state != GPRS_SNS_ST_CONFIGURED)</span><br><span style="color: hsl(120, 100%, 40%);">+    if(nse->bss_sns_fi->state != GPRS_SNS_ST_CONFIGURED && nse->bss_sns_fi->state != GPRS_SNS_ST_LOCAL_PROCEDURE)</span><br><span>            return;</span><br><span> </span><br><span>  if (alive == gss->alive)</span><br><span>@@ -1875,6 +2184,28 @@</span><br><span>         }</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+static void add_local_procedure(struct ns2_sns_state *gss, enum sns_procedure procedure, void *endpoint)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       struct ns2_sns_procedure *sns_proc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ switch (gss->nse->bss_sns_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%);">+        case GPRS_SNS_ST_SIZE:</span><br><span style="color: hsl(120, 100%, 40%);">+                /* we can ignore the procedure as nothing yet configured */</span><br><span style="color: hsl(120, 100%, 40%);">+           return;</span><br><span style="color: hsl(120, 100%, 40%);">+       default:</span><br><span style="color: hsl(120, 100%, 40%);">+              break;</span><br><span style="color: hsl(120, 100%, 40%);">+        }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   sns_proc = talloc_zero(gss, struct ns2_sns_procedure);</span><br><span style="color: hsl(120, 100%, 40%);">+        if (!sns_proc)</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%);">+     sns_proc->endpoint = endpoint;</span><br><span style="color: hsl(120, 100%, 40%);">+     sns_proc->procedure = procedure;</span><br><span style="color: hsl(120, 100%, 40%);">+   llist_add(&sns_proc->list, &gss->procedures);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> int gprs_ns2_sns_add_bind(struct gprs_ns2_nse *nse,</span><br><span>                        struct gprs_ns2_vc_bind *bind)</span><br><span> {</span><br><span>@@ -1899,15 +2230,13 @@</span><br><span>      if (!tmp)</span><br><span>            return -ENOMEM;</span><br><span>      tmp->bind = bind;</span><br><span style="color: hsl(0, 100%, 40%);">-    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> </span><br><span> /* Remove a bind from the SNS. All assosiated NSVC must be removed. */</span><br><span> int gprs_ns2_sns_del_bind(struct gprs_ns2_nse *nse,</span><br><span style="color: hsl(0, 100%, 40%);">-                          struct gprs_ns2_vc_bind *bind)</span><br><span style="color: hsl(120, 100%, 40%);">+                     struct gprs_ns2_vc_bind *bind)</span><br><span> {</span><br><span>        struct ns2_sns_state *gss;</span><br><span>   struct ns2_sns_bind *tmp, *tmp2;</span><br><span>@@ -1938,12 +2267,83 @@</span><br><span>   return 0;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-/* Update SNS weights</span><br><span style="color: hsl(0, 100%, 40%);">- * \param[in] nsvc the NSVC which should be updated</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* Update SNS weights for a bind (local endpoint). */</span><br><span style="color: hsl(120, 100%, 40%);">+static void _ns2_sns_update_weights(struct ns2_sns_state *gss, struct ns2_sns_bind *sns_bind) {</span><br><span style="color: hsl(120, 100%, 40%);">+  // find the ip_local entry by using the initial connection for 0.0.0.0</span><br><span style="color: hsl(120, 100%, 40%);">+        struct osmo_sockaddr *local = NULL, *remote = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+   const struct osmo_sockaddr *sa;</span><br><span style="color: hsl(120, 100%, 40%);">+       struct gprs_ns_ie_ip4_elem *ip4;</span><br><span style="color: hsl(120, 100%, 40%);">+      struct gprs_ns_ie_ip6_elem *ip6;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    sa = gprs_ns2_ip_bind_sockaddr(sns_bind->bind);</span><br><span style="color: hsl(120, 100%, 40%);">+    if (!sa)</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%);">+     switch (sa->u.sa.sa_family) {</span><br><span style="color: hsl(120, 100%, 40%);">+      case AF_INET:</span><br><span style="color: hsl(120, 100%, 40%);">+         if (sa->u.sin.sin_addr.s_addr == 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                      if (osmo_sockaddr_local_ip(local, &gss->initial->saddr))</span><br><span style="color: hsl(120, 100%, 40%);">+                            return;</span><br><span style="color: hsl(120, 100%, 40%);">+                       ip4 = ip4_elem_by_saddr(gss->ip4_local, gss->num_ip4_local, local);</span><br><span style="color: hsl(120, 100%, 40%);">+             } else {</span><br><span style="color: hsl(120, 100%, 40%);">+                      ip4 = ip4_elem_by_saddr(gss->ip4_local, gss->num_ip4_local, sa);</span><br><span style="color: hsl(120, 100%, 40%);">+                }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           /* TODO: check if this bind is about to be added */</span><br><span style="color: hsl(120, 100%, 40%);">+           if (!ip4)</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%);">+             ip4->data_weight = sns_bind->bind->sns_data_weight;</span><br><span style="color: hsl(120, 100%, 40%);">+          ip4->sig_weight = sns_bind->bind->sns_sig_weight;</span><br><span style="color: hsl(120, 100%, 40%);">+            add_local_procedure(gss, SNS_CHANGE_WEIGHT, ip4);</span><br><span style="color: hsl(120, 100%, 40%);">+             osmo_fsm_inst_dispatch(gss->nse->bss_sns_fi, GPRS_SNS_EV_REQ_CHANGE_WEIGHT, ip4);</span><br><span style="color: hsl(120, 100%, 40%);">+               break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case AF_INET6:</span><br><span style="color: hsl(120, 100%, 40%);">+                // in6addr_any</span><br><span style="color: hsl(120, 100%, 40%);">+                if (memcmp(&sa->u.sin6.sin6_addr, &in6addr_any, sizeof(struct in6_addr))) {</span><br><span style="color: hsl(120, 100%, 40%);">+                        if (osmo_sockaddr_local_ip(local, remote))</span><br><span style="color: hsl(120, 100%, 40%);">+                            return;</span><br><span style="color: hsl(120, 100%, 40%);">+                       ip6 = ip6_elem_by_saddr(gss->ip6_local, gss->num_ip6_local, local);</span><br><span style="color: hsl(120, 100%, 40%);">+             } else {</span><br><span style="color: hsl(120, 100%, 40%);">+                      ip6 = ip6_elem_by_saddr(gss->ip6_local, gss->num_ip6_local, sa);</span><br><span style="color: hsl(120, 100%, 40%);">+                }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           /* TODO: check if this bind is about to be added */</span><br><span style="color: hsl(120, 100%, 40%);">+           if (!ip6)</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%);">+             ip6->data_weight = sns_bind->bind->sns_data_weight;</span><br><span style="color: hsl(120, 100%, 40%);">+          ip6->sig_weight = sns_bind->bind->sns_sig_weight;</span><br><span style="color: hsl(120, 100%, 40%);">+            add_local_procedure(gss, SNS_CHANGE_WEIGHT, ip6);</span><br><span style="color: hsl(120, 100%, 40%);">+             osmo_fsm_inst_dispatch(gss->nse->bss_sns_fi, GPRS_SNS_EV_REQ_CHANGE_WEIGHT, ip6);</span><br><span style="color: hsl(120, 100%, 40%);">+               break;</span><br><span style="color: hsl(120, 100%, 40%);">+        default:</span><br><span style="color: hsl(120, 100%, 40%);">+              OSMO_ASSERT(false);</span><br><span style="color: hsl(120, 100%, 40%);">+           break;</span><br><span style="color: hsl(120, 100%, 40%);">+        }</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* Update SNS weights for a bind (local endpoint).</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[in] bind the bind which has been updated</span><br><span>  */</span><br><span> void ns2_sns_update_weights(struct gprs_ns2_vc_bind *bind)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-        /* TODO: implement weights after binds per sns implemented */</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ns2_sns_bind *sns_bind;</span><br><span style="color: hsl(120, 100%, 40%);">+        struct gprs_ns2_nse *nse;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct ns2_sns_state *gss;</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%);">+          if (!nse->bss_sns_fi)</span><br><span style="color: hsl(120, 100%, 40%);">+                      continue;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           gss = nse->bss_sns_fi->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+            llist_for_each_entry(sns_bind, &gss->binds, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+                    if (sns_bind->bind == bind) {</span><br><span style="color: hsl(120, 100%, 40%);">+                              _ns2_sns_update_weights(gss, sns_bind);</span><br><span style="color: hsl(120, 100%, 40%);">+                               break;</span><br><span style="color: hsl(120, 100%, 40%);">+                        }</span><br><span style="color: hsl(120, 100%, 40%);">+             }</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span> }</span><br><span> </span><br><span> /* initialize osmo_ctx on main tread */</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.osmocom.org/c/libosmocore/+/23187">change 23187</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/+/23187"/><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: Icec4dabb46bc198f68f91bfe09ba279fbe68d454 </div>
<div style="display:none"> Gerrit-Change-Number: 23187 </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>