From 3e23ddf88b38f9316b61daff6f8f41e57e883a14 Mon Sep 17 00:00:00 2001 From: Jacob Erlbeck Date: Mon, 11 Aug 2014 15:07:37 +0200 Subject: gbproxy: Parse Detach Request messages GSM 24.008 also allows a P-TMSI field in Detach request messages. This patch adds gbprox_parse_gmm_detach_req() to parse Detach Request messages which sets the ptmsi field if the IE is present. In addition, when power_off is set to 1 (MO only), the invalidate_tlli field is set, since Detach Request message is expected in this case. The second detach test (see 'RA update') is modified to use power_off instead of relying on a Detach Accept from the network. To make this work, the PTMSI of the RA Update Accept is fixed to match the TLLI of the Detach Request. Sponsored-by: On-Waves ehf --- openbsc/src/gprs/gb_proxy.c | 47 ++++++++++++++++++++++++++++++++--- openbsc/tests/gbproxy/gbproxy_test.c | 28 +++++++++++++-------- openbsc/tests/gbproxy/gbproxy_test.ok | 44 +++++++++++--------------------- 3 files changed, 75 insertions(+), 44 deletions(-) diff --git a/openbsc/src/gprs/gb_proxy.c b/openbsc/src/gprs/gb_proxy.c index 64fb55b77..dd7dead2b 100644 --- a/openbsc/src/gprs/gb_proxy.c +++ b/openbsc/src/gprs/gb_proxy.c @@ -959,6 +959,43 @@ static int gbprox_parse_gmm_attach_ack(uint8_t *data, size_t data_len, return 1; } +static int gbprox_parse_gmm_detach_req(uint8_t *data, size_t data_len, + struct gbproxy_parse_context *parse_ctx) +{ + uint8_t *value; + size_t value_len; + int detach_type; + int power_off; + + parse_ctx->llc_msg_name = "DETACH_REQ"; + + /* Skip spare half octet */ + /* Get Detach type */ + if (v_fixed_shift(&data, &data_len, 1, &value) <= 0) + /* invalid */ + return 0; + + detach_type = *value & 0x07; + power_off = *value & 0x08 ? 1 : 0; + + if (!parse_ctx->to_bss) { + /* Mobile originated */ + + if (power_off) + parse_ctx->invalidate_tlli = 1; + + /* Get P-TMSI (Mobile identity), see GSM 24.008, 9.4.5.2 */ + if (tlv_match(&data, &data_len, + GSM48_IE_GMM_ALLOC_PTMSI, &value, &value_len) > 0) + { + if (is_mi_tmsi(value, value_len)) + parse_ctx->ptmsi_enc = value; + } + } + + return 1; +} + static int gbprox_parse_gmm_ra_upd_req(uint8_t *data, size_t data_len, struct gbproxy_parse_context *parse_ctx) { @@ -1157,12 +1194,9 @@ static int gbprox_parse_dtap(uint8_t *data, size_t data_len, case GSM48_MT_GMM_ID_RESP: return gbprox_parse_gmm_id_resp(data, data_len, parse_ctx); - break; case GSM48_MT_GMM_DETACH_REQ: - /* TODO: Check power off if !to_bss, if yes invalidate */ - parse_ctx->llc_msg_name = "DETACH_REQ"; - break; + return gbprox_parse_gmm_detach_req(data, data_len, parse_ctx); case GSM48_MT_GMM_DETACH_ACK: parse_ctx->llc_msg_name = "DETACH_ACK"; @@ -1331,6 +1365,11 @@ static void gbprox_log_parse_context(struct gbproxy_parse_context *parse_ctx, sep, mi_buf); sep = ","; } + if (parse_ctx->invalidate_tlli) { + LOGP(DGPRS, LOGL_DEBUG, "%s invalidate", sep); + sep = ","; + } + LOGP(DGPRS, LOGL_DEBUG, "\n"); } diff --git a/openbsc/tests/gbproxy/gbproxy_test.c b/openbsc/tests/gbproxy/gbproxy_test.c index 5363749c6..27454a2a9 100644 --- a/openbsc/tests/gbproxy/gbproxy_test.c +++ b/openbsc/tests/gbproxy/gbproxy_test.c @@ -221,8 +221,8 @@ static const unsigned char bssgp_ra_upd_acc[91] = { 0x18, 0x00, 0x81, 0x00, 0x0e, 0x9d, 0x41, 0xc0, 0x19, 0x08, 0x09, 0x00, 0x49, 0x21, 0x63, 0x54, 0x40, 0x50, 0x60, 0x19, 0x54, 0xab, 0xb3, 0x18, - 0x05, 0xf4, 0xef, 0xe2, 0x81, 0x17, 0x17, 0x16, - 0xc3, 0xbf, 0xcc + 0x05, 0xf4, 0xef, 0xe2, 0xb7, 0x00, 0x17, 0x16, + 0xd7, 0x59, 0x65 }; /* Base Station Subsystem GPRS Protocol: GSM A-I/F DTAP - Activate PDP Context Request */ @@ -239,7 +239,19 @@ static const unsigned char bssgp_act_pdp_ctx_req[76] = { 0x00, 0x5a, 0xff, 0x02 }; -/* Base Station Subsystem GPRS Protocol: GSM A-I/F DTAP - Detach Request */ +/* Base Station Subsystem GPRS Protocol: GSM A-I/F DTAP - Detach Request (MO) */ +/* normal detach, power_off = 1 */ +static const unsigned char bssgp_detach_po_req[44] = { + 0x01, 0xef, 0xe2, 0xb7, 0x00, 0x00, 0x00, 0x04, + 0x08, 0x88, 0x11, 0x22, 0x33, 0x40, 0x50, 0x60, + 0x75, 0x30, 0x00, 0x80, 0x0e, 0x00, 0x15, 0x01, + 0xc0, 0x19, 0x08, 0x05, 0x09, 0x18, 0x05, 0xf4, + 0xef, 0xe2, 0xb7, 0x00, 0x19, 0x03, 0xb9, 0x97, + 0xcb, 0x84, 0x0c, 0xeb +}; + +/* Base Station Subsystem GPRS Protocol: GSM A-I/F DTAP - Detach Request (MO) */ +/* normal detach, power_off = 0 */ static const unsigned char bssgp_detach_req[44] = { 0x01, 0xef, 0xe2, 0xb7, 0x00, 0x00, 0x00, 0x04, 0x08, 0x88, 0x11, 0x22, 0x33, 0x40, 0x50, 0x60, @@ -1060,13 +1072,9 @@ static void test_gbproxy_ra_patching() dump_peers(stdout, 0, 0, &gbcfg); - /* Detach */ - send_ns_unitdata(nsi, "DETACH REQ", &bss_peer[0], 0x1002, - bssgp_detach_req, sizeof(bssgp_detach_req)); - - send_ns_unitdata(nsi, "DETACH ACC", &sgsn_peer, 0x1002, - bssgp_detach_acc, sizeof(bssgp_detach_acc)); - + /* Detach (power off -> no Detach Accept) */ + send_ns_unitdata(nsi, "DETACH REQ (PWR OFF)", &bss_peer[0], 0x1002, + bssgp_detach_po_req, sizeof(bssgp_detach_po_req)); dump_global(stdout, 0); dump_peers(stdout, 0, 0, &gbcfg); diff --git a/openbsc/tests/gbproxy/gbproxy_test.ok b/openbsc/tests/gbproxy/gbproxy_test.ok index 363a6e9be..28d501660 100644 --- a/openbsc/tests/gbproxy/gbproxy_test.ok +++ b/openbsc/tests/gbproxy/gbproxy_test.ok @@ -1780,14 +1780,14 @@ MESSAGE to SGSN at 0x05060708:32000, msg length 89 result (RA UPD REQ) = 89 PROCESSING RA UPD ACC from 0x05060708:32000 -00 00 10 02 00 bb c5 46 79 00 50 20 16 82 02 58 13 9d 19 13 42 33 57 2b f7 c8 48 02 13 48 50 c8 48 02 14 48 50 c8 48 02 17 49 10 c8 48 02 00 0a 82 07 04 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 9d 41 c0 19 08 09 00 49 21 63 54 40 50 60 19 54 ab b3 18 05 f4 ef e2 81 17 17 16 c3 bf cc +00 00 10 02 00 bb c5 46 79 00 50 20 16 82 02 58 13 9d 19 13 42 33 57 2b f7 c8 48 02 13 48 50 c8 48 02 14 48 50 c8 48 02 17 49 10 c8 48 02 00 0a 82 07 04 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 9d 41 c0 19 08 09 00 49 21 63 54 40 50 60 19 54 ab b3 18 05 f4 ef e2 b7 00 17 16 d7 59 65 CALLBACK, event 0, msg length 91, bvci 0x1002 -00 00 10 02 00 bb c5 46 79 00 50 20 16 82 02 58 13 9d 19 13 42 33 57 2b f7 c8 48 02 13 48 50 c8 48 02 14 48 50 c8 48 02 17 49 10 c8 48 02 00 0a 82 07 04 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 9d 41 c0 19 08 09 00 49 21 63 54 40 50 60 19 54 ab b3 18 05 f4 ef e2 81 17 17 16 c3 bf cc +00 00 10 02 00 bb c5 46 79 00 50 20 16 82 02 58 13 9d 19 13 42 33 57 2b f7 c8 48 02 13 48 50 c8 48 02 14 48 50 c8 48 02 17 49 10 c8 48 02 00 0a 82 07 04 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 9d 41 c0 19 08 09 00 49 21 63 54 40 50 60 19 54 ab b3 18 05 f4 ef e2 b7 00 17 16 d7 59 65 NS UNITDATA MESSAGE to BSS, BVCI 0x1002, msg length 91 (gprs_ns_sendmsg) MESSAGE to BSS at 0x01020304:1111, msg length 95 -00 00 10 02 00 bb c5 46 79 00 50 20 16 82 02 58 13 9d 19 13 42 33 57 2b f7 c8 48 02 13 48 50 c8 48 02 14 48 50 c8 48 02 17 49 10 c8 48 02 00 0a 82 07 04 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 9d 41 c0 19 08 09 00 49 11 22 33 40 50 60 19 54 ab b3 18 05 f4 ef e2 81 17 17 16 2e e5 fd +00 00 10 02 00 bb c5 46 79 00 50 20 16 82 02 58 13 9d 19 13 42 33 57 2b f7 c8 48 02 13 48 50 c8 48 02 14 48 50 c8 48 02 17 49 10 c8 48 02 00 0a 82 07 04 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 9d 41 c0 19 08 09 00 49 11 22 33 40 50 60 19 54 ab b3 18 05 f4 ef e2 b7 00 17 16 3a 03 54 result (RA UPD ACC) = 95 @@ -1809,33 +1809,20 @@ Peers: RAID patched (SGSN): 3 APN patched : 3 Attach Request count : 1 - TLLI cache size : 2 - TLLI-Cache: 2 - TLLI efe2b700, IMSI (none), AGE 0 - TLLI efe28117, IMSI 12131415161718, AGE 0 -PROCESSING DETACH REQ from 0x01020304:1111 -00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 75 30 00 80 0e 00 15 01 c0 19 08 05 01 18 05 f4 ef e2 b7 00 19 03 b9 97 cb 7e e1 41 + TLLI cache size : 1 + TLLI-Cache: 1 + TLLI efe2b700, IMSI 12131415161718, AGE 0 +PROCESSING DETACH REQ (PWR OFF) from 0x01020304:1111 +00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 75 30 00 80 0e 00 15 01 c0 19 08 05 09 18 05 f4 ef e2 b7 00 19 03 b9 97 cb 84 0c eb CALLBACK, event 0, msg length 44, bvci 0x1002 -00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 75 30 00 80 0e 00 15 01 c0 19 08 05 01 18 05 f4 ef e2 b7 00 19 03 b9 97 cb 7e e1 41 +00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 75 30 00 80 0e 00 15 01 c0 19 08 05 09 18 05 f4 ef e2 b7 00 19 03 b9 97 cb 84 0c eb NS UNITDATA MESSAGE to SGSN, BVCI 0x1002, msg length 44 (gprs_ns_sendmsg) MESSAGE to SGSN at 0x05060708:32000, msg length 48 -00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 21 63 54 40 50 60 75 30 00 80 0e 00 15 01 c0 19 08 05 01 18 05 f4 ef e2 b7 00 19 03 b9 97 cb 7e e1 41 - -result (DETACH REQ) = 48 - -PROCESSING DETACH ACC from 0x05060708:32000 -00 00 10 02 00 ef e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 89 41 c0 15 08 06 00 f7 35 f0 +00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 21 63 54 40 50 60 75 30 00 80 0e 00 15 01 c0 19 08 05 09 18 05 f4 ef e2 b7 00 19 03 b9 97 cb 84 0c eb -CALLBACK, event 0, msg length 67, bvci 0x1002 -00 00 10 02 00 ef e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 89 41 c0 15 08 06 00 f7 35 f0 - -NS UNITDATA MESSAGE to BSS, BVCI 0x1002, msg length 67 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 71 -00 00 10 02 00 ef e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 89 41 c0 15 08 06 00 f7 35 f0 - -result (DETACH ACC) = 71 +result (DETACH REQ (PWR OFF)) = 48 Gbproxy global: Peers: @@ -1844,9 +1831,7 @@ Peers: RAID patched (SGSN): 3 APN patched : 3 Attach Request count : 1 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI efe28117, IMSI 12131415161718, AGE 0 + TLLI-Cache: 0 --- Bad cases --- TLLI is already detached, shouldn't patch @@ -1884,10 +1869,9 @@ Peers: RAID patched (SGSN): 3 APN patched : 3 Attach Request count : 1 - TLLI cache size : 2 - TLLI-Cache: 2 + TLLI cache size : 1 + TLLI-Cache: 1 TLLI efe2b700, IMSI (none), AGE 0 - TLLI efe28117, IMSI 12131415161718, AGE 0 Test TLLI info expiry Test TLLI replacement: -- cgit v1.2.3 From 3c5b40fb759e07bba63b06b80560f1c59125c8e0 Mon Sep 17 00:00:00 2001 From: Jacob Erlbeck Date: Wed, 13 Aug 2014 14:17:23 +0200 Subject: gbproxy: Update enable_patching flag on existing tlli_info Currently the enable_patching field in tlli_info is not updated, when an IMSI is assigned to a TLLI that is already known. This patch fixes this in gbprox_update_state() after the call to gbprox_update_tlli_info(). The number of APN increases and the test output file is updated accordingly. Sponsored-by: On-Waves ehf --- openbsc/src/gprs/gb_proxy.c | 10 +++++++++- openbsc/tests/gbproxy/gbproxy_test.ok | 14 +++++++------- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/openbsc/src/gprs/gb_proxy.c b/openbsc/src/gprs/gb_proxy.c index dd7dead2b..5e19247a2 100644 --- a/openbsc/src/gprs/gb_proxy.c +++ b/openbsc/src/gprs/gb_proxy.c @@ -1437,10 +1437,18 @@ static struct gbproxy_tlli_info *gbprox_update_state( gbprox_touch_tlli(peer, tlli_info, now); } - if (parse_ctx->imsi && tlli_info && tlli_info->mi_data_len == 0) + if (parse_ctx->imsi && tlli_info && tlli_info->mi_data_len == 0) { + int enable_patching; gbprox_update_tlli_info(tlli_info, parse_ctx->imsi, parse_ctx->imsi_len); + /* Check, whether the IMSI matches */ + enable_patching = gbprox_check_imsi(peer, parse_ctx->imsi, + parse_ctx->imsi_len); + if (enable_patching >= 0) + tlli_info->enable_patching = enable_patching; + } + return tlli_info; } diff --git a/openbsc/tests/gbproxy/gbproxy_test.ok b/openbsc/tests/gbproxy/gbproxy_test.ok index 28d501660..a6ff67463 100644 --- a/openbsc/tests/gbproxy/gbproxy_test.ok +++ b/openbsc/tests/gbproxy/gbproxy_test.ok @@ -1797,17 +1797,17 @@ PROCESSING ACT PDP CTX REQ (REMOVE APN) from 0x01020304:1111 CALLBACK, event 0, msg length 76, bvci 0x1002 00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 75 30 00 80 0e 00 35 01 c0 0d 0a 41 05 03 0c 00 00 1f 10 00 00 00 00 00 00 00 00 02 01 21 28 03 02 61 62 27 14 80 80 21 10 01 00 00 10 81 06 00 00 00 00 83 06 00 00 00 00 5a ff 02 -NS UNITDATA MESSAGE to SGSN, BVCI 0x1002, msg length 76 (gprs_ns_sendmsg) -MESSAGE to SGSN at 0x05060708:32000, msg length 80 -00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 21 63 54 40 50 60 75 30 00 80 0e 00 35 01 c0 0d 0a 41 05 03 0c 00 00 1f 10 00 00 00 00 00 00 00 00 02 01 21 28 03 02 61 62 27 14 80 80 21 10 01 00 00 10 81 06 00 00 00 00 83 06 00 00 00 00 5a ff 02 +NS UNITDATA MESSAGE to SGSN, BVCI 0x1002, msg length 71 (gprs_ns_sendmsg) +MESSAGE to SGSN at 0x05060708:32000, msg length 75 +00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 21 63 54 40 50 60 75 30 00 80 0e 00 30 01 c0 0d 0a 41 05 03 0c 00 00 1f 10 00 00 00 00 00 00 00 00 02 01 21 27 14 80 80 21 10 01 00 00 10 81 06 00 00 00 00 83 06 00 00 00 00 85 fa 60 -result (ACT PDP CTX REQ (REMOVE APN)) = 80 +result (ACT PDP CTX REQ (REMOVE APN)) = 75 Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 RAID patched (BSS ): 12 RAID patched (SGSN): 3 - APN patched : 3 + APN patched : 4 Attach Request count : 1 TLLI cache size : 1 TLLI-Cache: 1 @@ -1829,7 +1829,7 @@ Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 RAID patched (BSS ): 13 RAID patched (SGSN): 3 - APN patched : 3 + APN patched : 4 Attach Request count : 1 TLLI-Cache: 0 --- Bad cases --- @@ -1867,7 +1867,7 @@ Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 RAID patched (BSS ): 14 RAID patched (SGSN): 3 - APN patched : 3 + APN patched : 4 Attach Request count : 1 TLLI cache size : 1 TLLI-Cache: 1 -- cgit v1.2.3 From 59748e653b7d6ab7e8bb62bf55ca714958b356e2 Mon Sep 17 00:00:00 2001 From: Jacob Erlbeck Date: Mon, 11 Aug 2014 17:26:21 +0200 Subject: gbproxy: Handle old and new P-TMSI/TLLI Don't replace the current TLLI immediately, store it in an additional 'assigned_tlli' field and discard the old TLLI when both sides have used the new one (see GSM 04.08, 4.7.1.5). Add an Attach Complete message to test and check, whether the related field of the corresponding tlli_info struct are set as expected during the local TLLI validation cycle. Sponsored-by: On-Waves ehf --- openbsc/include/openbsc/gb_proxy.h | 5 +++ openbsc/src/gprs/gb_proxy.c | 57 +++++++++++++++++++++++++++++------ openbsc/tests/gbproxy/gbproxy_test.c | 57 ++++++++++++++++++++++++++++++++--- openbsc/tests/gbproxy/gbproxy_test.ok | 24 +++++++++++---- 4 files changed, 124 insertions(+), 19 deletions(-) diff --git a/openbsc/include/openbsc/gb_proxy.h b/openbsc/include/openbsc/gb_proxy.h index d6dde109d..adc955c8a 100644 --- a/openbsc/include/openbsc/gb_proxy.h +++ b/openbsc/include/openbsc/gb_proxy.h @@ -85,6 +85,9 @@ struct gbproxy_tlli_info { struct llist_head list; uint32_t tlli; + uint32_t assigned_tlli; + int bss_validated; + int net_validated; time_t timestamp; uint8_t *mi_data; size_t mi_data_len; @@ -124,6 +127,8 @@ int gbprox_cleanup_peers(struct gbproxy_config *cfg, uint16_t nsei, uint16_t bvc struct gbproxy_peer *gbprox_peer_by_nsei(struct gbproxy_config *cfg, uint16_t nsei); +struct gbproxy_tlli_info *gbprox_find_tlli(struct gbproxy_peer *peer, + uint32_t tlli); struct gbproxy_tlli_info *gbprox_find_tlli_by_mi(struct gbproxy_peer *peer, const uint8_t *mi_data, size_t mi_data_len); diff --git a/openbsc/src/gprs/gb_proxy.c b/openbsc/src/gprs/gb_proxy.c index 5e19247a2..26f4c1755 100644 --- a/openbsc/src/gprs/gb_proxy.c +++ b/openbsc/src/gprs/gb_proxy.c @@ -420,14 +420,14 @@ struct gbproxy_parse_context { int pdu_type; }; -static struct gbproxy_tlli_info *gbprox_find_tlli(struct gbproxy_peer *peer, - uint32_t tlli) +struct gbproxy_tlli_info *gbprox_find_tlli(struct gbproxy_peer *peer, + uint32_t tlli) { struct gbproxy_tlli_info *tlli_info; struct gbproxy_patch_state *state = &peer->patch_state; llist_for_each_entry(tlli_info, &state->enabled_tllis, list) - if (tlli_info->tlli == tlli) + if (tlli_info->tlli == tlli || tlli_info->assigned_tlli == tlli) return tlli_info; return NULL; @@ -659,8 +659,41 @@ void gbprox_reassign_tlli(struct gbproxy_tlli_info *tlli_info, "The TLLI has been reassigned from %08x to %08x\n", tlli_info->tlli, new_tlli); - /* TODO: Save old TLLI */ - tlli_info->tlli = new_tlli; + /* Remember assigned TLLI */ + tlli_info->assigned_tlli = new_tlli; + tlli_info->bss_validated = 0; + tlli_info->net_validated = 0; +} + +static void gbprox_validate_tlli(struct gbproxy_tlli_info *tlli_info, + uint32_t tlli, int to_bss) +{ + LOGP(DGPRS, LOGL_DEBUG, + "%s({tlli = %08x, assigned_tlli = %08x, net_vld = %d, bss_vld = %d}, %08x)\n", + __func__, tlli_info->tlli, tlli_info->assigned_tlli, + tlli_info->net_validated, tlli_info->bss_validated, tlli); + + if (!tlli_info->assigned_tlli || tlli_info->assigned_tlli != tlli) + return; + + if (gprs_tlli_type(tlli) != TLLI_LOCAL) + return; + + /* See GSM 04.08, 4.7.1.5 */ + if (to_bss) + tlli_info->net_validated = 1; + else + tlli_info->bss_validated = 1; + + if (!tlli_info->bss_validated || !tlli_info->net_validated) + return; + + LOGP(DGPRS, LOGL_INFO, + "The TLLI %08x has been validated (was %08x)\n", + tlli_info->assigned_tlli, tlli_info->tlli); + + tlli_info->tlli = tlli; + tlli_info->assigned_tlli = 0; } void gbprox_touch_tlli(struct gbproxy_peer *peer, @@ -1429,10 +1462,16 @@ static struct gbproxy_tlli_info *gbprox_update_state( parse_ctx->imsi_len, now); } } else if (parse_ctx->tlli_enc && parse_ctx->llc) { - tlli_info = - gbprox_register_tlli(peer, parse_ctx->tlli, - parse_ctx->imsi, - parse_ctx->imsi_len, now); + if (!tlli_info) { + tlli_info = + gbprox_register_tlli(peer, parse_ctx->tlli, + parse_ctx->imsi, + parse_ctx->imsi_len, now); + } else { + gbprox_validate_tlli(tlli_info, parse_ctx->tlli, + parse_ctx->to_bss); + gbprox_touch_tlli(peer, tlli_info, now); + } } else if (tlli_info) { gbprox_touch_tlli(peer, tlli_info, now); } diff --git a/openbsc/tests/gbproxy/gbproxy_test.c b/openbsc/tests/gbproxy/gbproxy_test.c index 27454a2a9..0d55fb3db 100644 --- a/openbsc/tests/gbproxy/gbproxy_test.c +++ b/openbsc/tests/gbproxy/gbproxy_test.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -124,10 +125,12 @@ static int dump_peers(FILE *stream, int indent, time_t now, } else { snprintf(mi_buf, sizeof(mi_buf), "(none)"); } - rc = fprintf(stream, - "%*s TLLI %08x, IMSI %s, AGE %d\n", - indent, "", - tlli_info->tlli, mi_buf, (int)age); + fprintf(stream, "%*s TLLI %08x", + indent, "", tlli_info->tlli); + if (tlli_info->assigned_tlli) + fprintf(stream, "/%08x", tlli_info->assigned_tlli); + rc = fprintf(stream, ", IMSI %s, AGE %d\n", + mi_buf, (int)age); if (rc < 0) return rc; } @@ -181,6 +184,14 @@ static const unsigned char bssgp_attach_acc[88] = { 0xf4, 0xef, 0xe2, 0xb7, 0x00, 0x42, 0x67, 0x9a }; +/* Base Station Subsystem GPRS Protocol: GSM A-I/F DTAP - Attach Complete */ +static const unsigned char bssgp_attach_complete[] = { + 0x01, 0xef, 0xe2, 0xb7, 0x00, 0x00, 0x00, 0x04, + 0x08, 0x88, 0x11, 0x22, 0x33, 0x40, 0x50, 0x60, + 0x75, 0x30, 0x00, 0x80, 0x0e, 0x00, 0x08, 0x01, + 0xc0, 0x11, 0x08, 0x03, 0xff, 0xff, 0xff +}; + /* Base Station Subsystem GPRS Protocol: GSM A-I/F DTAP - GMM Information */ static const unsigned char bssgp_gmm_information[66] = { 0x00, 0xef, 0xe2, 0xb7, 0x00, 0x00, 0x50, 0x20, @@ -970,6 +981,12 @@ static void test_gbproxy_ra_patching() struct gprs_ra_id rai_unknown = {.mcc = 1, .mnc = 99, .lac = 99, .rac = 96}; const char *err_msg = NULL; + const uint32_t ptmsi = 0xefe2b700; + const uint32_t local_tlli = 0xefe2b700; + struct gbproxy_tlli_info *tlli_info; + struct gbproxy_peer *peer; + + OSMO_ASSERT(local_tlli == gprs_tmsi2tlli(ptmsi, TLLI_LOCAL)); bssgp_nsi = nsi; gbcfg.nsi = bssgp_nsi; @@ -1003,6 +1020,9 @@ static void test_gbproxy_ra_patching() gprs_dump_nsi(nsi); dump_peers(stdout, 0, 0, &gbcfg); + peer = gbprox_peer_by_nsei(&gbcfg, 0x1000); + OSMO_ASSERT(peer != NULL); + send_bssgp_reset_ack(nsi, &sgsn_peer, 0x1002); send_bssgp_suspend(nsi, &bss_peer[0], &rai_bss); @@ -1025,14 +1045,43 @@ static void test_gbproxy_ra_patching() send_ns_unitdata(nsi, "ATTACH ACCEPT", &sgsn_peer, 0x1002, bssgp_attach_acc, sizeof(bssgp_attach_acc)); + tlli_info = gbprox_find_tlli(peer, local_tlli); + OSMO_ASSERT(tlli_info); + OSMO_ASSERT(tlli_info->assigned_tlli == local_tlli); + OSMO_ASSERT(tlli_info->tlli != local_tlli); + OSMO_ASSERT(!tlli_info->bss_validated); + OSMO_ASSERT(!tlli_info->net_validated); + + send_ns_unitdata(nsi, "ATTACH COMPLETE", &bss_peer[0], 0x1002, + bssgp_attach_complete, sizeof(bssgp_attach_complete)); + + tlli_info = gbprox_find_tlli(peer, local_tlli); + OSMO_ASSERT(tlli_info); + OSMO_ASSERT(tlli_info->assigned_tlli == local_tlli); + OSMO_ASSERT(tlli_info->tlli != local_tlli); + OSMO_ASSERT(tlli_info->bss_validated); + OSMO_ASSERT(!tlli_info->net_validated); + /* Replace APN (1) */ send_ns_unitdata(nsi, "ACT PDP CTX REQ (REPLACE APN)", &bss_peer[0], 0x1002, bssgp_act_pdp_ctx_req, sizeof(bssgp_act_pdp_ctx_req)); + tlli_info = gbprox_find_tlli(peer, local_tlli); + OSMO_ASSERT(tlli_info); + OSMO_ASSERT(tlli_info->assigned_tlli == local_tlli); + OSMO_ASSERT(tlli_info->tlli != local_tlli); + OSMO_ASSERT(tlli_info->bss_validated); + OSMO_ASSERT(!tlli_info->net_validated); + send_ns_unitdata(nsi, "GMM INFO", &sgsn_peer, 0x1002, bssgp_gmm_information, sizeof(bssgp_gmm_information)); + tlli_info = gbprox_find_tlli(peer, local_tlli); + OSMO_ASSERT(tlli_info); + OSMO_ASSERT(tlli_info->assigned_tlli == 0); + OSMO_ASSERT(tlli_info->tlli == local_tlli); + /* Replace APN (2) */ send_ns_unitdata(nsi, "ACT PDP CTX REQ (REPLACE APN)", &bss_peer[0], 0x1002, diff --git a/openbsc/tests/gbproxy/gbproxy_test.ok b/openbsc/tests/gbproxy/gbproxy_test.ok index a6ff67463..1b3981308 100644 --- a/openbsc/tests/gbproxy/gbproxy_test.ok +++ b/openbsc/tests/gbproxy/gbproxy_test.ok @@ -1677,6 +1677,18 @@ MESSAGE to BSS at 0x01020304:1111, msg length 92 result (ATTACH ACCEPT) = 92 +PROCESSING ATTACH COMPLETE from 0x01020304:1111 +00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 75 30 00 80 0e 00 08 01 c0 11 08 03 ff ff ff + +CALLBACK, event 0, msg length 31, bvci 0x1002 +00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 75 30 00 80 0e 00 08 01 c0 11 08 03 ff ff ff + +NS UNITDATA MESSAGE to SGSN, BVCI 0x1002, msg length 31 (gprs_ns_sendmsg) +MESSAGE to SGSN at 0x05060708:32000, msg length 35 +00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 21 63 54 40 50 60 75 30 00 80 0e 00 08 01 c0 11 08 03 ff ff ff + +result (ATTACH COMPLETE) = 35 + PROCESSING ACT PDP CTX REQ (REPLACE APN) from 0x01020304:1111 00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 75 30 00 80 0e 00 35 01 c0 0d 0a 41 05 03 0c 00 00 1f 10 00 00 00 00 00 00 00 00 02 01 21 28 03 02 61 62 27 14 80 80 21 10 01 00 00 10 81 06 00 00 00 00 83 06 00 00 00 00 5a ff 02 @@ -1727,7 +1739,7 @@ result (ACT PDP CTX REQ (REMOVE APN)) = 75 Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - RAID patched (BSS ): 8 + RAID patched (BSS ): 9 RAID patched (SGSN): 2 APN patched : 3 Attach Request count : 1 @@ -1760,7 +1772,7 @@ result (DETACH ACC) = 71 Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - RAID patched (BSS ): 9 + RAID patched (BSS ): 10 RAID patched (SGSN): 2 APN patched : 3 Attach Request count : 1 @@ -1805,13 +1817,13 @@ result (ACT PDP CTX REQ (REMOVE APN)) = 75 Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - RAID patched (BSS ): 12 + RAID patched (BSS ): 13 RAID patched (SGSN): 3 APN patched : 4 Attach Request count : 1 TLLI cache size : 1 TLLI-Cache: 1 - TLLI efe2b700, IMSI 12131415161718, AGE 0 + TLLI bbc54679/efe2b700, IMSI 12131415161718, AGE 0 PROCESSING DETACH REQ (PWR OFF) from 0x01020304:1111 00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 75 30 00 80 0e 00 15 01 c0 19 08 05 09 18 05 f4 ef e2 b7 00 19 03 b9 97 cb 84 0c eb @@ -1827,7 +1839,7 @@ result (DETACH REQ (PWR OFF)) = 48 Gbproxy global: Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - RAID patched (BSS ): 13 + RAID patched (BSS ): 14 RAID patched (SGSN): 3 APN patched : 4 Attach Request count : 1 @@ -1865,7 +1877,7 @@ Gbproxy global: Patch error: no peer : 1 Peers: NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - RAID patched (BSS ): 14 + RAID patched (BSS ): 15 RAID patched (SGSN): 3 APN patched : 4 Attach Request count : 1 -- cgit v1.2.3 From 425afaca2f9a4abd858c4f109e8e99ef3d91ca76 Mon Sep 17 00:00:00 2001 From: Jacob Erlbeck Date: Fri, 15 Aug 2014 13:30:09 +0200 Subject: gbproxy/test: Fix BSSGP/LLC test messages The following parts of the messages have been fixed - Attach Accept: checksum - Attach Complete: checksum - RA Update Accept: Use the same MS Radio Access Capabilities and DRX Parameters like the other messages The N(U) of most messages have not been fixed. Sponsored-by: On-Waves ehf --- openbsc/tests/gbproxy/gbproxy_test.c | 27 +++++++++++++-------------- openbsc/tests/gbproxy/gbproxy_test.ok | 24 ++++++++++++------------ 2 files changed, 25 insertions(+), 26 deletions(-) diff --git a/openbsc/tests/gbproxy/gbproxy_test.c b/openbsc/tests/gbproxy/gbproxy_test.c index 0d55fb3db..c463222fb 100644 --- a/openbsc/tests/gbproxy/gbproxy_test.c +++ b/openbsc/tests/gbproxy/gbproxy_test.c @@ -181,7 +181,7 @@ static const unsigned char bssgp_attach_acc[88] = { 0x0e, 0x9e, 0x41, 0xc0, 0x05, 0x08, 0x02, 0x01, 0x49, 0x04, 0x21, 0x63, 0x54, 0x40, 0x50, 0x60, 0x19, 0xcd, 0xd7, 0x08, 0x17, 0x16, 0x18, 0x05, - 0xf4, 0xef, 0xe2, 0xb7, 0x00, 0x42, 0x67, 0x9a + 0xf4, 0xef, 0xe2, 0xb7, 0x00, 0x53, 0x62, 0xf1 }; /* Base Station Subsystem GPRS Protocol: GSM A-I/F DTAP - Attach Complete */ @@ -189,7 +189,7 @@ static const unsigned char bssgp_attach_complete[] = { 0x01, 0xef, 0xe2, 0xb7, 0x00, 0x00, 0x00, 0x04, 0x08, 0x88, 0x11, 0x22, 0x33, 0x40, 0x50, 0x60, 0x75, 0x30, 0x00, 0x80, 0x0e, 0x00, 0x08, 0x01, - 0xc0, 0x11, 0x08, 0x03, 0xff, 0xff, 0xff + 0xc0, 0x11, 0x08, 0x03, 0xea, 0x67, 0x11 }; /* Base Station Subsystem GPRS Protocol: GSM A-I/F DTAP - GMM Information */ @@ -221,19 +221,18 @@ static const unsigned char bssgp_ra_upd_req[85] = { }; /* Base Station Subsystem GPRS Protocol: GSM A-I/F DTAP - Routing Area Update Accept */ -static const unsigned char bssgp_ra_upd_acc[91] = { +static const unsigned char bssgp_ra_upd_acc[] = { 0x00, 0xbb, 0xc5, 0x46, 0x79, 0x00, 0x50, 0x20, - 0x16, 0x82, 0x02, 0x58, 0x13, 0x9d, 0x19, 0x13, - 0x42, 0x33, 0x57, 0x2b, 0xf7, 0xc8, 0x48, 0x02, - 0x13, 0x48, 0x50, 0xc8, 0x48, 0x02, 0x14, 0x48, - 0x50, 0xc8, 0x48, 0x02, 0x17, 0x49, 0x10, 0xc8, - 0x48, 0x02, 0x00, 0x0a, 0x82, 0x07, 0x04, 0x0d, - 0x88, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, - 0x18, 0x00, 0x81, 0x00, 0x0e, 0x9d, 0x41, 0xc0, - 0x19, 0x08, 0x09, 0x00, 0x49, 0x21, 0x63, 0x54, - 0x40, 0x50, 0x60, 0x19, 0x54, 0xab, 0xb3, 0x18, - 0x05, 0xf4, 0xef, 0xe2, 0xb7, 0x00, 0x17, 0x16, - 0xd7, 0x59, 0x65 + 0x16, 0x82, 0x02, 0x58, 0x13, 0x99, 0x18, 0xb3, + 0x43, 0x2b, 0x25, 0x96, 0x62, 0x00, 0x60, 0x80, + 0x9a, 0xc2, 0xc6, 0x62, 0x00, 0x60, 0x80, 0xba, + 0xc8, 0xc6, 0x62, 0x00, 0x60, 0x80, 0x00, 0x0a, + 0x82, 0x08, 0x02, 0x0d, 0x88, 0x11, 0x12, 0x13, + 0x14, 0x15, 0x16, 0x17, 0x18, 0x00, 0x81, 0x00, + 0x0e, 0x9d, 0x41, 0xc0, 0x19, 0x08, 0x09, 0x00, + 0x49, 0x21, 0x63, 0x54, 0x40, 0x50, 0x60, 0x19, + 0x54, 0xab, 0xb3, 0x18, 0x05, 0xf4, 0xef, 0xe2, + 0xb7, 0x00, 0x17, 0x16, 0xd7, 0x59, 0x65 }; /* Base Station Subsystem GPRS Protocol: GSM A-I/F DTAP - Activate PDP Context Request */ diff --git a/openbsc/tests/gbproxy/gbproxy_test.ok b/openbsc/tests/gbproxy/gbproxy_test.ok index 1b3981308..74e895505 100644 --- a/openbsc/tests/gbproxy/gbproxy_test.ok +++ b/openbsc/tests/gbproxy/gbproxy_test.ok @@ -1666,10 +1666,10 @@ MESSAGE to SGSN at 0x05060708:32000, msg length 44 result (IDENT RESPONSE) = 44 PROCESSING ATTACH ACCEPT from 0x05060708:32000 -00 00 10 02 00 bb c5 46 79 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 9e 41 c0 05 08 02 01 49 04 21 63 54 40 50 60 19 cd d7 08 17 16 18 05 f4 ef e2 b7 00 42 67 9a +00 00 10 02 00 bb c5 46 79 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 9e 41 c0 05 08 02 01 49 04 21 63 54 40 50 60 19 cd d7 08 17 16 18 05 f4 ef e2 b7 00 53 62 f1 CALLBACK, event 0, msg length 88, bvci 0x1002 -00 00 10 02 00 bb c5 46 79 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 9e 41 c0 05 08 02 01 49 04 21 63 54 40 50 60 19 cd d7 08 17 16 18 05 f4 ef e2 b7 00 42 67 9a +00 00 10 02 00 bb c5 46 79 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 9e 41 c0 05 08 02 01 49 04 21 63 54 40 50 60 19 cd d7 08 17 16 18 05 f4 ef e2 b7 00 53 62 f1 NS UNITDATA MESSAGE to BSS, BVCI 0x1002, msg length 88 (gprs_ns_sendmsg) MESSAGE to BSS at 0x01020304:1111, msg length 92 @@ -1678,14 +1678,14 @@ MESSAGE to BSS at 0x01020304:1111, msg length 92 result (ATTACH ACCEPT) = 92 PROCESSING ATTACH COMPLETE from 0x01020304:1111 -00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 75 30 00 80 0e 00 08 01 c0 11 08 03 ff ff ff +00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 75 30 00 80 0e 00 08 01 c0 11 08 03 ea 67 11 CALLBACK, event 0, msg length 31, bvci 0x1002 -00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 75 30 00 80 0e 00 08 01 c0 11 08 03 ff ff ff +00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 75 30 00 80 0e 00 08 01 c0 11 08 03 ea 67 11 NS UNITDATA MESSAGE to SGSN, BVCI 0x1002, msg length 31 (gprs_ns_sendmsg) MESSAGE to SGSN at 0x05060708:32000, msg length 35 -00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 21 63 54 40 50 60 75 30 00 80 0e 00 08 01 c0 11 08 03 ff ff ff +00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 21 63 54 40 50 60 75 30 00 80 0e 00 08 01 c0 11 08 03 ea 67 11 result (ATTACH COMPLETE) = 35 @@ -1792,16 +1792,16 @@ MESSAGE to SGSN at 0x05060708:32000, msg length 89 result (RA UPD REQ) = 89 PROCESSING RA UPD ACC from 0x05060708:32000 -00 00 10 02 00 bb c5 46 79 00 50 20 16 82 02 58 13 9d 19 13 42 33 57 2b f7 c8 48 02 13 48 50 c8 48 02 14 48 50 c8 48 02 17 49 10 c8 48 02 00 0a 82 07 04 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 9d 41 c0 19 08 09 00 49 21 63 54 40 50 60 19 54 ab b3 18 05 f4 ef e2 b7 00 17 16 d7 59 65 +00 00 10 02 00 bb c5 46 79 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 9d 41 c0 19 08 09 00 49 21 63 54 40 50 60 19 54 ab b3 18 05 f4 ef e2 b7 00 17 16 d7 59 65 -CALLBACK, event 0, msg length 91, bvci 0x1002 -00 00 10 02 00 bb c5 46 79 00 50 20 16 82 02 58 13 9d 19 13 42 33 57 2b f7 c8 48 02 13 48 50 c8 48 02 14 48 50 c8 48 02 17 49 10 c8 48 02 00 0a 82 07 04 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 9d 41 c0 19 08 09 00 49 21 63 54 40 50 60 19 54 ab b3 18 05 f4 ef e2 b7 00 17 16 d7 59 65 +CALLBACK, event 0, msg length 87, bvci 0x1002 +00 00 10 02 00 bb c5 46 79 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 9d 41 c0 19 08 09 00 49 21 63 54 40 50 60 19 54 ab b3 18 05 f4 ef e2 b7 00 17 16 d7 59 65 -NS UNITDATA MESSAGE to BSS, BVCI 0x1002, msg length 91 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 95 -00 00 10 02 00 bb c5 46 79 00 50 20 16 82 02 58 13 9d 19 13 42 33 57 2b f7 c8 48 02 13 48 50 c8 48 02 14 48 50 c8 48 02 17 49 10 c8 48 02 00 0a 82 07 04 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 9d 41 c0 19 08 09 00 49 11 22 33 40 50 60 19 54 ab b3 18 05 f4 ef e2 b7 00 17 16 3a 03 54 +NS UNITDATA MESSAGE to BSS, BVCI 0x1002, msg length 87 (gprs_ns_sendmsg) +MESSAGE to BSS at 0x01020304:1111, msg length 91 +00 00 10 02 00 bb c5 46 79 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 9d 41 c0 19 08 09 00 49 11 22 33 40 50 60 19 54 ab b3 18 05 f4 ef e2 b7 00 17 16 3a 03 54 -result (RA UPD ACC) = 95 +result (RA UPD ACC) = 91 PROCESSING ACT PDP CTX REQ (REMOVE APN) from 0x01020304:1111 00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 75 30 00 80 0e 00 35 01 c0 0d 0a 41 05 03 0c 00 00 1f 10 00 00 00 00 00 00 00 00 02 01 21 28 03 02 61 62 27 14 80 80 21 10 01 00 00 10 81 06 00 00 00 00 83 06 00 00 00 00 5a ff 02 -- cgit v1.2.3 From c53f2a6961780153fbf97910609c827a0e9300c3 Mon Sep 17 00:00:00 2001 From: Jacob Erlbeck Date: Fri, 15 Aug 2014 14:56:28 +0200 Subject: gbproxy/test: Generate BSSGP and LLC layer for DTAP messages This patch adds the functions send_bssgp_ul_unitdata(), send_bssgp_dl_unitdata(), send_llc_ul_ui(), and send_llc_dl_ui(). They are used instead of send_ns_unitdata() in test_gbproxy_ra_patching(). This make it easier to modify TLLI, N(U), and other parameters. Sponsored-by: On-Waves ehf --- openbsc/tests/gbproxy/gbproxy_test.c | 449 +++++++++++++++++++++++------------ 1 file changed, 299 insertions(+), 150 deletions(-) diff --git a/openbsc/tests/gbproxy/gbproxy_test.c b/openbsc/tests/gbproxy/gbproxy_test.c index c463222fb..ed30af8de 100644 --- a/openbsc/tests/gbproxy/gbproxy_test.c +++ b/openbsc/tests/gbproxy/gbproxy_test.c @@ -32,6 +32,7 @@ #include #include +#include #include #define REMOTE_BSS_ADDR 0x01020304 @@ -139,149 +140,90 @@ static int dump_peers(FILE *stream, int indent, time_t now, return 0; } -/* Base Station Subsystem GPRS Protocol: GSM A-I/F DTAP - Attach Request */ -static const unsigned char bssgp_attach_req[75] = { - 0x01, 0xbb, 0xc5, 0x46, 0x79, 0x00, 0x00, 0x04, - 0x08, 0x88, 0x11, 0x22, 0x33, 0x40, 0x50, 0x60, - 0x75, 0x30, 0x00, 0x80, 0x0e, 0x00, 0x34, 0x01, - 0xc0, 0x01, 0x08, 0x01, 0x02, 0xf5, 0xe0, 0x21, - 0x08, 0x02, 0x05, 0xf4, 0xfb, 0xc5, 0x46, 0x79, - 0x11, 0x22, 0x33, 0x40, 0x50, 0x60, 0x19, 0x18, - 0xb3, 0x43, 0x2b, 0x25, 0x96, 0x62, 0x00, 0x60, - 0x80, 0x9a, 0xc2, 0xc6, 0x62, 0x00, 0x60, 0x80, - 0xba, 0xc8, 0xc6, 0x62, 0x00, 0x60, 0x80, 0x00, - 0x16, 0x6d, 0x01 +/* DTAP - Attach Request */ +static const unsigned char dtap_attach_req[] = { + 0x08, 0x01, 0x02, 0xf5, 0xe0, 0x21, 0x08, 0x02, + 0x05, 0xf4, 0xfb, 0xc5, 0x46, 0x79, 0x11, 0x22, + 0x33, 0x40, 0x50, 0x60, 0x19, 0x18, 0xb3, 0x43, + 0x2b, 0x25, 0x96, 0x62, 0x00, 0x60, 0x80, 0x9a, + 0xc2, 0xc6, 0x62, 0x00, 0x60, 0x80, 0xba, 0xc8, + 0xc6, 0x62, 0x00, 0x60, 0x80, 0x00, }; -/* Base Station Subsystem GPRS Protocol: GSM A-I/F DTAP - Identity Request */ -static const unsigned char bssgp_identity_req[] = { - 0x00, 0xbb, 0xc5, 0x46, 0x79, 0x00, 0x50, 0x20, - 0x16, 0x82, 0x02, 0x58, 0x0e, 0x89, 0x41, 0xc0, - 0x01, 0x08, 0x15, 0x01, 0xff, 0x6c, 0xba +/* DTAP - Identity Request */ +static const unsigned char dtap_identity_req[] = { + 0x08, 0x15, 0x01 }; -/* Base Station Subsystem GPRS Protocol: GSM A-I/F DTAP - Identity Response */ -static const unsigned char bssgp_identity_resp[] = { - 0x01, 0xbb, 0xc5, 0x46, 0x79, 0x00, 0x00, 0x04, - 0x08, 0x88, 0x11, 0x22, 0x33, 0x40, 0x50, 0x60, - 0x75, 0x30, 0x00, 0x80, 0x0e, 0x00, 0x11, 0x01, - 0xc0, 0x0d, 0x08, 0x16, 0x08, 0x11, 0x12, 0x13, - 0x14, 0x15, 0x16, 0x17, 0x18, 0xb7, 0x1b, 0x9a +/* DTAP - Identity Response */ +static const unsigned char dtap_identity_resp[] = { + 0x08, 0x16, 0x08, 0x11, 0x12, 0x13, 0x14, 0x15, + 0x16, 0x17, 0x18 }; -/* Base Station Subsystem GPRS Protocol: GSM A-I/F DTAP - Attach Accept */ -static const unsigned char bssgp_attach_acc[88] = { - 0x00, 0xbb, 0xc5, 0x46, 0x79, 0x00, 0x50, 0x20, - 0x16, 0x82, 0x02, 0x58, 0x13, 0x99, 0x18, 0xb3, - 0x43, 0x2b, 0x25, 0x96, 0x62, 0x00, 0x60, 0x80, - 0x9a, 0xc2, 0xc6, 0x62, 0x00, 0x60, 0x80, 0xba, - 0xc8, 0xc6, 0x62, 0x00, 0x60, 0x80, 0x00, 0x0a, - 0x82, 0x08, 0x02, 0x0d, 0x88, 0x11, 0x12, 0x13, - 0x14, 0x15, 0x16, 0x17, 0x18, 0x00, 0x81, 0x00, - 0x0e, 0x9e, 0x41, 0xc0, 0x05, 0x08, 0x02, 0x01, - 0x49, 0x04, 0x21, 0x63, 0x54, 0x40, 0x50, 0x60, - 0x19, 0xcd, 0xd7, 0x08, 0x17, 0x16, 0x18, 0x05, - 0xf4, 0xef, 0xe2, 0xb7, 0x00, 0x53, 0x62, 0xf1 +/* DTAP - Attach Accept */ +static const unsigned char dtap_attach_acc[] = { + 0x08, 0x02, 0x01, 0x49, 0x04, 0x21, 0x63, 0x54, + 0x40, 0x50, 0x60, 0x19, 0xcd, 0xd7, 0x08, 0x17, + 0x16, 0x18, 0x05, 0xf4, 0xef, 0xe2, 0xb7, 0x00 }; -/* Base Station Subsystem GPRS Protocol: GSM A-I/F DTAP - Attach Complete */ -static const unsigned char bssgp_attach_complete[] = { - 0x01, 0xef, 0xe2, 0xb7, 0x00, 0x00, 0x00, 0x04, - 0x08, 0x88, 0x11, 0x22, 0x33, 0x40, 0x50, 0x60, - 0x75, 0x30, 0x00, 0x80, 0x0e, 0x00, 0x08, 0x01, - 0xc0, 0x11, 0x08, 0x03, 0xea, 0x67, 0x11 +/* DTAP - Attach Complete */ +static const unsigned char dtap_attach_complete[] = { + 0x08, 0x03 }; -/* Base Station Subsystem GPRS Protocol: GSM A-I/F DTAP - GMM Information */ -static const unsigned char bssgp_gmm_information[66] = { - 0x00, 0xef, 0xe2, 0xb7, 0x00, 0x00, 0x50, 0x20, - 0x16, 0x82, 0x02, 0x58, 0x13, 0x99, 0x18, 0xb3, - 0x43, 0x2b, 0x25, 0x96, 0x62, 0x00, 0x60, 0x80, - 0x9a, 0xc2, 0xc6, 0x62, 0x00, 0x60, 0x80, 0xba, - 0xc8, 0xc6, 0x62, 0x00, 0x60, 0x80, 0x00, 0x0a, - 0x82, 0x08, 0x02, 0x0d, 0x88, 0x11, 0x12, 0x13, - 0x14, 0x15, 0x16, 0x17, 0x18, 0x00, 0x81, 0x00, - 0x0e, 0x88, 0x41, 0xc0, 0x09, 0x08, 0x21, 0x04, - 0xba, 0x3d +/* DTAP - GMM Information */ +static const unsigned char dtap_gmm_information[] = { + 0x08, 0x21 }; -/* Base Station Subsystem GPRS Protocol: GSM A-I/F DTAP - Routing Area Update Request */ -static const unsigned char bssgp_ra_upd_req[85] = { - 0x01, 0xbb, 0xc5, 0x46, 0x79, 0x00, 0x00, 0x04, - 0x08, 0x88, 0x11, 0x22, 0x33, 0x40, 0x50, 0x60, - 0x70, 0x80, 0x00, 0x80, 0x0e, 0x00, 0x3e, 0x01, - 0xc0, 0x15, 0x08, 0x08, 0x10, 0x11, 0x22, 0x33, - 0x40, 0x50, 0x60, 0x1d, 0x19, 0x13, 0x42, 0x33, - 0x57, 0x2b, 0xf7, 0xc8, 0x48, 0x02, 0x13, 0x48, - 0x50, 0xc8, 0x48, 0x02, 0x14, 0x48, 0x50, 0xc8, - 0x48, 0x02, 0x17, 0x49, 0x10, 0xc8, 0x48, 0x02, - 0x00, 0x19, 0x8b, 0xb2, 0x92, 0x17, 0x16, 0x27, - 0x07, 0x04, 0x31, 0x02, 0xe5, 0xe0, 0x32, 0x02, - 0x20, 0x00, 0x96, 0x3e, 0x97 +/* DTAP - Routing Area Update Request */ +static const unsigned char dtap_ra_upd_req[] = { + 0x08, 0x08, 0x10, 0x11, 0x22, 0x33, 0x40, 0x50, + 0x60, 0x1d, 0x19, 0x13, 0x42, 0x33, 0x57, 0x2b, + 0xf7, 0xc8, 0x48, 0x02, 0x13, 0x48, 0x50, 0xc8, + 0x48, 0x02, 0x14, 0x48, 0x50, 0xc8, 0x48, 0x02, + 0x17, 0x49, 0x10, 0xc8, 0x48, 0x02, 0x00, 0x19, + 0x8b, 0xb2, 0x92, 0x17, 0x16, 0x27, 0x07, 0x04, + 0x31, 0x02, 0xe5, 0xe0, 0x32, 0x02, 0x20, 0x00 }; -/* Base Station Subsystem GPRS Protocol: GSM A-I/F DTAP - Routing Area Update Accept */ -static const unsigned char bssgp_ra_upd_acc[] = { - 0x00, 0xbb, 0xc5, 0x46, 0x79, 0x00, 0x50, 0x20, - 0x16, 0x82, 0x02, 0x58, 0x13, 0x99, 0x18, 0xb3, - 0x43, 0x2b, 0x25, 0x96, 0x62, 0x00, 0x60, 0x80, - 0x9a, 0xc2, 0xc6, 0x62, 0x00, 0x60, 0x80, 0xba, - 0xc8, 0xc6, 0x62, 0x00, 0x60, 0x80, 0x00, 0x0a, - 0x82, 0x08, 0x02, 0x0d, 0x88, 0x11, 0x12, 0x13, - 0x14, 0x15, 0x16, 0x17, 0x18, 0x00, 0x81, 0x00, - 0x0e, 0x9d, 0x41, 0xc0, 0x19, 0x08, 0x09, 0x00, - 0x49, 0x21, 0x63, 0x54, 0x40, 0x50, 0x60, 0x19, - 0x54, 0xab, 0xb3, 0x18, 0x05, 0xf4, 0xef, 0xe2, - 0xb7, 0x00, 0x17, 0x16, 0xd7, 0x59, 0x65 +/* DTAP - Routing Area Update Accept */ +static const unsigned char dtap_ra_upd_acc[] = { + 0x08, 0x09, 0x00, 0x49, 0x21, 0x63, 0x54, + 0x40, 0x50, 0x60, 0x19, 0x54, 0xab, 0xb3, 0x18, + 0x05, 0xf4, 0xef, 0xe2, 0xb7, 0x00, 0x17, 0x16, }; -/* Base Station Subsystem GPRS Protocol: GSM A-I/F DTAP - Activate PDP Context Request */ -static const unsigned char bssgp_act_pdp_ctx_req[76] = { - 0x01, 0xef, 0xe2, 0xb7, 0x00, 0x00, 0x00, 0x04, - 0x08, 0x88, 0x11, 0x22, 0x33, 0x40, 0x50, 0x60, - 0x75, 0x30, 0x00, 0x80, 0x0e, 0x00, 0x35, 0x01, - 0xc0, 0x0d, 0x0a, 0x41, 0x05, 0x03, 0x0c, 0x00, +/* DTAP - Activate PDP Context Request */ +static const unsigned char dtap_act_pdp_ctx_req[] = { + 0x0a, 0x41, 0x05, 0x03, 0x0c, 0x00, 0x00, 0x1f, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x01, 0x21, 0x28, 0x03, 0x02, 0x61, 0x62, 0x27, 0x14, 0x80, 0x80, 0x21, 0x10, 0x01, 0x00, 0x00, 0x10, 0x81, 0x06, 0x00, 0x00, 0x00, 0x00, 0x83, 0x06, 0x00, 0x00, 0x00, - 0x00, 0x5a, 0xff, 0x02 + 0x00 }; -/* Base Station Subsystem GPRS Protocol: GSM A-I/F DTAP - Detach Request (MO) */ +/* DTAP - Detach Request (MO) */ /* normal detach, power_off = 1 */ -static const unsigned char bssgp_detach_po_req[44] = { - 0x01, 0xef, 0xe2, 0xb7, 0x00, 0x00, 0x00, 0x04, - 0x08, 0x88, 0x11, 0x22, 0x33, 0x40, 0x50, 0x60, - 0x75, 0x30, 0x00, 0x80, 0x0e, 0x00, 0x15, 0x01, - 0xc0, 0x19, 0x08, 0x05, 0x09, 0x18, 0x05, 0xf4, - 0xef, 0xe2, 0xb7, 0x00, 0x19, 0x03, 0xb9, 0x97, - 0xcb, 0x84, 0x0c, 0xeb +static const unsigned char dtap_detach_po_req[] = { + 0x08, 0x05, 0x09, 0x18, 0x05, 0xf4, 0xef, 0xe2, + 0xb7, 0x00, 0x19, 0x03, 0xb9, 0x97, 0xcb }; -/* Base Station Subsystem GPRS Protocol: GSM A-I/F DTAP - Detach Request (MO) */ +/* DTAP - Detach Request (MO) */ /* normal detach, power_off = 0 */ -static const unsigned char bssgp_detach_req[44] = { - 0x01, 0xef, 0xe2, 0xb7, 0x00, 0x00, 0x00, 0x04, - 0x08, 0x88, 0x11, 0x22, 0x33, 0x40, 0x50, 0x60, - 0x75, 0x30, 0x00, 0x80, 0x0e, 0x00, 0x15, 0x01, - 0xc0, 0x19, 0x08, 0x05, 0x01, 0x18, 0x05, 0xf4, - 0xef, 0xe2, 0xb7, 0x00, 0x19, 0x03, 0xb9, 0x97, - 0xcb, 0x7e, 0xe1, 0x41 +static const unsigned char dtap_detach_req[] = { + 0x08, 0x05, 0x01, 0x18, 0x05, 0xf4, 0xef, 0xe2, + 0xb7, 0x00, 0x19, 0x03, 0xb9, 0x97, 0xcb }; -/* Base Station Subsystem GPRS Protocol: GSM A-I/F DTAP - Detach Accept */ -static const unsigned char bssgp_detach_acc[67] = { - 0x00, 0xef, 0xe2, 0xb7, 0x00, 0x00, 0x50, 0x20, - 0x16, 0x82, 0x02, 0x58, 0x13, 0x99, 0x18, 0xb3, - 0x43, 0x2b, 0x25, 0x96, 0x62, 0x00, 0x60, 0x80, - 0x9a, 0xc2, 0xc6, 0x62, 0x00, 0x60, 0x80, 0xba, - 0xc8, 0xc6, 0x62, 0x00, 0x60, 0x80, 0x00, 0x0a, - 0x82, 0x08, 0x02, 0x0d, 0x88, 0x11, 0x12, 0x13, - 0x14, 0x15, 0x16, 0x17, 0x18, 0x00, 0x81, 0x00, - 0x0e, 0x89, 0x41, 0xc0, 0x15, 0x08, 0x06, 0x00, - 0xf7, 0x35, 0xf0 +/* DTAP - Detach Accept */ +static const unsigned char dtap_detach_acc[] = { + 0x08, 0x06, 0x00 }; static int gprs_process_message(struct gprs_ns_inst *nsi, const char *text, @@ -383,6 +325,106 @@ static void send_ns_unitdata(struct gprs_ns_inst *nsi, const char *text, gprs_process_message(nsi, text ? text : "UNITDATA", src_addr, msg, bssgp_msg_size + 4); } +static void send_bssgp_ul_unitdata( + struct gprs_ns_inst *nsi, const char *text, + struct sockaddr_in *src_addr, uint16_t nsbvci, uint32_t tlli, + struct gprs_ra_id *raid, uint16_t cell_id, + const uint8_t *llc_msg, size_t llc_msg_size) +{ + /* GPRS Network Service, PDU type: NS_UNITDATA */ + /* Base Station Subsystem GPRS Protocol: UL_UNITDATA */ + unsigned char msg[4096] = { + 0x01, /* TLLI */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, + 0x08, 0x88, /* RAI */ 0x11, 0x22, 0x33, 0x40, 0x50, 0x60, + /* CELL ID */ 0x00, 0x00, 0x00, 0x80, 0x0e, /* LLC LEN */ 0x00, 0x00, + }; + + size_t bssgp_msg_size = 23 + llc_msg_size; + + OSMO_ASSERT(bssgp_msg_size <= sizeof(msg)); + + gsm48_construct_ra(msg + 10, raid); + msg[1] = (uint8_t)(tlli >> 24); + msg[2] = (uint8_t)(tlli >> 16); + msg[3] = (uint8_t)(tlli >> 8); + msg[4] = (uint8_t)(tlli >> 0); + msg[16] = cell_id / 256; + msg[17] = cell_id % 256; + msg[21] = llc_msg_size / 256; + msg[22] = llc_msg_size % 256; + memcpy(msg + 23, llc_msg, llc_msg_size); + + send_ns_unitdata(nsi, text ? text : "BSSGP UL UNITDATA", + src_addr, nsbvci, msg, bssgp_msg_size); +} + +static void send_bssgp_dl_unitdata( + struct gprs_ns_inst *nsi, const char *text, + struct sockaddr_in *src_addr, uint16_t nsbvci, uint32_t tlli, + int with_racap_drx, const uint8_t *imsi, size_t imsi_size, + const uint8_t *llc_msg, size_t llc_msg_size) +{ + /* Base Station Subsystem GPRS Protocol: DL_UNITDATA */ + unsigned char msg[4096] = { + 0x00, /* TLLI */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x20, + 0x16, 0x82, 0x02, 0x58, + }; + unsigned char racap_drx[] = { + 0x13, 0x99, 0x18, 0xb3, 0x43, 0x2b, 0x25, 0x96, + 0x62, 0x00, 0x60, 0x80, 0x9a, 0xc2, 0xc6, 0x62, + 0x00, 0x60, 0x80, 0xba, 0xc8, 0xc6, 0x62, 0x00, + 0x60, 0x80, 0x00, 0x0a, 0x82, 0x08, 0x02 + }; + + size_t bssgp_msg_size = 0; + + OSMO_ASSERT(51 + imsi_size + llc_msg_size <= sizeof(msg)); + + msg[1] = (uint8_t)(tlli >> 24); + msg[2] = (uint8_t)(tlli >> 16); + msg[3] = (uint8_t)(tlli >> 8); + msg[4] = (uint8_t)(tlli >> 0); + + bssgp_msg_size = 12; + + if (with_racap_drx) { + memcpy(msg + bssgp_msg_size, racap_drx, sizeof(racap_drx)); + bssgp_msg_size += sizeof(racap_drx); + } + + if (imsi) { + OSMO_ASSERT(imsi_size <= 127); + msg[bssgp_msg_size] = BSSGP_IE_IMSI; + msg[bssgp_msg_size + 1] = 0x80 | imsi_size; + memcpy(msg + bssgp_msg_size + 2, imsi, imsi_size); + bssgp_msg_size += 2 + imsi_size; + } + + if ((bssgp_msg_size % 4) != 0) { + size_t abytes = (4 - (bssgp_msg_size + 2) % 4) % 4; + msg[bssgp_msg_size] = BSSGP_IE_ALIGNMENT; + msg[bssgp_msg_size + 1] = 0x80 | abytes; + memset(msg + bssgp_msg_size + 2, 0, abytes); + bssgp_msg_size += 2 + abytes; + } + + msg[bssgp_msg_size] = BSSGP_IE_LLC_PDU; + if (llc_msg_size < 128) { + msg[bssgp_msg_size + 1] = 0x80 | llc_msg_size; + bssgp_msg_size += 2; + } else { + msg[bssgp_msg_size + 1] = llc_msg_size / 256; + msg[bssgp_msg_size + 2] = llc_msg_size % 256; + bssgp_msg_size += 3; + } + memcpy(msg + bssgp_msg_size, llc_msg, llc_msg_size); + bssgp_msg_size += llc_msg_size; + + + send_ns_unitdata(nsi, text ? text : "BSSGP DL UNITDATA", + src_addr, nsbvci, msg, bssgp_msg_size); +} + static void send_bssgp_reset(struct gprs_ns_inst *nsi, struct sockaddr_in *src_addr, uint16_t bvci) { @@ -447,6 +489,82 @@ static void send_bssgp_suspend_ack(struct gprs_ns_inst *nsi, send_ns_unitdata(nsi, "BVC_SUSPEND_ACK", src_addr, 0, msg, sizeof(msg)); } +static void send_llc_ul_ui( + struct gprs_ns_inst *nsi, const char *text, + struct sockaddr_in *src_addr, uint16_t nsbvci, uint32_t tlli, + struct gprs_ra_id *raid, uint16_t cell_id, + unsigned sapi, unsigned nu, + const uint8_t *msg, size_t msg_size) +{ + unsigned char llc_msg[4096] = { + 0x00, 0xc0, 0x01 + }; + + size_t llc_msg_size = 3 + msg_size + 3; + uint8_t e_bit = 0; + uint8_t pm_bit = 1; + unsigned fcs; + + nu &= 0x01ff; + + OSMO_ASSERT(llc_msg_size <= sizeof(llc_msg)); + + llc_msg[0] = (sapi & 0x0f); + llc_msg[1] = 0xc0 | (nu >> 6); /* UI frame */ + llc_msg[2] = (nu << 2) | ((e_bit & 1) << 1) | (pm_bit & 1); + + memcpy(llc_msg + 3, msg, msg_size); + + fcs = gprs_llc_fcs(llc_msg, msg_size + 3); + llc_msg[3 + msg_size + 0] = (uint8_t)(fcs >> 0); + llc_msg[3 + msg_size + 1] = (uint8_t)(fcs >> 8); + llc_msg[3 + msg_size + 2] = (uint8_t)(fcs >> 16); + + send_bssgp_ul_unitdata(nsi, text ? text : "LLC UI", + src_addr, nsbvci, tlli, raid, cell_id, + llc_msg, llc_msg_size); +} + +static void send_llc_dl_ui( + struct gprs_ns_inst *nsi, const char *text, + struct sockaddr_in *src_addr, uint16_t nsbvci, uint32_t tlli, + int with_racap_drx, const uint8_t *imsi, size_t imsi_size, + unsigned sapi, unsigned nu, + const uint8_t *msg, size_t msg_size) +{ + /* GPRS Network Service, PDU type: NS_UNITDATA */ + /* Base Station Subsystem GPRS Protocol: UL_UNITDATA */ + unsigned char llc_msg[4096] = { + 0x00, 0x00, 0x01 + }; + + size_t llc_msg_size = 3 + msg_size + 3; + uint8_t e_bit = 0; + uint8_t pm_bit = 1; + unsigned fcs; + + nu &= 0x01ff; + + OSMO_ASSERT(llc_msg_size <= sizeof(llc_msg)); + + llc_msg[0] = 0x40 | (sapi & 0x0f); + llc_msg[1] = 0xc0 | (nu >> 6); /* UI frame */ + llc_msg[2] = (nu << 2) | ((e_bit & 1) << 1) | (pm_bit & 1); + + memcpy(llc_msg + 3, msg, msg_size); + + fcs = gprs_llc_fcs(llc_msg, msg_size + 3); + llc_msg[3 + msg_size + 0] = (uint8_t)(fcs >> 0); + llc_msg[3 + msg_size + 1] = (uint8_t)(fcs >> 8); + llc_msg[3 + msg_size + 2] = (uint8_t)(fcs >> 16); + + send_bssgp_dl_unitdata(nsi, text ? text : "LLC UI", + src_addr, nsbvci, tlli, + with_racap_drx, imsi, imsi_size, + llc_msg, llc_msg_size); +} + + static void setup_ns(struct gprs_ns_inst *nsi, struct sockaddr_in *src_addr, uint16_t nsvci, uint16_t nsei) { @@ -979,9 +1097,12 @@ static void test_gbproxy_ra_patching() {.mcc = 123, .mnc = 456, .lac = 16464, .rac = 96}; struct gprs_ra_id rai_unknown = {.mcc = 1, .mnc = 99, .lac = 99, .rac = 96}; + uint16_t cell_id = 0x7530; const char *err_msg = NULL; const uint32_t ptmsi = 0xefe2b700; const uint32_t local_tlli = 0xefe2b700; + const uint32_t foreign_tlli = 0xbbc54679; + const uint8_t imsi[] = {0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18}; struct gbproxy_tlli_info *tlli_info; struct gbproxy_peer *peer; @@ -1032,17 +1153,25 @@ static void test_gbproxy_ra_patching() printf("--- Send message from BSS 1 to SGSN, BVCI 0x1002 ---\n\n"); - send_ns_unitdata(nsi, "ATTACH REQUEST", &bss_peer[0], 0x1002, - bssgp_attach_req, sizeof(bssgp_attach_req)); + send_llc_ul_ui(nsi, "ATTACH REQUEST", &bss_peer[0], 0x1002, + foreign_tlli, &rai_bss, cell_id, + GPRS_SAPI_GMM, 0, + dtap_attach_req, sizeof(dtap_attach_req)); - send_ns_unitdata(nsi, "IDENT REQUEST", &sgsn_peer, 0x1002, - bssgp_identity_req, sizeof(bssgp_identity_req)); + send_llc_dl_ui(nsi, "IDENT REQUEST", &sgsn_peer, 0x1002, + foreign_tlli, 0, NULL, 0, + GPRS_SAPI_GMM, 0, + dtap_identity_req, sizeof(dtap_identity_req)); - send_ns_unitdata(nsi, "IDENT RESPONSE", &bss_peer[0], 0x1002, - bssgp_identity_resp, sizeof(bssgp_identity_resp)); + send_llc_ul_ui(nsi, "IDENT RESPONSE", &bss_peer[0], 0x1002, + foreign_tlli, &rai_bss, cell_id, + GPRS_SAPI_GMM, 3, + dtap_identity_resp, sizeof(dtap_identity_resp)); - send_ns_unitdata(nsi, "ATTACH ACCEPT", &sgsn_peer, 0x1002, - bssgp_attach_acc, sizeof(bssgp_attach_acc)); + send_llc_dl_ui(nsi, "ATTACH ACCEPT", &sgsn_peer, 0x1002, + foreign_tlli, 1, imsi, sizeof(imsi), + GPRS_SAPI_GMM, 1, + dtap_attach_acc, sizeof(dtap_attach_acc)); tlli_info = gbprox_find_tlli(peer, local_tlli); OSMO_ASSERT(tlli_info); @@ -1051,8 +1180,10 @@ static void test_gbproxy_ra_patching() OSMO_ASSERT(!tlli_info->bss_validated); OSMO_ASSERT(!tlli_info->net_validated); - send_ns_unitdata(nsi, "ATTACH COMPLETE", &bss_peer[0], 0x1002, - bssgp_attach_complete, sizeof(bssgp_attach_complete)); + send_llc_ul_ui(nsi, "ATTACH COMPLETE", &bss_peer[0], 0x1002, + local_tlli, &rai_bss, cell_id, + GPRS_SAPI_GMM, 4, + dtap_attach_complete, sizeof(dtap_attach_complete)); tlli_info = gbprox_find_tlli(peer, local_tlli); OSMO_ASSERT(tlli_info); @@ -1062,9 +1193,10 @@ static void test_gbproxy_ra_patching() OSMO_ASSERT(!tlli_info->net_validated); /* Replace APN (1) */ - send_ns_unitdata(nsi, "ACT PDP CTX REQ (REPLACE APN)", - &bss_peer[0], 0x1002, - bssgp_act_pdp_ctx_req, sizeof(bssgp_act_pdp_ctx_req)); + send_llc_ul_ui(nsi, "ACT PDP CTX REQ (REPLACE APN)", &bss_peer[0], 0x1002, + local_tlli, &rai_bss, cell_id, + GPRS_SAPI_GMM, 3, + dtap_act_pdp_ctx_req, sizeof(dtap_act_pdp_ctx_req)); tlli_info = gbprox_find_tlli(peer, local_tlli); OSMO_ASSERT(tlli_info); @@ -1073,8 +1205,10 @@ static void test_gbproxy_ra_patching() OSMO_ASSERT(tlli_info->bss_validated); OSMO_ASSERT(!tlli_info->net_validated); - send_ns_unitdata(nsi, "GMM INFO", &sgsn_peer, 0x1002, - bssgp_gmm_information, sizeof(bssgp_gmm_information)); + send_llc_dl_ui(nsi, "GMM INFO", &sgsn_peer, 0x1002, + local_tlli, 1, imsi, sizeof(imsi), + GPRS_SAPI_GMM, 2, + dtap_gmm_information, sizeof(dtap_gmm_information)); tlli_info = gbprox_find_tlli(peer, local_tlli); OSMO_ASSERT(tlli_info); @@ -1082,47 +1216,60 @@ static void test_gbproxy_ra_patching() OSMO_ASSERT(tlli_info->tlli == local_tlli); /* Replace APN (2) */ - send_ns_unitdata(nsi, "ACT PDP CTX REQ (REPLACE APN)", - &bss_peer[0], 0x1002, - bssgp_act_pdp_ctx_req, sizeof(bssgp_act_pdp_ctx_req)); + send_llc_ul_ui(nsi, "ACT PDP CTX REQ (REPLACE APN)", &bss_peer[0], 0x1002, + local_tlli, &rai_bss, cell_id, + GPRS_SAPI_GMM, 3, + dtap_act_pdp_ctx_req, sizeof(dtap_act_pdp_ctx_req)); gbcfg.core_apn[0] = 0; gbcfg.core_apn_size = 0; /* Remove APN */ - send_ns_unitdata(nsi, "ACT PDP CTX REQ (REMOVE APN)", - &bss_peer[0], 0x1002, - bssgp_act_pdp_ctx_req, sizeof(bssgp_act_pdp_ctx_req)); + send_llc_ul_ui(nsi, "ACT PDP CTX REQ (REMOVE APN)", &bss_peer[0], 0x1002, + local_tlli, &rai_bss, cell_id, + GPRS_SAPI_GMM, 3, + dtap_act_pdp_ctx_req, sizeof(dtap_act_pdp_ctx_req)); dump_peers(stdout, 0, 0, &gbcfg); /* Detach */ - send_ns_unitdata(nsi, "DETACH REQ", &bss_peer[0], 0x1002, - bssgp_detach_req, sizeof(bssgp_detach_req)); + send_llc_ul_ui(nsi, "DETACH REQ", &bss_peer[0], 0x1002, + local_tlli, &rai_bss, cell_id, + GPRS_SAPI_GMM, 6, + dtap_detach_req, sizeof(dtap_detach_req)); - send_ns_unitdata(nsi, "DETACH ACC", &sgsn_peer, 0x1002, - bssgp_detach_acc, sizeof(bssgp_detach_acc)); + send_llc_dl_ui(nsi, "DETACH ACC", &sgsn_peer, 0x1002, + local_tlli, 1, imsi, sizeof(imsi), + GPRS_SAPI_GMM, 5, + dtap_detach_acc, sizeof(dtap_detach_acc)); dump_peers(stdout, 0, 0, &gbcfg); printf("--- RA update ---\n\n"); - send_ns_unitdata(nsi, "RA UPD REQ", &bss_peer[0], 0x1002, - bssgp_ra_upd_req, sizeof(bssgp_ra_upd_req)); + send_llc_ul_ui(nsi, "RA UPD REQ", &bss_peer[0], 0x1002, + foreign_tlli, &rai_bss, 0x7080, + GPRS_SAPI_GMM, 5, + dtap_ra_upd_req, sizeof(dtap_ra_upd_req)); - send_ns_unitdata(nsi, "RA UPD ACC", &sgsn_peer, 0x1002, - bssgp_ra_upd_acc, sizeof(bssgp_ra_upd_acc)); + send_llc_dl_ui(nsi, "RA UPD ACC", &sgsn_peer, 0x1002, + foreign_tlli, 1, imsi, sizeof(imsi), + GPRS_SAPI_GMM, 6, + dtap_ra_upd_acc, sizeof(dtap_ra_upd_acc)); /* Remove APN */ - send_ns_unitdata(nsi, "ACT PDP CTX REQ (REMOVE APN)", - &bss_peer[0], 0x1002, - bssgp_act_pdp_ctx_req, sizeof(bssgp_act_pdp_ctx_req)); + send_llc_ul_ui(nsi, "ACT PDP CTX REQ (REMOVE APN)", &bss_peer[0], 0x1002, + local_tlli, &rai_bss, cell_id, + GPRS_SAPI_GMM, 3, + dtap_act_pdp_ctx_req, sizeof(dtap_act_pdp_ctx_req)); dump_peers(stdout, 0, 0, &gbcfg); /* Detach (power off -> no Detach Accept) */ - send_ns_unitdata(nsi, "DETACH REQ (PWR OFF)", &bss_peer[0], 0x1002, - bssgp_detach_po_req, sizeof(bssgp_detach_po_req)); + send_llc_ul_ui(nsi, "DETACH REQ (PWR OFF)", &bss_peer[0], 0x1002, + local_tlli, &rai_bss, cell_id, + GPRS_SAPI_GMM, 6, + dtap_detach_po_req, sizeof(dtap_detach_po_req)); dump_global(stdout, 0); dump_peers(stdout, 0, 0, &gbcfg); @@ -1130,8 +1277,10 @@ static void test_gbproxy_ra_patching() printf("--- Bad cases ---\n\n"); printf("TLLI is already detached, shouldn't patch\n"); - send_ns_unitdata(nsi, "ACT PDP CTX REQ", &bss_peer[0], 0x1002, - bssgp_act_pdp_ctx_req, sizeof(bssgp_act_pdp_ctx_req)); + send_llc_ul_ui(nsi, "ACT PDP CTX REQ", &bss_peer[0], 0x1002, + local_tlli, &rai_bss, cell_id, + GPRS_SAPI_GMM, 3, + dtap_act_pdp_ctx_req, sizeof(dtap_act_pdp_ctx_req)); printf("Invalid RAI, shouldn't patch\n"); send_bssgp_suspend_ack(nsi, &sgsn_peer, &rai_unknown); -- cgit v1.2.3 From 9057bc3c727e97cd7ff2534bffbd9ba4dcd8d4ea Mon Sep 17 00:00:00 2001 From: Jacob Erlbeck Date: Tue, 12 Aug 2014 16:30:30 +0200 Subject: gbproxy: Track SGSN and BSS TLLI/PTMSI separately This patch separates BSS side from SGSN side TLLI/PTMSI tracking. When TLLI/PTMSI patching is not enabled, the corresponding states shall be identical. The TLLI/PTMSI state has been moved into the struct gbproxy_tlli_state and is used twice in gbproxy_tlli_info. Since the state handling for uplink and downlink messages is diverging, gbprox_update_state() is replaced by two functions gbprox_update_state_dl/gbprox_update_state_ul and gbprox_process_bssgp_message() is replaced by gbprox_process_bssgp_dl/gbprox_process_bssgp_ul. Sponsored-by: On-Waves ehf --- openbsc/include/openbsc/gb_proxy.h | 21 ++- openbsc/src/gprs/gb_proxy.c | 296 +++++++++++++++++++++++++++------- openbsc/src/gprs/gb_proxy_vty.c | 7 +- openbsc/tests/gbproxy/gbproxy_test.c | 96 +++++++---- openbsc/tests/gbproxy/gbproxy_test.ok | 6 +- 5 files changed, 327 insertions(+), 99 deletions(-) diff --git a/openbsc/include/openbsc/gb_proxy.h b/openbsc/include/openbsc/gb_proxy.h index adc955c8a..468228043 100644 --- a/openbsc/include/openbsc/gb_proxy.h +++ b/openbsc/include/openbsc/gb_proxy.h @@ -44,6 +44,7 @@ struct gbproxy_config { enum gbproxy_patch_mode patch_mode; int tlli_max_age; int tlli_max_len; + int patch_ptmsi; /* IMSI checking/matching */ int check_imsi; @@ -81,17 +82,26 @@ struct gbproxy_peer { struct gbproxy_patch_state patch_state; }; +struct gbproxy_tlli_state { + uint32_t current; + uint32_t assigned; + int bss_validated; + int net_validated; + + uint32_t ptmsi; +}; + struct gbproxy_tlli_info { struct llist_head list; - uint32_t tlli; - uint32_t assigned_tlli; - int bss_validated; - int net_validated; + struct gbproxy_tlli_state tlli; + struct gbproxy_tlli_state sgsn_tlli; + time_t timestamp; uint8_t *mi_data; size_t mi_data_len; + int enable_patching; }; @@ -132,6 +142,9 @@ struct gbproxy_tlli_info *gbprox_find_tlli(struct gbproxy_peer *peer, struct gbproxy_tlli_info *gbprox_find_tlli_by_mi(struct gbproxy_peer *peer, const uint8_t *mi_data, size_t mi_data_len); +struct gbproxy_tlli_info *gbprox_find_tlli_by_sgsn_tlli( + struct gbproxy_peer *peer, + uint32_t tlli); struct gbproxy_tlli_info *gbprox_register_tlli( struct gbproxy_peer *peer, uint32_t tlli, const uint8_t *imsi, size_t imsi_len, time_t now); diff --git a/openbsc/src/gprs/gb_proxy.c b/openbsc/src/gprs/gb_proxy.c index 26f4c1755..0c898cc9d 100644 --- a/openbsc/src/gprs/gb_proxy.c +++ b/openbsc/src/gprs/gb_proxy.c @@ -427,7 +427,23 @@ struct gbproxy_tlli_info *gbprox_find_tlli(struct gbproxy_peer *peer, struct gbproxy_patch_state *state = &peer->patch_state; llist_for_each_entry(tlli_info, &state->enabled_tllis, list) - if (tlli_info->tlli == tlli || tlli_info->assigned_tlli == tlli) + if (tlli_info->tlli.current == tlli || + tlli_info->tlli.assigned == tlli) + return tlli_info; + + return NULL; +} + +struct gbproxy_tlli_info *gbprox_find_tlli_by_sgsn_tlli( + struct gbproxy_peer *peer, + uint32_t tlli) +{ + struct gbproxy_tlli_info *tlli_info; + struct gbproxy_patch_state *state = &peer->patch_state; + + llist_for_each_entry(tlli_info, &state->enabled_tllis, list) + if (tlli_info->sgsn_tlli.current == tlli || + tlli_info->sgsn_tlli.assigned == tlli) return tlli_info; return NULL; @@ -583,7 +599,7 @@ int gbprox_remove_stale_tllis(struct gbproxy_peer *peer, time_t now) LOGP(DGPRS, LOGL_INFO, "Removing TLLI %08x from list " "(stale, length %d, max_len exceeded)\n", - tlli_info->tlli, state->enabled_tllis_count); + tlli_info->tlli.current, state->enabled_tllis_count); gbprox_delete_tlli(peer, tlli_info); deleted_count += 1; @@ -605,7 +621,7 @@ int gbprox_remove_stale_tllis(struct gbproxy_peer *peer, time_t now) LOGP(DGPRS, LOGL_INFO, "Removing TLLI %08x from list " "(stale, age %d, max_age exceeded)\n", - tlli_info->tlli, (int)age); + tlli_info->tlli.current, (int)age); gbprox_delete_tlli(peer, tlli_info); deleted_count += 1; @@ -622,8 +638,9 @@ static struct gbproxy_tlli_info *gbprox_get_detached_tlli_info( struct gbproxy_patch_state *state = &peer->patch_state; if (!tlli_info) { + /* move this into an tlli_alloc function */ tlli_info = talloc_zero(peer, struct gbproxy_tlli_info); - tlli_info->tlli = tlli; + tlli_info->tlli.current = tlli; } else { llist_del(&tlli_info->list); OSMO_ASSERT(state->enabled_tllis_count > 0); @@ -649,57 +666,58 @@ static void gbprox_update_tlli_info(struct gbproxy_tlli_info *tlli_info, memcpy(tlli_info->mi_data, imsi, imsi_len); } -void gbprox_reassign_tlli(struct gbproxy_tlli_info *tlli_info, +void gbprox_reassign_tlli(struct gbproxy_tlli_state *tlli_state, struct gbproxy_peer *peer, uint32_t new_tlli) { - if (new_tlli == tlli_info->tlli) + if (new_tlli == tlli_state->current) return; LOGP(DGPRS, LOGL_INFO, "The TLLI has been reassigned from %08x to %08x\n", - tlli_info->tlli, new_tlli); + tlli_state->current, new_tlli); /* Remember assigned TLLI */ - tlli_info->assigned_tlli = new_tlli; - tlli_info->bss_validated = 0; - tlli_info->net_validated = 0; + tlli_state->assigned = new_tlli; + tlli_state->bss_validated = 0; + tlli_state->net_validated = 0; } -static void gbprox_validate_tlli(struct gbproxy_tlli_info *tlli_info, +static void gbprox_validate_tlli(struct gbproxy_tlli_state *tlli_state, uint32_t tlli, int to_bss) { LOGP(DGPRS, LOGL_DEBUG, - "%s({tlli = %08x, assigned_tlli = %08x, net_vld = %d, bss_vld = %d}, %08x)\n", - __func__, tlli_info->tlli, tlli_info->assigned_tlli, - tlli_info->net_validated, tlli_info->bss_validated, tlli); + "%s({current = %08x, assigned = %08x, net_vld = %d, bss_vld = %d}, %08x)\n", + __func__, tlli_state->current, tlli_state->assigned, + tlli_state->net_validated, tlli_state->bss_validated, tlli); - if (!tlli_info->assigned_tlli || tlli_info->assigned_tlli != tlli) + if (!tlli_state->assigned || tlli_state->assigned != tlli) return; + /* TODO: Is this ok? Check spec */ if (gprs_tlli_type(tlli) != TLLI_LOCAL) return; /* See GSM 04.08, 4.7.1.5 */ if (to_bss) - tlli_info->net_validated = 1; + tlli_state->net_validated = 1; else - tlli_info->bss_validated = 1; + tlli_state->bss_validated = 1; - if (!tlli_info->bss_validated || !tlli_info->net_validated) + if (!tlli_state->bss_validated || !tlli_state->net_validated) return; LOGP(DGPRS, LOGL_INFO, "The TLLI %08x has been validated (was %08x)\n", - tlli_info->assigned_tlli, tlli_info->tlli); + tlli_state->assigned, tlli_state->current); - tlli_info->tlli = tlli; - tlli_info->assigned_tlli = 0; + tlli_state->current = tlli; + tlli_state->assigned = 0; } void gbprox_touch_tlli(struct gbproxy_peer *peer, struct gbproxy_tlli_info *tlli_info, time_t now) { - gbprox_get_detached_tlli_info(peer, tlli_info, tlli_info->tlli); + gbprox_get_detached_tlli_info(peer, tlli_info, 0); gbprox_attach_tlli_info(peer, now, tlli_info); } @@ -727,8 +745,8 @@ struct gbproxy_tlli_info *gbprox_register_tlli( /* TLLI has changed somehow, adjust it */ LOGP(DGPRS, LOGL_INFO, "The TLLI has changed from %08x to %08x\n", - tlli_info->tlli, tlli); - tlli_info->tlli = tlli; + tlli_info->tlli.current, tlli); + tlli_info->tlli.current = tlli; } } @@ -1313,6 +1331,9 @@ static int gbprox_patch_llc(struct msgb *msg, uint8_t *llc, size_t llc_len, return have_patched; if (parse_ctx->raid_enc) { + /* TODO: BSS->SGSN: Only patch if matches original BSSGP, + * don't update internal mapping, patch to invalid if P-TMSI + * unknown. */ gbprox_patch_raid(parse_ctx->raid_enc, peer, parse_ctx->to_bss, parse_ctx->llc_msg_name); have_patched = 1; @@ -1406,15 +1427,25 @@ static void gbprox_log_parse_context(struct gbproxy_parse_context *parse_ctx, LOGP(DGPRS, LOGL_DEBUG, "\n"); } -static struct gbproxy_tlli_info *gbprox_update_state( - struct gbproxy_peer *peer, time_t now, +static uint32_t gbprox_make_bss_ptmsi(struct gbproxy_peer *peer, + uint32_t sgsn_ptmsi) +{ + return sgsn_ptmsi; +} + +static uint32_t gbprox_make_sgsn_tlli(struct gbproxy_peer *peer, + uint32_t bss_tlli) +{ + return bss_tlli; +} + +static struct gbproxy_tlli_info *gbprox_update_state_ul( + struct gbproxy_peer *peer, + time_t now, struct gbproxy_parse_context *parse_ctx) { struct gbproxy_tlli_info *tlli_info = NULL; - if (!peer->cfg->check_imsi) - return NULL; - if (parse_ctx->tlli_enc) tlli_info = gbprox_find_tlli(peer, parse_ctx->tlli); @@ -1424,6 +1455,69 @@ static struct gbproxy_tlli_info *gbprox_update_state( rate_ctr_inc(&peer->ctrg->ctr[GBPROX_PEER_CTR_ATTACH_REQS]); break; + default: + break; + } + } + + gbprox_log_parse_context(parse_ctx, "BSSGP"); + + if (parse_ctx->tlli_enc && parse_ctx->llc) { + uint32_t sgsn_tlli; + if (!tlli_info) { + tlli_info = + gbprox_register_tlli(peer, parse_ctx->tlli, + parse_ctx->imsi, + parse_ctx->imsi_len, now); + /* Setup TLLIs */ + sgsn_tlli = gbprox_make_sgsn_tlli(peer, parse_ctx->tlli); + tlli_info->sgsn_tlli.current = sgsn_tlli; + } else { + sgsn_tlli = tlli_info->sgsn_tlli.assigned; + if (!sgsn_tlli) + sgsn_tlli = tlli_info->sgsn_tlli.current; + if (!sgsn_tlli) { + sgsn_tlli = gbprox_make_sgsn_tlli(peer, + parse_ctx->tlli); + } + + gbprox_validate_tlli(&tlli_info->tlli, + parse_ctx->tlli, 0); + gbprox_validate_tlli(&tlli_info->sgsn_tlli, + sgsn_tlli, 0); + gbprox_touch_tlli(peer, tlli_info, now); + } + } else if (tlli_info) { + gbprox_touch_tlli(peer, tlli_info, now); + } + + if (parse_ctx->imsi && tlli_info && tlli_info->mi_data_len == 0) { + int enable_patching; + gbprox_update_tlli_info(tlli_info, + parse_ctx->imsi, parse_ctx->imsi_len); + + /* Check, whether the IMSI matches */ + enable_patching = gbprox_check_imsi(peer, parse_ctx->imsi, + parse_ctx->imsi_len); + if (enable_patching >= 0) + tlli_info->enable_patching = enable_patching; + } + + return tlli_info; +} + +static struct gbproxy_tlli_info *gbprox_update_state_dl( + struct gbproxy_peer *peer, + time_t now, + struct gbproxy_parse_context *parse_ctx) +{ + struct gbproxy_tlli_info *tlli_info = NULL; + + if (parse_ctx->tlli_enc) + tlli_info = gbprox_find_tlli_by_sgsn_tlli(peer, parse_ctx->tlli); + + if (parse_ctx->g48_hdr) { + switch (parse_ctx->g48_hdr->msg_type) { case GSM48_MT_GMM_ATTACH_REJ: rate_ctr_inc(&peer->ctrg->ctr[GBPROX_PEER_CTR_ATTACH_REJS]); break; @@ -1435,43 +1529,69 @@ static struct gbproxy_tlli_info *gbprox_update_state( gbprox_log_parse_context(parse_ctx, "BSSGP"); - if (parse_ctx->tlli_enc && parse_ctx->new_ptmsi_enc && - parse_ctx->to_bss) { + if (parse_ctx->tlli_enc && parse_ctx->new_ptmsi_enc) { /* A new PTMSI has been signaled in the message, * register new TLLI */ - uint32_t new_ptmsi; - uint32_t new_tlli; + uint32_t new_sgsn_ptmsi; + uint32_t new_sgsn_tlli; + uint32_t new_bss_ptmsi; + uint32_t new_bss_tlli = 0; if (!parse_mi_tmsi(parse_ctx->new_ptmsi_enc, GSM48_TMSI_LEN, - &new_ptmsi)) { + &new_sgsn_ptmsi)) { LOGP(DGPRS, LOGL_ERROR, "Failed to parse new TLLI/PTMSI (current is %08x)\n", parse_ctx->tlli); return tlli_info; } - new_tlli = gprs_tmsi2tlli(new_ptmsi, TLLI_LOCAL); + new_sgsn_tlli = gprs_tmsi2tlli(new_sgsn_ptmsi, TLLI_LOCAL); + new_bss_ptmsi = gbprox_make_bss_ptmsi(peer, new_sgsn_ptmsi); + if (new_bss_ptmsi != GSM_RESERVED_TMSI) + new_bss_tlli = gprs_tmsi2tlli(new_bss_ptmsi, TLLI_LOCAL); LOGP(DGPRS, LOGL_INFO, - "Got new TLLI/PTMSI %08x/%08x (current is %08x)\n", - new_tlli, new_ptmsi, parse_ctx->tlli); + "Got new TLLI(PTMSI) %08x(%08x) from SGSN, using %08x(%08x)\n", + new_sgsn_tlli, new_sgsn_ptmsi, new_bss_tlli, new_bss_ptmsi); if (tlli_info) { - gbprox_reassign_tlli(tlli_info, peer, new_tlli); + gbprox_reassign_tlli(&tlli_info->sgsn_tlli, + peer, new_sgsn_tlli); + gbprox_reassign_tlli(&tlli_info->tlli, + peer, new_bss_tlli); gbprox_touch_tlli(peer, tlli_info, now); } else { tlli_info = - gbprox_register_tlli(peer, new_tlli, + gbprox_register_tlli(peer, new_bss_tlli, parse_ctx->imsi, parse_ctx->imsi_len, now); + /* Setup TLLIs */ + tlli_info->sgsn_tlli.current = new_sgsn_tlli; } - } else if (parse_ctx->tlli_enc && parse_ctx->llc) { - if (!tlli_info) { - tlli_info = - gbprox_register_tlli(peer, parse_ctx->tlli, - parse_ctx->imsi, - parse_ctx->imsi_len, now); - } else { - gbprox_validate_tlli(tlli_info, parse_ctx->tlli, - parse_ctx->to_bss); - gbprox_touch_tlli(peer, tlli_info, now); + /* Setup PTMSIs */ + tlli_info->sgsn_tlli.ptmsi = new_sgsn_ptmsi; + tlli_info->tlli.ptmsi = new_bss_ptmsi; + } else if (parse_ctx->tlli_enc && parse_ctx->llc && !tlli_info) { + /* Unknown SGSN TLLI */ + tlli_info = + gbprox_register_tlli(peer, parse_ctx->tlli, + parse_ctx->imsi, + parse_ctx->imsi_len, now); + + /* Setup TLLIs */ + tlli_info->sgsn_tlli.current = tlli_info->tlli.current; + if (peer->cfg->patch_ptmsi) { + /* TODO: We don't know the local TLLI here, perhaps add + * a workaround that derives a PTMSI from the SGSN TLLI + * and use that to get the missing values. This may + * only happen when the gbproxy has been restarted or a + * tlli_info has been discarded due to age or queue + * length. + */ + tlli_info->tlli.current = 0; } + } else if (parse_ctx->tlli_enc && parse_ctx->llc && tlli_info) { + gbprox_validate_tlli(&tlli_info->sgsn_tlli, parse_ctx->tlli, 1); + if (!peer->cfg->patch_ptmsi) + gbprox_validate_tlli(&tlli_info->tlli, + parse_ctx->tlli, 1); + gbprox_touch_tlli(peer, tlli_info, now); } else if (tlli_info) { gbprox_touch_tlli(peer, tlli_info, now); } @@ -1662,22 +1782,23 @@ patch_error: "Failed to patch BSSGP message as requested: %s.\n", err_info); } -/* patch BSSGP message to use core_mcc/mnc on the SGSN side */ -static void gbprox_process_bssgp_message(struct gbproxy_config *cfg, - struct msgb *msg, - struct gbproxy_peer *peer, int to_bss) +/* patch BSSGP message */ +static void gbprox_process_bssgp_ul(struct gbproxy_config *cfg, + struct msgb *msg, + struct gbproxy_peer *peer) { struct gbproxy_parse_context parse_ctx = {0}; int rc; int len_change = 0; time_t now; - struct gbproxy_tlli_info *tlli_info; + struct gbproxy_tlli_info *tlli_info = NULL; if (!cfg->core_mcc && !cfg->core_mnc && !cfg->core_apn) return; - parse_ctx.to_bss = to_bss; + parse_ctx.to_bss = 0; + /* Parse BSSGP/LLC */ rc = gbprox_parse_bssgp(msgb_bssgph(msg), msgb_bssgp_len(msg), &parse_ctx); @@ -1689,10 +1810,11 @@ static void gbprox_process_bssgp_message(struct gbproxy_config *cfg, } } + /* Get peer */ if (!peer && msgb_bvci(msg) >= 2) peer = peer_by_bvci(cfg, msgb_bvci(msg)); - if (!peer && !to_bss) + if (!peer) peer = gbprox_peer_by_nsei(cfg, msgb_nsei(msg)); if (!peer) @@ -1700,9 +1822,61 @@ static void gbprox_process_bssgp_message(struct gbproxy_config *cfg, if (!peer) { LOGP(DLLC, LOGL_INFO, - "NSEI=%d(%s) patching: didn't find peer for message, " + "NSEI=%d(BSS) patching: didn't find peer for message, " + "PDU %d\n", + msgb_nsei(msg), parse_ctx.pdu_type); + /* Increment counter */ + rate_ctr_inc(&cfg->ctrg->ctr[GBPROX_GLOB_CTR_PATCH_PEER_ERR]); + return; + } + + now = time(NULL); + + tlli_info = gbprox_update_state_ul(peer, now, &parse_ctx); + + gbprox_patch_bssgp(msg, msgb_bssgph(msg), msgb_bssgp_len(msg), + peer, tlli_info, &len_change, &parse_ctx); + + gbprox_update_state_after(peer, tlli_info, now, &parse_ctx); + + return; +} + +/* patch BSSGP message to use core_mcc/mnc on the SGSN side */ +static void gbprox_process_bssgp_dl(struct gbproxy_config *cfg, + struct msgb *msg, + struct gbproxy_peer *peer) +{ + struct gbproxy_parse_context parse_ctx = {0}; + int rc; + int len_change = 0; + time_t now; + struct gbproxy_tlli_info *tlli_info = NULL; + + parse_ctx.to_bss = 1; + + rc = gbprox_parse_bssgp(msgb_bssgph(msg), msgb_bssgp_len(msg), + &parse_ctx); + + if (!rc) { + if (!parse_ctx.need_decryption) { + LOGP(DGPRS, LOGL_ERROR, + "Failed to parse BSSGP/GMM message\n"); + return; + } + } + + if (!peer && msgb_bvci(msg) >= 2) + peer = peer_by_bvci(cfg, msgb_bvci(msg)); + + if (!peer) + peer = peer_by_bssgp_tlv(cfg, &parse_ctx.bssgp_tp); + + if (!peer) { + LOGP(DLLC, LOGL_INFO, + "NSEI=%d(SGSN) patching: didn't find peer for message, " "PDU %d\n", - msgb_nsei(msg), to_bss ? "SGSN" : "BSS", parse_ctx.pdu_type); + msgb_nsei(msg), parse_ctx.pdu_type); /* Increment counter */ rate_ctr_inc(&cfg->ctrg->ctr[GBPROX_GLOB_CTR_PATCH_PEER_ERR]); return; @@ -1710,7 +1884,7 @@ static void gbprox_process_bssgp_message(struct gbproxy_config *cfg, now = time(NULL); - tlli_info = gbprox_update_state(peer, now, &parse_ctx); + tlli_info = gbprox_update_state_dl(peer, now, &parse_ctx); gbprox_patch_bssgp(msg, msgb_bssgph(msg), msgb_bssgp_len(msg), peer, tlli_info, &len_change, &parse_ctx); @@ -1729,7 +1903,7 @@ static int gbprox_relay2sgsn(struct gbproxy_config *cfg, struct msgb *old_msg, struct msgb *msg = gprs_msgb_copy(old_msg, "msgb_relay2sgsn"); int rc; - gbprox_process_bssgp_message(cfg, msg, peer, 0); + gbprox_process_bssgp_ul(cfg, msg, peer); DEBUGP(DGPRS, "NSEI=%u proxying BTS->SGSN (NS_BVCI=%u, NSEI=%u)\n", msgb_nsei(msg), ns_bvci, cfg->nsip_sgsn_nsei); @@ -2147,7 +2321,7 @@ int gbprox_rcvmsg(struct gbproxy_config *cfg, struct msgb *msg, uint16_t nsei, int remote_end_is_sgsn = nsei == cfg->nsip_sgsn_nsei; if (remote_end_is_sgsn) - gbprox_process_bssgp_message(cfg, msg, NULL, 1); + gbprox_process_bssgp_dl(cfg, msg, NULL); /* Only BVCI=0 messages need special treatment */ if (ns_bvci == 0 || ns_bvci == 1) { diff --git a/openbsc/src/gprs/gb_proxy_vty.c b/openbsc/src/gprs/gb_proxy_vty.c index 9574a451f..d1b912fcd 100644 --- a/openbsc/src/gprs/gb_proxy_vty.c +++ b/openbsc/src/gprs/gb_proxy_vty.c @@ -377,7 +377,7 @@ DEFUN(show_gbproxy_tllis, show_gbproxy_tllis_cmd, "show gbproxy tllis", snprintf(mi_buf, sizeof(mi_buf), "(none)"); } vty_out(vty, " TLLI %08x, IMSI %s, AGE %d%s", - tlli_info->tlli, mi_buf, (int)age, + tlli_info->tlli.current, mi_buf, (int)age, VTY_NEWLINE); } } @@ -532,7 +532,7 @@ DEFUN(delete_gb_tlli, delete_gb_tlli_cmd, } llist_for_each_entry_safe(tlli_info, nxt, &state->enabled_tllis, list) { - if (match == MATCH_TLLI && tlli_info->tlli != tlli) + if (match == MATCH_TLLI && tlli_info->tlli.current != tlli) continue; if (match == MATCH_IMSI) { @@ -544,7 +544,8 @@ DEFUN(delete_gb_tlli, delete_gb_tlli_cmd, if (strcmp(mi_buf, imsi) != 0) continue; } - vty_out(vty, "Deleting TLLI %08x%s", tlli_info->tlli, VTY_NEWLINE); + vty_out(vty, "Deleting TLLI %08x%s", tlli_info->tlli.current, + VTY_NEWLINE); gbprox_delete_tlli(peer, tlli_info); found += 1; } diff --git a/openbsc/tests/gbproxy/gbproxy_test.c b/openbsc/tests/gbproxy/gbproxy_test.c index ed30af8de..2a521eeec 100644 --- a/openbsc/tests/gbproxy/gbproxy_test.c +++ b/openbsc/tests/gbproxy/gbproxy_test.c @@ -127,9 +127,16 @@ static int dump_peers(FILE *stream, int indent, time_t now, snprintf(mi_buf, sizeof(mi_buf), "(none)"); } fprintf(stream, "%*s TLLI %08x", - indent, "", tlli_info->tlli); - if (tlli_info->assigned_tlli) - fprintf(stream, "/%08x", tlli_info->assigned_tlli); + indent, "", tlli_info->tlli.current); + if (tlli_info->tlli.assigned) + fprintf(stream, "/%08x", tlli_info->tlli.assigned); + if (tlli_info->sgsn_tlli.current) { + fprintf(stream, " -> %08x", + tlli_info->sgsn_tlli.current); + if (tlli_info->sgsn_tlli.assigned) + fprintf(stream, "/%08x", + tlli_info->sgsn_tlli.assigned); + } rc = fprintf(stream, ", IMSI %s, AGE %d\n", mi_buf, (int)age); if (rc < 0) @@ -1115,6 +1122,7 @@ static void test_gbproxy_ra_patching() gbcfg.core_mnc = 456; gbcfg.core_apn = talloc_zero_size(NULL, 100); gbcfg.core_apn_size = gprs_str_to_apn(gbcfg.core_apn, 100, "foo.bar"); + gbcfg.patch_ptmsi = 0; configure_sgsn_peer(&sgsn_peer); configure_bss_peers(bss_peer, ARRAY_SIZE(bss_peer)); @@ -1173,24 +1181,32 @@ static void test_gbproxy_ra_patching() GPRS_SAPI_GMM, 1, dtap_attach_acc, sizeof(dtap_attach_acc)); - tlli_info = gbprox_find_tlli(peer, local_tlli); + tlli_info = gbprox_find_tlli_by_sgsn_tlli(peer, local_tlli); OSMO_ASSERT(tlli_info); - OSMO_ASSERT(tlli_info->assigned_tlli == local_tlli); - OSMO_ASSERT(tlli_info->tlli != local_tlli); - OSMO_ASSERT(!tlli_info->bss_validated); - OSMO_ASSERT(!tlli_info->net_validated); + OSMO_ASSERT(tlli_info->tlli.assigned == local_tlli); + OSMO_ASSERT(tlli_info->tlli.current != local_tlli); + OSMO_ASSERT(!tlli_info->tlli.bss_validated); + OSMO_ASSERT(!tlli_info->tlli.net_validated); + OSMO_ASSERT(tlli_info->sgsn_tlli.assigned == local_tlli); + OSMO_ASSERT(tlli_info->sgsn_tlli.current != local_tlli); + OSMO_ASSERT(!tlli_info->sgsn_tlli.bss_validated); + OSMO_ASSERT(!tlli_info->sgsn_tlli.net_validated); send_llc_ul_ui(nsi, "ATTACH COMPLETE", &bss_peer[0], 0x1002, local_tlli, &rai_bss, cell_id, GPRS_SAPI_GMM, 4, dtap_attach_complete, sizeof(dtap_attach_complete)); - tlli_info = gbprox_find_tlli(peer, local_tlli); + tlli_info = gbprox_find_tlli_by_sgsn_tlli(peer, local_tlli); OSMO_ASSERT(tlli_info); - OSMO_ASSERT(tlli_info->assigned_tlli == local_tlli); - OSMO_ASSERT(tlli_info->tlli != local_tlli); - OSMO_ASSERT(tlli_info->bss_validated); - OSMO_ASSERT(!tlli_info->net_validated); + OSMO_ASSERT(tlli_info->tlli.assigned == local_tlli); + OSMO_ASSERT(tlli_info->tlli.current != local_tlli); + OSMO_ASSERT(tlli_info->tlli.bss_validated); + OSMO_ASSERT(!tlli_info->tlli.net_validated); + OSMO_ASSERT(tlli_info->sgsn_tlli.assigned == local_tlli); + OSMO_ASSERT(tlli_info->sgsn_tlli.current != local_tlli); + OSMO_ASSERT(tlli_info->sgsn_tlli.bss_validated); + OSMO_ASSERT(!tlli_info->sgsn_tlli.net_validated); /* Replace APN (1) */ send_llc_ul_ui(nsi, "ACT PDP CTX REQ (REPLACE APN)", &bss_peer[0], 0x1002, @@ -1198,22 +1214,28 @@ static void test_gbproxy_ra_patching() GPRS_SAPI_GMM, 3, dtap_act_pdp_ctx_req, sizeof(dtap_act_pdp_ctx_req)); - tlli_info = gbprox_find_tlli(peer, local_tlli); + tlli_info = gbprox_find_tlli_by_sgsn_tlli(peer, local_tlli); OSMO_ASSERT(tlli_info); - OSMO_ASSERT(tlli_info->assigned_tlli == local_tlli); - OSMO_ASSERT(tlli_info->tlli != local_tlli); - OSMO_ASSERT(tlli_info->bss_validated); - OSMO_ASSERT(!tlli_info->net_validated); + OSMO_ASSERT(tlli_info->tlli.assigned == local_tlli); + OSMO_ASSERT(tlli_info->tlli.current != local_tlli); + OSMO_ASSERT(tlli_info->tlli.bss_validated); + OSMO_ASSERT(!tlli_info->tlli.net_validated); + OSMO_ASSERT(tlli_info->sgsn_tlli.assigned == local_tlli); + OSMO_ASSERT(tlli_info->sgsn_tlli.current != local_tlli); + OSMO_ASSERT(tlli_info->sgsn_tlli.bss_validated); + OSMO_ASSERT(!tlli_info->sgsn_tlli.net_validated); send_llc_dl_ui(nsi, "GMM INFO", &sgsn_peer, 0x1002, local_tlli, 1, imsi, sizeof(imsi), GPRS_SAPI_GMM, 2, dtap_gmm_information, sizeof(dtap_gmm_information)); - tlli_info = gbprox_find_tlli(peer, local_tlli); + tlli_info = gbprox_find_tlli_by_sgsn_tlli(peer, local_tlli); OSMO_ASSERT(tlli_info); - OSMO_ASSERT(tlli_info->assigned_tlli == 0); - OSMO_ASSERT(tlli_info->tlli == local_tlli); + OSMO_ASSERT(tlli_info->tlli.assigned == 0); + OSMO_ASSERT(tlli_info->tlli.current == local_tlli); + OSMO_ASSERT(tlli_info->sgsn_tlli.assigned == 0); + OSMO_ASSERT(tlli_info->sgsn_tlli.current == local_tlli); /* Replace APN (2) */ send_llc_ul_ui(nsi, "ACT PDP CTX REQ (REPLACE APN)", &bss_peer[0], 0x1002, @@ -1566,7 +1588,7 @@ static void test_gbproxy_tlli_expire(void) tlli_info = gbprox_register_tlli(peer, tlli1, imsi1, ARRAY_SIZE(imsi1), now); OSMO_ASSERT(tlli_info); - OSMO_ASSERT(tlli_info->tlli == tlli1); + OSMO_ASSERT(tlli_info->tlli.current == tlli1); OSMO_ASSERT(peer->patch_state.enabled_tllis_count == 1); /* replace the old entry */ @@ -1574,7 +1596,7 @@ static void test_gbproxy_tlli_expire(void) tlli_info = gbprox_register_tlli(peer, tlli2, imsi1, ARRAY_SIZE(imsi1), now); OSMO_ASSERT(tlli_info); - OSMO_ASSERT(tlli_info->tlli == tlli2); + OSMO_ASSERT(tlli_info->tlli.current == tlli2); OSMO_ASSERT(peer->patch_state.enabled_tllis_count == 1); dump_peers(stdout, 2, now, &cfg); @@ -1582,7 +1604,7 @@ static void test_gbproxy_tlli_expire(void) /* verify that 5678 has survived */ tlli_info = gbprox_find_tlli_by_mi(peer, imsi1, ARRAY_SIZE(imsi1)); OSMO_ASSERT(tlli_info); - OSMO_ASSERT(tlli_info->tlli == tlli2); + OSMO_ASSERT(tlli_info->tlli.current == tlli2); tlli_info = gbprox_find_tlli_by_mi(peer, imsi2, ARRAY_SIZE(imsi2)); OSMO_ASSERT(!tlli_info); @@ -1605,7 +1627,7 @@ static void test_gbproxy_tlli_expire(void) tlli_info = gbprox_register_tlli(peer, tlli1, imsi1, ARRAY_SIZE(imsi1), now); OSMO_ASSERT(tlli_info); - OSMO_ASSERT(tlli_info->tlli == tlli1); + OSMO_ASSERT(tlli_info->tlli.current == tlli1); OSMO_ASSERT(peer->patch_state.enabled_tllis_count == 1); /* try to replace the old entry */ @@ -1613,7 +1635,7 @@ static void test_gbproxy_tlli_expire(void) tlli_info = gbprox_register_tlli(peer, tlli1, imsi2, ARRAY_SIZE(imsi2), now); OSMO_ASSERT(tlli_info); - OSMO_ASSERT(tlli_info->tlli == tlli1); + OSMO_ASSERT(tlli_info->tlli.current == tlli1); OSMO_ASSERT(peer->patch_state.enabled_tllis_count == 1); dump_peers(stdout, 2, now, &cfg); @@ -1623,7 +1645,7 @@ static void test_gbproxy_tlli_expire(void) OSMO_ASSERT(!tlli_info); tlli_info = gbprox_find_tlli_by_mi(peer, imsi2, ARRAY_SIZE(imsi2)); OSMO_ASSERT(tlli_info); - OSMO_ASSERT(tlli_info->tlli == tlli1); + OSMO_ASSERT(tlli_info->tlli.current == tlli1); printf("\n"); @@ -1661,7 +1683,7 @@ static void test_gbproxy_tlli_expire(void) OSMO_ASSERT(!tlli_info); tlli_info = gbprox_find_tlli_by_mi(peer, imsi2, ARRAY_SIZE(imsi2)); OSMO_ASSERT(tlli_info); - OSMO_ASSERT(tlli_info->tlli == tlli2); + OSMO_ASSERT(tlli_info->tlli.current == tlli2); printf("\n"); @@ -1669,6 +1691,7 @@ static void test_gbproxy_tlli_expire(void) } { + struct gbproxy_tlli_info *tlli_info; int num_removed; printf("Test TLLI expiry, max_age == 1:\n"); @@ -1693,12 +1716,20 @@ static void test_gbproxy_tlli_expire(void) dump_peers(stdout, 2, now + 2, &cfg); + /* verify that 5678 has survived */ + tlli_info = gbprox_find_tlli_by_mi(peer, imsi1, ARRAY_SIZE(imsi1)); + OSMO_ASSERT(!tlli_info); + tlli_info = gbprox_find_tlli_by_mi(peer, imsi2, ARRAY_SIZE(imsi2)); + OSMO_ASSERT(tlli_info); + OSMO_ASSERT(tlli_info->tlli.current == tlli2); + printf("\n"); gbproxy_peer_free(peer); } { + struct gbproxy_tlli_info *tlli_info; int num_removed; printf("Test TLLI expiry, max_len == 2, max_age == 1:\n"); @@ -1731,6 +1762,15 @@ static void test_gbproxy_tlli_expire(void) dump_peers(stdout, 2, now + 2, &cfg); + /* verify that tlli3 has survived */ + tlli_info = gbprox_find_tlli_by_mi(peer, imsi1, ARRAY_SIZE(imsi1)); + OSMO_ASSERT(!tlli_info); + tlli_info = gbprox_find_tlli_by_mi(peer, imsi2, ARRAY_SIZE(imsi2)); + OSMO_ASSERT(!tlli_info); + tlli_info = gbprox_find_tlli_by_mi(peer, imsi3, ARRAY_SIZE(imsi3)); + OSMO_ASSERT(tlli_info); + OSMO_ASSERT(tlli_info->tlli.current == tlli3); + printf("\n"); gbproxy_peer_free(peer); diff --git a/openbsc/tests/gbproxy/gbproxy_test.ok b/openbsc/tests/gbproxy/gbproxy_test.ok index 74e895505..b9919060e 100644 --- a/openbsc/tests/gbproxy/gbproxy_test.ok +++ b/openbsc/tests/gbproxy/gbproxy_test.ok @@ -1745,7 +1745,7 @@ Peers: Attach Request count : 1 TLLI cache size : 1 TLLI-Cache: 1 - TLLI efe2b700, IMSI 12131415161718, AGE 0 + TLLI efe2b700 -> efe2b700, IMSI 12131415161718, AGE 0 PROCESSING DETACH REQ from 0x01020304:1111 00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 75 30 00 80 0e 00 15 01 c0 19 08 05 01 18 05 f4 ef e2 b7 00 19 03 b9 97 cb 7e e1 41 @@ -1823,7 +1823,7 @@ Peers: Attach Request count : 1 TLLI cache size : 1 TLLI-Cache: 1 - TLLI bbc54679/efe2b700, IMSI 12131415161718, AGE 0 + TLLI bbc54679/efe2b700 -> bbc54679/efe2b700, IMSI 12131415161718, AGE 0 PROCESSING DETACH REQ (PWR OFF) from 0x01020304:1111 00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 75 30 00 80 0e 00 15 01 c0 19 08 05 09 18 05 f4 ef e2 b7 00 19 03 b9 97 cb 84 0c eb @@ -1883,7 +1883,7 @@ Peers: Attach Request count : 1 TLLI cache size : 1 TLLI-Cache: 1 - TLLI efe2b700, IMSI (none), AGE 0 + TLLI efe2b700 -> efe2b700, IMSI (none), AGE 0 Test TLLI info expiry Test TLLI replacement: -- cgit v1.2.3 From 0d4236be54981cf4c7b39f5c6f6ed80b5f8fefe5 Mon Sep 17 00:00:00 2001 From: Jacob Erlbeck Date: Mon, 18 Aug 2014 14:54:37 +0200 Subject: gbproxy: Add 'patch-ptmsi' command to enable TLLI/P-TMSI patching This VTY command add the following commands to the gbproxy node: - patch-ptmsi: Enables P-TMSI/TLLI patching - no patch-ptmsi: Disables P-TMSI/TLLI patching Note that using these commands interactively can load to undefined behavior of existing LLC connections. Sponsored-by: On-Waves ehf --- openbsc/src/gprs/gb_proxy_vty.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/openbsc/src/gprs/gb_proxy_vty.c b/openbsc/src/gprs/gb_proxy_vty.c index d1b912fcd..a85f43969 100644 --- a/openbsc/src/gprs/gb_proxy_vty.c +++ b/openbsc/src/gprs/gb_proxy_vty.c @@ -104,6 +104,11 @@ static int config_write_gbproxy(struct vty *vty) else vty_out(vty, "%s", VTY_NEWLINE); } + + if (g_cfg->patch_ptmsi > 0) + vty_out(vty, " patch-ptmsi%s", + VTY_NEWLINE); + if (g_cfg->tlli_max_age > 0) vty_out(vty, " tlli-list max-age %d%s", g_cfg->tlli_max_age, VTY_NEWLINE); @@ -268,6 +273,28 @@ DEFUN(cfg_gbproxy_no_core_apn, return set_core_apn(vty, NULL, NULL); } +#define GBPROXY_PATCH_PTMSI_STR "Patch P-TMSI/TLLI\n" + +DEFUN(cfg_gbproxy_patch_ptmsi, + cfg_gbproxy_patch_ptmsi_cmd, + "patch-ptmsi", + GBPROXY_PATCH_PTMSI_STR) +{ + g_cfg->patch_ptmsi = 1; + + return CMD_SUCCESS; +} + +DEFUN(cfg_gbproxy_no_patch_ptmsi, + cfg_gbproxy_no_patch_ptmsi_cmd, + "no patch-ptmsi", + NO_STR GBPROXY_PATCH_PTMSI_STR) +{ + g_cfg->patch_ptmsi = 0; + + return CMD_SUCCESS; +} + #define GBPROXY_TLLI_LIST_STR "Set TLLI list parameters\n" #define GBPROXY_MAX_AGE_STR "Limit maximum age\n" @@ -575,11 +602,13 @@ int gbproxy_vty_init(void) install_element(GBPROXY_NODE, &cfg_gbproxy_core_mnc_cmd); install_element(GBPROXY_NODE, &cfg_gbproxy_core_apn_cmd); install_element(GBPROXY_NODE, &cfg_gbproxy_core_apn_match_cmd); + install_element(GBPROXY_NODE, &cfg_gbproxy_patch_ptmsi_cmd); install_element(GBPROXY_NODE, &cfg_gbproxy_tlli_list_max_age_cmd); install_element(GBPROXY_NODE, &cfg_gbproxy_tlli_list_max_len_cmd); install_element(GBPROXY_NODE, &cfg_gbproxy_no_core_mcc_cmd); install_element(GBPROXY_NODE, &cfg_gbproxy_no_core_mnc_cmd); install_element(GBPROXY_NODE, &cfg_gbproxy_no_core_apn_cmd); + install_element(GBPROXY_NODE, &cfg_gbproxy_no_patch_ptmsi_cmd); install_element(GBPROXY_NODE, &cfg_gbproxy_tlli_list_no_max_age_cmd); install_element(GBPROXY_NODE, &cfg_gbproxy_tlli_list_no_max_len_cmd); install_element(GBPROXY_NODE, &cfg_gbproxy_patch_mode_cmd); -- cgit v1.2.3 From 311592fc399505dec9188fedf82bb52797701b33 Mon Sep 17 00:00:00 2001 From: Jacob Erlbeck Date: Mon, 18 Aug 2014 15:02:17 +0200 Subject: gbproxy: Refactor gbprox_get_detached_tlli_info This patch splits the functionality of gbprox_get_detached_tlli_info into 2 new functions: - gbprox_tlli_info_alloc to allocate an intialized and detached tlli_info - gbprox_detach_tlli_info to detach an already attached tlli_info Sponsored-by: On-Waves ehf --- openbsc/src/gprs/gb_proxy.c | 46 ++++++++++++++++++++++++++------------------- 1 file changed, 27 insertions(+), 19 deletions(-) diff --git a/openbsc/src/gprs/gb_proxy.c b/openbsc/src/gprs/gb_proxy.c index 0c898cc9d..0d738aa38 100644 --- a/openbsc/src/gprs/gb_proxy.c +++ b/openbsc/src/gprs/gb_proxy.c @@ -630,27 +630,30 @@ int gbprox_remove_stale_tllis(struct gbproxy_peer *peer, time_t now) return deleted_count; } -static struct gbproxy_tlli_info *gbprox_get_detached_tlli_info( +static struct gbproxy_tlli_info *gbprox_tlli_info_alloc( + struct gbproxy_peer *peer) +{ + struct gbproxy_tlli_info *tlli_info; + + tlli_info = talloc_zero(peer, struct gbproxy_tlli_info); + tlli_info->tlli.ptmsi = GSM_RESERVED_TMSI; + tlli_info->sgsn_tlli.ptmsi = GSM_RESERVED_TMSI; + + return tlli_info; +} + +static void gbprox_detach_tlli_info( struct gbproxy_peer *peer, - struct gbproxy_tlli_info *tlli_info, - uint32_t tlli) + struct gbproxy_tlli_info *tlli_info) { struct gbproxy_patch_state *state = &peer->patch_state; - if (!tlli_info) { - /* move this into an tlli_alloc function */ - tlli_info = talloc_zero(peer, struct gbproxy_tlli_info); - tlli_info->tlli.current = tlli; - } else { - llist_del(&tlli_info->list); - OSMO_ASSERT(state->enabled_tllis_count > 0); - state->enabled_tllis_count -= 1; - - peer->ctrg->ctr[GBPROX_PEER_CTR_TLLI_CACHE_SIZE].current = - state->enabled_tllis_count; - } + llist_del(&tlli_info->list); + OSMO_ASSERT(state->enabled_tllis_count > 0); + state->enabled_tllis_count -= 1; - return tlli_info; + peer->ctrg->ctr[GBPROX_PEER_CTR_TLLI_CACHE_SIZE].current = + state->enabled_tllis_count; } static void gbprox_update_tlli_info(struct gbproxy_tlli_info *tlli_info, @@ -717,7 +720,7 @@ static void gbprox_validate_tlli(struct gbproxy_tlli_state *tlli_state, void gbprox_touch_tlli(struct gbproxy_peer *peer, struct gbproxy_tlli_info *tlli_info, time_t now) { - gbprox_get_detached_tlli_info(peer, tlli_info, 0); + gbprox_detach_tlli_info(peer, tlli_info); gbprox_attach_tlli_info(peer, now, tlli_info); } @@ -750,9 +753,14 @@ struct gbproxy_tlli_info *gbprox_register_tlli( } } - tlli_already_known = tlli_info != NULL; + if (!tlli_info) { + tlli_info = gbprox_tlli_info_alloc(peer); + tlli_info->tlli.current = tlli; + } else { + gbprox_detach_tlli_info(peer, tlli_info); + tlli_already_known = 1; + } - tlli_info = gbprox_get_detached_tlli_info(peer, tlli_info, tlli); OSMO_ASSERT(tlli_info != NULL); if (!tlli_already_known) -- cgit v1.2.3 From 12496dd7db41b3de8a9fe71b843c9378360b33d3 Mon Sep 17 00:00:00 2001 From: Jacob Erlbeck Date: Mon, 18 Aug 2014 15:41:41 +0200 Subject: gbproxy: Refactor gbprox_patch_raid(), use different RAI types properly Currently gbprox_patch_raid() updates the local MCC/MNC with every BSS originated message, even if the RAI is an 'old' one. This patch separates state updating and patching into 2 functions gbprox_update_current_raid and gbprox_patch_raid. In addition, a field named old_raid_enc is added to gbproxy_parse_context, which is used for 'old RAI' IEs in Attach Requests and RA Update Requests. Only the bssg_raid_enc in BSS originated message is used to update the BSS side 'local' MCC/MNC. Sponsored-by: On-Waves ehf --- openbsc/src/gprs/gb_proxy.c | 116 ++++++++++++++++++++++++++++++++------------ 1 file changed, 85 insertions(+), 31 deletions(-) diff --git a/openbsc/src/gprs/gb_proxy.c b/openbsc/src/gprs/gb_proxy.c index 0d738aa38..eb1a699e4 100644 --- a/openbsc/src/gprs/gb_proxy.c +++ b/openbsc/src/gprs/gb_proxy.c @@ -409,6 +409,7 @@ struct gbproxy_parse_context { uint8_t *ptmsi_enc; uint8_t *new_ptmsi_enc; uint8_t *raid_enc; + uint8_t *old_raid_enc; uint8_t *bssgp_raid_enc; uint8_t *bssgp_ptimsi; @@ -418,6 +419,7 @@ struct gbproxy_parse_context { int need_decryption; uint32_t tlli; int pdu_type; + int old_raid_matches; }; struct gbproxy_tlli_info *gbprox_find_tlli(struct gbproxy_peer *peer, @@ -821,13 +823,51 @@ static int patching_is_required(struct gbproxy_peer *peer, return need_at_least <= peer->cfg->patch_mode; } -/* patch RA identifier in place, update peer accordingly */ -static void gbprox_patch_raid(uint8_t *raid_enc, struct gbproxy_peer *peer, - int to_bss, const char *log_text) +/* update peer according to the BSS message */ +static void gbprox_update_current_raid(uint8_t *raid_enc, + struct gbproxy_peer *peer, + const char *log_text) { struct gbproxy_patch_state *state = &peer->patch_state; const int old_local_mcc = state->local_mcc; const int old_local_mnc = state->local_mnc; + struct gprs_ra_id raid; + + if (!raid_enc) + return; + + gsm48_parse_ra(&raid, raid_enc); + + /* save source side MCC/MNC */ + if (!peer->cfg->core_mcc || raid.mcc == peer->cfg->core_mcc) { + state->local_mcc = 0; + } else { + state->local_mcc = raid.mcc; + } + + if (!peer->cfg->core_mnc || raid.mnc == peer->cfg->core_mnc) { + state->local_mnc = 0; + } else { + state->local_mnc = raid.mnc; + } + + if (old_local_mcc != state->local_mcc || + old_local_mnc != state->local_mnc) + LOGP(DGPRS, LOGL_NOTICE, + "Patching RAID %sactivated, msg: %s, " + "local: %d-%d, core: %d-%d\n", + state->local_mcc || state->local_mnc ? + "" : "de", + log_text, + state->local_mcc, state->local_mnc, + peer->cfg->core_mcc, peer->cfg->core_mnc); +} + +/* patch RA identifier in place */ +static void gbprox_patch_raid(uint8_t *raid_enc, struct gbproxy_peer *peer, + int to_bss, const char *log_text) +{ + struct gbproxy_patch_state *state = &peer->patch_state; int old_mcc; int old_mnc; struct gprs_ra_id raid; @@ -839,20 +879,11 @@ static void gbprox_patch_raid(uint8_t *raid_enc, struct gbproxy_peer *peer, if (!to_bss) { /* BSS -> SGSN */ - /* save BSS side MCC/MNC */ - if (!peer->cfg->core_mcc || raid.mcc == peer->cfg->core_mcc) { - state->local_mcc = 0; - } else { - state->local_mcc = raid.mcc; + if (state->local_mcc) raid.mcc = peer->cfg->core_mcc; - } - if (!peer->cfg->core_mnc || raid.mnc == peer->cfg->core_mnc) { - state->local_mnc = 0; - } else { - state->local_mnc = raid.mnc; + if (state->local_mnc) raid.mnc = peer->cfg->core_mnc; - } } else { /* SGSN -> BSS */ if (state->local_mcc) @@ -862,18 +893,6 @@ static void gbprox_patch_raid(uint8_t *raid_enc, struct gbproxy_peer *peer, raid.mnc = state->local_mnc; } - if (old_local_mcc != state->local_mcc || - old_local_mnc != state->local_mnc) - LOGP(DGPRS, LOGL_NOTICE, - "Patching RAID %sactivated, msg: %s, " - "local: %d-%d, core: %d-%d, to %s\n", - state->local_mcc || state->local_mnc ? - "" : "de", - log_text, - state->local_mcc, state->local_mnc, - peer->cfg->core_mcc, peer->cfg->core_mnc, - to_bss ? "BSS" : "SGSN"); - if (state->local_mcc || state->local_mnc) { enum gbprox_peer_ctr counter = to_bss ? @@ -979,7 +998,7 @@ static int gbprox_parse_gmm_attach_req(uint8_t *data, size_t data_len, if (v_fixed_shift(&data, &data_len, 6, &value) <= 0) return 0; - parse_ctx->raid_enc = value; + parse_ctx->old_raid_enc = value; return 1; } @@ -1069,7 +1088,7 @@ static int gbprox_parse_gmm_ra_upd_req(uint8_t *data, size_t data_len, if (v_fixed_shift(&data, &data_len, 6, &value) <= 0) return 0; - parse_ctx->raid_enc = value; + parse_ctx->old_raid_enc = value; return 1; } @@ -1339,14 +1358,18 @@ static int gbprox_patch_llc(struct msgb *msg, uint8_t *llc, size_t llc_len, return have_patched; if (parse_ctx->raid_enc) { - /* TODO: BSS->SGSN: Only patch if matches original BSSGP, - * don't update internal mapping, patch to invalid if P-TMSI - * unknown. */ gbprox_patch_raid(parse_ctx->raid_enc, peer, parse_ctx->to_bss, parse_ctx->llc_msg_name); have_patched = 1; } + if (parse_ctx->old_raid_enc && parse_ctx->old_raid_matches) { + /* TODO: Patch to invalid if P-TMSI unknown. */ + gbprox_patch_raid(parse_ctx->old_raid_enc, peer, parse_ctx->to_bss, + parse_ctx->llc_msg_name); + have_patched = 1; + } + if (parse_ctx->apn_ie && peer->cfg->core_apn && !parse_ctx->to_bss && @@ -1399,6 +1422,30 @@ static void gbprox_log_parse_context(struct gbproxy_parse_context *parse_ctx, sep = ","; } + if (parse_ctx->bssgp_raid_enc) { + struct gprs_ra_id raid; + gsm48_parse_ra(&raid, parse_ctx->bssgp_raid_enc); + LOGP(DGPRS, LOGL_DEBUG, "%s BSSGP RAID %u-%u-%u-%u", sep, + raid.mcc, raid.mnc, raid.lac, raid.rac); + sep = ","; + } + + if (parse_ctx->raid_enc) { + struct gprs_ra_id raid; + gsm48_parse_ra(&raid, parse_ctx->raid_enc); + LOGP(DGPRS, LOGL_DEBUG, "%s RAID %u-%u-%u-%u", sep, + raid.mcc, raid.mnc, raid.lac, raid.rac); + sep = ","; + } + + if (parse_ctx->old_raid_enc) { + struct gprs_ra_id raid; + gsm48_parse_ra(&raid, parse_ctx->old_raid_enc); + LOGP(DGPRS, LOGL_DEBUG, "%s old RAID %u-%u-%u-%u", sep, + raid.mcc, raid.mnc, raid.lac, raid.rac); + sep = ","; + } + if (parse_ctx->ptmsi_enc) { uint32_t ptmsi = GSM_RESERVED_TMSI; int ok; @@ -1840,6 +1887,13 @@ static void gbprox_process_bssgp_ul(struct gbproxy_config *cfg, now = time(NULL); + if (parse_ctx.bssgp_raid_enc && parse_ctx.old_raid_enc && + memcmp(parse_ctx.bssgp_raid_enc, parse_ctx.old_raid_enc, 6) == 0) + parse_ctx.old_raid_matches = 1; + + gbprox_update_current_raid(parse_ctx.bssgp_raid_enc, peer, + parse_ctx.llc_msg_name); + tlli_info = gbprox_update_state_ul(peer, now, &parse_ctx); gbprox_patch_bssgp(msg, msgb_bssgph(msg), msgb_bssgp_len(msg), -- cgit v1.2.3 From 3b23d639ab667de85dd18ac89f8e9315cb43710f Mon Sep 17 00:00:00 2001 From: Jacob Erlbeck Date: Mon, 18 Aug 2014 16:50:11 +0200 Subject: gbproxy: Also handle LLC non UI and LL11 messages Currently, these messages lead to a parsing error which prevents them from being processed any further. This patch sets the return value of gbprox_parse_llc to 1 in these cases and fixes a segfault which is triggered by any non-04.08 message. Sponsored-by: On-Waves ehf --- openbsc/src/gprs/gb_proxy.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/openbsc/src/gprs/gb_proxy.c b/openbsc/src/gprs/gb_proxy.c index eb1a699e4..cbf2e9075 100644 --- a/openbsc/src/gprs/gb_proxy.c +++ b/openbsc/src/gprs/gb_proxy.c @@ -1327,10 +1327,10 @@ static int gbprox_parse_llc(uint8_t *llc, size_t llc_len, return 0; if (ghp->sapi != GPRS_SAPI_GMM) - return 0; + return 1; if (ghp->cmd != GPRS_LLC_UI) - return 0; + return 1; if (ghp->is_encrypted) { parse_ctx->need_decryption = 1; @@ -1354,7 +1354,7 @@ static int gbprox_patch_llc(struct msgb *msg, uint8_t *llc, size_t llc_len, int have_patched = 0; int fcs; - if (!allow_message_patching(peer, parse_ctx->g48_hdr->msg_type)) + if (parse_ctx->g48_hdr && !allow_message_patching(peer, parse_ctx->g48_hdr->msg_type)) return have_patched; if (parse_ctx->raid_enc) { -- cgit v1.2.3 From e37487e0838a03ebc5cb06cf980278d7196bc5df Mon Sep 17 00:00:00 2001 From: Jacob Erlbeck Date: Mon, 18 Aug 2014 17:01:32 +0200 Subject: gbproxy: Fix TLLI state handling This patch contains fixes for the TLLI tracking and handling. It adds and uses gbprox_map_tlli() the map the source TLLI to the destination TLLI while respecting whether it is current or assigned. It removes gbprox_register_tlli() from the downlink path. It fixes TLLI validation and disables the use of the BSSGP TLLI IE. Sponsored-by: On-Waves ehf --- openbsc/src/gprs/gb_proxy.c | 63 +++++++++++++++++++++++++++++++-------------- 1 file changed, 44 insertions(+), 19 deletions(-) diff --git a/openbsc/src/gprs/gb_proxy.c b/openbsc/src/gprs/gb_proxy.c index cbf2e9075..ef2f0d417 100644 --- a/openbsc/src/gprs/gb_proxy.c +++ b/openbsc/src/gprs/gb_proxy.c @@ -687,6 +687,26 @@ void gbprox_reassign_tlli(struct gbproxy_tlli_state *tlli_state, tlli_state->net_validated = 0; } +static uint32_t gbprox_map_tlli(uint32_t other_tlli, + struct gbproxy_tlli_info *tlli_info, int to_bss) +{ + uint32_t tlli = 0; + struct gbproxy_tlli_state *src, *dst; + if (to_bss) { + src = &tlli_info->sgsn_tlli; + dst = &tlli_info->tlli; + } else { + src = &tlli_info->tlli; + dst = &tlli_info->sgsn_tlli; + } + if (src->current == other_tlli) + tlli = dst->current; + else if (src->assigned == other_tlli) + tlli = dst->assigned; + + return tlli; +} + static void gbprox_validate_tlli(struct gbproxy_tlli_state *tlli_state, uint32_t tlli, int to_bss) { @@ -1489,6 +1509,7 @@ static uint32_t gbprox_make_bss_ptmsi(struct gbproxy_peer *peer, } static uint32_t gbprox_make_sgsn_tlli(struct gbproxy_peer *peer, + struct gbproxy_tlli_info *tlli_info, uint32_t bss_tlli) { return bss_tlli; @@ -1525,16 +1546,14 @@ static struct gbproxy_tlli_info *gbprox_update_state_ul( parse_ctx->imsi, parse_ctx->imsi_len, now); /* Setup TLLIs */ - sgsn_tlli = gbprox_make_sgsn_tlli(peer, parse_ctx->tlli); + sgsn_tlli = gbprox_make_sgsn_tlli(peer, tlli_info, + parse_ctx->tlli); tlli_info->sgsn_tlli.current = sgsn_tlli; } else { - sgsn_tlli = tlli_info->sgsn_tlli.assigned; + sgsn_tlli = gbprox_map_tlli(parse_ctx->tlli, tlli_info, 0); if (!sgsn_tlli) - sgsn_tlli = tlli_info->sgsn_tlli.current; - if (!sgsn_tlli) { - sgsn_tlli = gbprox_make_sgsn_tlli(peer, + sgsn_tlli = gbprox_make_sgsn_tlli(peer, tlli_info, parse_ctx->tlli); - } gbprox_validate_tlli(&tlli_info->tlli, parse_ctx->tlli, 0); @@ -1612,10 +1631,12 @@ static struct gbproxy_tlli_info *gbprox_update_state_dl( peer, new_bss_tlli); gbprox_touch_tlli(peer, tlli_info, now); } else { - tlli_info = - gbprox_register_tlli(peer, new_bss_tlli, - parse_ctx->imsi, - parse_ctx->imsi_len, now); + tlli_info = gbprox_tlli_info_alloc(peer); + LOGP(DGPRS, LOGL_INFO, + "Adding TLLI %08x to list (SGSN, new P-TMSI)\n", + new_sgsn_tlli); + + gbprox_attach_tlli_info(peer, now, tlli_info); /* Setup TLLIs */ tlli_info->sgsn_tlli.current = new_sgsn_tlli; } @@ -1624,13 +1645,13 @@ static struct gbproxy_tlli_info *gbprox_update_state_dl( tlli_info->tlli.ptmsi = new_bss_ptmsi; } else if (parse_ctx->tlli_enc && parse_ctx->llc && !tlli_info) { /* Unknown SGSN TLLI */ - tlli_info = - gbprox_register_tlli(peer, parse_ctx->tlli, - parse_ctx->imsi, - parse_ctx->imsi_len, now); + tlli_info = gbprox_tlli_info_alloc(peer); + LOGP(DGPRS, LOGL_INFO, "Adding TLLI %08x to list (SGSN)\n", + parse_ctx->tlli); + gbprox_attach_tlli_info(peer, now, tlli_info); /* Setup TLLIs */ - tlli_info->sgsn_tlli.current = tlli_info->tlli.current; + tlli_info->sgsn_tlli.current = parse_ctx->tlli; if (peer->cfg->patch_ptmsi) { /* TODO: We don't know the local TLLI here, perhaps add * a workaround that derives a PTMSI from the SGSN TLLI @@ -1640,12 +1661,14 @@ static struct gbproxy_tlli_info *gbprox_update_state_dl( * length. */ tlli_info->tlli.current = 0; + } else { + tlli_info->tlli.current = tlli_info->sgsn_tlli.current; } } else if (parse_ctx->tlli_enc && parse_ctx->llc && tlli_info) { + uint32_t bss_tlli = gbprox_map_tlli(parse_ctx->tlli, + tlli_info, 1); gbprox_validate_tlli(&tlli_info->sgsn_tlli, parse_ctx->tlli, 1); - if (!peer->cfg->patch_ptmsi) - gbprox_validate_tlli(&tlli_info->tlli, - parse_ctx->tlli, 1); + gbprox_validate_tlli(&tlli_info->tlli, bss_tlli, 1); gbprox_touch_tlli(peer, tlli_info, now); } else if (tlli_info) { gbprox_touch_tlli(peer, tlli_info, now); @@ -1730,7 +1753,9 @@ static int gbprox_parse_bssgp(uint8_t *bssgp, size_t bssgp_len, parse_ctx->imsi_len = TLVP_LEN(tp, BSSGP_IE_IMSI); } - if (TLVP_PRESENT(tp, BSSGP_IE_TLLI)) + /* TODO: This is TLLI old, don't confuse with TLLI current, add + * and use tlli_old_enc instead */ + if (0 && TLVP_PRESENT(tp, BSSGP_IE_TLLI)) parse_ctx->tlli_enc = (uint8_t *)TLVP_VAL(tp, BSSGP_IE_TLLI); if (TLVP_PRESENT(tp, BSSGP_IE_TMSI) && pdu_type == BSSGP_PDUT_PAGING_PS) -- cgit v1.2.3 From 03ca10e8635d86379c80e9eb295dd1561fa36d1f Mon Sep 17 00:00:00 2001 From: Jacob Erlbeck Date: Mon, 18 Aug 2014 17:23:01 +0200 Subject: gbproxy: Patch TLLI/P-TMSI This patch adds code to modify TLLIs and P-TMSIs. Related counters are also added. Sponsored-by: On-Waves ehf --- openbsc/src/gprs/gb_proxy.c | 123 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 123 insertions(+) diff --git a/openbsc/src/gprs/gb_proxy.c b/openbsc/src/gprs/gb_proxy.c index ef2f0d417..549d3d7ed 100644 --- a/openbsc/src/gprs/gb_proxy.c +++ b/openbsc/src/gprs/gb_proxy.c @@ -95,10 +95,15 @@ enum gbprox_peer_ctr { GBPROX_PEER_CTR_RAID_PATCHED_BSS, GBPROX_PEER_CTR_RAID_PATCHED_SGSN, GBPROX_PEER_CTR_APN_PATCHED, + GBPROX_PEER_CTR_TLLI_PATCHED_BSS, + GBPROX_PEER_CTR_TLLI_PATCHED_SGSN, + GBPROX_PEER_CTR_PTMSI_PATCHED_BSS, + GBPROX_PEER_CTR_PTMSI_PATCHED_SGSN, GBPROX_PEER_CTR_PATCH_CRYPT_ERR, GBPROX_PEER_CTR_PATCH_ERR, GBPROX_PEER_CTR_ATTACH_REQS, GBPROX_PEER_CTR_ATTACH_REJS, + GBPROX_PEER_CTR_TLLI_UNKNOWN, GBPROX_PEER_CTR_TLLI_CACHE_SIZE, }; @@ -111,10 +116,15 @@ static const struct rate_ctr_desc peer_ctr_description[] = { { "raid-mod.bss", "RAID patched (BSS )" }, { "raid-mod.sgsn", "RAID patched (SGSN)" }, { "apn-mod.sgsn", "APN patched " }, + { "tlli-mod.bss", "TLLI patched (BSS )" }, + { "tlli-mod.sgsn", "TLLI patched (SGSN)" }, + { "ptmsi-mod.bss", "P-TMSI patched (BSS )" }, + { "ptmsi-mod.sgsn","P-TMSI patched (SGSN)" }, { "mod-crypt-err", "Patch error: encrypted " }, { "mod-err", "Patch error: other " }, { "attach-reqs", "Attach Request count " }, { "attach-rejs", "Attach Reject count " }, + { "tlli-unknown", "TLLI from SGSN unknown " }, { "tlli-cache", "TLLI cache size " }, }; @@ -983,6 +993,67 @@ static void gbprox_patch_apn_ie(struct msgb *msg, rate_ctr_inc(&peer->ctrg->ctr[GBPROX_PEER_CTR_APN_PATCHED]); } +static int gbprox_patch_tlli(uint8_t *tlli_enc, + struct gbproxy_peer *peer, + uint32_t new_tlli, + int to_bss, const char *log_text) +{ + uint32_t tlli_be; + uint32_t tlli; + enum gbprox_peer_ctr counter = + to_bss ? + GBPROX_PEER_CTR_TLLI_PATCHED_SGSN : + GBPROX_PEER_CTR_TLLI_PATCHED_BSS; + + memcpy(&tlli_be, tlli_enc, sizeof(tlli_be)); + tlli = ntohl(tlli_be); + + if (tlli == new_tlli) + return 0; + + LOGP(DGPRS, LOGL_DEBUG, + "Patching %ss: " + "Replacing %08x -> %08x\n", + log_text, tlli, new_tlli); + + tlli_be = htonl(new_tlli); + memcpy(tlli_enc, &tlli_be, sizeof(tlli_be)); + + rate_ctr_inc(&peer->ctrg->ctr[counter]); + + return 1; +} + +static int gbprox_patch_ptmsi(uint8_t *ptmsi_enc, + struct gbproxy_peer *peer, + uint32_t new_ptmsi, + int to_bss, const char *log_text) +{ + uint32_t ptmsi_be; + uint32_t ptmsi; + enum gbprox_peer_ctr counter = + to_bss ? + GBPROX_PEER_CTR_PTMSI_PATCHED_SGSN : + GBPROX_PEER_CTR_PTMSI_PATCHED_BSS; + memcpy(&ptmsi_be, ptmsi_enc + 1, sizeof(ptmsi_be)); + ptmsi = ntohl(ptmsi_be); + + if (ptmsi == new_ptmsi) + return 0; + + LOGP(DGPRS, LOGL_DEBUG, + "Patching %ss: " + "Replacing %08x -> %08x\n", + log_text, ptmsi, new_ptmsi); + + ptmsi_be = htonl(new_ptmsi); + memcpy(ptmsi_enc + 1, &ptmsi_be, sizeof(ptmsi_be)); + + rate_ctr_inc(&peer->ctrg->ctr[counter]); + + return 1; +} + static int gbprox_parse_gmm_attach_req(uint8_t *data, size_t data_len, struct gbproxy_parse_context *parse_ctx) { @@ -1377,6 +1448,35 @@ static int gbprox_patch_llc(struct msgb *msg, uint8_t *llc, size_t llc_len, if (parse_ctx->g48_hdr && !allow_message_patching(peer, parse_ctx->g48_hdr->msg_type)) return have_patched; + if (parse_ctx->ptmsi_enc && tlli_info) { + uint32_t ptmsi; + if (parse_ctx->to_bss) + ptmsi = tlli_info->tlli.ptmsi; + else + ptmsi = tlli_info->sgsn_tlli.ptmsi; + + if (ptmsi != GSM_RESERVED_TMSI) { + if (gbprox_patch_ptmsi(parse_ctx->ptmsi_enc, peer, + ptmsi, parse_ctx->to_bss, "P-TMSI")) + have_patched = 1; + } else { + /* TODO: invalidate old RAI if present (see below) */ + } + } + + if (parse_ctx->new_ptmsi_enc && tlli_info) { + uint32_t ptmsi; + if (parse_ctx->to_bss) + ptmsi = tlli_info->tlli.ptmsi; + else + ptmsi = tlli_info->sgsn_tlli.ptmsi; + + OSMO_ASSERT(ptmsi); + if (gbprox_patch_ptmsi(parse_ctx->new_ptmsi_enc, peer, + ptmsi, parse_ctx->to_bss, "new P-TMSI")) + have_patched = 1; + } + if (parse_ctx->raid_enc) { gbprox_patch_raid(parse_ctx->raid_enc, peer, parse_ctx->to_bss, parse_ctx->llc_msg_name); @@ -1817,6 +1917,29 @@ static void gbprox_patch_bssgp(struct msgb *msg, uint8_t *bssgp, size_t bssgp_le goto patch_error; } + if (parse_ctx->tlli_enc && tlli_info) { + uint32_t tlli = gbprox_map_tlli(parse_ctx->tlli, + tlli_info, parse_ctx->to_bss); + + if (tlli) { + gbprox_patch_tlli(parse_ctx->tlli_enc, peer, tlli, + parse_ctx->to_bss, "TLLI"); + parse_ctx->tlli = tlli; + } else if (parse_ctx->to_bss) { + /* Happens with unknown (not cached) TLLI coming from + * the SGSN */ + /* TODO: What shall be done with the message in this case? */ + err_ctr = GBPROX_PEER_CTR_TLLI_UNKNOWN; + err_info = "TLLI sent by the SGSN is unknown"; + goto patch_error; + } else { + /* Internal error */ + err_ctr = GBPROX_PEER_CTR_PATCH_ERR; + err_info = "Replacement TLLI is 0"; + goto patch_error; + } + } + if (parse_ctx->llc) { uint8_t *llc = parse_ctx->llc; size_t llc_len = parse_ctx->llc_len; -- cgit v1.2.3 From 643d5228edd71f50a2ebb27854a4d5f3ff3b2835 Mon Sep 17 00:00:00 2001 From: Jacob Erlbeck Date: Mon, 18 Aug 2014 17:26:04 +0200 Subject: gbproxy: Add context info to log messages This mainly adds the NSEI to the messages, similar to log messages ogf the existing gbproxy code. Sponsored-by: On-Waves ehf --- openbsc/src/gprs/gb_proxy.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/openbsc/src/gprs/gb_proxy.c b/openbsc/src/gprs/gb_proxy.c index 549d3d7ed..8bad721ef 100644 --- a/openbsc/src/gprs/gb_proxy.c +++ b/openbsc/src/gprs/gb_proxy.c @@ -1982,7 +1982,9 @@ patch_error: OSMO_ASSERT(err_ctr >= 0); rate_ctr_inc(&peer->ctrg->ctr[err_ctr]); LOGP(DGPRS, LOGL_ERROR, - "Failed to patch BSSGP message as requested: %s.\n", err_info); + "NSEI=%u(%s) failed to patch BSSGP message as requested: %s.\n", + msgb_nsei(msg), parse_ctx->to_bss ? "SGSN" : "BSS", + err_info); } /* patch BSSGP message */ @@ -2008,7 +2010,9 @@ static void gbprox_process_bssgp_ul(struct gbproxy_config *cfg, if (!rc) { if (!parse_ctx.need_decryption) { LOGP(DGPRS, LOGL_ERROR, - "Failed to parse BSSGP/GMM message\n"); + "NSEI=%u(BSS) patching: " + "failed to parse BSSGP/GMM message\n", + msgb_nsei(msg)); return; } } @@ -2071,7 +2075,9 @@ static void gbprox_process_bssgp_dl(struct gbproxy_config *cfg, if (!rc) { if (!parse_ctx.need_decryption) { LOGP(DGPRS, LOGL_ERROR, - "Failed to parse BSSGP/GMM message\n"); + "NSEI=%u(SGSN) patching: " + "failed to parse BSSGP/GMM message\n", + msgb_nsei(msg)); return; } } -- cgit v1.2.3 From 0d37671824a50ab0924298284cfd1eb730dbb761 Mon Sep 17 00:00:00 2001 From: Jacob Erlbeck Date: Mon, 11 Aug 2014 19:12:24 +0200 Subject: gbproxy: Use different TLLI/P-TMSI for BSS and SGSN This patch modifies gbprox_make_bss_ptmsi() to generate a new P-TMSI when patch_ptmsi is set in the configuration instead of using the P-TMSI assigned by the SGSN. It modifies gbprox_make_sgsn_tlli() to either use a foreign TLLI based on the SGSN side P-TMSI or (if there is none) generate a random TLLI if patch_ptmsi is set. Otherwise, the TLLI used by the BSS is used. The seeds for the pseudo-random sequences sre set based on time initially. Note that these are neither cryptographically safe nor protected against collisions. Ticket: OW#1259 Sponsored-by: On-Waves ehf --- openbsc/include/openbsc/gb_proxy.h | 4 +++ openbsc/src/gprs/gb_proxy.c | 51 ++++++++++++++++++++++++++++++++++++-- 2 files changed, 53 insertions(+), 2 deletions(-) diff --git a/openbsc/include/openbsc/gb_proxy.h b/openbsc/include/openbsc/gb_proxy.h index 468228043..e7d1b1cbe 100644 --- a/openbsc/include/openbsc/gb_proxy.h +++ b/openbsc/include/openbsc/gb_proxy.h @@ -49,6 +49,10 @@ struct gbproxy_config { /* IMSI checking/matching */ int check_imsi; regex_t imsi_re_comp; + + /* Used to generate identifiers */ + unsigned bss_ptmsi_state; + unsigned sgsn_tlli_state; }; struct gbproxy_patch_state { diff --git a/openbsc/src/gprs/gb_proxy.c b/openbsc/src/gprs/gb_proxy.c index 8bad721ef..86ae0e821 100644 --- a/openbsc/src/gprs/gb_proxy.c +++ b/openbsc/src/gprs/gb_proxy.c @@ -446,6 +446,20 @@ struct gbproxy_tlli_info *gbprox_find_tlli(struct gbproxy_peer *peer, return NULL; } +static struct gbproxy_tlli_info *gbprox_find_tlli_by_ptmsi( + struct gbproxy_peer *peer, + uint32_t ptmsi) +{ + struct gbproxy_tlli_info *tlli_info; + struct gbproxy_patch_state *state = &peer->patch_state; + + llist_for_each_entry(tlli_info, &state->enabled_tllis, list) + if (tlli_info->tlli.ptmsi == ptmsi) + return tlli_info; + + return NULL; +} + struct gbproxy_tlli_info *gbprox_find_tlli_by_sgsn_tlli( struct gbproxy_peer *peer, uint32_t tlli) @@ -1605,14 +1619,43 @@ static void gbprox_log_parse_context(struct gbproxy_parse_context *parse_ctx, static uint32_t gbprox_make_bss_ptmsi(struct gbproxy_peer *peer, uint32_t sgsn_ptmsi) { - return sgsn_ptmsi; + uint32_t bss_ptmsi; + if (!peer->cfg->patch_ptmsi) { + bss_ptmsi = sgsn_ptmsi; + } else { + do { + bss_ptmsi = rand_r(&peer->cfg->bss_ptmsi_state); + bss_ptmsi = bss_ptmsi | 0xC0000000; + + if (gbprox_find_tlli_by_ptmsi(peer, bss_ptmsi)) + bss_ptmsi = GSM_RESERVED_TMSI; + } while (bss_ptmsi == GSM_RESERVED_TMSI); + } + + return bss_ptmsi; } static uint32_t gbprox_make_sgsn_tlli(struct gbproxy_peer *peer, struct gbproxy_tlli_info *tlli_info, uint32_t bss_tlli) { - return bss_tlli; + uint32_t sgsn_tlli; + if (!peer->cfg->patch_ptmsi) { + sgsn_tlli = bss_tlli; + } else if (tlli_info->sgsn_tlli.ptmsi != GSM_RESERVED_TMSI) { + sgsn_tlli = gprs_tmsi2tlli(tlli_info->sgsn_tlli.ptmsi, + TLLI_FOREIGN); + } else { + do { + /* create random TLLI, 0b01111xxx... */ + sgsn_tlli = rand_r(&peer->cfg->sgsn_tlli_state); + sgsn_tlli = (sgsn_tlli & 0x7fffffff) | 0x78000000; + + if (gbprox_find_tlli_by_sgsn_tlli(peer, sgsn_tlli)) + sgsn_tlli = 0; + } while (!sgsn_tlli); + } + return sgsn_tlli; } static struct gbproxy_tlli_info *gbprox_update_state_ul( @@ -2698,7 +2741,11 @@ int gbprox_cleanup_peers(struct gbproxy_config *cfg, uint16_t nsei, uint16_t bvc int gbproxy_init_config(struct gbproxy_config *cfg) { + struct timespec tp; INIT_LLIST_HEAD(&cfg->bts_peers); cfg->ctrg = rate_ctr_group_alloc(tall_bsc_ctx, &global_ctrg_desc, 0); + clock_gettime(CLOCK_REALTIME, &tp); + cfg->bss_ptmsi_state = tp.tv_sec + tp.tv_nsec; + cfg->sgsn_tlli_state = tp.tv_sec - tp.tv_nsec; return 0; } -- cgit v1.2.3 From 6bd7ded71ea3a1de200ad1190e7f7cbee6cae5f9 Mon Sep 17 00:00:00 2001 From: Jacob Erlbeck Date: Fri, 15 Aug 2014 17:20:06 +0200 Subject: gbproxy/test: Add test for TLLI patching Add LLC test messages containing XID (SAPI LLGMM, U frame) and IP traffic (SAPI LL11, UI frame). Add a test case containing a complete SGSN session with TLLI/PTMSI patching enabled. Sponsored-by: On-Waves ehf --- openbsc/tests/gbproxy/gbproxy_test.c | 238 +++++++++++++++++++++ openbsc/tests/gbproxy/gbproxy_test.ok | 378 ++++++++++++++++++++++++++++++++++ 2 files changed, 616 insertions(+) diff --git a/openbsc/tests/gbproxy/gbproxy_test.c b/openbsc/tests/gbproxy/gbproxy_test.c index 2a521eeec..d7ddafd80 100644 --- a/openbsc/tests/gbproxy/gbproxy_test.c +++ b/openbsc/tests/gbproxy/gbproxy_test.c @@ -233,6 +233,61 @@ static const unsigned char dtap_detach_acc[] = { 0x08, 0x06, 0x00 }; +/* GPRS-LLC - SAPI: LLGMM, U, XID */ +static const unsigned char llc_u_xid_ul[] = { + 0x41, 0xfb, 0x01, 0x00, 0x0e, 0x00, 0x64, 0x11, + 0x05, 0x16, 0x01, 0x90, 0x66, 0xb3, 0x28 +}; + +/* GPRS-LLC - SAPI: LLGMM, U, XID */ +static const unsigned char llc_u_xid_dl[] = { + 0x41, 0xfb, 0x30, 0x84, 0x10, 0x61, 0xb6, 0x64, + 0xe4, 0xa9, 0x1a, 0x9e +}; + +/* GPRS-LLC - SAPI: LL11, UI, NSAPI 5, DNS query */ +static const unsigned char llc_ui_ll11_dns_query_ul[] = { + 0x0b, 0xc0, 0x01, 0x65, 0x00, 0x00, 0x00, 0x45, + 0x00, 0x00, 0x38, 0x95, 0x72, 0x00, 0x00, 0x45, + 0x11, 0x20, 0x85, 0x0a, 0xc0, 0x07, 0xe4, 0xac, + 0x10, 0x01, 0x0a, 0xad, 0xab, 0x00, 0x35, 0x00, + 0x24, 0x0e, 0x1c, 0x3b, 0xe0, 0x01, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x6d, 0x05, 0x68, 0x65, 0x69, 0x73, 0x65, 0x02, + 0x64, 0x65, 0x00, 0x00, 0x01, 0x00, 0x01, 0x47, + 0x8f, 0x07 +}; + +/* GPRS-LLC - SAPI: LL11, UI, NSAPI 5, DNS query */ +static const unsigned char llc_ui_ll11_dns_resp_dl[] = { + 0x4b, 0xc0, 0x01, 0x65, 0x00, 0x00, 0x00, 0x45, + 0x00, 0x00, 0xc6, 0x00, 0x00, 0x40, 0x00, 0x3e, + 0x11, 0x7c, 0x69, 0xac, 0x10, 0x01, 0x0a, 0x0a, + 0xc0, 0x07, 0xe4, 0x00, 0x35, 0xad, 0xab, 0x00, + 0xb2, 0x74, 0x4e, 0x3b, 0xe0, 0x81, 0x80, 0x00, + 0x01, 0x00, 0x01, 0x00, 0x05, 0x00, 0x00, 0x01, + 0x6d, 0x05, 0x68, 0x65, 0x69, 0x73, 0x65, 0x02, + 0x64, 0x65, 0x00, 0x00, 0x01, 0x00, 0x01, 0xc0, + 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0e, + 0x10, 0x00, 0x04, 0xc1, 0x63, 0x90, 0x58, 0xc0, + 0x0e, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x0e, + 0x10, 0x00, 0x16, 0x03, 0x6e, 0x73, 0x32, 0x0c, + 0x70, 0x6f, 0x70, 0x2d, 0x68, 0x61, 0x6e, 0x6e, + 0x6f, 0x76, 0x65, 0x72, 0x03, 0x6e, 0x65, 0x74, + 0x00, 0xc0, 0x0e, 0x00, 0x02, 0x00, 0x01, 0x00, + 0x00, 0x0e, 0x10, 0x00, 0x10, 0x02, 0x6e, 0x73, + 0x01, 0x73, 0x08, 0x70, 0x6c, 0x75, 0x73, 0x6c, + 0x69, 0x6e, 0x65, 0xc0, 0x14, 0xc0, 0x0e, 0x00, + 0x02, 0x00, 0x01, 0x00, 0x00, 0x0e, 0x10, 0x00, + 0x05, 0x02, 0x6e, 0x73, 0xc0, 0x0e, 0xc0, 0x0e, + 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x0e, 0x10, + 0x00, 0x05, 0x02, 0x6e, 0x73, 0xc0, 0x5f, 0xc0, + 0x0e, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x0e, + 0x10, 0x00, 0x12, 0x02, 0x6e, 0x73, 0x0c, 0x70, + 0x6f, 0x70, 0x2d, 0x68, 0x61, 0x6e, 0x6e, 0x6f, + 0x76, 0x65, 0x72, 0xc0, 0x14, 0xaa, 0xdf, 0x31 +}; + static int gprs_process_message(struct gprs_ns_inst *nsi, const char *text, struct sockaddr_in *peer, const unsigned char* data, size_t data_len); @@ -1315,6 +1370,188 @@ static void test_gbproxy_ra_patching() nsi = NULL; } +static void test_gbproxy_ptmsi_patching() +{ + struct gprs_ns_inst *nsi = gprs_ns_instantiate(gprs_ns_callback, NULL); + struct sockaddr_in bss_peer[1] = {{0},}; + struct sockaddr_in sgsn_peer= {0}; + struct gprs_ra_id rai_bss = + {.mcc = 112, .mnc = 332, .lac = 16464, .rac = 96}; + struct gprs_ra_id rai_sgsn = + {.mcc = 123, .mnc = 456, .lac = 16464, .rac = 96}; + struct gprs_ra_id rai_unknown = + {.mcc = 1, .mnc = 99, .lac = 99, .rac = 96}; + uint16_t cell_id = 0x1234; + + const uint32_t sgsn_ptmsi = 0xefe2b700; + const uint32_t local_sgsn_tlli = 0xefe2b700; + const uint32_t random_sgsn_tlli = 0x7c69fb81; + + const uint32_t bss_ptmsi = 0xc00f7304; + const uint32_t local_bss_tlli = 0xc00f7304; + const uint32_t foreign_bss_tlli = 0x8000dead; + + const uint8_t imsi[] = {0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18}; + struct gbproxy_tlli_info *tlli_info; + struct gbproxy_peer *peer; + unsigned bss_nu = 0; + unsigned sgsn_nu = 0; + + OSMO_ASSERT(local_sgsn_tlli == gprs_tmsi2tlli(sgsn_ptmsi, TLLI_LOCAL)); + + bssgp_nsi = nsi; + gbcfg.nsi = bssgp_nsi; + gbcfg.nsip_sgsn_nsei = SGSN_NSEI; + gbcfg.core_mcc = 123; + gbcfg.core_mnc = 456; + gbcfg.core_apn = talloc_zero_size(NULL, 100); + gbcfg.core_apn_size = gprs_str_to_apn(gbcfg.core_apn, 100, "foo.bar"); + gbcfg.patch_ptmsi = 1; + gbcfg.bss_ptmsi_state = 0; + gbcfg.sgsn_tlli_state = 1; + + configure_sgsn_peer(&sgsn_peer); + configure_bss_peers(bss_peer, ARRAY_SIZE(bss_peer)); + + printf("=== %s ===\n", __func__); + printf("--- Initialise SGSN ---\n\n"); + + connect_sgsn(nsi, &sgsn_peer); + + printf("--- Initialise BSS 1 ---\n\n"); + + setup_ns(nsi, &bss_peer[0], 0x1001, 0x1000); + setup_bssgp(nsi, &bss_peer[0], 0x1002); + + peer = gbprox_peer_by_nsei(&gbcfg, 0x1000); + OSMO_ASSERT(peer != NULL); + + send_bssgp_reset_ack(nsi, &sgsn_peer, 0x1002); + + send_bssgp_suspend(nsi, &bss_peer[0], &rai_bss); + send_bssgp_suspend_ack(nsi, &sgsn_peer, &rai_sgsn); + + gprs_dump_nsi(nsi); + dump_global(stdout, 0); + dump_peers(stdout, 0, 0, &gbcfg); + + printf("--- Send message from BSS 1 to SGSN, BVCI 0x1002 ---\n\n"); + + send_llc_ul_ui(nsi, "ATTACH REQUEST", &bss_peer[0], 0x1002, + foreign_bss_tlli, &rai_unknown, cell_id, + GPRS_SAPI_GMM, bss_nu++, + dtap_attach_req, sizeof(dtap_attach_req)); + + dump_peers(stdout, 0, 0, &gbcfg); + + send_llc_dl_ui(nsi, "IDENT REQUEST", &sgsn_peer, 0x1002, + random_sgsn_tlli, 0, NULL, 0, + GPRS_SAPI_GMM, sgsn_nu++, + dtap_identity_req, sizeof(dtap_identity_req)); + + dump_peers(stdout, 0, 0, &gbcfg); + + send_llc_ul_ui(nsi, "IDENT RESPONSE", &bss_peer[0], 0x1002, + foreign_bss_tlli, &rai_bss, cell_id, + GPRS_SAPI_GMM, bss_nu++, + dtap_identity_resp, sizeof(dtap_identity_resp)); + + dump_peers(stdout, 0, 0, &gbcfg); + + send_llc_dl_ui(nsi, "ATTACH ACCEPT", &sgsn_peer, 0x1002, + random_sgsn_tlli, 1, imsi, sizeof(imsi), + GPRS_SAPI_GMM, sgsn_nu++, + dtap_attach_acc, sizeof(dtap_attach_acc)); + + dump_peers(stdout, 0, 0, &gbcfg); + + tlli_info = gbprox_find_tlli_by_sgsn_tlli(peer, random_sgsn_tlli); + OSMO_ASSERT(tlli_info); + OSMO_ASSERT(tlli_info->tlli.assigned == local_bss_tlli); + OSMO_ASSERT(tlli_info->tlli.current == foreign_bss_tlli); + OSMO_ASSERT(!tlli_info->tlli.bss_validated); + OSMO_ASSERT(!tlli_info->tlli.net_validated); + OSMO_ASSERT(tlli_info->tlli.ptmsi == bss_ptmsi); + OSMO_ASSERT(tlli_info->sgsn_tlli.assigned == local_sgsn_tlli); + OSMO_ASSERT(tlli_info->sgsn_tlli.current == random_sgsn_tlli); + OSMO_ASSERT(!tlli_info->sgsn_tlli.bss_validated); + OSMO_ASSERT(!tlli_info->sgsn_tlli.net_validated); + OSMO_ASSERT(tlli_info->sgsn_tlli.ptmsi == sgsn_ptmsi); + + send_llc_ul_ui(nsi, "ATTACH COMPLETE", &bss_peer[0], 0x1002, + local_bss_tlli, &rai_bss, cell_id, + GPRS_SAPI_GMM, bss_nu++, + dtap_attach_complete, sizeof(dtap_attach_complete)); + + dump_peers(stdout, 0, 0, &gbcfg); + + tlli_info = gbprox_find_tlli_by_sgsn_tlli(peer, local_sgsn_tlli); + OSMO_ASSERT(tlli_info); + OSMO_ASSERT(tlli_info->tlli.assigned == local_bss_tlli); + OSMO_ASSERT(tlli_info->tlli.current == foreign_bss_tlli); + OSMO_ASSERT(tlli_info->tlli.bss_validated); + OSMO_ASSERT(!tlli_info->tlli.net_validated); + OSMO_ASSERT(tlli_info->sgsn_tlli.assigned == local_sgsn_tlli); + OSMO_ASSERT(tlli_info->sgsn_tlli.current == random_sgsn_tlli); + OSMO_ASSERT(tlli_info->sgsn_tlli.bss_validated); + OSMO_ASSERT(!tlli_info->sgsn_tlli.net_validated); + + send_llc_dl_ui(nsi, "GMM INFO", &sgsn_peer, 0x1002, + local_sgsn_tlli, 1, imsi, sizeof(imsi), + GPRS_SAPI_GMM, sgsn_nu++, + dtap_gmm_information, sizeof(dtap_gmm_information)); + + dump_peers(stdout, 0, 0, &gbcfg); + + tlli_info = gbprox_find_tlli_by_sgsn_tlli(peer, local_sgsn_tlli); + OSMO_ASSERT(tlli_info); + OSMO_ASSERT(tlli_info->tlli.current == local_bss_tlli); + OSMO_ASSERT(tlli_info->tlli.assigned == 0); + OSMO_ASSERT(tlli_info->sgsn_tlli.current == local_sgsn_tlli); + OSMO_ASSERT(tlli_info->sgsn_tlli.assigned == 0); + + /* Non-DTAP */ + send_bssgp_ul_unitdata(nsi, "XID (UL)", &bss_peer[0], 0x1002, + local_bss_tlli, &rai_bss, cell_id, + llc_u_xid_ul, sizeof(llc_u_xid_ul)); + + send_bssgp_dl_unitdata(nsi, "XID (DL)", &sgsn_peer, 0x1002, + local_sgsn_tlli, 1, imsi, sizeof(imsi), + llc_u_xid_dl, sizeof(llc_u_xid_dl)); + + send_bssgp_ul_unitdata(nsi, "LL11 DNS QUERY (UL)", &bss_peer[0], 0x1002, + local_bss_tlli, &rai_bss, cell_id, + llc_ui_ll11_dns_query_ul, + sizeof(llc_ui_ll11_dns_query_ul)); + + send_bssgp_dl_unitdata(nsi, "LL11 DNS RESP (DL)", &sgsn_peer, 0x1002, + local_sgsn_tlli, 1, imsi, sizeof(imsi), + llc_ui_ll11_dns_resp_dl, + sizeof(llc_ui_ll11_dns_resp_dl)); + + dump_peers(stdout, 0, 0, &gbcfg); + + /* Detach */ + send_llc_ul_ui(nsi, "DETACH REQ", &bss_peer[0], 0x1002, + local_bss_tlli, &rai_bss, cell_id, + GPRS_SAPI_GMM, bss_nu++, + dtap_detach_req, sizeof(dtap_detach_req)); + + dump_peers(stdout, 0, 0, &gbcfg); + + send_llc_dl_ui(nsi, "DETACH ACC", &sgsn_peer, 0x1002, + local_sgsn_tlli, 1, imsi, sizeof(imsi), + GPRS_SAPI_GMM, sgsn_nu++, + dtap_detach_acc, sizeof(dtap_detach_acc)); + + dump_peers(stdout, 0, 0, &gbcfg); + dump_global(stdout, 0); + + gbprox_reset(&gbcfg); + gprs_ns_destroy(nsi); + nsi = NULL; +} + /* TODO: Move tlv testing to libosmocore */ int v_fixed_shift(uint8_t **data, size_t *data_len, size_t len, uint8_t **value); int tv_fixed_match(uint8_t **data, size_t *data_len, uint8_t tag, size_t len, @@ -1899,6 +2136,7 @@ int main(int argc, char **argv) test_gbproxy_ident_changes(); test_gbproxy_imsi_matching(); test_gbproxy_ra_patching(); + test_gbproxy_ptmsi_patching(); test_gbproxy_tlli_expire(); printf("===== GbProxy test END\n\n"); diff --git a/openbsc/tests/gbproxy/gbproxy_test.ok b/openbsc/tests/gbproxy/gbproxy_test.ok index b9919060e..4dd4e7e5d 100644 --- a/openbsc/tests/gbproxy/gbproxy_test.ok +++ b/openbsc/tests/gbproxy/gbproxy_test.ok @@ -1884,6 +1884,384 @@ Peers: TLLI cache size : 1 TLLI-Cache: 1 TLLI efe2b700 -> efe2b700, IMSI (none), AGE 0 +=== test_gbproxy_ptmsi_patching === +--- Initialise SGSN --- + +MESSAGE to SGSN at 0x05060708:32000, 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 at 0x05060708:32000, msg length 1 +0a + +result (RESET_ACK) = 1 + +PROCESSING ALIVE_ACK from 0x05060708:32000 +0b + +MESSAGE to SGSN at 0x05060708:32000, 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 + +PROCESSING ALIVE from 0x05060708:32000 +0a + +MESSAGE to SGSN at 0x05060708:32000, msg length 1 +0b + +result (ALIVE) = 1 + +--- Initialise BSS 1 --- + +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 at 0x01020304:1111, msg length 9 +03 01 82 10 01 04 82 10 00 + +MESSAGE to BSS at 0x01020304:1111, msg length 1 +0a + +result (RESET) = 9 + +PROCESSING ALIVE from 0x01020304:1111 +0a + +MESSAGE to BSS at 0x01020304:1111, 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 at 0x01020304:1111, msg length 1 +07 + +result (UNBLOCK) = 1 + +PROCESSING ALIVE_ACK from 0x01020304:1111 +0b + +result (ALIVE_ACK) = 0 + +Setup BSSGP: remote 0x01020304:1111, BVCI 0x1002(4098) + +PROCESSING BVC_RESET from 0x01020304:1111 +00 00 00 00 22 04 82 10 02 07 81 08 08 88 11 22 33 40 50 60 10 00 + +CALLBACK, event 0, msg length 18, bvci 0x0000 +00 00 00 00 22 04 82 10 02 07 81 08 08 88 11 22 33 40 50 60 10 00 + +NS UNITDATA MESSAGE to SGSN, BVCI 0x0000, msg length 18 (gprs_ns_sendmsg) +MESSAGE to SGSN at 0x05060708:32000, msg length 22 +00 00 00 00 22 04 82 10 02 07 81 08 08 88 21 63 54 40 50 60 10 00 + +result (BVC_RESET) = 22 + +PROCESSING BVC_RESET_ACK from 0x05060708:32000 +00 00 00 00 23 04 82 10 02 + +CALLBACK, event 0, msg length 5, bvci 0x0000 +00 00 00 00 23 04 82 10 02 + +NS UNITDATA MESSAGE to BSS, BVCI 0x0000, msg length 5 (gprs_ns_sendmsg) +MESSAGE to BSS at 0x01020304:1111, msg length 9 +00 00 00 00 23 04 82 10 02 + +result (BVC_RESET_ACK) = 9 + +PROCESSING BVC_SUSPEND from 0x01020304:1111 +00 00 00 00 0b 1f 84 cc d1 75 8b 1b 86 11 22 33 40 50 60 + +CALLBACK, event 0, msg length 15, bvci 0x0000 +00 00 00 00 0b 1f 84 cc d1 75 8b 1b 86 11 22 33 40 50 60 + +NS UNITDATA MESSAGE to SGSN, BVCI 0x0000, msg length 15 (gprs_ns_sendmsg) +MESSAGE to SGSN at 0x05060708:32000, msg length 19 +00 00 00 00 0b 1f 84 cc d1 75 8b 1b 86 21 63 54 40 50 60 + +result (BVC_SUSPEND) = 19 + +PROCESSING BVC_SUSPEND_ACK from 0x05060708:32000 +00 00 00 00 0c 1f 84 cc d1 75 8b 1b 86 21 63 54 40 50 60 1d 81 01 + +CALLBACK, event 0, msg length 18, bvci 0x0000 +00 00 00 00 0c 1f 84 cc d1 75 8b 1b 86 21 63 54 40 50 60 1d 81 01 + +NS UNITDATA MESSAGE to BSS, BVCI 0x0000, msg length 18 (gprs_ns_sendmsg) +MESSAGE to BSS at 0x01020304:1111, msg length 22 +00 00 00 00 0c 1f 84 cc d1 75 8b 1b 86 11 22 33 40 50 60 1d 81 01 + +result (BVC_SUSPEND_ACK) = 22 + +Current NS-VCIs: + VCI 0x1001, NSEI 0x1000, peer 0x01020304:1111 + VCI 0x0101, NSEI 0x0100, peer 0x05060708:32000 + NS-VC Block count : 1 + +Gbproxy global: +Peers: + NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 + RAID patched (BSS ): 2 + RAID patched (SGSN): 1 + TLLI-Cache: 0 +--- Send message from BSS 1 to SGSN, BVCI 0x1002 --- + +PROCESSING ATTACH REQUEST from 0x01020304:1111 +00 00 10 02 01 80 00 de ad 00 00 04 08 88 00 f1 99 00 63 60 12 34 00 80 0e 00 34 01 c0 01 08 01 02 f5 e0 21 08 02 05 f4 fb c5 46 79 11 22 33 40 50 60 19 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 16 6d 01 + +CALLBACK, event 0, msg length 75, bvci 0x1002 +00 00 10 02 01 80 00 de ad 00 00 04 08 88 00 f1 99 00 63 60 12 34 00 80 0e 00 34 01 c0 01 08 01 02 f5 e0 21 08 02 05 f4 fb c5 46 79 11 22 33 40 50 60 19 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 16 6d 01 + +NS UNITDATA MESSAGE to SGSN, BVCI 0x1002, msg length 75 (gprs_ns_sendmsg) +MESSAGE to SGSN at 0x05060708:32000, msg length 79 +00 00 10 02 01 7c 69 fb 81 00 00 04 08 88 21 63 54 00 63 60 12 34 00 80 0e 00 34 01 c0 01 08 01 02 f5 e0 21 08 02 05 f4 fb c5 46 79 11 22 33 40 50 60 19 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 16 6d 01 + +result (ATTACH REQUEST) = 79 + +Peers: + NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 + RAID patched (BSS ): 3 + RAID patched (SGSN): 1 + TLLI patched (BSS ): 1 + Attach Request count : 1 + TLLI cache size : 1 + TLLI-Cache: 1 + TLLI 8000dead -> 7c69fb81, IMSI (none), AGE 0 +PROCESSING IDENT REQUEST from 0x05060708:32000 +00 00 10 02 00 7c 69 fb 81 00 50 20 16 82 02 58 0e 89 41 c0 01 08 15 01 ff 6c ba + +CALLBACK, event 0, msg length 23, bvci 0x1002 +00 00 10 02 00 7c 69 fb 81 00 50 20 16 82 02 58 0e 89 41 c0 01 08 15 01 ff 6c ba + +NS UNITDATA MESSAGE to BSS, BVCI 0x1002, msg length 23 (gprs_ns_sendmsg) +MESSAGE to BSS at 0x01020304:1111, msg length 27 +00 00 10 02 00 80 00 de ad 00 50 20 16 82 02 58 0e 89 41 c0 01 08 15 01 ff 6c ba + +result (IDENT REQUEST) = 27 + +Peers: + NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 + RAID patched (BSS ): 3 + RAID patched (SGSN): 1 + TLLI patched (BSS ): 1 + TLLI patched (SGSN): 1 + Attach Request count : 1 + TLLI cache size : 1 + TLLI-Cache: 1 + TLLI 8000dead -> 7c69fb81, IMSI (none), AGE 0 +PROCESSING IDENT RESPONSE from 0x01020304:1111 +00 00 10 02 01 80 00 de ad 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 11 01 c0 05 08 16 08 11 12 13 14 15 16 17 18 ad 05 28 + +CALLBACK, event 0, msg length 40, bvci 0x1002 +00 00 10 02 01 80 00 de ad 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 11 01 c0 05 08 16 08 11 12 13 14 15 16 17 18 ad 05 28 + +NS UNITDATA MESSAGE to SGSN, BVCI 0x1002, msg length 40 (gprs_ns_sendmsg) +MESSAGE to SGSN at 0x05060708:32000, msg length 44 +00 00 10 02 01 7c 69 fb 81 00 00 04 08 88 21 63 54 40 50 60 12 34 00 80 0e 00 11 01 c0 05 08 16 08 11 12 13 14 15 16 17 18 ad 05 28 + +result (IDENT RESPONSE) = 44 + +Peers: + NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 + RAID patched (BSS ): 4 + RAID patched (SGSN): 1 + TLLI patched (BSS ): 2 + TLLI patched (SGSN): 1 + Attach Request count : 1 + TLLI cache size : 1 + TLLI-Cache: 1 + TLLI 8000dead -> 7c69fb81, IMSI 12131415161718, AGE 0 +PROCESSING ATTACH ACCEPT from 0x05060708:32000 +00 00 10 02 00 7c 69 fb 81 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 9e 41 c0 05 08 02 01 49 04 21 63 54 40 50 60 19 cd d7 08 17 16 18 05 f4 ef e2 b7 00 53 62 f1 + +CALLBACK, event 0, msg length 88, bvci 0x1002 +00 00 10 02 00 7c 69 fb 81 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 9e 41 c0 05 08 02 01 49 04 21 63 54 40 50 60 19 cd d7 08 17 16 18 05 f4 ef e2 b7 00 53 62 f1 + +NS UNITDATA MESSAGE to BSS, BVCI 0x1002, msg length 88 (gprs_ns_sendmsg) +MESSAGE to BSS at 0x01020304:1111, msg length 92 +00 00 10 02 00 80 00 de ad 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 9e 41 c0 05 08 02 01 49 04 11 22 33 40 50 60 19 cd d7 08 17 16 18 05 f4 c0 0f 73 04 50 22 97 + +result (ATTACH ACCEPT) = 92 + +Peers: + NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 + RAID patched (BSS ): 4 + RAID patched (SGSN): 2 + TLLI patched (BSS ): 2 + TLLI patched (SGSN): 2 + P-TMSI patched (SGSN): 1 + Attach Request count : 1 + TLLI cache size : 1 + TLLI-Cache: 1 + TLLI 8000dead/c00f7304 -> 7c69fb81/efe2b700, IMSI 12131415161718, AGE 0 +PROCESSING ATTACH COMPLETE from 0x01020304:1111 +00 00 10 02 01 c0 0f 73 04 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 08 01 c0 09 08 03 39 d7 bc + +CALLBACK, event 0, msg length 31, bvci 0x1002 +00 00 10 02 01 c0 0f 73 04 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 08 01 c0 09 08 03 39 d7 bc + +NS UNITDATA MESSAGE to SGSN, BVCI 0x1002, msg length 31 (gprs_ns_sendmsg) +MESSAGE to SGSN at 0x05060708:32000, msg length 35 +00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 21 63 54 40 50 60 12 34 00 80 0e 00 08 01 c0 09 08 03 39 d7 bc + +result (ATTACH COMPLETE) = 35 + +Peers: + NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 + RAID patched (BSS ): 5 + RAID patched (SGSN): 2 + TLLI patched (BSS ): 3 + TLLI patched (SGSN): 2 + P-TMSI patched (SGSN): 1 + Attach Request count : 1 + TLLI cache size : 1 + TLLI-Cache: 1 + TLLI 8000dead/c00f7304 -> 7c69fb81/efe2b700, IMSI 12131415161718, AGE 0 +PROCESSING GMM INFO from 0x05060708:32000 +00 00 10 02 00 ef e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 88 41 c0 09 08 21 04 ba 3d + +CALLBACK, event 0, msg length 66, bvci 0x1002 +00 00 10 02 00 ef e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 88 41 c0 09 08 21 04 ba 3d + +NS UNITDATA MESSAGE to BSS, BVCI 0x1002, msg length 66 (gprs_ns_sendmsg) +MESSAGE to BSS at 0x01020304:1111, msg length 70 +00 00 10 02 00 c0 0f 73 04 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 88 41 c0 09 08 21 04 ba 3d + +result (GMM INFO) = 70 + +Peers: + NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 + RAID patched (BSS ): 5 + RAID patched (SGSN): 2 + TLLI patched (BSS ): 3 + TLLI patched (SGSN): 3 + P-TMSI patched (SGSN): 1 + Attach Request count : 1 + TLLI cache size : 1 + TLLI-Cache: 1 + TLLI c00f7304 -> efe2b700, IMSI 12131415161718, AGE 0 +PROCESSING XID (UL) from 0x01020304:1111 +00 00 10 02 01 c0 0f 73 04 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 0f 41 fb 01 00 0e 00 64 11 05 16 01 90 66 b3 28 + +CALLBACK, event 0, msg length 38, bvci 0x1002 +00 00 10 02 01 c0 0f 73 04 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 0f 41 fb 01 00 0e 00 64 11 05 16 01 90 66 b3 28 + +NS UNITDATA MESSAGE to SGSN, BVCI 0x1002, msg length 38 (gprs_ns_sendmsg) +MESSAGE to SGSN at 0x05060708:32000, msg length 42 +00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 21 63 54 40 50 60 12 34 00 80 0e 00 0f 41 fb 01 00 0e 00 64 11 05 16 01 90 66 b3 28 + +result (XID (UL)) = 42 + +PROCESSING XID (DL) from 0x05060708:32000 +00 00 10 02 00 ef e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 8c 41 fb 30 84 10 61 b6 64 e4 a9 1a 9e + +CALLBACK, event 0, msg length 70, bvci 0x1002 +00 00 10 02 00 ef e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 8c 41 fb 30 84 10 61 b6 64 e4 a9 1a 9e + +NS UNITDATA MESSAGE to BSS, BVCI 0x1002, msg length 70 (gprs_ns_sendmsg) +MESSAGE to BSS at 0x01020304:1111, msg length 74 +00 00 10 02 00 c0 0f 73 04 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 8c 41 fb 30 84 10 61 b6 64 e4 a9 1a 9e + +result (XID (DL)) = 74 + +PROCESSING LL11 DNS QUERY (UL) from 0x01020304:1111 +00 00 10 02 01 c0 0f 73 04 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 42 0b c0 01 65 00 00 00 45 00 00 38 95 72 00 00 45 11 20 85 0a c0 07 e4 ac 10 01 0a ad ab 00 35 00 24 0e 1c 3b e0 01 00 00 01 00 00 00 00 00 00 01 6d 05 68 65 69 73 65 02 64 65 00 00 01 00 01 47 8f 07 + +CALLBACK, event 0, msg length 89, bvci 0x1002 +00 00 10 02 01 c0 0f 73 04 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 42 0b c0 01 65 00 00 00 45 00 00 38 95 72 00 00 45 11 20 85 0a c0 07 e4 ac 10 01 0a ad ab 00 35 00 24 0e 1c 3b e0 01 00 00 01 00 00 00 00 00 00 01 6d 05 68 65 69 73 65 02 64 65 00 00 01 00 01 47 8f 07 + +NS UNITDATA MESSAGE to SGSN, BVCI 0x1002, msg length 89 (gprs_ns_sendmsg) +MESSAGE to SGSN at 0x05060708:32000, msg length 93 +00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 21 63 54 40 50 60 12 34 00 80 0e 00 42 0b c0 01 65 00 00 00 45 00 00 38 95 72 00 00 45 11 20 85 0a c0 07 e4 ac 10 01 0a ad ab 00 35 00 24 0e 1c 3b e0 01 00 00 01 00 00 00 00 00 00 01 6d 05 68 65 69 73 65 02 64 65 00 00 01 00 01 47 8f 07 + +result (LL11 DNS QUERY (UL)) = 93 + +PROCESSING LL11 DNS RESP (DL) from 0x05060708:32000 +00 00 10 02 00 ef e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 00 d0 4b c0 01 65 00 00 00 45 00 00 c6 00 00 40 00 3e 11 7c 69 ac 10 01 0a 0a c0 07 e4 00 35 ad ab 00 b2 74 4e 3b e0 81 80 00 01 00 01 00 05 00 00 01 6d 05 68 65 69 73 65 02 64 65 00 00 01 00 01 c0 0c 00 01 00 01 00 00 0e 10 00 04 c1 63 90 58 c0 0e 00 02 00 01 00 00 0e 10 00 16 03 6e 73 32 0c 70 6f 70 2d 68 61 6e 6e 6f 76 65 72 03 6e 65 74 00 c0 0e 00 02 00 01 00 00 0e 10 00 10 02 6e 73 01 73 08 70 6c 75 73 6c 69 6e 65 c0 14 c0 0e 00 02 00 01 00 00 0e 10 00 05 02 6e 73 c0 0e c0 0e 00 02 00 01 00 00 0e 10 00 05 02 6e 73 c0 5f c0 0e 00 02 00 01 00 00 0e 10 00 12 02 6e 73 0c 70 6f 70 2d 68 61 6e 6e 6f 76 65 72 c0 14 aa df 31 + +CALLBACK, event 0, msg length 267, bvci 0x1002 +00 00 10 02 00 ef e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 00 d0 4b c0 01 65 00 00 00 45 00 00 c6 00 00 40 00 3e 11 7c 69 ac 10 01 0a 0a c0 07 e4 00 35 ad ab 00 b2 74 4e 3b e0 81 80 00 01 00 01 00 05 00 00 01 6d 05 68 65 69 73 65 02 64 65 00 00 01 00 01 c0 0c 00 01 00 01 00 00 0e 10 00 04 c1 63 90 58 c0 0e 00 02 00 01 00 00 0e 10 00 16 03 6e 73 32 0c 70 6f 70 2d 68 61 6e 6e 6f 76 65 72 03 6e 65 74 00 c0 0e 00 02 00 01 00 00 0e 10 00 10 02 6e 73 01 73 08 70 6c 75 73 6c 69 6e 65 c0 14 c0 0e 00 02 00 01 00 00 0e 10 00 05 02 6e 73 c0 0e c0 0e 00 02 00 01 00 00 0e 10 00 05 02 6e 73 c0 5f c0 0e 00 02 00 01 00 00 0e 10 00 12 02 6e 73 0c 70 6f 70 2d 68 61 6e 6e 6f 76 65 72 c0 14 aa df 31 + +NS UNITDATA MESSAGE to BSS, BVCI 0x1002, msg length 267 (gprs_ns_sendmsg) +MESSAGE to BSS at 0x01020304:1111, msg length 271 +00 00 10 02 00 c0 0f 73 04 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 00 d0 4b c0 01 65 00 00 00 45 00 00 c6 00 00 40 00 3e 11 7c 69 ac 10 01 0a 0a c0 07 e4 00 35 ad ab 00 b2 74 4e 3b e0 81 80 00 01 00 01 00 05 00 00 01 6d 05 68 65 69 73 65 02 64 65 00 00 01 00 01 c0 0c 00 01 00 01 00 00 0e 10 00 04 c1 63 90 58 c0 0e 00 02 00 01 00 00 0e 10 00 16 03 6e 73 32 0c 70 6f 70 2d 68 61 6e 6e 6f 76 65 72 03 6e 65 74 00 c0 0e 00 02 00 01 00 00 0e 10 00 10 02 6e 73 01 73 08 70 6c 75 73 6c 69 6e 65 c0 14 c0 0e 00 02 00 01 00 00 0e 10 00 05 02 6e 73 c0 0e c0 0e 00 02 00 01 00 00 0e 10 00 05 02 6e 73 c0 5f c0 0e 00 02 00 01 00 00 0e 10 00 12 02 6e 73 0c 70 6f 70 2d 68 61 6e 6e 6f 76 65 72 c0 14 aa df 31 + +result (LL11 DNS RESP (DL)) = 271 + +Peers: + NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 + RAID patched (BSS ): 7 + RAID patched (SGSN): 2 + TLLI patched (BSS ): 5 + TLLI patched (SGSN): 5 + P-TMSI patched (SGSN): 1 + Attach Request count : 1 + TLLI cache size : 1 + TLLI-Cache: 1 + TLLI c00f7304 -> efe2b700, IMSI 12131415161718, AGE 0 +PROCESSING DETACH REQ from 0x01020304:1111 +00 00 10 02 01 c0 0f 73 04 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 15 01 c0 0d 08 05 01 18 05 f4 ef e2 b7 00 19 03 b9 97 cb 37 67 c6 + +CALLBACK, event 0, msg length 44, bvci 0x1002 +00 00 10 02 01 c0 0f 73 04 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 15 01 c0 0d 08 05 01 18 05 f4 ef e2 b7 00 19 03 b9 97 cb 37 67 c6 + +NS UNITDATA MESSAGE to SGSN, BVCI 0x1002, msg length 44 (gprs_ns_sendmsg) +MESSAGE to SGSN at 0x05060708:32000, msg length 48 +00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 21 63 54 40 50 60 12 34 00 80 0e 00 15 01 c0 0d 08 05 01 18 05 f4 ef e2 b7 00 19 03 b9 97 cb 37 67 c6 + +result (DETACH REQ) = 48 + +Peers: + NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 + RAID patched (BSS ): 8 + RAID patched (SGSN): 2 + TLLI patched (BSS ): 6 + TLLI patched (SGSN): 5 + P-TMSI patched (SGSN): 1 + Attach Request count : 1 + TLLI cache size : 1 + TLLI-Cache: 1 + TLLI c00f7304 -> efe2b700, IMSI 12131415161718, AGE 0 +PROCESSING DETACH ACC from 0x05060708:32000 +00 00 10 02 00 ef e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 89 41 c0 0d 08 06 00 aa ab ee + +CALLBACK, event 0, msg length 67, bvci 0x1002 +00 00 10 02 00 ef e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 89 41 c0 0d 08 06 00 aa ab ee + +NS UNITDATA MESSAGE to BSS, BVCI 0x1002, msg length 67 (gprs_ns_sendmsg) +MESSAGE to BSS at 0x01020304:1111, msg length 71 +00 00 10 02 00 c0 0f 73 04 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 89 41 c0 0d 08 06 00 aa ab ee + +result (DETACH ACC) = 71 + +Peers: + NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 + RAID patched (BSS ): 8 + RAID patched (SGSN): 2 + TLLI patched (BSS ): 6 + TLLI patched (SGSN): 6 + P-TMSI patched (SGSN): 1 + Attach Request count : 1 + TLLI-Cache: 0 +Gbproxy global: Test TLLI info expiry Test TLLI replacement: -- cgit v1.2.3 From 9114bee2424fa5a5e30261054573f9f78b5c5477 Mon Sep 17 00:00:00 2001 From: Jacob Erlbeck Date: Tue, 19 Aug 2014 12:21:01 +0200 Subject: gbproxy: Refactor gb_proxy.c into several files This patch moves several functions and declarations out of gb_proxy.c to make them reusable by other components and to separate them by context and task. Counter enums (prefix is changed to gbproxy_): enum gbprox_global_ctr -> gprs/gb_proxy.h enum gbprox_peer_ctr -> gprs/gb_proxy.h Generic Gb parsing (prefix is changed to gprs_gb_): struct gbproxy_parse_context -> openbsc/gprs_gb_parse.h gbprox_parse_dtap() -> gprs/gprs_gb_parse.c gbprox_parse_llc() -> gprs/gprs_gb_parse.c gbprox_parse_bssgp() -> gprs/gprs_gb_parse.c gbprox_log_parse_context() -> gprs/gprs_gb_parse.c *_shift(), *_match() -> gprs/gprs_gb_parse.c (no prefix) gbprox_parse_gmm_* -> gprs/gprs_gb_parse.c (static) gbprox_parse_gsm_* -> gprs/gprs_gb_parse.c (static) MI testing/parsing (prefix gprs_ added): is_mi_tmsi() -> gprs/gprs_utils.c is_mi_imsi() -> gprs/gprs_utils.c parse_mi_tmsi() -> gprs/gprs_utils.c TLLI state handling (prefix is changed to gbproxy_): gbprox_*tlli* -> gprs/gb_proxy_tlli.c (except gbprox_patch_tlli, gbproxy_make_sgsn_tlli) Message patching (prefix is changed to gbproxy_): gbprox_*patch* -> gprs/gb_proxy_patch.c gbprox_check_imsi -> gprs/gb_proxy_patch.c Sponsored-by: On-Waves ehf --- openbsc/include/openbsc/gb_proxy.h | 118 +- openbsc/include/openbsc/gprs_gb_parse.h | 52 + openbsc/include/openbsc/gprs_utils.h | 3 + openbsc/src/gprs/Makefile.am | 3 +- openbsc/src/gprs/gb_proxy.c | 2072 +++---------------------------- openbsc/src/gprs/gb_proxy_patch.c | 475 +++++++ openbsc/src/gprs/gb_proxy_tlli.c | 544 ++++++++ openbsc/src/gprs/gb_proxy_vty.c | 10 +- openbsc/src/gprs/gprs_gb_parse.c | 642 ++++++++++ openbsc/src/gprs/gprs_utils.c | 39 + openbsc/tests/gbproxy/Makefile.am | 3 + openbsc/tests/gbproxy/gbproxy_test.c | 126 +- 12 files changed, 2119 insertions(+), 1968 deletions(-) create mode 100644 openbsc/include/openbsc/gprs_gb_parse.h create mode 100644 openbsc/src/gprs/gb_proxy_patch.c create mode 100644 openbsc/src/gprs/gb_proxy_tlli.c create mode 100644 openbsc/src/gprs/gprs_gb_parse.c diff --git a/openbsc/include/openbsc/gb_proxy.h b/openbsc/include/openbsc/gb_proxy.h index e7d1b1cbe..345a317e8 100644 --- a/openbsc/include/openbsc/gb_proxy.h +++ b/openbsc/include/openbsc/gb_proxy.h @@ -11,6 +11,7 @@ #include struct rate_ctr_group; +struct gprs_gb_parse_context; enum gbproxy_patch_mode { GBPROX_PATCH_DEFAULT, @@ -22,6 +23,42 @@ enum gbproxy_patch_mode { GBPROX_PATCH_LLC, /*!< BSSGP and all supported LLC msgs */ }; +enum gbproxy_global_ctr { + GBPROX_GLOB_CTR_INV_BVCI, + GBPROX_GLOB_CTR_INV_LAI, + GBPROX_GLOB_CTR_INV_RAI, + GBPROX_GLOB_CTR_INV_NSEI, + GBPROX_GLOB_CTR_PROTO_ERR_BSS, + GBPROX_GLOB_CTR_PROTO_ERR_SGSN, + GBPROX_GLOB_CTR_NOT_SUPPORTED_BSS, + GBPROX_GLOB_CTR_NOT_SUPPORTED_SGSN, + GBPROX_GLOB_CTR_RESTART_RESET_SGSN, + GBPROX_GLOB_CTR_TX_ERR_SGSN, + GBPROX_GLOB_CTR_OTHER_ERR, + GBPROX_GLOB_CTR_PATCH_PEER_ERR, +}; + +enum gbproxy_peer_ctr { + GBPROX_PEER_CTR_BLOCKED, + GBPROX_PEER_CTR_UNBLOCKED, + GBPROX_PEER_CTR_DROPPED, + GBPROX_PEER_CTR_INV_NSEI, + GBPROX_PEER_CTR_TX_ERR, + GBPROX_PEER_CTR_RAID_PATCHED_BSS, + GBPROX_PEER_CTR_RAID_PATCHED_SGSN, + GBPROX_PEER_CTR_APN_PATCHED, + GBPROX_PEER_CTR_TLLI_PATCHED_BSS, + GBPROX_PEER_CTR_TLLI_PATCHED_SGSN, + GBPROX_PEER_CTR_PTMSI_PATCHED_BSS, + GBPROX_PEER_CTR_PTMSI_PATCHED_SGSN, + GBPROX_PEER_CTR_PATCH_CRYPT_ERR, + GBPROX_PEER_CTR_PATCH_ERR, + GBPROX_PEER_CTR_ATTACH_REQS, + GBPROX_PEER_CTR_ATTACH_REJS, + GBPROX_PEER_CTR_TLLI_UNKNOWN, + GBPROX_PEER_CTR_TLLI_CACHE_SIZE, +}; + struct gbproxy_config { /* parsed from config file */ uint16_t nsip_sgsn_nsei; @@ -130,31 +167,74 @@ int gbprox_reset_persistent_nsvcs(struct gprs_ns_inst *nsi); void gbprox_reset(struct gbproxy_config *cfg); -int gbprox_set_patch_filter(struct gbproxy_config *cfg, const char *filter, - const char **err_msg); -void gbprox_clear_patch_filter(struct gbproxy_config *cfg); - -void gbprox_delete_tlli(struct gbproxy_peer *peer, - struct gbproxy_tlli_info *tlli_info); -int gbprox_remove_stale_tllis(struct gbproxy_peer *peer, time_t now); int gbprox_cleanup_peers(struct gbproxy_config *cfg, uint16_t nsei, uint16_t bvci); struct gbproxy_peer *gbprox_peer_by_nsei(struct gbproxy_config *cfg, uint16_t nsei); -struct gbproxy_tlli_info *gbprox_find_tlli(struct gbproxy_peer *peer, - uint32_t tlli); -struct gbproxy_tlli_info *gbprox_find_tlli_by_mi(struct gbproxy_peer *peer, - const uint8_t *mi_data, - size_t mi_data_len); -struct gbproxy_tlli_info *gbprox_find_tlli_by_sgsn_tlli( +struct gbproxy_peer *gbproxy_peer_alloc(struct gbproxy_config *cfg, uint16_t bvci); +void gbproxy_peer_free(struct gbproxy_peer *peer); + +/* TLLI state handling */ +void gbproxy_delete_tllis(struct gbproxy_peer *peer); +int gbproxy_check_tlli(struct gbproxy_peer *peer, uint32_t tlli); +struct gbproxy_tlli_info *gbprox_find_tlli_by_ptmsi( struct gbproxy_peer *peer, - uint32_t tlli); -struct gbproxy_tlli_info *gbprox_register_tlli( + uint32_t ptmsi); +uint32_t gbproxy_map_tlli( + uint32_t other_tlli, struct gbproxy_tlli_info *tlli_info, int to_bss); +struct gbproxy_tlli_info *gbproxy_update_tlli_state_ul( + struct gbproxy_peer *peer, time_t now, + struct gprs_gb_parse_context *parse_ctx); +struct gbproxy_tlli_info *gbproxy_update_tlli_state_dl( + struct gbproxy_peer *peer, time_t now, + struct gprs_gb_parse_context *parse_ctx); +void gbproxy_update_tlli_state_after( + struct gbproxy_peer *peer, struct gbproxy_tlli_info *tlli_info, + time_t now, struct gprs_gb_parse_context *parse_ctx); +int gbproxy_remove_stale_tllis(struct gbproxy_peer *peer, time_t now); +void gbproxy_delete_tlli(struct gbproxy_peer *peer, + struct gbproxy_tlli_info *tlli_info); + +struct gbproxy_tlli_info *gbproxy_register_tlli( struct gbproxy_peer *peer, uint32_t tlli, const uint8_t *imsi, size_t imsi_len, time_t now); -struct gbproxy_peer *gbproxy_peer_alloc(struct gbproxy_config *cfg, uint16_t bvci); -void gbproxy_peer_free(struct gbproxy_peer *peer); -int gbprox_check_imsi(struct gbproxy_peer *peer, - const uint8_t *imsi, size_t imsi_len); +struct gbproxy_tlli_info *gbproxy_find_tlli( + struct gbproxy_peer *peer, uint32_t tlli); +struct gbproxy_tlli_info *gbproxy_find_tlli_by_mi( + struct gbproxy_peer *peer, const uint8_t *mi_data, size_t mi_data_len); +struct gbproxy_tlli_info *gbproxy_find_tlli_by_sgsn_tlli( + struct gbproxy_peer *peer, + uint32_t tlli); +struct gbproxy_tlli_info *gbproxy_find_tlli_by_ptmsi( + struct gbproxy_peer *peer, + uint32_t ptmsi); + +/* needed by gb_proxy_tlli.h */ +uint32_t gbproxy_make_bss_ptmsi(struct gbproxy_peer *peer, uint32_t sgsn_ptmsi); +uint32_t gbproxy_make_sgsn_tlli( + struct gbproxy_peer *peer, struct gbproxy_tlli_info *tlli_info, + uint32_t bss_tlli); +int gbproxy_check_imsi( + struct gbproxy_peer *peer, const uint8_t *imsi, size_t imsi_len); + +/* Message patching */ +void gbproxy_patch_bssgp( + struct msgb *msg, uint8_t *bssgp, size_t bssgp_len, + struct gbproxy_peer *peer, struct gbproxy_tlli_info *tlli_info, + int *len_change, struct gprs_gb_parse_context *parse_ctx) + __attribute__((nonnull)); + +int gbproxy_patch_llc( + struct msgb *msg, uint8_t *llc, size_t llc_len, + struct gbproxy_peer *peer, struct gbproxy_tlli_info *tlli_info, + int *len_change, struct gprs_gb_parse_context *parse_ctx) + __attribute__((nonnull)); + +int gbproxy_set_patch_filter( + struct gbproxy_config *cfg, const char *filter, const char **err_msg); +void gbproxy_clear_patch_filter(struct gbproxy_config *cfg); +int gbproxy_check_imsi( + struct gbproxy_peer *peer, const uint8_t *imsi, size_t imsi_len); + #endif diff --git a/openbsc/include/openbsc/gprs_gb_parse.h b/openbsc/include/openbsc/gprs_gb_parse.h new file mode 100644 index 000000000..e5ef4ef43 --- /dev/null +++ b/openbsc/include/openbsc/gprs_gb_parse.h @@ -0,0 +1,52 @@ +#pragma once + +#include + +#include + +struct gprs_gb_parse_context { + /* Pointer to protocol specific parts */ + struct gsm48_hdr *g48_hdr; + struct bssgp_normal_hdr *bgp_hdr; + struct bssgp_ud_hdr *bud_hdr; + uint8_t *bssgp_data; + size_t bssgp_data_len; + uint8_t *llc; + size_t llc_len; + + /* Extracted information */ + struct gprs_llc_hdr_parsed llc_hdr_parsed; + struct tlv_parsed bssgp_tp; + int to_bss; + uint8_t *tlli_enc; + uint8_t *imsi; + size_t imsi_len; + uint8_t *apn_ie; + size_t apn_ie_len; + uint8_t *ptmsi_enc; + uint8_t *new_ptmsi_enc; + uint8_t *raid_enc; + uint8_t *old_raid_enc; + uint8_t *bssgp_raid_enc; + uint8_t *bssgp_ptimsi; + + /* General info */ + const char *llc_msg_name; + int invalidate_tlli; + int need_decryption; + uint32_t tlli; + int pdu_type; + int old_raid_matches; +}; + +int gprs_gb_parse_dtap(uint8_t *data, size_t data_len, + struct gprs_gb_parse_context *parse_ctx) __attribute__((nonnull)); + +int gprs_gb_parse_llc(uint8_t *llc, size_t llc_len, + struct gprs_gb_parse_context *parse_ctx) __attribute__((nonnull)); + +int gprs_gb_parse_bssgp(uint8_t *bssgp, size_t bssgp_len, + struct gprs_gb_parse_context *parse_ctx) __attribute__((nonnull)); + +void gprs_gb_log_parse_context(struct gprs_gb_parse_context *parse_ctx, + const char *default_msg_name) __attribute__((nonnull(1))); diff --git a/openbsc/include/openbsc/gprs_utils.h b/openbsc/include/openbsc/gprs_utils.h index 2ad5fe490..e610fdec9 100644 --- a/openbsc/include/openbsc/gprs_utils.h +++ b/openbsc/include/openbsc/gprs_utils.h @@ -31,3 +31,6 @@ int gprs_msgb_resize_area(struct msgb *msg, uint8_t *area, size_t old_size, size_t new_size); char *gprs_apn_to_str(char *out_str, const uint8_t *apn_enc, size_t rest_chars); int gprs_str_to_apn(uint8_t *apn_enc, size_t max_len, const char *str); +int gprs_is_mi_tmsi(const uint8_t *value, size_t value_len); +int gprs_is_mi_imsi(const uint8_t *value, size_t value_len); +int gprs_parse_mi_tmsi(const uint8_t *value, size_t value_len, uint32_t *tmsi); diff --git a/openbsc/src/gprs/Makefile.am b/openbsc/src/gprs/Makefile.am index bad38c8fc..4d0c9cdb2 100644 --- a/openbsc/src/gprs/Makefile.am +++ b/openbsc/src/gprs/Makefile.am @@ -14,7 +14,8 @@ bin_PROGRAMS = osmo-gbproxy endif osmo_gbproxy_SOURCES = gb_proxy.c gb_proxy_main.c gb_proxy_vty.c \ - gprs_llc_parse.c crc24.c gprs_utils.c + gb_proxy_patch.c gb_proxy_tlli.c \ + gprs_gb_parse.c gprs_llc_parse.c crc24.c gprs_utils.c osmo_gbproxy_LDADD = $(top_builddir)/src/libcommon/libcommon.a \ $(OSMO_LIBS) diff --git a/openbsc/src/gprs/gb_proxy.c b/openbsc/src/gprs/gb_proxy.c index 86ae0e821..7a1508ee7 100644 --- a/openbsc/src/gprs/gb_proxy.c +++ b/openbsc/src/gprs/gb_proxy.c @@ -42,6 +42,7 @@ #include #include +#include #include #include @@ -49,21 +50,6 @@ #include #include -enum gbprox_global_ctr { - GBPROX_GLOB_CTR_INV_BVCI, - GBPROX_GLOB_CTR_INV_LAI, - GBPROX_GLOB_CTR_INV_RAI, - GBPROX_GLOB_CTR_INV_NSEI, - GBPROX_GLOB_CTR_PROTO_ERR_BSS, - GBPROX_GLOB_CTR_PROTO_ERR_SGSN, - GBPROX_GLOB_CTR_NOT_SUPPORTED_BSS, - GBPROX_GLOB_CTR_NOT_SUPPORTED_SGSN, - GBPROX_GLOB_CTR_RESTART_RESET_SGSN, - GBPROX_GLOB_CTR_TX_ERR_SGSN, - GBPROX_GLOB_CTR_OTHER_ERR, - GBPROX_GLOB_CTR_PATCH_PEER_ERR, -}; - static const struct rate_ctr_desc global_ctr_description[] = { { "inv-bvci", "Invalid BVC Identifier " }, { "inv-lai", "Invalid Location Area Identifier" }, @@ -86,27 +72,6 @@ static const struct rate_ctr_group_desc global_ctrg_desc = { .ctr_desc = global_ctr_description, }; -enum gbprox_peer_ctr { - GBPROX_PEER_CTR_BLOCKED, - GBPROX_PEER_CTR_UNBLOCKED, - GBPROX_PEER_CTR_DROPPED, - GBPROX_PEER_CTR_INV_NSEI, - GBPROX_PEER_CTR_TX_ERR, - GBPROX_PEER_CTR_RAID_PATCHED_BSS, - GBPROX_PEER_CTR_RAID_PATCHED_SGSN, - GBPROX_PEER_CTR_APN_PATCHED, - GBPROX_PEER_CTR_TLLI_PATCHED_BSS, - GBPROX_PEER_CTR_TLLI_PATCHED_SGSN, - GBPROX_PEER_CTR_PTMSI_PATCHED_BSS, - GBPROX_PEER_CTR_PTMSI_PATCHED_SGSN, - GBPROX_PEER_CTR_PATCH_CRYPT_ERR, - GBPROX_PEER_CTR_PATCH_ERR, - GBPROX_PEER_CTR_ATTACH_REQS, - GBPROX_PEER_CTR_ATTACH_REJS, - GBPROX_PEER_CTR_TLLI_UNKNOWN, - GBPROX_PEER_CTR_TLLI_CACHE_SIZE, -}; - static const struct rate_ctr_desc peer_ctr_description[] = { { "blocked", "BVC Block " }, { "unblocked", "BVC Unblock " }, @@ -135,7 +100,6 @@ static const struct rate_ctr_group_desc peer_ctrg_desc = { .ctr_desc = peer_ctr_description, }; -static void gbprox_delete_tllis(struct gbproxy_peer *peer); /* Find the gbprox_peer by its BVCI */ static struct gbproxy_peer *peer_by_bvci(struct gbproxy_config *cfg, uint16_t bvci) @@ -229,7 +193,7 @@ void gbproxy_peer_free(struct gbproxy_peer *peer) { llist_del(&peer->list); - gbprox_delete_tllis(peer); + gbproxy_delete_tllis(peer); rate_ctr_group_free(peer->ctrg); peer->ctrg = NULL; @@ -244,1911 +208,259 @@ static void strip_ns_hdr(struct msgb *msg) msgb_pull(msg, strip_len); } -/* TODO: Move shift functions to libosmocore */ - -int v_fixed_shift(uint8_t **data, size_t *data_len, - size_t len, uint8_t **value) -{ - if (len > *data_len) - goto fail; - - if (value) - *value = *data; - - *data += len; - *data_len -= len; - - return len; - -fail: - *data += *data_len; - *data_len = 0; - return -1; -} - -int tv_fixed_match(uint8_t **data, size_t *data_len, - uint8_t tag, size_t len, - uint8_t **value) -{ - size_t ie_len; - - if (*data_len == 0) - goto fail; - - if ((*data)[0] != tag) - return 0; - - if (len > *data_len - 1) - goto fail; - - if (value) - *value = *data + 1; - - ie_len = len + 1; - *data += ie_len; - *data_len -= ie_len; - - return ie_len; - -fail: - *data += *data_len; - *data_len = 0; - return -1; -} - -int tlv_match(uint8_t **data, size_t *data_len, - uint8_t tag, uint8_t **value, size_t *value_len) +/* update peer according to the BSS message */ +static void gbprox_update_current_raid(uint8_t *raid_enc, + struct gbproxy_peer *peer, + const char *log_text) { - size_t len; - size_t ie_len; - - if (*data_len < 2) - goto fail; - - if ((*data)[0] != tag) - return 0; - - len = (*data)[1]; - if (len > *data_len - 2) - goto fail; + struct gbproxy_patch_state *state = &peer->patch_state; + const int old_local_mcc = state->local_mcc; + const int old_local_mnc = state->local_mnc; + struct gprs_ra_id raid; - if (value) - *value = *data + 2; - if (value_len) - *value_len = len; + if (!raid_enc) + return; - ie_len = len + 2; + gsm48_parse_ra(&raid, raid_enc); - *data += ie_len; - *data_len -= ie_len; + /* save source side MCC/MNC */ + if (!peer->cfg->core_mcc || raid.mcc == peer->cfg->core_mcc) { + state->local_mcc = 0; + } else { + state->local_mcc = raid.mcc; + } - return ie_len; + if (!peer->cfg->core_mnc || raid.mnc == peer->cfg->core_mnc) { + state->local_mnc = 0; + } else { + state->local_mnc = raid.mnc; + } -fail: - *data += *data_len; - *data_len = 0; - return -1; + if (old_local_mcc != state->local_mcc || + old_local_mnc != state->local_mnc) + LOGP(DGPRS, LOGL_NOTICE, + "Patching RAID %sactivated, msg: %s, " + "local: %d-%d, core: %d-%d\n", + state->local_mcc || state->local_mnc ? + "" : "de", + log_text, + state->local_mcc, state->local_mnc, + peer->cfg->core_mcc, peer->cfg->core_mnc); } -int lv_shift(uint8_t **data, size_t *data_len, - uint8_t **value, size_t *value_len) +struct gbproxy_peer *peer_by_bssgp_tlv(struct gbproxy_config *cfg, struct tlv_parsed *tp) { - size_t len; - size_t ie_len; - - if (*data_len < 1) - goto fail; - - len = (*data)[0]; - if (len > *data_len - 1) - goto fail; + if (TLVP_PRESENT(tp, BSSGP_IE_BVCI)) { + uint16_t bvci; - if (value) - *value = *data + 1; - if (value_len) - *value_len = len; + bvci = ntohs(tlvp_val16_unal(tp, BSSGP_IE_BVCI)); + if (bvci >= 2) + return peer_by_bvci(cfg, bvci); + } - ie_len = len + 1; - *data += ie_len; - *data_len -= ie_len; + if (TLVP_PRESENT(tp, BSSGP_IE_ROUTEING_AREA)) { + uint8_t *rai = (uint8_t *)TLVP_VAL(tp, BSSGP_IE_ROUTEING_AREA); + /* Only compare LAC part, since MCC/MNC are possibly patched. + * Since the LAC of different BSS must be different when + * MCC/MNC are patched, collisions shouldn't happen. */ + return peer_by_lac(cfg, rai); + } - return ie_len; + if (TLVP_PRESENT(tp, BSSGP_IE_LOCATION_AREA)) { + uint8_t *lai = (uint8_t *)TLVP_VAL(tp, BSSGP_IE_LOCATION_AREA); + return peer_by_lac(cfg, lai); + } -fail: - *data += *data_len; - *data_len = 0; - return -1; + return NULL; } -/* GSM 04.08, 10.5.1.4 */ -static int is_mi_tmsi(const uint8_t *value, size_t value_len) +uint32_t gbproxy_make_bss_ptmsi(struct gbproxy_peer *peer, + uint32_t sgsn_ptmsi) { - if (value_len != GSM48_TMSI_LEN) - return 0; + uint32_t bss_ptmsi; + if (!peer->cfg->patch_ptmsi) { + bss_ptmsi = sgsn_ptmsi; + } else { + do { + bss_ptmsi = rand_r(&peer->cfg->bss_ptmsi_state); + bss_ptmsi = bss_ptmsi | 0xC0000000; - if (!value || (value[0] & GSM_MI_TYPE_MASK) != GSM_MI_TYPE_TMSI) - return 0; + if (gbproxy_find_tlli_by_ptmsi(peer, bss_ptmsi)) + bss_ptmsi = GSM_RESERVED_TMSI; + } while (bss_ptmsi == GSM_RESERVED_TMSI); + } - return 1; + return bss_ptmsi; } -/* GSM 04.08, 10.5.1.4 */ -static int is_mi_imsi(const uint8_t *value, size_t value_len) +uint32_t gbproxy_make_sgsn_tlli(struct gbproxy_peer *peer, + struct gbproxy_tlli_info *tlli_info, + uint32_t bss_tlli) { - if (value_len == 0) - return 0; - - if (!value || (value[0] & GSM_MI_TYPE_MASK) != GSM_MI_TYPE_IMSI) - return 0; + uint32_t sgsn_tlli; + if (!peer->cfg->patch_ptmsi) { + sgsn_tlli = bss_tlli; + } else if (tlli_info->sgsn_tlli.ptmsi != GSM_RESERVED_TMSI) { + sgsn_tlli = gprs_tmsi2tlli(tlli_info->sgsn_tlli.ptmsi, + TLLI_FOREIGN); + } else { + do { + /* create random TLLI, 0b01111xxx... */ + sgsn_tlli = rand_r(&peer->cfg->sgsn_tlli_state); + sgsn_tlli = (sgsn_tlli & 0x7fffffff) | 0x78000000; - return 1; + if (gbproxy_find_tlli_by_sgsn_tlli(peer, sgsn_tlli)) + sgsn_tlli = 0; + } while (!sgsn_tlli); + } + return sgsn_tlli; } -static int parse_mi_tmsi(const uint8_t *value, size_t value_len, uint32_t *tmsi) +/* patch BSSGP message */ +static void gbprox_process_bssgp_ul(struct gbproxy_config *cfg, + struct msgb *msg, + struct gbproxy_peer *peer) { - uint32_t tmsi_be; - - if (!is_mi_tmsi(value, value_len)) - return 0; - - memcpy(&tmsi_be, value + 1, sizeof(tmsi_be)); - - *tmsi = ntohl(tmsi_be); - return 1; -} - -struct gbproxy_parse_context { - /* Pointer to protocol specific parts */ - struct gsm48_hdr *g48_hdr; - struct bssgp_normal_hdr *bgp_hdr; - struct bssgp_ud_hdr *bud_hdr; - uint8_t *bssgp_data; - size_t bssgp_data_len; - uint8_t *llc; - size_t llc_len; - - /* Extracted information */ - struct gprs_llc_hdr_parsed llc_hdr_parsed; - struct tlv_parsed bssgp_tp; - int to_bss; - uint8_t *tlli_enc; - uint8_t *imsi; - size_t imsi_len; - uint8_t *apn_ie; - size_t apn_ie_len; - uint8_t *ptmsi_enc; - uint8_t *new_ptmsi_enc; - uint8_t *raid_enc; - uint8_t *old_raid_enc; - uint8_t *bssgp_raid_enc; - uint8_t *bssgp_ptimsi; - - /* General info */ - const char *llc_msg_name; - int invalidate_tlli; - int need_decryption; - uint32_t tlli; - int pdu_type; - int old_raid_matches; -}; + struct gprs_gb_parse_context parse_ctx = {0}; + int rc; + int len_change = 0; + time_t now; + struct gbproxy_tlli_info *tlli_info = NULL; -struct gbproxy_tlli_info *gbprox_find_tlli(struct gbproxy_peer *peer, - uint32_t tlli) -{ - struct gbproxy_tlli_info *tlli_info; - struct gbproxy_patch_state *state = &peer->patch_state; + if (!cfg->core_mcc && !cfg->core_mnc && !cfg->core_apn) + return; - llist_for_each_entry(tlli_info, &state->enabled_tllis, list) - if (tlli_info->tlli.current == tlli || - tlli_info->tlli.assigned == tlli) - return tlli_info; + parse_ctx.to_bss = 0; - return NULL; -} + /* Parse BSSGP/LLC */ + rc = gprs_gb_parse_bssgp(msgb_bssgph(msg), msgb_bssgp_len(msg), + &parse_ctx); -static struct gbproxy_tlli_info *gbprox_find_tlli_by_ptmsi( - struct gbproxy_peer *peer, - uint32_t ptmsi) -{ - struct gbproxy_tlli_info *tlli_info; - struct gbproxy_patch_state *state = &peer->patch_state; + if (!rc) { + if (!parse_ctx.need_decryption) { + LOGP(DGPRS, LOGL_ERROR, + "NSEI=%u(BSS) patching: " + "failed to parse BSSGP/GMM message\n", + msgb_nsei(msg)); + return; + } + } - llist_for_each_entry(tlli_info, &state->enabled_tllis, list) - if (tlli_info->tlli.ptmsi == ptmsi) - return tlli_info; + /* Get peer */ + if (!peer && msgb_bvci(msg) >= 2) + peer = peer_by_bvci(cfg, msgb_bvci(msg)); - return NULL; -} + if (!peer) + peer = gbprox_peer_by_nsei(cfg, msgb_nsei(msg)); -struct gbproxy_tlli_info *gbprox_find_tlli_by_sgsn_tlli( - struct gbproxy_peer *peer, - uint32_t tlli) -{ - struct gbproxy_tlli_info *tlli_info; - struct gbproxy_patch_state *state = &peer->patch_state; + if (!peer) + peer = peer_by_bssgp_tlv(cfg, &parse_ctx.bssgp_tp); - llist_for_each_entry(tlli_info, &state->enabled_tllis, list) - if (tlli_info->sgsn_tlli.current == tlli || - tlli_info->sgsn_tlli.assigned == tlli) - return tlli_info; + if (!peer) { + LOGP(DLLC, LOGL_INFO, + "NSEI=%d(BSS) patching: didn't find peer for message, " + "PDU %d\n", + msgb_nsei(msg), parse_ctx.pdu_type); + /* Increment counter */ + rate_ctr_inc(&cfg->ctrg->ctr[GBPROX_GLOB_CTR_PATCH_PEER_ERR]); + return; + } - return NULL; -} + now = time(NULL); -struct gbproxy_tlli_info *gbprox_find_tlli_by_mi( - struct gbproxy_peer *peer, - const uint8_t *mi_data, - size_t mi_data_len) -{ - struct gbproxy_tlli_info *tlli_info; - struct gbproxy_patch_state *state = &peer->patch_state; + if (parse_ctx.bssgp_raid_enc && parse_ctx.old_raid_enc && + memcmp(parse_ctx.bssgp_raid_enc, parse_ctx.old_raid_enc, 6) == 0) + parse_ctx.old_raid_matches = 1; - if (!is_mi_imsi(mi_data, mi_data_len)) - return NULL; + gbprox_update_current_raid(parse_ctx.bssgp_raid_enc, peer, + parse_ctx.llc_msg_name); - llist_for_each_entry(tlli_info, &state->enabled_tllis, list) { - if (tlli_info->mi_data_len != mi_data_len) - continue; - if (memcmp(tlli_info->mi_data, mi_data, mi_data_len) != 0) - continue; + if (parse_ctx.g48_hdr) { + switch (parse_ctx.g48_hdr->msg_type) { + case GSM48_MT_GMM_ATTACH_REQ: + rate_ctr_inc(&peer->ctrg->ctr[GBPROX_PEER_CTR_ATTACH_REQS]); + break; - return tlli_info; + default: + break; + } } - return NULL; -} - -void gbprox_delete_tlli(struct gbproxy_peer *peer, - struct gbproxy_tlli_info *tlli_info) -{ - struct gbproxy_patch_state *state = &peer->patch_state; - - llist_del(&tlli_info->list); - talloc_free(tlli_info); - state->enabled_tllis_count -= 1; - - peer->ctrg->ctr[GBPROX_PEER_CTR_TLLI_CACHE_SIZE].current = - state->enabled_tllis_count; -} + gprs_gb_log_parse_context(&parse_ctx, "BSSGP"); -static void gbprox_delete_tllis(struct gbproxy_peer *peer) -{ - struct gbproxy_tlli_info *tlli_info, *nxt; - struct gbproxy_patch_state *state = &peer->patch_state; + tlli_info = gbproxy_update_tlli_state_ul(peer, now, &parse_ctx); - llist_for_each_entry_safe(tlli_info, nxt, &state->enabled_tllis, list) - gbprox_delete_tlli(peer, tlli_info); + gbproxy_patch_bssgp(msg, msgb_bssgph(msg), msgb_bssgp_len(msg), + peer, tlli_info, &len_change, &parse_ctx); - OSMO_ASSERT(state->enabled_tllis_count == 0); - OSMO_ASSERT(llist_empty(&state->enabled_tllis)); -} + gbproxy_update_tlli_state_after(peer, tlli_info, now, &parse_ctx); -void gbprox_clear_patch_filter(struct gbproxy_config *cfg) -{ - if (cfg->check_imsi) { - regfree(&cfg->imsi_re_comp); - cfg->check_imsi = 0; - } + return; } -int gbprox_set_patch_filter(struct gbproxy_config *cfg, const char *filter, - const char **err_msg) +/* patch BSSGP message to use core_mcc/mnc on the SGSN side */ +static void gbprox_process_bssgp_dl(struct gbproxy_config *cfg, + struct msgb *msg, + struct gbproxy_peer *peer) { - static char err_buf[300]; + struct gprs_gb_parse_context parse_ctx = {0}; int rc; + int len_change = 0; + time_t now; + struct gbproxy_tlli_info *tlli_info = NULL; - gbprox_clear_patch_filter(cfg); - - if (!filter) - return 0; - - rc = regcomp(&cfg->imsi_re_comp, filter, - REG_EXTENDED | REG_NOSUB | REG_ICASE); + parse_ctx.to_bss = 1; - if (rc == 0) { - cfg->check_imsi = 1; - return 0; - } + rc = gprs_gb_parse_bssgp(msgb_bssgph(msg), msgb_bssgp_len(msg), + &parse_ctx); - if (err_msg) { - regerror(rc, &cfg->imsi_re_comp, - err_buf, sizeof(err_buf)); - *err_msg = err_buf; + if (!rc) { + if (!parse_ctx.need_decryption) { + LOGP(DGPRS, LOGL_ERROR, + "NSEI=%u(SGSN) patching: " + "failed to parse BSSGP/GMM message\n", + msgb_nsei(msg)); + return; + } } - return -1; -} - -int gbprox_check_imsi(struct gbproxy_peer *peer, - const uint8_t *imsi, size_t imsi_len) -{ - char mi_buf[200]; - int rc; - - if (!peer->cfg->check_imsi) - return 1; - - rc = is_mi_imsi(imsi, imsi_len); - if (rc > 0) - rc = gsm48_mi_to_string(mi_buf, sizeof(mi_buf), imsi, imsi_len); - if (rc <= 0) { - LOGP(DGPRS, LOGL_NOTICE, "Invalid IMSI %s\n", - osmo_hexdump(imsi, imsi_len)); - return -1; - } + if (!peer && msgb_bvci(msg) >= 2) + peer = peer_by_bvci(cfg, msgb_bvci(msg)); - LOGP(DGPRS, LOGL_DEBUG, "Checking IMSI '%s' (%d)\n", mi_buf, rc); + if (!peer) + peer = peer_by_bssgp_tlv(cfg, &parse_ctx.bssgp_tp); - rc = regexec(&peer->cfg->imsi_re_comp, mi_buf, 0, NULL, 0); - if (rc == REG_NOMATCH) { - LOGP(DGPRS, LOGL_INFO, - "IMSI '%s' doesn't match pattern '%s'\n", - mi_buf, peer->cfg->match_re); - return 0; + if (!peer) { + LOGP(DLLC, LOGL_INFO, + "NSEI=%d(SGSN) patching: didn't find peer for message, " + "PDU %d\n", + msgb_nsei(msg), parse_ctx.pdu_type); + /* Increment counter */ + rate_ctr_inc(&cfg->ctrg->ctr[GBPROX_GLOB_CTR_PATCH_PEER_ERR]); + return; } - return 1; -} - -static void gbprox_attach_tlli_info(struct gbproxy_peer *peer, time_t now, - struct gbproxy_tlli_info *tlli_info) -{ - struct gbproxy_patch_state *state = &peer->patch_state; + now = time(NULL); - tlli_info->timestamp = now; - llist_add(&tlli_info->list, &state->enabled_tllis); - state->enabled_tllis_count += 1; + if (parse_ctx.g48_hdr) { + switch (parse_ctx.g48_hdr->msg_type) { + case GSM48_MT_GMM_ATTACH_REJ: + rate_ctr_inc(&peer->ctrg->ctr[GBPROX_PEER_CTR_ATTACH_REJS]); + break; - peer->ctrg->ctr[GBPROX_PEER_CTR_TLLI_CACHE_SIZE].current = - state->enabled_tllis_count; -} + default: + break; + } + } -int gbprox_remove_stale_tllis(struct gbproxy_peer *peer, time_t now) -{ - struct gbproxy_patch_state *state = &peer->patch_state; - int exceeded_max_len = 0; - int deleted_count = 0; - int check_for_age; - - if (peer->cfg->tlli_max_len > 0) - exceeded_max_len = - state->enabled_tllis_count - peer->cfg->tlli_max_len; - - check_for_age = peer->cfg->tlli_max_age > 0; - - for (; exceeded_max_len > 0; exceeded_max_len--) { - struct gbproxy_tlli_info *tlli_info; - OSMO_ASSERT(!llist_empty(&state->enabled_tllis)); - tlli_info = llist_entry(state->enabled_tllis.prev, - struct gbproxy_tlli_info, - list); - LOGP(DGPRS, LOGL_INFO, - "Removing TLLI %08x from list " - "(stale, length %d, max_len exceeded)\n", - tlli_info->tlli.current, state->enabled_tllis_count); - - gbprox_delete_tlli(peer, tlli_info); - deleted_count += 1; - } - - while (check_for_age && !llist_empty(&state->enabled_tllis)) { - time_t age; - struct gbproxy_tlli_info *tlli_info; - tlli_info = llist_entry(state->enabled_tllis.prev, - struct gbproxy_tlli_info, - list); - age = now - tlli_info->timestamp; - /* age < 0 only happens after system time jumps, discard entry */ - if (age <= peer->cfg->tlli_max_age && age >= 0) { - check_for_age = 0; - continue; - } - - LOGP(DGPRS, LOGL_INFO, - "Removing TLLI %08x from list " - "(stale, age %d, max_age exceeded)\n", - tlli_info->tlli.current, (int)age); - - gbprox_delete_tlli(peer, tlli_info); - deleted_count += 1; - } - - return deleted_count; -} - -static struct gbproxy_tlli_info *gbprox_tlli_info_alloc( - struct gbproxy_peer *peer) -{ - struct gbproxy_tlli_info *tlli_info; - - tlli_info = talloc_zero(peer, struct gbproxy_tlli_info); - tlli_info->tlli.ptmsi = GSM_RESERVED_TMSI; - tlli_info->sgsn_tlli.ptmsi = GSM_RESERVED_TMSI; - - return tlli_info; -} - -static void gbprox_detach_tlli_info( - struct gbproxy_peer *peer, - struct gbproxy_tlli_info *tlli_info) -{ - struct gbproxy_patch_state *state = &peer->patch_state; - - llist_del(&tlli_info->list); - OSMO_ASSERT(state->enabled_tllis_count > 0); - state->enabled_tllis_count -= 1; - - peer->ctrg->ctr[GBPROX_PEER_CTR_TLLI_CACHE_SIZE].current = - state->enabled_tllis_count; -} - -static void gbprox_update_tlli_info(struct gbproxy_tlli_info *tlli_info, - const uint8_t *imsi, size_t imsi_len) -{ - if (!is_mi_imsi(imsi, imsi_len)) - return; - - tlli_info->mi_data_len = imsi_len; - tlli_info->mi_data = - talloc_realloc_size(tlli_info, tlli_info->mi_data, imsi_len); - OSMO_ASSERT(tlli_info->mi_data != NULL); - memcpy(tlli_info->mi_data, imsi, imsi_len); -} - -void gbprox_reassign_tlli(struct gbproxy_tlli_state *tlli_state, - struct gbproxy_peer *peer, uint32_t new_tlli) -{ - if (new_tlli == tlli_state->current) - return; - - LOGP(DGPRS, LOGL_INFO, - "The TLLI has been reassigned from %08x to %08x\n", - tlli_state->current, new_tlli); - - /* Remember assigned TLLI */ - tlli_state->assigned = new_tlli; - tlli_state->bss_validated = 0; - tlli_state->net_validated = 0; -} - -static uint32_t gbprox_map_tlli(uint32_t other_tlli, - struct gbproxy_tlli_info *tlli_info, int to_bss) -{ - uint32_t tlli = 0; - struct gbproxy_tlli_state *src, *dst; - if (to_bss) { - src = &tlli_info->sgsn_tlli; - dst = &tlli_info->tlli; - } else { - src = &tlli_info->tlli; - dst = &tlli_info->sgsn_tlli; - } - if (src->current == other_tlli) - tlli = dst->current; - else if (src->assigned == other_tlli) - tlli = dst->assigned; - - return tlli; -} - -static void gbprox_validate_tlli(struct gbproxy_tlli_state *tlli_state, - uint32_t tlli, int to_bss) -{ - LOGP(DGPRS, LOGL_DEBUG, - "%s({current = %08x, assigned = %08x, net_vld = %d, bss_vld = %d}, %08x)\n", - __func__, tlli_state->current, tlli_state->assigned, - tlli_state->net_validated, tlli_state->bss_validated, tlli); - - if (!tlli_state->assigned || tlli_state->assigned != tlli) - return; - - /* TODO: Is this ok? Check spec */ - if (gprs_tlli_type(tlli) != TLLI_LOCAL) - return; - - /* See GSM 04.08, 4.7.1.5 */ - if (to_bss) - tlli_state->net_validated = 1; - else - tlli_state->bss_validated = 1; - - if (!tlli_state->bss_validated || !tlli_state->net_validated) - return; - - LOGP(DGPRS, LOGL_INFO, - "The TLLI %08x has been validated (was %08x)\n", - tlli_state->assigned, tlli_state->current); - - tlli_state->current = tlli; - tlli_state->assigned = 0; -} - -void gbprox_touch_tlli(struct gbproxy_peer *peer, - struct gbproxy_tlli_info *tlli_info, time_t now) -{ - gbprox_detach_tlli_info(peer, tlli_info); - gbprox_attach_tlli_info(peer, now, tlli_info); -} - -struct gbproxy_tlli_info *gbprox_register_tlli( - struct gbproxy_peer *peer, uint32_t tlli, - const uint8_t *imsi, size_t imsi_len, time_t now) -{ - struct gbproxy_tlli_info *tlli_info; - int enable_patching = -1; - int tlli_already_known; - - /* Check, whether the IMSI matches */ - if (is_mi_imsi(imsi, imsi_len)) { - enable_patching = gbprox_check_imsi(peer, imsi, imsi_len); - if (enable_patching < 0) - return NULL; - } - - tlli_info = gbprox_find_tlli(peer, tlli); - - if (!tlli_info) { - tlli_info = gbprox_find_tlli_by_mi(peer, imsi, imsi_len); - - if (tlli_info) { - /* TLLI has changed somehow, adjust it */ - LOGP(DGPRS, LOGL_INFO, - "The TLLI has changed from %08x to %08x\n", - tlli_info->tlli.current, tlli); - tlli_info->tlli.current = tlli; - } - } - - if (!tlli_info) { - tlli_info = gbprox_tlli_info_alloc(peer); - tlli_info->tlli.current = tlli; - } else { - gbprox_detach_tlli_info(peer, tlli_info); - tlli_already_known = 1; - } - - OSMO_ASSERT(tlli_info != NULL); - - if (!tlli_already_known) - LOGP(DGPRS, LOGL_INFO, "Adding TLLI %08x to list\n", tlli); - - gbprox_attach_tlli_info(peer, now, tlli_info); - gbprox_update_tlli_info(tlli_info, imsi, imsi_len); - - if (enable_patching >= 0) - tlli_info->enable_patching = enable_patching; - - return tlli_info; -} - -static void gbprox_unregister_tlli(struct gbproxy_peer *peer, uint32_t tlli) -{ - struct gbproxy_tlli_info *tlli_info; - - tlli_info = gbprox_find_tlli(peer, tlli); - if (tlli_info) { - LOGP(DGPRS, LOGL_INFO, - "Removing TLLI %08x from list\n", - tlli); - gbprox_delete_tlli(peer, tlli_info); - } -} - -static int gbprox_check_tlli(struct gbproxy_peer *peer, uint32_t tlli) -{ - struct gbproxy_tlli_info *tlli_info; - - LOGP(DGPRS, LOGL_INFO, "Checking TLLI %08x, class: %d\n", - tlli, gprs_tlli_type(tlli)); - - if (!peer->cfg->check_imsi) - return 1; - - tlli_info = gbprox_find_tlli(peer, tlli); - - return tlli_info != NULL && tlli_info->enable_patching; -} - -/* check whether patching is enabled at this level */ -static int patching_is_enabled(struct gbproxy_peer *peer, - enum gbproxy_patch_mode need_at_least) -{ - enum gbproxy_patch_mode patch_mode = peer->cfg->patch_mode; - if (patch_mode == GBPROX_PATCH_DEFAULT) - patch_mode = GBPROX_PATCH_LLC; - - return need_at_least <= patch_mode; -} - -/* check whether patching is enabled at this level */ -static int patching_is_required(struct gbproxy_peer *peer, - enum gbproxy_patch_mode need_at_least) -{ - return need_at_least <= peer->cfg->patch_mode; -} - -/* update peer according to the BSS message */ -static void gbprox_update_current_raid(uint8_t *raid_enc, - struct gbproxy_peer *peer, - const char *log_text) -{ - struct gbproxy_patch_state *state = &peer->patch_state; - const int old_local_mcc = state->local_mcc; - const int old_local_mnc = state->local_mnc; - struct gprs_ra_id raid; - - if (!raid_enc) - return; - - gsm48_parse_ra(&raid, raid_enc); - - /* save source side MCC/MNC */ - if (!peer->cfg->core_mcc || raid.mcc == peer->cfg->core_mcc) { - state->local_mcc = 0; - } else { - state->local_mcc = raid.mcc; - } - - if (!peer->cfg->core_mnc || raid.mnc == peer->cfg->core_mnc) { - state->local_mnc = 0; - } else { - state->local_mnc = raid.mnc; - } - - if (old_local_mcc != state->local_mcc || - old_local_mnc != state->local_mnc) - LOGP(DGPRS, LOGL_NOTICE, - "Patching RAID %sactivated, msg: %s, " - "local: %d-%d, core: %d-%d\n", - state->local_mcc || state->local_mnc ? - "" : "de", - log_text, - state->local_mcc, state->local_mnc, - peer->cfg->core_mcc, peer->cfg->core_mnc); -} - -/* patch RA identifier in place */ -static void gbprox_patch_raid(uint8_t *raid_enc, struct gbproxy_peer *peer, - int to_bss, const char *log_text) -{ - struct gbproxy_patch_state *state = &peer->patch_state; - int old_mcc; - int old_mnc; - struct gprs_ra_id raid; - - gsm48_parse_ra(&raid, raid_enc); - - old_mcc = raid.mcc; - old_mnc = raid.mnc; - - if (!to_bss) { - /* BSS -> SGSN */ - if (state->local_mcc) - raid.mcc = peer->cfg->core_mcc; - - if (state->local_mnc) - raid.mnc = peer->cfg->core_mnc; - } else { - /* SGSN -> BSS */ - if (state->local_mcc) - raid.mcc = state->local_mcc; - - if (state->local_mnc) - raid.mnc = state->local_mnc; - } - - if (state->local_mcc || state->local_mnc) { - enum gbprox_peer_ctr counter = - to_bss ? - GBPROX_PEER_CTR_RAID_PATCHED_SGSN : - GBPROX_PEER_CTR_RAID_PATCHED_BSS; - - LOGP(DGPRS, LOGL_DEBUG, - "Patching %s to %s: " - "%d-%d-%d-%d -> %d-%d-%d-%d\n", - log_text, - to_bss ? "BSS" : "SGSN", - old_mcc, old_mnc, raid.lac, raid.rac, - raid.mcc, raid.mnc, raid.lac, raid.rac); - - gsm48_construct_ra(raid_enc, &raid); - rate_ctr_inc(&peer->ctrg->ctr[counter]); - } -} - -static void gbprox_patch_apn_ie(struct msgb *msg, - uint8_t *apn_ie, size_t apn_ie_len, - struct gbproxy_peer *peer, - size_t *new_apn_ie_len, const char *log_text) -{ - struct apn_ie_hdr { - uint8_t iei; - uint8_t apn_len; - uint8_t apn[0]; - } *hdr = (void *)apn_ie; - - size_t apn_len = hdr->apn_len; - uint8_t *apn = hdr->apn; - - OSMO_ASSERT(apn_ie_len == apn_len + sizeof(struct apn_ie_hdr)); - OSMO_ASSERT(apn_ie_len > 2 && apn_ie_len <= 102); - - if (peer->cfg->core_apn_size == 0) { - char str1[110]; - /* Remove the IE */ - LOGP(DGPRS, LOGL_DEBUG, - "Patching %s to SGSN: Removing APN '%s'\n", - log_text, - gprs_apn_to_str(str1, apn, apn_len)); - - *new_apn_ie_len = 0; - gprs_msgb_resize_area(msg, apn_ie, apn_ie_len, 0); - } else { - /* Resize the IE */ - char str1[110]; - char str2[110]; - - OSMO_ASSERT(peer->cfg->core_apn_size <= 100); - - LOGP(DGPRS, LOGL_DEBUG, - "Patching %s to SGSN: " - "Replacing APN '%s' -> '%s'\n", - log_text, - gprs_apn_to_str(str1, apn, apn_len), - gprs_apn_to_str(str2, peer->cfg->core_apn, - peer->cfg->core_apn_size)); - - *new_apn_ie_len = peer->cfg->core_apn_size + 2; - gprs_msgb_resize_area(msg, apn, apn_len, peer->cfg->core_apn_size); - memcpy(apn, peer->cfg->core_apn, peer->cfg->core_apn_size); - hdr->apn_len = peer->cfg->core_apn_size; - } - - rate_ctr_inc(&peer->ctrg->ctr[GBPROX_PEER_CTR_APN_PATCHED]); -} - -static int gbprox_patch_tlli(uint8_t *tlli_enc, - struct gbproxy_peer *peer, - uint32_t new_tlli, - int to_bss, const char *log_text) -{ - uint32_t tlli_be; - uint32_t tlli; - enum gbprox_peer_ctr counter = - to_bss ? - GBPROX_PEER_CTR_TLLI_PATCHED_SGSN : - GBPROX_PEER_CTR_TLLI_PATCHED_BSS; - - memcpy(&tlli_be, tlli_enc, sizeof(tlli_be)); - tlli = ntohl(tlli_be); - - if (tlli == new_tlli) - return 0; - - LOGP(DGPRS, LOGL_DEBUG, - "Patching %ss: " - "Replacing %08x -> %08x\n", - log_text, tlli, new_tlli); - - tlli_be = htonl(new_tlli); - memcpy(tlli_enc, &tlli_be, sizeof(tlli_be)); - - rate_ctr_inc(&peer->ctrg->ctr[counter]); - - return 1; -} - -static int gbprox_patch_ptmsi(uint8_t *ptmsi_enc, - struct gbproxy_peer *peer, - uint32_t new_ptmsi, - int to_bss, const char *log_text) -{ - uint32_t ptmsi_be; - uint32_t ptmsi; - enum gbprox_peer_ctr counter = - to_bss ? - GBPROX_PEER_CTR_PTMSI_PATCHED_SGSN : - GBPROX_PEER_CTR_PTMSI_PATCHED_BSS; - memcpy(&ptmsi_be, ptmsi_enc + 1, sizeof(ptmsi_be)); - ptmsi = ntohl(ptmsi_be); - - if (ptmsi == new_ptmsi) - return 0; - - LOGP(DGPRS, LOGL_DEBUG, - "Patching %ss: " - "Replacing %08x -> %08x\n", - log_text, ptmsi, new_ptmsi); - - ptmsi_be = htonl(new_ptmsi); - memcpy(ptmsi_enc + 1, &ptmsi_be, sizeof(ptmsi_be)); - - rate_ctr_inc(&peer->ctrg->ctr[counter]); - - return 1; -} - -static int gbprox_parse_gmm_attach_req(uint8_t *data, size_t data_len, - struct gbproxy_parse_context *parse_ctx) -{ - uint8_t *value; - size_t value_len; - - parse_ctx->llc_msg_name = "ATTACH_REQ"; - - /* Skip MS network capability */ - if (lv_shift(&data, &data_len, NULL, &value_len) <= 0 || - value_len < 1 || value_len > 2) - /* invalid */ - return 0;; - - /* Skip Attach type */ - /* Skip Ciphering key sequence number */ - /* Skip DRX parameter */ - v_fixed_shift(&data, &data_len, 3, NULL); - - /* Get Mobile identity */ - if (lv_shift(&data, &data_len, &value, &value_len) <= 0 || - value_len < 5 || value_len > 8) - /* invalid */ - return 0; - - if (is_mi_tmsi(value, value_len)) { - parse_ctx->ptmsi_enc = value; - } else if (is_mi_imsi(value, value_len)) { - parse_ctx->imsi = value; - parse_ctx->imsi_len = value_len; - } - - if (v_fixed_shift(&data, &data_len, 6, &value) <= 0) - return 0; - - parse_ctx->old_raid_enc = value; - - return 1; -} - -static int gbprox_parse_gmm_attach_ack(uint8_t *data, size_t data_len, - struct gbproxy_parse_context *parse_ctx) -{ - uint8_t *value; - size_t value_len; - - parse_ctx->llc_msg_name = "ATTACH_ACK"; - - /* Skip Attach result */ - /* Skip Force to standby */ - /* Skip Periodic RA update timer */ - /* Skip Radio priority for SMS */ - /* Skip Spare half octet */ - v_fixed_shift(&data, &data_len, 3, NULL); - - if (v_fixed_shift(&data, &data_len, 6, &value) <= 0) - return 0; - - parse_ctx->raid_enc = value; - - /* Skip P-TMSI signature (P-TMSI signature, opt, TV, length 4) */ - tv_fixed_match(&data, &data_len, GSM48_IE_GMM_PTMSI_SIG, 3, NULL); - - /* Skip Negotiated READY timer value (GPRS timer, opt, TV, length 2) */ - tv_fixed_match(&data, &data_len, GSM48_IE_GMM_TIMER_READY, 1, NULL); - - /* Allocated P-TMSI (Mobile identity, opt, TLV, length 7) */ - if (tlv_match(&data, &data_len, GSM48_IE_GMM_ALLOC_PTMSI, - &value, &value_len) > 0 && - is_mi_tmsi(value, value_len)) - parse_ctx->new_ptmsi_enc = value; - return 1; -} - -static int gbprox_parse_gmm_detach_req(uint8_t *data, size_t data_len, - struct gbproxy_parse_context *parse_ctx) -{ - uint8_t *value; - size_t value_len; - int detach_type; - int power_off; - - parse_ctx->llc_msg_name = "DETACH_REQ"; - - /* Skip spare half octet */ - /* Get Detach type */ - if (v_fixed_shift(&data, &data_len, 1, &value) <= 0) - /* invalid */ - return 0; - - detach_type = *value & 0x07; - power_off = *value & 0x08 ? 1 : 0; - - if (!parse_ctx->to_bss) { - /* Mobile originated */ - - if (power_off) - parse_ctx->invalidate_tlli = 1; - - /* Get P-TMSI (Mobile identity), see GSM 24.008, 9.4.5.2 */ - if (tlv_match(&data, &data_len, - GSM48_IE_GMM_ALLOC_PTMSI, &value, &value_len) > 0) - { - if (is_mi_tmsi(value, value_len)) - parse_ctx->ptmsi_enc = value; - } - } - - return 1; -} - -static int gbprox_parse_gmm_ra_upd_req(uint8_t *data, size_t data_len, - struct gbproxy_parse_context *parse_ctx) -{ - uint8_t *value; - - parse_ctx->llc_msg_name = "RA_UPD_REQ"; - - /* Skip Update type */ - /* Skip GPRS ciphering key sequence number */ - v_fixed_shift(&data, &data_len, 1, NULL); - - if (v_fixed_shift(&data, &data_len, 6, &value) <= 0) - return 0; - - parse_ctx->old_raid_enc = value; - - return 1; -} - -static int gbprox_parse_gmm_ra_upd_ack(uint8_t *data, size_t data_len, - struct gbproxy_parse_context *parse_ctx) -{ - uint8_t *value; - size_t value_len; - - parse_ctx->llc_msg_name = "RA_UPD_ACK"; - - /* Skip Force to standby */ - /* Skip Update result */ - /* Skip Periodic RA update timer */ - v_fixed_shift(&data, &data_len, 2, NULL); - - if (v_fixed_shift(&data, &data_len, 6, &value) <= 0) - return 0; - - parse_ctx->raid_enc = value; - - /* Skip P-TMSI signature (P-TMSI signature, opt, TV, length 4) */ - tv_fixed_match(&data, &data_len, GSM48_IE_GMM_PTMSI_SIG, 3, NULL); - - /* Allocated P-TMSI (Mobile identity, opt, TLV, length 7) */ - if (tlv_match(&data, &data_len, GSM48_IE_GMM_ALLOC_PTMSI, - &value, &value_len) > 0 && - is_mi_tmsi(value, value_len)) - parse_ctx->new_ptmsi_enc = value; - - return 1; -} - -static int gbprox_parse_gmm_ptmsi_reall_cmd(uint8_t *data, size_t data_len, - struct gbproxy_parse_context *parse_ctx) -{ - uint8_t *value; - size_t value_len; - - parse_ctx->llc_msg_name = "PTMSI_REALL_CMD"; - - LOGP(DLLC, LOGL_NOTICE, - "Got P-TMSI Reallocation Command which is not covered by unit tests yet.\n"); - - /* Allocated P-TMSI */ - if (lv_shift(&data, &data_len, &value, &value_len) > 0 && - is_mi_tmsi(value, value_len)) - parse_ctx->new_ptmsi_enc = value; - - if (v_fixed_shift(&data, &data_len, 6, &value) <= 0) - return 0; - - parse_ctx->raid_enc = value; - - return 1; -} - -static int gbprox_parse_gmm_id_resp(uint8_t *data, size_t data_len, - struct gbproxy_parse_context *parse_ctx) -{ - uint8_t *value; - size_t value_len; - - parse_ctx->llc_msg_name = "ID_RESP"; - - /* Mobile identity, Mobile identity 10.5.1.4, M LV 2-10 */ - if (lv_shift(&data, &data_len, &value, &value_len) <= 0 || - value_len < 1 || value_len > 9) - /* invalid */ - return 0; - - if (is_mi_tmsi(value, value_len)) { - parse_ctx->ptmsi_enc = value; - } else if (is_mi_imsi(value, value_len)) { - parse_ctx->imsi = value; - parse_ctx->imsi_len = value_len; - } - - return 1; -} - -static int gbprox_parse_gsm_act_pdp_req(uint8_t *data, size_t data_len, - struct gbproxy_parse_context *parse_ctx) -{ - ssize_t old_len; - uint8_t *value; - size_t value_len; - - parse_ctx->llc_msg_name = "ACT_PDP_REQ"; - - /* Skip Requested NSAPI */ - /* Skip Requested LLC SAPI */ - v_fixed_shift(&data, &data_len, 2, NULL); - - /* Skip Requested QoS (support 04.08 and 24.008) */ - if (lv_shift(&data, &data_len, NULL, &value_len) <= 0 || - value_len < 4 || value_len > 14) - /* invalid */ - return 0;; - - /* Skip Requested PDP address */ - if (lv_shift(&data, &data_len, NULL, &value_len) <= 0 || - value_len < 2 || value_len > 18) - /* invalid */ - return 0; - - /* Access point name */ - old_len = tlv_match(&data, &data_len, - GSM48_IE_GSM_APN, &value, &value_len); - - if (old_len > 0 && value_len >=1 && value_len <= 100) { - parse_ctx->apn_ie = data - old_len; - parse_ctx->apn_ie_len = old_len; - } - - return 1; -} - -struct gbproxy_peer *peer_by_bssgp_tlv(struct gbproxy_config *cfg, struct tlv_parsed *tp) -{ - if (TLVP_PRESENT(tp, BSSGP_IE_BVCI)) { - uint16_t bvci; - - bvci = ntohs(tlvp_val16_unal(tp, BSSGP_IE_BVCI)); - if (bvci >= 2) - return peer_by_bvci(cfg, bvci); - } - - if (TLVP_PRESENT(tp, BSSGP_IE_ROUTEING_AREA)) { - uint8_t *rai = (uint8_t *)TLVP_VAL(tp, BSSGP_IE_ROUTEING_AREA); - /* Only compare LAC part, since MCC/MNC are possibly patched. - * Since the LAC of different BSS must be different when - * MCC/MNC are patched, collisions shouldn't happen. */ - return peer_by_lac(cfg, rai); - } - - if (TLVP_PRESENT(tp, BSSGP_IE_LOCATION_AREA)) { - uint8_t *lai = (uint8_t *)TLVP_VAL(tp, BSSGP_IE_LOCATION_AREA); - return peer_by_lac(cfg, lai); - } - - return NULL; -} - -static int gbprox_parse_dtap(uint8_t *data, size_t data_len, - struct gbproxy_parse_context *parse_ctx) __attribute__((nonnull)); - -static int gbprox_parse_dtap(uint8_t *data, size_t data_len, - struct gbproxy_parse_context *parse_ctx) -{ - struct gsm48_hdr *g48h; - - if (v_fixed_shift(&data, &data_len, sizeof(*g48h), (uint8_t **)&g48h) <= 0) - return 0; - - parse_ctx->g48_hdr = g48h; - - if ((g48h->proto_discr & 0x0f) != GSM48_PDISC_MM_GPRS && - (g48h->proto_discr & 0x0f) != GSM48_PDISC_SM_GPRS) - return 1; - - switch (g48h->msg_type) { - case GSM48_MT_GMM_ATTACH_REQ: - return gbprox_parse_gmm_attach_req(data, data_len, parse_ctx); - - case GSM48_MT_GMM_ATTACH_ACK: - return gbprox_parse_gmm_attach_ack(data, data_len, parse_ctx); - - case GSM48_MT_GMM_RA_UPD_REQ: - return gbprox_parse_gmm_ra_upd_req(data, data_len, parse_ctx); - - case GSM48_MT_GMM_RA_UPD_ACK: - return gbprox_parse_gmm_ra_upd_ack(data, data_len, parse_ctx); - - case GSM48_MT_GMM_PTMSI_REALL_CMD: - return gbprox_parse_gmm_ptmsi_reall_cmd(data, data_len, parse_ctx); - - case GSM48_MT_GSM_ACT_PDP_REQ: - return gbprox_parse_gsm_act_pdp_req(data, data_len, parse_ctx); - - case GSM48_MT_GMM_ID_RESP: - return gbprox_parse_gmm_id_resp(data, data_len, parse_ctx); - - case GSM48_MT_GMM_DETACH_REQ: - return gbprox_parse_gmm_detach_req(data, data_len, parse_ctx); - - case GSM48_MT_GMM_DETACH_ACK: - parse_ctx->llc_msg_name = "DETACH_ACK"; - parse_ctx->invalidate_tlli = 1; - break; - - default: - break; - }; - - return 1; -} - -static int allow_message_patching(struct gbproxy_peer *peer, int msg_type) -{ - if (msg_type >= GSM48_MT_GSM_ACT_PDP_REQ) { - return patching_is_enabled(peer, GBPROX_PATCH_LLC_GSM); - } else if (msg_type > GSM48_MT_GMM_ATTACH_REJ) { - return patching_is_enabled(peer, GBPROX_PATCH_LLC); - } else if (msg_type > GSM48_MT_GMM_ATTACH_REQ) { - return patching_is_enabled(peer, GBPROX_PATCH_LLC_ATTACH); - } else { - return patching_is_enabled(peer, GBPROX_PATCH_LLC_ATTACH_REQ); - } -} - -static int gbprox_parse_llc(uint8_t *llc, size_t llc_len, - struct gbproxy_parse_context *parse_ctx) __attribute__((nonnull)); - -static int gbprox_parse_llc(uint8_t *llc, size_t llc_len, - struct gbproxy_parse_context *parse_ctx) -{ - struct gprs_llc_hdr_parsed *ghp = &parse_ctx->llc_hdr_parsed; - int rc; - int fcs; - - /* parse LLC */ - rc = gprs_llc_hdr_parse(ghp, llc, llc_len); - gprs_llc_hdr_dump(ghp); - if (rc != 0) { - LOGP(DLLC, LOGL_NOTICE, "Error during LLC header parsing\n"); - return 0; - } - - fcs = gprs_llc_fcs(llc, ghp->crc_length); - LOGP(DLLC, LOGL_DEBUG, "Got LLC message, CRC: %06x (computed %06x)\n", - ghp->fcs, fcs); - - if (!ghp->data) - return 0; - - if (ghp->sapi != GPRS_SAPI_GMM) - return 1; - - if (ghp->cmd != GPRS_LLC_UI) - return 1; - - if (ghp->is_encrypted) { - parse_ctx->need_decryption = 1; - return 0; - } - - return gbprox_parse_dtap(ghp->data, ghp->data_len, parse_ctx); -} - -static int gbprox_patch_llc(struct msgb *msg, uint8_t *llc, size_t llc_len, - struct gbproxy_peer *peer, - struct gbproxy_tlli_info *tlli_info, int *len_change, - struct gbproxy_parse_context *parse_ctx) __attribute__((nonnull)); - -static int gbprox_patch_llc(struct msgb *msg, uint8_t *llc, size_t llc_len, - struct gbproxy_peer *peer, - struct gbproxy_tlli_info *tlli_info, int *len_change, - struct gbproxy_parse_context *parse_ctx) -{ - struct gprs_llc_hdr_parsed *ghp = &parse_ctx->llc_hdr_parsed; - int have_patched = 0; - int fcs; - - if (parse_ctx->g48_hdr && !allow_message_patching(peer, parse_ctx->g48_hdr->msg_type)) - return have_patched; - - if (parse_ctx->ptmsi_enc && tlli_info) { - uint32_t ptmsi; - if (parse_ctx->to_bss) - ptmsi = tlli_info->tlli.ptmsi; - else - ptmsi = tlli_info->sgsn_tlli.ptmsi; - - if (ptmsi != GSM_RESERVED_TMSI) { - if (gbprox_patch_ptmsi(parse_ctx->ptmsi_enc, peer, - ptmsi, parse_ctx->to_bss, "P-TMSI")) - have_patched = 1; - } else { - /* TODO: invalidate old RAI if present (see below) */ - } - } - - if (parse_ctx->new_ptmsi_enc && tlli_info) { - uint32_t ptmsi; - if (parse_ctx->to_bss) - ptmsi = tlli_info->tlli.ptmsi; - else - ptmsi = tlli_info->sgsn_tlli.ptmsi; - - OSMO_ASSERT(ptmsi); - if (gbprox_patch_ptmsi(parse_ctx->new_ptmsi_enc, peer, - ptmsi, parse_ctx->to_bss, "new P-TMSI")) - have_patched = 1; - } - - if (parse_ctx->raid_enc) { - gbprox_patch_raid(parse_ctx->raid_enc, peer, parse_ctx->to_bss, - parse_ctx->llc_msg_name); - have_patched = 1; - } - - if (parse_ctx->old_raid_enc && parse_ctx->old_raid_matches) { - /* TODO: Patch to invalid if P-TMSI unknown. */ - gbprox_patch_raid(parse_ctx->old_raid_enc, peer, parse_ctx->to_bss, - parse_ctx->llc_msg_name); - have_patched = 1; - } - - if (parse_ctx->apn_ie && - peer->cfg->core_apn && - !parse_ctx->to_bss && - gbprox_check_tlli(peer, parse_ctx->tlli)) { - size_t new_len; - gbprox_patch_apn_ie(msg, - parse_ctx->apn_ie, parse_ctx->apn_ie_len, - peer, &new_len, parse_ctx->llc_msg_name); - *len_change += (int)new_len - (int)parse_ctx->apn_ie_len; - - have_patched = 1; - } - - if (have_patched) { - llc_len += *len_change; - ghp->crc_length += *len_change; - - /* Fix FCS */ - fcs = gprs_llc_fcs(llc, ghp->crc_length); - LOGP(DLLC, LOGL_DEBUG, "Updated LLC message, CRC: %06x -> %06x\n", - ghp->fcs, fcs); - - llc[llc_len - 3] = fcs & 0xff; - llc[llc_len - 2] = (fcs >> 8) & 0xff; - llc[llc_len - 1] = (fcs >> 16) & 0xff; - } - - return have_patched; -} - -static void gbprox_log_parse_context(struct gbproxy_parse_context *parse_ctx, - const char *default_msg_name) -{ - const char *msg_name = default_msg_name; - const char *sep = ""; - - if (!parse_ctx->tlli_enc && - !parse_ctx->ptmsi_enc && - !parse_ctx->new_ptmsi_enc && - !parse_ctx->imsi) - return; - - if (parse_ctx->llc_msg_name) - msg_name = parse_ctx->llc_msg_name; - - LOGP(DGPRS, LOGL_DEBUG, "%s: Got", msg_name); - - if (parse_ctx->tlli_enc) { - LOGP(DGPRS, LOGL_DEBUG, "%s TLLI %08x", sep, parse_ctx->tlli); - sep = ","; - } - - if (parse_ctx->bssgp_raid_enc) { - struct gprs_ra_id raid; - gsm48_parse_ra(&raid, parse_ctx->bssgp_raid_enc); - LOGP(DGPRS, LOGL_DEBUG, "%s BSSGP RAID %u-%u-%u-%u", sep, - raid.mcc, raid.mnc, raid.lac, raid.rac); - sep = ","; - } - - if (parse_ctx->raid_enc) { - struct gprs_ra_id raid; - gsm48_parse_ra(&raid, parse_ctx->raid_enc); - LOGP(DGPRS, LOGL_DEBUG, "%s RAID %u-%u-%u-%u", sep, - raid.mcc, raid.mnc, raid.lac, raid.rac); - sep = ","; - } - - if (parse_ctx->old_raid_enc) { - struct gprs_ra_id raid; - gsm48_parse_ra(&raid, parse_ctx->old_raid_enc); - LOGP(DGPRS, LOGL_DEBUG, "%s old RAID %u-%u-%u-%u", sep, - raid.mcc, raid.mnc, raid.lac, raid.rac); - sep = ","; - } - - if (parse_ctx->ptmsi_enc) { - uint32_t ptmsi = GSM_RESERVED_TMSI; - int ok; - ok = parse_mi_tmsi(parse_ctx->ptmsi_enc, GSM48_TMSI_LEN, &ptmsi); - LOGP(DGPRS, LOGL_DEBUG, "%s PTMSI %08x%s", - sep, ptmsi, ok ? "" : " (parse error)"); - sep = ","; - } - - if (parse_ctx->new_ptmsi_enc) { - uint32_t new_ptmsi = GSM_RESERVED_TMSI; - int ok; - ok = parse_mi_tmsi(parse_ctx->new_ptmsi_enc, GSM48_TMSI_LEN, - &new_ptmsi); - LOGP(DGPRS, LOGL_DEBUG, "%s new PTMSI %08x%s", - sep, new_ptmsi, ok ? "" : " (parse error)"); - sep = ","; - } - - if (parse_ctx->imsi) { - char mi_buf[200]; - mi_buf[0] = '\0'; - gsm48_mi_to_string(mi_buf, sizeof(mi_buf), - parse_ctx->imsi, parse_ctx->imsi_len); - LOGP(DGPRS, LOGL_DEBUG, "%s IMSI %s", - sep, mi_buf); - sep = ","; - } - if (parse_ctx->invalidate_tlli) { - LOGP(DGPRS, LOGL_DEBUG, "%s invalidate", sep); - sep = ","; - } - - LOGP(DGPRS, LOGL_DEBUG, "\n"); -} - -static uint32_t gbprox_make_bss_ptmsi(struct gbproxy_peer *peer, - uint32_t sgsn_ptmsi) -{ - uint32_t bss_ptmsi; - if (!peer->cfg->patch_ptmsi) { - bss_ptmsi = sgsn_ptmsi; - } else { - do { - bss_ptmsi = rand_r(&peer->cfg->bss_ptmsi_state); - bss_ptmsi = bss_ptmsi | 0xC0000000; - - if (gbprox_find_tlli_by_ptmsi(peer, bss_ptmsi)) - bss_ptmsi = GSM_RESERVED_TMSI; - } while (bss_ptmsi == GSM_RESERVED_TMSI); - } - - return bss_ptmsi; -} - -static uint32_t gbprox_make_sgsn_tlli(struct gbproxy_peer *peer, - struct gbproxy_tlli_info *tlli_info, - uint32_t bss_tlli) -{ - uint32_t sgsn_tlli; - if (!peer->cfg->patch_ptmsi) { - sgsn_tlli = bss_tlli; - } else if (tlli_info->sgsn_tlli.ptmsi != GSM_RESERVED_TMSI) { - sgsn_tlli = gprs_tmsi2tlli(tlli_info->sgsn_tlli.ptmsi, - TLLI_FOREIGN); - } else { - do { - /* create random TLLI, 0b01111xxx... */ - sgsn_tlli = rand_r(&peer->cfg->sgsn_tlli_state); - sgsn_tlli = (sgsn_tlli & 0x7fffffff) | 0x78000000; - - if (gbprox_find_tlli_by_sgsn_tlli(peer, sgsn_tlli)) - sgsn_tlli = 0; - } while (!sgsn_tlli); - } - return sgsn_tlli; -} - -static struct gbproxy_tlli_info *gbprox_update_state_ul( - struct gbproxy_peer *peer, - time_t now, - struct gbproxy_parse_context *parse_ctx) -{ - struct gbproxy_tlli_info *tlli_info = NULL; - - if (parse_ctx->tlli_enc) - tlli_info = gbprox_find_tlli(peer, parse_ctx->tlli); - - if (parse_ctx->g48_hdr) { - switch (parse_ctx->g48_hdr->msg_type) { - case GSM48_MT_GMM_ATTACH_REQ: - rate_ctr_inc(&peer->ctrg->ctr[GBPROX_PEER_CTR_ATTACH_REQS]); - break; - - default: - break; - } - } - - gbprox_log_parse_context(parse_ctx, "BSSGP"); - - if (parse_ctx->tlli_enc && parse_ctx->llc) { - uint32_t sgsn_tlli; - if (!tlli_info) { - tlli_info = - gbprox_register_tlli(peer, parse_ctx->tlli, - parse_ctx->imsi, - parse_ctx->imsi_len, now); - /* Setup TLLIs */ - sgsn_tlli = gbprox_make_sgsn_tlli(peer, tlli_info, - parse_ctx->tlli); - tlli_info->sgsn_tlli.current = sgsn_tlli; - } else { - sgsn_tlli = gbprox_map_tlli(parse_ctx->tlli, tlli_info, 0); - if (!sgsn_tlli) - sgsn_tlli = gbprox_make_sgsn_tlli(peer, tlli_info, - parse_ctx->tlli); - - gbprox_validate_tlli(&tlli_info->tlli, - parse_ctx->tlli, 0); - gbprox_validate_tlli(&tlli_info->sgsn_tlli, - sgsn_tlli, 0); - gbprox_touch_tlli(peer, tlli_info, now); - } - } else if (tlli_info) { - gbprox_touch_tlli(peer, tlli_info, now); - } - - if (parse_ctx->imsi && tlli_info && tlli_info->mi_data_len == 0) { - int enable_patching; - gbprox_update_tlli_info(tlli_info, - parse_ctx->imsi, parse_ctx->imsi_len); - - /* Check, whether the IMSI matches */ - enable_patching = gbprox_check_imsi(peer, parse_ctx->imsi, - parse_ctx->imsi_len); - if (enable_patching >= 0) - tlli_info->enable_patching = enable_patching; - } - - return tlli_info; -} - -static struct gbproxy_tlli_info *gbprox_update_state_dl( - struct gbproxy_peer *peer, - time_t now, - struct gbproxy_parse_context *parse_ctx) -{ - struct gbproxy_tlli_info *tlli_info = NULL; - - if (parse_ctx->tlli_enc) - tlli_info = gbprox_find_tlli_by_sgsn_tlli(peer, parse_ctx->tlli); - - if (parse_ctx->g48_hdr) { - switch (parse_ctx->g48_hdr->msg_type) { - case GSM48_MT_GMM_ATTACH_REJ: - rate_ctr_inc(&peer->ctrg->ctr[GBPROX_PEER_CTR_ATTACH_REJS]); - break; - - default: - break; - } - } - - gbprox_log_parse_context(parse_ctx, "BSSGP"); - - if (parse_ctx->tlli_enc && parse_ctx->new_ptmsi_enc) { - /* A new PTMSI has been signaled in the message, - * register new TLLI */ - uint32_t new_sgsn_ptmsi; - uint32_t new_sgsn_tlli; - uint32_t new_bss_ptmsi; - uint32_t new_bss_tlli = 0; - if (!parse_mi_tmsi(parse_ctx->new_ptmsi_enc, GSM48_TMSI_LEN, - &new_sgsn_ptmsi)) { - LOGP(DGPRS, LOGL_ERROR, - "Failed to parse new TLLI/PTMSI (current is %08x)\n", - parse_ctx->tlli); - return tlli_info; - } - new_sgsn_tlli = gprs_tmsi2tlli(new_sgsn_ptmsi, TLLI_LOCAL); - new_bss_ptmsi = gbprox_make_bss_ptmsi(peer, new_sgsn_ptmsi); - if (new_bss_ptmsi != GSM_RESERVED_TMSI) - new_bss_tlli = gprs_tmsi2tlli(new_bss_ptmsi, TLLI_LOCAL); - LOGP(DGPRS, LOGL_INFO, - "Got new TLLI(PTMSI) %08x(%08x) from SGSN, using %08x(%08x)\n", - new_sgsn_tlli, new_sgsn_ptmsi, new_bss_tlli, new_bss_ptmsi); - if (tlli_info) { - gbprox_reassign_tlli(&tlli_info->sgsn_tlli, - peer, new_sgsn_tlli); - gbprox_reassign_tlli(&tlli_info->tlli, - peer, new_bss_tlli); - gbprox_touch_tlli(peer, tlli_info, now); - } else { - tlli_info = gbprox_tlli_info_alloc(peer); - LOGP(DGPRS, LOGL_INFO, - "Adding TLLI %08x to list (SGSN, new P-TMSI)\n", - new_sgsn_tlli); - - gbprox_attach_tlli_info(peer, now, tlli_info); - /* Setup TLLIs */ - tlli_info->sgsn_tlli.current = new_sgsn_tlli; - } - /* Setup PTMSIs */ - tlli_info->sgsn_tlli.ptmsi = new_sgsn_ptmsi; - tlli_info->tlli.ptmsi = new_bss_ptmsi; - } else if (parse_ctx->tlli_enc && parse_ctx->llc && !tlli_info) { - /* Unknown SGSN TLLI */ - tlli_info = gbprox_tlli_info_alloc(peer); - LOGP(DGPRS, LOGL_INFO, "Adding TLLI %08x to list (SGSN)\n", - parse_ctx->tlli); - - gbprox_attach_tlli_info(peer, now, tlli_info); - /* Setup TLLIs */ - tlli_info->sgsn_tlli.current = parse_ctx->tlli; - if (peer->cfg->patch_ptmsi) { - /* TODO: We don't know the local TLLI here, perhaps add - * a workaround that derives a PTMSI from the SGSN TLLI - * and use that to get the missing values. This may - * only happen when the gbproxy has been restarted or a - * tlli_info has been discarded due to age or queue - * length. - */ - tlli_info->tlli.current = 0; - } else { - tlli_info->tlli.current = tlli_info->sgsn_tlli.current; - } - } else if (parse_ctx->tlli_enc && parse_ctx->llc && tlli_info) { - uint32_t bss_tlli = gbprox_map_tlli(parse_ctx->tlli, - tlli_info, 1); - gbprox_validate_tlli(&tlli_info->sgsn_tlli, parse_ctx->tlli, 1); - gbprox_validate_tlli(&tlli_info->tlli, bss_tlli, 1); - gbprox_touch_tlli(peer, tlli_info, now); - } else if (tlli_info) { - gbprox_touch_tlli(peer, tlli_info, now); - } - - if (parse_ctx->imsi && tlli_info && tlli_info->mi_data_len == 0) { - int enable_patching; - gbprox_update_tlli_info(tlli_info, - parse_ctx->imsi, parse_ctx->imsi_len); - - /* Check, whether the IMSI matches */ - enable_patching = gbprox_check_imsi(peer, parse_ctx->imsi, - parse_ctx->imsi_len); - if (enable_patching >= 0) - tlli_info->enable_patching = enable_patching; - } - - return tlli_info; -} - -static void gbprox_update_state_after(struct gbproxy_peer *peer, - struct gbproxy_tlli_info *tlli_info, - time_t now, - struct gbproxy_parse_context *parse_ctx) -{ - if (parse_ctx->invalidate_tlli) - gbprox_unregister_tlli(peer, parse_ctx->tlli); - - gbprox_remove_stale_tllis(peer, now); -} - -static int gbprox_parse_bssgp(uint8_t *bssgp, size_t bssgp_len, - struct gbproxy_parse_context *parse_ctx) -{ - struct bssgp_normal_hdr *bgph; - struct bssgp_ud_hdr *budh = NULL; - struct tlv_parsed *tp = &parse_ctx->bssgp_tp; - uint8_t pdu_type; - uint8_t *data; - size_t data_len; - int rc; - - if (bssgp_len < sizeof(struct bssgp_normal_hdr)) - return 0; - - bgph = (struct bssgp_normal_hdr *)bssgp; - pdu_type = bgph->pdu_type; - - if (pdu_type == BSSGP_PDUT_UL_UNITDATA || - pdu_type == BSSGP_PDUT_DL_UNITDATA) { - if (bssgp_len < sizeof(struct bssgp_ud_hdr)) - return 0; - budh = (struct bssgp_ud_hdr *)bssgp; - bgph = NULL; - data = budh->data; - data_len = bssgp_len - sizeof(*budh); - } else { - data = bgph->data; - data_len = bssgp_len - sizeof(*bgph); - } - - if (bssgp_tlv_parse(tp, data, data_len) < 0) - return 0; - - parse_ctx->pdu_type = pdu_type; - parse_ctx->bud_hdr = budh; - parse_ctx->bgp_hdr = bgph; - parse_ctx->bssgp_data = data; - parse_ctx->bssgp_data_len = data_len; - - if (budh) - parse_ctx->tlli_enc = (uint8_t *)&budh->tlli; - - if (TLVP_PRESENT(tp, BSSGP_IE_ROUTEING_AREA)) - parse_ctx->bssgp_raid_enc = (uint8_t *)TLVP_VAL(tp, BSSGP_IE_ROUTEING_AREA); - - if (TLVP_PRESENT(tp, BSSGP_IE_CELL_ID)) - parse_ctx->bssgp_raid_enc = (uint8_t *)TLVP_VAL(tp, BSSGP_IE_CELL_ID); - - if (TLVP_PRESENT(tp, BSSGP_IE_IMSI)) { - parse_ctx->imsi = (uint8_t *)TLVP_VAL(tp, BSSGP_IE_IMSI); - parse_ctx->imsi_len = TLVP_LEN(tp, BSSGP_IE_IMSI); - } - - /* TODO: This is TLLI old, don't confuse with TLLI current, add - * and use tlli_old_enc instead */ - if (0 && TLVP_PRESENT(tp, BSSGP_IE_TLLI)) - parse_ctx->tlli_enc = (uint8_t *)TLVP_VAL(tp, BSSGP_IE_TLLI); - - if (TLVP_PRESENT(tp, BSSGP_IE_TMSI) && pdu_type == BSSGP_PDUT_PAGING_PS) - parse_ctx->ptmsi_enc = (uint8_t *)TLVP_VAL(tp, BSSGP_IE_TMSI); - - if (TLVP_PRESENT(tp, BSSGP_IE_LLC_PDU)) { - uint8_t *llc = (uint8_t *)TLVP_VAL(tp, BSSGP_IE_LLC_PDU); - size_t llc_len = TLVP_LEN(tp, BSSGP_IE_LLC_PDU); - - rc = gbprox_parse_llc(llc, llc_len, parse_ctx); - if (!rc) - return 0; - - parse_ctx->llc = llc; - parse_ctx->llc_len = llc_len; - } - - if (parse_ctx->tlli_enc) { - uint32_t tmp_tlli; - memcpy(&tmp_tlli, parse_ctx->tlli_enc, sizeof(tmp_tlli)); - parse_ctx->tlli = ntohl(tmp_tlli); - } - - return 1; -} - -/* patch BSSGP message to use core_mcc/mnc on the SGSN side */ -static void gbprox_patch_bssgp(struct msgb *msg, uint8_t *bssgp, size_t bssgp_len, - struct gbproxy_peer *peer, - struct gbproxy_tlli_info *tlli_info, int *len_change, - struct gbproxy_parse_context *parse_ctx) - __attribute__((nonnull)); -static void gbprox_patch_bssgp(struct msgb *msg, uint8_t *bssgp, size_t bssgp_len, - struct gbproxy_peer *peer, - struct gbproxy_tlli_info *tlli_info, int *len_change, - struct gbproxy_parse_context *parse_ctx) -{ - const char *err_info = NULL; - int err_ctr = -1; - - if (!patching_is_enabled(peer, GBPROX_PATCH_BSSGP)) - return; - - if (parse_ctx->bssgp_raid_enc) - gbprox_patch_raid(parse_ctx->bssgp_raid_enc, peer, - parse_ctx->to_bss, "BSSGP"); - - if (!patching_is_enabled(peer, GBPROX_PATCH_LLC_ATTACH_REQ)) - return; - - if (parse_ctx->need_decryption && - patching_is_required(peer, GBPROX_PATCH_LLC_ATTACH)) { - /* Patching LLC messages has been requested - * explicitly, but the message (including the - * type) is encrypted, so we possibly fail to - * patch the LLC part of the message. */ - err_ctr = GBPROX_PEER_CTR_PATCH_CRYPT_ERR; - err_info = "GMM message is encrypted"; - goto patch_error; - } - - if (parse_ctx->tlli_enc && tlli_info) { - uint32_t tlli = gbprox_map_tlli(parse_ctx->tlli, - tlli_info, parse_ctx->to_bss); - - if (tlli) { - gbprox_patch_tlli(parse_ctx->tlli_enc, peer, tlli, - parse_ctx->to_bss, "TLLI"); - parse_ctx->tlli = tlli; - } else if (parse_ctx->to_bss) { - /* Happens with unknown (not cached) TLLI coming from - * the SGSN */ - /* TODO: What shall be done with the message in this case? */ - err_ctr = GBPROX_PEER_CTR_TLLI_UNKNOWN; - err_info = "TLLI sent by the SGSN is unknown"; - goto patch_error; - } else { - /* Internal error */ - err_ctr = GBPROX_PEER_CTR_PATCH_ERR; - err_info = "Replacement TLLI is 0"; - goto patch_error; - } - } - - if (parse_ctx->llc) { - uint8_t *llc = parse_ctx->llc; - size_t llc_len = parse_ctx->llc_len; - int llc_len_change = 0; - - gbprox_patch_llc(msg, llc, llc_len, peer, tlli_info, - &llc_len_change, parse_ctx); - /* Note that the APN might have been resized here, but no - * pointer int the parse_ctx will refer to an adress after the - * APN. So it's possible to patch first and do the TLLI - * handling afterwards. */ - - if (llc_len_change) { - llc_len += llc_len_change; - - /* Fix LLC IE len */ - /* TODO: This is a kludge, but the a pointer to the - * start of the IE is not available here */ - if (llc[-2] == BSSGP_IE_LLC_PDU && llc[-1] & 0x80) { - /* most probably a one byte length */ - if (llc_len > 127) { - err_info = "Cannot increase size"; - err_ctr = GBPROX_PEER_CTR_PATCH_ERR; - goto patch_error; - } - llc[-1] = llc_len | 0x80; - } else { - llc[-2] = (llc_len >> 8) & 0x7f; - llc[-1] = llc_len & 0xff; - } - *len_change += llc_len_change; - } - /* Note that the tp struct might contain invalid pointers here - * if the LLC field has changed its size */ - parse_ctx->llc_len = llc_len; - } - return; - -patch_error: - OSMO_ASSERT(err_ctr >= 0); - rate_ctr_inc(&peer->ctrg->ctr[err_ctr]); - LOGP(DGPRS, LOGL_ERROR, - "NSEI=%u(%s) failed to patch BSSGP message as requested: %s.\n", - msgb_nsei(msg), parse_ctx->to_bss ? "SGSN" : "BSS", - err_info); -} - -/* patch BSSGP message */ -static void gbprox_process_bssgp_ul(struct gbproxy_config *cfg, - struct msgb *msg, - struct gbproxy_peer *peer) -{ - struct gbproxy_parse_context parse_ctx = {0}; - int rc; - int len_change = 0; - time_t now; - struct gbproxy_tlli_info *tlli_info = NULL; - - if (!cfg->core_mcc && !cfg->core_mnc && !cfg->core_apn) - return; - - parse_ctx.to_bss = 0; - - /* Parse BSSGP/LLC */ - rc = gbprox_parse_bssgp(msgb_bssgph(msg), msgb_bssgp_len(msg), - &parse_ctx); - - if (!rc) { - if (!parse_ctx.need_decryption) { - LOGP(DGPRS, LOGL_ERROR, - "NSEI=%u(BSS) patching: " - "failed to parse BSSGP/GMM message\n", - msgb_nsei(msg)); - return; - } - } - - /* Get peer */ - if (!peer && msgb_bvci(msg) >= 2) - peer = peer_by_bvci(cfg, msgb_bvci(msg)); - - if (!peer) - peer = gbprox_peer_by_nsei(cfg, msgb_nsei(msg)); - - if (!peer) - peer = peer_by_bssgp_tlv(cfg, &parse_ctx.bssgp_tp); - - if (!peer) { - LOGP(DLLC, LOGL_INFO, - "NSEI=%d(BSS) patching: didn't find peer for message, " - "PDU %d\n", - msgb_nsei(msg), parse_ctx.pdu_type); - /* Increment counter */ - rate_ctr_inc(&cfg->ctrg->ctr[GBPROX_GLOB_CTR_PATCH_PEER_ERR]); - return; - } - - now = time(NULL); - - if (parse_ctx.bssgp_raid_enc && parse_ctx.old_raid_enc && - memcmp(parse_ctx.bssgp_raid_enc, parse_ctx.old_raid_enc, 6) == 0) - parse_ctx.old_raid_matches = 1; - - gbprox_update_current_raid(parse_ctx.bssgp_raid_enc, peer, - parse_ctx.llc_msg_name); - - tlli_info = gbprox_update_state_ul(peer, now, &parse_ctx); - - gbprox_patch_bssgp(msg, msgb_bssgph(msg), msgb_bssgp_len(msg), - peer, tlli_info, &len_change, &parse_ctx); - - gbprox_update_state_after(peer, tlli_info, now, &parse_ctx); - - return; -} - -/* patch BSSGP message to use core_mcc/mnc on the SGSN side */ -static void gbprox_process_bssgp_dl(struct gbproxy_config *cfg, - struct msgb *msg, - struct gbproxy_peer *peer) -{ - struct gbproxy_parse_context parse_ctx = {0}; - int rc; - int len_change = 0; - time_t now; - struct gbproxy_tlli_info *tlli_info = NULL; - - parse_ctx.to_bss = 1; - - rc = gbprox_parse_bssgp(msgb_bssgph(msg), msgb_bssgp_len(msg), - &parse_ctx); - - if (!rc) { - if (!parse_ctx.need_decryption) { - LOGP(DGPRS, LOGL_ERROR, - "NSEI=%u(SGSN) patching: " - "failed to parse BSSGP/GMM message\n", - msgb_nsei(msg)); - return; - } - } - - if (!peer && msgb_bvci(msg) >= 2) - peer = peer_by_bvci(cfg, msgb_bvci(msg)); - - if (!peer) - peer = peer_by_bssgp_tlv(cfg, &parse_ctx.bssgp_tp); - - if (!peer) { - LOGP(DLLC, LOGL_INFO, - "NSEI=%d(SGSN) patching: didn't find peer for message, " - "PDU %d\n", - msgb_nsei(msg), parse_ctx.pdu_type); - /* Increment counter */ - rate_ctr_inc(&cfg->ctrg->ctr[GBPROX_GLOB_CTR_PATCH_PEER_ERR]); - return; - } - - now = time(NULL); + gprs_gb_log_parse_context(&parse_ctx, "BSSGP"); - tlli_info = gbprox_update_state_dl(peer, now, &parse_ctx); + tlli_info = gbproxy_update_tlli_state_dl(peer, now, &parse_ctx); - gbprox_patch_bssgp(msg, msgb_bssgph(msg), msgb_bssgp_len(msg), - peer, tlli_info, &len_change, &parse_ctx); + gbproxy_patch_bssgp(msg, msgb_bssgph(msg), msgb_bssgp_len(msg), + peer, tlli_info, &len_change, &parse_ctx); - gbprox_update_state_after(peer, tlli_info, now, &parse_ctx); + gbproxy_update_tlli_state_after(peer, tlli_info, now, &parse_ctx); return; } diff --git a/openbsc/src/gprs/gb_proxy_patch.c b/openbsc/src/gprs/gb_proxy_patch.c new file mode 100644 index 000000000..59d0b2f2b --- /dev/null +++ b/openbsc/src/gprs/gb_proxy_patch.c @@ -0,0 +1,475 @@ +/* Gb-proxy message patching */ + +/* (C) 2014 by On-Waves + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +#include + +#include +#include + +#include +#include +#include + +#include +#include + +/* check whether patching is enabled at this level */ +static int patching_is_enabled(struct gbproxy_peer *peer, + enum gbproxy_patch_mode need_at_least) +{ + enum gbproxy_patch_mode patch_mode = peer->cfg->patch_mode; + if (patch_mode == GBPROX_PATCH_DEFAULT) + patch_mode = GBPROX_PATCH_LLC; + + return need_at_least <= patch_mode; +} + +/* check whether patching is enabled at this level */ +static int patching_is_required(struct gbproxy_peer *peer, + enum gbproxy_patch_mode need_at_least) +{ + return need_at_least <= peer->cfg->patch_mode; +} + +static int allow_message_patching(struct gbproxy_peer *peer, int msg_type) +{ + if (msg_type >= GSM48_MT_GSM_ACT_PDP_REQ) { + return patching_is_enabled(peer, GBPROX_PATCH_LLC_GSM); + } else if (msg_type > GSM48_MT_GMM_ATTACH_REJ) { + return patching_is_enabled(peer, GBPROX_PATCH_LLC); + } else if (msg_type > GSM48_MT_GMM_ATTACH_REQ) { + return patching_is_enabled(peer, GBPROX_PATCH_LLC_ATTACH); + } else { + return patching_is_enabled(peer, GBPROX_PATCH_LLC_ATTACH_REQ); + } +} + +/* patch RA identifier in place */ +static void gbproxy_patch_raid(uint8_t *raid_enc, struct gbproxy_peer *peer, + int to_bss, const char *log_text) +{ + struct gbproxy_patch_state *state = &peer->patch_state; + int old_mcc; + int old_mnc; + struct gprs_ra_id raid; + + gsm48_parse_ra(&raid, raid_enc); + + old_mcc = raid.mcc; + old_mnc = raid.mnc; + + if (!to_bss) { + /* BSS -> SGSN */ + if (state->local_mcc) + raid.mcc = peer->cfg->core_mcc; + + if (state->local_mnc) + raid.mnc = peer->cfg->core_mnc; + } else { + /* SGSN -> BSS */ + if (state->local_mcc) + raid.mcc = state->local_mcc; + + if (state->local_mnc) + raid.mnc = state->local_mnc; + } + + if (state->local_mcc || state->local_mnc) { + enum gbproxy_peer_ctr counter = + to_bss ? + GBPROX_PEER_CTR_RAID_PATCHED_SGSN : + GBPROX_PEER_CTR_RAID_PATCHED_BSS; + + LOGP(DGPRS, LOGL_DEBUG, + "Patching %s to %s: " + "%d-%d-%d-%d -> %d-%d-%d-%d\n", + log_text, + to_bss ? "BSS" : "SGSN", + old_mcc, old_mnc, raid.lac, raid.rac, + raid.mcc, raid.mnc, raid.lac, raid.rac); + + gsm48_construct_ra(raid_enc, &raid); + rate_ctr_inc(&peer->ctrg->ctr[counter]); + } +} + +static void gbproxy_patch_apn_ie(struct msgb *msg, + uint8_t *apn_ie, size_t apn_ie_len, + struct gbproxy_peer *peer, + size_t *new_apn_ie_len, const char *log_text) +{ + struct apn_ie_hdr { + uint8_t iei; + uint8_t apn_len; + uint8_t apn[0]; + } *hdr = (void *)apn_ie; + + size_t apn_len = hdr->apn_len; + uint8_t *apn = hdr->apn; + + OSMO_ASSERT(apn_ie_len == apn_len + sizeof(struct apn_ie_hdr)); + OSMO_ASSERT(apn_ie_len > 2 && apn_ie_len <= 102); + + if (peer->cfg->core_apn_size == 0) { + char str1[110]; + /* Remove the IE */ + LOGP(DGPRS, LOGL_DEBUG, + "Patching %s to SGSN: Removing APN '%s'\n", + log_text, + gprs_apn_to_str(str1, apn, apn_len)); + + *new_apn_ie_len = 0; + gprs_msgb_resize_area(msg, apn_ie, apn_ie_len, 0); + } else { + /* Resize the IE */ + char str1[110]; + char str2[110]; + + OSMO_ASSERT(peer->cfg->core_apn_size <= 100); + + LOGP(DGPRS, LOGL_DEBUG, + "Patching %s to SGSN: " + "Replacing APN '%s' -> '%s'\n", + log_text, + gprs_apn_to_str(str1, apn, apn_len), + gprs_apn_to_str(str2, peer->cfg->core_apn, + peer->cfg->core_apn_size)); + + *new_apn_ie_len = peer->cfg->core_apn_size + 2; + gprs_msgb_resize_area(msg, apn, apn_len, peer->cfg->core_apn_size); + memcpy(apn, peer->cfg->core_apn, peer->cfg->core_apn_size); + hdr->apn_len = peer->cfg->core_apn_size; + } + + rate_ctr_inc(&peer->ctrg->ctr[GBPROX_PEER_CTR_APN_PATCHED]); +} + +static int gbproxy_patch_tlli(uint8_t *tlli_enc, + struct gbproxy_peer *peer, + uint32_t new_tlli, + int to_bss, const char *log_text) +{ + uint32_t tlli_be; + uint32_t tlli; + enum gbproxy_peer_ctr counter = + to_bss ? + GBPROX_PEER_CTR_TLLI_PATCHED_SGSN : + GBPROX_PEER_CTR_TLLI_PATCHED_BSS; + + memcpy(&tlli_be, tlli_enc, sizeof(tlli_be)); + tlli = ntohl(tlli_be); + + if (tlli == new_tlli) + return 0; + + LOGP(DGPRS, LOGL_DEBUG, + "Patching %ss: " + "Replacing %08x -> %08x\n", + log_text, tlli, new_tlli); + + tlli_be = htonl(new_tlli); + memcpy(tlli_enc, &tlli_be, sizeof(tlli_be)); + + rate_ctr_inc(&peer->ctrg->ctr[counter]); + + return 1; +} + +static int gbproxy_patch_ptmsi(uint8_t *ptmsi_enc, + struct gbproxy_peer *peer, + uint32_t new_ptmsi, + int to_bss, const char *log_text) +{ + uint32_t ptmsi_be; + uint32_t ptmsi; + enum gbproxy_peer_ctr counter = + to_bss ? + GBPROX_PEER_CTR_PTMSI_PATCHED_SGSN : + GBPROX_PEER_CTR_PTMSI_PATCHED_BSS; + memcpy(&ptmsi_be, ptmsi_enc + 1, sizeof(ptmsi_be)); + ptmsi = ntohl(ptmsi_be); + + if (ptmsi == new_ptmsi) + return 0; + + LOGP(DGPRS, LOGL_DEBUG, + "Patching %ss: " + "Replacing %08x -> %08x\n", + log_text, ptmsi, new_ptmsi); + + ptmsi_be = htonl(new_ptmsi); + memcpy(ptmsi_enc + 1, &ptmsi_be, sizeof(ptmsi_be)); + + rate_ctr_inc(&peer->ctrg->ctr[counter]); + + return 1; +} + +int gbproxy_patch_llc(struct msgb *msg, uint8_t *llc, size_t llc_len, + struct gbproxy_peer *peer, + struct gbproxy_tlli_info *tlli_info, int *len_change, + struct gprs_gb_parse_context *parse_ctx) +{ + struct gprs_llc_hdr_parsed *ghp = &parse_ctx->llc_hdr_parsed; + int have_patched = 0; + int fcs; + + if (parse_ctx->g48_hdr && !allow_message_patching(peer, parse_ctx->g48_hdr->msg_type)) + return have_patched; + + if (parse_ctx->ptmsi_enc && tlli_info) { + uint32_t ptmsi; + if (parse_ctx->to_bss) + ptmsi = tlli_info->tlli.ptmsi; + else + ptmsi = tlli_info->sgsn_tlli.ptmsi; + + if (ptmsi != GSM_RESERVED_TMSI) { + if (gbproxy_patch_ptmsi(parse_ctx->ptmsi_enc, peer, + ptmsi, parse_ctx->to_bss, "P-TMSI")) + have_patched = 1; + } else { + /* TODO: invalidate old RAI if present (see below) */ + } + } + + if (parse_ctx->new_ptmsi_enc && tlli_info) { + uint32_t ptmsi; + if (parse_ctx->to_bss) + ptmsi = tlli_info->tlli.ptmsi; + else + ptmsi = tlli_info->sgsn_tlli.ptmsi; + + OSMO_ASSERT(ptmsi); + if (gbproxy_patch_ptmsi(parse_ctx->new_ptmsi_enc, peer, + ptmsi, parse_ctx->to_bss, "new P-TMSI")) + have_patched = 1; + } + + if (parse_ctx->raid_enc) { + gbproxy_patch_raid(parse_ctx->raid_enc, peer, parse_ctx->to_bss, + parse_ctx->llc_msg_name); + have_patched = 1; + } + + if (parse_ctx->old_raid_enc && parse_ctx->old_raid_matches) { + /* TODO: Patch to invalid if P-TMSI unknown. */ + gbproxy_patch_raid(parse_ctx->old_raid_enc, peer, parse_ctx->to_bss, + parse_ctx->llc_msg_name); + have_patched = 1; + } + + if (parse_ctx->apn_ie && + peer->cfg->core_apn && + !parse_ctx->to_bss && + gbproxy_check_tlli(peer, parse_ctx->tlli)) { + size_t new_len; + gbproxy_patch_apn_ie(msg, + parse_ctx->apn_ie, parse_ctx->apn_ie_len, + peer, &new_len, parse_ctx->llc_msg_name); + *len_change += (int)new_len - (int)parse_ctx->apn_ie_len; + + have_patched = 1; + } + + if (have_patched) { + llc_len += *len_change; + ghp->crc_length += *len_change; + + /* Fix FCS */ + fcs = gprs_llc_fcs(llc, ghp->crc_length); + LOGP(DLLC, LOGL_DEBUG, "Updated LLC message, CRC: %06x -> %06x\n", + ghp->fcs, fcs); + + llc[llc_len - 3] = fcs & 0xff; + llc[llc_len - 2] = (fcs >> 8) & 0xff; + llc[llc_len - 1] = (fcs >> 16) & 0xff; + } + + return have_patched; +} + +/* patch BSSGP message to use core_mcc/mnc on the SGSN side */ +void gbproxy_patch_bssgp(struct msgb *msg, uint8_t *bssgp, size_t bssgp_len, + struct gbproxy_peer *peer, + struct gbproxy_tlli_info *tlli_info, int *len_change, + struct gprs_gb_parse_context *parse_ctx) +{ + const char *err_info = NULL; + int err_ctr = -1; + + if (!patching_is_enabled(peer, GBPROX_PATCH_BSSGP)) + return; + + if (parse_ctx->bssgp_raid_enc) + gbproxy_patch_raid(parse_ctx->bssgp_raid_enc, peer, + parse_ctx->to_bss, "BSSGP"); + + if (!patching_is_enabled(peer, GBPROX_PATCH_LLC_ATTACH_REQ)) + return; + + if (parse_ctx->need_decryption && + patching_is_required(peer, GBPROX_PATCH_LLC_ATTACH)) { + /* Patching LLC messages has been requested + * explicitly, but the message (including the + * type) is encrypted, so we possibly fail to + * patch the LLC part of the message. */ + err_ctr = GBPROX_PEER_CTR_PATCH_CRYPT_ERR; + err_info = "GMM message is encrypted"; + goto patch_error; + } + + if (parse_ctx->tlli_enc && tlli_info) { + uint32_t tlli = gbproxy_map_tlli(parse_ctx->tlli, + tlli_info, parse_ctx->to_bss); + + if (tlli) { + gbproxy_patch_tlli(parse_ctx->tlli_enc, peer, tlli, + parse_ctx->to_bss, "TLLI"); + parse_ctx->tlli = tlli; + } else if (parse_ctx->to_bss) { + /* Happens with unknown (not cached) TLLI coming from + * the SGSN */ + /* TODO: What shall be done with the message in this case? */ + err_ctr = GBPROX_PEER_CTR_TLLI_UNKNOWN; + err_info = "TLLI sent by the SGSN is unknown"; + goto patch_error; + } else { + /* Internal error */ + err_ctr = GBPROX_PEER_CTR_PATCH_ERR; + err_info = "Replacement TLLI is 0"; + goto patch_error; + } + } + + if (parse_ctx->llc) { + uint8_t *llc = parse_ctx->llc; + size_t llc_len = parse_ctx->llc_len; + int llc_len_change = 0; + + gbproxy_patch_llc(msg, llc, llc_len, peer, tlli_info, + &llc_len_change, parse_ctx); + /* Note that the APN might have been resized here, but no + * pointer int the parse_ctx will refer to an adress after the + * APN. So it's possible to patch first and do the TLLI + * handling afterwards. */ + + if (llc_len_change) { + llc_len += llc_len_change; + + /* Fix LLC IE len */ + /* TODO: This is a kludge, but the a pointer to the + * start of the IE is not available here */ + if (llc[-2] == BSSGP_IE_LLC_PDU && llc[-1] & 0x80) { + /* most probably a one byte length */ + if (llc_len > 127) { + err_info = "Cannot increase size"; + err_ctr = GBPROX_PEER_CTR_PATCH_ERR; + goto patch_error; + } + llc[-1] = llc_len | 0x80; + } else { + llc[-2] = (llc_len >> 8) & 0x7f; + llc[-1] = llc_len & 0xff; + } + *len_change += llc_len_change; + } + /* Note that the tp struct might contain invalid pointers here + * if the LLC field has changed its size */ + parse_ctx->llc_len = llc_len; + } + return; + +patch_error: + OSMO_ASSERT(err_ctr >= 0); + rate_ctr_inc(&peer->ctrg->ctr[err_ctr]); + LOGP(DGPRS, LOGL_ERROR, + "NSEI=%u(%s) failed to patch BSSGP message as requested: %s.\n", + msgb_nsei(msg), parse_ctx->to_bss ? "SGSN" : "BSS", + err_info); +} + +void gbproxy_clear_patch_filter(struct gbproxy_config *cfg) +{ + if (cfg->check_imsi) { + regfree(&cfg->imsi_re_comp); + cfg->check_imsi = 0; + } +} + +int gbproxy_set_patch_filter(struct gbproxy_config *cfg, const char *filter, + const char **err_msg) +{ + static char err_buf[300]; + int rc; + + gbproxy_clear_patch_filter(cfg); + + if (!filter) + return 0; + + rc = regcomp(&cfg->imsi_re_comp, filter, + REG_EXTENDED | REG_NOSUB | REG_ICASE); + + if (rc == 0) { + cfg->check_imsi = 1; + return 0; + } + + if (err_msg) { + regerror(rc, &cfg->imsi_re_comp, + err_buf, sizeof(err_buf)); + *err_msg = err_buf; + } + + return -1; +} + +int gbproxy_check_imsi(struct gbproxy_peer *peer, + const uint8_t *imsi, size_t imsi_len) +{ + char mi_buf[200]; + int rc; + + if (!peer->cfg->check_imsi) + return 1; + + rc = gprs_is_mi_imsi(imsi, imsi_len); + if (rc > 0) + rc = gsm48_mi_to_string(mi_buf, sizeof(mi_buf), imsi, imsi_len); + if (rc <= 0) { + LOGP(DGPRS, LOGL_NOTICE, "Invalid IMSI %s\n", + osmo_hexdump(imsi, imsi_len)); + return -1; + } + + LOGP(DGPRS, LOGL_DEBUG, "Checking IMSI '%s' (%d)\n", mi_buf, rc); + + rc = regexec(&peer->cfg->imsi_re_comp, mi_buf, 0, NULL, 0); + if (rc == REG_NOMATCH) { + LOGP(DGPRS, LOGL_INFO, + "IMSI '%s' doesn't match pattern '%s'\n", + mi_buf, peer->cfg->match_re); + return 0; + } + + return 1; +} + diff --git a/openbsc/src/gprs/gb_proxy_tlli.c b/openbsc/src/gprs/gb_proxy_tlli.c new file mode 100644 index 000000000..ccd118ed5 --- /dev/null +++ b/openbsc/src/gprs/gb_proxy_tlli.c @@ -0,0 +1,544 @@ +/* Gb-proxy TLLI state handling */ + +/* (C) 2014 by On-Waves + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +#include + +#include +#include + +#include +#include + +#include + +#include +#include + +struct gbproxy_tlli_info *gbproxy_find_tlli(struct gbproxy_peer *peer, + uint32_t tlli) +{ + struct gbproxy_tlli_info *tlli_info; + struct gbproxy_patch_state *state = &peer->patch_state; + + llist_for_each_entry(tlli_info, &state->enabled_tllis, list) + if (tlli_info->tlli.current == tlli || + tlli_info->tlli.assigned == tlli) + return tlli_info; + + return NULL; +} + +struct gbproxy_tlli_info *gbproxy_find_tlli_by_ptmsi( + struct gbproxy_peer *peer, + uint32_t ptmsi) +{ + struct gbproxy_tlli_info *tlli_info; + struct gbproxy_patch_state *state = &peer->patch_state; + + llist_for_each_entry(tlli_info, &state->enabled_tllis, list) + if (tlli_info->tlli.ptmsi == ptmsi) + return tlli_info; + + return NULL; +} + +struct gbproxy_tlli_info *gbproxy_find_tlli_by_sgsn_tlli( + struct gbproxy_peer *peer, + uint32_t tlli) +{ + struct gbproxy_tlli_info *tlli_info; + struct gbproxy_patch_state *state = &peer->patch_state; + + llist_for_each_entry(tlli_info, &state->enabled_tllis, list) + if (tlli_info->sgsn_tlli.current == tlli || + tlli_info->sgsn_tlli.assigned == tlli) + return tlli_info; + + return NULL; +} + +struct gbproxy_tlli_info *gbproxy_find_tlli_by_mi( + struct gbproxy_peer *peer, + const uint8_t *mi_data, + size_t mi_data_len) +{ + struct gbproxy_tlli_info *tlli_info; + struct gbproxy_patch_state *state = &peer->patch_state; + + if (!gprs_is_mi_imsi(mi_data, mi_data_len)) + return NULL; + + llist_for_each_entry(tlli_info, &state->enabled_tllis, list) { + if (tlli_info->mi_data_len != mi_data_len) + continue; + if (memcmp(tlli_info->mi_data, mi_data, mi_data_len) != 0) + continue; + + return tlli_info; + } + + return NULL; +} + +void gbproxy_delete_tlli(struct gbproxy_peer *peer, + struct gbproxy_tlli_info *tlli_info) +{ + struct gbproxy_patch_state *state = &peer->patch_state; + + llist_del(&tlli_info->list); + talloc_free(tlli_info); + state->enabled_tllis_count -= 1; + + peer->ctrg->ctr[GBPROX_PEER_CTR_TLLI_CACHE_SIZE].current = + state->enabled_tllis_count; +} + +void gbproxy_delete_tllis(struct gbproxy_peer *peer) +{ + struct gbproxy_tlli_info *tlli_info, *nxt; + struct gbproxy_patch_state *state = &peer->patch_state; + + llist_for_each_entry_safe(tlli_info, nxt, &state->enabled_tllis, list) + gbproxy_delete_tlli(peer, tlli_info); + + OSMO_ASSERT(state->enabled_tllis_count == 0); + OSMO_ASSERT(llist_empty(&state->enabled_tllis)); +} + +static void gbproxy_attach_tlli_info(struct gbproxy_peer *peer, time_t now, + struct gbproxy_tlli_info *tlli_info) +{ + struct gbproxy_patch_state *state = &peer->patch_state; + + tlli_info->timestamp = now; + llist_add(&tlli_info->list, &state->enabled_tllis); + state->enabled_tllis_count += 1; + + peer->ctrg->ctr[GBPROX_PEER_CTR_TLLI_CACHE_SIZE].current = + state->enabled_tllis_count; +} + +int gbproxy_remove_stale_tllis(struct gbproxy_peer *peer, time_t now) +{ + struct gbproxy_patch_state *state = &peer->patch_state; + int exceeded_max_len = 0; + int deleted_count = 0; + int check_for_age; + + if (peer->cfg->tlli_max_len > 0) + exceeded_max_len = + state->enabled_tllis_count - peer->cfg->tlli_max_len; + + check_for_age = peer->cfg->tlli_max_age > 0; + + for (; exceeded_max_len > 0; exceeded_max_len--) { + struct gbproxy_tlli_info *tlli_info; + OSMO_ASSERT(!llist_empty(&state->enabled_tllis)); + tlli_info = llist_entry(state->enabled_tllis.prev, + struct gbproxy_tlli_info, + list); + LOGP(DGPRS, LOGL_INFO, + "Removing TLLI %08x from list " + "(stale, length %d, max_len exceeded)\n", + tlli_info->tlli.current, state->enabled_tllis_count); + + gbproxy_delete_tlli(peer, tlli_info); + deleted_count += 1; + } + + while (check_for_age && !llist_empty(&state->enabled_tllis)) { + time_t age; + struct gbproxy_tlli_info *tlli_info; + tlli_info = llist_entry(state->enabled_tllis.prev, + struct gbproxy_tlli_info, + list); + age = now - tlli_info->timestamp; + /* age < 0 only happens after system time jumps, discard entry */ + if (age <= peer->cfg->tlli_max_age && age >= 0) { + check_for_age = 0; + continue; + } + + LOGP(DGPRS, LOGL_INFO, + "Removing TLLI %08x from list " + "(stale, age %d, max_age exceeded)\n", + tlli_info->tlli.current, (int)age); + + gbproxy_delete_tlli(peer, tlli_info); + deleted_count += 1; + } + + return deleted_count; +} + +static struct gbproxy_tlli_info *gbproxy_tlli_info_alloc( + struct gbproxy_peer *peer) +{ + struct gbproxy_tlli_info *tlli_info; + + tlli_info = talloc_zero(peer, struct gbproxy_tlli_info); + tlli_info->tlli.ptmsi = GSM_RESERVED_TMSI; + tlli_info->sgsn_tlli.ptmsi = GSM_RESERVED_TMSI; + + return tlli_info; +} + +static void gbproxy_detach_tlli_info( + struct gbproxy_peer *peer, + struct gbproxy_tlli_info *tlli_info) +{ + struct gbproxy_patch_state *state = &peer->patch_state; + + llist_del(&tlli_info->list); + OSMO_ASSERT(state->enabled_tllis_count > 0); + state->enabled_tllis_count -= 1; + + peer->ctrg->ctr[GBPROX_PEER_CTR_TLLI_CACHE_SIZE].current = + state->enabled_tllis_count; +} + +static void gbproxy_update_tlli_info(struct gbproxy_tlli_info *tlli_info, + const uint8_t *imsi, size_t imsi_len) +{ + if (!gprs_is_mi_imsi(imsi, imsi_len)) + return; + + tlli_info->mi_data_len = imsi_len; + tlli_info->mi_data = + talloc_realloc_size(tlli_info, tlli_info->mi_data, imsi_len); + OSMO_ASSERT(tlli_info->mi_data != NULL); + memcpy(tlli_info->mi_data, imsi, imsi_len); +} + +void gbproxy_reassign_tlli(struct gbproxy_tlli_state *tlli_state, + struct gbproxy_peer *peer, uint32_t new_tlli) +{ + if (new_tlli == tlli_state->current) + return; + + LOGP(DGPRS, LOGL_INFO, + "The TLLI has been reassigned from %08x to %08x\n", + tlli_state->current, new_tlli); + + /* Remember assigned TLLI */ + tlli_state->assigned = new_tlli; + tlli_state->bss_validated = 0; + tlli_state->net_validated = 0; +} + +uint32_t gbproxy_map_tlli(uint32_t other_tlli, + struct gbproxy_tlli_info *tlli_info, int to_bss) +{ + uint32_t tlli = 0; + struct gbproxy_tlli_state *src, *dst; + if (to_bss) { + src = &tlli_info->sgsn_tlli; + dst = &tlli_info->tlli; + } else { + src = &tlli_info->tlli; + dst = &tlli_info->sgsn_tlli; + } + if (src->current == other_tlli) + tlli = dst->current; + else if (src->assigned == other_tlli) + tlli = dst->assigned; + + return tlli; +} + +static void gbproxy_validate_tlli(struct gbproxy_tlli_state *tlli_state, + uint32_t tlli, int to_bss) +{ + LOGP(DGPRS, LOGL_DEBUG, + "%s({current = %08x, assigned = %08x, net_vld = %d, bss_vld = %d}, %08x)\n", + __func__, tlli_state->current, tlli_state->assigned, + tlli_state->net_validated, tlli_state->bss_validated, tlli); + + if (!tlli_state->assigned || tlli_state->assigned != tlli) + return; + + /* TODO: Is this ok? Check spec */ + if (gprs_tlli_type(tlli) != TLLI_LOCAL) + return; + + /* See GSM 04.08, 4.7.1.5 */ + if (to_bss) + tlli_state->net_validated = 1; + else + tlli_state->bss_validated = 1; + + if (!tlli_state->bss_validated || !tlli_state->net_validated) + return; + + LOGP(DGPRS, LOGL_INFO, + "The TLLI %08x has been validated (was %08x)\n", + tlli_state->assigned, tlli_state->current); + + tlli_state->current = tlli; + tlli_state->assigned = 0; +} + +void gbproxy_touch_tlli(struct gbproxy_peer *peer, + struct gbproxy_tlli_info *tlli_info, time_t now) +{ + gbproxy_detach_tlli_info(peer, tlli_info); + gbproxy_attach_tlli_info(peer, now, tlli_info); +} + +struct gbproxy_tlli_info *gbproxy_register_tlli( + struct gbproxy_peer *peer, uint32_t tlli, + const uint8_t *imsi, size_t imsi_len, time_t now) +{ + struct gbproxy_tlli_info *tlli_info; + int enable_patching = -1; + int tlli_already_known; + + /* Check, whether the IMSI matches */ + if (gprs_is_mi_imsi(imsi, imsi_len)) { + enable_patching = gbproxy_check_imsi(peer, imsi, imsi_len); + if (enable_patching < 0) + return NULL; + } + + tlli_info = gbproxy_find_tlli(peer, tlli); + + if (!tlli_info) { + tlli_info = gbproxy_find_tlli_by_mi(peer, imsi, imsi_len); + + if (tlli_info) { + /* TLLI has changed somehow, adjust it */ + LOGP(DGPRS, LOGL_INFO, + "The TLLI has changed from %08x to %08x\n", + tlli_info->tlli.current, tlli); + tlli_info->tlli.current = tlli; + } + } + + if (!tlli_info) { + tlli_info = gbproxy_tlli_info_alloc(peer); + tlli_info->tlli.current = tlli; + } else { + gbproxy_detach_tlli_info(peer, tlli_info); + tlli_already_known = 1; + } + + OSMO_ASSERT(tlli_info != NULL); + + if (!tlli_already_known) + LOGP(DGPRS, LOGL_INFO, "Adding TLLI %08x to list\n", tlli); + + gbproxy_attach_tlli_info(peer, now, tlli_info); + gbproxy_update_tlli_info(tlli_info, imsi, imsi_len); + + if (enable_patching >= 0) + tlli_info->enable_patching = enable_patching; + + return tlli_info; +} + +static void gbproxy_unregister_tlli(struct gbproxy_peer *peer, uint32_t tlli) +{ + struct gbproxy_tlli_info *tlli_info; + + tlli_info = gbproxy_find_tlli(peer, tlli); + if (tlli_info) { + LOGP(DGPRS, LOGL_INFO, + "Removing TLLI %08x from list\n", + tlli); + gbproxy_delete_tlli(peer, tlli_info); + } +} + +int gbproxy_check_tlli(struct gbproxy_peer *peer, uint32_t tlli) +{ + struct gbproxy_tlli_info *tlli_info; + + LOGP(DGPRS, LOGL_INFO, "Checking TLLI %08x, class: %d\n", + tlli, gprs_tlli_type(tlli)); + + if (!peer->cfg->check_imsi) + return 1; + + tlli_info = gbproxy_find_tlli(peer, tlli); + + return tlli_info != NULL && tlli_info->enable_patching; +} + +struct gbproxy_tlli_info *gbproxy_update_tlli_state_ul( + struct gbproxy_peer *peer, + time_t now, + struct gprs_gb_parse_context *parse_ctx) +{ + struct gbproxy_tlli_info *tlli_info = NULL; + + if (parse_ctx->tlli_enc) + tlli_info = gbproxy_find_tlli(peer, parse_ctx->tlli); + + if (parse_ctx->tlli_enc && parse_ctx->llc) { + uint32_t sgsn_tlli; + if (!tlli_info) { + tlli_info = + gbproxy_register_tlli(peer, parse_ctx->tlli, + parse_ctx->imsi, + parse_ctx->imsi_len, now); + /* Setup TLLIs */ + sgsn_tlli = gbproxy_make_sgsn_tlli(peer, tlli_info, + parse_ctx->tlli); + tlli_info->sgsn_tlli.current = sgsn_tlli; + } else { + sgsn_tlli = gbproxy_map_tlli(parse_ctx->tlli, tlli_info, 0); + if (!sgsn_tlli) + sgsn_tlli = gbproxy_make_sgsn_tlli(peer, tlli_info, + parse_ctx->tlli); + + gbproxy_validate_tlli(&tlli_info->tlli, + parse_ctx->tlli, 0); + gbproxy_validate_tlli(&tlli_info->sgsn_tlli, + sgsn_tlli, 0); + gbproxy_touch_tlli(peer, tlli_info, now); + } + } else if (tlli_info) { + gbproxy_touch_tlli(peer, tlli_info, now); + } + + if (parse_ctx->imsi && tlli_info && tlli_info->mi_data_len == 0) { + int enable_patching; + gbproxy_update_tlli_info(tlli_info, + parse_ctx->imsi, parse_ctx->imsi_len); + + /* Check, whether the IMSI matches */ + enable_patching = gbproxy_check_imsi(peer, parse_ctx->imsi, + parse_ctx->imsi_len); + if (enable_patching >= 0) + tlli_info->enable_patching = enable_patching; + } + + return tlli_info; +} + +struct gbproxy_tlli_info *gbproxy_update_tlli_state_dl( + struct gbproxy_peer *peer, + time_t now, + struct gprs_gb_parse_context *parse_ctx) +{ + struct gbproxy_tlli_info *tlli_info = NULL; + + if (parse_ctx->tlli_enc) + tlli_info = gbproxy_find_tlli_by_sgsn_tlli(peer, parse_ctx->tlli); + + if (parse_ctx->tlli_enc && parse_ctx->new_ptmsi_enc) { + /* A new PTMSI has been signaled in the message, + * register new TLLI */ + uint32_t new_sgsn_ptmsi; + uint32_t new_sgsn_tlli; + uint32_t new_bss_ptmsi; + uint32_t new_bss_tlli = 0; + if (!gprs_parse_mi_tmsi(parse_ctx->new_ptmsi_enc, GSM48_TMSI_LEN, + &new_sgsn_ptmsi)) { + LOGP(DGPRS, LOGL_ERROR, + "Failed to parse new TLLI/PTMSI (current is %08x)\n", + parse_ctx->tlli); + return tlli_info; + } + new_sgsn_tlli = gprs_tmsi2tlli(new_sgsn_ptmsi, TLLI_LOCAL); + new_bss_ptmsi = gbproxy_make_bss_ptmsi(peer, new_sgsn_ptmsi); + if (new_bss_ptmsi != GSM_RESERVED_TMSI) + new_bss_tlli = gprs_tmsi2tlli(new_bss_ptmsi, TLLI_LOCAL); + LOGP(DGPRS, LOGL_INFO, + "Got new TLLI(PTMSI) %08x(%08x) from SGSN, using %08x(%08x)\n", + new_sgsn_tlli, new_sgsn_ptmsi, new_bss_tlli, new_bss_ptmsi); + if (tlli_info) { + gbproxy_reassign_tlli(&tlli_info->sgsn_tlli, + peer, new_sgsn_tlli); + gbproxy_reassign_tlli(&tlli_info->tlli, + peer, new_bss_tlli); + gbproxy_touch_tlli(peer, tlli_info, now); + } else { + tlli_info = gbproxy_tlli_info_alloc(peer); + LOGP(DGPRS, LOGL_INFO, + "Adding TLLI %08x to list (SGSN, new P-TMSI)\n", + new_sgsn_tlli); + + gbproxy_attach_tlli_info(peer, now, tlli_info); + /* Setup TLLIs */ + tlli_info->sgsn_tlli.current = new_sgsn_tlli; + } + /* Setup PTMSIs */ + tlli_info->sgsn_tlli.ptmsi = new_sgsn_ptmsi; + tlli_info->tlli.ptmsi = new_bss_ptmsi; + } else if (parse_ctx->tlli_enc && parse_ctx->llc && !tlli_info) { + /* Unknown SGSN TLLI */ + tlli_info = gbproxy_tlli_info_alloc(peer); + LOGP(DGPRS, LOGL_INFO, "Adding TLLI %08x to list (SGSN)\n", + parse_ctx->tlli); + + gbproxy_attach_tlli_info(peer, now, tlli_info); + /* Setup TLLIs */ + tlli_info->sgsn_tlli.current = parse_ctx->tlli; + if (peer->cfg->patch_ptmsi) { + /* TODO: We don't know the local TLLI here, perhaps add + * a workaround that derives a PTMSI from the SGSN TLLI + * and use that to get the missing values. This may + * only happen when the gbproxy has been restarted or a + * tlli_info has been discarded due to age or queue + * length. + */ + tlli_info->tlli.current = 0; + } else { + tlli_info->tlli.current = tlli_info->sgsn_tlli.current; + } + } else if (parse_ctx->tlli_enc && parse_ctx->llc && tlli_info) { + uint32_t bss_tlli = gbproxy_map_tlli(parse_ctx->tlli, + tlli_info, 1); + gbproxy_validate_tlli(&tlli_info->sgsn_tlli, parse_ctx->tlli, 1); + gbproxy_validate_tlli(&tlli_info->tlli, bss_tlli, 1); + gbproxy_touch_tlli(peer, tlli_info, now); + } else if (tlli_info) { + gbproxy_touch_tlli(peer, tlli_info, now); + } + + if (parse_ctx->imsi && tlli_info && tlli_info->mi_data_len == 0) { + int enable_patching; + gbproxy_update_tlli_info(tlli_info, + parse_ctx->imsi, parse_ctx->imsi_len); + + /* Check, whether the IMSI matches */ + enable_patching = gbproxy_check_imsi(peer, parse_ctx->imsi, + parse_ctx->imsi_len); + if (enable_patching >= 0) + tlli_info->enable_patching = enable_patching; + } + + return tlli_info; +} + +void gbproxy_update_tlli_state_after( + struct gbproxy_peer *peer, + struct gbproxy_tlli_info *tlli_info, + time_t now, + struct gprs_gb_parse_context *parse_ctx) +{ + if (parse_ctx->invalidate_tlli) + gbproxy_unregister_tlli(peer, parse_ctx->tlli); + + gbproxy_remove_stale_tllis(peer, now); +} + + diff --git a/openbsc/src/gprs/gb_proxy_vty.c b/openbsc/src/gprs/gb_proxy_vty.c index a85f43969..b2f25a3fd 100644 --- a/openbsc/src/gprs/gb_proxy_vty.c +++ b/openbsc/src/gprs/gb_proxy_vty.c @@ -198,7 +198,7 @@ static int set_core_apn(struct vty *vty, const char *apn, const char *filter) talloc_free(g_cfg->core_apn); g_cfg->core_apn = NULL; g_cfg->core_apn_size = 0; - gbprox_clear_patch_filter(g_cfg); + gbproxy_clear_patch_filter(g_cfg); return CMD_SUCCESS; } @@ -211,8 +211,8 @@ static int set_core_apn(struct vty *vty, const char *apn, const char *filter) } if (!filter) { - gbprox_clear_patch_filter(g_cfg); - } else if (gbprox_set_patch_filter(g_cfg, filter, &err_msg) != 0) { + gbproxy_clear_patch_filter(g_cfg); + } else if (gbproxy_set_patch_filter(g_cfg, filter, &err_msg) != 0) { vty_out(vty, "Match expression invalid: %s%s", err_msg, VTY_NEWLINE); return CMD_WARNING; @@ -551,7 +551,7 @@ DEFUN(delete_gb_tlli, delete_gb_tlli_cmd, state = &peer->patch_state; if (match == MATCH_STALE) { - found = gbprox_remove_stale_tllis(peer, time(NULL)); + found = gbproxy_remove_stale_tllis(peer, time(NULL)); if (found) vty_out(vty, "Deleted %d stale TLLI%s%s", found, found == 1 ? "" : "s", VTY_NEWLINE); @@ -573,7 +573,7 @@ DEFUN(delete_gb_tlli, delete_gb_tlli_cmd, } vty_out(vty, "Deleting TLLI %08x%s", tlli_info->tlli.current, VTY_NEWLINE); - gbprox_delete_tlli(peer, tlli_info); + gbproxy_delete_tlli(peer, tlli_info); found += 1; } diff --git a/openbsc/src/gprs/gprs_gb_parse.c b/openbsc/src/gprs/gprs_gb_parse.c new file mode 100644 index 000000000..72c0d57e8 --- /dev/null +++ b/openbsc/src/gprs/gprs_gb_parse.c @@ -0,0 +1,642 @@ +/* GPRS Gb message parser */ + +/* (C) 2014 by On-Waves + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +#include + +#include + +#include +#include +#include + +#include + +/* TODO: Move shift functions to libosmocore */ + +int v_fixed_shift(uint8_t **data, size_t *data_len, + size_t len, uint8_t **value) +{ + if (len > *data_len) + goto fail; + + if (value) + *value = *data; + + *data += len; + *data_len -= len; + + return len; + +fail: + *data += *data_len; + *data_len = 0; + return -1; +} + +int tv_fixed_match(uint8_t **data, size_t *data_len, + uint8_t tag, size_t len, + uint8_t **value) +{ + size_t ie_len; + + if (*data_len == 0) + goto fail; + + if ((*data)[0] != tag) + return 0; + + if (len > *data_len - 1) + goto fail; + + if (value) + *value = *data + 1; + + ie_len = len + 1; + *data += ie_len; + *data_len -= ie_len; + + return ie_len; + +fail: + *data += *data_len; + *data_len = 0; + return -1; +} + +int tlv_match(uint8_t **data, size_t *data_len, + uint8_t tag, uint8_t **value, size_t *value_len) +{ + size_t len; + size_t ie_len; + + if (*data_len < 2) + goto fail; + + if ((*data)[0] != tag) + return 0; + + len = (*data)[1]; + if (len > *data_len - 2) + goto fail; + + if (value) + *value = *data + 2; + if (value_len) + *value_len = len; + + ie_len = len + 2; + + *data += ie_len; + *data_len -= ie_len; + + return ie_len; + +fail: + *data += *data_len; + *data_len = 0; + return -1; +} + +int lv_shift(uint8_t **data, size_t *data_len, + uint8_t **value, size_t *value_len) +{ + size_t len; + size_t ie_len; + + if (*data_len < 1) + goto fail; + + len = (*data)[0]; + if (len > *data_len - 1) + goto fail; + + if (value) + *value = *data + 1; + if (value_len) + *value_len = len; + + ie_len = len + 1; + *data += ie_len; + *data_len -= ie_len; + + return ie_len; + +fail: + *data += *data_len; + *data_len = 0; + return -1; +} + +static int gprs_gb_parse_gmm_attach_req(uint8_t *data, size_t data_len, + struct gprs_gb_parse_context *parse_ctx) +{ + uint8_t *value; + size_t value_len; + + parse_ctx->llc_msg_name = "ATTACH_REQ"; + + /* Skip MS network capability */ + if (lv_shift(&data, &data_len, NULL, &value_len) <= 0 || + value_len < 1 || value_len > 2) + /* invalid */ + return 0;; + + /* Skip Attach type */ + /* Skip Ciphering key sequence number */ + /* Skip DRX parameter */ + v_fixed_shift(&data, &data_len, 3, NULL); + + /* Get Mobile identity */ + if (lv_shift(&data, &data_len, &value, &value_len) <= 0 || + value_len < 5 || value_len > 8) + /* invalid */ + return 0; + + if (gprs_is_mi_tmsi(value, value_len)) { + parse_ctx->ptmsi_enc = value; + } else if (gprs_is_mi_imsi(value, value_len)) { + parse_ctx->imsi = value; + parse_ctx->imsi_len = value_len; + } + + if (v_fixed_shift(&data, &data_len, 6, &value) <= 0) + return 0; + + parse_ctx->old_raid_enc = value; + + return 1; +} + +static int gprs_gb_parse_gmm_attach_ack(uint8_t *data, size_t data_len, + struct gprs_gb_parse_context *parse_ctx) +{ + uint8_t *value; + size_t value_len; + + parse_ctx->llc_msg_name = "ATTACH_ACK"; + + /* Skip Attach result */ + /* Skip Force to standby */ + /* Skip Periodic RA update timer */ + /* Skip Radio priority for SMS */ + /* Skip Spare half octet */ + v_fixed_shift(&data, &data_len, 3, NULL); + + if (v_fixed_shift(&data, &data_len, 6, &value) <= 0) + return 0; + + parse_ctx->raid_enc = value; + + /* Skip P-TMSI signature (P-TMSI signature, opt, TV, length 4) */ + tv_fixed_match(&data, &data_len, GSM48_IE_GMM_PTMSI_SIG, 3, NULL); + + /* Skip Negotiated READY timer value (GPRS timer, opt, TV, length 2) */ + tv_fixed_match(&data, &data_len, GSM48_IE_GMM_TIMER_READY, 1, NULL); + + /* Allocated P-TMSI (Mobile identity, opt, TLV, length 7) */ + if (tlv_match(&data, &data_len, GSM48_IE_GMM_ALLOC_PTMSI, + &value, &value_len) > 0 && + gprs_is_mi_tmsi(value, value_len)) + parse_ctx->new_ptmsi_enc = value; + return 1; +} + +static int gprs_gb_parse_gmm_detach_req(uint8_t *data, size_t data_len, + struct gprs_gb_parse_context *parse_ctx) +{ + uint8_t *value; + size_t value_len; + int detach_type; + int power_off; + + parse_ctx->llc_msg_name = "DETACH_REQ"; + + /* Skip spare half octet */ + /* Get Detach type */ + if (v_fixed_shift(&data, &data_len, 1, &value) <= 0) + /* invalid */ + return 0; + + detach_type = *value & 0x07; + power_off = *value & 0x08 ? 1 : 0; + + if (!parse_ctx->to_bss) { + /* Mobile originated */ + + if (power_off) + parse_ctx->invalidate_tlli = 1; + + /* Get P-TMSI (Mobile identity), see GSM 24.008, 9.4.5.2 */ + if (tlv_match(&data, &data_len, + GSM48_IE_GMM_ALLOC_PTMSI, &value, &value_len) > 0) + { + if (gprs_is_mi_tmsi(value, value_len)) + parse_ctx->ptmsi_enc = value; + } + } + + return 1; +} + +static int gprs_gb_parse_gmm_ra_upd_req(uint8_t *data, size_t data_len, + struct gprs_gb_parse_context *parse_ctx) +{ + uint8_t *value; + + parse_ctx->llc_msg_name = "RA_UPD_REQ"; + + /* Skip Update type */ + /* Skip GPRS ciphering key sequence number */ + v_fixed_shift(&data, &data_len, 1, NULL); + + if (v_fixed_shift(&data, &data_len, 6, &value) <= 0) + return 0; + + parse_ctx->old_raid_enc = value; + + return 1; +} + +static int gprs_gb_parse_gmm_ra_upd_ack(uint8_t *data, size_t data_len, + struct gprs_gb_parse_context *parse_ctx) +{ + uint8_t *value; + size_t value_len; + + parse_ctx->llc_msg_name = "RA_UPD_ACK"; + + /* Skip Force to standby */ + /* Skip Update result */ + /* Skip Periodic RA update timer */ + v_fixed_shift(&data, &data_len, 2, NULL); + + if (v_fixed_shift(&data, &data_len, 6, &value) <= 0) + return 0; + + parse_ctx->raid_enc = value; + + /* Skip P-TMSI signature (P-TMSI signature, opt, TV, length 4) */ + tv_fixed_match(&data, &data_len, GSM48_IE_GMM_PTMSI_SIG, 3, NULL); + + /* Allocated P-TMSI (Mobile identity, opt, TLV, length 7) */ + if (tlv_match(&data, &data_len, GSM48_IE_GMM_ALLOC_PTMSI, + &value, &value_len) > 0 && + gprs_is_mi_tmsi(value, value_len)) + parse_ctx->new_ptmsi_enc = value; + + return 1; +} + +static int gprs_gb_parse_gmm_ptmsi_reall_cmd(uint8_t *data, size_t data_len, + struct gprs_gb_parse_context *parse_ctx) +{ + uint8_t *value; + size_t value_len; + + parse_ctx->llc_msg_name = "PTMSI_REALL_CMD"; + + LOGP(DLLC, LOGL_NOTICE, + "Got P-TMSI Reallocation Command which is not covered by unit tests yet.\n"); + + /* Allocated P-TMSI */ + if (lv_shift(&data, &data_len, &value, &value_len) > 0 && + gprs_is_mi_tmsi(value, value_len)) + parse_ctx->new_ptmsi_enc = value; + + if (v_fixed_shift(&data, &data_len, 6, &value) <= 0) + return 0; + + parse_ctx->raid_enc = value; + + return 1; +} + +static int gprs_gb_parse_gmm_id_resp(uint8_t *data, size_t data_len, + struct gprs_gb_parse_context *parse_ctx) +{ + uint8_t *value; + size_t value_len; + + parse_ctx->llc_msg_name = "ID_RESP"; + + /* Mobile identity, Mobile identity 10.5.1.4, M LV 2-10 */ + if (lv_shift(&data, &data_len, &value, &value_len) <= 0 || + value_len < 1 || value_len > 9) + /* invalid */ + return 0; + + if (gprs_is_mi_tmsi(value, value_len)) { + parse_ctx->ptmsi_enc = value; + } else if (gprs_is_mi_imsi(value, value_len)) { + parse_ctx->imsi = value; + parse_ctx->imsi_len = value_len; + } + + return 1; +} + +static int gprs_gb_parse_gsm_act_pdp_req(uint8_t *data, size_t data_len, + struct gprs_gb_parse_context *parse_ctx) +{ + ssize_t old_len; + uint8_t *value; + size_t value_len; + + parse_ctx->llc_msg_name = "ACT_PDP_REQ"; + + /* Skip Requested NSAPI */ + /* Skip Requested LLC SAPI */ + v_fixed_shift(&data, &data_len, 2, NULL); + + /* Skip Requested QoS (support 04.08 and 24.008) */ + if (lv_shift(&data, &data_len, NULL, &value_len) <= 0 || + value_len < 4 || value_len > 14) + /* invalid */ + return 0;; + + /* Skip Requested PDP address */ + if (lv_shift(&data, &data_len, NULL, &value_len) <= 0 || + value_len < 2 || value_len > 18) + /* invalid */ + return 0; + + /* Access point name */ + old_len = tlv_match(&data, &data_len, + GSM48_IE_GSM_APN, &value, &value_len); + + if (old_len > 0 && value_len >=1 && value_len <= 100) { + parse_ctx->apn_ie = data - old_len; + parse_ctx->apn_ie_len = old_len; + } + + return 1; +} + +int gprs_gb_parse_dtap(uint8_t *data, size_t data_len, + struct gprs_gb_parse_context *parse_ctx) +{ + struct gsm48_hdr *g48h; + + if (v_fixed_shift(&data, &data_len, sizeof(*g48h), (uint8_t **)&g48h) <= 0) + return 0; + + parse_ctx->g48_hdr = g48h; + + if ((g48h->proto_discr & 0x0f) != GSM48_PDISC_MM_GPRS && + (g48h->proto_discr & 0x0f) != GSM48_PDISC_SM_GPRS) + return 1; + + switch (g48h->msg_type) { + case GSM48_MT_GMM_ATTACH_REQ: + return gprs_gb_parse_gmm_attach_req(data, data_len, parse_ctx); + + case GSM48_MT_GMM_ATTACH_ACK: + return gprs_gb_parse_gmm_attach_ack(data, data_len, parse_ctx); + + case GSM48_MT_GMM_RA_UPD_REQ: + return gprs_gb_parse_gmm_ra_upd_req(data, data_len, parse_ctx); + + case GSM48_MT_GMM_RA_UPD_ACK: + return gprs_gb_parse_gmm_ra_upd_ack(data, data_len, parse_ctx); + + case GSM48_MT_GMM_PTMSI_REALL_CMD: + return gprs_gb_parse_gmm_ptmsi_reall_cmd(data, data_len, parse_ctx); + + case GSM48_MT_GSM_ACT_PDP_REQ: + return gprs_gb_parse_gsm_act_pdp_req(data, data_len, parse_ctx); + + case GSM48_MT_GMM_ID_RESP: + return gprs_gb_parse_gmm_id_resp(data, data_len, parse_ctx); + + case GSM48_MT_GMM_DETACH_REQ: + return gprs_gb_parse_gmm_detach_req(data, data_len, parse_ctx); + + case GSM48_MT_GMM_DETACH_ACK: + parse_ctx->llc_msg_name = "DETACH_ACK"; + parse_ctx->invalidate_tlli = 1; + break; + + default: + break; + }; + + return 1; +} + +int gprs_gb_parse_llc(uint8_t *llc, size_t llc_len, + struct gprs_gb_parse_context *parse_ctx) +{ + struct gprs_llc_hdr_parsed *ghp = &parse_ctx->llc_hdr_parsed; + int rc; + int fcs; + + /* parse LLC */ + rc = gprs_llc_hdr_parse(ghp, llc, llc_len); + gprs_llc_hdr_dump(ghp); + if (rc != 0) { + LOGP(DLLC, LOGL_NOTICE, "Error during LLC header parsing\n"); + return 0; + } + + fcs = gprs_llc_fcs(llc, ghp->crc_length); + LOGP(DLLC, LOGL_DEBUG, "Got LLC message, CRC: %06x (computed %06x)\n", + ghp->fcs, fcs); + + if (!ghp->data) + return 0; + + if (ghp->sapi != GPRS_SAPI_GMM) + return 1; + + if (ghp->cmd != GPRS_LLC_UI) + return 1; + + if (ghp->is_encrypted) { + parse_ctx->need_decryption = 1; + return 0; + } + + return gprs_gb_parse_dtap(ghp->data, ghp->data_len, parse_ctx); +} + +int gprs_gb_parse_bssgp(uint8_t *bssgp, size_t bssgp_len, + struct gprs_gb_parse_context *parse_ctx) +{ + struct bssgp_normal_hdr *bgph; + struct bssgp_ud_hdr *budh = NULL; + struct tlv_parsed *tp = &parse_ctx->bssgp_tp; + uint8_t pdu_type; + uint8_t *data; + size_t data_len; + int rc; + + if (bssgp_len < sizeof(struct bssgp_normal_hdr)) + return 0; + + bgph = (struct bssgp_normal_hdr *)bssgp; + pdu_type = bgph->pdu_type; + + if (pdu_type == BSSGP_PDUT_UL_UNITDATA || + pdu_type == BSSGP_PDUT_DL_UNITDATA) { + if (bssgp_len < sizeof(struct bssgp_ud_hdr)) + return 0; + budh = (struct bssgp_ud_hdr *)bssgp; + bgph = NULL; + data = budh->data; + data_len = bssgp_len - sizeof(*budh); + } else { + data = bgph->data; + data_len = bssgp_len - sizeof(*bgph); + } + + if (bssgp_tlv_parse(tp, data, data_len) < 0) + return 0; + + parse_ctx->pdu_type = pdu_type; + parse_ctx->bud_hdr = budh; + parse_ctx->bgp_hdr = bgph; + parse_ctx->bssgp_data = data; + parse_ctx->bssgp_data_len = data_len; + + if (budh) + parse_ctx->tlli_enc = (uint8_t *)&budh->tlli; + + if (TLVP_PRESENT(tp, BSSGP_IE_ROUTEING_AREA)) + parse_ctx->bssgp_raid_enc = (uint8_t *)TLVP_VAL(tp, BSSGP_IE_ROUTEING_AREA); + + if (TLVP_PRESENT(tp, BSSGP_IE_CELL_ID)) + parse_ctx->bssgp_raid_enc = (uint8_t *)TLVP_VAL(tp, BSSGP_IE_CELL_ID); + + if (TLVP_PRESENT(tp, BSSGP_IE_IMSI)) { + parse_ctx->imsi = (uint8_t *)TLVP_VAL(tp, BSSGP_IE_IMSI); + parse_ctx->imsi_len = TLVP_LEN(tp, BSSGP_IE_IMSI); + } + + /* TODO: This is TLLI old, don't confuse with TLLI current, add + * and use tlli_old_enc instead */ + if (0 && TLVP_PRESENT(tp, BSSGP_IE_TLLI)) + parse_ctx->tlli_enc = (uint8_t *)TLVP_VAL(tp, BSSGP_IE_TLLI); + + if (TLVP_PRESENT(tp, BSSGP_IE_TMSI) && pdu_type == BSSGP_PDUT_PAGING_PS) + parse_ctx->ptmsi_enc = (uint8_t *)TLVP_VAL(tp, BSSGP_IE_TMSI); + + if (TLVP_PRESENT(tp, BSSGP_IE_LLC_PDU)) { + uint8_t *llc = (uint8_t *)TLVP_VAL(tp, BSSGP_IE_LLC_PDU); + size_t llc_len = TLVP_LEN(tp, BSSGP_IE_LLC_PDU); + + rc = gprs_gb_parse_llc(llc, llc_len, parse_ctx); + if (!rc) + return 0; + + parse_ctx->llc = llc; + parse_ctx->llc_len = llc_len; + } + + if (parse_ctx->tlli_enc) { + uint32_t tmp_tlli; + memcpy(&tmp_tlli, parse_ctx->tlli_enc, sizeof(tmp_tlli)); + parse_ctx->tlli = ntohl(tmp_tlli); + } + + return 1; +} + +void gprs_gb_log_parse_context(struct gprs_gb_parse_context *parse_ctx, + const char *default_msg_name) +{ + const char *msg_name = default_msg_name; + const char *sep = ""; + + if (!parse_ctx->tlli_enc && + !parse_ctx->ptmsi_enc && + !parse_ctx->new_ptmsi_enc && + !parse_ctx->imsi) + return; + + if (parse_ctx->llc_msg_name) + msg_name = parse_ctx->llc_msg_name; + + LOGP(DGPRS, LOGL_DEBUG, "%s: Got", msg_name); + + if (parse_ctx->tlli_enc) { + LOGP(DGPRS, LOGL_DEBUG, "%s TLLI %08x", sep, parse_ctx->tlli); + sep = ","; + } + + if (parse_ctx->bssgp_raid_enc) { + struct gprs_ra_id raid; + gsm48_parse_ra(&raid, parse_ctx->bssgp_raid_enc); + LOGP(DGPRS, LOGL_DEBUG, "%s BSSGP RAID %u-%u-%u-%u", sep, + raid.mcc, raid.mnc, raid.lac, raid.rac); + sep = ","; + } + + if (parse_ctx->raid_enc) { + struct gprs_ra_id raid; + gsm48_parse_ra(&raid, parse_ctx->raid_enc); + LOGP(DGPRS, LOGL_DEBUG, "%s RAID %u-%u-%u-%u", sep, + raid.mcc, raid.mnc, raid.lac, raid.rac); + sep = ","; + } + + if (parse_ctx->old_raid_enc) { + struct gprs_ra_id raid; + gsm48_parse_ra(&raid, parse_ctx->old_raid_enc); + LOGP(DGPRS, LOGL_DEBUG, "%s old RAID %u-%u-%u-%u", sep, + raid.mcc, raid.mnc, raid.lac, raid.rac); + sep = ","; + } + + if (parse_ctx->ptmsi_enc) { + uint32_t ptmsi = GSM_RESERVED_TMSI; + int ok; + ok = gprs_parse_mi_tmsi(parse_ctx->ptmsi_enc, GSM48_TMSI_LEN, &ptmsi); + LOGP(DGPRS, LOGL_DEBUG, "%s PTMSI %08x%s", + sep, ptmsi, ok ? "" : " (parse error)"); + sep = ","; + } + + if (parse_ctx->new_ptmsi_enc) { + uint32_t new_ptmsi = GSM_RESERVED_TMSI; + int ok; + ok = gprs_parse_mi_tmsi(parse_ctx->new_ptmsi_enc, GSM48_TMSI_LEN, + &new_ptmsi); + LOGP(DGPRS, LOGL_DEBUG, "%s new PTMSI %08x%s", + sep, new_ptmsi, ok ? "" : " (parse error)"); + sep = ","; + } + + if (parse_ctx->imsi) { + char mi_buf[200]; + mi_buf[0] = '\0'; + gsm48_mi_to_string(mi_buf, sizeof(mi_buf), + parse_ctx->imsi, parse_ctx->imsi_len); + LOGP(DGPRS, LOGL_DEBUG, "%s IMSI %s", + sep, mi_buf); + sep = ","; + } + if (parse_ctx->invalidate_tlli) { + LOGP(DGPRS, LOGL_DEBUG, "%s invalidate", sep); + sep = ","; + } + + LOGP(DGPRS, LOGL_DEBUG, "\n"); +} + diff --git a/openbsc/src/gprs/gprs_utils.c b/openbsc/src/gprs/gprs_utils.c index 1a8fa4316..55d4efda1 100644 --- a/openbsc/src/gprs/gprs_utils.c +++ b/openbsc/src/gprs/gprs_utils.c @@ -24,6 +24,8 @@ #include #include +#include + #include /* FIXME: this needs to go to libosmocore/msgb.c */ @@ -162,3 +164,40 @@ int gprs_str_to_apn(uint8_t *apn_enc, size_t max_len, const char *str) return len; } +/* GSM 04.08, 10.5.1.4 */ +int gprs_is_mi_tmsi(const uint8_t *value, size_t value_len) +{ + if (value_len != GSM48_TMSI_LEN) + return 0; + + if (!value || (value[0] & GSM_MI_TYPE_MASK) != GSM_MI_TYPE_TMSI) + return 0; + + return 1; +} + +/* GSM 04.08, 10.5.1.4 */ +int gprs_is_mi_imsi(const uint8_t *value, size_t value_len) +{ + if (value_len == 0) + return 0; + + if (!value || (value[0] & GSM_MI_TYPE_MASK) != GSM_MI_TYPE_IMSI) + return 0; + + return 1; +} + +int gprs_parse_mi_tmsi(const uint8_t *value, size_t value_len, uint32_t *tmsi) +{ + uint32_t tmsi_be; + + if (!gprs_is_mi_tmsi(value, value_len)) + return 0; + + memcpy(&tmsi_be, value + 1, sizeof(tmsi_be)); + + *tmsi = ntohl(tmsi_be); + return 1; +} + diff --git a/openbsc/tests/gbproxy/Makefile.am b/openbsc/tests/gbproxy/Makefile.am index 409d79125..5f5e58248 100644 --- a/openbsc/tests/gbproxy/Makefile.am +++ b/openbsc/tests/gbproxy/Makefile.am @@ -9,6 +9,9 @@ noinst_PROGRAMS = gbproxy_test gbproxy_test_SOURCES = gbproxy_test.c gbproxy_test_LDADD = \ $(top_builddir)/src/gprs/gb_proxy.o \ + $(top_builddir)/src/gprs/gb_proxy_patch.o \ + $(top_builddir)/src/gprs/gb_proxy_tlli.o \ + $(top_builddir)/src/gprs/gprs_gb_parse.o \ $(top_builddir)/src/gprs/gprs_llc_parse.o \ $(top_builddir)/src/gprs/crc24.o \ $(top_builddir)/src/gprs/gprs_utils.o \ diff --git a/openbsc/tests/gbproxy/gbproxy_test.c b/openbsc/tests/gbproxy/gbproxy_test.c index d7ddafd80..1d89ef6f2 100644 --- a/openbsc/tests/gbproxy/gbproxy_test.c +++ b/openbsc/tests/gbproxy/gbproxy_test.c @@ -1183,7 +1183,7 @@ static void test_gbproxy_ra_patching() configure_bss_peers(bss_peer, ARRAY_SIZE(bss_peer)); gbcfg.match_re = talloc_strdup(NULL, "^9898|^121314"); - if (gbprox_set_patch_filter(&gbcfg, gbcfg.match_re, &err_msg) != 0) { + if (gbproxy_set_patch_filter(&gbcfg, gbcfg.match_re, &err_msg) != 0) { fprintf(stderr, "Failed to compile RE '%s': %s\n", gbcfg.match_re, err_msg); exit(1); @@ -1236,7 +1236,7 @@ static void test_gbproxy_ra_patching() GPRS_SAPI_GMM, 1, dtap_attach_acc, sizeof(dtap_attach_acc)); - tlli_info = gbprox_find_tlli_by_sgsn_tlli(peer, local_tlli); + tlli_info = gbproxy_find_tlli_by_sgsn_tlli(peer, local_tlli); OSMO_ASSERT(tlli_info); OSMO_ASSERT(tlli_info->tlli.assigned == local_tlli); OSMO_ASSERT(tlli_info->tlli.current != local_tlli); @@ -1252,7 +1252,7 @@ static void test_gbproxy_ra_patching() GPRS_SAPI_GMM, 4, dtap_attach_complete, sizeof(dtap_attach_complete)); - tlli_info = gbprox_find_tlli_by_sgsn_tlli(peer, local_tlli); + tlli_info = gbproxy_find_tlli_by_sgsn_tlli(peer, local_tlli); OSMO_ASSERT(tlli_info); OSMO_ASSERT(tlli_info->tlli.assigned == local_tlli); OSMO_ASSERT(tlli_info->tlli.current != local_tlli); @@ -1269,7 +1269,7 @@ static void test_gbproxy_ra_patching() GPRS_SAPI_GMM, 3, dtap_act_pdp_ctx_req, sizeof(dtap_act_pdp_ctx_req)); - tlli_info = gbprox_find_tlli_by_sgsn_tlli(peer, local_tlli); + tlli_info = gbproxy_find_tlli_by_sgsn_tlli(peer, local_tlli); OSMO_ASSERT(tlli_info); OSMO_ASSERT(tlli_info->tlli.assigned == local_tlli); OSMO_ASSERT(tlli_info->tlli.current != local_tlli); @@ -1285,7 +1285,7 @@ static void test_gbproxy_ra_patching() GPRS_SAPI_GMM, 2, dtap_gmm_information, sizeof(dtap_gmm_information)); - tlli_info = gbprox_find_tlli_by_sgsn_tlli(peer, local_tlli); + tlli_info = gbproxy_find_tlli_by_sgsn_tlli(peer, local_tlli); OSMO_ASSERT(tlli_info); OSMO_ASSERT(tlli_info->tlli.assigned == 0); OSMO_ASSERT(tlli_info->tlli.current == local_tlli); @@ -1465,7 +1465,7 @@ static void test_gbproxy_ptmsi_patching() dump_peers(stdout, 0, 0, &gbcfg); - tlli_info = gbprox_find_tlli_by_sgsn_tlli(peer, random_sgsn_tlli); + tlli_info = gbproxy_find_tlli_by_sgsn_tlli(peer, random_sgsn_tlli); OSMO_ASSERT(tlli_info); OSMO_ASSERT(tlli_info->tlli.assigned == local_bss_tlli); OSMO_ASSERT(tlli_info->tlli.current == foreign_bss_tlli); @@ -1485,7 +1485,7 @@ static void test_gbproxy_ptmsi_patching() dump_peers(stdout, 0, 0, &gbcfg); - tlli_info = gbprox_find_tlli_by_sgsn_tlli(peer, local_sgsn_tlli); + tlli_info = gbproxy_find_tlli_by_sgsn_tlli(peer, local_sgsn_tlli); OSMO_ASSERT(tlli_info); OSMO_ASSERT(tlli_info->tlli.assigned == local_bss_tlli); OSMO_ASSERT(tlli_info->tlli.current == foreign_bss_tlli); @@ -1503,7 +1503,7 @@ static void test_gbproxy_ptmsi_patching() dump_peers(stdout, 0, 0, &gbcfg); - tlli_info = gbprox_find_tlli_by_sgsn_tlli(peer, local_sgsn_tlli); + tlli_info = gbproxy_find_tlli_by_sgsn_tlli(peer, local_sgsn_tlli); OSMO_ASSERT(tlli_info); OSMO_ASSERT(tlli_info->tlli.current == local_bss_tlli); OSMO_ASSERT(tlli_info->tlli.assigned == 0); @@ -1805,7 +1805,7 @@ static void test_gbproxy_tlli_expire(void) gbproxy_init_config(&cfg); - if (gbprox_set_patch_filter(&cfg, filter_re, &err_msg) != 0) { + if (gbproxy_set_patch_filter(&cfg, filter_re, &err_msg) != 0) { fprintf(stderr, "gbprox_set_patch_filter: got error: %s\n", err_msg); OSMO_ASSERT(err_msg == NULL); @@ -1822,16 +1822,16 @@ static void test_gbproxy_tlli_expire(void) OSMO_ASSERT(peer->patch_state.enabled_tllis_count == 0); printf(" Add TLLI 1, IMSI 1\n"); - tlli_info = gbprox_register_tlli(peer, tlli1, - imsi1, ARRAY_SIZE(imsi1), now); + tlli_info = gbproxy_register_tlli(peer, tlli1, + imsi1, ARRAY_SIZE(imsi1), now); OSMO_ASSERT(tlli_info); OSMO_ASSERT(tlli_info->tlli.current == tlli1); OSMO_ASSERT(peer->patch_state.enabled_tllis_count == 1); /* replace the old entry */ printf(" Add TLLI 2, IMSI 1 (should replace TLLI 1)\n"); - tlli_info = gbprox_register_tlli(peer, tlli2, - imsi1, ARRAY_SIZE(imsi1), now); + tlli_info = gbproxy_register_tlli(peer, tlli2, + imsi1, ARRAY_SIZE(imsi1), now); OSMO_ASSERT(tlli_info); OSMO_ASSERT(tlli_info->tlli.current == tlli2); OSMO_ASSERT(peer->patch_state.enabled_tllis_count == 1); @@ -1839,10 +1839,10 @@ static void test_gbproxy_tlli_expire(void) dump_peers(stdout, 2, now, &cfg); /* verify that 5678 has survived */ - tlli_info = gbprox_find_tlli_by_mi(peer, imsi1, ARRAY_SIZE(imsi1)); + tlli_info = gbproxy_find_tlli_by_mi(peer, imsi1, ARRAY_SIZE(imsi1)); OSMO_ASSERT(tlli_info); OSMO_ASSERT(tlli_info->tlli.current == tlli2); - tlli_info = gbprox_find_tlli_by_mi(peer, imsi2, ARRAY_SIZE(imsi2)); + tlli_info = gbproxy_find_tlli_by_mi(peer, imsi2, ARRAY_SIZE(imsi2)); OSMO_ASSERT(!tlli_info); printf("\n"); @@ -1861,16 +1861,16 @@ static void test_gbproxy_tlli_expire(void) OSMO_ASSERT(peer->patch_state.enabled_tllis_count == 0); printf(" Add TLLI 1, IMSI 1\n"); - tlli_info = gbprox_register_tlli(peer, tlli1, - imsi1, ARRAY_SIZE(imsi1), now); + tlli_info = gbproxy_register_tlli(peer, tlli1, + imsi1, ARRAY_SIZE(imsi1), now); OSMO_ASSERT(tlli_info); OSMO_ASSERT(tlli_info->tlli.current == tlli1); OSMO_ASSERT(peer->patch_state.enabled_tllis_count == 1); /* try to replace the old entry */ printf(" Add TLLI 1, IMSI 2 (should replace IMSI 1)\n"); - tlli_info = gbprox_register_tlli(peer, tlli1, - imsi2, ARRAY_SIZE(imsi2), now); + tlli_info = gbproxy_register_tlli(peer, tlli1, + imsi2, ARRAY_SIZE(imsi2), now); OSMO_ASSERT(tlli_info); OSMO_ASSERT(tlli_info->tlli.current == tlli1); OSMO_ASSERT(peer->patch_state.enabled_tllis_count == 1); @@ -1878,9 +1878,9 @@ static void test_gbproxy_tlli_expire(void) dump_peers(stdout, 2, now, &cfg); /* verify that 5678 has survived */ - tlli_info = gbprox_find_tlli_by_mi(peer, imsi1, ARRAY_SIZE(imsi1)); + tlli_info = gbproxy_find_tlli_by_mi(peer, imsi1, ARRAY_SIZE(imsi1)); OSMO_ASSERT(!tlli_info); - tlli_info = gbprox_find_tlli_by_mi(peer, imsi2, ARRAY_SIZE(imsi2)); + tlli_info = gbproxy_find_tlli_by_mi(peer, imsi2, ARRAY_SIZE(imsi2)); OSMO_ASSERT(tlli_info); OSMO_ASSERT(tlli_info->tlli.current == tlli1); @@ -1901,24 +1901,24 @@ static void test_gbproxy_tlli_expire(void) OSMO_ASSERT(peer->patch_state.enabled_tllis_count == 0); printf(" Add TLLI 1, IMSI 1\n"); - gbprox_register_tlli(peer, tlli1, imsi1, ARRAY_SIZE(imsi1), now); + gbproxy_register_tlli(peer, tlli1, imsi1, ARRAY_SIZE(imsi1), now); OSMO_ASSERT(peer->patch_state.enabled_tllis_count == 1); /* replace the old entry */ printf(" Add TLLI 2, IMSI 2 (should replace IMSI 1)\n"); - gbprox_register_tlli(peer, tlli2, imsi2, ARRAY_SIZE(imsi2), now); + gbproxy_register_tlli(peer, tlli2, imsi2, ARRAY_SIZE(imsi2), now); OSMO_ASSERT(peer->patch_state.enabled_tllis_count == 2); - num_removed = gbprox_remove_stale_tllis(peer, time(NULL) + 2); + num_removed = gbproxy_remove_stale_tllis(peer, time(NULL) + 2); OSMO_ASSERT(num_removed == 1); OSMO_ASSERT(peer->patch_state.enabled_tllis_count == 1); dump_peers(stdout, 2, now, &cfg); /* verify that 5678 has survived */ - tlli_info = gbprox_find_tlli_by_mi(peer, imsi1, ARRAY_SIZE(imsi1)); + tlli_info = gbproxy_find_tlli_by_mi(peer, imsi1, ARRAY_SIZE(imsi1)); OSMO_ASSERT(!tlli_info); - tlli_info = gbprox_find_tlli_by_mi(peer, imsi2, ARRAY_SIZE(imsi2)); + tlli_info = gbproxy_find_tlli_by_mi(peer, imsi2, ARRAY_SIZE(imsi2)); OSMO_ASSERT(tlli_info); OSMO_ASSERT(tlli_info->tlli.current == tlli2); @@ -1939,24 +1939,24 @@ static void test_gbproxy_tlli_expire(void) OSMO_ASSERT(peer->patch_state.enabled_tllis_count == 0); printf(" Add TLLI 1, IMSI 1 (should expire after timeout)\n"); - gbprox_register_tlli(peer, tlli1, imsi1, ARRAY_SIZE(imsi1), now); + gbproxy_register_tlli(peer, tlli1, imsi1, ARRAY_SIZE(imsi1), now); OSMO_ASSERT(peer->patch_state.enabled_tllis_count == 1); printf(" Add TLLI 2, IMSI 2 (should not expire after timeout)\n"); - gbprox_register_tlli(peer, tlli2, imsi2, ARRAY_SIZE(imsi2), + gbproxy_register_tlli(peer, tlli2, imsi2, ARRAY_SIZE(imsi2), now + 1); OSMO_ASSERT(peer->patch_state.enabled_tllis_count == 2); - num_removed = gbprox_remove_stale_tllis(peer, now + 2); + num_removed = gbproxy_remove_stale_tllis(peer, now + 2); OSMO_ASSERT(num_removed == 1); OSMO_ASSERT(peer->patch_state.enabled_tllis_count == 1); dump_peers(stdout, 2, now + 2, &cfg); /* verify that 5678 has survived */ - tlli_info = gbprox_find_tlli_by_mi(peer, imsi1, ARRAY_SIZE(imsi1)); + tlli_info = gbproxy_find_tlli_by_mi(peer, imsi1, ARRAY_SIZE(imsi1)); OSMO_ASSERT(!tlli_info); - tlli_info = gbprox_find_tlli_by_mi(peer, imsi2, ARRAY_SIZE(imsi2)); + tlli_info = gbproxy_find_tlli_by_mi(peer, imsi2, ARRAY_SIZE(imsi2)); OSMO_ASSERT(tlli_info); OSMO_ASSERT(tlli_info->tlli.current == tlli2); @@ -1977,34 +1977,34 @@ static void test_gbproxy_tlli_expire(void) OSMO_ASSERT(peer->patch_state.enabled_tllis_count == 0); printf(" Add TLLI 1, IMSI 1 (should expire)\n"); - gbprox_register_tlli(peer, tlli1, imsi1, ARRAY_SIZE(imsi1), now); + gbproxy_register_tlli(peer, tlli1, imsi1, ARRAY_SIZE(imsi1), now); OSMO_ASSERT(peer->patch_state.enabled_tllis_count == 1); printf(" Add TLLI 2, IMSI 2 (should expire after timeout)\n"); - gbprox_register_tlli(peer, tlli2, imsi2, ARRAY_SIZE(imsi2), + gbproxy_register_tlli(peer, tlli2, imsi2, ARRAY_SIZE(imsi2), now + 1); OSMO_ASSERT(peer->patch_state.enabled_tllis_count == 2); printf(" Add TLLI 3, IMSI 3 (should not expire after timeout)\n"); - gbprox_register_tlli(peer, tlli3, imsi3, ARRAY_SIZE(imsi3), - now + 2); + gbproxy_register_tlli(peer, tlli3, imsi3, ARRAY_SIZE(imsi3), + now + 2); OSMO_ASSERT(peer->patch_state.enabled_tllis_count == 3); dump_peers(stdout, 2, now + 2, &cfg); printf(" Remove stale TLLIs\n"); - num_removed = gbprox_remove_stale_tllis(peer, now + 3); + num_removed = gbproxy_remove_stale_tllis(peer, now + 3); OSMO_ASSERT(num_removed == 2); OSMO_ASSERT(peer->patch_state.enabled_tllis_count == 1); dump_peers(stdout, 2, now + 2, &cfg); /* verify that tlli3 has survived */ - tlli_info = gbprox_find_tlli_by_mi(peer, imsi1, ARRAY_SIZE(imsi1)); + tlli_info = gbproxy_find_tlli_by_mi(peer, imsi1, ARRAY_SIZE(imsi1)); OSMO_ASSERT(!tlli_info); - tlli_info = gbprox_find_tlli_by_mi(peer, imsi2, ARRAY_SIZE(imsi2)); + tlli_info = gbproxy_find_tlli_by_mi(peer, imsi2, ARRAY_SIZE(imsi2)); OSMO_ASSERT(!tlli_info); - tlli_info = gbprox_find_tlli_by_mi(peer, imsi3, ARRAY_SIZE(imsi3)); + tlli_info = gbproxy_find_tlli_by_mi(peer, imsi3, ARRAY_SIZE(imsi3)); OSMO_ASSERT(tlli_info); OSMO_ASSERT(tlli_info->tlli.current == tlli3); @@ -2036,55 +2036,55 @@ static void test_gbproxy_imsi_matching(void) gbproxy_init_config(&cfg); OSMO_ASSERT(cfg.check_imsi == 0); - OSMO_ASSERT(gbprox_set_patch_filter(&cfg, filter_re1, &err_msg) == 0); + OSMO_ASSERT(gbproxy_set_patch_filter(&cfg, filter_re1, &err_msg) == 0); OSMO_ASSERT(cfg.check_imsi == 1); - OSMO_ASSERT(gbprox_set_patch_filter(&cfg, filter_re2, &err_msg) == 0); + OSMO_ASSERT(gbproxy_set_patch_filter(&cfg, filter_re2, &err_msg) == 0); OSMO_ASSERT(cfg.check_imsi == 1); err_msg = NULL; - OSMO_ASSERT(gbprox_set_patch_filter(&cfg, filter_re4_bad, &err_msg) == -1); + OSMO_ASSERT(gbproxy_set_patch_filter(&cfg, filter_re4_bad, &err_msg) == -1); OSMO_ASSERT(err_msg != NULL); OSMO_ASSERT(cfg.check_imsi == 0); - OSMO_ASSERT(gbprox_set_patch_filter(&cfg, filter_re2, &err_msg) == 0); + OSMO_ASSERT(gbproxy_set_patch_filter(&cfg, filter_re2, &err_msg) == 0); OSMO_ASSERT(cfg.check_imsi == 1); - OSMO_ASSERT(gbprox_set_patch_filter(&cfg, NULL, &err_msg) == 0); + OSMO_ASSERT(gbproxy_set_patch_filter(&cfg, NULL, &err_msg) == 0); OSMO_ASSERT(cfg.check_imsi == 0); - OSMO_ASSERT(gbprox_set_patch_filter(&cfg, filter_re2, &err_msg) == 0); + OSMO_ASSERT(gbproxy_set_patch_filter(&cfg, filter_re2, &err_msg) == 0); OSMO_ASSERT(cfg.check_imsi == 1); - gbprox_clear_patch_filter(&cfg); + gbproxy_clear_patch_filter(&cfg); OSMO_ASSERT(cfg.check_imsi == 0); peer = gbproxy_peer_alloc(&cfg, 20); - OSMO_ASSERT(gbprox_set_patch_filter(&cfg, filter_re2, &err_msg) == 0); + OSMO_ASSERT(gbproxy_set_patch_filter(&cfg, filter_re2, &err_msg) == 0); OSMO_ASSERT(cfg.check_imsi == 1); - OSMO_ASSERT(gbprox_check_imsi(peer, imsi1, ARRAY_SIZE(imsi1)) == 1); - OSMO_ASSERT(gbprox_check_imsi(peer, imsi2, ARRAY_SIZE(imsi2)) == 1); + OSMO_ASSERT(gbproxy_check_imsi(peer, imsi1, ARRAY_SIZE(imsi1)) == 1); + OSMO_ASSERT(gbproxy_check_imsi(peer, imsi2, ARRAY_SIZE(imsi2)) == 1); /* imsi3_bad contains 0xE and 0xF digits, but the conversion function - * doesn't complain, so gbprox_check_imsi() doesn't return -1 in this + * doesn't complain, so gbproxy_check_imsi() doesn't return -1 in this * case. */ - OSMO_ASSERT(gbprox_check_imsi(peer, imsi3_bad, ARRAY_SIZE(imsi3_bad)) == 0); - OSMO_ASSERT(gbprox_check_imsi(peer, tmsi1, ARRAY_SIZE(tmsi1)) == -1); - OSMO_ASSERT(gbprox_check_imsi(peer, tmsi2_bad, ARRAY_SIZE(tmsi2_bad)) == -1); - OSMO_ASSERT(gbprox_check_imsi(peer, imei1, ARRAY_SIZE(imei1)) == -1); - OSMO_ASSERT(gbprox_check_imsi(peer, imei2, ARRAY_SIZE(imei2)) == -1); + OSMO_ASSERT(gbproxy_check_imsi(peer, imsi3_bad, ARRAY_SIZE(imsi3_bad)) == 0); + OSMO_ASSERT(gbproxy_check_imsi(peer, tmsi1, ARRAY_SIZE(tmsi1)) == -1); + OSMO_ASSERT(gbproxy_check_imsi(peer, tmsi2_bad, ARRAY_SIZE(tmsi2_bad)) == -1); + OSMO_ASSERT(gbproxy_check_imsi(peer, imei1, ARRAY_SIZE(imei1)) == -1); + OSMO_ASSERT(gbproxy_check_imsi(peer, imei2, ARRAY_SIZE(imei2)) == -1); - OSMO_ASSERT(gbprox_set_patch_filter(&cfg, filter_re3, &err_msg) == 0); + OSMO_ASSERT(gbproxy_set_patch_filter(&cfg, filter_re3, &err_msg) == 0); OSMO_ASSERT(cfg.check_imsi == 1); - OSMO_ASSERT(gbprox_check_imsi(peer, imsi1, ARRAY_SIZE(imsi1)) == 0); - OSMO_ASSERT(gbprox_check_imsi(peer, imsi2, ARRAY_SIZE(imsi2)) == 0); - OSMO_ASSERT(gbprox_check_imsi(peer, imsi3_bad, ARRAY_SIZE(imsi3_bad)) == 0); - OSMO_ASSERT(gbprox_check_imsi(peer, tmsi1, ARRAY_SIZE(tmsi1)) == -1); - OSMO_ASSERT(gbprox_check_imsi(peer, tmsi2_bad, ARRAY_SIZE(tmsi2_bad)) == -1); - OSMO_ASSERT(gbprox_check_imsi(peer, imei1, ARRAY_SIZE(imei1)) == -1); - OSMO_ASSERT(gbprox_check_imsi(peer, imei2, ARRAY_SIZE(imei2)) == -1); + OSMO_ASSERT(gbproxy_check_imsi(peer, imsi1, ARRAY_SIZE(imsi1)) == 0); + OSMO_ASSERT(gbproxy_check_imsi(peer, imsi2, ARRAY_SIZE(imsi2)) == 0); + OSMO_ASSERT(gbproxy_check_imsi(peer, imsi3_bad, ARRAY_SIZE(imsi3_bad)) == 0); + OSMO_ASSERT(gbproxy_check_imsi(peer, tmsi1, ARRAY_SIZE(tmsi1)) == -1); + OSMO_ASSERT(gbproxy_check_imsi(peer, tmsi2_bad, ARRAY_SIZE(tmsi2_bad)) == -1); + OSMO_ASSERT(gbproxy_check_imsi(peer, imei1, ARRAY_SIZE(imei1)) == -1); + OSMO_ASSERT(gbproxy_check_imsi(peer, imei2, ARRAY_SIZE(imei2)) == -1); /* TODO: Check correct length but wrong type with is_mi_tmsi */ -- cgit v1.2.3 From 5f1faa3cd25663716de8cc4c2a81fac0f378ff76 Mon Sep 17 00:00:00 2001 From: Jacob Erlbeck Date: Thu, 21 Aug 2014 10:01:30 +0200 Subject: gbproxy: Move peer definitions to gb_proxy_peer.c This patch moves the peer related definitions from gb_proxy.c to gb_proxy_peer.c and adjusts the prefix of each global symbol to gbproxy_: Peer definitions (prefix adjusted to gbproxy_): peer_ctr_description -> gprs/gb_proxy_peer.c (static) peer_ctrg_desc -> gprs/gb_proxy_peer.c (static) *peer_by_* -> gprs/gb_proxy_peer.c gbproxy_peer_alloc -> gprs/gb_proxy_peer.c gbproxy_peer_free -> gprs/gb_proxy_peer.c gbprox_cleanup_peers -> gprs/gb_proxy_peer.c Sponsored-by: On-Waves ehf --- openbsc/include/openbsc/gb_proxy.h | 26 +++-- openbsc/src/gprs/Makefile.am | 2 +- openbsc/src/gprs/gb_proxy.c | 190 +++------------------------------ openbsc/src/gprs/gb_proxy_peer.c | 200 +++++++++++++++++++++++++++++++++++ openbsc/src/gprs/gb_proxy_vty.c | 6 +- openbsc/tests/gbproxy/Makefile.am | 1 + openbsc/tests/gbproxy/gbproxy_test.c | 4 +- 7 files changed, 241 insertions(+), 188 deletions(-) create mode 100644 openbsc/src/gprs/gb_proxy_peer.c diff --git a/openbsc/include/openbsc/gb_proxy.h b/openbsc/include/openbsc/gb_proxy.h index 345a317e8..9fcffd431 100644 --- a/openbsc/include/openbsc/gb_proxy.h +++ b/openbsc/include/openbsc/gb_proxy.h @@ -12,6 +12,7 @@ struct rate_ctr_group; struct gprs_gb_parse_context; +struct tlv_parsed; enum gbproxy_patch_mode { GBPROX_PATCH_DEFAULT, @@ -167,13 +168,6 @@ int gbprox_reset_persistent_nsvcs(struct gprs_ns_inst *nsi); void gbprox_reset(struct gbproxy_config *cfg); -int gbprox_cleanup_peers(struct gbproxy_config *cfg, uint16_t nsei, uint16_t bvci); - -struct gbproxy_peer *gbprox_peer_by_nsei(struct gbproxy_config *cfg, uint16_t nsei); - -struct gbproxy_peer *gbproxy_peer_alloc(struct gbproxy_config *cfg, uint16_t bvci); -void gbproxy_peer_free(struct gbproxy_peer *peer); - /* TLLI state handling */ void gbproxy_delete_tllis(struct gbproxy_peer *peer); int gbproxy_check_tlli(struct gbproxy_peer *peer, uint32_t tlli); @@ -237,4 +231,22 @@ void gbproxy_clear_patch_filter(struct gbproxy_config *cfg); int gbproxy_check_imsi( struct gbproxy_peer *peer, const uint8_t *imsi, size_t imsi_len); +/* Peer handling */ +struct gbproxy_peer *gbproxy_peer_by_bvci( + struct gbproxy_config *cfg, uint16_t bvci) __attribute__((nonnull)); +struct gbproxy_peer *gbproxy_peer_by_nsei( + struct gbproxy_config *cfg, uint16_t nsei) __attribute__((nonnull)); +struct gbproxy_peer *gbproxy_peer_by_rai( + struct gbproxy_config *cfg, const uint8_t *ra) __attribute__((nonnull)); +struct gbproxy_peer *gbproxy_peer_by_lai( + struct gbproxy_config *cfg, const uint8_t *la) __attribute__((nonnull)); +struct gbproxy_peer *gbproxy_peer_by_bssgp_tlv( + struct gbproxy_config *cfg, struct tlv_parsed *tp) + __attribute__((nonnull)); +struct gbproxy_peer *gbproxy_peer_alloc(struct gbproxy_config *cfg, uint16_t bvci) + __attribute__((nonnull)); +void gbproxy_peer_free(struct gbproxy_peer *peer) __attribute__((nonnull)); +int gbproxy_cleanup_peers(struct gbproxy_config *cfg, uint16_t nsei, uint16_t bvci) + __attribute__((nonnull)); + #endif diff --git a/openbsc/src/gprs/Makefile.am b/openbsc/src/gprs/Makefile.am index 4d0c9cdb2..a8de0a4bb 100644 --- a/openbsc/src/gprs/Makefile.am +++ b/openbsc/src/gprs/Makefile.am @@ -14,7 +14,7 @@ bin_PROGRAMS = osmo-gbproxy endif osmo_gbproxy_SOURCES = gb_proxy.c gb_proxy_main.c gb_proxy_vty.c \ - gb_proxy_patch.c gb_proxy_tlli.c \ + gb_proxy_patch.c gb_proxy_tlli.c gb_proxy_peer.c \ gprs_gb_parse.c gprs_llc_parse.c crc24.c gprs_utils.c osmo_gbproxy_LDADD = $(top_builddir)/src/libcommon/libcommon.a \ $(OSMO_LIBS) diff --git a/openbsc/src/gprs/gb_proxy.c b/openbsc/src/gprs/gb_proxy.c index 7a1508ee7..9a9967fce 100644 --- a/openbsc/src/gprs/gb_proxy.c +++ b/openbsc/src/gprs/gb_proxy.c @@ -72,91 +72,6 @@ static const struct rate_ctr_group_desc global_ctrg_desc = { .ctr_desc = global_ctr_description, }; -static const struct rate_ctr_desc peer_ctr_description[] = { - { "blocked", "BVC Block " }, - { "unblocked", "BVC Unblock " }, - { "dropped", "BVC blocked, dropped packet " }, - { "inv-nsei", "NSEI mismatch " }, - { "tx-err", "NS Transmission error " }, - { "raid-mod.bss", "RAID patched (BSS )" }, - { "raid-mod.sgsn", "RAID patched (SGSN)" }, - { "apn-mod.sgsn", "APN patched " }, - { "tlli-mod.bss", "TLLI patched (BSS )" }, - { "tlli-mod.sgsn", "TLLI patched (SGSN)" }, - { "ptmsi-mod.bss", "P-TMSI patched (BSS )" }, - { "ptmsi-mod.sgsn","P-TMSI patched (SGSN)" }, - { "mod-crypt-err", "Patch error: encrypted " }, - { "mod-err", "Patch error: other " }, - { "attach-reqs", "Attach Request count " }, - { "attach-rejs", "Attach Reject count " }, - { "tlli-unknown", "TLLI from SGSN unknown " }, - { "tlli-cache", "TLLI cache size " }, -}; - -static const struct rate_ctr_group_desc peer_ctrg_desc = { - .group_name_prefix = "gbproxy.peer", - .group_description = "GBProxy Peer Statistics", - .num_ctr = ARRAY_SIZE(peer_ctr_description), - .ctr_desc = peer_ctr_description, -}; - - -/* Find the gbprox_peer by its BVCI */ -static struct gbproxy_peer *peer_by_bvci(struct gbproxy_config *cfg, uint16_t bvci) -{ - struct gbproxy_peer *peer; - llist_for_each_entry(peer, &cfg->bts_peers, list) { - if (peer->bvci == bvci) - return peer; - } - return NULL; -} - -/* Find the gbprox_peer by its NSEI */ -struct gbproxy_peer *gbprox_peer_by_nsei(struct gbproxy_config *cfg, uint16_t nsei) -{ - struct gbproxy_peer *peer; - llist_for_each_entry(peer, &cfg->bts_peers, list) { - if (peer->nsei == nsei) - return peer; - } - return NULL; -} - -/* look-up a peer by its Routeing Area Identification (RAI) */ -static struct gbproxy_peer *peer_by_rai(struct gbproxy_config *cfg, const uint8_t *ra) -{ - struct gbproxy_peer *peer; - llist_for_each_entry(peer, &cfg->bts_peers, list) { - if (!memcmp(peer->ra, ra, 6)) - return peer; - } - return NULL; -} - -/* look-up a peer by its Location Area Identification (LAI) */ -static struct gbproxy_peer *peer_by_lai(struct gbproxy_config *cfg, const uint8_t *la) -{ - struct gbproxy_peer *peer; - llist_for_each_entry(peer, &cfg->bts_peers, list) { - if (!memcmp(peer->ra, la, 5)) - return peer; - } - return NULL; -} - -/* look-up a peer by its Location Area Code (LAC) */ -static struct gbproxy_peer *peer_by_lac(struct gbproxy_config *cfg, const uint8_t *la) -{ - struct gbproxy_peer *peer; - llist_for_each_entry(peer, &cfg->bts_peers, list) { - if (!memcmp(peer->ra + 3, la + 3, 2)) - return peer; - } - return NULL; -} - - static int check_peer_nsei(struct gbproxy_peer *peer, uint16_t nsei) { if (peer->nsei != nsei) { @@ -170,37 +85,6 @@ static int check_peer_nsei(struct gbproxy_peer *peer, uint16_t nsei) return 1; } -struct gbproxy_peer *gbproxy_peer_alloc(struct gbproxy_config *cfg, uint16_t bvci) -{ - struct gbproxy_peer *peer; - - peer = talloc_zero(tall_bsc_ctx, struct gbproxy_peer); - if (!peer) - return NULL; - - peer->bvci = bvci; - peer->ctrg = rate_ctr_group_alloc(peer, &peer_ctrg_desc, bvci); - peer->cfg = cfg; - - llist_add(&peer->list, &cfg->bts_peers); - - INIT_LLIST_HEAD(&peer->patch_state.enabled_tllis); - - return peer; -} - -void gbproxy_peer_free(struct gbproxy_peer *peer) -{ - llist_del(&peer->list); - - gbproxy_delete_tllis(peer); - - rate_ctr_group_free(peer->ctrg); - peer->ctrg = NULL; - - talloc_free(peer); -} - /* strip off the NS header */ static void strip_ns_hdr(struct msgb *msg) { @@ -248,32 +132,6 @@ static void gbprox_update_current_raid(uint8_t *raid_enc, peer->cfg->core_mcc, peer->cfg->core_mnc); } -struct gbproxy_peer *peer_by_bssgp_tlv(struct gbproxy_config *cfg, struct tlv_parsed *tp) -{ - if (TLVP_PRESENT(tp, BSSGP_IE_BVCI)) { - uint16_t bvci; - - bvci = ntohs(tlvp_val16_unal(tp, BSSGP_IE_BVCI)); - if (bvci >= 2) - return peer_by_bvci(cfg, bvci); - } - - if (TLVP_PRESENT(tp, BSSGP_IE_ROUTEING_AREA)) { - uint8_t *rai = (uint8_t *)TLVP_VAL(tp, BSSGP_IE_ROUTEING_AREA); - /* Only compare LAC part, since MCC/MNC are possibly patched. - * Since the LAC of different BSS must be different when - * MCC/MNC are patched, collisions shouldn't happen. */ - return peer_by_lac(cfg, rai); - } - - if (TLVP_PRESENT(tp, BSSGP_IE_LOCATION_AREA)) { - uint8_t *lai = (uint8_t *)TLVP_VAL(tp, BSSGP_IE_LOCATION_AREA); - return peer_by_lac(cfg, lai); - } - - return NULL; -} - uint32_t gbproxy_make_bss_ptmsi(struct gbproxy_peer *peer, uint32_t sgsn_ptmsi) { @@ -348,13 +206,13 @@ static void gbprox_process_bssgp_ul(struct gbproxy_config *cfg, /* Get peer */ if (!peer && msgb_bvci(msg) >= 2) - peer = peer_by_bvci(cfg, msgb_bvci(msg)); + peer = gbproxy_peer_by_bvci(cfg, msgb_bvci(msg)); if (!peer) - peer = gbprox_peer_by_nsei(cfg, msgb_nsei(msg)); + peer = gbproxy_peer_by_nsei(cfg, msgb_nsei(msg)); if (!peer) - peer = peer_by_bssgp_tlv(cfg, &parse_ctx.bssgp_tp); + peer = gbproxy_peer_by_bssgp_tlv(cfg, &parse_ctx.bssgp_tp); if (!peer) { LOGP(DLLC, LOGL_INFO, @@ -425,10 +283,10 @@ static void gbprox_process_bssgp_dl(struct gbproxy_config *cfg, } if (!peer && msgb_bvci(msg) >= 2) - peer = peer_by_bvci(cfg, msgb_bvci(msg)); + peer = gbproxy_peer_by_bvci(cfg, msgb_bvci(msg)); if (!peer) - peer = peer_by_bssgp_tlv(cfg, &parse_ctx.bssgp_tp); + peer = gbproxy_peer_by_bssgp_tlv(cfg, &parse_ctx.bssgp_tp); if (!peer) { LOGP(DLLC, LOGL_INFO, @@ -520,7 +378,7 @@ static int block_unblock_peer(struct gbproxy_config *cfg, uint16_t ptp_bvci, uin { struct gbproxy_peer *peer; - peer = peer_by_bvci(cfg, ptp_bvci); + peer = gbproxy_peer_by_bvci(cfg, ptp_bvci); if (!peer) { LOGP(DGPRS, LOGL_ERROR, "BVCI=%u: Cannot find BSS\n", ptp_bvci); @@ -550,7 +408,7 @@ static int gbprox_relay2bvci(struct gbproxy_config *cfg, struct msgb *msg, uint1 { struct gbproxy_peer *peer; - peer = peer_by_bvci(cfg, ptp_bvci); + peer = gbproxy_peer_by_bvci(cfg, ptp_bvci); if (!peer) { LOGP(DGPRS, LOGL_ERROR, "BVCI=%u: Cannot find BSS\n", ptp_bvci); @@ -605,7 +463,7 @@ static int gbprox_rx_sig_from_bss(struct gbproxy_config *cfg, * BSSGP */ if (!TLVP_PRESENT(&tp, BSSGP_IE_ROUTEING_AREA)) goto err_mand_ie; - from_peer = gbprox_peer_by_nsei(cfg, nsei); + from_peer = gbproxy_peer_by_nsei(cfg, nsei); if (!from_peer) goto err_no_peer; memcpy(from_peer->ra, TLVP_VAL(&tp, BSSGP_IE_ROUTEING_AREA), @@ -632,7 +490,7 @@ static int gbprox_rx_sig_from_bss(struct gbproxy_config *cfg, return bssgp_tx_simple_bvci(BSSGP_PDUT_BVC_RESET_ACK, nsei, 0, ns_bvci); } - from_peer = peer_by_bvci(cfg, bvci); + from_peer = gbproxy_peer_by_bvci(cfg, bvci); if (!from_peer) { /* if a PTP-BVC is reset, and we don't know that * PTP-BVCI yet, we should allocate a new peer */ @@ -694,12 +552,12 @@ static int gbprox_rx_paging(struct gbproxy_config *cfg, struct msgb *msg, struct bvci); errctr = GBPROX_GLOB_CTR_OTHER_ERR; } else if (TLVP_PRESENT(tp, BSSGP_IE_ROUTEING_AREA)) { - peer = peer_by_rai(cfg, TLVP_VAL(tp, BSSGP_IE_ROUTEING_AREA)); + peer = gbproxy_peer_by_rai(cfg, TLVP_VAL(tp, BSSGP_IE_ROUTEING_AREA)); LOGPC(DGPRS, LOGL_INFO, "routing by RAI to peer BVCI=%u\n", peer ? peer->bvci : -1); errctr = GBPROX_GLOB_CTR_INV_RAI; } else if (TLVP_PRESENT(tp, BSSGP_IE_LOCATION_AREA)) { - peer = peer_by_lai(cfg, TLVP_VAL(tp, BSSGP_IE_LOCATION_AREA)); + peer = gbproxy_peer_by_lai(cfg, TLVP_VAL(tp, BSSGP_IE_LOCATION_AREA)); LOGPC(DGPRS, LOGL_INFO, "routing by LAI to peer BVCI=%u\n", peer ? peer->bvci : -1); errctr = GBPROX_GLOB_CTR_INV_LAI; @@ -734,7 +592,7 @@ static int rx_reset_from_sgsn(struct gbproxy_config *cfg, if (ptp_bvci >= 2) { /* A reset for a PTP BVC was received, forward it to its * respective peer */ - peer = peer_by_bvci(cfg, ptp_bvci); + peer = gbproxy_peer_by_bvci(cfg, ptp_bvci); if (!peer) { LOGP(DGPRS, LOGL_ERROR, "NSEI=%u BVCI=%u: Cannot find BSS\n", nsei, ptp_bvci); @@ -830,7 +688,7 @@ static int gbprox_rx_sig_from_sgsn(struct gbproxy_config *cfg, /* RAI IE is mandatory */ if (!TLVP_PRESENT(&tp, BSSGP_IE_ROUTEING_AREA)) goto err_mand_ie; - peer = peer_by_rai(cfg, TLVP_VAL(&tp, BSSGP_IE_ROUTEING_AREA)); + peer = gbproxy_peer_by_rai(cfg, TLVP_VAL(&tp, BSSGP_IE_ROUTEING_AREA)); if (!peer) goto err_no_peer; rc = gbprox_relay2peer(msg, peer, ns_bvci); @@ -901,7 +759,7 @@ int gbprox_rcvmsg(struct gbproxy_config *cfg, struct msgb *msg, uint16_t nsei, else rc = gbprox_rx_sig_from_bss(cfg, msg, nsei, ns_bvci); } else { - peer = peer_by_bvci(cfg, ns_bvci); + peer = gbproxy_peer_by_bvci(cfg, ns_bvci); /* All other BVCI are PTP and thus can be simply forwarded */ if (!remote_end_is_sgsn) { @@ -976,7 +834,7 @@ int gbprox_signal(unsigned int subsys, unsigned int signal, if (!nsvc->remote_end_is_sgsn) { /* from BSS to SGSN */ - peer = gbprox_peer_by_nsei(cfg, nsvc->nsei); + peer = gbproxy_peer_by_nsei(cfg, nsvc->nsei); if (!peer) { LOGP(DGPRS, LOGL_NOTICE, "signal %u for unknown peer " "NSEI=%u/NSVCI=%u\n", signal, nsvc->nsei, @@ -1033,24 +891,6 @@ void gbprox_reset(struct gbproxy_config *cfg) gbproxy_init_config(cfg); } -int gbprox_cleanup_peers(struct gbproxy_config *cfg, uint16_t nsei, uint16_t bvci) -{ - int counter = 0; - struct gbproxy_peer *peer, *tmp; - - llist_for_each_entry_safe(peer, tmp, &cfg->bts_peers, list) { - if (peer->nsei != nsei) - continue; - if (bvci && peer->bvci != bvci) - continue; - - gbproxy_peer_free(peer); - counter += 1; - } - - return counter; -} - int gbproxy_init_config(struct gbproxy_config *cfg) { struct timespec tp; diff --git a/openbsc/src/gprs/gb_proxy_peer.c b/openbsc/src/gprs/gb_proxy_peer.c new file mode 100644 index 000000000..820d8df87 --- /dev/null +++ b/openbsc/src/gprs/gb_proxy_peer.c @@ -0,0 +1,200 @@ +/* Gb proxy peer handling */ + +/* (C) 2010 by Harald Welte + * (C) 2010-2013 by On-Waves + * (C) 2013 by Holger Hans Peter Freyther + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include + +static const struct rate_ctr_desc peer_ctr_description[] = { + { "blocked", "BVC Block " }, + { "unblocked", "BVC Unblock " }, + { "dropped", "BVC blocked, dropped packet " }, + { "inv-nsei", "NSEI mismatch " }, + { "tx-err", "NS Transmission error " }, + { "raid-mod.bss", "RAID patched (BSS )" }, + { "raid-mod.sgsn", "RAID patched (SGSN)" }, + { "apn-mod.sgsn", "APN patched " }, + { "tlli-mod.bss", "TLLI patched (BSS )" }, + { "tlli-mod.sgsn", "TLLI patched (SGSN)" }, + { "ptmsi-mod.bss", "P-TMSI patched (BSS )" }, + { "ptmsi-mod.sgsn","P-TMSI patched (SGSN)" }, + { "mod-crypt-err", "Patch error: encrypted " }, + { "mod-err", "Patch error: other " }, + { "attach-reqs", "Attach Request count " }, + { "attach-rejs", "Attach Reject count " }, + { "tlli-unknown", "TLLI from SGSN unknown " }, + { "tlli-cache", "TLLI cache size " }, +}; + +static const struct rate_ctr_group_desc peer_ctrg_desc = { + .group_name_prefix = "gbproxy.peer", + .group_description = "GBProxy Peer Statistics", + .num_ctr = ARRAY_SIZE(peer_ctr_description), + .ctr_desc = peer_ctr_description, +}; + + +/* Find the gbprox_peer by its BVCI */ +struct gbproxy_peer *gbproxy_peer_by_bvci(struct gbproxy_config *cfg, uint16_t bvci) +{ + struct gbproxy_peer *peer; + llist_for_each_entry(peer, &cfg->bts_peers, list) { + if (peer->bvci == bvci) + return peer; + } + return NULL; +} + +/* Find the gbprox_peer by its NSEI */ +struct gbproxy_peer *gbproxy_peer_by_nsei(struct gbproxy_config *cfg, + uint16_t nsei) +{ + struct gbproxy_peer *peer; + llist_for_each_entry(peer, &cfg->bts_peers, list) { + if (peer->nsei == nsei) + return peer; + } + return NULL; +} + +/* look-up a peer by its Routeing Area Identification (RAI) */ +struct gbproxy_peer *gbproxy_peer_by_rai(struct gbproxy_config *cfg, + const uint8_t *ra) +{ + struct gbproxy_peer *peer; + llist_for_each_entry(peer, &cfg->bts_peers, list) { + if (!memcmp(peer->ra, ra, 6)) + return peer; + } + return NULL; +} + +/* look-up a peer by its Location Area Identification (LAI) */ +struct gbproxy_peer *gbproxy_peer_by_lai(struct gbproxy_config *cfg, + const uint8_t *la) +{ + struct gbproxy_peer *peer; + llist_for_each_entry(peer, &cfg->bts_peers, list) { + if (!memcmp(peer->ra, la, 5)) + return peer; + } + return NULL; +} + +/* look-up a peer by its Location Area Code (LAC) */ +struct gbproxy_peer *gbproxy_peer_by_lac(struct gbproxy_config *cfg, + const uint8_t *la) +{ + struct gbproxy_peer *peer; + llist_for_each_entry(peer, &cfg->bts_peers, list) { + if (!memcmp(peer->ra + 3, la + 3, 2)) + return peer; + } + return NULL; +} + +struct gbproxy_peer *gbproxy_peer_by_bssgp_tlv(struct gbproxy_config *cfg, + struct tlv_parsed *tp) +{ + if (TLVP_PRESENT(tp, BSSGP_IE_BVCI)) { + uint16_t bvci; + + bvci = ntohs(tlvp_val16_unal(tp, BSSGP_IE_BVCI)); + if (bvci >= 2) + return gbproxy_peer_by_bvci(cfg, bvci); + } + + if (TLVP_PRESENT(tp, BSSGP_IE_ROUTEING_AREA)) { + uint8_t *rai = (uint8_t *)TLVP_VAL(tp, BSSGP_IE_ROUTEING_AREA); + /* Only compare LAC part, since MCC/MNC are possibly patched. + * Since the LAC of different BSS must be different when + * MCC/MNC are patched, collisions shouldn't happen. */ + return gbproxy_peer_by_lac(cfg, rai); + } + + if (TLVP_PRESENT(tp, BSSGP_IE_LOCATION_AREA)) { + uint8_t *lai = (uint8_t *)TLVP_VAL(tp, BSSGP_IE_LOCATION_AREA); + return gbproxy_peer_by_lac(cfg, lai); + } + + return NULL; +} + + +struct gbproxy_peer *gbproxy_peer_alloc(struct gbproxy_config *cfg, uint16_t bvci) +{ + struct gbproxy_peer *peer; + + peer = talloc_zero(tall_bsc_ctx, struct gbproxy_peer); + if (!peer) + return NULL; + + peer->bvci = bvci; + peer->ctrg = rate_ctr_group_alloc(peer, &peer_ctrg_desc, bvci); + peer->cfg = cfg; + + llist_add(&peer->list, &cfg->bts_peers); + + INIT_LLIST_HEAD(&peer->patch_state.enabled_tllis); + + return peer; +} + +void gbproxy_peer_free(struct gbproxy_peer *peer) +{ + llist_del(&peer->list); + + gbproxy_delete_tllis(peer); + + rate_ctr_group_free(peer->ctrg); + peer->ctrg = NULL; + + talloc_free(peer); +} + +int gbproxy_cleanup_peers(struct gbproxy_config *cfg, uint16_t nsei, uint16_t bvci) +{ + int counter = 0; + struct gbproxy_peer *peer, *tmp; + + llist_for_each_entry_safe(peer, tmp, &cfg->bts_peers, list) { + if (peer->nsei != nsei) + continue; + if (bvci && peer->bvci != bvci) + continue; + + gbproxy_peer_free(peer); + counter += 1; + } + + return counter; +} + diff --git a/openbsc/src/gprs/gb_proxy_vty.c b/openbsc/src/gprs/gb_proxy_vty.c index b2f25a3fd..f1811c3d9 100644 --- a/openbsc/src/gprs/gb_proxy_vty.c +++ b/openbsc/src/gprs/gb_proxy_vty.c @@ -422,7 +422,7 @@ DEFUN(delete_gb_bvci, delete_gb_bvci_cmd, const uint16_t bvci = atoi(argv[1]); int counter; - counter = gbprox_cleanup_peers(g_cfg, nsei, bvci); + counter = gbproxy_cleanup_peers(g_cfg, nsei, bvci); if (counter == 0) { vty_out(vty, "BVC not found%s", VTY_NEWLINE); @@ -458,7 +458,7 @@ DEFUN(delete_gb_nsei, delete_gb_nsei_cmd, if (delete_bvc) { if (!dry_run) - counter = gbprox_cleanup_peers(g_cfg, nsei, 0); + counter = gbproxy_cleanup_peers(g_cfg, nsei, 0); else { struct gbproxy_peer *peer; counter = 0; @@ -541,7 +541,7 @@ DEFUN(delete_gb_tlli, delete_gb_tlli_cmd, break; } - peer = gbprox_peer_by_nsei(g_cfg, nsei); + peer = gbproxy_peer_by_nsei(g_cfg, nsei); if (!peer) { vty_out(vty, "Didn't find peer with NSEI %d%s", nsei, VTY_NEWLINE); diff --git a/openbsc/tests/gbproxy/Makefile.am b/openbsc/tests/gbproxy/Makefile.am index 5f5e58248..f6dd78595 100644 --- a/openbsc/tests/gbproxy/Makefile.am +++ b/openbsc/tests/gbproxy/Makefile.am @@ -10,6 +10,7 @@ gbproxy_test_SOURCES = gbproxy_test.c gbproxy_test_LDADD = \ $(top_builddir)/src/gprs/gb_proxy.o \ $(top_builddir)/src/gprs/gb_proxy_patch.o \ + $(top_builddir)/src/gprs/gb_proxy_peer.o \ $(top_builddir)/src/gprs/gb_proxy_tlli.o \ $(top_builddir)/src/gprs/gprs_gb_parse.o \ $(top_builddir)/src/gprs/gprs_llc_parse.o \ diff --git a/openbsc/tests/gbproxy/gbproxy_test.c b/openbsc/tests/gbproxy/gbproxy_test.c index 1d89ef6f2..a8a84af84 100644 --- a/openbsc/tests/gbproxy/gbproxy_test.c +++ b/openbsc/tests/gbproxy/gbproxy_test.c @@ -1203,7 +1203,7 @@ static void test_gbproxy_ra_patching() gprs_dump_nsi(nsi); dump_peers(stdout, 0, 0, &gbcfg); - peer = gbprox_peer_by_nsei(&gbcfg, 0x1000); + peer = gbproxy_peer_by_nsei(&gbcfg, 0x1000); OSMO_ASSERT(peer != NULL); send_bssgp_reset_ack(nsi, &sgsn_peer, 0x1002); @@ -1423,7 +1423,7 @@ static void test_gbproxy_ptmsi_patching() setup_ns(nsi, &bss_peer[0], 0x1001, 0x1000); setup_bssgp(nsi, &bss_peer[0], 0x1002); - peer = gbprox_peer_by_nsei(&gbcfg, 0x1000); + peer = gbproxy_peer_by_nsei(&gbcfg, 0x1000); OSMO_ASSERT(peer != NULL); send_bssgp_reset_ack(nsi, &sgsn_peer, 0x1002); -- cgit v1.2.3