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
This commit is contained in:
parent
6bd7ded71e
commit
9114bee242
|
@ -11,6 +11,7 @@
|
|||
#include <regex.h>
|
||||
|
||||
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 *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);
|
||||
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);
|
||||
/* 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 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_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
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
#pragma once
|
||||
|
||||
#include <openbsc/gprs_llc.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
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)));
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <openbsc/gb_proxy.h>
|
||||
|
||||
#include <openbsc/gprs_utils.h>
|
||||
#include <openbsc/gprs_gb_parse.h>
|
||||
|
||||
#include <openbsc/gsm_data_shared.h>
|
||||
#include <openbsc/gsm_04_08_gprs.h>
|
||||
#include <openbsc/debug.h>
|
||||
|
||||
#include <osmocom/gprs/protocol/gsm_08_18.h>
|
||||
#include <osmocom/core/rate_ctr.h>
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <openbsc/gb_proxy.h>
|
||||
|
||||
#include <openbsc/gprs_utils.h>
|
||||
#include <openbsc/gprs_gb_parse.h>
|
||||
|
||||
#include <openbsc/gsm_data_shared.h>
|
||||
#include <openbsc/debug.h>
|
||||
|
||||
#include <osmocom/gsm/gsm_utils.h>
|
||||
|
||||
#include <osmocom/core/rate_ctr.h>
|
||||
#include <osmocom/core/talloc.h>
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <openbsc/gprs_gb_parse.h>
|
||||
|
||||
#include <openbsc/gprs_utils.h>
|
||||
|
||||
#include <openbsc/gsm_04_08_gprs.h>
|
||||
#include <openbsc/gsm_data_shared.h>
|
||||
#include <openbsc/debug.h>
|
||||
|
||||
#include <osmocom/gprs/gprs_bssgp.h>
|
||||
|
||||
/* 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");
|
||||
}
|
||||
|
|
@ -24,6 +24,8 @@
|
|||
#include <osmocom/core/msgb.h>
|
||||
#include <osmocom/gprs/gprs_ns.h>
|
||||
|
||||
#include <osmocom/gsm/protocol/gsm_04_08.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -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 */
|
||||
|
||||
|
|
Loading…
Reference in New Issue