Change in libosmocore[master]: gprs_ns2: implement outbound ADD/DEL SNS procedures

This is merely a historical archive of years 2008-2021, before the migration to mailman3.

A maintained and still updated list archive can be found at https://lists.osmocom.org/hyperkitty/list/gerrit-log@lists.osmocom.org/.

lynxis lazus gerrit-no-reply at lists.osmocom.org
Tue May 4 13:42:06 UTC 2021


lynxis lazus has uploaded this change for review. ( https://gerrit.osmocom.org/c/libosmocore/+/24123 )


Change subject: gprs_ns2: implement outbound ADD/DEL SNS procedures
......................................................................

gprs_ns2: implement outbound ADD/DEL SNS procedures

When adding or removing a bind, the remote side needs to be
informed via the SNS-ADD/SNS-DELETE procedure.

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



  git pull ssh://gerrit.osmocom.org:29418/libosmocore refs/changes/23/24123/1

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

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

Gerrit-Project: libosmocore
Gerrit-Branch: master
Gerrit-Change-Id: I71c33200bd1f0307ceb943ee958db5ebe3623d36
Gerrit-Change-Number: 24123
Gerrit-PatchSet: 1
Gerrit-Owner: lynxis lazus <lynxis at fe80.eu>
Gerrit-MessageType: newchange
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.osmocom.org/pipermail/gerrit-log/attachments/20210504/53b82c99/attachment.htm>


More information about the gerrit-log mailing list