<p>laforge <strong>submitted</strong> this change.</p><p><a href="https://gerrit.osmocom.org/c/libosmo-sccp/+/22777">View Change</a></p><div style="white-space:pre-wrap">Approvals:
  Jenkins Builder: Verified
  pespin: Looks good to me, but someone else must approve
  laforge: Looks good to me, approved

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

<div style="display:none"> Gerrit-Project: libosmo-sccp </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-Change-Id: Id92be4691b0fd77598a6edb642c028bbd8c5b623 </div>
<div style="display:none"> Gerrit-Change-Number: 22777 </div>
<div style="display:none"> Gerrit-PatchSet: 4 </div>
<div style="display:none"> Gerrit-Owner: laforge <laforge@osmocom.org> </div>
<div style="display:none"> Gerrit-Reviewer: Jenkins Builder </div>
<div style="display:none"> Gerrit-Reviewer: laforge <laforge@osmocom.org> </div>
<div style="display:none"> Gerrit-Reviewer: pespin <pespin@sysmocom.de> </div>
<div style="display:none"> Gerrit-MessageType: merged </div>