laforge submitted this change.

View Change

Approvals: Jenkins Builder: Verified osmith: Looks good to me, but someone else must approve laforge: Looks good to me, approved daniel: Looks good to me, but someone else must approve
mtp3: Implement RTPC transfer prohibited to concerned SP or STP

Send Transfer prohibited (DUNA in M3UA) to originator upon trying to route
message to inaccessible DPC, as explained in Q.704 Figure 44 and section
13.2.

Related: OS#6892
Change-Id: I7e89db3d82374ca03a2e71fb558c7cec9bd651c4
---
M src/Makefile.am
M src/m3ua.c
M src/mtp3_hmrt.c
A src/mtp3_rtpc.c
A src/mtp3_rtpc.h
M src/xua_internal.h
6 files changed, 155 insertions(+), 5 deletions(-)

diff --git a/src/Makefile.am b/src/Makefile.am
index 29cf10a..f51819e 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -6,6 +6,7 @@
mtp3_hmdc.h \
mtp3_hmdt.h \
mtp3_hmrt.h \
+ mtp3_rtpc.h \
sccp_connection.h \
sccp_scoc_fsm.h \
sccp_instance.h \
@@ -53,6 +54,7 @@
mtp3_hmdc.c \
mtp3_hmdt.c \
mtp3_hmrt.c \
+ mtp3_rtpc.c \
sccp2sua.c \
sccp_connection.c \
sccp_helpers.c \
diff --git a/src/m3ua.c b/src/m3ua.c
index 36018e1..2b7c1e7 100644
--- a/src/m3ua.c
+++ b/src/m3ua.c
@@ -864,9 +864,9 @@
***********************************************************************/

