lists.osmocom.org
Sign In Sign Up
Manage this list Sign In Sign Up

Keyboard Shortcuts

Thread View

  • j: Next unread message
  • k: Previous unread message
  • j a: Jump to all threads
  • j l: Jump to MailingList overview

gerrit-log

Thread Start a new thread
Download
Threads by month
  • ----- 2026 -----
  • November
  • October
  • September
  • August
  • July
  • June
  • May
  • April
  • March
  • February
  • January
  • ----- 2025 -----
  • December
  • November
  • October
  • September
  • August
  • July
  • June
  • May
  • April
  • March
  • February
  • January
  • ----- 2024 -----
  • December
  • November
  • October
  • September
  • August
  • July
  • June
  • May
  • April
  • March
  • February
  • January
  • ----- 2023 -----
  • December
  • November
  • October
  • September
  • August
  • July
  • June
  • May
  • April
  • March
  • February
  • January
  • ----- 2022 -----
  • December
  • November
  • October
  • September
  • August
  • July
  • June
  • May
  • April
  • March
  • February
  • January
gerrit-log@lists.osmocom.org

December 2025

  • 1 participants
  • 1175 discussions
[M] Change in libosmo-sigtran[master]: Implement ITU Q.704 timer T8
by laforge 02 Dec '25

