This adds a 'nsvc nsvci <0-65535> (block|unblock|reset)' vty command. It selects the NS-VC based on the nsvci instead of using the first with a matching NSEI, like it is done when the 'nsei' keyword is used instead.
Sponsored-by: On-Waves ehf --- src/gb/gprs_ns_vty.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-)
diff --git a/src/gb/gprs_ns_vty.c b/src/gb/gprs_ns_vty.c index a2e7beb..f33fd0b 100644 --- a/src/gb/gprs_ns_vty.c +++ b/src/gb/gprs_ns_vty.c @@ -499,21 +499,29 @@ DEFUN(cfg_frgre_enable, cfg_frgre_enable_cmd, }
DEFUN(nsvc_nsei, nsvc_nsei_cmd, - "nsvc nsei <0-65535> (block|unblock|reset)", + "nsvc (nsei|nsvci) <0-65535> (block|unblock|reset)", "Perform an operation on a NSVC\n" "NSEI to identify NS-VC Identifier (NS-VCI)\n" + "NS-VC Identifier (NS-VCI)\n" "The NSEI\n" "Initiate BLOCK procedure\n" "Initiate UNBLOCK procedure\n" "Initiate RESET procedure\n") { - uint16_t nsvci = atoi(argv[0]); - const char *operation = argv[1]; + const char *id_type = argv[0]; + uint16_t id = atoi(argv[1]); + const char *operation = argv[2]; struct gprs_nsvc *nsvc;
- nsvc = gprs_nsvc_by_nsei(vty_nsi, nsvci); + if (!strcmp(id_type, "nsei")) + nsvc = gprs_nsvc_by_nsei(vty_nsi, id); + else if (!strcmp(id_type, "nsvci")) + nsvc = gprs_nsvc_by_nsvci(vty_nsi, id); + else + return CMD_WARNING; + if (!nsvc) { - vty_out(vty, "No such NSVCI (%u)%s", nsvci, VTY_NEWLINE); + vty_out(vty, "No such %s (%u)%s", id_type, id, VTY_NEWLINE); return CMD_WARNING; }
Add a test handling proper and mismatching RESETs. The latter may occur, when ports change within a NS-VC without the SGSN getting notice.
The current implementation doesn't handle this correctly in all cases, especially concerning GSM 08.16, 7.3.1.
Sponsored-by: On-Waves ehf --- tests/gb/gprs_ns_test.c | 157 +++++++++++++++++++++ tests/gb/gprs_ns_test.ok | 344 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 501 insertions(+)
diff --git a/tests/gb/gprs_ns_test.c b/tests/gb/gprs_ns_test.c index 38c7d1f..df7f18b 100644 --- a/tests/gb/gprs_ns_test.c +++ b/tests/gb/gprs_ns_test.c @@ -493,6 +493,156 @@ static void test_bss_port_changes() nsi = NULL; }
+static void test_bss_reset_ack() +{ + struct gprs_ns_inst *nsi = gprs_ns_instantiate(gprs_ns_callback, NULL); + struct sockaddr_in peer[4] = {{0},}; + struct gprs_nsvc *nsvc; + struct sockaddr_in *nse[4]; + int rc; + + peer[0].sin_family = AF_INET; + peer[0].sin_port = htons(1111); + peer[0].sin_addr.s_addr = htonl(REMOTE_BSS_ADDR); + peer[1].sin_family = AF_INET; + peer[1].sin_port = htons(2222); + peer[1].sin_addr.s_addr = htonl(REMOTE_BSS_ADDR); + peer[2].sin_family = AF_INET; + peer[2].sin_port = htons(3333); + peer[2].sin_addr.s_addr = htonl(REMOTE_BSS_ADDR); + peer[3].sin_family = AF_INET; + peer[3].sin_port = htons(4444); + peer[3].sin_addr.s_addr = htonl(REMOTE_BSS_ADDR); + + nse[0] = &peer[0]; + nse[1] = &peer[1]; + + printf("--- Setup VC 1 BSS -> SGSN ---\n\n"); + + setup_ns(nsi, nse[0], 0x1001, 0x1000); + gprs_dump_nsi(nsi); + + printf("--- Setup VC 2 BSS -> SGSN ---\n\n"); + + setup_ns(nsi, nse[1], 0x2001, 0x2000); + gprs_dump_nsi(nsi); + + printf("--- Setup VC 1 SGSN -> BSS ---\n\n"); + + nsvc = gprs_nsvc_by_nsvci(nsi, 0x1001); + gprs_ns_tx_reset(nsvc, NS_CAUSE_OM_INTERVENTION); + send_ns_reset_ack(nsi, nse[0], 0x1001, 0x1000); + gprs_dump_nsi(nsi); + + printf("--- Exchange NSEI 1 + 2 links ---\n\n"); + + nse[1] = &peer[0]; + nse[0] = &peer[1]; + + printf("--- Setup VC 2 SGSN -> BSS (hits NSEI 1) ---\n\n"); + + nsvc = gprs_nsvc_by_nsvci(nsi, 0x2001); + gprs_ns_tx_reset(nsvc, NS_CAUSE_OM_INTERVENTION); + send_ns_reset_ack(nsi, nse[0], 0x1001, 0x1000); + gprs_dump_nsi(nsi); + + printf("--- Setup VC 2 SGSN -> BSS (hits NSEI 2) ---\n\n"); + + nsvc = gprs_nsvc_by_nsvci(nsi, 0x2001); + rc = gprs_ns_tx_reset(nsvc, NS_CAUSE_OM_INTERVENTION); + if (rc < 0) + printf("Failed to send RESET to %s\n\n", gprs_ns_ll_str(nsvc)); + else { + send_ns_reset_ack(nsi, nse[1], 0x2001, 0x2000); + gprs_dump_nsi(nsi); + } + + printf("--- Setup VC 1 SGSN -> BSS (hits NSEI 1) ---\n\n"); + + nsvc = gprs_nsvc_by_nsvci(nsi, 0x1001); + gprs_ns_tx_reset(nsvc, NS_CAUSE_OM_INTERVENTION); + send_ns_reset_ack(nsi, nse[0], 0x1001, 0x1000); + gprs_dump_nsi(nsi); + + printf("--- Setup VC 2 BSS -> SGSN ---\n\n"); + + setup_ns(nsi, nse[1], 0x2001, 0x2000); + gprs_dump_nsi(nsi); + + /* Test 3GPP TS 08.16, 7.3.1, 5th paragraph. */ + + printf("--- Unexpected RESET_ACK VC 1, BSS -> SGSN ---\n\n"); + + send_ns_reset_ack(nsi, nse[0], 0x1001, 0x1000); + gprs_dump_nsi(nsi); + + /* Test 3GPP TS 08.16, 7.3.1, 4th paragraph. */ + + printf("--- RESET_ACK with invalid NSEI, BSS -> SGSN ---\n\n"); + + nsvc = gprs_nsvc_by_nsvci(nsi, 0x1001); + gprs_ns_tx_reset(nsvc, NS_CAUSE_OM_INTERVENTION); + send_ns_reset_ack(nsi, nse[0], 0x1001, 0xf000); + gprs_dump_nsi(nsi); + + /* Test 3GPP TS 08.16, 7.3.1, 4th paragraph. */ + + printf("--- RESET_ACK with invalid NSVCI, BSS -> SGSN ---\n\n"); + + nsvc = gprs_nsvc_by_nsvci(nsi, 0x1001); + gprs_ns_tx_reset(nsvc, NS_CAUSE_OM_INTERVENTION); + send_ns_reset_ack(nsi, nse[0], 0xf001, 0x1000); + gprs_dump_nsi(nsi); + + gprs_ns_destroy(nsi); + nsi = NULL; +} + + +static void test_sgsn_reset() +{ + struct gprs_ns_inst *nsi = gprs_ns_instantiate(gprs_ns_callback, NULL); + struct sockaddr_in sgsn_peer= {0}; + + sgsn_peer.sin_family = AF_INET; + sgsn_peer.sin_port = htons(32000); + sgsn_peer.sin_addr.s_addr = htonl(REMOTE_SGSN_ADDR); + + gprs_dump_nsi(nsi); + + printf("--- Setup SGSN connection, BSS -> SGSN ---\n\n"); + + gprs_ns_nsip_connect(nsi, &sgsn_peer, SGSN_NSEI, SGSN_NSEI+1); + send_ns_reset_ack(nsi, &sgsn_peer, SGSN_NSEI+1, SGSN_NSEI); + send_ns_alive_ack(nsi, &sgsn_peer); + send_ns_unblock_ack(nsi, &sgsn_peer); + gprs_dump_nsi(nsi); + + printf("--- RESET, SGSN -> BSS ---\n\n"); + + send_ns_reset(nsi, &sgsn_peer, NS_CAUSE_OM_INTERVENTION, + SGSN_NSEI+1, SGSN_NSEI); + gprs_dump_nsi(nsi); + + /* Test 3GPP TS 08.16, 7.3.1, 3rd paragraph. */ + + printf("--- RESET with invalid NSEI, SGSN -> BSS ---\n\n"); + + send_ns_reset(nsi, &sgsn_peer, NS_CAUSE_OM_INTERVENTION, + SGSN_NSEI+1, 0xf000); + gprs_dump_nsi(nsi); + + /* Test 3GPP TS 08.16, 7.3.1, 2nd paragraph. */ + + printf("--- RESET with invalid NSVCI, SGSN -> BSS ---\n\n"); + + send_ns_reset(nsi, &sgsn_peer, NS_CAUSE_OM_INTERVENTION, + 0xf001, SGSN_NSEI); + gprs_dump_nsi(nsi); + + gprs_ns_destroy(nsi); + nsi = NULL; +}
static void test_sgsn_output() { @@ -567,8 +717,15 @@ int main(int argc, char **argv) log_set_print_filename(osmo_stderr_target, 0); osmo_signal_register_handler(SS_L_NS, &test_signal, NULL);
+ log_set_print_filename(osmo_stderr_target, 0); + log_set_log_level(osmo_stderr_target, LOGL_INFO); + + setlinebuf(stdout); + printf("===== NS protocol test START\n"); test_bss_port_changes(); + test_bss_reset_ack(); + test_sgsn_reset(); test_sgsn_output(); printf("===== NS protocol test END\n\n");
diff --git a/tests/gb/gprs_ns_test.ok b/tests/gb/gprs_ns_test.ok index 424d681..ddd0b00 100644 --- a/tests/gb/gprs_ns_test.ok +++ b/tests/gb/gprs_ns_test.ok @@ -143,6 +143,350 @@ Current NS-VCIs: NS-VC replaced other count: 1 NS-VC changed NSEI : 2
+--- Setup VC 1 BSS -> SGSN --- + +Setup NS-VC: remote 0x01020304:1111, NSVCI 0x1001(4097), NSEI 0x1000(4096) + +PROCESSING RESET from 0x01020304:1111 +02 00 81 01 01 82 10 01 04 82 10 00 + +==> got signal NS_RESET, NS-VC 0x1001/1.2.3.4:1111 +MESSAGE to BSS, msg length 9 +03 01 82 10 01 04 82 10 00 + +MESSAGE to BSS, msg length 1 +0a + +result (RESET) = 9 + +PROCESSING ALIVE from 0x01020304:1111 +0a + +MESSAGE to BSS, msg length 1 +0b + +result (ALIVE) = 1 + +PROCESSING UNBLOCK from 0x01020304:1111 +06 + +==> got signal NS_UNBLOCK, NS-VC 0x1001/1.2.3.4:1111 +MESSAGE to BSS, msg length 1 +07 + +result (UNBLOCK) = 1 + +PROCESSING ALIVE_ACK from 0x01020304:1111 +0b + +result (ALIVE_ACK) = 0 + +Current NS-VCIs: + VCI 0x1001, NSEI 0x1000, peer 0x01020304:1111 + +--- Setup VC 2 BSS -> SGSN --- + +Setup NS-VC: remote 0x01020304:2222, NSVCI 0x2001(8193), NSEI 0x2000(8192) + +PROCESSING RESET from 0x01020304:2222 +02 00 81 01 01 82 20 01 04 82 20 00 + +==> got signal NS_RESET, NS-VC 0x2001/1.2.3.4:2222 +MESSAGE to BSS, msg length 9 +03 01 82 20 01 04 82 20 00 + +MESSAGE to BSS, msg length 1 +0a + +result (RESET) = 9 + +PROCESSING ALIVE from 0x01020304:2222 +0a + +MESSAGE to BSS, msg length 1 +0b + +result (ALIVE) = 1 + +PROCESSING UNBLOCK from 0x01020304:2222 +06 + +==> got signal NS_UNBLOCK, NS-VC 0x2001/1.2.3.4:2222 +MESSAGE to BSS, msg length 1 +07 + +result (UNBLOCK) = 1 + +PROCESSING ALIVE_ACK from 0x01020304:2222 +0b + +result (ALIVE_ACK) = 0 + +Current NS-VCIs: + VCI 0x2001, NSEI 0x2000, peer 0x01020304:2222 + VCI 0x1001, NSEI 0x1000, peer 0x01020304:1111 + +--- Setup VC 1 SGSN -> BSS --- + +MESSAGE to BSS, msg length 12 +02 00 81 01 01 82 10 01 04 82 10 00 + +PROCESSING RESET_ACK from 0x01020304:1111 +03 01 82 10 01 04 82 10 00 + +MESSAGE to BSS, msg length 1 +0a + +result (RESET_ACK) = 1 + +Current NS-VCIs: + VCI 0x2001, NSEI 0x2000, peer 0x01020304:2222 + VCI 0x1001, NSEI 0x1000, peer 0x01020304:1111, blocked + NS-VC Block count : 1 + +--- Exchange NSEI 1 + 2 links --- + +--- Setup VC 2 SGSN -> BSS (hits NSEI 1) --- + +MESSAGE to BSS, msg length 12 +02 00 81 01 01 82 20 01 04 82 20 00 + +PROCESSING RESET_ACK from 0x01020304:2222 +03 01 82 10 01 04 82 10 00 + +MESSAGE to BSS, msg length 1 +0a + +result (RESET_ACK) = 1 + +Current NS-VCIs: + VCI 0x2001, NSEI 0x2000, peer 0x01020304:2222, blocked + NS-VC Block count : 1 + VCI 0x1001, NSEI 0x1000, peer 0x01020304:1111, blocked + NS-VC Block count : 1 + +--- Setup VC 2 SGSN -> BSS (hits NSEI 2) --- + +MESSAGE to BSS, msg length 12 +02 00 81 01 01 82 20 01 04 82 20 00 + +PROCESSING RESET_ACK from 0x01020304:1111 +03 01 82 20 01 04 82 20 00 + +MESSAGE to BSS, msg length 1 +0a + +result (RESET_ACK) = 1 + +Current NS-VCIs: + VCI 0x2001, NSEI 0x2000, peer 0x01020304:2222, blocked + NS-VC Block count : 1 + VCI 0x1001, NSEI 0x1000, peer 0x01020304:1111, blocked + NS-VC Block count : 2 + +--- Setup VC 1 SGSN -> BSS (hits NSEI 1) --- + +MESSAGE to BSS, msg length 12 +02 00 81 01 01 82 10 01 04 82 10 00 + +PROCESSING RESET_ACK from 0x01020304:2222 +03 01 82 10 01 04 82 10 00 + +MESSAGE to BSS, msg length 1 +0a + +result (RESET_ACK) = 1 + +Current NS-VCIs: + VCI 0x2001, NSEI 0x2000, peer 0x01020304:2222, blocked + NS-VC Block count : 2 + VCI 0x1001, NSEI 0x1000, peer 0x01020304:1111, blocked + NS-VC Block count : 2 + +--- Setup VC 2 BSS -> SGSN --- + +Setup NS-VC: remote 0x01020304:1111, NSVCI 0x2001(8193), NSEI 0x2000(8192) + +PROCESSING RESET from 0x01020304:1111 +02 00 81 01 01 82 20 01 04 82 20 00 + +==> got signal NS_REPLACED: 0x2001/1.2.3.4:2222 -> 0x1001/1.2.3.4:1111 +==> got signal NS_RESET, NS-VC 0x2001/1.2.3.4:1111 +MESSAGE to BSS, msg length 9 +03 01 82 20 01 04 82 20 00 + +MESSAGE to BSS, msg length 1 +0a + +result (RESET) = 9 + +PROCESSING ALIVE from 0x01020304:1111 +0a + +MESSAGE to BSS, msg length 1 +0b + +result (ALIVE) = 1 + +PROCESSING UNBLOCK from 0x01020304:1111 +06 + +==> got signal NS_UNBLOCK, NS-VC 0x2001/1.2.3.4:1111 +MESSAGE to BSS, msg length 1 +07 + +result (UNBLOCK) = 1 + +PROCESSING ALIVE_ACK from 0x01020304:1111 +0b + +result (ALIVE_ACK) = 0 + +Current NS-VCIs: + VCI 0x2001, NSEI 0x2000, peer 0x01020304:1111 + NS-VC Block count : 2 + NS-VC replaced other count: 1 + VCI 0x1001, NSEI 0x1000, peer 0x00000000:0, blocked + NS-VC Block count : 2 + +--- Unexpected RESET_ACK VC 1, BSS -> SGSN --- + +PROCESSING RESET_ACK from 0x01020304:2222 +03 01 82 10 01 04 82 10 00 + +MESSAGE to BSS, msg length 15 +08 00 81 0a 02 89 03 01 82 10 01 04 82 10 00 + +result (RESET_ACK) = 0 + +Current NS-VCIs: + VCI 0x2001, NSEI 0x2000, peer 0x01020304:1111 + NS-VC Block count : 2 + NS-VC replaced other count: 1 + VCI 0x1001, NSEI 0x1000, peer 0x00000000:0, blocked + NS-VC Block count : 2 + +--- RESET_ACK with invalid NSEI, BSS -> SGSN --- + +PROCESSING RESET_ACK from 0x01020304:2222 +03 01 82 10 01 04 82 f0 00 + +MESSAGE to BSS, msg length 15 +08 00 81 0a 02 89 03 01 82 10 01 04 82 f0 00 + +result (RESET_ACK) = 0 + +Current NS-VCIs: + VCI 0x2001, NSEI 0x2000, peer 0x01020304:1111 + NS-VC Block count : 2 + NS-VC replaced other count: 1 + VCI 0x1001, NSEI 0x1000, peer 0x00000000:0, blocked + NS-VC Block count : 2 + +--- RESET_ACK with invalid NSVCI, BSS -> SGSN --- + +PROCESSING RESET_ACK from 0x01020304:2222 +03 01 82 f0 01 04 82 10 00 + +MESSAGE to BSS, msg length 15 +08 00 81 0a 02 89 03 01 82 f0 01 04 82 10 00 + +result (RESET_ACK) = 0 + +Current NS-VCIs: + VCI 0x2001, NSEI 0x2000, peer 0x01020304:1111 + NS-VC Block count : 2 + NS-VC replaced other count: 1 + VCI 0x1001, NSEI 0x1000, peer 0x00000000:0, blocked + NS-VC Block count : 2 + +Current NS-VCIs: + +--- Setup SGSN connection, BSS -> SGSN --- + +MESSAGE to SGSN, msg length 12 +02 00 81 01 01 82 01 01 04 82 01 00 + +PROCESSING RESET_ACK from 0x05060708:32000 +03 01 82 01 01 04 82 01 00 + +MESSAGE to SGSN, msg length 1 +0a + +result (RESET_ACK) = 1 + +PROCESSING ALIVE_ACK from 0x05060708:32000 +0b + +MESSAGE to SGSN, msg length 1 +06 + +result (ALIVE_ACK) = 1 + +PROCESSING UNBLOCK_ACK from 0x05060708:32000 +07 + +==> got signal NS_UNBLOCK, NS-VC 0x0101/5.6.7.8:32000 +result (UNBLOCK_ACK) = 0 + +Current NS-VCIs: + VCI 0x0101, NSEI 0x0100, peer 0x05060708:32000 + NS-VC Block count : 1 + +--- RESET, SGSN -> BSS --- + +PROCESSING RESET from 0x05060708:32000 +02 00 81 01 01 82 01 01 04 82 01 00 + +==> got signal NS_RESET, NS-VC 0x0101/5.6.7.8:32000 +MESSAGE to SGSN, msg length 9 +03 01 82 01 01 04 82 01 00 + +MESSAGE to SGSN, msg length 1 +0a + +result (RESET) = 9 + +Current NS-VCIs: + VCI 0x0101, NSEI 0x0100, peer 0x05060708:32000, blocked + NS-VC Block count : 1 + +--- RESET with invalid NSEI, SGSN -> BSS --- + +PROCESSING RESET from 0x05060708:32000 +02 00 81 01 01 82 01 01 04 82 f0 00 + +==> got signal NS_RESET, NS-VC 0x0101/5.6.7.8:32000 +MESSAGE to SGSN, msg length 9 +03 01 82 01 01 04 82 f0 00 + +MESSAGE to SGSN, msg length 1 +0a + +result (RESET) = 9 + +Current NS-VCIs: + VCI 0x0101, NSEI 0xf000, peer 0x05060708:32000, blocked + NS-VC Block count : 1 + +--- RESET with invalid NSVCI, SGSN -> BSS --- + +PROCESSING RESET from 0x05060708:32000 +02 00 81 01 01 82 f0 01 04 82 01 00 + +==> got signal NS_RESET, NS-VC 0xf001/5.6.7.8:32000 +MESSAGE to SGSN, msg length 9 +03 01 82 f0 01 04 82 01 00 + +MESSAGE to SGSN, msg length 1 +0a + +result (RESET) = 9 + +Current NS-VCIs: + VCI 0xf001, NSEI 0x0100, peer 0x05060708:32000, blocked + NS-VC Block count : 1 + Current NS-VCIs:
--- Send message to SGSN ---
On 10/24/2013 07:35 AM, Holger Hans Peter Freyther wrote:
On Tue, Oct 22, 2013 at 12:22:40PM +0200, Jacob Erlbeck wrote:
- setlinebuf(stdout);
out of curiosity, why is this needed?
To have a sensible relation between stderr and stdout lines, e.g. when calling something like:
./tests/gbproxy/gbproxy_test 2>&1 | less
or writing the output to a file. Since by default stderr is unbuffered and stdout is (possibly) block buffered when not writing to tty. You'd get chunks of stderr and stdout blobs in this case. See setlinebuf(3) for details.
Jacob
This changes the implementations for the reception of RESET and RESET_ACK to be compatible with 3GPP TS 08.16, 7.3.1:
- Just send a RESET_ACK with correct values back to the SGSN when a RESET with an invalid NSVCI or NSEI has been received. - Check RESET_ACK for matching NSEI and NSVCI. - Ignore unexpected RESET_ACKs.
In addition, use RESET_ACK from a BSS to update the BSS source address based on the NSVCI to be tolerant with changing UDP source addresses/ports.
Sponsored-by: On-Waves ehf --- include/osmocom/gprs/gprs_ns.h | 5 + src/gb/gprs_ns.c | 259 +++++++++++++++++++++++++++++++++------- tests/gb/gprs_ns_test.c | 6 + tests/gb/gprs_ns_test.ok | 104 +++++++--------- 4 files changed, 269 insertions(+), 105 deletions(-)
diff --git a/include/osmocom/gprs/gprs_ns.h b/include/osmocom/gprs/gprs_ns.h index b28c58d..296800e 100644 --- a/include/osmocom/gprs/gprs_ns.h +++ b/include/osmocom/gprs/gprs_ns.h @@ -36,6 +36,7 @@ enum ns_timeout {
#define NSE_S_BLOCKED 0x0001 #define NSE_S_ALIVE 0x0002 +#define NSE_S_RESET 0x0004
/*! \brief Osmocom NS link layer types */ enum gprs_ns_ll { @@ -199,12 +200,16 @@ enum signal_ns { S_NS_UNBLOCK, S_NS_ALIVE_EXP, /* Tns-alive expired more than N times */ S_NS_REPLACED, /* nsvc object is replaced (sets old_nsvc) */ + S_NS_MISMATCH, /* got an unexpected IE (sets msg, pdu_type, ie_type) */ };
struct ns_signal_data { struct gprs_nsvc *nsvc; struct gprs_nsvc *old_nsvc; uint8_t cause; + uint8_t pdu_type; + uint8_t ie_type; + struct msgb *msg; };
void gprs_ns_set_log_ss(int ss); diff --git a/src/gb/gprs_ns.c b/src/gb/gprs_ns.c index 6a35ad3..b50a700 100644 --- a/src/gb/gprs_ns.c +++ b/src/gb/gprs_ns.c @@ -102,6 +102,8 @@ enum ns_ctr { NS_CTR_DEAD, NS_CTR_REPLACED, NS_CTR_NSEI_CHG, + NS_CTR_INV_VCI, + NS_CTR_INV_NSEI, };
static const struct rate_ctr_desc nsvc_ctr_description[] = { @@ -113,6 +115,8 @@ static const struct rate_ctr_desc nsvc_ctr_description[] = { { "dead", "NS-VC gone dead count " }, { "replaced", "NS-VC replaced other count" }, { "nsei-chg", "NS-VC changed NSEI " }, + { "inv-nsvci", "NS-VCI was invalid count " }, + { "inv-nsei", "NSEI was invalid count " }, };
static const struct rate_ctr_group_desc nsvc_ctrg_desc = { @@ -190,6 +194,7 @@ struct gprs_nsvc *gprs_nsvc_create(struct gprs_ns_inst *nsi, uint16_t nsvci)
nsvc = talloc_zero(nsi, struct gprs_nsvc); nsvc->nsvci = nsvci; + nsvc->nsvci_is_valid = 1; /* before RESET procedure: BLOCKED and DEAD */ nsvc->state = NSE_S_BLOCKED; nsvc->nsi = nsi; @@ -224,6 +229,20 @@ static void ns_osmo_signal_dispatch(struct gprs_nsvc *nsvc, unsigned int signal, osmo_signal_dispatch(SS_L_NS, signal, &nssd); }
+static void ns_osmo_signal_dispatch_mismatch(struct gprs_nsvc *nsvc, + struct msgb *msg, + uint8_t pdu_type, uint8_t ie_type) +{ + struct ns_signal_data nssd = {0}; + + nssd.nsvc = nsvc; + nssd.pdu_type = pdu_type; + nssd.ie_type = ie_type; + nssd.msg = msg; + + osmo_signal_dispatch(SS_L_NS, S_NS_MISMATCH, &nssd); +} + static void ns_osmo_signal_dispatch_replaced(struct gprs_nsvc *nsvc, struct gprs_nsvc *old_nsvc) { struct ns_signal_data nssd = {0}; @@ -322,6 +341,8 @@ int gprs_ns_tx_reset(struct gprs_nsvc *nsvc, uint8_t cause) LOGP(DNS, LOGL_INFO, "NSEI=%u Tx NS RESET (NSVCI=%u, cause=%s)\n", nsvc->nsei, nsvc->nsvci, gprs_ns_cause_str(cause));
+ nsvc->state |= NSE_S_RESET; + msg->l2h = msgb_put(msg, sizeof(*nsh)); nsh = (struct gprs_ns_hdr *) msg->l2h; nsh->pdu_type = NS_PDUT_RESET; @@ -671,6 +692,49 @@ static int gprs_ns_rx_status(struct gprs_nsvc *nsvc, struct msgb *msg) return 0; }
+/* Replace a nsvc object with another based on NSVCI. + * This function replaces looks for a NSVC with the given NSVCI and replaces it + * if possible and necessary. If replaced, the former value of *nsvc is + * returned in *old_nsvc. + * \return != 0 if *nsvc points to a matching NSVC. + */ +static int gprs_nsvc_replace_if_found(uint16_t nsvci, + struct gprs_nsvc **nsvc, + struct gprs_nsvc **old_nsvc) +{ + struct gprs_nsvc *matching_nsvc; + + if ((*nsvc)->nsvci == nsvci) { + *old_nsvc = NULL; + return 1; + } + + matching_nsvc = gprs_nsvc_by_nsvci((*nsvc)->nsi, nsvci); + + if (!matching_nsvc) + return 0; + + /* The NS-VCI is already used by this NS-VC */ + + char *old_peer; + + /* Exchange the NS-VC objects */ + *old_nsvc = *nsvc; + *nsvc = matching_nsvc; + + /* Do logging */ + old_peer = talloc_strdup(*old_nsvc, gprs_ns_ll_str(*old_nsvc)); + LOGP(DNS, LOGL_INFO, "NS-VC changed link (NSVCI=%u) from %s to %s\n", + nsvci, old_peer, gprs_ns_ll_str(*nsvc)); + + talloc_free(old_peer); + + /* Do statistics */ + rate_ctr_inc(&(*nsvc)->ctrg->ctr[NS_CTR_REPLACED]); + + return 1; +} + /* Section 7.3 */ static int gprs_ns_rx_reset(struct gprs_nsvc **nsvc, struct msgb *msg) { @@ -678,7 +742,7 @@ static int gprs_ns_rx_reset(struct gprs_nsvc **nsvc, struct msgb *msg) struct tlv_parsed tp; uint8_t cause; uint16_t nsvci, nsei; - struct gprs_nsvc *other_nsvc = NULL; + struct gprs_nsvc *orig_nsvc = NULL; int rc;
rc = tlv_parse(&tp, &ns_att_tlvdef, nsh->data, @@ -705,39 +769,42 @@ static int gprs_ns_rx_reset(struct gprs_nsvc **nsvc, struct msgb *msg) (*nsvc)->nsvci, (*nsvc)->nsvci_is_valid ? "" : "(invalid)", nsei, nsvci, gprs_ns_cause_str(cause));
- if ((*nsvc)->nsvci_is_valid && (*nsvc)->nsvci != nsvci) { - /* NS-VCI has changed */ - other_nsvc = gprs_nsvc_by_nsvci((*nsvc)->nsi, nsvci); - - if (other_nsvc) { - /* The NS-VCI is already used by this NS-VC */ - - struct gprs_nsvc *tmp_nsvc; - char *old_peer; - - /* Exchange the NS-VC objects */ - tmp_nsvc = *nsvc; - *nsvc = other_nsvc; - other_nsvc = tmp_nsvc; - - /* Do logging */ - old_peer = talloc_strdup(other_nsvc, - gprs_ns_ll_str(other_nsvc)); - LOGP(DNS, LOGL_INFO, - "NS-VC changed link (NSVCI=%u) from %s to %s\n", - nsvci, old_peer, gprs_ns_ll_str(*nsvc)); - - talloc_free(old_peer); - - /* Do statistics */ - rate_ctr_inc(&(*nsvc)->ctrg->ctr[NS_CTR_REPLACED]); + if (!(*nsvc)->nsvci_is_valid) { + /* It's a new uninitialised NS-VC, nothing to check here */ + } else if ((*nsvc)->nsvci != nsvci) { + if ((*nsvc)->remote_end_is_sgsn) { + /* The incoming RESET doesn't match the NSVCI. Send an + * appropriate RESET_ACK and ignore the RESET. + * See 3GPP TS 08.16, 7.3.1, 2nd paragraph. + */ + ns_osmo_signal_dispatch_mismatch(*nsvc, msg, + NS_PDUT_RESET, + NS_IE_VCI); + rate_ctr_inc(&(*nsvc)->ctrg->ctr[NS_CTR_INV_VCI]); + gprs_ns_tx_reset_ack(*nsvc); + return 0; } + + /* NS-VCI has changed */ + gprs_nsvc_replace_if_found(nsvci, nsvc, &orig_nsvc); + + } else if ((*nsvc)->nsei != nsei) { + /* The incoming RESET doesn't match the NSEI. Send an + * appropriate RESET_ACK and ignore the RESET. + * See 3GPP TS 08.16, 7.3.1, 3rd paragraph. + */ + ns_osmo_signal_dispatch_mismatch(*nsvc, msg, + NS_PDUT_RESET, + NS_IE_NSEI); + rate_ctr_inc(&(*nsvc)->ctrg->ctr[NS_CTR_INV_NSEI]); + gprs_ns_tx_reset_ack(*nsvc); + return 0; }
/* Mark NS-VC as blocked and alive */ (*nsvc)->state = NSE_S_BLOCKED | NSE_S_ALIVE;
- if (other_nsvc) { + if (orig_nsvc) { /* Check NSEI */ if ((*nsvc)->nsei != nsei) { LOGP(DNS, LOGL_NOTICE, @@ -751,11 +818,11 @@ static int gprs_ns_rx_reset(struct gprs_nsvc **nsvc, struct msgb *msg) rate_ctr_inc(&(*nsvc)->ctrg->ctr[NS_CTR_NSEI_CHG]); }
- ns_osmo_signal_dispatch_replaced(*nsvc, other_nsvc); + ns_osmo_signal_dispatch_replaced(*nsvc, orig_nsvc);
/* Update the ll info fields */ - gprs_ns_ll_copy(*nsvc, other_nsvc); - gprs_ns_ll_clear(other_nsvc); + gprs_ns_ll_copy(*nsvc, orig_nsvc); + gprs_ns_ll_clear(orig_nsvc); } else { (*nsvc)->nsei = nsei; (*nsvc)->nsvci = nsvci; @@ -775,6 +842,121 @@ static int gprs_ns_rx_reset(struct gprs_nsvc **nsvc, struct msgb *msg) return rc; }
+static int gprs_ns_rx_reset_ack(struct gprs_nsvc **nsvc, struct msgb *msg) +{ + struct gprs_ns_hdr *nsh = (struct gprs_ns_hdr *) msg->l2h; + struct tlv_parsed tp; + uint16_t nsvci, nsei; + struct gprs_nsvc *orig_nsvc = NULL; + int rc; + + rc = tlv_parse(&tp, &ns_att_tlvdef, nsh->data, + msgb_l2len(msg) - sizeof(*nsh), 0, 0); + if (rc < 0) { + LOGP(DNS, LOGL_ERROR, "NSEI=%u Rx NS RESET ACK " + "Error during TLV Parse\n", (*nsvc)->nsei); + return rc; + } + + if (!TLVP_PRESENT(&tp, NS_IE_VCI) || + !TLVP_PRESENT(&tp, NS_IE_NSEI)) { + LOGP(DNS, LOGL_ERROR, "NS RESET ACK Missing mandatory IE\n"); + gprs_ns_tx_status(*nsvc, NS_CAUSE_MISSING_ESSENT_IE, 0, msg); + return -EINVAL; + } + + nsvci = ntohs(*(uint16_t *) TLVP_VAL(&tp, NS_IE_VCI)); + nsei = ntohs(*(uint16_t *) TLVP_VAL(&tp, NS_IE_NSEI)); + + LOGP(DNS, LOGL_INFO, "NSVCI=%u%s Rx NS RESET ACK (NSEI=%u, NSVCI=%u)\n", + (*nsvc)->nsvci, (*nsvc)->nsvci_is_valid ? "" : "(invalid)", + nsei, nsvci); + + if (!((*nsvc)->state & NSE_S_RESET)) { + /* Not waiting for a RESET_ACK on this NS-VC, ignore it. + * See 3GPP TS 08.16, 7.3.1, 5th paragraph. + */ + LOGP(DNS, LOGL_ERROR, + "NS RESET ACK Discarding unexpected message for " + "NS-VCI %d from SGSN NSEI=%d\n", + nsvci, nsei); + return 0; + } + + if (!(*nsvc)->nsvci_is_valid) { + LOGP(DNS, LOGL_NOTICE, + "NS RESET ACK Uninitialised NS-VC (%u) for " + "NS-VCI %d, NSEI=%d from %s\n", + (*nsvc)->nsvci, nsvci, nsei, gprs_ns_ll_str(*nsvc)); + return -EINVAL; + } + + if ((*nsvc)->nsvci != nsvci) { + /* NS-VCI has changed */ + + /* if !0, use another NSVC object that matches the NSVCI */ + int use_other_nsvc; + + /* Only do this with BSS peers */ + use_other_nsvc = !(*nsvc)->remote_end_is_sgsn; + + if (use_other_nsvc) + /* Update *nsvc to point to the right NSVC object */ + use_other_nsvc = gprs_nsvc_replace_if_found(nsvci, nsvc, + &orig_nsvc); + + if (!use_other_nsvc) { + /* The incoming RESET_ACK doesn't match the NSVCI. + * See 3GPP TS 08.16, 7.3.1, 4th paragraph. + */ + ns_osmo_signal_dispatch_mismatch(*nsvc, msg, + NS_PDUT_RESET_ACK, + NS_IE_VCI); + rate_ctr_inc(&(*nsvc)->ctrg->ctr[NS_CTR_INV_VCI]); + LOGP(DNS, LOGL_ERROR, + "NS RESET ACK Unknown NS-VCI %d (%s NSEI=%d) " + "from %s\n", + nsvci, + (*nsvc)->remote_end_is_sgsn ? "SGSN" : "BSS", + nsei, gprs_ns_ll_str(*nsvc)); + return -EINVAL; + } + + /* Notify others */ + ns_osmo_signal_dispatch_replaced(*nsvc, orig_nsvc); + + /* Update the ll info fields */ + gprs_ns_ll_copy(*nsvc, orig_nsvc); + gprs_ns_ll_clear(orig_nsvc); + } else if ((*nsvc)->nsei != nsei) { + /* The incoming RESET_ACK doesn't match the NSEI. + * See 3GPP TS 08.16, 7.3.1, 4th paragraph. + */ + ns_osmo_signal_dispatch_mismatch(*nsvc, msg, + NS_PDUT_RESET_ACK, + NS_IE_NSEI); + rate_ctr_inc(&(*nsvc)->ctrg->ctr[NS_CTR_INV_NSEI]); + LOGP(DNS, LOGL_ERROR, + "NS RESET ACK Unknown NSEI %d (NS-VCI=%u) from %s\n", + nsei, nsvci, gprs_ns_ll_str(*nsvc)); + return -EINVAL; + } + + /* Mark NS-VC as blocked and alive */ + (*nsvc)->state = NSE_S_BLOCKED | NSE_S_ALIVE; + (*nsvc)->remote_state = NSE_S_BLOCKED | NSE_S_ALIVE; + rate_ctr_inc(&(*nsvc)->ctrg->ctr[NS_CTR_BLOCKED]); + if ((*nsvc)->persistent || (*nsvc)->remote_end_is_sgsn) { + /* stop RESET timer */ + osmo_timer_del(&(*nsvc)->timer); + } + /* Initiate TEST proc.: Send ALIVE and start timer */ + rc = gprs_ns_tx_simple(*nsvc, NS_PDUT_ALIVE); + nsvc_start_timer(*nsvc, NSVC_TIMER_TNS_TEST); + + return rc; +} + static int gprs_ns_rx_block(struct gprs_nsvc *nsvc, struct msgb *msg) { struct gprs_ns_hdr *nsh = (struct gprs_ns_hdr *) msg->l2h; @@ -943,6 +1125,7 @@ int gprs_ns_vc_create(struct gprs_ns_inst *nsi, struct msgb *msg, "from %s for non-existing NS-VC\n", nsh->pdu_type, gprs_ns_ll_str(fallback_nsvc)); fallback_nsvc->nsvci = fallback_nsvc->nsei = 0xfffe; + fallback_nsvc->nsvci_is_valid = 0; fallback_nsvc->state = NSE_S_ALIVE;
rc = gprs_ns_tx_status(fallback_nsvc, @@ -1056,18 +1239,7 @@ int gprs_ns_process_msg(struct gprs_ns_inst *nsi, struct msgb *msg, rc = gprs_ns_rx_reset(nsvc, msg); break; case NS_PDUT_RESET_ACK: - LOGP(DNS, LOGL_INFO, "NSEI=%u Rx NS RESET ACK\n", (*nsvc)->nsei); - /* mark NS-VC as blocked + active */ - (*nsvc)->state = NSE_S_BLOCKED | NSE_S_ALIVE; - (*nsvc)->remote_state = NSE_S_BLOCKED | NSE_S_ALIVE; - rate_ctr_inc(&(*nsvc)->ctrg->ctr[NS_CTR_BLOCKED]); - if ((*nsvc)->persistent || (*nsvc)->remote_end_is_sgsn) { - /* stop RESET timer */ - osmo_timer_del(&(*nsvc)->timer); - } - /* Initiate TEST proc.: Send ALIVE and start timer */ - rc = gprs_ns_tx_simple(*nsvc, NS_PDUT_ALIVE); - nsvc_start_timer(*nsvc, NSVC_TIMER_TNS_TEST); + rc = gprs_ns_rx_reset_ack(nsvc, msg); break; case NS_PDUT_UNBLOCK: /* Section 7.2: unblocking procedure */ @@ -1322,6 +1494,7 @@ struct gprs_nsvc *gprs_ns_nsip_connect(struct gprs_ns_inst *nsi, nsvc->ip.bts_addr = *dest; nsvc->nsei = nsei; nsvc->nsvci = nsvci; + nsvc->nsvci_is_valid = 1; nsvc->remote_end_is_sgsn = 1;
gprs_nsvc_reset(nsvc, NS_CAUSE_OM_INTERVENTION); diff --git a/tests/gb/gprs_ns_test.c b/tests/gb/gprs_ns_test.c index df7f18b..d2d2825 100644 --- a/tests/gb/gprs_ns_test.c +++ b/tests/gb/gprs_ns_test.c @@ -356,6 +356,12 @@ static int test_signal(unsigned int subsys, unsigned int signal, gprs_ns_ll_str(nssd->old_nsvc)); break;
+ case S_NS_MISMATCH: + printf("==> got signal NS_MISMATCH: 0x%04x/%s pdu=%d, ie=%d\n", + nssd->nsvc->nsvci, gprs_ns_ll_str(nssd->nsvc), + nssd->pdu_type, nssd->ie_type); + break; + default: printf("==> got signal %d, NS-VC 0x%04x/%s\n", signal, nssd->nsvc->nsvci, diff --git a/tests/gb/gprs_ns_test.ok b/tests/gb/gprs_ns_test.ok index ddd0b00..b3c3236 100644 --- a/tests/gb/gprs_ns_test.ok +++ b/tests/gb/gprs_ns_test.ok @@ -254,35 +254,21 @@ MESSAGE to BSS, msg length 12 PROCESSING RESET_ACK from 0x01020304:2222 03 01 82 10 01 04 82 10 00
+==> got signal NS_REPLACED: 0x1001/1.2.3.4:1111 -> 0x2001/1.2.3.4:2222 MESSAGE to BSS, msg length 1 0a
result (RESET_ACK) = 1
Current NS-VCIs: - VCI 0x2001, NSEI 0x2000, peer 0x01020304:2222, blocked - NS-VC Block count : 1 - VCI 0x1001, NSEI 0x1000, peer 0x01020304:1111, blocked - NS-VC Block count : 1 + VCI 0x2001, NSEI 0x2000, peer 0x00000000:0 + VCI 0x1001, NSEI 0x1000, peer 0x01020304:2222, blocked + NS-VC Block count : 2 + NS-VC replaced other count: 1
--- Setup VC 2 SGSN -> BSS (hits NSEI 2) ---
-MESSAGE to BSS, msg length 12 -02 00 81 01 01 82 20 01 04 82 20 00 - -PROCESSING RESET_ACK from 0x01020304:1111 -03 01 82 20 01 04 82 20 00 - -MESSAGE to BSS, msg length 1 -0a - -result (RESET_ACK) = 1 - -Current NS-VCIs: - VCI 0x2001, NSEI 0x2000, peer 0x01020304:2222, blocked - NS-VC Block count : 1 - VCI 0x1001, NSEI 0x1000, peer 0x01020304:1111, blocked - NS-VC Block count : 2 +Failed to send RESET to 0.0.0.0:0
--- Setup VC 1 SGSN -> BSS (hits NSEI 1) ---
@@ -298,10 +284,10 @@ MESSAGE to BSS, msg length 1 result (RESET_ACK) = 1
Current NS-VCIs: - VCI 0x2001, NSEI 0x2000, peer 0x01020304:2222, blocked - NS-VC Block count : 2 - VCI 0x1001, NSEI 0x1000, peer 0x01020304:1111, blocked - NS-VC Block count : 2 + VCI 0x2001, NSEI 0x2000, peer 0x00000000:0 + VCI 0x1001, NSEI 0x1000, peer 0x01020304:2222, blocked + NS-VC Block count : 3 + NS-VC replaced other count: 1
--- Setup VC 2 BSS -> SGSN ---
@@ -310,7 +296,6 @@ Setup NS-VC: remote 0x01020304:1111, NSVCI 0x2001(8193), NSEI 0x2000(8192) PROCESSING RESET from 0x01020304:1111 02 00 81 01 01 82 20 01 04 82 20 00
-==> got signal NS_REPLACED: 0x2001/1.2.3.4:2222 -> 0x1001/1.2.3.4:1111 ==> got signal NS_RESET, NS-VC 0x2001/1.2.3.4:1111 MESSAGE to BSS, msg length 9 03 01 82 20 01 04 82 20 00 @@ -344,61 +329,59 @@ result (ALIVE_ACK) = 0
Current NS-VCIs: VCI 0x2001, NSEI 0x2000, peer 0x01020304:1111 - NS-VC Block count : 2 + VCI 0x1001, NSEI 0x1000, peer 0x01020304:2222, blocked + NS-VC Block count : 3 NS-VC replaced other count: 1 - VCI 0x1001, NSEI 0x1000, peer 0x00000000:0, blocked - NS-VC Block count : 2
--- Unexpected RESET_ACK VC 1, BSS -> SGSN ---
PROCESSING RESET_ACK from 0x01020304:2222 03 01 82 10 01 04 82 10 00
-MESSAGE to BSS, msg length 15 -08 00 81 0a 02 89 03 01 82 10 01 04 82 10 00 - result (RESET_ACK) = 0
Current NS-VCIs: VCI 0x2001, NSEI 0x2000, peer 0x01020304:1111 - NS-VC Block count : 2 + VCI 0x1001, NSEI 0x1000, peer 0x01020304:2222, blocked + NS-VC Block count : 3 NS-VC replaced other count: 1 - VCI 0x1001, NSEI 0x1000, peer 0x00000000:0, blocked - NS-VC Block count : 2
--- RESET_ACK with invalid NSEI, BSS -> SGSN ---
+MESSAGE to BSS, msg length 12 +02 00 81 01 01 82 10 01 04 82 10 00 + PROCESSING RESET_ACK from 0x01020304:2222 03 01 82 10 01 04 82 f0 00
-MESSAGE to BSS, msg length 15 -08 00 81 0a 02 89 03 01 82 10 01 04 82 f0 00 - -result (RESET_ACK) = 0 +==> got signal NS_MISMATCH: 0x1001/1.2.3.4:2222 pdu=3, ie=4 +result (RESET_ACK) = -22
Current NS-VCIs: VCI 0x2001, NSEI 0x2000, peer 0x01020304:1111 - NS-VC Block count : 2 + VCI 0x1001, NSEI 0x1000, peer 0x01020304:2222, blocked + NS-VC Block count : 3 NS-VC replaced other count: 1 - VCI 0x1001, NSEI 0x1000, peer 0x00000000:0, blocked - NS-VC Block count : 2 + NSEI was invalid count : 1
--- RESET_ACK with invalid NSVCI, BSS -> SGSN ---
+MESSAGE to BSS, msg length 12 +02 00 81 01 01 82 10 01 04 82 10 00 + PROCESSING RESET_ACK from 0x01020304:2222 03 01 82 f0 01 04 82 10 00
-MESSAGE to BSS, msg length 15 -08 00 81 0a 02 89 03 01 82 f0 01 04 82 10 00 - -result (RESET_ACK) = 0 +==> got signal NS_MISMATCH: 0x1001/1.2.3.4:2222 pdu=3, ie=1 +result (RESET_ACK) = -22
Current NS-VCIs: VCI 0x2001, NSEI 0x2000, peer 0x01020304:1111 - NS-VC Block count : 2 + VCI 0x1001, NSEI 0x1000, peer 0x01020304:2222, blocked + NS-VC Block count : 3 NS-VC replaced other count: 1 - VCI 0x1001, NSEI 0x1000, peer 0x00000000:0, blocked - NS-VC Block count : 2 + NS-VCI was invalid count : 1 + NSEI was invalid count : 1
Current NS-VCIs:
@@ -456,36 +439,33 @@ Current NS-VCIs: PROCESSING RESET from 0x05060708:32000 02 00 81 01 01 82 01 01 04 82 f0 00
-==> got signal NS_RESET, NS-VC 0x0101/5.6.7.8:32000 +==> got signal NS_MISMATCH: 0x0101/5.6.7.8:32000 pdu=2, ie=4 MESSAGE to SGSN, msg length 9 -03 01 82 01 01 04 82 f0 00 - -MESSAGE to SGSN, msg length 1 -0a +03 01 82 01 01 04 82 01 00
-result (RESET) = 9 +result (RESET) = 0
Current NS-VCIs: - VCI 0x0101, NSEI 0xf000, peer 0x05060708:32000, blocked + VCI 0x0101, NSEI 0x0100, peer 0x05060708:32000, blocked NS-VC Block count : 1 + NSEI was invalid count : 1
--- RESET with invalid NSVCI, SGSN -> BSS ---
PROCESSING RESET from 0x05060708:32000 02 00 81 01 01 82 f0 01 04 82 01 00
-==> got signal NS_RESET, NS-VC 0xf001/5.6.7.8:32000 +==> got signal NS_MISMATCH: 0x0101/5.6.7.8:32000 pdu=2, ie=1 MESSAGE to SGSN, msg length 9 -03 01 82 f0 01 04 82 01 00 - -MESSAGE to SGSN, msg length 1 -0a +03 01 82 01 01 04 82 01 00
-result (RESET) = 9 +result (RESET) = 0
Current NS-VCIs: - VCI 0xf001, NSEI 0x0100, peer 0x05060708:32000, blocked + VCI 0x0101, NSEI 0x0100, peer 0x05060708:32000, blocked NS-VC Block count : 1 + NS-VCI was invalid count : 1 + NSEI was invalid count : 1
Current NS-VCIs:
This adds a 'nsvc nsvci <0-65535> (block|unblock|reset)' vty command. It selects the NS-VC based on the nsvci instead of using the first with a matching NSEI, like it is done when the 'nsei' keyword is used instead.
Sponsored-by: On-Waves ehf --- src/gb/gprs_ns_vty.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-)
diff --git a/src/gb/gprs_ns_vty.c b/src/gb/gprs_ns_vty.c index a2e7beb..f33fd0b 100644 --- a/src/gb/gprs_ns_vty.c +++ b/src/gb/gprs_ns_vty.c @@ -499,21 +499,29 @@ DEFUN(cfg_frgre_enable, cfg_frgre_enable_cmd, }
DEFUN(nsvc_nsei, nsvc_nsei_cmd, - "nsvc nsei <0-65535> (block|unblock|reset)", + "nsvc (nsei|nsvci) <0-65535> (block|unblock|reset)", "Perform an operation on a NSVC\n" "NSEI to identify NS-VC Identifier (NS-VCI)\n" + "NS-VC Identifier (NS-VCI)\n" "The NSEI\n" "Initiate BLOCK procedure\n" "Initiate UNBLOCK procedure\n" "Initiate RESET procedure\n") { - uint16_t nsvci = atoi(argv[0]); - const char *operation = argv[1]; + const char *id_type = argv[0]; + uint16_t id = atoi(argv[1]); + const char *operation = argv[2]; struct gprs_nsvc *nsvc;
- nsvc = gprs_nsvc_by_nsei(vty_nsi, nsvci); + if (!strcmp(id_type, "nsei")) + nsvc = gprs_nsvc_by_nsei(vty_nsi, id); + else if (!strcmp(id_type, "nsvci")) + nsvc = gprs_nsvc_by_nsvci(vty_nsi, id); + else + return CMD_WARNING; + if (!nsvc) { - vty_out(vty, "No such NSVCI (%u)%s", nsvci, VTY_NEWLINE); + vty_out(vty, "No such %s (%u)%s", id_type, id, VTY_NEWLINE); return CMD_WARNING; }
Use 'config-ns' instead of plain 'ns' and append a blank after the '#' to make the vty python test script work.
Sponsored-by: On-Waves ehf --- src/gb/gprs_ns_vty.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/gb/gprs_ns_vty.c b/src/gb/gprs_ns_vty.c index f33fd0b..73277f8 100644 --- a/src/gb/gprs_ns_vty.c +++ b/src/gb/gprs_ns_vty.c @@ -71,7 +71,7 @@ static void log_set_nsvc_filter(struct log_target *target,
static struct cmd_node ns_node = { L_NS_NODE, - "%s(ns)#", + "%s(config-ns)# ", 1, };
This fixes a SEGV error that happens the next time the statistics are updated.
Addresses: Program terminated with signal 11, Segmentation fault. #0 0xb7711fa5 in rate_ctr_group_intv (grp=<optimized out>) at rate_ctr.c:107 107 for (i = 0; i < grp->desc->num_ctr; i++) { #0 0xb7711fa5 in rate_ctr_group_intv (grp=<optimized out>) at rate_ctr.c:107 #1 rate_ctr_timer_cb (data=0x0) at rate_ctr.c:129 #2 0xb770ec59 in osmo_timers_update () at timer.c:243 #3 0xb770ef7a in osmo_select_main (polling=0) at select.c:133 #4 0x08049987 in main (argc=3, argv=0xbfba8084) at gb_proxy_main.c:306
Sponsored-by: On-Waves ehf --- src/gb/gprs_ns.c | 1 + tests/gb/gprs_ns_test.c | 41 ++++++++++++++++++++++ tests/gb/gprs_ns_test.ok | 86 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 128 insertions(+)
diff --git a/src/gb/gprs_ns.c b/src/gb/gprs_ns.c index 6a35ad3..a4a6376 100644 --- a/src/gb/gprs_ns.c +++ b/src/gb/gprs_ns.c @@ -210,6 +210,7 @@ void gprs_nsvc_delete(struct gprs_nsvc *nsvc) if (osmo_timer_pending(&nsvc->timer)) osmo_timer_del(&nsvc->timer); llist_del(&nsvc->list); + rate_ctr_group_free(nsvc->ctrg); talloc_free(nsvc); }
diff --git a/tests/gb/gprs_ns_test.c b/tests/gb/gprs_ns_test.c index 38c7d1f..74eb701 100644 --- a/tests/gb/gprs_ns_test.c +++ b/tests/gb/gprs_ns_test.c @@ -8,6 +8,7 @@
#include <stdio.h> #include <stdlib.h> +#include <unistd.h> #include <stdint.h> #include <string.h> #include <getopt.h> @@ -439,6 +440,45 @@ static void gprs_dump_nsi(struct gprs_ns_inst *nsi) printf("\n"); }
+static void test_nsvc() +{ + struct gprs_ns_inst *nsi = gprs_ns_instantiate(gprs_ns_callback, NULL); + struct sockaddr_in peer[1] = {{0},}; + struct gprs_nsvc *nsvc; + int i; + + peer[0].sin_family = AF_INET; + peer[0].sin_port = htons(1111); + peer[0].sin_addr.s_addr = htonl(REMOTE_BSS_ADDR); + + for (i=0; i<4; ++i) { + printf("--- Create via RESET (round %d) ---\n\n", i); + + send_ns_reset(nsi, &peer[0], NS_CAUSE_OM_INTERVENTION, + 0x1001, 0x1000); + gprs_dump_nsi(nsi); + + printf("--- Delete nsvc object (round %d)---\n\n", i); + + nsvc = gprs_nsvc_by_nsvci(nsi, 0x1001); + OSMO_ASSERT(nsvc != NULL); + gprs_nsvc_delete(nsvc); + + gprs_dump_nsi(nsi); + } + + gprs_ns_destroy(nsi); + nsi = NULL; + + printf("--- Process timers ---\n\n"); + /* wait for rate_ctr_timer expiry */ + usleep(1100000); + /* ensure termination */ + alarm(2); + osmo_timers_update(); + alarm(0); +} + static void test_bss_port_changes() { struct gprs_ns_inst *nsi = gprs_ns_instantiate(gprs_ns_callback, NULL); @@ -568,6 +608,7 @@ int main(int argc, char **argv) osmo_signal_register_handler(SS_L_NS, &test_signal, NULL);
printf("===== NS protocol test START\n"); + test_nsvc(); test_bss_port_changes(); test_sgsn_output(); printf("===== NS protocol test END\n\n"); diff --git a/tests/gb/gprs_ns_test.ok b/tests/gb/gprs_ns_test.ok index 424d681..b5d578a 100644 --- a/tests/gb/gprs_ns_test.ok +++ b/tests/gb/gprs_ns_test.ok @@ -1,4 +1,90 @@ ===== NS protocol test START +--- Create via RESET (round 0) --- + +PROCESSING RESET from 0x01020304:1111 +02 00 81 01 01 82 10 01 04 82 10 00 + +==> got signal NS_RESET, NS-VC 0x1001/1.2.3.4:1111 +MESSAGE to BSS, msg length 9 +03 01 82 10 01 04 82 10 00 + +MESSAGE to BSS, msg length 1 +0a + +result (RESET) = 9 + +Current NS-VCIs: + VCI 0x1001, NSEI 0x1000, peer 0x01020304:1111, blocked + +--- Delete nsvc object (round 0)--- + +Current NS-VCIs: + +--- Create via RESET (round 1) --- + +PROCESSING RESET from 0x01020304:1111 +02 00 81 01 01 82 10 01 04 82 10 00 + +==> got signal NS_RESET, NS-VC 0x1001/1.2.3.4:1111 +MESSAGE to BSS, msg length 9 +03 01 82 10 01 04 82 10 00 + +MESSAGE to BSS, msg length 1 +0a + +result (RESET) = 9 + +Current NS-VCIs: + VCI 0x1001, NSEI 0x1000, peer 0x01020304:1111, blocked + +--- Delete nsvc object (round 1)--- + +Current NS-VCIs: + +--- Create via RESET (round 2) --- + +PROCESSING RESET from 0x01020304:1111 +02 00 81 01 01 82 10 01 04 82 10 00 + +==> got signal NS_RESET, NS-VC 0x1001/1.2.3.4:1111 +MESSAGE to BSS, msg length 9 +03 01 82 10 01 04 82 10 00 + +MESSAGE to BSS, msg length 1 +0a + +result (RESET) = 9 + +Current NS-VCIs: + VCI 0x1001, NSEI 0x1000, peer 0x01020304:1111, blocked + +--- Delete nsvc object (round 2)--- + +Current NS-VCIs: + +--- Create via RESET (round 3) --- + +PROCESSING RESET from 0x01020304:1111 +02 00 81 01 01 82 10 01 04 82 10 00 + +==> got signal NS_RESET, NS-VC 0x1001/1.2.3.4:1111 +MESSAGE to BSS, msg length 9 +03 01 82 10 01 04 82 10 00 + +MESSAGE to BSS, msg length 1 +0a + +result (RESET) = 9 + +Current NS-VCIs: + VCI 0x1001, NSEI 0x1000, peer 0x01020304:1111, blocked + +--- Delete nsvc object (round 3)--- + +Current NS-VCIs: + +--- Process timers --- + --- Setup, send BSSGP RESET ---
Setup NS-VC: remote 0x01020304:1111, NSVCI 0x1122(4386), NSEI 0x1122(4386)
Add a test handling proper and mismatching RESETs. The latter may occur, when ports change within a NS-VC without the SGSN getting notice.
This tests for the behavior of the NS protocol stack for RESET and RESET_ACK messages which changing/invalid NSEI and NSVCI like it is being described in 3GPP TS 08.16, 7.3.1.
Sponsored-by: On-Waves ehf --- tests/gb/gprs_ns_test.c | 218 +++++++++++++++++++++ tests/gb/gprs_ns_test.ok | 485 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 703 insertions(+)
diff --git a/tests/gb/gprs_ns_test.c b/tests/gb/gprs_ns_test.c index 74eb701..3d0293e 100644 --- a/tests/gb/gprs_ns_test.c +++ b/tests/gb/gprs_ns_test.c @@ -533,6 +533,217 @@ static void test_bss_port_changes() nsi = NULL; }
+static void test_bss_reset_ack() +{ + struct gprs_ns_inst *nsi = gprs_ns_instantiate(gprs_ns_callback, NULL); + struct sockaddr_in peer[4] = {{0},}; + struct gprs_nsvc *nsvc; + struct sockaddr_in *nse[4]; + int rc; + + peer[0].sin_family = AF_INET; + peer[0].sin_port = htons(1111); + peer[0].sin_addr.s_addr = htonl(REMOTE_BSS_ADDR); + peer[1].sin_family = AF_INET; + peer[1].sin_port = htons(2222); + peer[1].sin_addr.s_addr = htonl(REMOTE_BSS_ADDR); + peer[2].sin_family = AF_INET; + peer[2].sin_port = htons(3333); + peer[2].sin_addr.s_addr = htonl(REMOTE_BSS_ADDR); + peer[3].sin_family = AF_INET; + peer[3].sin_port = htons(4444); + peer[3].sin_addr.s_addr = htonl(REMOTE_BSS_ADDR); + + nse[0] = &peer[0]; + nse[1] = &peer[1]; + + printf("--- Setup VC 1 BSS -> SGSN ---\n\n"); + + setup_ns(nsi, nse[0], 0x1001, 0x1000); + gprs_dump_nsi(nsi); + + printf("--- Setup VC 2 BSS -> SGSN ---\n\n"); + + setup_ns(nsi, nse[1], 0x2001, 0x2000); + gprs_dump_nsi(nsi); + + printf("--- Setup VC 1 SGSN -> BSS ---\n\n"); + + nsvc = gprs_nsvc_by_nsvci(nsi, 0x1001); + gprs_ns_tx_reset(nsvc, NS_CAUSE_OM_INTERVENTION); + send_ns_reset_ack(nsi, nse[0], 0x1001, 0x1000); + gprs_dump_nsi(nsi); + + printf("--- Exchange NSEI 1 + 2 links ---\n\n"); + + nse[1] = &peer[0]; + nse[0] = &peer[1]; + + printf("--- Setup VC 2 SGSN -> BSS (hits NSEI 1) ---\n\n"); + + nsvc = gprs_nsvc_by_nsvci(nsi, 0x2001); + gprs_ns_tx_reset(nsvc, NS_CAUSE_OM_INTERVENTION); + send_ns_reset_ack(nsi, nse[0], 0x1001, 0x1000); + gprs_dump_nsi(nsi); + + printf("--- Setup VC 2 SGSN -> BSS (hits NSEI 2) ---\n\n"); + + nsvc = gprs_nsvc_by_nsvci(nsi, 0x2001); + rc = gprs_ns_tx_reset(nsvc, NS_CAUSE_OM_INTERVENTION); + if (rc < 0) + printf("Failed to send RESET to %s\n\n", gprs_ns_ll_str(nsvc)); + else { + send_ns_reset_ack(nsi, nse[1], 0x2001, 0x2000); + gprs_dump_nsi(nsi); + } + + printf("--- Setup VC 1 SGSN -> BSS (hits NSEI 1) ---\n\n"); + + nsvc = gprs_nsvc_by_nsvci(nsi, 0x1001); + gprs_ns_tx_reset(nsvc, NS_CAUSE_OM_INTERVENTION); + send_ns_reset_ack(nsi, nse[0], 0x1001, 0x1000); + gprs_dump_nsi(nsi); + + printf("--- Setup VC 2 BSS -> SGSN ---\n\n"); + + setup_ns(nsi, nse[1], 0x2001, 0x2000); + gprs_dump_nsi(nsi); + + /* Test 3GPP TS 08.16, 7.3.1, 3rd paragraph. */ + /* This is not rejected because the NSEI has been + * assigned dynamically and not by configuration. + * This is not strictly spec conformant. */ + + printf("--- RESET with invalid NSEI, BSS -> SGSN ---\n\n"); + + send_ns_reset(nsi, nse[0], NS_CAUSE_OM_INTERVENTION, + 0x1001, 0xf000); + gprs_dump_nsi(nsi); + + /* Test 3GPP TS 08.16, 7.3.1, 2nd paragraph. */ + /* This is not rejected because the NSEI has been + * assigned dynamically and not by configuration. + * This is not strictly spec conformant. */ + + printf("--- RESET with invalid NSVCI, BSS -> SGSN ---\n\n"); + + send_ns_reset(nsi, nse[0], NS_CAUSE_OM_INTERVENTION, + 0xf001, 0x1000); + gprs_dump_nsi(nsi); + + printf("--- RESET with old NSEI, NSVCI, BSS -> SGSN ---\n\n"); + + send_ns_reset(nsi, nse[0], NS_CAUSE_OM_INTERVENTION, + 0x1001, 0x1000); + gprs_dump_nsi(nsi); + + /* Test 3GPP TS 08.16, 7.3.1, 5th paragraph. */ + + printf("--- Unexpected RESET_ACK VC 1, BSS -> SGSN ---\n\n"); + + send_ns_reset_ack(nsi, nse[0], 0x1001, 0x1000); + gprs_dump_nsi(nsi); + + /* Test 3GPP TS 08.16, 7.3.1, 4th paragraph. */ + + printf("--- RESET_ACK with invalid NSEI, BSS -> SGSN ---\n\n"); + + nsvc = gprs_nsvc_by_nsvci(nsi, 0x1001); + gprs_ns_tx_reset(nsvc, NS_CAUSE_OM_INTERVENTION); + send_ns_reset_ack(nsi, nse[0], 0x1001, 0xf000); + gprs_dump_nsi(nsi); + + /* Test 3GPP TS 08.16, 7.3.1, 4th paragraph. */ + + printf("--- RESET_ACK with invalid NSVCI, BSS -> SGSN ---\n\n"); + + nsvc = gprs_nsvc_by_nsvci(nsi, 0x1001); + gprs_ns_tx_reset(nsvc, NS_CAUSE_OM_INTERVENTION); + send_ns_reset_ack(nsi, nse[0], 0xf001, 0x1000); + gprs_dump_nsi(nsi); + + gprs_ns_destroy(nsi); + nsi = NULL; +} + + +static void test_sgsn_reset() +{ + struct gprs_ns_inst *nsi = gprs_ns_instantiate(gprs_ns_callback, NULL); + struct sockaddr_in sgsn_peer= {0}; + struct gprs_nsvc *nsvc; + + sgsn_peer.sin_family = AF_INET; + sgsn_peer.sin_port = htons(32000); + sgsn_peer.sin_addr.s_addr = htonl(REMOTE_SGSN_ADDR); + + gprs_dump_nsi(nsi); + + printf("--- Setup SGSN connection, BSS -> SGSN ---\n\n"); + + gprs_ns_nsip_connect(nsi, &sgsn_peer, SGSN_NSEI, SGSN_NSEI+1); + send_ns_reset_ack(nsi, &sgsn_peer, SGSN_NSEI+1, SGSN_NSEI); + send_ns_alive_ack(nsi, &sgsn_peer); + send_ns_unblock_ack(nsi, &sgsn_peer); + gprs_dump_nsi(nsi); + + printf("--- RESET, SGSN -> BSS ---\n\n"); + + send_ns_reset(nsi, &sgsn_peer, NS_CAUSE_OM_INTERVENTION, + SGSN_NSEI+1, SGSN_NSEI); + gprs_dump_nsi(nsi); + + /* Test 3GPP TS 08.16, 7.3.1, 3rd paragraph. */ + + printf("--- RESET with invalid NSEI, SGSN -> BSS ---\n\n"); + + send_ns_reset(nsi, &sgsn_peer, NS_CAUSE_OM_INTERVENTION, + SGSN_NSEI+1, 0xf000); + gprs_dump_nsi(nsi); + + /* Test 3GPP TS 08.16, 7.3.1, 2nd paragraph. */ + + printf("--- RESET with invalid NSVCI, SGSN -> BSS ---\n\n"); + + send_ns_reset(nsi, &sgsn_peer, NS_CAUSE_OM_INTERVENTION, + 0xf001, SGSN_NSEI); + gprs_dump_nsi(nsi); + + printf("--- RESET, SGSN -> BSS ---\n\n"); + + send_ns_reset(nsi, &sgsn_peer, NS_CAUSE_OM_INTERVENTION, + SGSN_NSEI+1, SGSN_NSEI); + gprs_dump_nsi(nsi); + + /* Test 3GPP TS 08.16, 7.3.1, 5th paragraph. */ + + printf("--- Unexpected RESET_ACK VC 1, BSS -> SGSN ---\n\n"); + + send_ns_reset_ack(nsi, &sgsn_peer, SGSN_NSEI+1, SGSN_NSEI); + gprs_dump_nsi(nsi); + + /* Test 3GPP TS 08.16, 7.3.1, 4th paragraph. */ + + printf("--- RESET_ACK with invalid NSEI, BSS -> SGSN ---\n\n"); + + nsvc = gprs_nsvc_by_nsvci(nsi, SGSN_NSEI+1); + gprs_ns_tx_reset(nsvc, NS_CAUSE_OM_INTERVENTION); + send_ns_reset_ack(nsi, &sgsn_peer, SGSN_NSEI+1, 0xe000); + gprs_dump_nsi(nsi); + + /* Test 3GPP TS 08.16, 7.3.1, 4th paragraph. */ + + printf("--- RESET_ACK with invalid NSVCI, BSS -> SGSN ---\n\n"); + + nsvc = gprs_nsvc_by_nsvci(nsi, SGSN_NSEI+1); + gprs_ns_tx_reset(nsvc, NS_CAUSE_OM_INTERVENTION); + send_ns_reset_ack(nsi, &sgsn_peer, 0xe001, SGSN_NSEI); + gprs_dump_nsi(nsi); + + + gprs_ns_destroy(nsi); + nsi = NULL; +}
static void test_sgsn_output() { @@ -607,9 +818,16 @@ int main(int argc, char **argv) log_set_print_filename(osmo_stderr_target, 0); osmo_signal_register_handler(SS_L_NS, &test_signal, NULL);
+ log_set_print_filename(osmo_stderr_target, 0); + log_set_log_level(osmo_stderr_target, LOGL_INFO); + + setlinebuf(stdout); + printf("===== NS protocol test START\n"); test_nsvc(); test_bss_port_changes(); + test_bss_reset_ack(); + test_sgsn_reset(); test_sgsn_output(); printf("===== NS protocol test END\n\n");
diff --git a/tests/gb/gprs_ns_test.ok b/tests/gb/gprs_ns_test.ok index b5d578a..96fbd38 100644 --- a/tests/gb/gprs_ns_test.ok +++ b/tests/gb/gprs_ns_test.ok @@ -229,6 +229,491 @@ Current NS-VCIs: NS-VC replaced other count: 1 NS-VC changed NSEI : 2
+--- Setup VC 1 BSS -> SGSN --- + +Setup NS-VC: remote 0x01020304:1111, NSVCI 0x1001(4097), NSEI 0x1000(4096) + +PROCESSING RESET from 0x01020304:1111 +02 00 81 01 01 82 10 01 04 82 10 00 + +==> got signal NS_RESET, NS-VC 0x1001/1.2.3.4:1111 +MESSAGE to BSS, msg length 9 +03 01 82 10 01 04 82 10 00 + +MESSAGE to BSS, msg length 1 +0a + +result (RESET) = 9 + +PROCESSING ALIVE from 0x01020304:1111 +0a + +MESSAGE to BSS, msg length 1 +0b + +result (ALIVE) = 1 + +PROCESSING UNBLOCK from 0x01020304:1111 +06 + +==> got signal NS_UNBLOCK, NS-VC 0x1001/1.2.3.4:1111 +MESSAGE to BSS, msg length 1 +07 + +result (UNBLOCK) = 1 + +PROCESSING ALIVE_ACK from 0x01020304:1111 +0b + +result (ALIVE_ACK) = 0 + +Current NS-VCIs: + VCI 0x1001, NSEI 0x1000, peer 0x01020304:1111 + +--- Setup VC 2 BSS -> SGSN --- + +Setup NS-VC: remote 0x01020304:2222, NSVCI 0x2001(8193), NSEI 0x2000(8192) + +PROCESSING RESET from 0x01020304:2222 +02 00 81 01 01 82 20 01 04 82 20 00 + +==> got signal NS_RESET, NS-VC 0x2001/1.2.3.4:2222 +MESSAGE to BSS, msg length 9 +03 01 82 20 01 04 82 20 00 + +MESSAGE to BSS, msg length 1 +0a + +result (RESET) = 9 + +PROCESSING ALIVE from 0x01020304:2222 +0a + +MESSAGE to BSS, msg length 1 +0b + +result (ALIVE) = 1 + +PROCESSING UNBLOCK from 0x01020304:2222 +06 + +==> got signal NS_UNBLOCK, NS-VC 0x2001/1.2.3.4:2222 +MESSAGE to BSS, msg length 1 +07 + +result (UNBLOCK) = 1 + +PROCESSING ALIVE_ACK from 0x01020304:2222 +0b + +result (ALIVE_ACK) = 0 + +Current NS-VCIs: + VCI 0x2001, NSEI 0x2000, peer 0x01020304:2222 + VCI 0x1001, NSEI 0x1000, peer 0x01020304:1111 + +--- Setup VC 1 SGSN -> BSS --- + +MESSAGE to BSS, msg length 12 +02 00 81 01 01 82 10 01 04 82 10 00 + +PROCESSING RESET_ACK from 0x01020304:1111 +03 01 82 10 01 04 82 10 00 + +MESSAGE to BSS, msg length 1 +0a + +result (RESET_ACK) = 1 + +Current NS-VCIs: + VCI 0x2001, NSEI 0x2000, peer 0x01020304:2222 + VCI 0x1001, NSEI 0x1000, peer 0x01020304:1111, blocked + NS-VC Block count : 1 + +--- Exchange NSEI 1 + 2 links --- + +--- Setup VC 2 SGSN -> BSS (hits NSEI 1) --- + +MESSAGE to BSS, msg length 12 +02 00 81 01 01 82 20 01 04 82 20 00 + +PROCESSING RESET_ACK from 0x01020304:2222 +03 01 82 10 01 04 82 10 00 + +MESSAGE to BSS, msg length 1 +0a + +result (RESET_ACK) = 1 + +Current NS-VCIs: + VCI 0x2001, NSEI 0x2000, peer 0x01020304:2222, blocked + NS-VC Block count : 1 + VCI 0x1001, NSEI 0x1000, peer 0x01020304:1111, blocked + NS-VC Block count : 1 + +--- Setup VC 2 SGSN -> BSS (hits NSEI 2) --- + +MESSAGE to BSS, msg length 12 +02 00 81 01 01 82 20 01 04 82 20 00 + +PROCESSING RESET_ACK from 0x01020304:1111 +03 01 82 20 01 04 82 20 00 + +MESSAGE to BSS, msg length 1 +0a + +result (RESET_ACK) = 1 + +Current NS-VCIs: + VCI 0x2001, NSEI 0x2000, peer 0x01020304:2222, blocked + NS-VC Block count : 1 + VCI 0x1001, NSEI 0x1000, peer 0x01020304:1111, blocked + NS-VC Block count : 2 + +--- Setup VC 1 SGSN -> BSS (hits NSEI 1) --- + +MESSAGE to BSS, msg length 12 +02 00 81 01 01 82 10 01 04 82 10 00 + +PROCESSING RESET_ACK from 0x01020304:2222 +03 01 82 10 01 04 82 10 00 + +MESSAGE to BSS, msg length 1 +0a + +result (RESET_ACK) = 1 + +Current NS-VCIs: + VCI 0x2001, NSEI 0x2000, peer 0x01020304:2222, blocked + NS-VC Block count : 2 + VCI 0x1001, NSEI 0x1000, peer 0x01020304:1111, blocked + NS-VC Block count : 2 + +--- Setup VC 2 BSS -> SGSN --- + +Setup NS-VC: remote 0x01020304:1111, NSVCI 0x2001(8193), NSEI 0x2000(8192) + +PROCESSING RESET from 0x01020304:1111 +02 00 81 01 01 82 20 01 04 82 20 00 + +==> got signal NS_REPLACED: 0x2001/1.2.3.4:2222 -> 0x1001/1.2.3.4:1111 +==> got signal NS_RESET, NS-VC 0x2001/1.2.3.4:1111 +MESSAGE to BSS, msg length 9 +03 01 82 20 01 04 82 20 00 + +MESSAGE to BSS, msg length 1 +0a + +result (RESET) = 9 + +PROCESSING ALIVE from 0x01020304:1111 +0a + +MESSAGE to BSS, msg length 1 +0b + +result (ALIVE) = 1 + +PROCESSING UNBLOCK from 0x01020304:1111 +06 + +==> got signal NS_UNBLOCK, NS-VC 0x2001/1.2.3.4:1111 +MESSAGE to BSS, msg length 1 +07 + +result (UNBLOCK) = 1 + +PROCESSING ALIVE_ACK from 0x01020304:1111 +0b + +result (ALIVE_ACK) = 0 + +Current NS-VCIs: + VCI 0x2001, NSEI 0x2000, peer 0x01020304:1111 + NS-VC Block count : 2 + NS-VC replaced other count: 1 + VCI 0x1001, NSEI 0x1000, peer 0x00000000:0, blocked + NS-VC Block count : 2 + +--- RESET with invalid NSEI, BSS -> SGSN --- + +PROCESSING RESET from 0x01020304:2222 +02 00 81 01 01 82 10 01 04 82 f0 00 + +==> got signal NS_RESET, NS-VC 0x1001/1.2.3.4:2222 +MESSAGE to BSS, msg length 9 +03 01 82 10 01 04 82 f0 00 + +MESSAGE to BSS, msg length 1 +0a + +result (RESET) = 9 + +Current NS-VCIs: + VCI 0x2001, NSEI 0x2000, peer 0x01020304:1111 + NS-VC Block count : 2 + NS-VC replaced other count: 1 + VCI 0x1001, NSEI 0xf000, peer 0x01020304:2222, blocked + NS-VC Block count : 2 + NS-VC changed NSEI : 1 + +--- RESET with invalid NSVCI, BSS -> SGSN --- + +PROCESSING RESET from 0x01020304:2222 +02 00 81 01 01 82 f0 01 04 82 10 00 + +==> got signal NS_RESET, NS-VC 0xf001/1.2.3.4:2222 +MESSAGE to BSS, msg length 9 +03 01 82 f0 01 04 82 10 00 + +MESSAGE to BSS, msg length 1 +0a + +result (RESET) = 9 + +Current NS-VCIs: + VCI 0x2001, NSEI 0x2000, peer 0x01020304:1111 + NS-VC Block count : 2 + NS-VC replaced other count: 1 + VCI 0xf001, NSEI 0x1000, peer 0x01020304:2222, blocked + NS-VC Block count : 2 + NS-VC changed NSEI : 1 + +--- RESET with old NSEI, NSVCI, BSS -> SGSN --- + +PROCESSING RESET from 0x01020304:2222 +02 00 81 01 01 82 10 01 04 82 10 00 + +==> got signal NS_RESET, NS-VC 0x1001/1.2.3.4:2222 +MESSAGE to BSS, msg length 9 +03 01 82 10 01 04 82 10 00 + +MESSAGE to BSS, msg length 1 +0a + +result (RESET) = 9 + +Current NS-VCIs: + VCI 0x2001, NSEI 0x2000, peer 0x01020304:1111 + NS-VC Block count : 2 + NS-VC replaced other count: 1 + VCI 0x1001, NSEI 0x1000, peer 0x01020304:2222, blocked + NS-VC Block count : 2 + NS-VC changed NSEI : 1 + +--- Unexpected RESET_ACK VC 1, BSS -> SGSN --- + +PROCESSING RESET_ACK from 0x01020304:2222 +03 01 82 10 01 04 82 10 00 + +MESSAGE to BSS, msg length 1 +0a + +result (RESET_ACK) = 1 + +Current NS-VCIs: + VCI 0x2001, NSEI 0x2000, peer 0x01020304:1111 + NS-VC Block count : 2 + NS-VC replaced other count: 1 + VCI 0x1001, NSEI 0x1000, peer 0x01020304:2222, blocked + NS-VC Block count : 3 + NS-VC changed NSEI : 1 + +--- RESET_ACK with invalid NSEI, BSS -> SGSN --- + +MESSAGE to BSS, msg length 12 +02 00 81 01 01 82 10 01 04 82 10 00 + +PROCESSING RESET_ACK from 0x01020304:2222 +03 01 82 10 01 04 82 f0 00 + +MESSAGE to BSS, msg length 1 +0a + +result (RESET_ACK) = 1 + +Current NS-VCIs: + VCI 0x2001, NSEI 0x2000, peer 0x01020304:1111 + NS-VC Block count : 2 + NS-VC replaced other count: 1 + VCI 0x1001, NSEI 0x1000, peer 0x01020304:2222, blocked + NS-VC Block count : 4 + NS-VC changed NSEI : 1 + +--- RESET_ACK with invalid NSVCI, BSS -> SGSN --- + +MESSAGE to BSS, msg length 12 +02 00 81 01 01 82 10 01 04 82 10 00 + +PROCESSING RESET_ACK from 0x01020304:2222 +03 01 82 f0 01 04 82 10 00 + +MESSAGE to BSS, msg length 1 +0a + +result (RESET_ACK) = 1 + +Current NS-VCIs: + VCI 0x2001, NSEI 0x2000, peer 0x01020304:1111 + NS-VC Block count : 2 + NS-VC replaced other count: 1 + VCI 0x1001, NSEI 0x1000, peer 0x01020304:2222, blocked + NS-VC Block count : 5 + NS-VC changed NSEI : 1 + +Current NS-VCIs: + +--- Setup SGSN connection, BSS -> SGSN --- + +MESSAGE to SGSN, msg length 12 +02 00 81 01 01 82 01 01 04 82 01 00 + +PROCESSING RESET_ACK from 0x05060708:32000 +03 01 82 01 01 04 82 01 00 + +MESSAGE to SGSN, msg length 1 +0a + +result (RESET_ACK) = 1 + +PROCESSING ALIVE_ACK from 0x05060708:32000 +0b + +MESSAGE to SGSN, msg length 1 +06 + +result (ALIVE_ACK) = 1 + +PROCESSING UNBLOCK_ACK from 0x05060708:32000 +07 + +==> got signal NS_UNBLOCK, NS-VC 0x0101/5.6.7.8:32000 +result (UNBLOCK_ACK) = 0 + +Current NS-VCIs: + VCI 0x0101, NSEI 0x0100, peer 0x05060708:32000 + NS-VC Block count : 1 + +--- RESET, SGSN -> BSS --- + +PROCESSING RESET from 0x05060708:32000 +02 00 81 01 01 82 01 01 04 82 01 00 + +==> got signal NS_RESET, NS-VC 0x0101/5.6.7.8:32000 +MESSAGE to SGSN, msg length 9 +03 01 82 01 01 04 82 01 00 + +MESSAGE to SGSN, msg length 1 +0a + +result (RESET) = 9 + +Current NS-VCIs: + VCI 0x0101, NSEI 0x0100, peer 0x05060708:32000, blocked + NS-VC Block count : 1 + +--- RESET with invalid NSEI, SGSN -> BSS --- + +PROCESSING RESET from 0x05060708:32000 +02 00 81 01 01 82 01 01 04 82 f0 00 + +==> got signal NS_RESET, NS-VC 0x0101/5.6.7.8:32000 +MESSAGE to SGSN, msg length 9 +03 01 82 01 01 04 82 f0 00 + +MESSAGE to SGSN, msg length 1 +0a + +result (RESET) = 9 + +Current NS-VCIs: + VCI 0x0101, NSEI 0xf000, peer 0x05060708:32000, blocked + NS-VC Block count : 1 + +--- RESET with invalid NSVCI, SGSN -> BSS --- + +PROCESSING RESET from 0x05060708:32000 +02 00 81 01 01 82 f0 01 04 82 01 00 + +==> got signal NS_RESET, NS-VC 0xf001/5.6.7.8:32000 +MESSAGE to SGSN, msg length 9 +03 01 82 f0 01 04 82 01 00 + +MESSAGE to SGSN, msg length 1 +0a + +result (RESET) = 9 + +Current NS-VCIs: + VCI 0xf001, NSEI 0x0100, peer 0x05060708:32000, blocked + NS-VC Block count : 1 + +--- RESET, SGSN -> BSS --- + +PROCESSING RESET from 0x05060708:32000 +02 00 81 01 01 82 01 01 04 82 01 00 + +==> got signal NS_RESET, NS-VC 0x0101/5.6.7.8:32000 +MESSAGE to SGSN, msg length 9 +03 01 82 01 01 04 82 01 00 + +MESSAGE to SGSN, msg length 1 +0a + +result (RESET) = 9 + +Current NS-VCIs: + VCI 0x0101, NSEI 0x0100, peer 0x05060708:32000, blocked + NS-VC Block count : 1 + +--- Unexpected RESET_ACK VC 1, BSS -> SGSN --- + +PROCESSING RESET_ACK from 0x05060708:32000 +03 01 82 01 01 04 82 01 00 + +MESSAGE to SGSN, msg length 1 +0a + +result (RESET_ACK) = 1 + +Current NS-VCIs: + VCI 0x0101, NSEI 0x0100, peer 0x05060708:32000, blocked + NS-VC Block count : 2 + +--- RESET_ACK with invalid NSEI, BSS -> SGSN --- + +MESSAGE to SGSN, msg length 12 +02 00 81 01 01 82 01 01 04 82 01 00 + +PROCESSING RESET_ACK from 0x05060708:32000 +03 01 82 01 01 04 82 e0 00 + +MESSAGE to SGSN, msg length 1 +0a + +result (RESET_ACK) = 1 + +Current NS-VCIs: + VCI 0x0101, NSEI 0x0100, peer 0x05060708:32000, blocked + NS-VC Block count : 3 + +--- RESET_ACK with invalid NSVCI, BSS -> SGSN --- + +MESSAGE to SGSN, msg length 12 +02 00 81 01 01 82 01 01 04 82 01 00 + +PROCESSING RESET_ACK from 0x05060708:32000 +03 01 82 e0 01 04 82 01 00 + +MESSAGE to SGSN, msg length 1 +0a + +result (RESET_ACK) = 1 + +Current NS-VCIs: + VCI 0x0101, NSEI 0x0100, peer 0x05060708:32000, blocked + NS-VC Block count : 4 + Current NS-VCIs:
--- Send message to SGSN ---
This changes the implementations for the reception of RESET and RESET_ACK to be compatible with 3GPP TS 08.16, 7.3.1:
- Just send a RESET_ACK with correct values back to the SGSN when a RESET with an invalid NSVCI or NSEI has been received. - Check RESET_ACK for matching NSEI and NSVCI. - Ignore unexpected RESET_ACKs.
In addition, use RESET_ACK from a BSS to update the BSS source address based on the NSVCI to be tolerant with changing UDP source addresses/ports.
Sponsored-by: On-Waves ehf --- include/osmocom/gprs/gprs_ns.h | 5 + src/gb/gprs_ns.c | 271 +++++++++++++++++++++++++++++++--------- tests/gb/gprs_ns_test.c | 6 + tests/gb/gprs_ns_test.ok | 169 ++++++++++--------------- 4 files changed, 294 insertions(+), 157 deletions(-)
diff --git a/include/osmocom/gprs/gprs_ns.h b/include/osmocom/gprs/gprs_ns.h index b28c58d..296800e 100644 --- a/include/osmocom/gprs/gprs_ns.h +++ b/include/osmocom/gprs/gprs_ns.h @@ -36,6 +36,7 @@ enum ns_timeout {
#define NSE_S_BLOCKED 0x0001 #define NSE_S_ALIVE 0x0002 +#define NSE_S_RESET 0x0004
/*! \brief Osmocom NS link layer types */ enum gprs_ns_ll { @@ -199,12 +200,16 @@ enum signal_ns { S_NS_UNBLOCK, S_NS_ALIVE_EXP, /* Tns-alive expired more than N times */ S_NS_REPLACED, /* nsvc object is replaced (sets old_nsvc) */ + S_NS_MISMATCH, /* got an unexpected IE (sets msg, pdu_type, ie_type) */ };
struct ns_signal_data { struct gprs_nsvc *nsvc; struct gprs_nsvc *old_nsvc; uint8_t cause; + uint8_t pdu_type; + uint8_t ie_type; + struct msgb *msg; };
void gprs_ns_set_log_ss(int ss); diff --git a/src/gb/gprs_ns.c b/src/gb/gprs_ns.c index a4a6376..a597c2c 100644 --- a/src/gb/gprs_ns.c +++ b/src/gb/gprs_ns.c @@ -102,6 +102,8 @@ enum ns_ctr { NS_CTR_DEAD, NS_CTR_REPLACED, NS_CTR_NSEI_CHG, + NS_CTR_INV_VCI, + NS_CTR_INV_NSEI, };
static const struct rate_ctr_desc nsvc_ctr_description[] = { @@ -113,6 +115,8 @@ static const struct rate_ctr_desc nsvc_ctr_description[] = { { "dead", "NS-VC gone dead count " }, { "replaced", "NS-VC replaced other count" }, { "nsei-chg", "NS-VC changed NSEI " }, + { "inv-nsvci", "NS-VCI was invalid count " }, + { "inv-nsei", "NSEI was invalid count " }, };
static const struct rate_ctr_group_desc nsvc_ctrg_desc = { @@ -225,6 +229,20 @@ static void ns_osmo_signal_dispatch(struct gprs_nsvc *nsvc, unsigned int signal, osmo_signal_dispatch(SS_L_NS, signal, &nssd); }
+static void ns_osmo_signal_dispatch_mismatch(struct gprs_nsvc *nsvc, + struct msgb *msg, + uint8_t pdu_type, uint8_t ie_type) +{ + struct ns_signal_data nssd = {0}; + + nssd.nsvc = nsvc; + nssd.pdu_type = pdu_type; + nssd.ie_type = ie_type; + nssd.msg = msg; + + osmo_signal_dispatch(SS_L_NS, S_NS_MISMATCH, &nssd); +} + static void ns_osmo_signal_dispatch_replaced(struct gprs_nsvc *nsvc, struct gprs_nsvc *old_nsvc) { struct ns_signal_data nssd = {0}; @@ -323,6 +341,8 @@ int gprs_ns_tx_reset(struct gprs_nsvc *nsvc, uint8_t cause) LOGP(DNS, LOGL_INFO, "NSEI=%u Tx NS RESET (NSVCI=%u, cause=%s)\n", nsvc->nsei, nsvc->nsvci, gprs_ns_cause_str(cause));
+ nsvc->state |= NSE_S_RESET; + msg->l2h = msgb_put(msg, sizeof(*nsh)); nsh = (struct gprs_ns_hdr *) msg->l2h; nsh->pdu_type = NS_PDUT_RESET; @@ -672,6 +692,49 @@ static int gprs_ns_rx_status(struct gprs_nsvc *nsvc, struct msgb *msg) return 0; }
+/* Replace a nsvc object with another based on NSVCI. + * This function replaces looks for a NSVC with the given NSVCI and replaces it + * if possible and necessary. If replaced, the former value of *nsvc is + * returned in *old_nsvc. + * \return != 0 if *nsvc points to a matching NSVC. + */ +static int gprs_nsvc_replace_if_found(uint16_t nsvci, + struct gprs_nsvc **nsvc, + struct gprs_nsvc **old_nsvc) +{ + struct gprs_nsvc *matching_nsvc; + + if ((*nsvc)->nsvci == nsvci) { + *old_nsvc = NULL; + return 1; + } + + matching_nsvc = gprs_nsvc_by_nsvci((*nsvc)->nsi, nsvci); + + if (!matching_nsvc) + return 0; + + /* The NS-VCI is already used by this NS-VC */ + + char *old_peer; + + /* Exchange the NS-VC objects */ + *old_nsvc = *nsvc; + *nsvc = matching_nsvc; + + /* Do logging */ + old_peer = talloc_strdup(*old_nsvc, gprs_ns_ll_str(*old_nsvc)); + LOGP(DNS, LOGL_INFO, "NS-VC changed link (NSVCI=%u) from %s to %s\n", + nsvci, old_peer, gprs_ns_ll_str(*nsvc)); + + talloc_free(old_peer); + + /* Do statistics */ + rate_ctr_inc(&(*nsvc)->ctrg->ctr[NS_CTR_REPLACED]); + + return 1; +} + /* Section 7.3 */ static int gprs_ns_rx_reset(struct gprs_nsvc **nsvc, struct msgb *msg) { @@ -679,7 +742,7 @@ static int gprs_ns_rx_reset(struct gprs_nsvc **nsvc, struct msgb *msg) struct tlv_parsed tp; uint8_t cause; uint16_t nsvci, nsei; - struct gprs_nsvc *other_nsvc = NULL; + struct gprs_nsvc *orig_nsvc = NULL; int rc;
rc = tlv_parse(&tp, &ns_att_tlvdef, nsh->data, @@ -706,57 +769,47 @@ static int gprs_ns_rx_reset(struct gprs_nsvc **nsvc, struct msgb *msg) (*nsvc)->nsvci, (*nsvc)->nsvci_is_valid ? "" : "(invalid)", nsei, nsvci, gprs_ns_cause_str(cause));
- if ((*nsvc)->nsvci_is_valid && (*nsvc)->nsvci != nsvci) { - /* NS-VCI has changed */ - other_nsvc = gprs_nsvc_by_nsvci((*nsvc)->nsi, nsvci); - - if (other_nsvc) { - /* The NS-VCI is already used by this NS-VC */ - - struct gprs_nsvc *tmp_nsvc; - char *old_peer; - - /* Exchange the NS-VC objects */ - tmp_nsvc = *nsvc; - *nsvc = other_nsvc; - other_nsvc = tmp_nsvc; - - /* Do logging */ - old_peer = talloc_strdup(other_nsvc, - gprs_ns_ll_str(other_nsvc)); - LOGP(DNS, LOGL_INFO, - "NS-VC changed link (NSVCI=%u) from %s to %s\n", - nsvci, old_peer, gprs_ns_ll_str(*nsvc)); - - talloc_free(old_peer); - - /* Do statistics */ - rate_ctr_inc(&(*nsvc)->ctrg->ctr[NS_CTR_REPLACED]); + if (!(*nsvc)->nsvci_is_valid) { + /* It's a new uninitialised NS-VC, nothing to check here */ + } else if ((*nsvc)->nsvci != nsvci) { + if ((*nsvc)->remote_end_is_sgsn) { + /* The incoming RESET doesn't match the NSVCI. Send an + * appropriate RESET_ACK and ignore the RESET. + * See 3GPP TS 08.16, 7.3.1, 2nd paragraph. + */ + ns_osmo_signal_dispatch_mismatch(*nsvc, msg, + NS_PDUT_RESET, + NS_IE_VCI); + rate_ctr_inc(&(*nsvc)->ctrg->ctr[NS_CTR_INV_VCI]); + gprs_ns_tx_reset_ack(*nsvc); + return 0; } + + /* NS-VCI has changed */ + gprs_nsvc_replace_if_found(nsvci, nsvc, &orig_nsvc); + + } else if ((*nsvc)->nsei != nsei) { + /* The incoming RESET doesn't match the NSEI. Send an + * appropriate RESET_ACK and ignore the RESET. + * See 3GPP TS 08.16, 7.3.1, 3rd paragraph. + */ + ns_osmo_signal_dispatch_mismatch(*nsvc, msg, + NS_PDUT_RESET, + NS_IE_NSEI); + rate_ctr_inc(&(*nsvc)->ctrg->ctr[NS_CTR_INV_NSEI]); + gprs_ns_tx_reset_ack(*nsvc); + return 0; }
/* Mark NS-VC as blocked and alive */ (*nsvc)->state = NSE_S_BLOCKED | NSE_S_ALIVE;
- if (other_nsvc) { - /* Check NSEI */ - if ((*nsvc)->nsei != nsei) { - LOGP(DNS, LOGL_NOTICE, - "NS-VC changed NSEI (NSVCI=%u) from %u to %u\n", - nsvci, (*nsvc)->nsei, nsei); - - /* Override old NSEI */ - (*nsvc)->nsei = nsei; - - /* Do statistics */ - rate_ctr_inc(&(*nsvc)->ctrg->ctr[NS_CTR_NSEI_CHG]); - } - - ns_osmo_signal_dispatch_replaced(*nsvc, other_nsvc); + if (orig_nsvc) { + ns_osmo_signal_dispatch_replaced(*nsvc, orig_nsvc);
/* Update the ll info fields */ - gprs_ns_ll_copy(*nsvc, other_nsvc); - gprs_ns_ll_clear(other_nsvc); + gprs_ns_ll_copy(*nsvc, orig_nsvc); + gprs_ns_ll_clear(orig_nsvc); } else { (*nsvc)->nsei = nsei; (*nsvc)->nsvci = nsvci; @@ -776,6 +829,121 @@ static int gprs_ns_rx_reset(struct gprs_nsvc **nsvc, struct msgb *msg) return rc; }
+static int gprs_ns_rx_reset_ack(struct gprs_nsvc **nsvc, struct msgb *msg) +{ + struct gprs_ns_hdr *nsh = (struct gprs_ns_hdr *) msg->l2h; + struct tlv_parsed tp; + uint16_t nsvci, nsei; + struct gprs_nsvc *orig_nsvc = NULL; + int rc; + + rc = tlv_parse(&tp, &ns_att_tlvdef, nsh->data, + msgb_l2len(msg) - sizeof(*nsh), 0, 0); + if (rc < 0) { + LOGP(DNS, LOGL_ERROR, "NSEI=%u Rx NS RESET ACK " + "Error during TLV Parse\n", (*nsvc)->nsei); + return rc; + } + + if (!TLVP_PRESENT(&tp, NS_IE_VCI) || + !TLVP_PRESENT(&tp, NS_IE_NSEI)) { + LOGP(DNS, LOGL_ERROR, "NS RESET ACK Missing mandatory IE\n"); + gprs_ns_tx_status(*nsvc, NS_CAUSE_MISSING_ESSENT_IE, 0, msg); + return -EINVAL; + } + + nsvci = ntohs(*(uint16_t *) TLVP_VAL(&tp, NS_IE_VCI)); + nsei = ntohs(*(uint16_t *) TLVP_VAL(&tp, NS_IE_NSEI)); + + LOGP(DNS, LOGL_INFO, "NSVCI=%u%s Rx NS RESET ACK (NSEI=%u, NSVCI=%u)\n", + (*nsvc)->nsvci, (*nsvc)->nsvci_is_valid ? "" : "(invalid)", + nsei, nsvci); + + if (!((*nsvc)->state & NSE_S_RESET)) { + /* Not waiting for a RESET_ACK on this NS-VC, ignore it. + * See 3GPP TS 08.16, 7.3.1, 5th paragraph. + */ + LOGP(DNS, LOGL_ERROR, + "NS RESET ACK Discarding unexpected message for " + "NS-VCI %d from SGSN NSEI=%d\n", + nsvci, nsei); + return 0; + } + + if (!(*nsvc)->nsvci_is_valid) { + LOGP(DNS, LOGL_NOTICE, + "NS RESET ACK Uninitialised NS-VC (%u) for " + "NS-VCI %d, NSEI=%d from %s\n", + (*nsvc)->nsvci, nsvci, nsei, gprs_ns_ll_str(*nsvc)); + return -EINVAL; + } + + if ((*nsvc)->nsvci != nsvci) { + /* NS-VCI has changed */ + + /* if !0, use another NSVC object that matches the NSVCI */ + int use_other_nsvc; + + /* Only do this with BSS peers */ + use_other_nsvc = !(*nsvc)->remote_end_is_sgsn; + + if (use_other_nsvc) + /* Update *nsvc to point to the right NSVC object */ + use_other_nsvc = gprs_nsvc_replace_if_found(nsvci, nsvc, + &orig_nsvc); + + if (!use_other_nsvc) { + /* The incoming RESET_ACK doesn't match the NSVCI. + * See 3GPP TS 08.16, 7.3.1, 4th paragraph. + */ + ns_osmo_signal_dispatch_mismatch(*nsvc, msg, + NS_PDUT_RESET_ACK, + NS_IE_VCI); + rate_ctr_inc(&(*nsvc)->ctrg->ctr[NS_CTR_INV_VCI]); + LOGP(DNS, LOGL_ERROR, + "NS RESET ACK Unknown NS-VCI %d (%s NSEI=%d) " + "from %s\n", + nsvci, + (*nsvc)->remote_end_is_sgsn ? "SGSN" : "BSS", + nsei, gprs_ns_ll_str(*nsvc)); + return -EINVAL; + } + + /* Notify others */ + ns_osmo_signal_dispatch_replaced(*nsvc, orig_nsvc); + + /* Update the ll info fields */ + gprs_ns_ll_copy(*nsvc, orig_nsvc); + gprs_ns_ll_clear(orig_nsvc); + } else if ((*nsvc)->nsei != nsei) { + /* The incoming RESET_ACK doesn't match the NSEI. + * See 3GPP TS 08.16, 7.3.1, 4th paragraph. + */ + ns_osmo_signal_dispatch_mismatch(*nsvc, msg, + NS_PDUT_RESET_ACK, + NS_IE_NSEI); + rate_ctr_inc(&(*nsvc)->ctrg->ctr[NS_CTR_INV_NSEI]); + LOGP(DNS, LOGL_ERROR, + "NS RESET ACK Unknown NSEI %d (NS-VCI=%u) from %s\n", + nsei, nsvci, gprs_ns_ll_str(*nsvc)); + return -EINVAL; + } + + /* Mark NS-VC as blocked and alive */ + (*nsvc)->state = NSE_S_BLOCKED | NSE_S_ALIVE; + (*nsvc)->remote_state = NSE_S_BLOCKED | NSE_S_ALIVE; + rate_ctr_inc(&(*nsvc)->ctrg->ctr[NS_CTR_BLOCKED]); + if ((*nsvc)->persistent || (*nsvc)->remote_end_is_sgsn) { + /* stop RESET timer */ + osmo_timer_del(&(*nsvc)->timer); + } + /* Initiate TEST proc.: Send ALIVE and start timer */ + rc = gprs_ns_tx_simple(*nsvc, NS_PDUT_ALIVE); + nsvc_start_timer(*nsvc, NSVC_TIMER_TNS_TEST); + + return rc; +} + static int gprs_ns_rx_block(struct gprs_nsvc *nsvc, struct msgb *msg) { struct gprs_ns_hdr *nsh = (struct gprs_ns_hdr *) msg->l2h; @@ -944,6 +1112,7 @@ int gprs_ns_vc_create(struct gprs_ns_inst *nsi, struct msgb *msg, "from %s for non-existing NS-VC\n", nsh->pdu_type, gprs_ns_ll_str(fallback_nsvc)); fallback_nsvc->nsvci = fallback_nsvc->nsei = 0xfffe; + fallback_nsvc->nsvci_is_valid = 0; fallback_nsvc->state = NSE_S_ALIVE;
rc = gprs_ns_tx_status(fallback_nsvc, @@ -1057,18 +1226,7 @@ int gprs_ns_process_msg(struct gprs_ns_inst *nsi, struct msgb *msg, rc = gprs_ns_rx_reset(nsvc, msg); break; case NS_PDUT_RESET_ACK: - LOGP(DNS, LOGL_INFO, "NSEI=%u Rx NS RESET ACK\n", (*nsvc)->nsei); - /* mark NS-VC as blocked + active */ - (*nsvc)->state = NSE_S_BLOCKED | NSE_S_ALIVE; - (*nsvc)->remote_state = NSE_S_BLOCKED | NSE_S_ALIVE; - rate_ctr_inc(&(*nsvc)->ctrg->ctr[NS_CTR_BLOCKED]); - if ((*nsvc)->persistent || (*nsvc)->remote_end_is_sgsn) { - /* stop RESET timer */ - osmo_timer_del(&(*nsvc)->timer); - } - /* Initiate TEST proc.: Send ALIVE and start timer */ - rc = gprs_ns_tx_simple(*nsvc, NS_PDUT_ALIVE); - nsvc_start_timer(*nsvc, NSVC_TIMER_TNS_TEST); + rc = gprs_ns_rx_reset_ack(nsvc, msg); break; case NS_PDUT_UNBLOCK: /* Section 7.2: unblocking procedure */ @@ -1323,6 +1481,7 @@ struct gprs_nsvc *gprs_ns_nsip_connect(struct gprs_ns_inst *nsi, nsvc->ip.bts_addr = *dest; nsvc->nsei = nsei; nsvc->nsvci = nsvci; + nsvc->nsvci_is_valid = 1; nsvc->remote_end_is_sgsn = 1;
gprs_nsvc_reset(nsvc, NS_CAUSE_OM_INTERVENTION); diff --git a/tests/gb/gprs_ns_test.c b/tests/gb/gprs_ns_test.c index 3d0293e..546c20a 100644 --- a/tests/gb/gprs_ns_test.c +++ b/tests/gb/gprs_ns_test.c @@ -357,6 +357,12 @@ static int test_signal(unsigned int subsys, unsigned int signal, gprs_ns_ll_str(nssd->old_nsvc)); break;
+ case S_NS_MISMATCH: + printf("==> got signal NS_MISMATCH: 0x%04x/%s pdu=%d, ie=%d\n", + nssd->nsvc->nsvci, gprs_ns_ll_str(nssd->nsvc), + nssd->pdu_type, nssd->ie_type); + break; + default: printf("==> got signal %d, NS-VC 0x%04x/%s\n", signal, nssd->nsvc->nsvci, diff --git a/tests/gb/gprs_ns_test.ok b/tests/gb/gprs_ns_test.ok index 96fbd38..a882488 100644 --- a/tests/gb/gprs_ns_test.ok +++ b/tests/gb/gprs_ns_test.ok @@ -196,7 +196,7 @@ PROCESSING RESET from 0x01020304:3333 ==> got signal NS_REPLACED: 0x1122/1.2.3.4:4444 -> 0x3344/1.2.3.4:3333 ==> got signal NS_RESET, NS-VC 0x1122/1.2.3.4:3333 MESSAGE to BSS, msg length 9 -03 01 82 11 22 04 82 11 22 +03 01 82 11 22 04 82 33 44
MESSAGE to BSS, msg length 1 0a @@ -205,9 +205,9 @@ result (RESET) = 9
Current NS-VCIs: VCI 0x3344, NSEI 0x1122, peer 0x00000000:0, blocked - VCI 0x1122, NSEI 0x1122, peer 0x01020304:3333, blocked + VCI 0x1122, NSEI 0x3344, peer 0x01020304:3333, blocked NS-VC replaced other count: 1 - NS-VC changed NSEI : 2 + NS-VC changed NSEI : 1
--- Peer port 4444, RESET, NSEI is changed back ---
@@ -340,35 +340,21 @@ MESSAGE to BSS, msg length 12 PROCESSING RESET_ACK from 0x01020304:2222 03 01 82 10 01 04 82 10 00
+==> got signal NS_REPLACED: 0x1001/1.2.3.4:1111 -> 0x2001/1.2.3.4:2222 MESSAGE to BSS, msg length 1 0a
result (RESET_ACK) = 1
Current NS-VCIs: - VCI 0x2001, NSEI 0x2000, peer 0x01020304:2222, blocked - NS-VC Block count : 1 - VCI 0x1001, NSEI 0x1000, peer 0x01020304:1111, blocked - NS-VC Block count : 1 + VCI 0x2001, NSEI 0x2000, peer 0x00000000:0 + VCI 0x1001, NSEI 0x1000, peer 0x01020304:2222, blocked + NS-VC Block count : 2 + NS-VC replaced other count: 1
--- Setup VC 2 SGSN -> BSS (hits NSEI 2) ---
-MESSAGE to BSS, msg length 12 -02 00 81 01 01 82 20 01 04 82 20 00 - -PROCESSING RESET_ACK from 0x01020304:1111 -03 01 82 20 01 04 82 20 00 - -MESSAGE to BSS, msg length 1 -0a - -result (RESET_ACK) = 1 - -Current NS-VCIs: - VCI 0x2001, NSEI 0x2000, peer 0x01020304:2222, blocked - NS-VC Block count : 1 - VCI 0x1001, NSEI 0x1000, peer 0x01020304:1111, blocked - NS-VC Block count : 2 +Failed to send RESET to 0.0.0.0:0
--- Setup VC 1 SGSN -> BSS (hits NSEI 1) ---
@@ -384,10 +370,10 @@ MESSAGE to BSS, msg length 1 result (RESET_ACK) = 1
Current NS-VCIs: - VCI 0x2001, NSEI 0x2000, peer 0x01020304:2222, blocked - NS-VC Block count : 2 - VCI 0x1001, NSEI 0x1000, peer 0x01020304:1111, blocked - NS-VC Block count : 2 + VCI 0x2001, NSEI 0x2000, peer 0x00000000:0 + VCI 0x1001, NSEI 0x1000, peer 0x01020304:2222, blocked + NS-VC Block count : 3 + NS-VC replaced other count: 1
--- Setup VC 2 BSS -> SGSN ---
@@ -396,7 +382,6 @@ Setup NS-VC: remote 0x01020304:1111, NSVCI 0x2001(8193), NSEI 0x2000(8192) PROCESSING RESET from 0x01020304:1111 02 00 81 01 01 82 20 01 04 82 20 00
-==> got signal NS_REPLACED: 0x2001/1.2.3.4:2222 -> 0x1001/1.2.3.4:1111 ==> got signal NS_RESET, NS-VC 0x2001/1.2.3.4:1111 MESSAGE to BSS, msg length 9 03 01 82 20 01 04 82 20 00 @@ -430,32 +415,27 @@ result (ALIVE_ACK) = 0
Current NS-VCIs: VCI 0x2001, NSEI 0x2000, peer 0x01020304:1111 - NS-VC Block count : 2 + VCI 0x1001, NSEI 0x1000, peer 0x01020304:2222, blocked + NS-VC Block count : 3 NS-VC replaced other count: 1 - VCI 0x1001, NSEI 0x1000, peer 0x00000000:0, blocked - NS-VC Block count : 2
--- RESET with invalid NSEI, BSS -> SGSN ---
PROCESSING RESET from 0x01020304:2222 02 00 81 01 01 82 10 01 04 82 f0 00
-==> got signal NS_RESET, NS-VC 0x1001/1.2.3.4:2222 +==> got signal NS_MISMATCH: 0x1001/1.2.3.4:2222 pdu=2, ie=4 MESSAGE to BSS, msg length 9 -03 01 82 10 01 04 82 f0 00 +03 01 82 10 01 04 82 10 00
-MESSAGE to BSS, msg length 1 -0a - -result (RESET) = 9 +result (RESET) = 0
Current NS-VCIs: VCI 0x2001, NSEI 0x2000, peer 0x01020304:1111 - NS-VC Block count : 2 + VCI 0x1001, NSEI 0x1000, peer 0x01020304:2222, blocked + NS-VC Block count : 3 NS-VC replaced other count: 1 - VCI 0x1001, NSEI 0xf000, peer 0x01020304:2222, blocked - NS-VC Block count : 2 - NS-VC changed NSEI : 1 + NSEI was invalid count : 1
--- RESET with invalid NSVCI, BSS -> SGSN ---
@@ -473,11 +453,10 @@ result (RESET) = 9
Current NS-VCIs: VCI 0x2001, NSEI 0x2000, peer 0x01020304:1111 - NS-VC Block count : 2 - NS-VC replaced other count: 1 VCI 0xf001, NSEI 0x1000, peer 0x01020304:2222, blocked - NS-VC Block count : 2 - NS-VC changed NSEI : 1 + NS-VC Block count : 3 + NS-VC replaced other count: 1 + NSEI was invalid count : 1
--- RESET with old NSEI, NSVCI, BSS -> SGSN ---
@@ -495,29 +474,24 @@ result (RESET) = 9
Current NS-VCIs: VCI 0x2001, NSEI 0x2000, peer 0x01020304:1111 - NS-VC Block count : 2 - NS-VC replaced other count: 1 VCI 0x1001, NSEI 0x1000, peer 0x01020304:2222, blocked - NS-VC Block count : 2 - NS-VC changed NSEI : 1 + NS-VC Block count : 3 + NS-VC replaced other count: 1 + NSEI was invalid count : 1
--- Unexpected RESET_ACK VC 1, BSS -> SGSN ---
PROCESSING RESET_ACK from 0x01020304:2222 03 01 82 10 01 04 82 10 00
-MESSAGE to BSS, msg length 1 -0a - -result (RESET_ACK) = 1 +result (RESET_ACK) = 0
Current NS-VCIs: VCI 0x2001, NSEI 0x2000, peer 0x01020304:1111 - NS-VC Block count : 2 - NS-VC replaced other count: 1 VCI 0x1001, NSEI 0x1000, peer 0x01020304:2222, blocked NS-VC Block count : 3 - NS-VC changed NSEI : 1 + NS-VC replaced other count: 1 + NSEI was invalid count : 1
--- RESET_ACK with invalid NSEI, BSS -> SGSN ---
@@ -527,18 +501,15 @@ MESSAGE to BSS, msg length 12 PROCESSING RESET_ACK from 0x01020304:2222 03 01 82 10 01 04 82 f0 00
-MESSAGE to BSS, msg length 1 -0a - -result (RESET_ACK) = 1 +==> got signal NS_MISMATCH: 0x1001/1.2.3.4:2222 pdu=3, ie=4 +result (RESET_ACK) = -22
Current NS-VCIs: VCI 0x2001, NSEI 0x2000, peer 0x01020304:1111 - NS-VC Block count : 2 - NS-VC replaced other count: 1 VCI 0x1001, NSEI 0x1000, peer 0x01020304:2222, blocked - NS-VC Block count : 4 - NS-VC changed NSEI : 1 + NS-VC Block count : 3 + NS-VC replaced other count: 1 + NSEI was invalid count : 2
--- RESET_ACK with invalid NSVCI, BSS -> SGSN ---
@@ -548,18 +519,16 @@ MESSAGE to BSS, msg length 12 PROCESSING RESET_ACK from 0x01020304:2222 03 01 82 f0 01 04 82 10 00
-MESSAGE to BSS, msg length 1 -0a - -result (RESET_ACK) = 1 +==> got signal NS_MISMATCH: 0x1001/1.2.3.4:2222 pdu=3, ie=1 +result (RESET_ACK) = -22
Current NS-VCIs: VCI 0x2001, NSEI 0x2000, peer 0x01020304:1111 - NS-VC Block count : 2 - NS-VC replaced other count: 1 VCI 0x1001, NSEI 0x1000, peer 0x01020304:2222, blocked - NS-VC Block count : 5 - NS-VC changed NSEI : 1 + NS-VC Block count : 3 + NS-VC replaced other count: 1 + NS-VCI was invalid count : 1 + NSEI was invalid count : 2
Current NS-VCIs:
@@ -617,36 +586,33 @@ Current NS-VCIs: PROCESSING RESET from 0x05060708:32000 02 00 81 01 01 82 01 01 04 82 f0 00
-==> got signal NS_RESET, NS-VC 0x0101/5.6.7.8:32000 +==> got signal NS_MISMATCH: 0x0101/5.6.7.8:32000 pdu=2, ie=4 MESSAGE to SGSN, msg length 9 -03 01 82 01 01 04 82 f0 00 - -MESSAGE to SGSN, msg length 1 -0a +03 01 82 01 01 04 82 01 00
-result (RESET) = 9 +result (RESET) = 0
Current NS-VCIs: - VCI 0x0101, NSEI 0xf000, peer 0x05060708:32000, blocked + VCI 0x0101, NSEI 0x0100, peer 0x05060708:32000, blocked NS-VC Block count : 1 + NSEI was invalid count : 1
--- RESET with invalid NSVCI, SGSN -> BSS ---
PROCESSING RESET from 0x05060708:32000 02 00 81 01 01 82 f0 01 04 82 01 00
-==> got signal NS_RESET, NS-VC 0xf001/5.6.7.8:32000 +==> got signal NS_MISMATCH: 0x0101/5.6.7.8:32000 pdu=2, ie=1 MESSAGE to SGSN, msg length 9 -03 01 82 f0 01 04 82 01 00 - -MESSAGE to SGSN, msg length 1 -0a +03 01 82 01 01 04 82 01 00
-result (RESET) = 9 +result (RESET) = 0
Current NS-VCIs: - VCI 0xf001, NSEI 0x0100, peer 0x05060708:32000, blocked + VCI 0x0101, NSEI 0x0100, peer 0x05060708:32000, blocked NS-VC Block count : 1 + NS-VCI was invalid count : 1 + NSEI was invalid count : 1
--- RESET, SGSN -> BSS ---
@@ -665,20 +631,21 @@ result (RESET) = 9 Current NS-VCIs: VCI 0x0101, NSEI 0x0100, peer 0x05060708:32000, blocked NS-VC Block count : 1 + NS-VCI was invalid count : 1 + NSEI was invalid count : 1
--- Unexpected RESET_ACK VC 1, BSS -> SGSN ---
PROCESSING RESET_ACK from 0x05060708:32000 03 01 82 01 01 04 82 01 00
-MESSAGE to SGSN, msg length 1 -0a - -result (RESET_ACK) = 1 +result (RESET_ACK) = 0
Current NS-VCIs: VCI 0x0101, NSEI 0x0100, peer 0x05060708:32000, blocked - NS-VC Block count : 2 + NS-VC Block count : 1 + NS-VCI was invalid count : 1 + NSEI was invalid count : 1
--- RESET_ACK with invalid NSEI, BSS -> SGSN ---
@@ -688,14 +655,14 @@ MESSAGE to SGSN, msg length 12 PROCESSING RESET_ACK from 0x05060708:32000 03 01 82 01 01 04 82 e0 00
-MESSAGE to SGSN, msg length 1 -0a - -result (RESET_ACK) = 1 +==> got signal NS_MISMATCH: 0x0101/5.6.7.8:32000 pdu=3, ie=4 +result (RESET_ACK) = -22
Current NS-VCIs: VCI 0x0101, NSEI 0x0100, peer 0x05060708:32000, blocked - NS-VC Block count : 3 + NS-VC Block count : 1 + NS-VCI was invalid count : 1 + NSEI was invalid count : 2
--- RESET_ACK with invalid NSVCI, BSS -> SGSN ---
@@ -705,14 +672,14 @@ MESSAGE to SGSN, msg length 12 PROCESSING RESET_ACK from 0x05060708:32000 03 01 82 e0 01 04 82 01 00
-MESSAGE to SGSN, msg length 1 -0a - -result (RESET_ACK) = 1 +==> got signal NS_MISMATCH: 0x0101/5.6.7.8:32000 pdu=3, ie=1 +result (RESET_ACK) = -22
Current NS-VCIs: VCI 0x0101, NSEI 0x0100, peer 0x05060708:32000, blocked - NS-VC Block count : 4 + NS-VC Block count : 1 + NS-VCI was invalid count : 2 + NSEI was invalid count : 2
Current NS-VCIs:
This modifies the NS stack's behavior to accept RESET and RESET_ACK NSEI changes for NS-VC dynamically created by RESET messages from BSSes. This feature is not used for NS-VC configured via VTY or NS-VC to a SGSN.
Sponsored-by: On-Waves ehf --- src/gb/gprs_ns.c | 68 +++++++++++++++++++++++++++------------------- tests/gb/gprs_ns_test.ok | 49 ++++++++++++++++++--------------- 2 files changed, 67 insertions(+), 50 deletions(-)
diff --git a/src/gb/gprs_ns.c b/src/gb/gprs_ns.c index a597c2c..043a66c 100644 --- a/src/gb/gprs_ns.c +++ b/src/gb/gprs_ns.c @@ -114,7 +114,7 @@ static const struct rate_ctr_desc nsvc_ctr_description[] = { { "blocked", "NS-VC Block count " }, { "dead", "NS-VC gone dead count " }, { "replaced", "NS-VC replaced other count" }, - { "nsei-chg", "NS-VC changed NSEI " }, + { "nsei-chg", "NS-VC changed NSEI count " }, { "inv-nsvci", "NS-VCI was invalid count " }, { "inv-nsei", "NSEI was invalid count " }, }; @@ -769,10 +769,8 @@ static int gprs_ns_rx_reset(struct gprs_nsvc **nsvc, struct msgb *msg) (*nsvc)->nsvci, (*nsvc)->nsvci_is_valid ? "" : "(invalid)", nsei, nsvci, gprs_ns_cause_str(cause));
- if (!(*nsvc)->nsvci_is_valid) { - /* It's a new uninitialised NS-VC, nothing to check here */ - } else if ((*nsvc)->nsvci != nsvci) { - if ((*nsvc)->remote_end_is_sgsn) { + if ((*nsvc)->nsvci_is_valid && (*nsvc)->nsvci != nsvci) { + if ((*nsvc)->persistent || (*nsvc)->remote_end_is_sgsn) { /* The incoming RESET doesn't match the NSVCI. Send an * appropriate RESET_ACK and ignore the RESET. * See 3GPP TS 08.16, 7.3.1, 2nd paragraph. @@ -787,18 +785,25 @@ static int gprs_ns_rx_reset(struct gprs_nsvc **nsvc, struct msgb *msg)
/* NS-VCI has changed */ gprs_nsvc_replace_if_found(nsvci, nsvc, &orig_nsvc); + }
- } else if ((*nsvc)->nsei != nsei) { - /* The incoming RESET doesn't match the NSEI. Send an - * appropriate RESET_ACK and ignore the RESET. - * See 3GPP TS 08.16, 7.3.1, 3rd paragraph. - */ - ns_osmo_signal_dispatch_mismatch(*nsvc, msg, - NS_PDUT_RESET, - NS_IE_NSEI); - rate_ctr_inc(&(*nsvc)->ctrg->ctr[NS_CTR_INV_NSEI]); - gprs_ns_tx_reset_ack(*nsvc); - return 0; + if ((*nsvc)->nsvci_is_valid && (*nsvc)->nsei != nsei) { + if ((*nsvc)->persistent || (*nsvc)->remote_end_is_sgsn) { + /* The incoming RESET doesn't match the NSEI. Send an + * appropriate RESET_ACK and ignore the RESET. + * See 3GPP TS 08.16, 7.3.1, 3rd paragraph. + */ + ns_osmo_signal_dispatch_mismatch(*nsvc, msg, + NS_PDUT_RESET, + NS_IE_NSEI); + rate_ctr_inc(&(*nsvc)->ctrg->ctr[NS_CTR_INV_NSEI]); + gprs_ns_tx_reset_ack(*nsvc); + return 0; + } + + /* NSEI has changed */ + rate_ctr_inc(&(*nsvc)->ctrg->ctr[NS_CTR_NSEI_CHG]); + (*nsvc)->nsei = nsei; }
/* Mark NS-VC as blocked and alive */ @@ -885,7 +890,8 @@ static int gprs_ns_rx_reset_ack(struct gprs_nsvc **nsvc, struct msgb *msg) int use_other_nsvc;
/* Only do this with BSS peers */ - use_other_nsvc = !(*nsvc)->remote_end_is_sgsn; + use_other_nsvc = !(*nsvc)->remote_end_is_sgsn && + !(*nsvc)->persistent;
if (use_other_nsvc) /* Update *nsvc to point to the right NSVC object */ @@ -916,17 +922,23 @@ static int gprs_ns_rx_reset_ack(struct gprs_nsvc **nsvc, struct msgb *msg) gprs_ns_ll_copy(*nsvc, orig_nsvc); gprs_ns_ll_clear(orig_nsvc); } else if ((*nsvc)->nsei != nsei) { - /* The incoming RESET_ACK doesn't match the NSEI. - * See 3GPP TS 08.16, 7.3.1, 4th paragraph. - */ - ns_osmo_signal_dispatch_mismatch(*nsvc, msg, - NS_PDUT_RESET_ACK, - NS_IE_NSEI); - rate_ctr_inc(&(*nsvc)->ctrg->ctr[NS_CTR_INV_NSEI]); - LOGP(DNS, LOGL_ERROR, - "NS RESET ACK Unknown NSEI %d (NS-VCI=%u) from %s\n", - nsei, nsvci, gprs_ns_ll_str(*nsvc)); - return -EINVAL; + if ((*nsvc)->persistent || (*nsvc)->remote_end_is_sgsn) { + /* The incoming RESET_ACK doesn't match the NSEI. + * See 3GPP TS 08.16, 7.3.1, 4th paragraph. + */ + ns_osmo_signal_dispatch_mismatch(*nsvc, msg, + NS_PDUT_RESET_ACK, + NS_IE_NSEI); + rate_ctr_inc(&(*nsvc)->ctrg->ctr[NS_CTR_INV_NSEI]); + LOGP(DNS, LOGL_ERROR, + "NS RESET ACK Unknown NSEI %d (NS-VCI=%u) from %s\n", + nsei, nsvci, gprs_ns_ll_str(*nsvc)); + return -EINVAL; + } + + /* NSEI has changed */ + rate_ctr_inc(&(*nsvc)->ctrg->ctr[NS_CTR_NSEI_CHG]); + (*nsvc)->nsei = nsei; }
/* Mark NS-VC as blocked and alive */ diff --git a/tests/gb/gprs_ns_test.ok b/tests/gb/gprs_ns_test.ok index a882488..5f90d03 100644 --- a/tests/gb/gprs_ns_test.ok +++ b/tests/gb/gprs_ns_test.ok @@ -186,7 +186,7 @@ result (RESET) = 9 Current NS-VCIs: VCI 0x3344, NSEI 0x1122, peer 0x01020304:3333, blocked VCI 0x1122, NSEI 0x3344, peer 0x01020304:4444, blocked - NS-VC changed NSEI : 1 + NS-VC changed NSEI count : 1
--- Peer port 3333, RESET, VCI is changed back ---
@@ -196,7 +196,7 @@ PROCESSING RESET from 0x01020304:3333 ==> got signal NS_REPLACED: 0x1122/1.2.3.4:4444 -> 0x3344/1.2.3.4:3333 ==> got signal NS_RESET, NS-VC 0x1122/1.2.3.4:3333 MESSAGE to BSS, msg length 9 -03 01 82 11 22 04 82 33 44 +03 01 82 11 22 04 82 11 22
MESSAGE to BSS, msg length 1 0a @@ -205,9 +205,9 @@ result (RESET) = 9
Current NS-VCIs: VCI 0x3344, NSEI 0x1122, peer 0x00000000:0, blocked - VCI 0x1122, NSEI 0x3344, peer 0x01020304:3333, blocked + VCI 0x1122, NSEI 0x1122, peer 0x01020304:3333, blocked NS-VC replaced other count: 1 - NS-VC changed NSEI : 1 + NS-VC changed NSEI count : 2
--- Peer port 4444, RESET, NSEI is changed back ---
@@ -227,7 +227,7 @@ Current NS-VCIs: VCI 0x3344, NSEI 0x1122, peer 0x00000000:0, blocked VCI 0x1122, NSEI 0x1122, peer 0x01020304:4444, blocked NS-VC replaced other count: 1 - NS-VC changed NSEI : 2 + NS-VC changed NSEI count : 2
--- Setup VC 1 BSS -> SGSN ---
@@ -424,18 +424,21 @@ Current NS-VCIs: PROCESSING RESET from 0x01020304:2222 02 00 81 01 01 82 10 01 04 82 f0 00
-==> got signal NS_MISMATCH: 0x1001/1.2.3.4:2222 pdu=2, ie=4 +==> got signal NS_RESET, NS-VC 0x1001/1.2.3.4:2222 MESSAGE to BSS, msg length 9 -03 01 82 10 01 04 82 10 00 +03 01 82 10 01 04 82 f0 00
-result (RESET) = 0 +MESSAGE to BSS, msg length 1 +0a + +result (RESET) = 9
Current NS-VCIs: VCI 0x2001, NSEI 0x2000, peer 0x01020304:1111 - VCI 0x1001, NSEI 0x1000, peer 0x01020304:2222, blocked + VCI 0x1001, NSEI 0xf000, peer 0x01020304:2222, blocked NS-VC Block count : 3 NS-VC replaced other count: 1 - NSEI was invalid count : 1 + NS-VC changed NSEI count : 1
--- RESET with invalid NSVCI, BSS -> SGSN ---
@@ -456,7 +459,7 @@ Current NS-VCIs: VCI 0xf001, NSEI 0x1000, peer 0x01020304:2222, blocked NS-VC Block count : 3 NS-VC replaced other count: 1 - NSEI was invalid count : 1 + NS-VC changed NSEI count : 2
--- RESET with old NSEI, NSVCI, BSS -> SGSN ---
@@ -477,7 +480,7 @@ Current NS-VCIs: VCI 0x1001, NSEI 0x1000, peer 0x01020304:2222, blocked NS-VC Block count : 3 NS-VC replaced other count: 1 - NSEI was invalid count : 1 + NS-VC changed NSEI count : 2
--- Unexpected RESET_ACK VC 1, BSS -> SGSN ---
@@ -491,7 +494,7 @@ Current NS-VCIs: VCI 0x1001, NSEI 0x1000, peer 0x01020304:2222, blocked NS-VC Block count : 3 NS-VC replaced other count: 1 - NSEI was invalid count : 1 + NS-VC changed NSEI count : 2
--- RESET_ACK with invalid NSEI, BSS -> SGSN ---
@@ -501,20 +504,22 @@ MESSAGE to BSS, msg length 12 PROCESSING RESET_ACK from 0x01020304:2222 03 01 82 10 01 04 82 f0 00
-==> got signal NS_MISMATCH: 0x1001/1.2.3.4:2222 pdu=3, ie=4 -result (RESET_ACK) = -22 +MESSAGE to BSS, msg length 1 +0a + +result (RESET_ACK) = 1
Current NS-VCIs: VCI 0x2001, NSEI 0x2000, peer 0x01020304:1111 - VCI 0x1001, NSEI 0x1000, peer 0x01020304:2222, blocked - NS-VC Block count : 3 + VCI 0x1001, NSEI 0xf000, peer 0x01020304:2222, blocked + NS-VC Block count : 4 NS-VC replaced other count: 1 - NSEI was invalid count : 2 + NS-VC changed NSEI count : 3
--- RESET_ACK with invalid NSVCI, BSS -> SGSN ---
MESSAGE to BSS, msg length 12 -02 00 81 01 01 82 10 01 04 82 10 00 +02 00 81 01 01 82 10 01 04 82 f0 00
PROCESSING RESET_ACK from 0x01020304:2222 03 01 82 f0 01 04 82 10 00 @@ -524,11 +529,11 @@ result (RESET_ACK) = -22
Current NS-VCIs: VCI 0x2001, NSEI 0x2000, peer 0x01020304:1111 - VCI 0x1001, NSEI 0x1000, peer 0x01020304:2222, blocked - NS-VC Block count : 3 + VCI 0x1001, NSEI 0xf000, peer 0x01020304:2222, blocked + NS-VC Block count : 4 NS-VC replaced other count: 1 + NS-VC changed NSEI count : 3 NS-VCI was invalid count : 1 - NSEI was invalid count : 2
Current NS-VCIs:
When a RESET is received on the same link with a different NSVCI from a BSS on a dynamically created NS connection do not patch the nsvc object but create a new one instead. Thus the NSVCI is never modified at a nsvc object after the NS-VC has been established.
Sponsored-by: On-Waves ehf --- src/gb/gprs_ns.c | 16 ++++++++++++---- tests/gb/gprs_ns_test.c | 5 +++-- tests/gb/gprs_ns_test.ok | 35 +++++++++++++++++++++++++---------- 3 files changed, 40 insertions(+), 16 deletions(-)
diff --git a/src/gb/gprs_ns.c b/src/gb/gprs_ns.c index 043a66c..1754501 100644 --- a/src/gb/gprs_ns.c +++ b/src/gb/gprs_ns.c @@ -729,9 +729,6 @@ static int gprs_nsvc_replace_if_found(uint16_t nsvci,
talloc_free(old_peer);
- /* Do statistics */ - rate_ctr_inc(&(*nsvc)->ctrg->ctr[NS_CTR_REPLACED]); - return 1; }
@@ -784,7 +781,16 @@ static int gprs_ns_rx_reset(struct gprs_nsvc **nsvc, struct msgb *msg) }
/* NS-VCI has changed */ - gprs_nsvc_replace_if_found(nsvci, nsvc, &orig_nsvc); + if (!gprs_nsvc_replace_if_found(nsvci, nsvc, &orig_nsvc)) { + LOGP(DNS, LOGL_INFO, "Creating NS-VC %d replacing %d " + "at %s\n", + nsvci, (*nsvc)->nsvci, + gprs_ns_ll_str(*nsvc)); + orig_nsvc = *nsvc; + *nsvc = gprs_nsvc_create((*nsvc)->nsi, nsvci); + (*nsvc)->nsvci_is_valid = 1; + (*nsvc)->nsei = nsei; + } }
if ((*nsvc)->nsvci_is_valid && (*nsvc)->nsei != nsei) { @@ -810,6 +816,7 @@ static int gprs_ns_rx_reset(struct gprs_nsvc **nsvc, struct msgb *msg) (*nsvc)->state = NSE_S_BLOCKED | NSE_S_ALIVE;
if (orig_nsvc) { + rate_ctr_inc(&(*nsvc)->ctrg->ctr[NS_CTR_REPLACED]); ns_osmo_signal_dispatch_replaced(*nsvc, orig_nsvc);
/* Update the ll info fields */ @@ -916,6 +923,7 @@ static int gprs_ns_rx_reset_ack(struct gprs_nsvc **nsvc, struct msgb *msg) }
/* Notify others */ + rate_ctr_inc(&(*nsvc)->ctrg->ctr[NS_CTR_REPLACED]); ns_osmo_signal_dispatch_replaced(*nsvc, orig_nsvc);
/* Update the ll info fields */ diff --git a/tests/gb/gprs_ns_test.c b/tests/gb/gprs_ns_test.c index 546c20a..c88792c 100644 --- a/tests/gb/gprs_ns_test.c +++ b/tests/gb/gprs_ns_test.c @@ -435,11 +435,12 @@ static void gprs_dump_nsi(struct gprs_ns_inst *nsi) printf("Current NS-VCIs:\n"); llist_for_each_entry(nsvc, &nsi->gprs_nsvcs, list) { struct sockaddr_in *peer = &(nsvc->ip.bts_addr); - printf(" VCI 0x%04x, NSEI 0x%04x, peer 0x%08x:%d%s%s\n", + printf(" VCI 0x%04x, NSEI 0x%04x, peer 0x%08x:%d%s%s%s\n", nsvc->nsvci, nsvc->nsei, ntohl(peer->sin_addr.s_addr), ntohs(peer->sin_port), nsvc->state & NSE_S_BLOCKED ? ", blocked" : "", - nsvc->state & NSE_S_ALIVE ? "" : ", dead" + nsvc->state & NSE_S_ALIVE ? "" : ", dead", + nsvc->nsvci_is_valid ? "" : ", invalid VCI" ); dump_rate_ctr_group(stdout, " ", nsvc->ctrg); } diff --git a/tests/gb/gprs_ns_test.ok b/tests/gb/gprs_ns_test.ok index 5f90d03..8a61450 100644 --- a/tests/gb/gprs_ns_test.ok +++ b/tests/gb/gprs_ns_test.ok @@ -445,6 +445,7 @@ Current NS-VCIs: PROCESSING RESET from 0x01020304:2222 02 00 81 01 01 82 f0 01 04 82 10 00
+==> got signal NS_REPLACED: 0xf001/0.0.0.0:0 -> 0x1001/1.2.3.4:2222 ==> got signal NS_RESET, NS-VC 0xf001/1.2.3.4:2222 MESSAGE to BSS, msg length 9 03 01 82 f0 01 04 82 10 00 @@ -455,17 +456,20 @@ MESSAGE to BSS, msg length 1 result (RESET) = 9
Current NS-VCIs: - VCI 0x2001, NSEI 0x2000, peer 0x01020304:1111 VCI 0xf001, NSEI 0x1000, peer 0x01020304:2222, blocked + NS-VC replaced other count: 1 + VCI 0x2001, NSEI 0x2000, peer 0x01020304:1111 + VCI 0x1001, NSEI 0xf000, peer 0x00000000:0, blocked NS-VC Block count : 3 NS-VC replaced other count: 1 - NS-VC changed NSEI count : 2 + NS-VC changed NSEI count : 1
--- RESET with old NSEI, NSVCI, BSS -> SGSN ---
PROCESSING RESET from 0x01020304:2222 02 00 81 01 01 82 10 01 04 82 10 00
+==> got signal NS_REPLACED: 0x1001/0.0.0.0:0 -> 0xf001/1.2.3.4:2222 ==> got signal NS_RESET, NS-VC 0x1001/1.2.3.4:2222 MESSAGE to BSS, msg length 9 03 01 82 10 01 04 82 10 00 @@ -476,10 +480,12 @@ MESSAGE to BSS, msg length 1 result (RESET) = 9
Current NS-VCIs: + VCI 0xf001, NSEI 0x1000, peer 0x00000000:0, blocked + NS-VC replaced other count: 1 VCI 0x2001, NSEI 0x2000, peer 0x01020304:1111 VCI 0x1001, NSEI 0x1000, peer 0x01020304:2222, blocked NS-VC Block count : 3 - NS-VC replaced other count: 1 + NS-VC replaced other count: 2 NS-VC changed NSEI count : 2
--- Unexpected RESET_ACK VC 1, BSS -> SGSN --- @@ -490,10 +496,12 @@ PROCESSING RESET_ACK from 0x01020304:2222 result (RESET_ACK) = 0
Current NS-VCIs: + VCI 0xf001, NSEI 0x1000, peer 0x00000000:0, blocked + NS-VC replaced other count: 1 VCI 0x2001, NSEI 0x2000, peer 0x01020304:1111 VCI 0x1001, NSEI 0x1000, peer 0x01020304:2222, blocked NS-VC Block count : 3 - NS-VC replaced other count: 1 + NS-VC replaced other count: 2 NS-VC changed NSEI count : 2
--- RESET_ACK with invalid NSEI, BSS -> SGSN --- @@ -510,10 +518,12 @@ MESSAGE to BSS, msg length 1 result (RESET_ACK) = 1
Current NS-VCIs: + VCI 0xf001, NSEI 0x1000, peer 0x00000000:0, blocked + NS-VC replaced other count: 1 VCI 0x2001, NSEI 0x2000, peer 0x01020304:1111 VCI 0x1001, NSEI 0xf000, peer 0x01020304:2222, blocked NS-VC Block count : 4 - NS-VC replaced other count: 1 + NS-VC replaced other count: 2 NS-VC changed NSEI count : 3
--- RESET_ACK with invalid NSVCI, BSS -> SGSN --- @@ -524,16 +534,21 @@ MESSAGE to BSS, msg length 12 PROCESSING RESET_ACK from 0x01020304:2222 03 01 82 f0 01 04 82 10 00
-==> got signal NS_MISMATCH: 0x1001/1.2.3.4:2222 pdu=3, ie=1 -result (RESET_ACK) = -22 +==> got signal NS_REPLACED: 0xf001/0.0.0.0:0 -> 0x1001/1.2.3.4:2222 +MESSAGE to BSS, msg length 1 +0a + +result (RESET_ACK) = 1
Current NS-VCIs: + VCI 0xf001, NSEI 0x1000, peer 0x01020304:2222, blocked + NS-VC Block count : 1 + NS-VC replaced other count: 2 VCI 0x2001, NSEI 0x2000, peer 0x01020304:1111 - VCI 0x1001, NSEI 0xf000, peer 0x01020304:2222, blocked + VCI 0x1001, NSEI 0xf000, peer 0x00000000:0, blocked NS-VC Block count : 4 - NS-VC replaced other count: 1 + NS-VC replaced other count: 2 NS-VC changed NSEI count : 3 - NS-VCI was invalid count : 1
Current NS-VCIs:
On Thu, Oct 24, 2013 at 01:33:19AM +0200, Jacob Erlbeck wrote:
Hi,
I had just merged all your previous changes. How is this patchset different to the one posted on tuesday? I see that patch 1 has some minor modifications in the print statement and two more patches were added?
holger
On 10/24/2013 09:48 AM, Holger Hans Peter Freyther wrote:
On Thu, Oct 24, 2013 at 01:33:19AM +0200, Jacob Erlbeck wrote:
I had just merged all your previous changes. How is this patchset different to the one posted on tuesday? I see that patch 1 has some minor modifications in the print statement and two more patches were added?
I've slightly reordered them, merged the two commits extending the RESET test and separated the RESET fixes into spec-related and relaxed handling of NSEI changes.
Jacob
On Tue, Oct 22, 2013 at 12:22:39PM +0200, Jacob Erlbeck wrote:
Good Morning Jacob!
as usual, the patch looks good!
- nsvc = gprs_nsvc_by_nsei(vty_nsi, nsvci);
- if (!strcmp(id_type, "nsei"))
nsvc = gprs_nsvc_by_nsei(vty_nsi, id);- else if (!strcmp(id_type, "nsvci"))
nsvc = gprs_nsvc_by_nsvci(vty_nsi, id);- else
return CMD_WARNING;
the VTY will make sure that id_type is either nsei or nsvc. So we can omit the else path. In case you want to keep the else path. I think we should a vty_out with a warning that the given id_type does not exist.
I will modify this locally.