/* 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 *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();

diff --git a/src/mtp3_hmrt.c b/src/mtp3_hmrt.c
index 9ab7e33..25b2bc4 100644
--- a/src/mtp3_hmrt.c
+++ b/src/mtp3_hmrt.c
@@ -36,6 +36,7 @@
#include <osmocom/sigtran/protocol/m3ua.h>

#include "mtp3_hmdc.h"
+#include "mtp3_rtpc.h"
#include "xua_internal.h"
#include "ss7_as.h"
#include "ss7_asp.h"
@@ -111,8 +112,9 @@
} else {
LOGSS7(inst, LOGL_ERROR, "MTP-TRANSFER.req for dpc=%u=%s: no route!\n",
dpc, osmo_ss7_pointcode_print(inst, dpc));
- /* DPC unknown HMRT -> MGMT */
- /* Message Received for inaccesible SP HMRT ->RTPC */
+ /* "Message received for unknown SP HMRT -> MGMT"*/
+ /* "Message received for inaccessible SP HMRT -> RTPC" */
+ mtp3_rtpc_rx_msg_for_inaccessible_sp(inst, xua);
/* Discard Message */
}
xua_msg_free(xua);
diff --git a/src/mtp3_rtpc.c b/src/mtp3_rtpc.c
new file mode 100644
index 0000000..1ce5c25
--- /dev/null
+++ b/src/mtp3_rtpc.c
@@ -0,0 +1,131 @@
+/***********************************************************************
+ * MTP Level 3 - Transfer prohibited control (RTPC), ITU Q.704 Figure 44
+ ***********************************************************************/
+
+/* (C) 2025 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
+ * 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/sigtran/protocol/m3ua.h>
+#include <osmocom/sigtran/osmo_ss7.h>
+
+#include "mtp3_hmdt.h"
+#include "mtp3_rtpc.h"
+#include "ss7_as.h"
+#include "ss7_internal.h"
+#include "ss7_route.h"
+#include "ss7_route_table.h"
+#include "xua_internal.h"
+#include "xua_msg.h"
+
+/* Generate a DUNA message to be sent back to originator. */
+static struct xua_msg *gen_duna_ret_msg(struct osmo_ss7_instance *inst, const struct xua_msg *orig_xua)
+{
+ struct xua_msg *xua;
+ struct xua_msg_part *rctx_ie;
+ unsigned int num_rctx = 0;
+ uint32_t rctx = 0;
+ uint32_t aff_pc = htonl(orig_xua->mtp.dpc);
+
+ if ((rctx_ie = xua_msg_find_tag(orig_xua, M3UA_IEI_ROUTE_CTX))) {
+ rctx = xua_msg_part_get_u32(rctx_ie);
+ num_rctx = 1;
+ }
+ xua = m3ua_encode_duna(&rctx, num_rctx, &aff_pc, 1,
+ "transfer prohibited (inaccessible SP)");
+ OSMO_ASSERT(xua);
+
+ xua->mtp = orig_xua->mtp;
+ xua->mtp.opc = orig_xua->mtp.dpc;
+ xua->mtp.dpc = orig_xua->mtp.opc;
+ return xua;
+}
+
+ /* Figure 44/Q.704 (sheet 1 of 3), "Message received for inaccessible SP HMRT -> RTPC" */
+int mtp3_rtpc_rx_msg_for_inaccessible_sp(struct osmo_ss7_instance *inst, const struct xua_msg *orig_xua)
+{
+ struct xua_msg *xua;
+ char buf_orig_opc[MAX_PC_STR_LEN];
+ char buf_orig_dpc[MAX_PC_STR_LEN];
+ struct osmo_ss7_route_label rtlabel;
+ struct osmo_ss7_route *rt;
+
+ /* TODO: Start T8 */
+
+ /* "transfer prohibited RTPC -> HMRT", "To concerned SP or STP".
+ * See also Q.704 13.2 Transfer-prohibited. */
+
+ /* Note: There's no explicit mention of MTP3 TFP equivalent in RFC4666 (M3UA) specs,
+ * but section 1.4.3.2 explicitly mentions: "TFP ... MUST NOT be encapsulated as
+ * Data message Payload Data and sent either from SG to ASP or from ASP to
+ * SG. The SG MUST terminate these messages and generate M3UA messages,
+ * as appropriate."
+ * Best match for it is DUNA, so DUNA we send.
+ */
+
+ if (osmo_ss7_pc_is_local(inst, orig_xua->mtp.opc)) {
+ xua = gen_duna_ret_msg(inst, orig_xua);
+ return mtp3_hmdt_message_for_distribution(inst, xua);
+ }
+
+ /* We should only be sending DUNA to M3UA peers, hence why we don't
+ * simply call mtp3_hmrt_message_for_routing() here. */
+ rtlabel = (struct osmo_ss7_route_label){
+ .opc = orig_xua->mtp.dpc,
+ .dpc = orig_xua->mtp.opc,
+ .sls = orig_xua->mtp.sls,
+ };
+ rt = ss7_instance_lookup_route(inst, &rtlabel);
+ if (!rt) {
+ LOGSS7(inst, LOGL_NOTICE, "Tx TFP (DUNA) inaccessible SP %u=%s to concerned SP %u=%s: no route!\n",
+ orig_xua->mtp.dpc, osmo_ss7_pointcode_print_buf(buf_orig_dpc, sizeof(buf_orig_dpc), inst, orig_xua->mtp.dpc),
+ orig_xua->mtp.opc, osmo_ss7_pointcode_print_buf(buf_orig_opc, sizeof(buf_orig_opc), inst, orig_xua->mtp.opc));
+ return 0;
+ }
+ if (!rt->dest.as) {
+ LOGSS7(inst, LOGL_ERROR, "Tx TFP (DUNA) inaccessible SP %u=%s to concerned SP %u=%s: unsupported for linkset!\n",
+ orig_xua->mtp.dpc, osmo_ss7_pointcode_print_buf(buf_orig_dpc, sizeof(buf_orig_dpc), inst, orig_xua->mtp.dpc),
+ orig_xua->mtp.opc, osmo_ss7_pointcode_print_buf(buf_orig_opc, sizeof(buf_orig_opc), inst, orig_xua->mtp.opc));
+ return 0;
+ }
+
+ switch (rt->dest.as->cfg.proto) {
+ case OSMO_SS7_ASP_PROT_M3UA:
+ LOGSS7(inst, LOGL_INFO, "Message received for inaccessible SP %u=%s. Tx TFP (DUNA) to concerned SP %u=%s\n",
+ orig_xua->mtp.dpc, osmo_ss7_pointcode_print_buf(buf_orig_dpc, sizeof(buf_orig_dpc), inst, orig_xua->mtp.dpc),
+ orig_xua->mtp.opc, osmo_ss7_pointcode_print_buf(buf_orig_opc, sizeof(buf_orig_opc), inst, orig_xua->mtp.opc));
+ xua = gen_duna_ret_msg(inst, orig_xua);
+ return m3ua_tx_xua_as(rt->dest.as, xua);
+ case OSMO_SS7_ASP_PROT_IPA:
+ /* FIXME: No DUNA in IPA, maybe send SUA CLDR (SCCP UDTS) instead? */
+ LOGSS7(inst, LOGL_INFO, "Message received for inaccessible SP %u=%s, "
+ "but concerned SP %u=%s is IPA-based and doesn't support TFP (DUNA)\n",
+ orig_xua->mtp.dpc, osmo_ss7_pointcode_print_buf(buf_orig_dpc, sizeof(buf_orig_dpc), inst, orig_xua->mtp.dpc),
+ orig_xua->mtp.opc, osmo_ss7_pointcode_print_buf(buf_orig_opc, sizeof(buf_orig_opc), inst, orig_xua->mtp.opc));
+ return 0;
+ default:
+ LOGSS7(inst, LOGL_ERROR, "DUNA message for ASP of unknown protocol %u\n",
+ rt->dest.as->cfg.proto);
+ return 0;
+ }
+
+ return 0;
+}
diff --git a/src/mtp3_rtpc.h b/src/mtp3_rtpc.h
new file mode 100644
index 0000000..8a0569d
--- /dev/null
+++ b/src/mtp3_rtpc.h
@@ -0,0 +1,11 @@
+#pragma once
+
+#include <stdint.h>
+#include <unistd.h>
+
+#include <osmocom/sigtran/mtp_sap.h>
+
+#include "ss7_instance.h"
+#include "xua_msg.h"
+
+int mtp3_rtpc_rx_msg_for_inaccessible_sp(struct osmo_ss7_instance *inst, const struct xua_msg *xua);
diff --git a/src/xua_internal.h b/src/xua_internal.h
index a1023c1..8674ef5 100644
--- a/src/xua_internal.h
+++ b/src/xua_internal.h
@@ -53,6 +53,10 @@
void m3ua_tx_dupu(struct osmo_ss7_asp *asp, const uint32_t *rctx, unsigned int num_rctx,
uint32_t dpc, uint16_t user, uint16_t cause, const char *info_str);

+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);
+
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);

To view, visit change 41524. To unsubscribe, or for help writing mail filters, visit settings.

Gerrit-MessageType: merged
Gerrit-Project: libosmo-sigtran
Gerrit-Branch: master
Gerrit-Change-Id: I7e89db3d82374ca03a2e71fb558c7cec9bd651c4
Gerrit-Change-Number: 41524
Gerrit-PatchSet: 2
Gerrit-Owner: pespin <pespin@sysmocom.de>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: daniel <dwillmann@sysmocom.de>
Gerrit-Reviewer: fixeria <vyanitskiy@sysmocom.de>
Gerrit-Reviewer: laforge <laforge@osmocom.org>
Gerrit-Reviewer: osmith <osmith@sysmocom.de>