diff options
author | Jacob Erlbeck <jerlbeck@sysmocom.de> | 2014-08-19 12:21:01 +0200 |
---|---|---|
committer | Holger Hans Peter Freyther <holger@moiji-mobile.com> | 2014-08-24 16:16:40 +0200 |
commit | 9114bee2424fa5a5e30261054573f9f78b5c5477 (patch) | |
tree | d19928d839a625ec509dd1606c1786c397db7111 /openbsc/src/gprs/gb_proxy.c | |
parent | 6bd7ded71ea3a1de200ad1190e7f7cbee6cae5f9 (diff) |
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
Diffstat (limited to 'openbsc/src/gprs/gb_proxy.c')
-rw-r--r-- | openbsc/src/gprs/gb_proxy.c | 1786 |
1 files changed, 49 insertions, 1737 deletions
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 <openbsc/signal.h> #include <openbsc/debug.h> +#include <openbsc/gprs_gb_parse.h> #include <openbsc/gb_proxy.h> #include <openbsc/gprs_llc.h> @@ -49,21 +50,6 @@ #include <openbsc/gsm_04_08_gprs.h> #include <openbsc/gprs_utils.h> -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,629 +208,6 @@ 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) -{ - 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; -} - -/* GSM 04.08, 10.5.1.4 */ -static int 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 */ -static int 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; -} - -static int parse_mi_tmsi(const uint8_t *value, size_t value_len, uint32_t *tmsi) -{ - 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 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.current == tlli || - tlli_info->tlli.assigned == tlli) - return tlli_info; - - 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) -{ - 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 *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 (!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 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; -} - -static void gbprox_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) - gbprox_delete_tlli(peer, tlli_info); - - OSMO_ASSERT(state->enabled_tllis_count == 0); - OSMO_ASSERT(llist_empty(&state->enabled_tllis)); -} - -void gbprox_clear_patch_filter(struct gbproxy_config *cfg) -{ - if (cfg->check_imsi) { - regfree(&cfg->imsi_re_comp); - cfg->check_imsi = 0; - } -} - -int gbprox_set_patch_filter(struct gbproxy_config *cfg, const char *filter, - const char **err_msg) -{ - static char err_buf[300]; - int rc; - - gbprox_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 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; - } - - 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; -} - -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; - - 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 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, @@ -907,412 +248,6 @@ static void gbprox_update_current_raid(uint8_t *raid_enc, 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)) { @@ -1339,285 +274,8 @@ struct gbproxy_peer *peer_by_bssgp_tlv(struct gbproxy_config *cfg, struct tlv_pa 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 gbproxy_make_bss_ptmsi(struct gbproxy_peer *peer, + uint32_t sgsn_ptmsi) { uint32_t bss_ptmsi; if (!peer->cfg->patch_ptmsi) { @@ -1627,7 +285,7 @@ static uint32_t gbprox_make_bss_ptmsi(struct gbproxy_peer *peer, bss_ptmsi = rand_r(&peer->cfg->bss_ptmsi_state); bss_ptmsi = bss_ptmsi | 0xC0000000; - if (gbprox_find_tlli_by_ptmsi(peer, bss_ptmsi)) + if (gbproxy_find_tlli_by_ptmsi(peer, bss_ptmsi)) bss_ptmsi = GSM_RESERVED_TMSI; } while (bss_ptmsi == GSM_RESERVED_TMSI); } @@ -1635,9 +293,9 @@ static uint32_t gbprox_make_bss_ptmsi(struct gbproxy_peer *peer, 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 gbproxy_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) { @@ -1651,391 +309,19 @@ static uint32_t gbprox_make_sgsn_tlli(struct gbproxy_peer *peer, 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)) + if (gbproxy_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}; + struct gprs_gb_parse_context parse_ctx = {0}; int rc; int len_change = 0; time_t now; @@ -2047,8 +333,8 @@ static void gbprox_process_bssgp_ul(struct gbproxy_config *cfg, parse_ctx.to_bss = 0; /* Parse BSSGP/LLC */ - rc = gbprox_parse_bssgp(msgb_bssgph(msg), msgb_bssgp_len(msg), - &parse_ctx); + rc = gprs_gb_parse_bssgp(msgb_bssgph(msg), msgb_bssgp_len(msg), + &parse_ctx); if (!rc) { if (!parse_ctx.need_decryption) { @@ -2089,12 +375,25 @@ static void gbprox_process_bssgp_ul(struct gbproxy_config *cfg, 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); + 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; - gbprox_patch_bssgp(msg, msgb_bssgph(msg), msgb_bssgp_len(msg), - peer, tlli_info, &len_change, &parse_ctx); + default: + break; + } + } - gbprox_update_state_after(peer, tlli_info, now, &parse_ctx); + gprs_gb_log_parse_context(&parse_ctx, "BSSGP"); + + tlli_info = gbproxy_update_tlli_state_ul(peer, now, &parse_ctx); + + gbproxy_patch_bssgp(msg, msgb_bssgph(msg), msgb_bssgp_len(msg), + peer, tlli_info, &len_change, &parse_ctx); + + gbproxy_update_tlli_state_after(peer, tlli_info, now, &parse_ctx); return; } @@ -2104,7 +403,7 @@ static void gbprox_process_bssgp_dl(struct gbproxy_config *cfg, struct msgb *msg, struct gbproxy_peer *peer) { - struct gbproxy_parse_context parse_ctx = {0}; + struct gprs_gb_parse_context parse_ctx = {0}; int rc; int len_change = 0; time_t now; @@ -2112,8 +411,8 @@ static void gbprox_process_bssgp_dl(struct gbproxy_config *cfg, parse_ctx.to_bss = 1; - rc = gbprox_parse_bssgp(msgb_bssgph(msg), msgb_bssgp_len(msg), - &parse_ctx); + rc = gprs_gb_parse_bssgp(msgb_bssgph(msg), msgb_bssgp_len(msg), + &parse_ctx); if (!rc) { if (!parse_ctx.need_decryption) { @@ -2143,12 +442,25 @@ static void gbprox_process_bssgp_dl(struct gbproxy_config *cfg, now = time(NULL); - tlli_info = gbprox_update_state_dl(peer, now, &parse_ctx); + 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; + } + } + + gprs_gb_log_parse_context(&parse_ctx, "BSSGP"); + + 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; } |