Change in libosmo-sccp[master]: xua: Implement SNM availability/unavailability messaging

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

laforge gerrit-no-reply at lists.osmocom.org
Wed Feb 10 16:02:45 UTC 2021


laforge has submitted this change. ( https://gerrit.osmocom.org/c/libosmo-sccp/+/22777 )

Change subject: xua: Implement SNM availability/unavailability messaging
......................................................................

xua: Implement SNM availability/unavailability messaging

M3UA and SUA have one sub-protocol called [S]SNM, through which the
SG informs the ASP about certain destinations (point codes) becoming
available (DAVA) or unavailable (DUNA) in the SS7 network.

This patch adds support for
* generating DAVA/DUAN on a SGP when the AS FSM changes to/from AS-ACTIVE
* receiving DAVA/DUNA on an ASP and informing other "SG role" AS/ASP
* processing DAUD from ASP received by SG, generating relate DAVA/DUNA
  responses

Related: OS#2623
Change-Id: Id92be4691b0fd77598a6edb642c028bbd8c5b623
---
M src/Makefile.am
M src/m3ua.c
M src/sua.c
M src/xua_as_fsm.c
M src/xua_internal.h
A src/xua_snm.c
6 files changed, 554 insertions(+), 6 deletions(-)

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



diff --git a/src/Makefile.am b/src/Makefile.am
index 91084de..41d2a8d 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -31,7 +31,7 @@
 			     sccp2sua.c sccp_scrc.c sccp_sclc.c sccp_scoc.c \
 			     sccp_user.c sccp_types.c xua_rkm.c xua_shared.c xua_default_lm_fsm.c \
 			     osmo_ss7.c osmo_ss7_hmrt.c xua_asp_fsm.c xua_as_fsm.c \
-			     osmo_ss7_vty.c sccp_vty.c ipa.c
+			     xua_snm.c osmo_ss7_vty.c sccp_vty.c ipa.c
 libosmo_sigtran_la_LDFLAGS = -version-info $(LIBVERSION) -no-undefined -export-symbols-regex '^osmo_'
 libosmo_sigtran_la_LIBADD = $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) $(LIBOSMOVTY_LIBS) \
 			    $(LIBOSMONETIF_LIBS) $(LIBSCTP_LIBS)
diff --git a/src/m3ua.c b/src/m3ua.c
index bfb0c23..6639c28 100644
--- a/src/m3ua.c
+++ b/src/m3ua.c
@@ -677,6 +677,8 @@
 	return 0;
 }
 
+static int m3ua_rx_snm(struct osmo_ss7_asp *asp, struct xua_msg *xua);
+
 /*! \brief process M3UA message received from socket
  *  \param[in] asp Application Server Process receiving \ref msg
  *  \param[in] msg received message buffer
@@ -737,10 +739,7 @@
 		rc = m3ua_rx_rkm(asp, xua);
 		break;
 	case M3UA_MSGC_SNM:
-		/* FIXME */
-		LOGPASP(asp, DLM3UA, LOGL_NOTICE, "Received unsupported M3UA "
-			"Message Class %u\n", xua->hdr.msg_class);
-		err = m3ua_gen_error_msg(M3UA_ERR_UNSUPP_MSG_CLASS, msg);
+		rc = m3ua_rx_snm(asp, xua);
 		break;
 	default:
 		LOGPASP(asp, DLM3UA, LOGL_NOTICE, "Received unknown M3UA "
@@ -760,3 +759,146 @@
 
 	return rc;
 }