02 Dec '25
laforge has submitted this change. ( https://gerrit.osmocom.org/c/libosmo-sigtran/+/41526?usp=email ) Change subject: Implement ITU Q.704 timer T8 ...................................................................... Implement ITU Q.704 timer T8 Related: OS#6892 Change-Id: I27ebf7327448554a6e4600e45a4ab0343ab846a4 --- M src/mtp3_rtpc.c M src/ss7_instance.c M src/ss7_instance.h M src/ss7_vty.c M tests/vty/osmo_stp_test.vty 5 files changed, 208 insertions(+), 1 deletion(-) Approvals: osmith: Looks good to me, but someone else must approve laforge: Looks good to me, approved Jenkins Builder: Verified diff --git a/src/mtp3_rtpc.c b/src/mtp3_rtpc.c index 1ce5c25..34d40e7 100644 --- a/src/mtp3_rtpc.c +++ b/src/mtp3_rtpc.c @@ -68,7 +68,15 @@ struct osmo_ss7_route_label rtlabel; struct osmo_ss7_route *rt; - /* TODO: Start T8 */ + /* Start T8 */ + if (ss7_instance_t8_inaccessible_sp_running(inst, orig_xua->mtp.dpc)) { + /* T8 is running for this SP, inhibit Tx of transfer prohibited */ + LOGSS7(inst, LOGL_DEBUG, "Tx TFP (DUNA) inaccessible SP %u=%s to concerned SP %u=%s: inhibit due to T8\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; + } + ss7_instance_t8_inaccessible_sp_start(inst, orig_xua->mtp.dpc); /* "transfer prohibited RTPC -> HMRT", "To concerned SP or STP". * See also Q.704 13.2 Transfer-prohibited. */ diff --git a/src/ss7_instance.c b/src/ss7_instance.c index f8c78b4..b51f1b9 100644 --- a/src/ss7_instance.c +++ b/src/ss7_instance.c @@ -63,6 +63,25 @@ .ctr_desc = ss7_inst_rcd, }; +const struct osmo_tdef ss7_instance_xua_timer_defaults[SS7_INST_XUA_TIMERS_LEN] = { + { .T = SS7_INST_XUA_T8, .default_val = SS7_INST_XUA_DEFAULT_T8_MSEC, .unit = OSMO_TDEF_MS, + .desc = "T8 - Transfer prohibited inhibition timer (transient solution) (ms)", + .min_val = 800, .max_val = 1200}, + {} +}; + +/* ITU Q.704 16.8 Timers and timer values */ +const struct value_string ss7_instance_xua_timer_names[] = { + { SS7_INST_XUA_T8, "T8" }, + {} +}; + +osmo_static_assert(ARRAY_SIZE(ss7_instance_xua_timer_defaults) == (SS7_INST_XUA_TIMERS_LEN) && + ARRAY_SIZE(ss7_instance_xua_timer_names) == (SS7_INST_XUA_TIMERS_LEN), + assert_ss7_instance_xua_timer_count); + +static void t8_inaccessible_sp_timer_cb(void *_inst); + struct osmo_ss7_instance * ss7_instance_alloc(void *ctx, uint32_t id) { @@ -84,6 +103,13 @@ INIT_LLIST_HEAD(&inst->asp_list); INIT_LLIST_HEAD(&inst->rtable_list); INIT_LLIST_HEAD(&inst->xua_servers); + INIT_LLIST_HEAD(&inst->t8_inaccessible_sp.list); + + osmo_timer_setup(&inst->t8_inaccessible_sp.timer, t8_inaccessible_sp_timer_cb, inst); + + inst->cfg.T_defs_xua = talloc_memdup(inst, ss7_instance_xua_timer_defaults, + sizeof(ss7_instance_xua_timer_defaults)); + osmo_tdefs_reset(inst->cfg.T_defs_xua); inst->ctrg = rate_ctr_group_alloc(inst, &ss7_inst_rcgd, id); if (!inst->ctrg) { @@ -124,6 +150,9 @@ llist_for_each_entry_safe(lset, lset2, &inst->linksets, list) ss7_linkset_destroy(lset); + osmo_timer_del(&inst->t8_inaccessible_sp.timer); + /* Talloc takes care of freeing inst->t8_inaccessible_sp.list and its entries */ + rate_ctr_group_free(inst->ctrg); llist_del(&inst->list); talloc_free(inst); @@ -803,3 +832,61 @@ return NULL; } + + +static void t8_inaccessible_sp_timer_cb(void *_inst) +{ + struct osmo_ss7_instance *inst = _inst; + struct t8_inaccessible_sp_entry *it; + struct timespec ts_now, ts_t8; + char buf_dpc[MAX_PC_STR_LEN]; + + unsigned int t8_msec = osmo_tdef_get(inst->cfg.T_defs_xua, SS7_INST_XUA_T8, OSMO_TDEF_MS, -1); + ts_t8.tv_sec = (t8_msec/1000); + ts_t8.tv_nsec = (t8_msec%1000)*1000*1000; + osmo_clock_gettime(CLOCK_MONOTONIC, &ts_now); + + while ((it = llist_first_entry_or_null(&inst->t8_inaccessible_sp.list, struct t8_inaccessible_sp_entry, entry))) { + struct timespec ts_expire; + timespecadd(&it->ts_started, &ts_t8, &ts_expire); + if (timespeccmp(&ts_expire, &ts_now, >)) { + struct timespec ts_diff; + timespecsub(&ts_expire, &ts_now, &ts_diff); + osmo_timer_schedule(&inst->t8_inaccessible_sp.timer, ts_diff.tv_sec, ts_diff.tv_nsec / 1000); + break; + } + LOGSS7(inst, LOGL_DEBUG, "T8: SP %u=%s: Timeout\n", it->dpc, osmo_ss7_pointcode_print_buf(buf_dpc, sizeof(buf_dpc), inst, it->dpc)); + llist_del(&it->entry); + talloc_free(it); + } +} + +bool ss7_instance_t8_inaccessible_sp_running(const struct osmo_ss7_instance *inst, uint32_t dpc) +{ + struct t8_inaccessible_sp_entry *it; + llist_for_each_entry(it, &inst->t8_inaccessible_sp.list, entry) { + if (it->dpc == dpc) + return true; + } + return false; +} + +void ss7_instance_t8_inaccessible_sp_start(struct osmo_ss7_instance *inst, uint32_t dpc) +{ + struct t8_inaccessible_sp_entry *it; + char buf_dpc[MAX_PC_STR_LEN]; + + LOGSS7(inst, LOGL_DEBUG, "T8: SP %u=%s: Start\n", + dpc, osmo_ss7_pointcode_print_buf(buf_dpc, sizeof(buf_dpc), inst, dpc)); + + OSMO_ASSERT(!ss7_instance_t8_inaccessible_sp_running(inst, dpc)); + + it = talloc_zero(inst, struct t8_inaccessible_sp_entry); + it->dpc = dpc; + osmo_clock_gettime(CLOCK_MONOTONIC, &it->ts_started); + if (llist_empty(&inst->t8_inaccessible_sp.list)) { + unsigned int timeout_msec = osmo_tdef_get(inst->cfg.T_defs_xua, SS7_INST_XUA_T8, OSMO_TDEF_MS, -1); + osmo_timer_schedule(&inst->t8_inaccessible_sp.timer, (timeout_msec/1000), ((timeout_msec%1000)*10)); + } + llist_add_tail(&it->entry, &inst->t8_inaccessible_sp.list); +} diff --git a/src/ss7_instance.h b/src/ss7_instance.h index 3045403..29310f4 100644 --- a/src/ss7_instance.h +++ b/src/ss7_instance.h @@ -3,6 +3,9 @@ #include <stdint.h> #include <stdbool.h> #include <osmocom/core/linuxlist.h> +#include <osmocom/core/tdef.h> +#include <osmocom/core/timer.h> +#include <osmocom/core/timer_compat.h> #include <osmocom/core/rate_ctr.h> #include <osmocom/sigtran/protocol/mtp.h> @@ -16,6 +19,17 @@ struct osmo_ss7_route_label; struct osmo_sccp_instance; +enum ss7_instance_xua_timer { + /* 0 kept unused on purpose since it's handled specially by osmo_fsm */ + SS7_INST_XUA_T8 = 1, /* Q.704 T8 */ + /* This must remain the last item: */ + SS7_INST_XUA_TIMERS_LEN +}; +extern const struct value_string ss7_instance_xua_timer_names[]; +extern const struct osmo_tdef ss7_instance_xua_timer_defaults[SS7_INST_XUA_TIMERS_LEN]; +/* According to SUA RFC3868 Section 8, M3UA RFC4666 Section 4.3.4.1 */ +#define SS7_INST_XUA_DEFAULT_T8_MSEC 1000 + enum ss7_instance_ctr { SS7_INST_CTR_PKT_RX_TOTAL, SS7_INST_CTR_PKT_RX_UNKNOWN, @@ -51,6 +65,13 @@ struct rate_ctr_group *ctrg; + /* Q.704 Figure 44 and section 13.2: List to store remote PCs with T8 started */ + struct { + /* list of struct t8_inaccessible_sp_entry, sorted by entry->ts_started */ + struct llist_head list; + struct osmo_timer_list timer; + } t8_inaccessible_sp; + struct { uint32_t id; char *name; @@ -71,6 +92,9 @@ * to skip for routing decisions. * range 0-3, defaults to 0, which means take all 4 bits. */ uint8_t sls_shift; + + /* T_defs defined at instance level: */ + struct osmo_tdef *T_defs_xua; } cfg; }; @@ -85,3 +109,15 @@ LOGP(subsys, level, "%u: " fmt, inst ? (inst)->cfg.id : 0, ## args) #define LOGSS7(inst, level, fmt, args ...) \ _LOGSS7(inst, DLSS7, level, fmt, ## args) + + +/*********************************************************************** + * ITUQ.704 13.2.2: Timer T8 concerning one SP + ***********************************************************************/ +struct t8_inaccessible_sp_entry { + struct llist_head entry; /* item in (struct osmo_ss7_instance)->t8_inaccessible_sp.list */ + uint32_t dpc; /* SP inaccessible */ + struct timespec ts_started; /* Timestamp T8 was started for this SP */ +}; +bool ss7_instance_t8_inaccessible_sp_running(const struct osmo_ss7_instance *inst, uint32_t dpc); +void ss7_instance_t8_inaccessible_sp_start(struct osmo_ss7_instance *inst, uint32_t dpc); diff --git a/src/ss7_vty.c b/src/ss7_vty.c index 98c6073..f3ba750 100644 --- a/src/ss7_vty.c +++ b/src/ss7_vty.c @@ -279,6 +279,61 @@ return CMD_SUCCESS; } +/* timer xua <name> <1-999999> + * (cmdstr and doc are dynamically generated from ss7_instance_xua_timer_names.) */ +DEFUN_ATTR(cs7_timer_xua, cs7_timer_xua_cmd, + NULL, NULL, CMD_ATTR_IMMEDIATE) +{ + struct osmo_ss7_instance *inst = vty->index; + enum ss7_instance_xua_timer timer = get_string_value(ss7_instance_xua_timer_names, argv[0]); + + if (timer <= 0 || timer >= SS7_INST_XUA_TIMERS_LEN) { + vty_out(vty, "%% Invalid timer: %s%s", argv[0], VTY_NEWLINE); + return CMD_WARNING; + } + + osmo_tdef_set(inst->cfg.T_defs_xua, timer, atoi(argv[1]), OSMO_TDEF_S); + return CMD_SUCCESS; +} + +static void gen_cs7_timer_xua_cmd_strs(struct cmd_element *cmd) +{ + int i; + char *cmd_str = NULL; + char *doc_str = NULL; + + OSMO_ASSERT(cmd->string == NULL); + OSMO_ASSERT(cmd->doc == NULL); + + osmo_talloc_asprintf(tall_vty_ctx, cmd_str, "timer xua ("); + osmo_talloc_asprintf(tall_vty_ctx, doc_str, + "Configure CS7 Instance default timer values\n" + "Configure CS7 Instance default xua timer values\n"); + + for (i = 0; ss7_instance_xua_timer_names[i].str; i++) { + const struct osmo_tdef *def; + enum ss7_asp_xua_timer timer; + + timer = ss7_instance_xua_timer_names[i].value; + def = osmo_tdef_get_entry((struct osmo_tdef *)&ss7_instance_xua_timer_defaults, timer); + OSMO_ASSERT(def); + + osmo_talloc_asprintf(tall_vty_ctx, cmd_str, "%s%s", + i ? "|" : "", + ss7_instance_xua_timer_names[i].str); + osmo_talloc_asprintf(tall_vty_ctx, doc_str, "%s (default: %lu)\n", + def->desc, + def->default_val); + } + + osmo_talloc_asprintf(tall_vty_ctx, cmd_str, ") <1-999999>"); + osmo_talloc_asprintf(tall_vty_ctx, doc_str, + "Timer value, in seconds\n"); + + cmd->string = cmd_str; + cmd->doc = doc_str; +} + static void write_one_cs7(struct vty *vty, struct osmo_ss7_instance *inst, bool show_dyn_config); static int write_all_cs7(struct vty *vty, bool show_dyn_config) @@ -1276,6 +1331,20 @@ * Common ***********************************************************************/ +static void write_cs7_timers_xua(struct vty *vty, const char *indent, + struct osmo_ss7_instance *inst) +{ + for (unsigned int i = 0; ss7_instance_xua_timer_names[i].str; i++) { + const struct osmo_tdef *tdef = osmo_tdef_get_entry(inst->cfg.T_defs_xua, ss7_instance_xua_timer_names[i].value); + if (!tdef) + continue; + if (tdef->val == tdef->default_val) + continue; + vty_out(vty, "%stimer xua %s %lu%s", indent, ss7_instance_xua_timer_names[i].str, + tdef->val, VTY_NEWLINE); + } +} + static void write_one_cs7(struct vty *vty, struct osmo_ss7_instance *inst, bool show_dyn_config) { struct osmo_ss7_asp *asp; @@ -1325,6 +1394,8 @@ if (inst->cfg.sls_shift != 0) vty_out(vty, " sls-shift %u%s", inst->cfg.sls_shift, VTY_NEWLINE); + write_cs7_timers_xua(vty, " ", inst); + /* first dump ASPs, as ASs reference them */ llist_for_each_entry(asp, &inst->asp_list, list) ss7_vty_write_one_asp(vty, asp, show_dyn_config); @@ -1482,6 +1553,9 @@ cs7_role = CS7_ROLE_SG; vty_init_shared(ctx); + gen_cs7_timer_xua_cmd_strs(&cs7_timer_xua_cmd); + install_lib_element(L_CS7_NODE, &cs7_timer_xua_cmd); + install_node(&rtable_node, NULL); install_lib_element(L_CS7_NODE, &cs7_route_table_cmd); install_lib_element(L_CS7_RTABLE_NODE, &cfg_description_cmd); diff --git a/tests/vty/osmo_stp_test.vty b/tests/vty/osmo_stp_test.vty index 8f2a96a..08d0092 100644 --- a/tests/vty/osmo_stp_test.vty +++ b/tests/vty/osmo_stp_test.vty @@ -130,6 +130,7 @@ no as NAME sccp-address NAME no sccp-address NAME + timer xua (T8) <1-999999> route-table system listen (sua|m3ua|ipa) <0-65534> [(sctp|tcp)] no listen (sua|m3ua|ipa) <0-65534> [(sctp|tcp)] @@ -149,6 +150,7 @@ no Negate a command or set its defaults as Configure an Application Server sccp-address Create/Modify an SCCP addressbook entry + timer Configure CS7 Instance default timer values route-table Specify the name of the route table listen Configure/Enable xUA Listener sccp-timer Configure SCCP timer values, see ITU-T Q.714 -- To view, visit https://gerrit.osmocom.org/c/libosmo-sigtran/+/41526?usp=email To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings?usp=email Gerrit-MessageType: merged Gerrit-Project: libosmo-sigtran Gerrit-Branch: master Gerrit-Change-Id: I27ebf7327448554a6e4600e45a4ab0343ab846a4 Gerrit-Change-Number: 41526 Gerrit-PatchSet: 3 Gerrit-Owner: pespin <pespin(a)sysmocom.de> Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: daniel <dwillmann(a)sysmocom.de> Gerrit-Reviewer: fixeria <vyanitskiy(a)sysmocom.de> Gerrit-Reviewer: laforge <laforge(a)osmocom.org> Gerrit-Reviewer: osmith <osmith(a)sysmocom.de>
1 0
0 0
[L] Change in libosmo-sigtran[master]: Split ss7_hmrt.c into mtp3_hm{dc,dt,rt}.c
by laforge 02 Dec '25

02 Dec '25
laforge has submitted this change. ( https://gerrit.osmocom.org/c/libosmo-sigtran/+/41521?usp=email ) Change subject: Split ss7_hmrt.c into mtp3_hm{dc,dt,rt}.c ...................................................................... Split ss7_hmrt.c into mtp3_hm{dc,dt,rt}.c ITU Q.704 (MTP level 3) spec clearly splits the functionality between subsystems/block, and they coordinate through specific events/messages. Let's split our current code base in different files to follow the module split, so it becomes a lot easier to match the spec and extend it with more blocks in the future. The new naming also clarifies this logic happens within the MTP layer3, which communicates with layer2 (MTP2, SCTP in M3UA, etc.) and layer 3 (eg. SCCP). Change-Id: I1b94c1474722b49ce29796681cfbcfce65c95388 --- M src/Makefile.am M src/ipa.c M src/m3ua.c A src/mtp3_hmdc.c A src/mtp3_hmdc.h A src/mtp3_hmdt.c A src/mtp3_hmdt.h A src/mtp3_hmrt.c A src/mtp3_hmrt.h M src/mtp_sap.c D src/ss7_hmrt.c M src/xua_internal.h 12 files changed, 358 insertions(+), 262 deletions(-) Approvals: Jenkins Builder: Verified laforge: Looks good to me, approved daniel: Looks good to me, but someone else must approve osmith: Looks good to me, but someone else must approve diff --git a/src/Makefile.am b/src/Makefile.am index de3d02e..29cf10a 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -3,6 +3,9 @@ $(LIBOSMONETIF_CFLAGS) noinst_HEADERS = \ + mtp3_hmdc.h \ + mtp3_hmdt.h \ + mtp3_hmrt.h \ sccp_connection.h \ sccp_scoc_fsm.h \ sccp_instance.h \ @@ -47,6 +50,9 @@ ipa.c \ m3ua.c \ mtp_sap.c \ + mtp3_hmdc.c \ + mtp3_hmdt.c \ + mtp3_hmrt.c \ sccp2sua.c \ sccp_connection.c \ sccp_helpers.c \ @@ -68,7 +74,6 @@ ss7_asp_vty.c \ ss7_asp_peer.c \ ss7_combined_linkset.c \ - ss7_hmrt.c \ ss7_instance.c \ ss7_link.c \ ss7_linkset.c \ diff --git a/src/ipa.c b/src/ipa.c index 2e74414..2083d09 100644 --- a/src/ipa.c +++ b/src/ipa.c @@ -37,7 +37,6 @@ //#include <osmocom/netif/stream.h> #include <osmocom/netif/ipa.h> -#include "xua_msg.h" #include <osmocom/sigtran/mtp_sap.h> #include <osmocom/sigtran/sccp_sap.h> @@ -46,11 +45,13 @@ #include <osmocom/sigtran/protocol/sua.h> #include <osmocom/sigtran/protocol/mtp.h> -#include "xua_internal.h" +#include "mtp3_hmdc.h" #include "ss7_as.h" #include "ss7_asp.h" #include "ss7_internal.h" #include "xua_asp_fsm.h" +#include "xua_internal.h" +#include "xua_msg.h" /* generate a msgb containing an IPA CCM PING message */ struct msgb *ipa_gen_ping(void) @@ -344,7 +345,7 @@ /* Pass on as if we had received it from an M3UA ASP. * xua ownership is passed here: */ - rc = m3ua_hmdc_rx_from_l2(asp->inst, xua); + rc = mtp3_hmdc_rx_from_l2(asp->inst, xua); return rc; } diff --git a/src/m3ua.c b/src/m3ua.c index 8e93515..36018e1 100644 --- a/src/m3ua.c +++ b/src/m3ua.c @@ -33,7 +33,6 @@ #include <osmocom/core/socket.h> #include <osmocom/netif/stream.h> -#include "xua_msg.h" #include <osmocom/sigtran/mtp_sap.h> #include <osmocom/sigtran/sccp_sap.h> @@ -41,12 +40,14 @@ #include <osmocom/sigtran/protocol/m3ua.h> #include <osmocom/sigtran/protocol/sua.h> +#include "mtp3_hmdc.h" #include "xua_as_fsm.h" #include "xua_asp_fsm.h" #include "xua_internal.h" #include "ss7_as.h" #include "ss7_asp.h" #include "ss7_internal.h" +#include "xua_msg.h" #define M3UA_MSGB_SIZE 1500 @@ -667,7 +668,7 @@ } /* xua ownership is passed here: */ - return m3ua_hmdc_rx_from_l2(asp->inst, xua); + return mtp3_hmdc_rx_from_l2(asp->inst, xua); ret_free: xua_msg_free(xua); diff --git a/src/mtp3_hmdc.c b/src/mtp3_hmdc.c new file mode 100644 index 0000000..68154a2 --- /dev/null +++ b/src/mtp3_hmdc.c @@ -0,0 +1,52 @@ +/*********************************************************************** + * MTP Level 3 - Message Discrimination (HMDC), ITU Q.704 Figure 24 + ***********************************************************************/ + +/* (C) 2015-2017 by Harald Welte <laforge(a)gnumonks.org> + * (C) 2025 by sysmocom s.f.m.c. GmbH <info(a)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/core/logging.h> + +#include "mtp3_hmdc.h" +#include "mtp3_hmdt.h" +#include "mtp3_hmrt.h" +#include "ss7_instance.h" +#include "xua_msg.h" + + +/* HMDC: Received Message L2 -> L3; Figure 24/Q.704 */ +/* This means a message was received from L2 and we have to decide if it + * is for the local stack (HMDT) or for routng (HMRT) + * Ownership of xua_msg passed is transferred to this function. */ +int mtp3_hmdc_rx_from_l2(struct osmo_ss7_instance *inst, struct xua_msg *xua) +{ + uint32_t dpc = xua->mtp.dpc; + if (osmo_ss7_pc_is_local(inst, dpc)) { + LOGSS7(inst, LOGL_DEBUG, "%s(): found dpc=%u=%s as local\n", + __func__, dpc, osmo_ss7_pointcode_print(inst, dpc)); + return mtp3_hmdt_message_for_distribution(inst, xua); + } + LOGSS7(inst, LOGL_DEBUG, "%s(): dpc=%u=%s not local, message is for routing\n", + __func__, dpc, osmo_ss7_pointcode_print(inst, dpc)); + return mtp3_hmrt_message_for_routing(inst, xua); +} diff --git a/src/mtp3_hmdc.h b/src/mtp3_hmdc.h new file mode 100644 index 0000000..9f882c5 --- /dev/null +++ b/src/mtp3_hmdc.h @@ -0,0 +1,6 @@ +#pragma once + +#include "ss7_instance.h" +#include "xua_msg.h" + +int mtp3_hmdc_rx_from_l2(struct osmo_ss7_instance *inst, struct xua_msg *xua); diff --git a/src/mtp3_hmdt.c b/src/mtp3_hmdt.c new file mode 100644 index 0000000..a6cf1b3 --- /dev/null +++ b/src/mtp3_hmdt.c @@ -0,0 +1,126 @@ +/*********************************************************************** + * MTP Level 3 - Message Distribution (HMDT), ITU Q.704 Figure 25 + ***********************************************************************/ + +/* (C) 2015-2017 by Harald Welte <laforge(a)gnumonks.org> + * (C) 2025 by sysmocom s.f.m.c. GmbH <info(a)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 <osmocom/sigtran/protocol/m3ua.h> +#include <osmocom/sigtran/mtp_sap.h> + +#include "ss7_instance.h" +#include "ss7_user.h" +#include "xua_internal.h" +#include "xua_msg.h" + + +/* convert from M3UA message to MTP-TRANSFER.ind osmo_mtp_prim */ +static struct osmo_mtp_prim *m3ua_to_xfer_ind(struct xua_msg *xua) +{ + struct xua_msg_part *data_ie = xua_msg_find_tag(xua, M3UA_IEI_PROT_DATA); + struct osmo_mtp_prim *prim; + struct m3ua_data_hdr *data_hdr; + + if (!data_ie || data_ie->len < sizeof(*data_hdr)) { + /* FIXME: ERROR message */ + return NULL; + } + data_hdr = (struct m3ua_data_hdr *) data_ie->dat; + + prim = mtp_prim_xfer_ind_alloc(NULL, + data_ie->dat + sizeof(*data_hdr), + data_ie->len - sizeof(*data_hdr)); + m3ua_dh_to_xfer_param(&prim->u.transfer, data_hdr); + + return prim; +} + +/* delivery given XUA message to given SS7 user + * Ownership of xua_msg passed is transferred to this function. + */ +static int deliver_to_mtp_user(const struct osmo_ss7_user *osu, struct xua_msg *xua) +{ + struct osmo_mtp_prim *prim; + int rc; + + /* Create MTP-TRANSFER.ind and feed to user */ + prim = m3ua_to_xfer_ind(xua); + if (!prim) { + rc = -1; + goto ret_free; + } + prim->u.transfer = xua->mtp; + + rc = ss7_user_mtp_sap_prim_up(osu, prim); + +ret_free: + xua_msg_free(xua); + return rc; +} + +/* HMDC -> HMDT: Message for distribution; Figure 25/Q.704 */ +/* This means it is a message we received from remote/L2, and it is to + * be routed to a local user part. + * Ownership of xua_msg passed is transferred to this function. + */ +int mtp3_hmdt_message_for_distribution(struct osmo_ss7_instance *inst, struct xua_msg *xua) +{ + struct m3ua_data_hdr *mdh; + const struct osmo_ss7_user *osu; + uint32_t service_ind; + + switch (xua->hdr.msg_class) { + case M3UA_MSGC_XFER: + switch (xua->hdr.msg_type) { + case M3UA_XFER_DATA: + mdh = data_hdr_from_m3ua(xua); + service_ind = mdh->si & 0xf; + break; + default: + LOGSS7(inst, LOGL_ERROR, "Unknown M3UA XFER Message Type %u\n", xua->hdr.msg_type); + xua_msg_free(xua); + return -1; + } + break; + case M3UA_MSGC_SNM: + /* FIXME */ + /* FIXME: SI = Signalling Network Management -> SRM/SLM/STM */ + /* FIXME: SI = Signalling Network Testing and Maintenance -> SLTC */ + default: + /* Discard Message */ + LOGSS7(inst, LOGL_ERROR, "Unknown M3UA Message Class %u\n", xua->hdr.msg_class); + xua_msg_free(xua); + return -1; + } + + /* "User Part Available?" */ + osu = osmo_ss7_user_find_by_si(inst, service_ind); + if (!osu) { + /* "Discard Message" */ + LOGSS7(inst, LOGL_NOTICE, "No MTP-User for SI %u\n", service_ind); + /* FIXME: User Part Unavailable HMDT -> HMRT */ + xua_msg_free(xua); + return -1; + } + + /* "MTP Transfer indication HMDT→L4" */ + return deliver_to_mtp_user(osu, xua); +} diff --git a/src/mtp3_hmdt.h b/src/mtp3_hmdt.h new file mode 100644 index 0000000..ab8854a --- /dev/null +++ b/src/mtp3_hmdt.h @@ -0,0 +1,6 @@ +#pragma once + +#include "ss7_instance.h" +#include "xua_msg.h" + +int mtp3_hmdt_message_for_distribution(struct osmo_ss7_instance *inst, struct xua_msg *xua); diff --git a/src/mtp3_hmrt.c b/src/mtp3_hmrt.c new file mode 100644 index 0000000..9ab7e33 --- /dev/null +++ b/src/mtp3_hmrt.c @@ -0,0 +1,140 @@ +/*********************************************************************** + * MTP Level 3 - Message Routing (HMRT), ITU Q.704 Figure 26 + ***********************************************************************/ + +/* (C) 2015-2017 by Harald Welte <laforge(a)gnumonks.org> + * (C) 2025 by sysmocom s.f.m.c. GmbH <info(a)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 <stdbool.h> +#include <string.h> +#include <errno.h> + +#include <arpa/inet.h> + +#include <osmocom/core/linuxlist.h> +#include <osmocom/core/logging.h> +#include <osmocom/sigtran/mtp_sap.h> +#include <osmocom/sigtran/osmo_ss7.h> +#include <osmocom/sigtran/protocol/m3ua.h> + +#include "mtp3_hmdc.h" +#include "xua_internal.h" +#include "ss7_as.h" +#include "ss7_asp.h" +#include "ss7_linkset.h" +#include "ss7_route.h" +#include "ss7_route_table.h" +#include "ss7_internal.h" +#include "ss7_user.h" + +/* HMDC->HMRT Msg For Routing; Figure 26/Q.704 */ +/* local message was receive d from L4, SRM, SLM, STM or SLTC, or + * remote message received from L2 and HMDC determined msg for routing + * Ownership of xua_msg passed is transferred to this function. + */ +int mtp3_hmrt_message_for_routing(struct osmo_ss7_instance *inst, struct xua_msg *xua) +{ + uint32_t dpc = xua->mtp.dpc; + struct osmo_ss7_route_label rtlabel = { + .opc = xua->mtp.opc, + .dpc = xua->mtp.dpc, + .sls = xua->mtp.sls, + }; + struct osmo_ss7_route *rt; + + /* find route for OPC+DPC+SLS: */ + /* FIXME: unify with gen_mtp_transfer_req_xua() */ + rt = ss7_instance_lookup_route(inst, &rtlabel); + if (rt) { + /* FIXME: DPC SP restart? */ + /* FIXME: DPC Congested? */ + /* FIXME: Select link based on SLS */ + /* FIXME: Transmit over respective Link */ + if (rt->dest.as) { + struct osmo_ss7_as *as = rt->dest.as; + + if (log_check_level(DLSS7, LOGL_DEBUG)) { + /* osmo_ss7_route_name() calls osmo_ss7_pointcode_print() and + * osmo_ss7_pointcode_print2(), guard against its static buffer being + * overwritten. */ + const char *rt_name = osmo_ss7_route_name(rt, false); + LOGSS7(inst, LOGL_DEBUG, "Found route for dpc=%u=%s: %s\n", + dpc, osmo_ss7_pointcode_print(inst, dpc), rt_name); + } + + rate_ctr_inc2(as->ctrg, SS7_AS_CTR_TX_MSU_TOTAL); + OSMO_ASSERT(xua->mtp.sls <= 0xf); + rate_ctr_inc2(as->ctrg, SS7_AS_CTR_TX_MSU_SLS_0 + xua->mtp.sls); + + switch (as->cfg.proto) { + case OSMO_SS7_ASP_PROT_M3UA: + LOGSS7(inst, LOGL_DEBUG, "rt->dest.as proto is M3UA for dpc=%u=%s\n", + dpc, osmo_ss7_pointcode_print(inst, dpc)); + return m3ua_tx_xua_as(as, xua); + case OSMO_SS7_ASP_PROT_IPA: + return ipa_tx_xua_as(as, xua); + default: + LOGSS7(inst, LOGL_ERROR, "MTP message for ASP of unknown protocol %u\n", + as->cfg.proto); + break; + } + } else if (rt->dest.linkset) { + if (log_check_level(DLSS7, LOGL_ERROR)) { + /* osmo_ss7_route_name() calls osmo_ss7_pointcode_print() and + * osmo_ss7_pointcode_print2(), guard against its static buffer being + * overwritten. */ + const char *rt_name = osmo_ss7_route_name(rt, false); + LOGSS7(inst, LOGL_ERROR, + "Found route for dpc=%u=%s: %s, but MTP-TRANSFER.req unsupported for linkset.\n", + dpc, osmo_ss7_pointcode_print(inst, dpc), rt_name); + } + } else + OSMO_ASSERT(0); + } 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 */ + /* Discard Message */ + } + xua_msg_free(xua); + return -1; +} + +/* Figure 26/Q.704 (sheet 1 of 5) "MTP Transfer request L4→L3" */ +int mtp3_hmrt_mtp_xfer_request_l4_to_l3(struct osmo_ss7_instance *inst, const struct osmo_mtp_transfer_param *param, uint8_t *user_data, size_t user_data_len) +{ + struct m3ua_data_hdr data_hdr; + struct xua_msg *xua; + + /* convert from osmo_mtp_prim MTP-TRANSFER.req to xua_msg */ + mtp_xfer_param_to_m3ua_dh(&data_hdr, param); + xua = m3ua_xfer_from_data(&data_hdr, user_data, user_data_len); + OSMO_ASSERT(xua); + xua->mtp = *param; + + /* normally we would call mtp3_hmrt_message_for_routing() here, if we were to follow the state + * diagrams of the ITU-T Q.70x specifications. However, what if a local MTP user sends a + * MTP-TRANSFER.req to a local SSN? This wouldn't work as per the spec, but I believe it + * is a very useful feature (aka "loopback device" in IPv4). So we call + * mtp3_hmdc_rx_from_l2() just like the MTP-TRANSFER had been received from L2. */ + return mtp3_hmdc_rx_from_l2(inst, xua); +} diff --git a/src/mtp3_hmrt.h b/src/mtp3_hmrt.h new file mode 100644 index 0000000..4e51570 --- /dev/null +++ b/src/mtp3_hmrt.h @@ -0,0 +1,12 @@ +#pragma once + +#include <stdint.h> +#include <unistd.h> + +#include <osmocom/sigtran/mtp_sap.h> + +#include "ss7_instance.h" +#include "xua_msg.h" + +int mtp3_hmrt_mtp_xfer_request_l4_to_l3(struct osmo_ss7_instance *inst, const struct osmo_mtp_transfer_param *param, uint8_t *user_data, size_t user_data_len); +int mtp3_hmrt_message_for_routing(struct osmo_ss7_instance *inst, struct xua_msg *xua); diff --git a/src/mtp_sap.c b/src/mtp_sap.c index 8c21f53..69838dd 100644 --- a/src/mtp_sap.c +++ b/src/mtp_sap.c @@ -27,6 +27,7 @@ #include <osmocom/sigtran/osmo_ss7.h> #include <osmocom/sigtran/mtp_sap.h> +#include "mtp3_hmrt.h" #include "ss7_user.h" #include "ss7_internal.h" #include "xua_internal.h" @@ -220,8 +221,8 @@ switch (OSMO_PRIM_HDR(&omp->oph)) { case OSMO_PRIM(OSMO_MTP_PRIM_TRANSFER, PRIM_OP_REQUEST): - rc = hmrt_mtp_xfer_request_l4_to_l3(osu->inst, &omp->u.transfer, - msgb_l2(msg), msgb_l2len(msg)); + rc = mtp3_hmrt_mtp_xfer_request_l4_to_l3(osu->inst, &omp->u.transfer, + msgb_l2(msg), msgb_l2len(msg)); break; default: LOGPSS7U(osu, LOGL_ERROR, "Ignoring unknown primitive %u:%u\n", diff --git a/src/ss7_hmrt.c b/src/ss7_hmrt.c deleted file mode 100644 index 72b26d8..0000000 --- a/src/ss7_hmrt.c +++ /dev/null @@ -1,250 +0,0 @@ -/*********************************************************************** - * MTP Level 3 - Signalling message handling (SMH) Figure 23/Q.704 - ***********************************************************************/ - -/* (C) 2015-2017 by Harald Welte <laforge(a)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 <stdbool.h> -#include <string.h> -#include <errno.h> - -#include <arpa/inet.h> - -#include <osmocom/core/linuxlist.h> -#include <osmocom/core/logging.h> -#include <osmocom/sigtran/mtp_sap.h> -#include <osmocom/sigtran/osmo_ss7.h> -#include <osmocom/sigtran/protocol/m3ua.h> - -#include "xua_internal.h" -#include "ss7_as.h" -#include "ss7_asp.h" -#include "ss7_linkset.h" -#include "ss7_route.h" -#include "ss7_route_table.h" -#include "ss7_internal.h" -#include "ss7_user.h" - -/* convert from M3UA message to MTP-TRANSFER.ind osmo_mtp_prim */ -static struct osmo_mtp_prim *m3ua_to_xfer_ind(struct xua_msg *xua) -{ - struct xua_msg_part *data_ie = xua_msg_find_tag(xua, M3UA_IEI_PROT_DATA); - struct osmo_mtp_prim *prim; - struct m3ua_data_hdr *data_hdr; - - if (!data_ie || data_ie->len < sizeof(*data_hdr)) { - /* FIXME: ERROR message */ - return NULL; - } - data_hdr = (struct m3ua_data_hdr *) data_ie->dat; - - prim = mtp_prim_xfer_ind_alloc(NULL, - data_ie->dat + sizeof(*data_hdr), - data_ie->len - sizeof(*data_hdr)); - m3ua_dh_to_xfer_param(&prim->u.transfer, data_hdr); - - return prim; -} - -/* delivery given XUA message to given SS7 user - * Ownership of xua_msg passed is transferred to this function. - */ -static int deliver_to_mtp_user(const struct osmo_ss7_user *osu, struct xua_msg *xua) -{ - struct osmo_mtp_prim *prim; - int rc; - - /* Create MTP-TRANSFER.ind and feed to user */ - prim = m3ua_to_xfer_ind(xua); - if (!prim) { - rc = -1; - goto ret_free; - } - prim->u.transfer = xua->mtp; - - rc = ss7_user_mtp_sap_prim_up(osu, prim); - -ret_free: - xua_msg_free(xua); - return rc; -} - -/* HMDC -> HMDT: Message for distribution; Figure 25/Q.704 */ -/* This means it is a message we received from remote/L2, and it is to - * be routed to a local user part. - * Ownership of xua_msg passed is transferred to this function. - */ -static int hmdt_message_for_distribution(struct osmo_ss7_instance *inst, struct xua_msg *xua) -{ - struct m3ua_data_hdr *mdh; - const struct osmo_ss7_user *osu; - uint32_t service_ind; - - switch (xua->hdr.msg_class) { - case M3UA_MSGC_XFER: - switch (xua->hdr.msg_type) { - case M3UA_XFER_DATA: - mdh = data_hdr_from_m3ua(xua); - service_ind = mdh->si & 0xf; - break; - default: - LOGSS7(inst, LOGL_ERROR, "Unknown M3UA XFER Message Type %u\n", xua->hdr.msg_type); - xua_msg_free(xua); - return -1; - } - break; - case M3UA_MSGC_SNM: - /* FIXME */ - /* FIXME: SI = Signalling Network Management -> SRM/SLM/STM */ - /* FIXME: SI = Signalling Network Testing and Maintenance -> SLTC */ - default: - /* Discard Message */ - LOGSS7(inst, LOGL_ERROR, "Unknown M3UA Message Class %u\n", xua->hdr.msg_class); - xua_msg_free(xua); - return -1; - } - - /* "User Part Available?" */ - osu = osmo_ss7_user_find_by_si(inst, service_ind); - if (!osu) { - /* "Discard Message" */ - LOGSS7(inst, LOGL_NOTICE, "No MTP-User for SI %u\n", service_ind); - /* FIXME: User Part Unavailable HMDT -> HMRT */ - xua_msg_free(xua); - return -1; - } - - /* "MTP Transfer indication HMDT→L4" */ - return deliver_to_mtp_user(osu, xua); -} - -/* HMDC->HMRT Msg For Routing; Figure 26/Q.704 */ -/* local message was receive d from L4, SRM, SLM, STM or SLTC, or - * remote message received from L2 and HMDC determined msg for routing - * Ownership of xua_msg passed is transferred to this function. - */ -static int hmrt_message_for_routing(struct osmo_ss7_instance *inst, - struct xua_msg *xua) -{ - uint32_t dpc = xua->mtp.dpc; - struct osmo_ss7_route_label rtlabel = { - .opc = xua->mtp.opc, - .dpc = xua->mtp.dpc, - .sls = xua->mtp.sls, - }; - struct osmo_ss7_route *rt; - - /* find route for OPC+DPC+SLS: */ - /* FIXME: unify with gen_mtp_transfer_req_xua() */ - rt = ss7_instance_lookup_route(inst, &rtlabel); - if (rt) { - /* FIXME: DPC SP restart? */ - /* FIXME: DPC Congested? */ - /* FIXME: Select link based on SLS */ - /* FIXME: Transmit over respective Link */ - if (rt->dest.as) { - struct osmo_ss7_as *as = rt->dest.as; - - if (log_check_level(DLSS7, LOGL_DEBUG)) { - /* osmo_ss7_route_name() calls osmo_ss7_pointcode_print() and - * osmo_ss7_pointcode_print2(), guard against its static buffer being - * overwritten. */ - const char *rt_name = osmo_ss7_route_name(rt, false); - LOGSS7(inst, LOGL_DEBUG, "Found route for dpc=%u=%s: %s\n", - dpc, osmo_ss7_pointcode_print(inst, dpc), rt_name); - } - - rate_ctr_inc2(as->ctrg, SS7_AS_CTR_TX_MSU_TOTAL); - OSMO_ASSERT(xua->mtp.sls <= 0xf); - rate_ctr_inc2(as->ctrg, SS7_AS_CTR_TX_MSU_SLS_0 + xua->mtp.sls); - - switch (as->cfg.proto) { - case OSMO_SS7_ASP_PROT_M3UA: - LOGSS7(inst, LOGL_DEBUG, "rt->dest.as proto is M3UA for dpc=%u=%s\n", - dpc, osmo_ss7_pointcode_print(inst, dpc)); - return m3ua_tx_xua_as(as, xua); - case OSMO_SS7_ASP_PROT_IPA: - return ipa_tx_xua_as(as, xua); - default: - LOGSS7(inst, LOGL_ERROR, "MTP message for ASP of unknown protocol %u\n", - as->cfg.proto); - break; - } - } else if (rt->dest.linkset) { - if (log_check_level(DLSS7, LOGL_ERROR)) { - /* osmo_ss7_route_name() calls osmo_ss7_pointcode_print() and - * osmo_ss7_pointcode_print2(), guard against its static buffer being - * overwritten. */ - const char *rt_name = osmo_ss7_route_name(rt, false); - LOGSS7(inst, LOGL_ERROR, - "Found route for dpc=%u=%s: %s, but MTP-TRANSFER.req unsupported for linkset.\n", - dpc, osmo_ss7_pointcode_print(inst, dpc), rt_name); - } - } else - OSMO_ASSERT(0); - } 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 */ - /* Discard Message */ - } - xua_msg_free(xua); - return -1; -} - -/* HMDC: Received Message L2 -> L3; Figure 24/Q.704 */ -/* This means a message was received from L2 and we have to decide if it - * is for the local stack (HMDT) or for routng (HMRT) - * Ownership of xua_msg passed is transferred to this function. */ -int m3ua_hmdc_rx_from_l2(struct osmo_ss7_instance *inst, struct xua_msg *xua) -{ - uint32_t dpc = xua->mtp.dpc; - if (osmo_ss7_pc_is_local(inst, dpc)) { - LOGSS7(inst, LOGL_DEBUG, "%s(): found dpc=%u=%s as local\n", - __func__, dpc, osmo_ss7_pointcode_print(inst, dpc)); - return hmdt_message_for_distribution(inst, xua); - } else { - LOGSS7(inst, LOGL_DEBUG, "%s(): dpc=%u=%s not local, message is for routing\n", - __func__, dpc, osmo_ss7_pointcode_print(inst, dpc)); - return hmrt_message_for_routing(inst, xua); - } -} - -/* Figure 26/Q.704 (sheet 1 of 5) "MTP Transfer request L4→L3" */ -int hmrt_mtp_xfer_request_l4_to_l3(struct osmo_ss7_instance *inst, const struct osmo_mtp_transfer_param *param, uint8_t *user_data, size_t user_data_len) -{ - struct m3ua_data_hdr data_hdr; - struct xua_msg *xua; - - /* convert from osmo_mtp_prim MTP-TRANSFER.req to xua_msg */ - mtp_xfer_param_to_m3ua_dh(&data_hdr, param); - xua = m3ua_xfer_from_data(&data_hdr, user_data, user_data_len); - OSMO_ASSERT(xua); - xua->mtp = *param; - - /* normally we would call hmrt_message_for_routing() here, if we were to follow the state - * diagrams of the ITU-T Q.70x specifications. However, what if a local MTP user sends a - * MTP-TRANSFER.req to a local SSN? This wouldn't work as per the spec, but I believe it - * is a very useful feature (aka "loopback device" in IPv4). So we call - * m3ua_hmdc_rx_from_l2() just like the MTP-TRANSFER had been received from L2. */ - return m3ua_hmdc_rx_from_l2(inst, xua); -} diff --git a/src/xua_internal.h b/src/xua_internal.h index 54172ff..a1023c1 100644 --- a/src/xua_internal.h +++ b/src/xua_internal.h @@ -39,7 +39,6 @@ struct xua_msg *sua_gen_cldr(const struct xua_msg *xua_in, uint32_t route_ctx, uint32_t ret_cause); -int m3ua_hmdc_rx_from_l2(struct osmo_ss7_instance *inst, struct xua_msg *xua); struct msgb *m3ua_to_msg(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, @@ -73,9 +72,6 @@ const struct m3ua_data_hdr *mdh); void mtp_xfer_param_to_m3ua_dh(struct m3ua_data_hdr *mdh, const struct osmo_mtp_transfer_param *param); -int hmrt_mtp_xfer_request_l4_to_l3(struct osmo_ss7_instance *inst, - const struct osmo_mtp_transfer_param *param, - uint8_t *user_data, size_t user_data_len); extern const struct xua_msg_class m3ua_msg_class_mgmt; -- To view, visit https://gerrit.osmocom.org/c/libosmo-sigtran/+/41521?usp=email To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings?usp=email Gerrit-MessageType: merged Gerrit-Project: libosmo-sigtran Gerrit-Branch: master Gerrit-Change-Id: I1b94c1474722b49ce29796681cfbcfce65c95388 Gerrit-Change-Number: 41521 Gerrit-PatchSet: 1 Gerrit-Owner: pespin <pespin(a)sysmocom.de> Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: daniel <dwillmann(a)sysmocom.de> Gerrit-Reviewer: fixeria <vyanitskiy(a)sysmocom.de> Gerrit-Reviewer: laforge <laforge(a)osmocom.org> Gerrit-Reviewer: osmith <osmith(a)sysmocom.de>
1 0
0 0
[M] Change in libosmo-sigtran[master]: Implement ITU Q.704 timer T8
by laforge 02 Dec '25

02 Dec '25
Attention is currently required from: daniel, fixeria, pespin. laforge has posted comments on this change by pespin. ( https://gerrit.osmocom.org/c/libosmo-sigtran/+/41526?usp=email ) Change subject: Implement ITU Q.704 timer T8 ...................................................................... Patch Set 3: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/c/libosmo-sigtran/+/41526?usp=email To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings?usp=email Gerrit-MessageType: comment Gerrit-Project: libosmo-sigtran Gerrit-Branch: master Gerrit-Change-Id: I27ebf7327448554a6e4600e45a4ab0343ab846a4 Gerrit-Change-Number: 41526 Gerrit-PatchSet: 3 Gerrit-Owner: pespin <pespin(a)sysmocom.de> Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: daniel <dwillmann(a)sysmocom.de> Gerrit-Reviewer: fixeria <vyanitskiy(a)sysmocom.de> Gerrit-Reviewer: laforge <laforge(a)osmocom.org> Gerrit-Reviewer: osmith <osmith(a)sysmocom.de> Gerrit-Attention: pespin <pespin(a)sysmocom.de> Gerrit-Attention: fixeria <vyanitskiy(a)sysmocom.de> Gerrit-Attention: daniel <dwillmann(a)sysmocom.de> Gerrit-Comment-Date: Tue, 02 Dec 2025 09:27:51 +0000 Gerrit-HasComments: No Gerrit-Has-Labels: Yes
1 0
0 0
[M] Change in libosmo-sigtran[master]: mtp3: Implement RTPC transfer prohibited to concerned SP or STP
by laforge 02 Dec '25

02 Dec '25
Attention is currently required from: fixeria, pespin. laforge has posted comments on this change by pespin. ( https://gerrit.osmocom.org/c/libosmo-sigtran/+/41524?usp=email ) Change subject: mtp3: Implement RTPC transfer prohibited to concerned SP or STP ...................................................................... Patch Set 2: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/c/libosmo-sigtran/+/41524?usp=email To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings?usp=email Gerrit-MessageType: comment Gerrit-Project: libosmo-sigtran Gerrit-Branch: master Gerrit-Change-Id: I7e89db3d82374ca03a2e71fb558c7cec9bd651c4 Gerrit-Change-Number: 41524 Gerrit-PatchSet: 2 Gerrit-Owner: pespin <pespin(a)sysmocom.de> Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: daniel <dwillmann(a)sysmocom.de> Gerrit-Reviewer: fixeria <vyanitskiy(a)sysmocom.de> Gerrit-Reviewer: laforge <laforge(a)osmocom.org> Gerrit-Reviewer: osmith <osmith(a)sysmocom.de> Gerrit-Attention: pespin <pespin(a)sysmocom.de> Gerrit-Attention: fixeria <vyanitskiy(a)sysmocom.de> Gerrit-Comment-Date: Tue, 02 Dec 2025 09:26:58 +0000 Gerrit-HasComments: No Gerrit-Has-Labels: Yes
1 0
0 0
[L] Change in libosmo-sigtran[master]: Split ss7_hmrt.c into mtp3_hm{dc,dt,rt}.c
by laforge 02 Dec '25

02 Dec '25
Attention is currently required from: fixeria, pespin. laforge has posted comments on this change by pespin. ( https://gerrit.osmocom.org/c/libosmo-sigtran/+/41521?usp=email ) Change subject: Split ss7_hmrt.c into mtp3_hm{dc,dt,rt}.c ...................................................................... Patch Set 1: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/c/libosmo-sigtran/+/41521?usp=email To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings?usp=email Gerrit-MessageType: comment Gerrit-Project: libosmo-sigtran Gerrit-Branch: master Gerrit-Change-Id: I1b94c1474722b49ce29796681cfbcfce65c95388 Gerrit-Change-Number: 41521 Gerrit-PatchSet: 1 Gerrit-Owner: pespin <pespin(a)sysmocom.de> Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: daniel <dwillmann(a)sysmocom.de> Gerrit-Reviewer: fixeria <vyanitskiy(a)sysmocom.de> Gerrit-Reviewer: laforge <laforge(a)osmocom.org> Gerrit-Reviewer: osmith <osmith(a)sysmocom.de> Gerrit-Attention: pespin <pespin(a)sysmocom.de> Gerrit-Attention: fixeria <vyanitskiy(a)sysmocom.de> Gerrit-Comment-Date: Tue, 02 Dec 2025 09:25:30 +0000 Gerrit-HasComments: No Gerrit-Has-Labels: Yes
1 0
0 0
[XS] Change in ...osmo-s1gw[master]: config/sys.config: document available sockopts
by fixeria 02 Dec '25

02 Dec '25
fixeria has submitted this change. ( https://gerrit.osmocom.org/c/erlang/osmo-s1gw/+/41532?usp=email ) Change subject: config/sys.config: document available sockopts ...................................................................... config/sys.config: document available sockopts Change-Id: Ie6b62839ec1634078b292cdd7e0f2a481ebd83fc Related: SYS#7653 --- M config/sys.config 1 file changed, 4 insertions(+), 4 deletions(-) Approvals: Jenkins Builder: Verified pespin: Looks good to me, but someone else must approve laforge: Looks good to me, approved jolly: Looks good to me, but someone else must approve diff --git a/config/sys.config b/config/sys.config index f17dd13..3c8f0f3 100644 --- a/config/sys.config +++ b/config/sys.config @@ -10,8 +10,9 @@ laddr => "127.0.1.1", %% local (bind) port for incoming eNB connections lport => 36412, - %% socket options (recbuf, sndbuf, nodelay) - %% if omitted or left empty, defaults apply + %% socket options (if omitted or left empty, defaults apply) + %% * recbuf/sndbuf - Rx/Rx buffer size (default: 65536) + %% * nodelay - enable (false) / disable (true) the Naggle (default: true) sockopts => #{ } }}, %% SCTP client configuration @@ -22,8 +23,7 @@ raddr => "127.0.2.10", %% remote port for outgoing connections to the MME rport => 36412, - %% socket options (recbuf, sndbuf, nodelay) - %% if omitted or left empty, defaults apply + %% socket options (if omitted or left empty, defaults apply) - see above sockopts => #{ } }}, {pfcp_loc_addr, "127.0.1.1"}, %% local address for incoming PFCP PDUs from the UPF -- To view, visit https://gerrit.osmocom.org/c/erlang/osmo-s1gw/+/41532?usp=email To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings?usp=email Gerrit-MessageType: merged Gerrit-Project: erlang/osmo-s1gw Gerrit-Branch: master Gerrit-Change-Id: Ie6b62839ec1634078b292cdd7e0f2a481ebd83fc Gerrit-Change-Number: 41532 Gerrit-PatchSet: 1 Gerrit-Owner: fixeria <vyanitskiy(a)sysmocom.de> Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: fixeria <vyanitskiy(a)sysmocom.de> Gerrit-Reviewer: jolly <andreas(a)eversberg.eu> Gerrit-Reviewer: laforge <laforge(a)osmocom.org> Gerrit-Reviewer: pespin <pespin(a)sysmocom.de>
1 0
0 0
[M] Change in ...osmo-s1gw[master]: config/sys.config: group sctp_{client,server} params into maps
by fixeria 02 Dec '25

02 Dec '25
fixeria has submitted this change. ( https://gerrit.osmocom.org/c/erlang/osmo-s1gw/+/41530?usp=email ) Change subject: config/sys.config: group sctp_{client,server} params into maps ...................................................................... config/sys.config: group sctp_{client,server} params into maps A follow-up patch brings even more SCTP SockOpts related params. Let's prepare for this by grouping the existing sctp_{client,server} related variables into distinct maps and moving the socket options into their own sub-map. Keep support for legacy options, for the sake of backwards compatibility. This helps to avoid having two instances of each new parameter (s1gw_ and mme_) and generally improves readability/editability of the config file. Change-Id: Ib573915fdeb3ce73a1f6110c19fd6b1d46e68a03 Related: SYS#7653 --- M config/sys.config M src/osmo_s1gw_sup.erl M src/sctp_common.erl 3 files changed, 67 insertions(+), 26 deletions(-) Approvals: laforge: Looks good to me, approved pespin: Looks good to me, but someone else must approve jolly: Looks good to me, but someone else must approve Jenkins Builder: Verified diff --git a/config/sys.config b/config/sys.config index 9ad1ca2..f17dd13 100644 --- a/config/sys.config +++ b/config/sys.config @@ -2,18 +2,30 @@ [%% ================================================================================ %% application config - %% - %% eNB S1GW - %% +-----+ +----------------+ - %% | ... | --> | s1gw_bind_addr | MME - %% +-----+ +----------------+ +-----------------+ - %% | mme_loc_addr | --> | mme_rem_addr | - %% +----------------+ +-----------------+ %% ================================================================================ - {osmo_s1gw, - [{s1gw_bind_addr, "127.0.1.1"}, %% S1GW bind address for incoming eNB connections - {mme_loc_addr, "127.0.2.1"}, %% local address for outgoing connections to the MME - {mme_rem_addr, "127.0.2.10"}, %% remote address for outgoing connections to the MME + {osmo_s1gw, [ + %% SCTP server configuration + {sctp_server, #{ + %% local (bind) address for incoming eNB connections + laddr => "127.0.1.1", + %% local (bind) port for incoming eNB connections + lport => 36412, + %% socket options (recbuf, sndbuf, nodelay) + %% if omitted or left empty, defaults apply + sockopts => #{ } + }}, + %% SCTP client configuration + {sctp_client, #{ + %% local (bind) address for outgoing connections to the MME + laddr => "127.0.2.1", + %% remote address for outgoing connections to the MME + raddr => "127.0.2.10", + %% remote port for outgoing connections to the MME + rport => 36412, + %% socket options (recbuf, sndbuf, nodelay) + %% if omitted or left empty, defaults apply + sockopts => #{ } + }}, {pfcp_loc_addr, "127.0.1.1"}, %% local address for incoming PFCP PDUs from the UPF {pfcp_rem_addr, "127.0.1.2"} %% remote address for outgoing PFCP PDUs to the UPF %% Optional PFCP Network Instance IEs (omitted if not configured) diff --git a/src/osmo_s1gw_sup.erl b/src/osmo_s1gw_sup.erl index 1616fe5..bde7b54 100644 --- a/src/osmo_s1gw_sup.erl +++ b/src/osmo_s1gw_sup.erl @@ -41,8 +41,6 @@ -include("s1ap.hrl"). -define(SERVER, ?MODULE). --define(ENV_DEFAULT_SCTP_BUFSZ, 65536). --define(ENV_DEFAULT_SCTP_NODELAY, true). -define(ENV_DEFAULT_S1GW_BIND_ADDR, "127.0.1.1"). -define(ENV_DEFAULT_S1GW_BIND_PORT, ?S1AP_PORT). -define(ENV_DEFAULT_MME_LOC_ADDR, "127.0.2.1"). @@ -103,26 +101,44 @@ %% private API %% ------------------------------------------------------------------ +-spec parse_env_map(map()) -> map(). +parse_env_map(M0) -> + M1 = maps:map(fun(_, P) -> osmo_s1gw:get_env(P, undefined) end, M0), + maps:filter(fun(_, V) -> V =/= undefined end, M1). + -spec client_cfg() -> sctp_client:cfg(). client_cfg() -> - SockOpts = #{sctp_nodelay => osmo_s1gw:get_env(mme_nodelay, ?ENV_DEFAULT_SCTP_NODELAY), - recbuf => osmo_s1gw:get_env(mme_recbuf, ?ENV_DEFAULT_SCTP_BUFSZ), - sndbuf => osmo_s1gw:get_env(mme_sndbuf, ?ENV_DEFAULT_SCTP_BUFSZ)}, - #{laddr => osmo_s1gw:get_env(mme_loc_addr, ?ENV_DEFAULT_MME_LOC_ADDR), - raddr => osmo_s1gw:get_env(mme_rem_addr, ?ENV_DEFAULT_MME_REM_ADDR), - rport => osmo_s1gw:get_env(mme_rem_port, ?ENV_DEFAULT_MME_REM_PORT), - sockopts => maps:to_list(SockOpts)}. + %% parse old/legacy environment options, if any + OldCfg = parse_env_map(#{laddr => mme_loc_addr, + raddr => mme_rem_addr, + rport => mme_rem_port}), + OldSockOpts = parse_env_map(#{nodelay => mme_nodelay, + recbuf => mme_recbuf, + sndbuf => mme_sndbuf}), + %% parse the new sctp_client configuration block + Cfg = maps:merge(OldCfg, osmo_s1gw:get_env(sctp_client, #{ })), + SockOpts = maps:merge(OldSockOpts, maps:get(sockopts, Cfg, #{ })), + #{laddr => maps:get(laddr, Cfg, ?ENV_DEFAULT_MME_LOC_ADDR), + raddr => maps:get(raddr, Cfg, ?ENV_DEFAULT_MME_REM_ADDR), + rport => maps:get(rport, Cfg, ?ENV_DEFAULT_MME_REM_PORT), + sockopts => sctp_common:gen_sockopts(SockOpts)}. -spec server_cfg() -> sctp_server:cfg(). server_cfg() -> - SockOpts = #{sctp_nodelay => osmo_s1gw:get_env(s1gw_nodelay, ?ENV_DEFAULT_SCTP_NODELAY), - recbuf => osmo_s1gw:get_env(s1gw_recbuf, ?ENV_DEFAULT_SCTP_BUFSZ), - sndbuf => osmo_s1gw:get_env(s1gw_sndbuf, ?ENV_DEFAULT_SCTP_BUFSZ)}, - #{laddr => osmo_s1gw:get_env(s1gw_bind_addr, ?ENV_DEFAULT_S1GW_BIND_ADDR), - lport => osmo_s1gw:get_env(s1gw_bind_port, ?ENV_DEFAULT_S1GW_BIND_PORT), - sockopts => maps:to_list(SockOpts), + %% parse old/legacy environment options, if any + DefCfg = parse_env_map(#{laddr => s1gw_bind_addr, + lport => s1gw_bind_port}), + DefSockOpts = parse_env_map(#{nodelay => s1gw_nodelay, + recbuf => s1gw_recbuf, + sndbuf => s1gw_sndbuf}), + %% parse the new sctp_server configuration block + Cfg = maps:merge(DefCfg, osmo_s1gw:get_env(sctp_server, #{ })), + SockOpts = maps:merge(DefSockOpts, maps:get(sockopts, Cfg, #{ })), + #{laddr => maps:get(laddr, Cfg, ?ENV_DEFAULT_S1GW_BIND_ADDR), + lport => maps:get(lport, Cfg, ?ENV_DEFAULT_S1GW_BIND_PORT), + sockopts => sctp_common:gen_sockopts(SockOpts), handler => sctp_proxy, priv => client_cfg()}. diff --git a/src/sctp_common.erl b/src/sctp_common.erl index 9b86b50..9a57798 100644 --- a/src/sctp_common.erl +++ b/src/sctp_common.erl @@ -36,6 +36,7 @@ -export([parse_addr/1, report_error/1, + gen_sockopts/1, send_data/2, shutdown/1]). @@ -46,6 +47,10 @@ -include("s1ap.hrl"). +-define(SOCKOPTS_DEFAULT_BUFSZ, 65536). +-define(SOCKOPTS_DEFAULT_NODELAY, true). + + -type sock_aid() :: {gen_sctp:sctp_socket(), gen_sctp:assoc_id()}. @@ -84,6 +89,14 @@ end. +-spec gen_sockopts(map()) -> [gen_sctp:option()]. +gen_sockopts(SockOptsCfg) -> + SockOpts = #{recbuf => maps:get(recbuf, SockOptsCfg, ?SOCKOPTS_DEFAULT_BUFSZ), + sndbuf => maps:get(sndbuf, SockOptsCfg, ?SOCKOPTS_DEFAULT_BUFSZ), + sctp_nodelay => maps:get(nodelay, SockOptsCfg, ?SOCKOPTS_DEFAULT_NODELAY)}, + maps:to_list(SockOpts). + + -spec send_data(sock_aid(), binary()) -> ok | {error, term()}. send_data({Sock, Aid}, Data) -> gen_sctp:send(Sock, #sctp_sndrcvinfo{stream = ?S1AP_SCTP_STREAM, -- To view, visit https://gerrit.osmocom.org/c/erlang/osmo-s1gw/+/41530?usp=email To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings?usp=email Gerrit-MessageType: merged Gerrit-Project: erlang/osmo-s1gw Gerrit-Branch: master Gerrit-Change-Id: Ib573915fdeb3ce73a1f6110c19fd6b1d46e68a03 Gerrit-Change-Number: 41530 Gerrit-PatchSet: 1 Gerrit-Owner: fixeria <vyanitskiy(a)sysmocom.de> Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: fixeria <vyanitskiy(a)sysmocom.de> Gerrit-Reviewer: jolly <andreas(a)eversberg.eu> Gerrit-Reviewer: laforge <laforge(a)osmocom.org> Gerrit-Reviewer: pespin <pespin(a)sysmocom.de>
1 0
0 0
[XS] Change in ...osmo-s1gw[master]: config/sys.config: document available sockopts
by laforge 02 Dec '25

02 Dec '25
Attention is currently required from: fixeria. laforge has posted comments on this change by fixeria. ( https://gerrit.osmocom.org/c/erlang/osmo-s1gw/+/41532?usp=email ) Change subject: config/sys.config: document available sockopts ...................................................................... Patch Set 1: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/c/erlang/osmo-s1gw/+/41532?usp=email To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings?usp=email Gerrit-MessageType: comment Gerrit-Project: erlang/osmo-s1gw Gerrit-Branch: master Gerrit-Change-Id: Ie6b62839ec1634078b292cdd7e0f2a481ebd83fc Gerrit-Change-Number: 41532 Gerrit-PatchSet: 1 Gerrit-Owner: fixeria <vyanitskiy(a)sysmocom.de> Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: jolly <andreas(a)eversberg.eu> Gerrit-Reviewer: laforge <laforge(a)osmocom.org> Gerrit-Reviewer: pespin <pespin(a)sysmocom.de> Gerrit-Attention: fixeria <vyanitskiy(a)sysmocom.de> Gerrit-Comment-Date: Tue, 02 Dec 2025 09:21:15 +0000 Gerrit-HasComments: No Gerrit-Has-Labels: Yes
1 0
0 0
[M] Change in ...osmo-s1gw[master]: config/sys.config: group sctp_{client,server} params into maps
by laforge 02 Dec '25

02 Dec '25
Attention is currently required from: fixeria. laforge has posted comments on this change by fixeria. ( https://gerrit.osmocom.org/c/erlang/osmo-s1gw/+/41530?usp=email ) Change subject: config/sys.config: group sctp_{client,server} params into maps ...................................................................... Patch Set 1: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/c/erlang/osmo-s1gw/+/41530?usp=email To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings?usp=email Gerrit-MessageType: comment Gerrit-Project: erlang/osmo-s1gw Gerrit-Branch: master Gerrit-Change-Id: Ib573915fdeb3ce73a1f6110c19fd6b1d46e68a03 Gerrit-Change-Number: 41530 Gerrit-PatchSet: 1 Gerrit-Owner: fixeria <vyanitskiy(a)sysmocom.de> Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: jolly <andreas(a)eversberg.eu> Gerrit-Reviewer: laforge <laforge(a)osmocom.org> Gerrit-Reviewer: pespin <pespin(a)sysmocom.de> Gerrit-Attention: fixeria <vyanitskiy(a)sysmocom.de> Gerrit-Comment-Date: Tue, 02 Dec 2025 09:21:07 +0000 Gerrit-HasComments: No Gerrit-Has-Labels: Yes
1 0
0 0
[M] Change in libosmo-sigtran[master]: Use DLTCAP for TCAP log messages
by pespin 02 Dec '25

02 Dec '25
Attention is currently required from: daniel, fixeria. pespin has posted comments on this change by daniel. ( https://gerrit.osmocom.org/c/libosmo-sigtran/+/41523?usp=email ) Change subject: Use DLTCAP for TCAP log messages ...................................................................... Patch Set 6: Code-Review-1 (1 comment) Patchset: PS6: Please @dwillmann@sysmocom.de add entry to TODO-RELEASE file: libosmocore >1.9.3 DLTCAP -- To view, visit https://gerrit.osmocom.org/c/libosmo-sigtran/+/41523?usp=email To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings?usp=email Gerrit-MessageType: comment Gerrit-Project: libosmo-sigtran Gerrit-Branch: master Gerrit-Change-Id: Ic2fba30208a11d562fc67bb6f5c4586451a275df Gerrit-Change-Number: 41523 Gerrit-PatchSet: 6 Gerrit-Owner: daniel <dwillmann(a)sysmocom.de> Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: fixeria <vyanitskiy(a)sysmocom.de> Gerrit-Reviewer: osmith <osmith(a)sysmocom.de> Gerrit-Reviewer: pespin <pespin(a)sysmocom.de> Gerrit-Attention: fixeria <vyanitskiy(a)sysmocom.de> Gerrit-Attention: daniel <dwillmann(a)sysmocom.de> Gerrit-Comment-Date: Tue, 02 Dec 2025 09:15:04 +0000 Gerrit-HasComments: Yes Gerrit-Has-Labels: Yes
1 0
0 0
  • ← Newer
  • 1
  • ...
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • ...
  • 118
  • Older →

HyperKitty Powered by HyperKitty version 1.3.12.