<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>