+
+/***********************************************************************
+ * SSNM msg generation
+ ***********************************************************************/
+
+/* 3.4.1 Destination Unavailable (DUNA) */
+static struct xua_msg *m3ua_encode_duna(const uint32_t *rctx, unsigned int num_rctx,
+					const uint32_t *aff_pc, unsigned int num_aff_pc,
+					const char *info_string)
+{
+	struct xua_msg *xua = xua_msg_alloc();
+
+	xua->hdr = XUA_HDR(M3UA_MSGC_SNM, M3UA_SNM_DUNA);
+	xua->hdr.version = M3UA_VERSION;
+	if (rctx)
+		xua_msg_add_data(xua, M3UA_IEI_ROUTE_CTX, num_rctx * sizeof(*rctx), (const uint8_t *)rctx);
+
+	xua_msg_add_data(xua, M3UA_IEI_AFFECTED_PC, num_aff_pc * sizeof(*aff_pc), (const uint8_t *) aff_pc);
+
+	if (info_string) {
+		xua_msg_add_data(xua, M3UA_IEI_INFO_STRING,
+				 strlen(info_string)+1,
+				 (const uint8_t *) info_string);
+	}
+	return xua;
+}
+
+/* 3.4.2 Destination Available (DAVA) */
+static struct xua_msg *m3ua_encode_dava(const uint32_t *rctx, unsigned int num_rctx,
+					const uint32_t *aff_pc, unsigned int num_aff_pc,
+					const char *info_string)
+{
+	/* encoding is exactly identical to DUNA */
+	struct xua_msg *xua = m3ua_encode_duna(rctx, num_rctx, aff_pc, num_aff_pc, info_string);
+	if (xua)
+		xua->hdr.msg_type = M3UA_SNM_DAVA;
+	return xua;
+}
+
+#if 0 /* not used so far */
+/* 3.4.3 Destination Available (DAUD) */
+static struct xua_msg *m3ua_encode_daud(const uint32_t *rctx, unsigned int num_rctx,
+					const uint32_t *aff_pc, unsigned int num_aff_pc,
+					const char *info_string)
+{
+	/* encoding is exactly identical to DUNA */
+	struct xua_msg *xua = m3ua_encode_duna(rctx, num_rctx, aff_pc, num_aff_pc, info_string);
+	if (xua)
+		xua->hdr.msg_type = M3UA_SNM_DAUD;
+	return xua;
+}
+#endif
+
+
+/* TODO: 3.4.5 Destination User Part Unavailable (DUPU) */
+
+/*! Transmit SSNM DUNA/DAVA message indicating [un]availability of certain point code[s]
+ *  \param[in] asp ASP through which to transmit message. Must be ACTIVE.
+ *  \param[in] rctx array of Routing Contexts in network byte order.
+ *  \param[in] num_rctx number of rctx
+ *  \param[in] aff_pc array of 'Affected Point Code' in network byte order.
+ *  \param[in] num_aff_pc number of aff_pc
+ *  \param[in] info_string optional information string (can be NULL).
+ *  \param[in] available are aff_pc now available (true) or unavailable (false) */
+void m3ua_tx_snm_available(struct osmo_ss7_asp *asp, const uint32_t *rctx, unsigned int num_rctx,
+			   const uint32_t *aff_pc, unsigned int num_aff_pc,
+			   const char *info_string, bool available)
+{
+	struct xua_msg *xua;
+
+	if (available)
+		xua = m3ua_encode_dava(rctx, num_rctx, aff_pc, num_aff_pc, info_string);
+	else
+		xua = m3ua_encode_duna(rctx, num_rctx, aff_pc, num_aff_pc, info_string);
+
+	m3ua_tx_xua_asp(asp, xua);
+}
+
+/* received SNM message on ASP side */
+static int m3ua_rx_snm_asp(struct osmo_ss7_asp *asp, struct xua_msg *xua)
+{
+	struct osmo_ss7_as *as = NULL;
+	struct xua_msg_part *rctx_ie = xua_msg_find_tag(xua, M3UA_IEI_ROUTE_CTX);
+	int rc;
+
+	rc = xua_find_as_for_asp(&as, asp, rctx_ie);
+	if (rc)
+		return rc;
+
+	/* report those up the stack so both other ASPs and local SCCP users can be notified */
+	switch (xua->hdr.msg_type) {
+	case M3UA_SNM_DUNA:
+		xua_snm_rx_duna(asp, as, xua);
+		break;
+	case M3UA_SNM_DAVA:
+		xua_snm_rx_dava(asp, as, xua);
+		break;
+	case M3UA_SNM_DUPU:
+	case M3UA_SNM_SCON:
+	case M3UA_SNM_DRST:
+		LOGPASP(asp, DLM3UA, LOGL_NOTICE, "Received unsupported M3UA SNM message type %u\n",
+			xua->hdr.msg_type);
+		/* silently ignore those to not confuse the sender */
+		break;
+	default:
+		return M3UA_ERR_UNSUPP_MSG_TYPE;
+	}
+
+	return 0;
+}
+
+/* received SNM message on SG side */
+static int m3ua_rx_snm_sg(struct osmo_ss7_asp *asp, struct xua_msg *xua)
+{
+	switch (xua->hdr.msg_type) {
+	case M3UA_SNM_DAUD:	/* Audit: ASP inquires about availability of Point Codes */
+		xua_snm_rx_daud(asp, xua);
+		break;
+	default:
+		return M3UA_ERR_UNSUPP_MSG_TYPE;
+	}
+
+	return 0;
+}
+
+static int m3ua_rx_snm(struct osmo_ss7_asp *asp, struct xua_msg *xua)
+{
+	/* SNM only permitted in ACTIVE state */
+	if (asp->fi->state != XUA_ASP_S_ACTIVE) {
+		LOGPASP(asp, DLM3UA, LOGL_NOTICE, "Received M3UA SNM while ASP in state %s\n",
+			osmo_fsm_inst_state_name(asp->fi));
+		return M3UA_ERR_UNEXPECTED_MSG;
+	}
+
+	switch (asp->cfg.role) {
+	case OSMO_SS7_ASP_ROLE_SG:
+		return m3ua_rx_snm_sg(asp, xua);
+	case OSMO_SS7_ASP_ROLE_ASP:
+		return m3ua_rx_snm_asp(asp, xua);
+	default:
+		return M3UA_ERR_UNSUPP_MSG_CLASS;
+	}
+}
diff --git a/src/sua.c b/src/sua.c
index 42d43e8..c9e880f 100644
--- a/src/sua.c
+++ b/src/sua.c
@@ -1,6 +1,6 @@
 /* Minimal implementation of RFC 3868 - SCCP User Adaptation Layer */
 
