diff options
author | Jacob Erlbeck <jerlbeck@sysmocom.de> | 2014-09-17 10:56:38 +0200 |
---|---|---|
committer | Jacob Erlbeck <jerlbeck@sysmocom.de> | 2014-09-19 11:21:35 +0200 |
commit | 91a0e8639a74231f41d14ca7cc952079cc541755 (patch) | |
tree | f908e1752528fc985f953f25f2c9e06b774d209e /openbsc/src | |
parent | af952baffc73dae23d9498518ec26a30f50f07f0 (diff) |
gbproxy: Separate SGSN numeric namespaces
Currently the SGSN side message's TLLI are searched without checking
the originating SGSN. This leads to collisions if both SGSN use the
same P-TMSI for different MS.
With this patch, the SGSN NSEI is stored within the tlli_info and is
used in comparisons to separate the namespaces.
Note that this type of collision cannot happen with BSS numbers,
since the tlli_info are already separated and stored per (BSS) peer.
Sponsored-by: On-Waves ehf
Diffstat (limited to 'openbsc/src')
-rw-r--r-- | openbsc/src/gprs/gb_proxy.c | 19 | ||||
-rw-r--r-- | openbsc/src/gprs/gb_proxy_tlli.c | 27 | ||||
-rw-r--r-- | openbsc/src/gprs/gb_proxy_vty.c | 32 |
3 files changed, 58 insertions, 20 deletions
diff --git a/openbsc/src/gprs/gb_proxy.c b/openbsc/src/gprs/gb_proxy.c index ee8037565..4b46b0e2b 100644 --- a/openbsc/src/gprs/gb_proxy.c +++ b/openbsc/src/gprs/gb_proxy.c @@ -257,7 +257,7 @@ uint32_t gbproxy_make_sgsn_tlli(struct gbproxy_peer *peer, sgsn_tlli = rand_r(&peer->cfg->sgsn_tlli_state); sgsn_tlli = (sgsn_tlli & 0x7fffffff) | 0x78000000; - if (gbproxy_find_tlli_by_sgsn_tlli(peer, sgsn_tlli)) + if (gbproxy_find_tlli_by_any_sgsn_tlli(peer, sgsn_tlli)) sgsn_tlli = 0; } while (!sgsn_tlli); } @@ -309,6 +309,7 @@ static void gbproxy_flush_stored_messages(struct gbproxy_peer *peer, while ((stored_msg = msgb_dequeue(&tlli_info->stored_msgs))) { struct gprs_gb_parse_context tmp_parse_ctx = {0}; tmp_parse_ctx.to_bss = 0; + tmp_parse_ctx.peer_nsei = msgb_nsei(stored_msg); int len_change = 0; gprs_gb_parse_bssgp(msgb_bssgph(stored_msg), @@ -511,13 +512,13 @@ static int gbprox_process_bssgp_ul(struct gbproxy_config *cfg, time_t now; struct gbproxy_tlli_info *tlli_info = NULL; uint32_t sgsn_nsei = cfg->nsip_sgsn_nsei; - int send_msg_directly = 0; if (!cfg->core_mcc && !cfg->core_mnc && !cfg->core_apn && !cfg->acquire_imsi && !cfg->patch_ptmsi && !cfg->route_to_sgsn2) return 1; parse_ctx.to_bss = 0; + parse_ctx.peer_nsei = msgb_nsei(msg); /* Parse BSSGP/LLC */ rc = gprs_gb_parse_bssgp(msgb_bssgph(msg), msgb_bssgp_len(msg), @@ -560,11 +561,16 @@ static int gbprox_process_bssgp_ul(struct gbproxy_config *cfg, } } - if (tlli_info && cfg->route_to_sgsn2 && gbproxy_check_tlli(peer, tlli_info)) { - sgsn_nsei = cfg->nsip_sgsn2_nsei; - send_msg_directly = 1; + if (tlli_info && cfg->route_to_sgsn2) { + if (cfg->acquire_imsi && tlli_info->imsi_len == 0) + sgsn_nsei = 0xffff; + else if (gbproxy_check_tlli(peer, tlli_info)) + sgsn_nsei = cfg->nsip_sgsn2_nsei; } + if (tlli_info) + tlli_info->sgsn_nsei = sgsn_nsei; + /* Handle IMSI acquisition */ if (cfg->acquire_imsi) { rc = gbproxy_imsi_acquisition(peer, msg, sgsn_nsei, now, @@ -578,7 +584,7 @@ static int gbprox_process_bssgp_ul(struct gbproxy_config *cfg, gbproxy_update_tlli_state_after(peer, tlli_info, now, &parse_ctx); - if (send_msg_directly) { + if (sgsn_nsei != cfg->nsip_sgsn_nsei) { /* Send message directly to the selected SGSN */ rc = gbprox_relay2sgsn(cfg, msg, msgb_bvci(msg), sgsn_nsei); /* Don't let the calling code handle the transmission */ @@ -604,6 +610,7 @@ static void gbprox_process_bssgp_dl(struct gbproxy_config *cfg, return; parse_ctx.to_bss = 1; + parse_ctx.peer_nsei = msgb_nsei(msg); rc = gprs_gb_parse_bssgp(msgb_bssgph(msg), msgb_bssgp_len(msg), &parse_ctx); diff --git a/openbsc/src/gprs/gb_proxy_tlli.c b/openbsc/src/gprs/gb_proxy_tlli.c index c4140f7e8..8aadd2f44 100644 --- a/openbsc/src/gprs/gb_proxy_tlli.c +++ b/openbsc/src/gprs/gb_proxy_tlli.c @@ -60,16 +60,33 @@ struct gbproxy_tlli_info *gbproxy_find_tlli_by_ptmsi( return NULL; } -struct gbproxy_tlli_info *gbproxy_find_tlli_by_sgsn_tlli( +struct gbproxy_tlli_info *gbproxy_find_tlli_by_any_sgsn_tlli( struct gbproxy_peer *peer, uint32_t tlli) { struct gbproxy_tlli_info *tlli_info; struct gbproxy_patch_state *state = &peer->patch_state; + /* Don't care about the NSEI */ llist_for_each_entry(tlli_info, &state->enabled_tllis, list) if (tlli_info->sgsn_tlli.current == tlli || - tlli_info->sgsn_tlli.assigned == tlli) + tlli_info->sgsn_tlli.assigned == tlli) + return tlli_info; + + return NULL; +} + +struct gbproxy_tlli_info *gbproxy_find_tlli_by_sgsn_tlli( + struct gbproxy_peer *peer, + uint32_t tlli, uint32_t sgsn_nsei) +{ + 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) && + tlli_info->sgsn_nsei == sgsn_nsei) return tlli_info; return NULL; @@ -409,7 +426,8 @@ static void gbproxy_remove_matching_tllis(struct gbproxy_peer *peer, continue; if (!gbproxy_tlli_match(&tlli_info->tlli, &info->tlli) && - !gbproxy_tlli_match(&tlli_info->sgsn_tlli, &info->sgsn_tlli)) + (tlli_info->sgsn_nsei != info->sgsn_nsei || + !gbproxy_tlli_match(&tlli_info->sgsn_tlli, &info->sgsn_tlli))) continue; LOGP(DGPRS, LOGL_INFO, @@ -508,7 +526,8 @@ struct gbproxy_tlli_info *gbproxy_update_tlli_state_dl( struct gbproxy_tlli_info *tlli_info = NULL; if (parse_ctx->tlli_enc) - tlli_info = gbproxy_find_tlli_by_sgsn_tlli(peer, parse_ctx->tlli); + tlli_info = gbproxy_find_tlli_by_sgsn_tlli( + peer, parse_ctx->tlli, parse_ctx->peer_nsei); if (parse_ctx->tlli_enc && parse_ctx->new_ptmsi_enc && tlli_info) { /* A new P-TMSI has been signalled in the message, diff --git a/openbsc/src/gprs/gb_proxy_vty.c b/openbsc/src/gprs/gb_proxy_vty.c index 22592a162..da615630e 100644 --- a/openbsc/src/gprs/gb_proxy_vty.c +++ b/openbsc/src/gprs/gb_proxy_vty.c @@ -479,6 +479,10 @@ DEFUN(show_gbproxy_tllis, show_gbproxy_tllis_cmd, "show gbproxy tllis", if (stored_msgs) vty_out(vty, ", STORED %d", stored_msgs); + if (g_cfg->route_to_sgsn2) + vty_out(vty, ", SGSN NSEI %d", + tlli_info->sgsn_nsei); + if (tlli_info->is_deregistered) vty_out(vty, ", DE-REGISTERED"); @@ -583,15 +587,15 @@ DEFUN(delete_gb_nsei, delete_gb_nsei_cmd, "Delete a GBProxy TLLI entry by NSEI and identification\nNSEI number\n" DEFUN(delete_gb_tlli_by_id, delete_gb_tlli_by_id_cmd, - "delete-gbproxy-tlli <0-65534> (tlli|imsi) IDENT", + "delete-gbproxy-tlli <0-65534> (tlli|imsi|sgsn-nsei) IDENT", GBPROXY_DELETE_TLLI_STR "Delete entries with a matching TLLI (hex)\n" "Delete entries with a matching IMSI\n" "Identification to match\n") { const uint16_t nsei = atoi(argv[0]); - enum {MATCH_TLLI = 't', MATCH_IMSI = 'i'} match; - uint32_t tlli = 0; + enum {MATCH_TLLI = 't', MATCH_IMSI = 'i', MATCH_SGSN = 's'} match; + uint32_t ident = 0; const char *imsi = NULL; struct gbproxy_peer *peer = 0; struct gbproxy_tlli_info *tlli_info, *nxt; @@ -601,10 +605,11 @@ DEFUN(delete_gb_tlli_by_id, delete_gb_tlli_by_id_cmd, match = argv[1][0]; - if (match == MATCH_TLLI) - tlli = strtoll(argv[2], NULL, 16); - else - imsi = argv[2]; + switch (match) { + case MATCH_TLLI: ident = strtoll(argv[2], NULL, 16); break; + case MATCH_IMSI: imsi = argv[2]; break; + case MATCH_SGSN: ident = strtoll(argv[2], NULL, 0); break; + }; peer = gbproxy_peer_by_nsei(g_cfg, nsei); if (!peer) { @@ -616,10 +621,16 @@ DEFUN(delete_gb_tlli_by_id, delete_gb_tlli_by_id_cmd, state = &peer->patch_state; llist_for_each_entry_safe(tlli_info, nxt, &state->enabled_tllis, list) { - if (match == MATCH_TLLI) { - if (tlli_info->tlli.current != tlli) + switch (match) { + case MATCH_TLLI: + if (tlli_info->tlli.current != ident) + continue; + break; + case MATCH_SGSN: + if (tlli_info->sgsn_nsei != ident) continue; - } else { + break; + case MATCH_IMSI: mi_buf[0] = '\0'; gsm48_mi_to_string(mi_buf, sizeof(mi_buf), tlli_info->imsi, @@ -627,6 +638,7 @@ DEFUN(delete_gb_tlli_by_id, delete_gb_tlli_by_id_cmd, if (strcmp(mi_buf, imsi) != 0) continue; + break; } vty_out(vty, "Deleting TLLI %08x%s", tlli_info->tlli.current, |