lynxis lazus has submitted this change. ( 
https://gerrit.osmocom.org/c/libosmocore/+/24591 )

Change subject: gprs_ns2_sns: implement outbound SNS DEL procedures
......................................................................

gprs_ns2_sns: implement outbound SNS DEL procedures

When removing a bind the remote side needs to be
informed via the SNS DELETE procedure.

Related: OS#5036
Change-Id: I53cd54dfd262c70c425c3f13dad3b29526daa523
---
M src/gb/gprs_ns2_sns.c
1 file changed, 95 insertions(+), 9 deletions(-)

Approvals:
  Jenkins Builder: Verified
  laforge: Looks good to me, but someone else must approve
  daniel: Looks good to me, approved



diff --git a/src/gb/gprs_ns2_sns.c b/src/gb/gprs_ns2_sns.c
index 0cb24c5..3eff0f3 100644
--- a/src/gb/gprs_ns2_sns.c
+++ b/src/gb/gprs_ns2_sns.c
@@ -150,6 +150,9 @@
        /* prevent recursive reselection */
        bool reselection_running;

+       /* protection against recursive free() */
+       bool block_no_nsvc_events;
+
        /* The current initial SNS endpoints.
         * The initial connection will be moved into the NSE
         * if configured via SNS. Otherwise it will be removed
@@ -323,7 +326,8 @@
                }
        }

-       osmo_fsm_inst_dispatch(fi, NS2_SNS_EV_REQ_NO_NSVC, NULL);
+       if (gss->block_no_nsvc_events)
+               osmo_fsm_inst_dispatch(fi, NS2_SNS_EV_REQ_NO_NSVC, NULL);
 }

 static void ns2_clear_elems(struct ns2_sns_elems *elems)
@@ -595,6 +599,32 @@
        return -1;
 }

+static int remove_bind_elem(struct ns2_sns_state *gss, struct ns2_sns_elems 
*elems, struct ns2_sns_bind *sbind)
+{
+       struct gprs_ns_ie_ip4_elem ip4;
+       struct gprs_ns_ie_ip6_elem ip6;
+       const struct osmo_sockaddr *saddr = 
gprs_ns2_ip_bind_sockaddr(sbind->bind);
+
+       switch (saddr->u.sa.sa_family) {
+       case AF_INET:
+               ip4.ip_addr = saddr->u.sin.sin_addr.s_addr;
+               ip4.udp_port = saddr->u.sin.sin_port;
+               ip4.sig_weight = sbind->bind->sns_sig_weight;
+               ip4.data_weight = sbind->bind->sns_data_weight;
+               return remove_ip4_elem(gss, elems, &ip4);
+       case AF_INET6:
+               memcpy(&ip6.ip_addr, &saddr->u.sin6.sin6_addr, sizeof(struct 
in6_addr));
+               ip6.udp_port = saddr->u.sin.sin_port;
+               ip6.sig_weight = sbind->bind->sns_sig_weight;
+               ip6.data_weight = sbind->bind->sns_data_weight;
+               return remove_ip6_elem(gss, elems, &ip6);
+       default:
+               return -1;
+       }
+
+       return -1;
+}
+
 static int do_sns_change_weight(struct osmo_fsm_inst *fi, const struct 
gprs_ns_ie_ip4_elem *ip4, const struct gprs_ns_ie_ip6_elem *ip6)
 {
        struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
@@ -1487,6 +1517,12 @@
                else
                        ns2_tx_sns_change_weight(gss->sns_nsvc, 
gss->current_procedure->trans_id, NULL, 0, &gss->current_procedure->ip6, 1);
                break;
+       case SNS_PROC_DEL:
+               if (gss->family == AF_INET)
+                       ns2_tx_sns_del(gss->sns_nsvc, 
gss->current_procedure->trans_id, &gss->current_procedure->ip4, 1, NULL, 0);
+               else
+                       ns2_tx_sns_del(gss->sns_nsvc, 
gss->current_procedure->trans_id, NULL, 0, &gss->current_procedure->ip6, 1);
+               break;
        default:
                break;
        }
@@ -1599,8 +1635,11 @@
                                add_ip6_elem(gss, &gss->local, 
&gss->current_procedure->ip6);
                                break;
                        }
-                       create_nsvc_for_new_sbind(gss, 
gss->current_procedure->sbind);
-                       gprs_ns2_start_alive_all_nsvcs(nse);
+                       /* the sbind can be NULL if the bind has been released 
by del_bind */
+                       if (gss->current_procedure->sbind) {
+                               create_nsvc_for_new_sbind(gss, 
gss->current_procedure->sbind);
+                               gprs_ns2_start_alive_all_nsvcs(nse);
+                       }
                        break;
                case SNS_PROC_CHANGE_WEIGHT:
                        switch (gss->family) {
@@ -1633,6 +1672,16 @@
                                OSMO_ASSERT(0);
                        }
                        break;
+               case SNS_PROC_DEL:
+                       switch (gss->family) {
+                       case AF_INET:
+                               remove_ip4_elem(gss, &gss->local, 
&gss->current_procedure->ip4);
+                               break;
+                       case AF_INET6:
+                               remove_ip6_elem(gss, &gss->local, 
&gss->current_procedure->ip6);
+                               break;
+                       }
+                       break;
                default:
                        break;
                }