-/* (C) 2015-2017 by Harald Welte <laforge at gnumonks.org>
+/* (C) 2015-2021 by Harald Welte <laforge at gnumonks.org>
  * All Rights Reserved
  *
  * SPDX-License-Identifier: GPL-2.0+
@@ -661,6 +661,8 @@
 	return 0;
 }
 
+static int sua_rx_snm(struct osmo_ss7_asp *asp, struct xua_msg *xua);
+
 /*! \brief process SUA message received from socket
  *  \param[in] asp Application Server Process receiving \ref msg
  *  \param[in] msg received message buffer
@@ -736,6 +738,8 @@
 		rc = sua_rx_mgmt(asp, xua);
 		break;
 	case SUA_MSGC_SNM:
+		rc = sua_rx_snm(asp, xua);
+		break;
 	case SUA_MSGC_RKM:
 		/* FIXME */
 		LOGPASP(asp, DLSUA, LOGL_NOTICE, "Received unsupported SUA "
@@ -760,3 +764,151 @@
 
 	return rc;
 }
+
+/***********************************************************************
+ * SSNM msg generation
+ ***********************************************************************/
+
+/* 3.4.1 Destination Unavailable (DUNA) */
+static struct xua_msg *sua_encode_duna(const uint32_t *rctx, unsigned int num_rctx,
+					const uint32_t *aff_pc, unsigned int num_aff_pc,
+					const uint32_t *ssn, const uint32_t *smi, const char *info_string)
+{
+	struct xua_msg *xua = xua_msg_alloc();
+
+	xua->hdr = XUA_HDR(SUA_MSGC_SNM, SUA_SNM_DUNA);
+	xua->hdr.version = SUA_VERSION;
+	if (rctx)
+		xua_msg_add_data(xua, SUA_IEI_ROUTE_CTX, num_rctx * 4, (const uint8_t *)rctx);
+
+	xua_msg_add_data(xua, SUA_IEI_AFFECTED_PC, num_aff_pc * 4, (const uint8_t *) aff_pc);
+
+	if (ssn)
+		xua_msg_add_u32(xua, SUA_IEI_SSN, *ssn);
+
+	if (smi)
+		xua_msg_add_u32(xua, SUA_IEI_SSN, *smi);
+
+	if (info_string) {
+		xua_msg_add_data(xua, SUA_IEI_INFO_STRING,
+				 strlen(info_string)+1,
+				 (const uint8_t *) info_string);
+	}
+	return xua;
+}
+
+/* 3.4.2 Destination Available (DAVA) */
+static struct xua_msg *sua_encode_dava(const uint32_t *rctx, unsigned int num_rctx,
+					const uint32_t *aff_pc, unsigned int num_aff_pc,
+					const uint32_t *ssn, const uint32_t *smi, const char *info_string)
+{
+	/* encoding is exactly identical to DUNA */
+	struct xua_msg *xua = sua_encode_duna(rctx, num_rctx, aff_pc, num_aff_pc, ssn, smi, info_string);
+	if (xua)
+		xua->hdr.msg_type = SUA_SNM_DAVA;
+	return xua;
+}
+
+#if 0 /* not used so far */
+/* 3.4.3 Destination Available (DAUD) */
+static struct xua_msg *sua_encode_daud(const uint32_t *rctx, unsigned int num_rctx,
+					const uint32_t *aff_pc, unsigned int num_aff_pc,
+					const uint32_t *ssn, const uint32_t *smi, const char *info_string)
+{
+	/* encoding is exactly identical to DUNA */
+	struct xua_msg *xua = sua_encode_duna(rctx, num_rctx, aff_pc, num_aff_pc, ssn, smi, info_string);
+	if (xua)
+		xua->hdr.msg_type = SUA_SNM_DAUD;
+	return xua;
+}
+#endif
+
+
+/*! Transmit SSNM DUNA/DAVA message indicating [un]availability of certain point code[s]
+ *  \param[in] asp ASP through whihc to transmit message. Must be ACTIVE.
+ *  \param[in] rctx array of Routing Contexts in network byte order.
+ *  \param[in] num_rctx number of rctx
+ *  \param[in] aff_pc array of 'Affected Point Code' in network byte order.
+ *  \param[in] num_aff_pc number of aff_pc
+ *  \param[in] aff_ssn affected SSN (optional)
+ *  \param[in] smi subsystem multiplicity indicator (optional)
+ *  \param[in] info_string optional information strng (can be NULL).
+ *  \param[in] available are aff_pc now available (true) or unavailable (false) */
+void sua_tx_snm_available(struct osmo_ss7_asp *asp, const uint32_t *rctx, unsigned int num_rctx,
+			  const uint32_t *aff_pc, unsigned int num_aff_pc, const uint32_t *aff_ssn,
+			  const uint32_t *smi, const char *info_string, bool available)
+{
+	struct xua_msg *xua;
+
+	if (available)
+		xua = sua_encode_dava(rctx, num_rctx, aff_pc, num_aff_pc, aff_ssn, smi, info_string);
+	else
+		xua = sua_encode_duna(rctx, num_rctx, aff_pc, num_aff_pc, aff_ssn, smi, info_string);
+
+	sua_tx_xua_asp(asp, xua);
+}
+
+/* received SNM message on ASP side */
+static int sua_rx_snm_asp(struct osmo_ss7_asp *asp, struct xua_msg *xua)
+{
+	struct osmo_ss7_as *as = NULL;
+	struct xua_msg_part *rctx_ie = xua_msg_find_tag(xua, SUA_IEI_ROUTE_CTX);
+	int rc;
+
+	rc = xua_find_as_for_asp(&as, asp, rctx_ie);
+	if (rc)
+		return rc;
+
+	switch (xua->hdr.msg_type) {
+	case SUA_SNM_DUNA:
+		xua_snm_rx_duna(asp, as, xua);
+		break;
+	case SUA_SNM_DAVA:
+		xua_snm_rx_dava(asp, as, xua);
+		break;
+	case SUA_SNM_DUPU:
+	case SUA_SNM_SCON:
+	case SUA_SNM_DRST:
+		LOGPASP(asp, DLSUA, LOGL_NOTICE, "Received unsupported SUA SNM message type %u\n",
+			xua->hdr.msg_type);
+		/* silently ignore those to not confuse the sender */
+		break;
+	default:
+		return SUA_ERR_UNSUPP_MSG_TYPE;
+	}
+
+	return 0;
+}
+
+/* received SNM message on SG side */
+static int sua_rx_snm_sg(struct osmo_ss7_asp *asp, struct xua_msg *xua)
+{
+	switch (xua->hdr.msg_type) {
+	case SUA_SNM_DAUD:	/* Audit: ASP inquires about availability of Point Codes */
+		xua_snm_rx_daud(asp, xua);
+		break;
+	default:
+		return SUA_ERR_UNSUPP_MSG_TYPE;
+	}
+
+	return 0;
+}
+
+static int sua_rx_snm(struct osmo_ss7_asp *asp, struct xua_msg *xua)
+{
+	/* SNM only permitted in ACTIVE state */
+	if (asp->fi->state != XUA_ASP_S_ACTIVE) {
+		LOGPASP(asp, DLSUA, LOGL_NOTICE, "Received M3UA SNM while ASP in state %s\n",
+			osmo_fsm_inst_state_name(asp->fi));
+		return SUA_ERR_UNEXPECTED_MSG;
+	}
+
+	switch (asp->cfg.role) {
+	case OSMO_SS7_ASP_ROLE_SG:
+		return sua_rx_snm_sg(asp, xua);
+	case OSMO_SS7_ASP_ROLE_ASP:
+		return sua_rx_snm_asp(asp, xua);
+	default:
+		return SUA_ERR_UNSUPP_MSG_CLASS;
+	}
+}
diff --git a/src/xua_as_fsm.c b/src/xua_as_fsm.c
index 731504b..7c791cf 100644
--- a/src/xua_as_fsm.c
+++ b/src/xua_as_fsm.c
@@ -75,6 +75,26 @@
 	return sent;
 }
 
