summaryrefslogtreecommitdiffstats
path: root/openbsc/src/gprs/gb_proxy.c
diff options
context:
space:
mode:
authorJacob Erlbeck <jerlbeck@sysmocom.de>2014-08-12 16:30:30 +0200
committerHolger Hans Peter Freyther <holger@moiji-mobile.com>2014-08-24 16:16:39 +0200
commit9057bc3c727e97cd7ff2534bffbd9ba4dcd8d4ea (patch)
treed63a0a24749b5961285515b44c4641b8a13f10ba /openbsc/src/gprs/gb_proxy.c
parentc53f2a6961780153fbf97910609c827a0e9300c3 (diff)
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
Diffstat (limited to 'openbsc/src/gprs/gb_proxy.c')
-rw-r--r--openbsc/src/gprs/gb_proxy.c296
1 files changed, 235 insertions, 61 deletions
diff --git a/openbsc/src/gprs/gb_proxy.c b/openbsc/src/gprs/gb_proxy.c
index 26f4c17..0c898cc 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) {