@@ -1849,6 +1898,8 @@
        switch (procedure_type) {
        case SNS_PROC_ADD:
                break;
+       case SNS_PROC_DEL:
+               break;
        case SNS_PROC_CHANGE_WEIGHT:
                llist_for_each_entry(procedure, &gss->procedures, list) {
                        if (procedure->sbind == sbind && procedure->procedure 
== procedure_type &&
@@ -1879,8 +1930,16 @@
        if (!procedure)
                return;

+       switch (procedure_type) {
+       case SNS_PROC_ADD:
+       case SNS_PROC_CHANGE_WEIGHT:
+               procedure->sbind = sbind;
+               break;
+       default:
+               break;
+       }
+
        llist_add_tail(&procedure->list, &gss->procedures);
-       procedure->sbind = sbind;
        procedure->procedure = procedure_type;
        procedure->sig_weight = sbind->bind->sns_sig_weight;
        procedure->data_weight = sbind->bind->sns_data_weight;
@@ -1893,7 +1952,6 @@
                procedure->ip4.data_weight = sbind->bind->sns_data_weight;
                break;
        case AF_INET6:
-
                memcpy(&procedure->ip6.ip_addr, &saddr->u.sin6.sin6_addr, 
sizeof(struct in6_addr));
                procedure->ip6.udp_port = saddr->u.sin.sin_port;
                procedure->ip6.sig_weight = sbind->bind->sns_sig_weight;
@@ -1948,6 +2006,7 @@
        struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
        struct ns2_sns_bind *sbind;
        struct gprs_ns2_vc *nsvc, *nsvc2;
+       struct ns2_sns_procedure *procedure;

        switch (event) {
        case NS2_SNS_EV_REQ_ADD_BIND:
@@ -2020,25 +2079,46 @@
                case GPRS_SNS_ST_UNCONFIGURED:
                        break;
                case GPRS_SNS_ST_BSS_SIZE:
-                       /* TODO: remove the ip4 element from the list */
                        llist_for_each_entry_safe(nsvc, nsvc2, &nse->nsvc, 
list) {
                                if (nsvc->bind == sbind->bind) {
                                        gprs_ns2_free_nsvc(nsvc);
                                }
                        }
+                       osmo_fsm_inst_dispatch(fi, 
NS2_SNS_EV_REQ_SELECT_ENDPOINT, NULL);
                        break;
                case GPRS_SNS_ST_BSS_CONFIG_BSS:
                case GPRS_SNS_ST_BSS_CONFIG_SGSN:
                case GPRS_SNS_ST_CONFIGURED:
-                       /* TODO: do an delete SNS-IP procedure */
-                       /* TODO: remove the ip4 element to the list */
+               case GPRS_SNS_ST_LOCAL_PROCEDURE:
+                       remove_bind_elem(gss, &gss->local_procedure, sbind);
+                       if (ip46_weight_sum(&gss->local_procedure, true) == 0 ||
+                                       ip46_weight_sum(&gss->local_procedure, 
false) == 0) {
+                               LOGPFSML(fi, LOGL_ERROR, "NSE %d: weight has 
become invalid because of removing bind %s. Resetting the configuration\n",
+                                        nse->nsei, sbind->bind->name);
+                               sns_failed(fi, NULL);
+                               break;
+                       }
+                       gss->block_no_nsvc_events = true;
                        llist_for_each_entry_safe(nsvc, nsvc2, &nse->nsvc, 
list) {
                                if (nsvc->bind == sbind->bind) {
                                        gprs_ns2_free_nsvc(nsvc);
                                }
                        }
+                       gss->block_no_nsvc_events = false;
+                       if (nse->sum_sig_weight == 0 || !nse->alive || 
!gss->alive) {
+                               sns_failed(fi, "While deleting a bind the 
current state became invalid (no signalling weight)");
+                               break;
+                       }
+
+                       /* ensure other procedures doesn't use the sbind */
+                       llist_for_each_entry(procedure, &gss->procedures, list) 
{
+                               if (procedure->sbind == sbind)
+                                       procedure->sbind = NULL;
+                       }
+                       ns2_add_procedure(gss, sbind, SNS_PROC_DEL);
                        break;
                }
+
                /* if this is the last bind, the free_nsvc() will trigger a 
reselection */
                talloc_free(sbind);
                break;
@@ -2124,7 +2204,7 @@
        switch (event) {
        case NS2_SNS_EV_REQ_NO_NSVC:
                /* ignore reselection running */
-               if (gss->reselection_running)
+               if (gss->reselection_running || gss->block_no_nsvc_events)
                        break;

                sns_failed(fi, "no remaining NSVC, resetting SNS FSM");
@@ -2134,6 +2214,9 @@
                /* TODO: keep the order of binds when data == 
GPRS_SNS_FLAG_KEEP_SELECT_ENDPOINT_ORDER */
                /* tear down previous state
                 * gprs_ns2_free_nsvcs() will trigger NO_NSVC, prevent this 
from triggering a reselection */
+               if (gss->reselection_running || gss->block_no_nsvc_events)
+                       break;
+
                gss->reselection_running = true;
                ns2_free_nsvcs(nse);
                ns2_clear_elems(&gss->local);
@@ -2512,6 +2595,9 @@
        if (nse->bss_sns_fi->state != GPRS_SNS_ST_CONFIGURED && 
nse->bss_sns_fi->state != GPRS_SNS_ST_LOCAL_PROCEDURE)
                return;

+       if (gss->block_no_nsvc_events)
+               return;
+
        if (alive == gss->alive)
                return;


--
To view, visit https://gerrit.osmocom.org/c/libosmocore/+/24591
To unsubscribe, or for help writing mail filters, visit 
https://gerrit.osmocom.org/settings

Gerrit-Project: libosmocore
Gerrit-Branch: master
Gerrit-Change-Id: I53cd54dfd262c70c425c3f13dad3b29526daa523
Gerrit-Change-Number: 24591
Gerrit-PatchSet: 12
Gerrit-Owner: lynxis lazus <[email protected]>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: daniel <[email protected]>
Gerrit-Reviewer: dexter <[email protected]>
Gerrit-Reviewer: laforge <[email protected]>
Gerrit-Reviewer: lynxis lazus <[email protected]>
Gerrit-Reviewer: pespin <[email protected]>
Gerrit-MessageType: merged

Reply via email to