+/* determine which role (SG/ASP/IPSP) we operate in */
+static int get_local_role(struct osmo_ss7_as *as)
+{
+	unsigned int i;
+
+	/* this is a bit tricky. "osmo_ss7_as" has no configuation of a role,
+	 * only the ASPs have.  As they all must be of the same role, let's simply
+	 * find the first one and return its role */
+	for (i = 0; i < ARRAY_SIZE(as->cfg.asps); i++) {
+		struct osmo_ss7_asp *asp = as->cfg.asps[i];
+
+		if (!asp)
+			continue;
+
+		return asp->cfg.role;
+	}
+	/* we don't have any ASPs in this AS? Strange */
+	return -1;
+}
+
 static struct osmo_ss7_asp *xua_as_select_asp_override(struct osmo_ss7_as *as)
 {
 	struct osmo_ss7_asp *asp;
@@ -318,6 +338,17 @@
 	/* TODO: ASP-Id of ASP triggering this state change */
 
 	as_notify_all_asp(xafp->as, &npar);
+
+	/* only if we are the SG, we must start broadcasting availability information
+	 * to everyone else */
+	if (get_local_role(xafp->as) == OSMO_SS7_ASP_ROLE_SG) {
+		/* advertise availability of the routing key to others */
+		uint32_t aff_pc = htonl(as->cfg.routing_key.pc);
+		if (old_state != XUA_AS_S_ACTIVE && fi->state == XUA_AS_S_ACTIVE)
+			xua_snm_pc_available(as, &aff_pc, 1, NULL, true);
+		else if (old_state == XUA_AS_S_ACTIVE && fi->state != XUA_AS_S_ACTIVE)
+			xua_snm_pc_available(as, &aff_pc, 1, NULL, false);
+	}
 };
 
 static void xua_as_fsm_inactive(struct osmo_fsm_inst *fi, uint32_t event, void *data)
