feat!: carry the network indicator through the MTP interface

Merged
GO
16d ago
+546-66

The MTP-TRANSFER primitive carries OPC, DPC, SLS, SIO and user data (ITU-T Q.711 (03/01) §7.2, Table 18), and a signalling point code is an address element only "together with the MTP-SAP instance" (§6.1.1.2.2). The network indicator in the SIO (ITU-T Q.704 (07/96) §14.2.2: 00 international, 01 spare, 10 national, 11 reserved for national use) says which network a point code belongs to. M3UA carries it in its protocol data (RFC 4666 §3.3.1).

RoutingLabel had only OPC, DPC and SLS. The stack therefore answered without knowing which network a message came from, keyed reassembly and the per-peer bound on point codes that are unique only within a network, and left every application to remember the network itself. The SGP example did exactly that with its own reply table.

Changes

  • RoutingLabel.NI, a NetworkIndicator with the four codes of Q.704 §14.2.2 (stringer-generated names). StackConfig.NetworkIndicator is the network of the messages the stack originates, international by default. A node that originates in several networks runs one Stack per network.
  • Every response goes to the network of the message it answers. That covers the UDTS/XUDTS/LUDTS returns, the CREF, the Table B.2 responses, and the messages of a connection section, whose peer is now identified by its NI and point code. A CC in state c3 associates both.
  • The reassembly key (the whole RoutingLabel) and the per-peer bound (now keyed on NI and OPC) include the network.
  • The MTP side is held to the field widths of the standard routing label: 14-bit DPC and OPC and a 4-bit SLS (Q.704 §§2.2.2-2.2.4), which §2.2.1 applies to national applications too, and the 2-bit NI.
    • NewStack refuses a point code above 14 bits and a network indicator above 3.
    • Unitdata and Connect refuse a DPC above 14 bits.
    • A received message that breaks a width is discarded with ErrInvalidRequest, without being parsed or reaching LocalGlobalTitle, instead of being answered with a label the MTP cannot carry.
  • docs/standards.md and the README describe the network handling.

BREAKING CHANGE: RoutingLabel has a new field, and point codes above 14 bits and SLS values above 15 are refused on the MTP side.

Verification

  • network_indicator_test.go covers:
    • the configuration and width boundaries: 0x3fff accepted, 0x4000 refused; SLS 15 accepted, 16 refused; NI 3 accepted, 4 refused;
    • origination in the configured network;
    • returns, CREF, CC, DT1, IT, RLSD and the Table B.2 responses in the received network;
    • two messages identical except for NI reassembling independently;
    • separate per-peer budgets for one OPC in two networks;
    • a section refusing its own OPC from another network as a point code mismatch;
    • the NI exposed on indications and discards.
  • FuzzUnitdataTransfer and FuzzConnectionTransfer vary the NI. The connectionless fuzz checks the per-(NI, OPC) accounting against its own tally. 60 s each: 13.3 and 18.7 million executions, no failure.
  • 15 planted faults, one per guard and propagation path, each fail the tests. Two were re-run independently in review: replies without NI, and the per-peer key without NI.
  • go test -race, vet, staticcheck (current and 0.8.1), golangci-lint: clean. go generate with stringer v0.52.0 is stable; go fix -diff reports nothing.
  • On the wire, the SCCP examples over M3UA/SCTP between two Linux containers, captured with tshark at the SGP, with the examples branch that follows this PR:
ScenarioRequest NIReply NI
Before: an SGP that stops tracking the network itself, on the current library20, wrong network
After, national network22 (UDTS, cause 0x04)
After, default00
After, national, two XUDT segments22 (one XUDTS with the first segment's segmentation parameter)

No Wireshark expert information in any capture.


Summary by cubic

Carries the network indicator through the MTP interface so the SCCP stack can tell which network each message came from and answer in that network. The routing label now carries the NI (Q.704 §14.2.2), every response goes to the network of the message it answers, and reassembly and the per-peer octet bound are keyed on (NI, OPC). Originated messages use the network from StackConfig.NetworkIndicator, international by default.

The MTP side is also held to the field widths of the standard routing label: 14-bit OPC/DPC, 4-bit SLS, 2-bit NI. Values wider than that are refused with ErrInvalidRequest instead of being truncated or answered with a label the MTP cannot carry.

Breaking changes

  • RoutingLabel gains a NetworkIndicator field; point codes above 14 bits and SLS values above 15 are refused at the MTP.