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