diff --git a/src/xua_internal.h b/src/xua_internal.h
index 65adfb6..e76fddf 100644
--- a/src/xua_internal.h
+++ b/src/xua_internal.h
@@ -18,10 +18,19 @@
 int sua_rx_msg(struct osmo_ss7_asp *asp, struct msgb *msg);
 
 int sua_tx_xua_as(struct osmo_ss7_as *as, struct xua_msg *xua);
+void sua_tx_snm_available(struct osmo_ss7_asp *asp, const uint32_t *rctx, unsigned int num_rctx,
+			  const uint32_t *aff_pc, unsigned int num_aff_pc, const uint32_t *aff_ssn,
+			  const uint32_t *smi, const char *info_string, bool available);
 
 struct osmo_mtp_prim *m3ua_to_xfer_ind(struct xua_msg *xua);
 int m3ua_hmdc_rx_from_l2(struct osmo_ss7_instance *inst, struct xua_msg *xua);
 int m3ua_tx_xua_as(struct osmo_ss7_as *as, struct xua_msg *xua);
+void m3ua_tx_snm_available(struct osmo_ss7_asp *asp, const uint32_t *rctx, unsigned int num_rctx,
+			   const uint32_t *aff_pc, unsigned int num_aff_pc,
+			   const char *info_string, bool available);
+void xua_snm_rx_daud(struct osmo_ss7_asp *asp, struct xua_msg *xua);
+void xua_snm_rx_duna(struct osmo_ss7_asp *asp, struct osmo_ss7_as *as, struct xua_msg *xua);
+void xua_snm_rx_dava(struct osmo_ss7_asp *asp, struct osmo_ss7_as *as, struct xua_msg *xua);
 int m3ua_rx_msg(struct osmo_ss7_asp *asp, struct msgb *msg);
 
 struct msgb *m3ua_msgb_alloc(const char *name);
@@ -59,6 +68,9 @@
 				enum osmo_xlm_prim_type prim_type,
 				enum osmo_prim_operation op);
 
+void xua_snm_pc_available(struct osmo_ss7_as *as, const uint32_t *aff_pc,
+                          unsigned int num_aff_pc, const char *info_str, bool available);
+
 extern struct osmo_fsm xua_default_lm_fsm;
 extern const struct value_string m3ua_rkm_reg_status_vals[];
 extern const struct value_string m3ua_rkm_dereg_status_vals[];
diff --git a/src/xua_snm.c b/src/xua_snm.c
new file mode 100644
index 0000000..c4dffbb
--- /dev/null
+++ b/src/xua_snm.c
@@ -0,0 +1,211 @@
+/* M3UA/SUA [S]SNM Handling */
+
+/* (C) 2021 by Harald Welte <laforge at gnumonks.org>
+ * All Rights Reserved
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <stdint.h>
+
+#include <osmocom/core/utils.h>
+#include <osmocom/core/talloc.h>
+#include <osmocom/core/linuxlist.h>
+
+#include <osmocom/sigtran/osmo_ss7.h>
+#include <osmocom/sigtran/protocol/m3ua.h>
+#include <osmocom/sigtran/protocol/sua.h>
+
+#include "xua_internal.h"
+
+/* we can share this code between M3UA and SUA as the below conditions are true */
+osmo_static_assert(M3UA_SNM_DUNA == SUA_SNM_DUNA, _sa_duna);
+osmo_static_assert(M3UA_SNM_DAVA == SUA_SNM_DAVA, _sa_dava);
+osmo_static_assert(M3UA_SNM_DAUD == SUA_SNM_DAUD, _sa_dava);
+osmo_static_assert(M3UA_IEI_AFFECTED_PC == SUA_IEI_AFFECTED_PC, _sa_aff_pc);
+osmo_static_assert(M3UA_IEI_ROUTE_CTX == SUA_IEI_ROUTE_CTX, _sa_rctx);
+osmo_static_assert(M3UA_IEI_INFO_STRING == SUA_IEI_INFO_STRING, _sa_inf_str);
+
+static const char *format_affected_pcs_c(void *ctx, const struct osmo_ss7_instance *s7i,
+					 const struct xua_msg_part *ie_aff_pc)
+{
+	const uint32_t *aff_pc = (const uint32_t *) ie_aff_pc->dat;
+	unsigned int num_aff_pc = ie_aff_pc->len / sizeof(uint32_t);
+	char *out = talloc_strdup(ctx, "");
+	int i;
+
+	for (i = 0; i < num_aff_pc; i++) {
+		uint32_t _aff_pc = ntohl(aff_pc[i]);
+		uint32_t pc = _aff_pc & 0xffffff;
+		uint8_t mask = _aff_pc >> 24;
+
+		/* append point code + mask */
+		out = talloc_asprintf_append(out, "%s%s/%u, ", i == 0 ? "" : ", ",
+					     osmo_ss7_pointcode_print(s7i, pc), mask);
+	}
+	return out;
+}
+
+/* obtain all routing contexts (in network byte order) that exist within the given ASP */
+static unsigned int get_all_rctx_for_asp(uint32_t *rctx, unsigned int rctx_size,
+					 struct osmo_ss7_asp *asp, struct osmo_ss7_as *excl_as)
+{
+	unsigned int count = 0;
+	struct osmo_ss7_as *as;
+
+	llist_for_each_entry(as, &asp->inst->as_list, list) {
+		if (as == excl_as)
+			continue;
+		if (!osmo_ss7_as_has_asp(as, asp))
+			continue;
+		if (as->cfg.routing_key.context == 0)
+			continue;
+		if (count >= rctx_size)
+			break;
+		rctx[count] = htonl(as->cfg.routing_key.context);
+		count++;
+	}
+	return count;
+}
+
+static void xua_tx_snm_available(struct osmo_ss7_asp *asp, const uint32_t *rctx, unsigned int num_rctx,
+				 const uint32_t *aff_pc, unsigned int num_aff_pc,
+				 const char *info_str, bool available)
+{
+	switch (asp->cfg.proto) {
+	case OSMO_SS7_ASP_PROT_M3UA:
+		m3ua_tx_snm_available(asp, rctx, num_rctx, aff_pc, num_aff_pc, info_str, available);
+		break;
+	case OSMO_SS7_ASP_PROT_SUA:
+		sua_tx_snm_available(asp, rctx, num_rctx, aff_pc, num_aff_pc, NULL, NULL, info_str, available);
+		break;
+	default:
+		break;
+	}
+}
+
+/* advertise availability of point codes (with masks) */
+void xua_snm_pc_available(struct osmo_ss7_as *as, const uint32_t *aff_pc,
+			  unsigned int num_aff_pc, const char *info_str, bool available)
+{
+	struct osmo_ss7_instance *s7i = as->inst;
+	struct osmo_ss7_asp *asp;
+	uint32_t rctx[32];
+	unsigned int num_rctx;
+
+	llist_for_each_entry(asp, &s7i->asp_list, list) {
+		/* SSNM is only permitted for ASPs in ACTIVE state */
+		if (!osmo_ss7_asp_active(asp))
+			continue;
+
+		/* only send DAVA/DUNA if we locally are the SG and the remote is ASP */
+		if (asp->cfg.role != OSMO_SS7_ASP_ROLE_SG)
+			continue;
+
+		num_rctx = get_all_rctx_for_asp(rctx, ARRAY_SIZE(rctx), asp, as);
+		/* this can happen if the given ASP is only in the AS that reports the change,
+		 * which shall be excluded */
+		if (num_rctx == 0)
+			continue;
+		xua_tx_snm_available(asp, rctx, num_rctx, aff_pc, num_aff_pc, info_str, available);
+	}
+}
+
+/* receive DAUD from ASP; pc is 'affected PC' IE with mask in network byte order! */
+void xua_snm_rx_daud(struct osmo_ss7_asp *asp, struct xua_msg *xua)
+{
+	struct xua_msg_part *ie_aff_pc = xua_msg_find_tag(xua, M3UA_IEI_AFFECTED_PC);
+	const char *info_str = xua_msg_get_str(xua, M3UA_IEI_INFO_STRING);
+	struct osmo_ss7_instance *s7i = asp->inst;
+	unsigned int num_aff_pc;
+	unsigned int num_rctx;
+	const uint32_t *aff_pc;
+	uint32_t rctx[32];
+	int log_ss = osmo_ss7_asp_get_log_subsys(asp);
+	int i;
+
+	OSMO_ASSERT(ie_aff_pc);
+	aff_pc = (const uint32_t *) ie_aff_pc->dat;
+	num_aff_pc = ie_aff_pc->len / sizeof(uint32_t);
+
+	num_rctx = get_all_rctx_for_asp(rctx, ARRAY_SIZE(rctx), asp, NULL);
+
+	LOGPASP(asp, log_ss, LOGL_INFO, "Rx DAUD(%s) for %s\n", info_str ? info_str : "",
+		format_affected_pcs_c(xua, asp->inst, ie_aff_pc));
+
+	/* iterate over list of point codes, generate DAVA/DUPU */
+	for (i = 0; i < num_aff_pc; i++) {
+		uint32_t _aff_pc = ntohl(aff_pc[i]);
+		uint32_t pc = _aff_pc & 0xffffff;
+		uint8_t mask = _aff_pc >> 24;
+		bool is_available = false;
+
+		if (mask == 0) {
+			/* one single point code */
+
+			/* FIXME: don't just check for a route; but also check if the route is "active" */
+			if (osmo_ss7_route_lookup(s7i, pc))
+				is_available = true;
+
+			xua_tx_snm_available(asp, rctx, num_rctx, &aff_pc[i], 1, "Response to DAUD",
+					     is_available);
+		} else {
+			/* TODO: wildcard match */
+			LOGPASP(asp, log_ss, LOGL_NOTICE, "DAUD with wildcard match not supported yet\n");
+		}
+	}
+}
+
+/* an incoming xUA DUNA was received from a remote SG */
+void xua_snm_rx_duna(struct osmo_ss7_asp *asp, struct osmo_ss7_as *as, struct xua_msg *xua)
+{
+	struct xua_msg_part *ie_aff_pc = xua_msg_find_tag(xua, M3UA_IEI_AFFECTED_PC);
+	const char *info_str = xua_msg_get_str(xua, M3UA_IEI_INFO_STRING);
+	/* TODO: should our processing depend on the RCTX included? I somehow don't think so */
+	//struct xua_msg_part *ie_rctx = xua_msg_find_tag(xua, M3UA_IEI_ROUTE_CTX);
+	int log_ss = osmo_ss7_asp_get_log_subsys(asp);
+
+	OSMO_ASSERT(ie_aff_pc);
+
+	if (asp->cfg.role != OSMO_SS7_ASP_ROLE_ASP)
+		return;
+
+	LOGPASP(asp, log_ss, LOGL_NOTICE, "Rx DUNA(%s) for %s\n", info_str ? info_str : "",
+		format_affected_pcs_c(xua, asp->inst, ie_aff_pc));
+
+	xua_snm_pc_available(as, (const uint32_t *)ie_aff_pc->dat, ie_aff_pc->len/4, info_str, false);
+}
+
+/* an incoming xUA DAVA was received from a remote SG */
+void xua_snm_rx_dava(struct osmo_ss7_asp *asp, struct osmo_ss7_as *as, struct xua_msg *xua)
+{
+	struct xua_msg_part *ie_aff_pc = xua_msg_find_tag(xua, M3UA_IEI_AFFECTED_PC);
+	const char *info_str = xua_msg_get_str(xua, M3UA_IEI_INFO_STRING);
+	/* TODO: should our processing depend on the RCTX included? I somehow don't think so */
+	//struct xua_msg_part *ie_rctx = xua_msg_find_tag(xua, M3UA_IEI_ROUTE_CTX);
+	int log_ss = osmo_ss7_asp_get_log_subsys(asp);
+
+	OSMO_ASSERT(ie_aff_pc);
+
+	if (asp->cfg.role != OSMO_SS7_ASP_ROLE_ASP)
+		return;
+
+	LOGPASP(asp, log_ss, LOGL_NOTICE, "Rx DAVA(%s) for %s\n", info_str ? info_str : "",
+		format_affected_pcs_c(xua, asp->inst, ie_aff_pc));
+
+	xua_snm_pc_available(as, (const uint32_t *)ie_aff_pc->dat, ie_aff_pc->len/4, info_str, true);
+}

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

Gerrit-Project: libosmo-sccp
Gerrit-Branch: master
Gerrit-Change-Id: Id92be4691b0fd77598a6edb642c028bbd8c5b623
Gerrit-Change-Number: 22777
Gerrit-PatchSet: 4
Gerrit-Owner: laforge <laforge at osmocom.org>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: laforge <laforge at osmocom.org>
Gerrit-Reviewer: pespin <pespin at sysmocom.de>
Gerrit-MessageType: merged
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.osmocom.org/pipermail/gerrit-log/attachments/20210210/6d269844/attachment.htm>


More information about the gerrit-log mailing list