aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHolger Hans Peter Freyther <holger@moiji-mobile.com>2014-08-24 16:17:17 +0200
committerHolger Hans Peter Freyther <holger@moiji-mobile.com>2014-08-24 16:18:26 +0200
commitddbbe695b339256b5db02269ccb3dd2c4c2a539c (patch)
tree0c02c1de5d2dbcfd3370ec4512b5b5b3802a25ef
parent1449c9f06f7f10319517f50fd64b5e2926284d44 (diff)
parent5f1faa3cd25663716de8cc4c2a81fac0f378ff76 (diff)
Merge Jacob's GPRS GB Proxy related configs
All review feedback will be addressed _after_ the split of the files. This is the only reasonable approach to get the split of files merged. I didn't have the time to review all of the code before the point of splitting.
-rw-r--r--openbsc/include/openbsc/gb_proxy.h154
-rw-r--r--openbsc/include/openbsc/gprs_gb_parse.h52
-rw-r--r--openbsc/include/openbsc/gprs_utils.h3
-rw-r--r--openbsc/src/gprs/Makefile.am3
-rw-r--r--openbsc/src/gprs/gb_proxy.c1617
-rw-r--r--openbsc/src/gprs/gb_proxy_patch.c475
-rw-r--r--openbsc/src/gprs/gb_proxy_peer.c200
-rw-r--r--openbsc/src/gprs/gb_proxy_tlli.c544
-rw-r--r--openbsc/src/gprs/gb_proxy_vty.c52
-rw-r--r--openbsc/src/gprs/gprs_gb_parse.c642
-rw-r--r--openbsc/src/gprs/gprs_utils.c39
-rw-r--r--openbsc/tests/gbproxy/Makefile.am4
-rw-r--r--openbsc/tests/gbproxy/gbproxy_test.c893
-rw-r--r--openbsc/tests/gbproxy/gbproxy_test.ok474
14 files changed, 3394 insertions, 1758 deletions
diff --git a/openbsc/include/openbsc/gb_proxy.h b/openbsc/include/openbsc/gb_proxy.h
index d6dde109d..9fcffd431 100644
--- a/openbsc/include/openbsc/gb_proxy.h
+++ b/openbsc/include/openbsc/gb_proxy.h
@@ -11,6 +11,8 @@
#include <regex.h>
struct rate_ctr_group;
+struct gprs_gb_parse_context;
+struct tlv_parsed;
enum gbproxy_patch_mode {
GBPROX_PATCH_DEFAULT,
@@ -22,6 +24,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;
@@ -44,10 +82,15 @@ struct gbproxy_config {
enum gbproxy_patch_mode patch_mode;
int tlli_max_age;
int tlli_max_len;
+ int patch_ptmsi;
/* IMSI checking/matching */
int check_imsi;
regex_t imsi_re_comp;
+
+ /* Used to generate identifiers */
+ unsigned bss_ptmsi_state;
+ unsigned sgsn_tlli_state;
};
struct gbproxy_patch_state {
@@ -81,14 +124,26 @@ struct gbproxy_peer {
struct gbproxy_patch_state patch_state;
};
+struct gbproxy_tlli_state {
+ uint32_t current;
+ uint32_t assigned;
+ int bss_validated;
+ int net_validated;
+
+ uint32_t ptmsi;
+};
+
struct gbproxy_tlli_info {
struct llist_head list;
- uint32_t tlli;
+ struct gbproxy_tlli_state tlli;
+ struct gbproxy_tlli_state sgsn_tlli;
+
time_t timestamp;
uint8_t *mi_data;
size_t mi_data_len;
+
int enable_patching;
};
@@ -113,26 +168,85 @@ 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_by_mi(struct gbproxy_peer *peer,
- const uint8_t *mi_data,
- size_t mi_data_len);
-struct gbproxy_tlli_info *gbprox_register_tlli(
+/* 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_peer *gbproxy_peer_alloc(struct gbproxy_config *cfg, uint16_t bvci);
-void gbproxy_peer_free(struct gbproxy_peer *peer);
-int gbprox_check_imsi(struct gbproxy_peer *peer,
- const uint8_t *imsi, size_t imsi_len);
+struct gbproxy_tlli_info *gbproxy_find_tlli(
+ struct gbproxy_peer *peer, uint32_t tlli);
+struct gbproxy_tlli_info *gbproxy_find_tlli_by_mi(
+ struct gbproxy_peer *peer, const uint8_t *mi_data, size_t mi_data_len);
+struct gbproxy_tlli_info *gbproxy_find_tlli_by_sgsn_tlli(
+ struct gbproxy_peer *peer,
+ uint32_t tlli);
+struct gbproxy_tlli_info *gbproxy_find_tlli_by_ptmsi(
+ struct gbproxy_peer *peer,
+ uint32_t ptmsi);
+
+/* needed by gb_proxy_tlli.h */
+uint32_t gbproxy_make_bss_ptmsi(struct gbproxy_peer *peer, uint32_t sgsn_ptmsi);
+uint32_t gbproxy_make_sgsn_tlli(
+ struct gbproxy_peer *peer, struct gbproxy_tlli_info *tlli_info,
+ uint32_t bss_tlli);
+int gbproxy_check_imsi(
+ struct gbproxy_peer *peer, const uint8_t *imsi, size_t imsi_len);
+
+/* Message patching */
+void gbproxy_patch_bssgp(
+ struct msgb *msg, uint8_t *bssgp, size_t bssgp_len,
+ struct gbproxy_peer *peer, struct gbproxy_tlli_info *tlli_info,
+ int *len_change, struct gprs_gb_parse_context *parse_ctx)
+ __attribute__((nonnull));
+
+int gbproxy_patch_llc(
+ struct msgb *msg, uint8_t *llc, size_t llc_len,
+ struct gbproxy_peer *peer, struct gbproxy_tlli_info *tlli_info,
+ int *len_change, struct gprs_gb_parse_context *parse_ctx)
+ __attribute__((nonnull));
+
+int gbproxy_set_patch_filter(
+ struct gbproxy_config *cfg, const char *filter, const char **err_msg);
+void gbproxy_clear_patch_filter(struct gbproxy_config *cfg);
+int gbproxy_check_imsi(
+ struct gbproxy_peer *peer, const uint8_t *imsi, size_t imsi_len);
+
+/* Peer handling */
+struct gbproxy_peer *gbproxy_peer_by_bvci(
+ struct gbproxy_config *cfg, uint16_t bvci) __attribute__((nonnull));
+struct gbproxy_peer *gbproxy_peer_by_nsei(
+ struct gbproxy_config *cfg, uint16_t nsei) __attribute__((nonnull));
+struct gbproxy_peer *gbproxy_peer_by_rai(
+ struct gbproxy_config *cfg, const uint8_t *ra) __attribute__((nonnull));
+struct gbproxy_peer *gbproxy_peer_by_lai(
+ struct gbproxy_config *cfg, const uint8_t *la) __attribute__((nonnull));
+struct gbproxy_peer *gbproxy_peer_by_bssgp_tlv(
+ struct gbproxy_config *cfg, struct tlv_parsed *tp)
+ __attribute__((nonnull));
+struct gbproxy_peer *gbproxy_peer_alloc(struct gbproxy_config *cfg, uint16_t bvci)
+ __attribute__((nonnull));
+void gbproxy_peer_free(struct gbproxy_peer *peer) __attribute__((nonnull));
+int gbproxy_cleanup_peers(struct gbproxy_config *cfg, uint16_t nsei, uint16_t bvci)
+ __attribute__((nonnull));
+
#endif
diff --git a/openbsc/include/openbsc/gprs_gb_parse.h b/openbsc/include/openbsc/gprs_gb_parse.h
new file mode 100644
index 000000000..e5ef4ef43
--- /dev/null
+++ b/openbsc/include/openbsc/gprs_gb_parse.h
@@ -0,0 +1,52 @@
+#pragma once
+
+#include <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)));
diff --git a/openbsc/include/openbsc/gprs_utils.h b/openbsc/include/openbsc/gprs_utils.h
index 2ad5fe490..e610fdec9 100644
--- a/openbsc/include/openbsc/gprs_utils.h
+++ b/openbsc/include/openbsc/gprs_utils.h
@@ -31,3 +31,6 @@ int gprs_msgb_resize_area(struct msgb *msg, uint8_t *area,
size_t old_size, size_t new_size);
char *gprs_apn_to_str(char *out_str, const uint8_t *apn_enc, size_t rest_chars);
int gprs_str_to_apn(uint8_t *apn_enc, size_t max_len, const char *str);
+int gprs_is_mi_tmsi(const uint8_t *value, size_t value_len);
+int gprs_is_mi_imsi(const uint8_t *value, size_t value_len);
+int gprs_parse_mi_tmsi(const uint8_t *value, size_t value_len, uint32_t *tmsi);
diff --git a/openbsc/src/gprs/Makefile.am b/openbsc/src/gprs/Makefile.am
index bad38c8fc..a8de0a4bb 100644
--- a/openbsc/src/gprs/Makefile.am
+++ b/openbsc/src/gprs/Makefile.am
@@ -14,7 +14,8 @@ bin_PROGRAMS = osmo-gbproxy
endif
osmo_gbproxy_SOURCES = gb_proxy.c gb_proxy_main.c gb_proxy_vty.c \
- gprs_llc_parse.c crc24.c gprs_utils.c
+ gb_proxy_patch.c gb_proxy_tlli.c gb_proxy_peer.c \
+ gprs_gb_parse.c gprs_llc_parse.c crc24.c gprs_utils.c
osmo_gbproxy_LDADD = $(top_builddir)/src/libcommon/libcommon.a \
$(OSMO_LIBS)
diff --git a/openbsc/src/gprs/gb_proxy.c b/openbsc/src/gprs/gb_proxy.c
index 64fb55b77..9a9967fce 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,103 +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_PATCH_CRYPT_ERR,
- GBPROX_PEER_CTR_PATCH_ERR,
- GBPROX_PEER_CTR_ATTACH_REQS,
- GBPROX_PEER_CTR_ATTACH_REJS,
- GBPROX_PEER_CTR_TLLI_CACHE_SIZE,
-};
-
-static const struct rate_ctr_desc peer_ctr_description[] = {
- { "blocked", "BVC Block " },
- { "unblocked", "BVC Unblock " },
- { "dropped", "BVC blocked, dropped packet " },
- { "inv-nsei", "NSEI mismatch " },
- { "tx-err", "NS Transmission error " },
- { "raid-mod.bss", "RAID patched (BSS )" },
- { "raid-mod.sgsn", "RAID patched (SGSN)" },
- { "apn-mod.sgsn", "APN patched " },
- { "mod-crypt-err", "Patch error: encrypted " },
- { "mod-err", "Patch error: other " },
- { "attach-reqs", "Attach Request count " },
- { "attach-rejs", "Attach Reject count " },
- { "tlli-cache", "TLLI cache size " },
-};
-
-static const struct rate_ctr_group_desc peer_ctrg_desc = {
- .group_name_prefix = "gbproxy.peer",
- .group_description = "GBProxy Peer Statistics",
- .num_ctr = ARRAY_SIZE(peer_ctr_description),
- .ctr_desc = peer_ctr_description,
-};
-
-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)
-{
- struct gbproxy_peer *peer;
- llist_for_each_entry(peer, &cfg->bts_peers, list) {
- if (peer->bvci == bvci)
- return peer;
- }
- return NULL;
-}
-
-/* Find the gbprox_peer by its NSEI */
-struct gbproxy_peer *gbprox_peer_by_nsei(struct gbproxy_config *cfg, uint16_t nsei)
-{
- struct gbproxy_peer *peer;
- llist_for_each_entry(peer, &cfg->bts_peers, list) {
- if (peer->nsei == nsei)
- return peer;
- }
- return NULL;
-}
-
-/* look-up a peer by its Routeing Area Identification (RAI) */
-static struct gbproxy_peer *peer_by_rai(struct gbproxy_config *cfg, const uint8_t *ra)
-{
- struct gbproxy_peer *peer;
- llist_for_each_entry(peer, &cfg->bts_peers, list) {
- if (!memcmp(peer->ra, ra, 6))
- return peer;
- }
- return NULL;
-}
-
-/* look-up a peer by its Location Area Identification (LAI) */
-static struct gbproxy_peer *peer_by_lai(struct gbproxy_config *cfg, const uint8_t *la)
-{
- struct gbproxy_peer *peer;
- llist_for_each_entry(peer, &cfg->bts_peers, list) {
- if (!memcmp(peer->ra, la, 5))
- return peer;
- }
- return NULL;
-}
-
-/* look-up a peer by its Location Area Code (LAC) */
-static struct gbproxy_peer *peer_by_lac(struct gbproxy_config *cfg, const uint8_t *la)
-{
- struct gbproxy_peer *peer;
- llist_for_each_entry(peer, &cfg->bts_peers, list) {
- if (!memcmp(peer->ra + 3, la + 3, 2))
- return peer;
- }
- return NULL;
-}
-
-
static int check_peer_nsei(struct gbproxy_peer *peer, uint16_t nsei)
{
if (peer->nsei != nsei) {
@@ -196,37 +85,6 @@ static int check_peer_nsei(struct gbproxy_peer *peer, uint16_t nsei)
return 1;
}
-struct gbproxy_peer *gbproxy_peer_alloc(struct gbproxy_config *cfg, uint16_t bvci)
-{
- struct gbproxy_peer *peer;
-
- peer = talloc_zero(tall_bsc_ctx, struct gbproxy_peer);
- if (!peer)
- return NULL;
-
- peer->bvci = bvci;
- peer->ctrg = rate_ctr_group_alloc(peer, &peer_ctrg_desc, bvci);
- peer->cfg = cfg;
-
- llist_add(&peer->list, &cfg->bts_peers);
-
- INIT_LLIST_HEAD(&peer->patch_state.enabled_tllis);
-
- return peer;
-}
-
-void gbproxy_peer_free(struct gbproxy_peer *peer)
-{
- llist_del(&peer->list);
-
- gbprox_delete_tllis(peer);
-
- rate_ctr_group_free(peer->ctrg);
- peer->ctrg = NULL;
-
- talloc_free(peer);
-}
-
/* strip off the NS header */
static void strip_ns_hdr(struct msgb *msg)
{
@@ -234,1389 +92,207 @@ 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 *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;
-};
-
-static struct gbproxy_tlli_info *gbprox_find_tlli(struct gbproxy_peer *peer,
- uint32_t tlli)
-{
- struct gbproxy_tlli_info *tlli_info;
- struct gbproxy_patch_state *state = &peer->patch_state;
-
- llist_for_each_entry(tlli_info, &state->enabled_tllis, list)
- if (tlli_info->tlli == tlli)
- 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, 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, (int)age);
-
- gbprox_delete_tlli(peer, tlli_info);
- deleted_count += 1;
- }
-
- return deleted_count;
-}
-
-static struct gbproxy_tlli_info *gbprox_get_detached_tlli_info(
- struct gbproxy_peer *peer,
- struct gbproxy_tlli_info *tlli_info,
- uint32_t tlli)
-{
- struct gbproxy_patch_state *state = &peer->patch_state;
-
- if (!tlli_info) {
- tlli_info = talloc_zero(peer, struct gbproxy_tlli_info);
- tlli_info->tlli = tlli;
- } else {
- llist_del(&tlli_info->list);
- OSMO_ASSERT(state->enabled_tllis_count > 0);
- state->enabled_tllis_count -= 1;
-
- peer->ctrg->ctr[GBPROX_PEER_CTR_TLLI_CACHE_SIZE].current =
- state->enabled_tllis_count;
- }
-
- return tlli_info;
-}
-
-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_info *tlli_info,
- struct gbproxy_peer *peer, uint32_t new_tlli)
-{
- if (new_tlli == tlli_info->tlli)
- return;
-
- LOGP(DGPRS, LOGL_INFO,
- "The TLLI has been reassigned from %08x to %08x\n",
- tlli_info->tlli, new_tlli);
-
- /* TODO: Save old TLLI */
- tlli_info->tlli = new_tlli;
-}
-
-void gbprox_touch_tlli(struct gbproxy_peer *peer,
- struct gbproxy_tlli_info *tlli_info, time_t now)
-{
- gbprox_get_detached_tlli_info(peer, tlli_info, tlli_info->tlli);
- gbprox_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, tlli);
- tlli_info->tlli = tlli;
- }
- }
-
- tlli_already_known = tlli_info != NULL;
-
- tlli_info = gbprox_get_detached_tlli_info(peer, tlli_info, tlli);
- 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;
-}
-
-/* patch RA identifier in place, update peer accordingly */
-static void gbprox_patch_raid(uint8_t *raid_enc, struct gbproxy_peer *peer,
- int to_bss, const char *log_text)
+/* update peer according to the BSS message */
+static void gbprox_update_current_raid(uint8_t *raid_enc,
+ struct gbproxy_peer *peer,
+ const char *log_text)
{
struct gbproxy_patch_state *state = &peer->patch_state;
const int old_local_mcc = state->local_mcc;
const int old_local_mnc = state->local_mnc;
- 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 (!raid_enc)
+ return;
- if (!to_bss) {
- /* BSS -> SGSN */
- /* save BSS side MCC/MNC */
- if (!peer->cfg->core_mcc || raid.mcc == peer->cfg->core_mcc) {
- state->local_mcc = 0;
- } else {
- state->local_mcc = raid.mcc;
- raid.mcc = peer->cfg->core_mcc;
- }
+ gsm48_parse_ra(&raid, raid_enc);
- if (!peer->cfg->core_mnc || raid.mnc == peer->cfg->core_mnc) {
- state->local_mnc = 0;
- } else {
- state->local_mnc = raid.mnc;
- raid.mnc = peer->cfg->core_mnc;
- }
+ /* save source side MCC/MNC */
+ if (!peer->cfg->core_mcc || raid.mcc == peer->cfg->core_mcc) {
+ state->local_mcc = 0;
} else {
- /* SGSN -> BSS */
- if (state->local_mcc)
- raid.mcc = state->local_mcc;
+ state->local_mcc = raid.mcc;
+ }
- if (state->local_mnc)
- raid.mnc = state->local_mnc;
+ if (!peer->cfg->core_mnc || raid.mnc == peer->cfg->core_mnc) {
+ state->local_mnc = 0;
+ } else {
+ state->local_mnc = raid.mnc;
}
if (old_local_mcc != state->local_mcc ||
old_local_mnc != state->local_mnc)
LOGP(DGPRS, LOGL_NOTICE,
"Patching RAID %sactivated, msg: %s, "
- "local: %d-%d, core: %d-%d, to %s\n",
+ "local: %d-%d, core: %d-%d\n",
state->local_mcc || state->local_mnc ?
"" : "de",
log_text,
state->local_mcc, state->local_mnc,
- peer->cfg->core_mcc, peer->cfg->core_mnc,
- to_bss ? "BSS" : "SGSN");
-
- 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]);
- }
+ peer->cfg->core_mcc, peer->cfg->core_mnc);
}
-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)
+uint32_t gbproxy_make_bss_ptmsi(struct gbproxy_peer *peer,
+ uint32_t sgsn_ptmsi)
{
- 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);
+ uint32_t bss_ptmsi;
+ if (!peer->cfg->patch_ptmsi) {
+ bss_ptmsi = sgsn_ptmsi;
} 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_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->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_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->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;
+ do {
+ bss_ptmsi = rand_r(&peer->cfg->bss_ptmsi_state);
+ bss_ptmsi = bss_ptmsi | 0xC0000000;
- 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;
+ if (gbproxy_find_tlli_by_ptmsi(peer, bss_ptmsi))
+ bss_ptmsi = GSM_RESERVED_TMSI;
+ } while (bss_ptmsi == GSM_RESERVED_TMSI);
}
- return 1;
+ return bss_ptmsi;
}
-static int gbprox_parse_gsm_act_pdp_req(uint8_t *data, size_t data_len,
- struct gbproxy_parse_context *parse_ctx)
+uint32_t gbproxy_make_sgsn_tlli(struct gbproxy_peer *peer,
+ struct gbproxy_tlli_info *tlli_info,
+ uint32_t bss_tlli)
{
- ssize_t old_len;
- uint8_t *value;
- size_t value_len;
-
- parse_ctx->llc_msg_name = "ACT_PDP_REQ";
-
- /* Skip Requested NSAPI */
- /* Skip Requested LLC SAPI */
- v_fixed_shift(&data, &data_len, 2, NULL);
-
- /* Skip Requested QoS (support 04.08 and 24.008) */
- if (lv_shift(&data, &data_len, NULL, &value_len) <= 0 ||
- value_len < 4 || value_len > 14)
- /* invalid */
- return 0;;
-
- /* Skip Requested PDP address */
- if (lv_shift(&data, &data_len, NULL, &value_len) <= 0 ||
- value_len < 2 || value_len > 18)
- /* invalid */
- return 0;
-
- /* Access point name */
- old_len = tlv_match(&data, &data_len,
- GSM48_IE_GSM_APN, &value, &value_len);
-
- if (old_len > 0 && value_len >=1 && value_len <= 100) {
- parse_ctx->apn_ie = data - old_len;
- parse_ctx->apn_ie_len = old_len;
- }
-
- return 1;
-}
-
-struct gbproxy_peer *peer_by_bssgp_tlv(struct gbproxy_config *cfg, struct tlv_parsed *tp)
-{
- if (TLVP_PRESENT(tp, BSSGP_IE_BVCI)) {
- uint16_t bvci;
-
- bvci = ntohs(tlvp_val16_unal(tp, BSSGP_IE_BVCI));
- if (bvci >= 2)
- return peer_by_bvci(cfg, bvci);
- }
-
- if (TLVP_PRESENT(tp, BSSGP_IE_ROUTEING_AREA)) {
- uint8_t *rai = (uint8_t *)TLVP_VAL(tp, BSSGP_IE_ROUTEING_AREA);
- /* Only compare LAC part, since MCC/MNC are possibly patched.
- * Since the LAC of different BSS must be different when
- * MCC/MNC are patched, collisions shouldn't happen. */
- return peer_by_lac(cfg, rai);
- }
-
- if (TLVP_PRESENT(tp, BSSGP_IE_LOCATION_AREA)) {
- uint8_t *lai = (uint8_t *)TLVP_VAL(tp, BSSGP_IE_LOCATION_AREA);
- return peer_by_lac(cfg, lai);
- }
-
- return NULL;
-}
-
-static int gbprox_parse_dtap(uint8_t *data, size_t data_len,
- struct gbproxy_parse_context *parse_ctx) __attribute__((nonnull));
-
-static int gbprox_parse_dtap(uint8_t *data, size_t data_len,
- struct gbproxy_parse_context *parse_ctx)
-{
- struct gsm48_hdr *g48h;
-
- if (v_fixed_shift(&data, &data_len, sizeof(*g48h), (uint8_t **)&g48h) <= 0)
- return 0;
-
- parse_ctx->g48_hdr = g48h;
-
- if ((g48h->proto_discr & 0x0f) != GSM48_PDISC_MM_GPRS &&
- (g48h->proto_discr & 0x0f) != GSM48_PDISC_SM_GPRS)
- return 1;
-
- switch (g48h->msg_type) {
- case GSM48_MT_GMM_ATTACH_REQ:
- return gbprox_parse_gmm_attach_req(data, data_len, parse_ctx);
-
- case GSM48_MT_GMM_ATTACH_ACK:
- return gbprox_parse_gmm_attach_ack(data, data_len, parse_ctx);
-
- case GSM48_MT_GMM_RA_UPD_REQ:
- return gbprox_parse_gmm_ra_upd_req(data, data_len, parse_ctx);
-
- case GSM48_MT_GMM_RA_UPD_ACK:
- return gbprox_parse_gmm_ra_upd_ack(data, data_len, parse_ctx);
-
- case GSM48_MT_GMM_PTMSI_REALL_CMD:
- return gbprox_parse_gmm_ptmsi_reall_cmd(data, data_len, parse_ctx);
-
- case GSM48_MT_GSM_ACT_PDP_REQ:
- return gbprox_parse_gsm_act_pdp_req(data, data_len, parse_ctx);
-
- case GSM48_MT_GMM_ID_RESP:
- return gbprox_parse_gmm_id_resp(data, data_len, parse_ctx);
- break;
-
- case GSM48_MT_GMM_DETACH_REQ:
- /* TODO: Check power off if !to_bss, if yes invalidate */
- parse_ctx->llc_msg_name = "DETACH_REQ";
- break;
-
- 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);
+ uint32_t sgsn_tlli;
+ if (!peer->cfg->patch_ptmsi) {
+ sgsn_tlli = bss_tlli;
+ } else if (tlli_info->sgsn_tlli.ptmsi != GSM_RESERVED_TMSI) {
+ sgsn_tlli = gprs_tmsi2tlli(tlli_info->sgsn_tlli.ptmsi,
+ TLLI_FOREIGN);
} else {
- return patching_is_enabled(peer, GBPROX_PATCH_LLC_ATTACH_REQ);
+ do {
+ /* create random TLLI, 0b01111xxx... */
+ sgsn_tlli = rand_r(&peer->cfg->sgsn_tlli_state);
+ sgsn_tlli = (sgsn_tlli & 0x7fffffff) | 0x78000000;
+
+ if (gbproxy_find_tlli_by_sgsn_tlli(peer, sgsn_tlli))
+ sgsn_tlli = 0;
+ } while (!sgsn_tlli);
}
+ return sgsn_tlli;
}
-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)
+/* patch BSSGP message */
+static void gbprox_process_bssgp_ul(struct gbproxy_config *cfg,
+ struct msgb *msg,
+ struct gbproxy_peer *peer)
{
- struct gprs_llc_hdr_parsed *ghp = &parse_ctx->llc_hdr_parsed;
+ struct gprs_gb_parse_context parse_ctx = {0};
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 0;
-
- if (ghp->cmd != GPRS_LLC_UI)
- return 0;
-
- 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));
+ int len_change = 0;
+ time_t now;
+ struct gbproxy_tlli_info *tlli_info = NULL;
-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 (!cfg->core_mcc && !cfg->core_mnc && !cfg->core_apn)
+ return;
- if (!allow_message_patching(peer, parse_ctx->g48_hdr->msg_type))
- return have_patched;
+ parse_ctx.to_bss = 0;
- 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;
- }
+ /* Parse BSSGP/LLC */
+ rc = gprs_gb_parse_bssgp(msgb_bssgph(msg), msgb_bssgp_len(msg),
+ &parse_ctx);
- 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 (!rc) {
+ if (!parse_ctx.need_decryption) {
+ LOGP(DGPRS, LOGL_ERROR,
+ "NSEI=%u(BSS) patching: "
+ "failed to parse BSSGP/GMM message\n",
+ msgb_nsei(msg));
+ return;
+ }
}
- 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;
- }
+ /* Get peer */
+ if (!peer && msgb_bvci(msg) >= 2)
+ peer = gbproxy_peer_by_bvci(cfg, msgb_bvci(msg));
- return have_patched;
-}
+ if (!peer)
+ peer = gbproxy_peer_by_nsei(cfg, msgb_nsei(msg));
-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 (!peer)
+ peer = gbproxy_peer_by_bssgp_tlv(cfg, &parse_ctx.bssgp_tp);
- if (!parse_ctx->tlli_enc &&
- !parse_ctx->ptmsi_enc &&
- !parse_ctx->new_ptmsi_enc &&
- !parse_ctx->imsi)
+ if (!peer) {
+ LOGP(DLLC, LOGL_INFO,
+ "NSEI=%d(BSS) patching: didn't find peer for message, "
+ "PDU %d\n",
+ msgb_nsei(msg), parse_ctx.pdu_type);
+ /* Increment counter */
+ rate_ctr_inc(&cfg->ctrg->ctr[GBPROX_GLOB_CTR_PATCH_PEER_ERR]);
return;
-
- 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->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 = ",";
- }
- LOGP(DGPRS, LOGL_DEBUG, "\n");
-}
-
-static struct gbproxy_tlli_info *gbprox_update_state(
- struct gbproxy_peer *peer, time_t now,
- struct gbproxy_parse_context *parse_ctx)
-{
- struct gbproxy_tlli_info *tlli_info = NULL;
+ now = time(NULL);
- if (!peer->cfg->check_imsi)
- return NULL;
+ if (parse_ctx.bssgp_raid_enc && parse_ctx.old_raid_enc &&
+ memcmp(parse_ctx.bssgp_raid_enc, parse_ctx.old_raid_enc, 6) == 0)
+ parse_ctx.old_raid_matches = 1;
- if (parse_ctx->tlli_enc)
- tlli_info = gbprox_find_tlli(peer, parse_ctx->tlli);
+ gbprox_update_current_raid(parse_ctx.bssgp_raid_enc, peer,
+ parse_ctx.llc_msg_name);
- if (parse_ctx->g48_hdr) {
- switch (parse_ctx->g48_hdr->msg_type) {
+ 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;
- 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 &&
- parse_ctx->to_bss) {
- /* A new PTMSI has been signaled in the message,
- * register new TLLI */
- uint32_t new_ptmsi;
- uint32_t new_tlli;
- if (!parse_mi_tmsi(parse_ctx->new_ptmsi_enc, GSM48_TMSI_LEN,
- &new_ptmsi)) {
- LOGP(DGPRS, LOGL_ERROR,
- "Failed to parse new TLLI/PTMSI (current is %08x)\n",
- parse_ctx->tlli);
- return tlli_info;
- }
- new_tlli = gprs_tmsi2tlli(new_ptmsi, TLLI_LOCAL);
- LOGP(DGPRS, LOGL_INFO,
- "Got new TLLI/PTMSI %08x/%08x (current is %08x)\n",
- new_tlli, new_ptmsi, parse_ctx->tlli);
- if (tlli_info) {
- gbprox_reassign_tlli(tlli_info, peer, new_tlli);
- gbprox_touch_tlli(peer, tlli_info, now);
- } else {
- tlli_info =
- gbprox_register_tlli(peer, new_tlli,
- parse_ctx->imsi,
- parse_ctx->imsi_len, now);
- }
- } else if (parse_ctx->tlli_enc && parse_ctx->llc) {
- tlli_info =
- gbprox_register_tlli(peer, parse_ctx->tlli,
- parse_ctx->imsi,
- parse_ctx->imsi_len, now);
- } else if (tlli_info) {
- gbprox_touch_tlli(peer, tlli_info, now);
- }
-
- if (parse_ctx->imsi && tlli_info && tlli_info->mi_data_len == 0)
- gbprox_update_tlli_info(tlli_info,
- parse_ctx->imsi, parse_ctx->imsi_len);
-
- 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);
-}
+ gprs_gb_log_parse_context(&parse_ctx, "BSSGP");
-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;
+ tlli_info = gbproxy_update_tlli_state_ul(peer, now, &parse_ctx);
- if (bssgp_len < sizeof(struct bssgp_normal_hdr))
- return 0;
+ gbproxy_patch_bssgp(msg, msgb_bssgph(msg), msgb_bssgp_len(msg),
+ peer, tlli_info, &len_change, &parse_ctx);
- bgph = (struct bssgp_normal_hdr *)bssgp;
- pdu_type = bgph->pdu_type;
+ gbproxy_update_tlli_state_after(peer, tlli_info, now, &parse_ctx);
- 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);
- }
-
- if (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->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,
- "Failed to patch BSSGP message as requested: %s.\n", err_info);
}
/* patch BSSGP message to use core_mcc/mnc on the SGSN side */
-static void gbprox_process_bssgp_message(struct gbproxy_config *cfg,
- struct msgb *msg,
- struct gbproxy_peer *peer, int to_bss)
+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;
- struct gbproxy_tlli_info *tlli_info;
-
- if (!cfg->core_mcc && !cfg->core_mnc && !cfg->core_apn)
- return;
+ struct gbproxy_tlli_info *tlli_info = NULL;
- parse_ctx.to_bss = to_bss;
+ 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) {
LOGP(DGPRS, LOGL_ERROR,
- "Failed to parse BSSGP/GMM message\n");
+ "NSEI=%u(SGSN) patching: "
+ "failed to parse BSSGP/GMM message\n",
+ msgb_nsei(msg));
return;
}
}
if (!peer && msgb_bvci(msg) >= 2)
- peer = peer_by_bvci(cfg, msgb_bvci(msg));
-
- if (!peer && !to_bss)
- peer = gbprox_peer_by_nsei(cfg, msgb_nsei(msg));
+ peer = gbproxy_peer_by_bvci(cfg, msgb_bvci(msg));
if (!peer)
- peer = peer_by_bssgp_tlv(cfg, &parse_ctx.bssgp_tp);
+ peer = gbproxy_peer_by_bssgp_tlv(cfg, &parse_ctx.bssgp_tp);
if (!peer) {
LOGP(DLLC, LOGL_INFO,
- "NSEI=%d(%s) patching: didn't find peer for message, "
+ "NSEI=%d(SGSN) patching: didn't find peer for message, "
"PDU %d\n",
- msgb_nsei(msg), to_bss ? "SGSN" : "BSS", parse_ctx.pdu_type);
+ msgb_nsei(msg), parse_ctx.pdu_type);
/* Increment counter */
rate_ctr_inc(&cfg->ctrg->ctr[GBPROX_GLOB_CTR_PATCH_PEER_ERR]);
return;
@@ -1624,12 +300,25 @@ static void gbprox_process_bssgp_message(struct gbproxy_config *cfg,
now = time(NULL);
- tlli_info = gbprox_update_state(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");
- gbprox_patch_bssgp(msg, msgb_bssgph(msg), msgb_bssgp_len(msg),
- peer, tlli_info, &len_change, &parse_ctx);
+ tlli_info = gbproxy_update_tlli_state_dl(peer, now, &parse_ctx);
- gbprox_update_state_after(peer, tlli_info, 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;
}
@@ -1643,7 +332,7 @@ static int gbprox_relay2sgsn(struct gbproxy_config *cfg, struct msgb *old_msg,
struct msgb *msg = gprs_msgb_copy(old_msg, "msgb_relay2sgsn");
int rc;
- gbprox_process_bssgp_message(cfg, msg, peer, 0);
+ gbprox_process_bssgp_ul(cfg, msg, peer);
DEBUGP(DGPRS, "NSEI=%u proxying BTS->SGSN (NS_BVCI=%u, NSEI=%u)\n",
msgb_nsei(msg), ns_bvci, cfg->nsip_sgsn_nsei);
@@ -1689,7 +378,7 @@ static int block_unblock_peer(struct gbproxy_config *cfg, uint16_t ptp_bvci, uin
{
struct gbproxy_peer *peer;
- peer = peer_by_bvci(cfg, ptp_bvci);
+ peer = gbproxy_peer_by_bvci(cfg, ptp_bvci);
if (!peer) {
LOGP(DGPRS, LOGL_ERROR, "BVCI=%u: Cannot find BSS\n",
ptp_bvci);
@@ -1719,7 +408,7 @@ static int gbprox_relay2bvci(struct gbproxy_config *cfg, struct msgb *msg, uint1
{
struct gbproxy_peer *peer;
- peer = peer_by_bvci(cfg, ptp_bvci);
+ peer = gbproxy_peer_by_bvci(cfg, ptp_bvci);
if (!peer) {
LOGP(DGPRS, LOGL_ERROR, "BVCI=%u: Cannot find BSS\n",
ptp_bvci);
@@ -1774,7 +463,7 @@ static int gbprox_rx_sig_from_bss(struct gbproxy_config *cfg,
* BSSGP */
if (!TLVP_PRESENT(&tp, BSSGP_IE_ROUTEING_AREA))
goto err_mand_ie;
- from_peer = gbprox_peer_by_nsei(cfg, nsei);
+ from_peer = gbproxy_peer_by_nsei(cfg, nsei);
if (!from_peer)
goto err_no_peer;
memcpy(from_peer->ra, TLVP_VAL(&tp, BSSGP_IE_ROUTEING_AREA),
@@ -1801,7 +490,7 @@ static int gbprox_rx_sig_from_bss(struct gbproxy_config *cfg,
return bssgp_tx_simple_bvci(BSSGP_PDUT_BVC_RESET_ACK,
nsei, 0, ns_bvci);
}
- from_peer = peer_by_bvci(cfg, bvci);
+ from_peer = gbproxy_peer_by_bvci(cfg, bvci);
if (!from_peer) {
/* if a PTP-BVC is reset, and we don't know that
* PTP-BVCI yet, we should allocate a new peer */
@@ -1863,12 +552,12 @@ static int gbprox_rx_paging(struct gbproxy_config *cfg, struct msgb *msg, struct
bvci);
errctr = GBPROX_GLOB_CTR_OTHER_ERR;
} else if (TLVP_PRESENT(tp, BSSGP_IE_ROUTEING_AREA)) {
- peer = peer_by_rai(cfg, TLVP_VAL(tp, BSSGP_IE_ROUTEING_AREA));
+ peer = gbproxy_peer_by_rai(cfg, TLVP_VAL(tp, BSSGP_IE_ROUTEING_AREA));
LOGPC(DGPRS, LOGL_INFO, "routing by RAI to peer BVCI=%u\n",
peer ? peer->bvci : -1);
errctr = GBPROX_GLOB_CTR_INV_RAI;
} else if (TLVP_PRESENT(tp, BSSGP_IE_LOCATION_AREA)) {
- peer = peer_by_lai(cfg, TLVP_VAL(tp, BSSGP_IE_LOCATION_AREA));
+ peer = gbproxy_peer_by_lai(cfg, TLVP_VAL(tp, BSSGP_IE_LOCATION_AREA));
LOGPC(DGPRS, LOGL_INFO, "routing by LAI to peer BVCI=%u\n",
peer ? peer->bvci : -1);
errctr = GBPROX_GLOB_CTR_INV_LAI;
@@ -1903,7 +592,7 @@ static int rx_reset_from_sgsn(struct gbproxy_config *cfg,
if (ptp_bvci >= 2) {
/* A reset for a PTP BVC was received, forward it to its
* respective peer */
- peer = peer_by_bvci(cfg, ptp_bvci);
+ peer = gbproxy_peer_by_bvci(cfg, ptp_bvci);
if (!peer) {
LOGP(DGPRS, LOGL_ERROR, "NSEI=%u BVCI=%u: Cannot find BSS\n",
nsei, ptp_bvci);
@@ -1999,7 +688,7 @@ static int gbprox_rx_sig_from_sgsn(struct gbproxy_config *cfg,
/* RAI IE is mandatory */
if (!TLVP_PRESENT(&tp, BSSGP_IE_ROUTEING_AREA))
goto err_mand_ie;
- peer = peer_by_rai(cfg, TLVP_VAL(&tp, BSSGP_IE_ROUTEING_AREA));
+ peer = gbproxy_peer_by_rai(cfg, TLVP_VAL(&tp, BSSGP_IE_ROUTEING_AREA));
if (!peer)
goto err_no_peer;
rc = gbprox_relay2peer(msg, peer, ns_bvci);
@@ -2061,7 +750,7 @@ int gbprox_rcvmsg(struct gbproxy_config *cfg, struct msgb *msg, uint16_t nsei,
int remote_end_is_sgsn = nsei == cfg->nsip_sgsn_nsei;
if (remote_end_is_sgsn)
- gbprox_process_bssgp_message(cfg, msg, NULL, 1);
+ gbprox_process_bssgp_dl(cfg, msg, NULL);
/* Only BVCI=0 messages need special treatment */
if (ns_bvci == 0 || ns_bvci == 1) {
@@ -2070,7 +759,7 @@ int gbprox_rcvmsg(struct gbproxy_config *cfg, struct msgb *msg, uint16_t nsei,
else
rc = gbprox_rx_sig_from_bss(cfg, msg, nsei, ns_bvci);
} else {
- peer = peer_by_bvci(cfg, ns_bvci);
+ peer = gbproxy_peer_by_bvci(cfg, ns_bvci);
/* All other BVCI are PTP and thus can be simply forwarded */
if (!remote_end_is_sgsn) {
@@ -2145,7 +834,7 @@ int gbprox_signal(unsigned int subsys, unsigned int signal,
if (!nsvc->remote_end_is_sgsn) {
/* from BSS to SGSN */
- peer = gbprox_peer_by_nsei(cfg, nsvc->nsei);
+ peer = gbproxy_peer_by_nsei(cfg, nsvc->nsei);
if (!peer) {
LOGP(DGPRS, LOGL_NOTICE, "signal %u for unknown peer "
"NSEI=%u/NSVCI=%u\n", signal, nsvc->nsei,
@@ -2202,27 +891,13 @@ void gbprox_reset(struct gbproxy_config *cfg)
gbproxy_init_config(cfg);
}
-int gbprox_cleanup_peers(struct gbproxy_config *cfg, uint16_t nsei, uint16_t bvci)
-{
- int counter = 0;
- struct gbproxy_peer *peer, *tmp;
-
- llist_for_each_entry_safe(peer, tmp, &cfg->bts_peers, list) {
- if (peer->nsei != nsei)
- continue;
- if (bvci && peer->bvci != bvci)
- continue;
-
- gbproxy_peer_free(peer);
- counter += 1;
- }
-
- return counter;
-}
-
int gbproxy_init_config(struct gbproxy_config *cfg)
{
+ struct timespec tp;
INIT_LLIST_HEAD(&cfg->bts_peers);
cfg->ctrg = rate_ctr_group_alloc(tall_bsc_ctx, &global_ctrg_desc, 0);
+ clock_gettime(CLOCK_REALTIME, &tp);
+ cfg->bss_ptmsi_state = tp.tv_sec + tp.tv_nsec;
+ cfg->sgsn_tlli_state = tp.tv_sec - tp.tv_nsec;
return 0;
}
diff --git a/openbsc/src/gprs/gb_proxy_patch.c b/openbsc/src/gprs/gb_proxy_patch.c
new file mode 100644
index 000000000..59d0b2f2b
--- /dev/null
+++ b/openbsc/src/gprs/gb_proxy_patch.c
@@ -0,0 +1,475 @@
+/* Gb-proxy message patching */
+
+/* (C) 2014 by On-Waves
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <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;
+}
+
diff --git a/openbsc/src/gprs/gb_proxy_peer.c b/openbsc/src/gprs/gb_proxy_peer.c
new file mode 100644
index 000000000..820d8df87
--- /dev/null
+++ b/openbsc/src/gprs/gb_proxy_peer.c
@@ -0,0 +1,200 @@
+/* Gb proxy peer handling */
+
+/* (C) 2010 by Harald Welte <laforge@gnumonks.org>
+ * (C) 2010-2013 by On-Waves
+ * (C) 2013 by Holger Hans Peter Freyther
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <openbsc/gb_proxy.h>
+
+#include <openbsc/gsm_data.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>
+#include <osmocom/core/talloc.h>
+
+#include <string.h>
+
+static const struct rate_ctr_desc peer_ctr_description[] = {
+ { "blocked", "BVC Block " },
+ { "unblocked", "BVC Unblock " },
+ { "dropped", "BVC blocked, dropped packet " },
+ { "inv-nsei", "NSEI mismatch " },
+ { "tx-err", "NS Transmission error " },
+ { "raid-mod.bss", "RAID patched (BSS )" },
+ { "raid-mod.sgsn", "RAID patched (SGSN)" },
+ { "apn-mod.sgsn", "APN patched " },
+ { "tlli-mod.bss", "TLLI patched (BSS )" },
+ { "tlli-mod.sgsn", "TLLI patched (SGSN)" },
+ { "ptmsi-mod.bss", "P-TMSI patched (BSS )" },
+ { "ptmsi-mod.sgsn","P-TMSI patched (SGSN)" },
+ { "mod-crypt-err", "Patch error: encrypted " },
+ { "mod-err", "Patch error: other " },
+ { "attach-reqs", "Attach Request count " },
+ { "attach-rejs", "Attach Reject count " },
+ { "tlli-unknown", "TLLI from SGSN unknown " },
+ { "tlli-cache", "TLLI cache size " },
+};
+
+static const struct rate_ctr_group_desc peer_ctrg_desc = {
+ .group_name_prefix = "gbproxy.peer",
+ .group_description = "GBProxy Peer Statistics",
+ .num_ctr = ARRAY_SIZE(peer_ctr_description),
+ .ctr_desc = peer_ctr_description,
+};
+
+
+/* Find the gbprox_peer by its BVCI */
+struct gbproxy_peer *gbproxy_peer_by_bvci(struct gbproxy_config *cfg, uint16_t bvci)
+{
+ struct gbproxy_peer *peer;
+ llist_for_each_entry(peer, &cfg->bts_peers, list) {
+ if (peer->bvci == bvci)
+ return peer;
+ }
+ return NULL;
+}
+
+/* Find the gbprox_peer by its NSEI */
+struct gbproxy_peer *gbproxy_peer_by_nsei(struct gbproxy_config *cfg,
+ uint16_t nsei)
+{
+ struct gbproxy_peer *peer;
+ llist_for_each_entry(peer, &cfg->bts_peers, list) {
+ if (peer->nsei == nsei)
+ return peer;
+ }
+ return NULL;
+}
+
+/* look-up a peer by its Routeing Area Identification (RAI) */
+struct gbproxy_peer *gbproxy_peer_by_rai(struct gbproxy_config *cfg,
+ const uint8_t *ra)
+{
+ struct gbproxy_peer *peer;
+ llist_for_each_entry(peer, &cfg->bts_peers, list) {
+ if (!memcmp(peer->ra, ra, 6))
+ return peer;
+ }
+ return NULL;
+}
+
+/* look-up a peer by its Location Area Identification (LAI) */
+struct gbproxy_peer *gbproxy_peer_by_lai(struct gbproxy_config *cfg,
+ const uint8_t *la)
+{
+ struct gbproxy_peer *peer;
+ llist_for_each_entry(peer, &cfg->bts_peers, list) {
+ if (!memcmp(peer->ra, la, 5))
+ return peer;
+ }
+ return NULL;
+}
+
+/* look-up a peer by its Location Area Code (LAC) */
+struct gbproxy_peer *gbproxy_peer_by_lac(struct gbproxy_config *cfg,
+ const uint8_t *la)
+{
+ struct gbproxy_peer *peer;
+ llist_for_each_entry(peer, &cfg->bts_peers, list) {
+ if (!memcmp(peer->ra + 3, la + 3, 2))
+ return peer;
+ }
+ return NULL;
+}
+
+struct gbproxy_peer *gbproxy_peer_by_bssgp_tlv(struct gbproxy_config *cfg,
+ struct tlv_parsed *tp)
+{
+ if (TLVP_PRESENT(tp, BSSGP_IE_BVCI)) {
+ uint16_t bvci;
+
+ bvci = ntohs(tlvp_val16_unal(tp, BSSGP_IE_BVCI));
+ if (bvci >= 2)
+ return gbproxy_peer_by_bvci(cfg, bvci);
+ }
+
+ if (TLVP_PRESENT(tp, BSSGP_IE_ROUTEING_AREA)) {
+ uint8_t *rai = (uint8_t *)TLVP_VAL(tp, BSSGP_IE_ROUTEING_AREA);
+ /* Only compare LAC part, since MCC/MNC are possibly patched.
+ * Since the LAC of different BSS must be different when
+ * MCC/MNC are patched, collisions shouldn't happen. */
+ return gbproxy_peer_by_lac(cfg, rai);
+ }
+
+ if (TLVP_PRESENT(tp, BSSGP_IE_LOCATION_AREA)) {
+ uint8_t *lai = (uint8_t *)TLVP_VAL(tp, BSSGP_IE_LOCATION_AREA);
+ return gbproxy_peer_by_lac(cfg, lai);
+ }
+
+ return NULL;
+}
+
+
+struct gbproxy_peer *gbproxy_peer_alloc(struct gbproxy_config *cfg, uint16_t bvci)
+{
+ struct gbproxy_peer *peer;
+
+ peer = talloc_zero(tall_bsc_ctx, struct gbproxy_peer);
+ if (!peer)
+ return NULL;
+
+ peer->bvci = bvci;
+ peer->ctrg = rate_ctr_group_alloc(peer, &peer_ctrg_desc, bvci);
+ peer->cfg = cfg;
+
+ llist_add(&peer->list, &cfg->bts_peers);
+
+ INIT_LLIST_HEAD(&peer->patch_state.enabled_tllis);
+
+ return peer;
+}
+
+void gbproxy_peer_free(struct gbproxy_peer *peer)
+{
+ llist_del(&peer->list);
+
+ gbproxy_delete_tllis(peer);
+
+ rate_ctr_group_free(peer->ctrg);
+ peer->ctrg = NULL;
+
+ talloc_free(peer);
+}
+
+int gbproxy_cleanup_peers(struct gbproxy_config *cfg, uint16_t nsei, uint16_t bvci)
+{
+ int counter = 0;
+ struct gbproxy_peer *peer, *tmp;
+
+ llist_for_each_entry_safe(peer, tmp, &cfg->bts_peers, list) {
+ if (peer->nsei != nsei)
+ continue;
+ if (bvci && peer->bvci != bvci)
+ continue;
+
+ gbproxy_peer_free(peer);
+ counter += 1;
+ }
+
+ return counter;
+}
+
diff --git a/openbsc/src/gprs/gb_proxy_tlli.c b/openbsc/src/gprs/gb_proxy_tlli.c
new file mode 100644
index 000000000..ccd118ed5
--- /dev/null
+++ b/openbsc/src/gprs/gb_proxy_tlli.c
@@ -0,0 +1,544 @@
+/* Gb-proxy TLLI state handling */
+
+/* (C) 2014 by On-Waves
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <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);
+}
+
+
diff --git a/openbsc/src/gprs/gb_proxy_vty.c b/openbsc/src/gprs/gb_proxy_vty.c
index 9574a451f..f1811c3d9 100644
--- a/openbsc/src/gprs/gb_proxy_vty.c
+++ b/openbsc/src/gprs/gb_proxy_vty.c
@@ -104,6 +104,11 @@ static int config_write_gbproxy(struct vty *vty)
else
vty_out(vty, "%s", VTY_NEWLINE);
}
+
+ if (g_cfg->patch_ptmsi > 0)
+ vty_out(vty, " patch-ptmsi%s",
+ VTY_NEWLINE);
+
if (g_cfg->tlli_max_age > 0)
vty_out(vty, " tlli-list max-age %d%s",
g_cfg->tlli_max_age, VTY_NEWLINE);
@@ -193,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;
}
@@ -206,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;
@@ -268,6 +273,28 @@ DEFUN(cfg_gbproxy_no_core_apn,
return set_core_apn(vty, NULL, NULL);
}
+#define GBPROXY_PATCH_PTMSI_STR "Patch P-TMSI/TLLI\n"
+
+DEFUN(cfg_gbproxy_patch_ptmsi,
+ cfg_gbproxy_patch_ptmsi_cmd,
+ "patch-ptmsi",
+ GBPROXY_PATCH_PTMSI_STR)
+{
+ g_cfg->patch_ptmsi = 1;
+
+ return CMD_SUCCESS;
+}
+
+DEFUN(cfg_gbproxy_no_patch_ptmsi,
+ cfg_gbproxy_no_patch_ptmsi_cmd,
+ "no patch-ptmsi",
+ NO_STR GBPROXY_PATCH_PTMSI_STR)
+{
+ g_cfg->patch_ptmsi = 0;
+
+ return CMD_SUCCESS;
+}
+
#define GBPROXY_TLLI_LIST_STR "Set TLLI list parameters\n"
#define GBPROXY_MAX_AGE_STR "Limit maximum age\n"
@@ -377,7 +404,7 @@ DEFUN(show_gbproxy_tllis, show_gbproxy_tllis_cmd, "show gbproxy tllis",
snprintf(mi_buf, sizeof(mi_buf), "(none)");
}
vty_out(vty, " TLLI %08x, IMSI %s, AGE %d%s",
- tlli_info->tlli, mi_buf, (int)age,
+ tlli_info->tlli.current, mi_buf, (int)age,
VTY_NEWLINE);
}
}
@@ -395,7 +422,7 @@ DEFUN(delete_gb_bvci, delete_gb_bvci_cmd,
const uint16_t bvci = atoi(argv[1]);
int counter;
- counter = gbprox_cleanup_peers(g_cfg, nsei, bvci);
+ counter = gbproxy_cleanup_peers(g_cfg, nsei, bvci);
if (counter == 0) {
vty_out(vty, "BVC not found%s", VTY_NEWLINE);
@@ -431,7 +458,7 @@ DEFUN(delete_gb_nsei, delete_gb_nsei_cmd,
if (delete_bvc) {
if (!dry_run)
- counter = gbprox_cleanup_peers(g_cfg, nsei, 0);
+ counter = gbproxy_cleanup_peers(g_cfg, nsei, 0);
else {
struct gbproxy_peer *peer;
counter = 0;
@@ -514,7 +541,7 @@ DEFUN(delete_gb_tlli, delete_gb_tlli_cmd,
break;
}
- peer = gbprox_peer_by_nsei(g_cfg, nsei);
+ peer = gbproxy_peer_by_nsei(g_cfg, nsei);
if (!peer) {
vty_out(vty, "Didn't find peer with NSEI %d%s",
nsei, VTY_NEWLINE);
@@ -524,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);
@@ -532,7 +559,7 @@ DEFUN(delete_gb_tlli, delete_gb_tlli_cmd,
}
llist_for_each_entry_safe(tlli_info, nxt, &state->enabled_tllis, list) {
- if (match == MATCH_TLLI && tlli_info->tlli != tlli)
+ if (match == MATCH_TLLI && tlli_info->tlli.current != tlli)
continue;
if (match == MATCH_IMSI) {
@@ -544,8 +571,9 @@ DEFUN(delete_gb_tlli, delete_gb_tlli_cmd,
if (strcmp(mi_buf, imsi) != 0)
continue;
}
- vty_out(vty, "Deleting TLLI %08x%s", tlli_info->tlli, VTY_NEWLINE);
- gbprox_delete_tlli(peer, tlli_info);
+ vty_out(vty, "Deleting TLLI %08x%s", tlli_info->tlli.current,
+ VTY_NEWLINE);
+ gbproxy_delete_tlli(peer, tlli_info);
found += 1;
}
@@ -574,11 +602,13 @@ int gbproxy_vty_init(void)
install_element(GBPROXY_NODE, &cfg_gbproxy_core_mnc_cmd);
install_element(GBPROXY_NODE, &cfg_gbproxy_core_apn_cmd);
install_element(GBPROXY_NODE, &cfg_gbproxy_core_apn_match_cmd);
+ install_element(GBPROXY_NODE, &cfg_gbproxy_patch_ptmsi_cmd);
install_element(GBPROXY_NODE, &cfg_gbproxy_tlli_list_max_age_cmd);
install_element(GBPROXY_NODE, &cfg_gbproxy_tlli_list_max_len_cmd);
install_element(GBPROXY_NODE, &cfg_gbproxy_no_core_mcc_cmd);
install_element(GBPROXY_NODE, &cfg_gbproxy_no_core_mnc_cmd);
install_element(GBPROXY_NODE, &cfg_gbproxy_no_core_apn_cmd);
+ install_element(GBPROXY_NODE, &cfg_gbproxy_no_patch_ptmsi_cmd);
install_element(GBPROXY_NODE, &cfg_gbproxy_tlli_list_no_max_age_cmd);
install_element(GBPROXY_NODE, &cfg_gbproxy_tlli_list_no_max_len_cmd);
install_element(GBPROXY_NODE, &cfg_gbproxy_patch_mode_cmd);
diff --git a/openbsc/src/gprs/gprs_gb_parse.c b/openbsc/src/gprs/gprs_gb_parse.c
new file mode 100644
index 000000000..72c0d57e8
--- /dev/null
+++ b/openbsc/src/gprs/gprs_gb_parse.c
@@ -0,0 +1,642 @@
+/* GPRS Gb message parser */
+
+/* (C) 2014 by On-Waves
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <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");
+}
+
diff --git a/openbsc/src/gprs/gprs_utils.c b/openbsc/src/gprs/gprs_utils.c
index 1a8fa4316..55d4efda1 100644
--- a/openbsc/src/gprs/gprs_utils.c
+++ b/openbsc/src/gprs/gprs_utils.c
@@ -24,6 +24,8 @@
#include <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;
+}
+
diff --git a/openbsc/tests/gbproxy/Makefile.am b/openbsc/tests/gbproxy/Makefile.am
index 409d79125..f6dd78595 100644
--- a/openbsc/tests/gbproxy/Makefile.am
+++ b/openbsc/tests/gbproxy/Makefile.am
@@ -9,6 +9,10 @@ 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_peer.o \
+ $(top_builddir)/src/gprs/gb_proxy_tlli.o \
+ $(top_builddir)/src/gprs/gprs_gb_parse.o \
$(top_builddir)/src/gprs/gprs_llc_parse.o \
$(top_builddir)/src/gprs/crc24.o \
$(top_builddir)/src/gprs/gprs_utils.o \
diff --git a/openbsc/tests/gbproxy/gbproxy_test.c b/openbsc/tests/gbproxy/gbproxy_test.c
index 5363749c6..a8a84af84 100644
--- a/openbsc/tests/gbproxy/gbproxy_test.c
+++ b/openbsc/tests/gbproxy/gbproxy_test.c
@@ -25,12 +25,14 @@
#include <osmocom/core/signal.h>
#include <osmocom/core/rate_ctr.h>
#include <osmocom/gsm/tlv.h>
+#include <osmocom/gsm/gsm_utils.h>
#include <osmocom/gprs/gprs_msgb.h>
#include <osmocom/gprs/gprs_ns.h>
#include <osmocom/gprs/gprs_bssgp.h>
#include <openbsc/gb_proxy.h>
#include <openbsc/gprs_utils.h>
+#include <openbsc/gprs_llc.h>
#include <openbsc/debug.h>
#define REMOTE_BSS_ADDR 0x01020304
@@ -124,10 +126,19 @@ static int dump_peers(FILE *stream, int indent, time_t now,
} else {
snprintf(mi_buf, sizeof(mi_buf), "(none)");
}
- rc = fprintf(stream,
- "%*s TLLI %08x, IMSI %s, AGE %d\n",
- indent, "",
- tlli_info->tlli, mi_buf, (int)age);
+ fprintf(stream, "%*s TLLI %08x",
+ indent, "", tlli_info->tlli.current);
+ if (tlli_info->tlli.assigned)
+ fprintf(stream, "/%08x", tlli_info->tlli.assigned);
+ if (tlli_info->sgsn_tlli.current) {
+ fprintf(stream, " -> %08x",
+ tlli_info->sgsn_tlli.current);
+ if (tlli_info->sgsn_tlli.assigned)
+ fprintf(stream, "/%08x",
+ tlli_info->sgsn_tlli.assigned);
+ }
+ rc = fprintf(stream, ", IMSI %s, AGE %d\n",
+ mi_buf, (int)age);
if (rc < 0)
return rc;
}
@@ -136,130 +147,145 @@ static int dump_peers(FILE *stream, int indent, time_t now,
return 0;
}
-/* Base Station Subsystem GPRS Protocol: GSM A-I/F DTAP - Attach Request */
-static const unsigned char bssgp_attach_req[75] = {
- 0x01, 0xbb, 0xc5, 0x46, 0x79, 0x00, 0x00, 0x04,
- 0x08, 0x88, 0x11, 0x22, 0x33, 0x40, 0x50, 0x60,
- 0x75, 0x30, 0x00, 0x80, 0x0e, 0x00, 0x34, 0x01,
- 0xc0, 0x01, 0x08, 0x01, 0x02, 0xf5, 0xe0, 0x21,
- 0x08, 0x02, 0x05, 0xf4, 0xfb, 0xc5, 0x46, 0x79,
- 0x11, 0x22, 0x33, 0x40, 0x50, 0x60, 0x19, 0x18,
- 0xb3, 0x43, 0x2b, 0x25, 0x96, 0x62, 0x00, 0x60,
- 0x80, 0x9a, 0xc2, 0xc6, 0x62, 0x00, 0x60, 0x80,
- 0xba, 0xc8, 0xc6, 0x62, 0x00, 0x60, 0x80, 0x00,
- 0x16, 0x6d, 0x01
+/* DTAP - Attach Request */
+static const unsigned char dtap_attach_req[] = {
+ 0x08, 0x01, 0x02, 0xf5, 0xe0, 0x21, 0x08, 0x02,
+ 0x05, 0xf4, 0xfb, 0xc5, 0x46, 0x79, 0x11, 0x22,
+ 0x33, 0x40, 0x50, 0x60, 0x19, 0x18, 0xb3, 0x43,
+ 0x2b, 0x25, 0x96, 0x62, 0x00, 0x60, 0x80, 0x9a,
+ 0xc2, 0xc6, 0x62, 0x00, 0x60, 0x80, 0xba, 0xc8,
+ 0xc6, 0x62, 0x00, 0x60, 0x80, 0x00,
+};
+
+/* DTAP - Identity Request */
+static const unsigned char dtap_identity_req[] = {
+ 0x08, 0x15, 0x01
};
-/* Base Station Subsystem GPRS Protocol: GSM A-I/F DTAP - Identity Request */
-static const unsigned char bssgp_identity_req[] = {
- 0x00, 0xbb, 0xc5, 0x46, 0x79, 0x00, 0x50, 0x20,
- 0x16, 0x82, 0x02, 0x58, 0x0e, 0x89, 0x41, 0xc0,
- 0x01, 0x08, 0x15, 0x01, 0xff, 0x6c, 0xba
+/* DTAP - Identity Response */
+static const unsigned char dtap_identity_resp[] = {
+ 0x08, 0x16, 0x08, 0x11, 0x12, 0x13, 0x14, 0x15,
+ 0x16, 0x17, 0x18
};
-/* Base Station Subsystem GPRS Protocol: GSM A-I/F DTAP - Identity Response */
-static const unsigned char bssgp_identity_resp[] = {
- 0x01, 0xbb, 0xc5, 0x46, 0x79, 0x00, 0x00, 0x04,
- 0x08, 0x88, 0x11, 0x22, 0x33, 0x40, 0x50, 0x60,
- 0x75, 0x30, 0x00, 0x80, 0x0e, 0x00, 0x11, 0x01,
- 0xc0, 0x0d, 0x08, 0x16, 0x08, 0x11, 0x12, 0x13,
- 0x14, 0x15, 0x16, 0x17, 0x18, 0xb7, 0x1b, 0x9a
+/* DTAP - Attach Accept */
+static const unsigned char dtap_attach_acc[] = {
+ 0x08, 0x02, 0x01, 0x49, 0x04, 0x21, 0x63, 0x54,
+ 0x40, 0x50, 0x60, 0x19, 0xcd, 0xd7, 0x08, 0x17,
+ 0x16, 0x18, 0x05, 0xf4, 0xef, 0xe2, 0xb7, 0x00
};
-/* Base Station Subsystem GPRS Protocol: GSM A-I/F DTAP - Attach Accept */
-static const unsigned char bssgp_attach_acc[88] = {
- 0x00, 0xbb, 0xc5, 0x46, 0x79, 0x00, 0x50, 0x20,
- 0x16, 0x82, 0x02, 0x58, 0x13, 0x99, 0x18, 0xb3,
- 0x43, 0x2b, 0x25, 0x96, 0x62, 0x00, 0x60, 0x80,
- 0x9a, 0xc2, 0xc6, 0x62, 0x00, 0x60, 0x80, 0xba,
- 0xc8, 0xc6, 0x62, 0x00, 0x60, 0x80, 0x00, 0x0a,
- 0x82, 0x08, 0x02, 0x0d, 0x88, 0x11, 0x12, 0x13,
- 0x14, 0x15, 0x16, 0x17, 0x18, 0x00, 0x81, 0x00,
- 0x0e, 0x9e, 0x41, 0xc0, 0x05, 0x08, 0x02, 0x01,
- 0x49, 0x04, 0x21, 0x63, 0x54, 0x40, 0x50, 0x60,
- 0x19, 0xcd, 0xd7, 0x08, 0x17, 0x16, 0x18, 0x05,
- 0xf4, 0xef, 0xe2, 0xb7, 0x00, 0x42, 0x67, 0x9a
+/* DTAP - Attach Complete */
+static const unsigned char dtap_attach_complete[] = {
+ 0x08, 0x03
};
-/* Base Station Subsystem GPRS Protocol: GSM A-I/F DTAP - GMM Information */
-static const unsigned char bssgp_gmm_information[66] = {
- 0x00, 0xef, 0xe2, 0xb7, 0x00, 0x00, 0x50, 0x20,
- 0x16, 0x82, 0x02, 0x58, 0x13, 0x99, 0x18, 0xb3,
- 0x43, 0x2b, 0x25, 0x96, 0x62, 0x00, 0x60, 0x80,
- 0x9a, 0xc2, 0xc6, 0x62, 0x00, 0x60, 0x80, 0xba,
- 0xc8, 0xc6, 0x62, 0x00, 0x60, 0x80, 0x00, 0x0a,
- 0x82, 0x08, 0x02, 0x0d, 0x88, 0x11, 0x12, 0x13,
- 0x14, 0x15, 0x16, 0x17, 0x18, 0x00, 0x81, 0x00,
- 0x0e, 0x88, 0x41, 0xc0, 0x09, 0x08, 0x21, 0x04,
- 0xba, 0x3d
+/* DTAP - GMM Information */
+static const unsigned char dtap_gmm_information[] = {
+ 0x08, 0x21
};
-/* Base Station Subsystem GPRS Protocol: GSM A-I/F DTAP - Routing Area Update Request */
-static const unsigned char bssgp_ra_upd_req[85] = {
- 0x01, 0xbb, 0xc5, 0x46, 0x79, 0x00, 0x00, 0x04,
- 0x08, 0x88, 0x11, 0x22, 0x33, 0x40, 0x50, 0x60,
- 0x70, 0x80, 0x00, 0x80, 0x0e, 0x00, 0x3e, 0x01,
- 0xc0, 0x15, 0x08, 0x08, 0x10, 0x11, 0x22, 0x33,
- 0x40, 0x50, 0x60, 0x1d, 0x19, 0x13, 0x42, 0x33,
- 0x57, 0x2b, 0xf7, 0xc8, 0x48, 0x02, 0x13, 0x48,
- 0x50, 0xc8, 0x48, 0x02, 0x14, 0x48, 0x50, 0xc8,
- 0x48, 0x02, 0x17, 0x49, 0x10, 0xc8, 0x48, 0x02,
- 0x00, 0x19, 0x8b, 0xb2, 0x92, 0x17, 0x16, 0x27,
- 0x07, 0x04, 0x31, 0x02, 0xe5, 0xe0, 0x32, 0x02,
- 0x20, 0x00, 0x96, 0x3e, 0x97
+/* DTAP - Routing Area Update Request */
+static const unsigned char dtap_ra_upd_req[] = {
+ 0x08, 0x08, 0x10, 0x11, 0x22, 0x33, 0x40, 0x50,
+ 0x60, 0x1d, 0x19, 0x13, 0x42, 0x33, 0x57, 0x2b,
+ 0xf7, 0xc8, 0x48, 0x02, 0x13, 0x48, 0x50, 0xc8,
+ 0x48, 0x02, 0x14, 0x48, 0x50, 0xc8, 0x48, 0x02,
+ 0x17, 0x49, 0x10, 0xc8, 0x48, 0x02, 0x00, 0x19,
+ 0x8b, 0xb2, 0x92, 0x17, 0x16, 0x27, 0x07, 0x04,
+ 0x31, 0x02, 0xe5, 0xe0, 0x32, 0x02, 0x20, 0x00
};
-/* Base Station Subsystem GPRS Protocol: GSM A-I/F DTAP - Routing Area Update Accept */
-static const unsigned char bssgp_ra_upd_acc[91] = {
- 0x00, 0xbb, 0xc5, 0x46, 0x79, 0x00, 0x50, 0x20,
- 0x16, 0x82, 0x02, 0x58, 0x13, 0x9d, 0x19, 0x13,
- 0x42, 0x33, 0x57, 0x2b, 0xf7, 0xc8, 0x48, 0x02,
- 0x13, 0x48, 0x50, 0xc8, 0x48, 0x02, 0x14, 0x48,
- 0x50, 0xc8, 0x48, 0x02, 0x17, 0x49, 0x10, 0xc8,
- 0x48, 0x02, 0x00, 0x0a, 0x82, 0x07, 0x04, 0x0d,
- 0x88, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
- 0x18, 0x00, 0x81, 0x00, 0x0e, 0x9d, 0x41, 0xc0,
- 0x19, 0x08, 0x09, 0x00, 0x49, 0x21, 0x63, 0x54,
+/* DTAP - Routing Area Update Accept */
+static const unsigned char dtap_ra_upd_acc[] = {
+ 0x08, 0x09, 0x00, 0x49, 0x21, 0x63, 0x54,
0x40, 0x50, 0x60, 0x19, 0x54, 0xab, 0xb3, 0x18,
- 0x05, 0xf4, 0xef, 0xe2, 0x81, 0x17, 0x17, 0x16,
- 0xc3, 0xbf, 0xcc
+ 0x05, 0xf4, 0xef, 0xe2, 0xb7, 0x00, 0x17, 0x16,
};
-/* Base Station Subsystem GPRS Protocol: GSM A-I/F DTAP - Activate PDP Context Request */
-static const unsigned char bssgp_act_pdp_ctx_req[76] = {
- 0x01, 0xef, 0xe2, 0xb7, 0x00, 0x00, 0x00, 0x04,
- 0x08, 0x88, 0x11, 0x22, 0x33, 0x40, 0x50, 0x60,
- 0x75, 0x30, 0x00, 0x80, 0x0e, 0x00, 0x35, 0x01,
- 0xc0, 0x0d, 0x0a, 0x41, 0x05, 0x03, 0x0c, 0x00,
+/* DTAP - Activate PDP Context Request */
+static const unsigned char dtap_act_pdp_ctx_req[] = {
+ 0x0a, 0x41, 0x05, 0x03, 0x0c, 0x00,
0x00, 0x1f, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x02, 0x01, 0x21, 0x28, 0x03,
0x02, 0x61, 0x62, 0x27, 0x14, 0x80, 0x80, 0x21,
0x10, 0x01, 0x00, 0x00, 0x10, 0x81, 0x06, 0x00,
0x00, 0x00, 0x00, 0x83, 0x06, 0x00, 0x00, 0x00,
- 0x00, 0x5a, 0xff, 0x02
+ 0x00
+};
+
+/* DTAP - Detach Request (MO) */
+/* normal detach, power_off = 1 */
+static const unsigned char dtap_detach_po_req[] = {
+ 0x08, 0x05, 0x09, 0x18, 0x05, 0xf4, 0xef, 0xe2,
+ 0xb7, 0x00, 0x19, 0x03, 0xb9, 0x97, 0xcb
+};
+
+/* DTAP - Detach Request (MO) */
+/* normal detach, power_off = 0 */
+static const unsigned char dtap_detach_req[] = {
+ 0x08, 0x05, 0x01, 0x18, 0x05, 0xf4, 0xef, 0xe2,
+ 0xb7, 0x00, 0x19, 0x03, 0xb9, 0x97, 0xcb
+};
+
+/* DTAP - Detach Accept */
+static const unsigned char dtap_detach_acc[] = {
+ 0x08, 0x06, 0x00
+};
+
+/* GPRS-LLC - SAPI: LLGMM, U, XID */
+static const unsigned char llc_u_xid_ul[] = {
+ 0x41, 0xfb, 0x01, 0x00, 0x0e, 0x00, 0x64, 0x11,
+ 0x05, 0x16, 0x01, 0x90, 0x66, 0xb3, 0x28
+};
+
+/* GPRS-LLC - SAPI: LLGMM, U, XID */
+static const unsigned char llc_u_xid_dl[] = {
+ 0x41, 0xfb, 0x30, 0x84, 0x10, 0x61, 0xb6, 0x64,
+ 0xe4, 0xa9, 0x1a, 0x9e
};
-/* Base Station Subsystem GPRS Protocol: GSM A-I/F DTAP - Detach Request */
-static const unsigned char bssgp_detach_req[44] = {
- 0x01, 0xef, 0xe2, 0xb7, 0x00, 0x00, 0x00, 0x04,
- 0x08, 0x88, 0x11, 0x22, 0x33, 0x40, 0x50, 0x60,
- 0x75, 0x30, 0x00, 0x80, 0x0e, 0x00, 0x15, 0x01,
- 0xc0, 0x19, 0x08, 0x05, 0x01, 0x18, 0x05, 0xf4,
- 0xef, 0xe2, 0xb7, 0x00, 0x19, 0x03, 0xb9, 0x97,
- 0xcb, 0x7e, 0xe1, 0x41
+/* GPRS-LLC - SAPI: LL11, UI, NSAPI 5, DNS query */
+static const unsigned char llc_ui_ll11_dns_query_ul[] = {
+ 0x0b, 0xc0, 0x01, 0x65, 0x00, 0x00, 0x00, 0x45,
+ 0x00, 0x00, 0x38, 0x95, 0x72, 0x00, 0x00, 0x45,
+ 0x11, 0x20, 0x85, 0x0a, 0xc0, 0x07, 0xe4, 0xac,
+ 0x10, 0x01, 0x0a, 0xad, 0xab, 0x00, 0x35, 0x00,
+ 0x24, 0x0e, 0x1c, 0x3b, 0xe0, 0x01, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x6d, 0x05, 0x68, 0x65, 0x69, 0x73, 0x65, 0x02,
+ 0x64, 0x65, 0x00, 0x00, 0x01, 0x00, 0x01, 0x47,
+ 0x8f, 0x07
};
-/* Base Station Subsystem GPRS Protocol: GSM A-I/F DTAP - Detach Accept */
-static const unsigned char bssgp_detach_acc[67] = {
- 0x00, 0xef, 0xe2, 0xb7, 0x00, 0x00, 0x50, 0x20,
- 0x16, 0x82, 0x02, 0x58, 0x13, 0x99, 0x18, 0xb3,
- 0x43, 0x2b, 0x25, 0x96, 0x62, 0x00, 0x60, 0x80,
- 0x9a, 0xc2, 0xc6, 0x62, 0x00, 0x60, 0x80, 0xba,
- 0xc8, 0xc6, 0x62, 0x00, 0x60, 0x80, 0x00, 0x0a,
- 0x82, 0x08, 0x02, 0x0d, 0x88, 0x11, 0x12, 0x13,
- 0x14, 0x15, 0x16, 0x17, 0x18, 0x00, 0x81, 0x00,
- 0x0e, 0x89, 0x41, 0xc0, 0x15, 0x08, 0x06, 0x00,
- 0xf7, 0x35, 0xf0
+/* GPRS-LLC - SAPI: LL11, UI, NSAPI 5, DNS query */
+static const unsigned char llc_ui_ll11_dns_resp_dl[] = {
+ 0x4b, 0xc0, 0x01, 0x65, 0x00, 0x00, 0x00, 0x45,
+ 0x00, 0x00, 0xc6, 0x00, 0x00, 0x40, 0x00, 0x3e,
+ 0x11, 0x7c, 0x69, 0xac, 0x10, 0x01, 0x0a, 0x0a,
+ 0xc0, 0x07, 0xe4, 0x00, 0x35, 0xad, 0xab, 0x00,
+ 0xb2, 0x74, 0x4e, 0x3b, 0xe0, 0x81, 0x80, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x05, 0x00, 0x00, 0x01,
+ 0x6d, 0x05, 0x68, 0x65, 0x69, 0x73, 0x65, 0x02,
+ 0x64, 0x65, 0x00, 0x00, 0x01, 0x00, 0x01, 0xc0,
+ 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0e,
+ 0x10, 0x00, 0x04, 0xc1, 0x63, 0x90, 0x58, 0xc0,
+ 0x0e, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x0e,
+ 0x10, 0x00, 0x16, 0x03, 0x6e, 0x73, 0x32, 0x0c,
+ 0x70, 0x6f, 0x70, 0x2d, 0x68, 0x61, 0x6e, 0x6e,
+ 0x6f, 0x76, 0x65, 0x72, 0x03, 0x6e, 0x65, 0x74,
+ 0x00, 0xc0, 0x0e, 0x00, 0x02, 0x00, 0x01, 0x00,
+ 0x00, 0x0e, 0x10, 0x00, 0x10, 0x02, 0x6e, 0x73,
+ 0x01, 0x73, 0x08, 0x70, 0x6c, 0x75, 0x73, 0x6c,
+ 0x69, 0x6e, 0x65, 0xc0, 0x14, 0xc0, 0x0e, 0x00,
+ 0x02, 0x00, 0x01, 0x00, 0x00, 0x0e, 0x10, 0x00,
+ 0x05, 0x02, 0x6e, 0x73, 0xc0, 0x0e, 0xc0, 0x0e,
+ 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x0e, 0x10,
+ 0x00, 0x05, 0x02, 0x6e, 0x73, 0xc0, 0x5f, 0xc0,
+ 0x0e, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x0e,
+ 0x10, 0x00, 0x12, 0x02, 0x6e, 0x73, 0x0c, 0x70,
+ 0x6f, 0x70, 0x2d, 0x68, 0x61, 0x6e, 0x6e, 0x6f,
+ 0x76, 0x65, 0x72, 0xc0, 0x14, 0xaa, 0xdf, 0x31
};
static int gprs_process_message(struct gprs_ns_inst *nsi, const char *text,
@@ -361,6 +387,106 @@ static void send_ns_unitdata(struct gprs_ns_inst *nsi, const char *text,
gprs_process_message(nsi, text ? text : "UNITDATA", src_addr, msg, bssgp_msg_size + 4);
}
+static void send_bssgp_ul_unitdata(
+ struct gprs_ns_inst *nsi, const char *text,
+ struct sockaddr_in *src_addr, uint16_t nsbvci, uint32_t tlli,
+ struct gprs_ra_id *raid, uint16_t cell_id,
+ const uint8_t *llc_msg, size_t llc_msg_size)
+{
+ /* GPRS Network Service, PDU type: NS_UNITDATA */
+ /* Base Station Subsystem GPRS Protocol: UL_UNITDATA */
+ unsigned char msg[4096] = {
+ 0x01, /* TLLI */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04,
+ 0x08, 0x88, /* RAI */ 0x11, 0x22, 0x33, 0x40, 0x50, 0x60,
+ /* CELL ID */ 0x00, 0x00, 0x00, 0x80, 0x0e, /* LLC LEN */ 0x00, 0x00,
+ };
+
+ size_t bssgp_msg_size = 23 + llc_msg_size;
+
+ OSMO_ASSERT(bssgp_msg_size <= sizeof(msg));
+
+ gsm48_construct_ra(msg + 10, raid);
+ msg[1] = (uint8_t)(tlli >> 24);
+ msg[2] = (uint8_t)(tlli >> 16);
+ msg[3] = (uint8_t)(tlli >> 8);
+ msg[4] = (uint8_t)(tlli >> 0);
+ msg[16] = cell_id / 256;
+ msg[17] = cell_id % 256;
+ msg[21] = llc_msg_size / 256;
+ msg[22] = llc_msg_size % 256;
+ memcpy(msg + 23, llc_msg, llc_msg_size);
+
+ send_ns_unitdata(nsi, text ? text : "BSSGP UL UNITDATA",
+ src_addr, nsbvci, msg, bssgp_msg_size);
+}
+
+static void send_bssgp_dl_unitdata(
+ struct gprs_ns_inst *nsi, const char *text,
+ struct sockaddr_in *src_addr, uint16_t nsbvci, uint32_t tlli,
+ int with_racap_drx, const uint8_t *imsi, size_t imsi_size,
+ const uint8_t *llc_msg, size_t llc_msg_size)
+{
+ /* Base Station Subsystem GPRS Protocol: DL_UNITDATA */
+ unsigned char msg[4096] = {
+ 0x00, /* TLLI */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x20,
+ 0x16, 0x82, 0x02, 0x58,
+ };
+ unsigned char racap_drx[] = {
+ 0x13, 0x99, 0x18, 0xb3, 0x43, 0x2b, 0x25, 0x96,
+ 0x62, 0x00, 0x60, 0x80, 0x9a, 0xc2, 0xc6, 0x62,
+ 0x00, 0x60, 0x80, 0xba, 0xc8, 0xc6, 0x62, 0x00,
+ 0x60, 0x80, 0x00, 0x0a, 0x82, 0x08, 0x02
+ };
+
+ size_t bssgp_msg_size = 0;
+
+ OSMO_ASSERT(51 + imsi_size + llc_msg_size <= sizeof(msg));
+
+ msg[1] = (uint8_t)(tlli >> 24);
+ msg[2] = (uint8_t)(tlli >> 16);
+ msg[3] = (uint8_t)(tlli >> 8);
+ msg[4] = (uint8_t)(tlli >> 0);
+
+ bssgp_msg_size = 12;
+
+ if (with_racap_drx) {
+ memcpy(msg + bssgp_msg_size, racap_drx, sizeof(racap_drx));
+ bssgp_msg_size += sizeof(racap_drx);
+ }
+
+ if (imsi) {
+ OSMO_ASSERT(imsi_size <= 127);
+ msg[bssgp_msg_size] = BSSGP_IE_IMSI;
+ msg[bssgp_msg_size + 1] = 0x80 | imsi_size;
+ memcpy(msg + bssgp_msg_size + 2, imsi, imsi_size);
+ bssgp_msg_size += 2 + imsi_size;
+ }
+
+ if ((bssgp_msg_size % 4) != 0) {
+ size_t abytes = (4 - (bssgp_msg_size + 2) % 4) % 4;
+ msg[bssgp_msg_size] = BSSGP_IE_ALIGNMENT;
+ msg[bssgp_msg_size + 1] = 0x80 | abytes;
+ memset(msg + bssgp_msg_size + 2, 0, abytes);
+ bssgp_msg_size += 2 + abytes;
+ }
+
+ msg[bssgp_msg_size] = BSSGP_IE_LLC_PDU;
+ if (llc_msg_size < 128) {
+ msg[bssgp_msg_size + 1] = 0x80 | llc_msg_size;
+ bssgp_msg_size += 2;
+ } else {
+ msg[bssgp_msg_size + 1] = llc_msg_size / 256;
+ msg[bssgp_msg_size + 2] = llc_msg_size % 256;
+ bssgp_msg_size += 3;
+ }
+ memcpy(msg + bssgp_msg_size, llc_msg, llc_msg_size);
+ bssgp_msg_size += llc_msg_size;
+
+
+ send_ns_unitdata(nsi, text ? text : "BSSGP DL UNITDATA",
+ src_addr, nsbvci, msg, bssgp_msg_size);
+}
+
static void send_bssgp_reset(struct gprs_ns_inst *nsi, struct sockaddr_in *src_addr,
uint16_t bvci)
{
@@ -425,6 +551,82 @@ static void send_bssgp_suspend_ack(struct gprs_ns_inst *nsi,
send_ns_unitdata(nsi, "BVC_SUSPEND_ACK", src_addr, 0, msg, sizeof(msg));
}
+static void send_llc_ul_ui(
+ struct gprs_ns_inst *nsi, const char *text,
+ struct sockaddr_in *src_addr, uint16_t nsbvci, uint32_t tlli,
+ struct gprs_ra_id *raid, uint16_t cell_id,
+ unsigned sapi, unsigned nu,
+ const uint8_t *msg, size_t msg_size)
+{
+ unsigned char llc_msg[4096] = {
+ 0x00, 0xc0, 0x01
+ };
+
+ size_t llc_msg_size = 3 + msg_size + 3;
+ uint8_t e_bit = 0;
+ uint8_t pm_bit = 1;
+ unsigned fcs;
+
+ nu &= 0x01ff;
+
+ OSMO_ASSERT(llc_msg_size <= sizeof(llc_msg));
+
+ llc_msg[0] = (sapi & 0x0f);
+ llc_msg[1] = 0xc0 | (nu >> 6); /* UI frame */
+ llc_msg[2] = (nu << 2) | ((e_bit & 1) << 1) | (pm_bit & 1);
+
+ memcpy(llc_msg + 3, msg, msg_size);
+
+ fcs = gprs_llc_fcs(llc_msg, msg_size + 3);
+ llc_msg[3 + msg_size + 0] = (uint8_t)(fcs >> 0);
+ llc_msg[3 + msg_size + 1] = (uint8_t)(fcs >> 8);
+ llc_msg[3 + msg_size + 2] = (uint8_t)(fcs >> 16);
+
+ send_bssgp_ul_unitdata(nsi, text ? text : "LLC UI",
+ src_addr, nsbvci, tlli, raid, cell_id,
+ llc_msg, llc_msg_size);
+}
+
+static void send_llc_dl_ui(
+ struct gprs_ns_inst *nsi, const char *text,
+ struct sockaddr_in *src_addr, uint16_t nsbvci, uint32_t tlli,
+ int with_racap_drx, const uint8_t *imsi, size_t imsi_size,
+ unsigned sapi, unsigned nu,
+ const uint8_t *msg, size_t msg_size)
+{
+ /* GPRS Network Service, PDU type: NS_UNITDATA */
+ /* Base Station Subsystem GPRS Protocol: UL_UNITDATA */
+ unsigned char llc_msg[4096] = {
+ 0x00, 0x00, 0x01
+ };
+
+ size_t llc_msg_size = 3 + msg_size + 3;
+ uint8_t e_bit = 0;
+ uint8_t pm_bit = 1;
+ unsigned fcs;
+
+ nu &= 0x01ff;
+
+ OSMO_ASSERT(llc_msg_size <= sizeof(llc_msg));
+
+ llc_msg[0] = 0x40 | (sapi & 0x0f);
+ llc_msg[1] = 0xc0 | (nu >> 6); /* UI frame */
+ llc_msg[2] = (nu << 2) | ((e_bit & 1) << 1) | (pm_bit & 1);
+
+ memcpy(llc_msg + 3, msg, msg_size);
+
+ fcs = gprs_llc_fcs(llc_msg, msg_size + 3);
+ llc_msg[3 + msg_size + 0] = (uint8_t)(fcs >> 0);
+ llc_msg[3 + msg_size + 1] = (uint8_t)(fcs >> 8);
+ llc_msg[3 + msg_size + 2] = (uint8_t)(fcs >> 16);
+
+ send_bssgp_dl_unitdata(nsi, text ? text : "LLC UI",
+ src_addr, nsbvci, tlli,
+ with_racap_drx, imsi, imsi_size,
+ llc_msg, llc_msg_size);
+}
+
+
static void setup_ns(struct gprs_ns_inst *nsi, struct sockaddr_in *src_addr,
uint16_t nsvci, uint16_t nsei)
{
@@ -957,7 +1159,16 @@ static void test_gbproxy_ra_patching()
{.mcc = 123, .mnc = 456, .lac = 16464, .rac = 96};
struct gprs_ra_id rai_unknown =
{.mcc = 1, .mnc = 99, .lac = 99, .rac = 96};
+ uint16_t cell_id = 0x7530;
const char *err_msg = NULL;
+ const uint32_t ptmsi = 0xefe2b700;
+ const uint32_t local_tlli = 0xefe2b700;
+ const uint32_t foreign_tlli = 0xbbc54679;
+ const uint8_t imsi[] = {0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18};
+ struct gbproxy_tlli_info *tlli_info;
+ struct gbproxy_peer *peer;
+
+ OSMO_ASSERT(local_tlli == gprs_tmsi2tlli(ptmsi, TLLI_LOCAL));
bssgp_nsi = nsi;
gbcfg.nsi = bssgp_nsi;
@@ -966,12 +1177,13 @@ static void test_gbproxy_ra_patching()
gbcfg.core_mnc = 456;
gbcfg.core_apn = talloc_zero_size(NULL, 100);
gbcfg.core_apn_size = gprs_str_to_apn(gbcfg.core_apn, 100, "foo.bar");
+ gbcfg.patch_ptmsi = 0;
configure_sgsn_peer(&sgsn_peer);
configure_bss_peers(bss_peer, ARRAY_SIZE(bss_peer));
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);
@@ -991,6 +1203,9 @@ static void test_gbproxy_ra_patching()
gprs_dump_nsi(nsi);
dump_peers(stdout, 0, 0, &gbcfg);
+ peer = gbproxy_peer_by_nsei(&gbcfg, 0x1000);
+ OSMO_ASSERT(peer != NULL);
+
send_bssgp_reset_ack(nsi, &sgsn_peer, 0x1002);
send_bssgp_suspend(nsi, &bss_peer[0], &rai_bss);
@@ -1001,72 +1216,137 @@ static void test_gbproxy_ra_patching()
printf("--- Send message from BSS 1 to SGSN, BVCI 0x1002 ---\n\n");
- send_ns_unitdata(nsi, "ATTACH REQUEST", &bss_peer[0], 0x1002,
- bssgp_attach_req, sizeof(bssgp_attach_req));
-
- send_ns_unitdata(nsi, "IDENT REQUEST", &sgsn_peer, 0x1002,
- bssgp_identity_req, sizeof(bssgp_identity_req));
-
- send_ns_unitdata(nsi, "IDENT RESPONSE", &bss_peer[0], 0x1002,
- bssgp_identity_resp, sizeof(bssgp_identity_resp));
-
- send_ns_unitdata(nsi, "ATTACH ACCEPT", &sgsn_peer, 0x1002,
- bssgp_attach_acc, sizeof(bssgp_attach_acc));
+ send_llc_ul_ui(nsi, "ATTACH REQUEST", &bss_peer[0], 0x1002,
+ foreign_tlli, &rai_bss, cell_id,
+ GPRS_SAPI_GMM, 0,
+ dtap_attach_req, sizeof(dtap_attach_req));
+
+ send_llc_dl_ui(nsi, "IDENT REQUEST", &sgsn_peer, 0x1002,
+ foreign_tlli, 0, NULL, 0,
+ GPRS_SAPI_GMM, 0,
+ dtap_identity_req, sizeof(dtap_identity_req));
+
+ send_llc_ul_ui(nsi, "IDENT RESPONSE", &bss_peer[0], 0x1002,
+ foreign_tlli, &rai_bss, cell_id,
+ GPRS_SAPI_GMM, 3,
+ dtap_identity_resp, sizeof(dtap_identity_resp));
+
+ send_llc_dl_ui(nsi, "ATTACH ACCEPT", &sgsn_peer, 0x1002,
+ foreign_tlli, 1, imsi, sizeof(imsi),
+ GPRS_SAPI_GMM, 1,
+ dtap_attach_acc, sizeof(dtap_attach_acc));
+
+ tlli_info = 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);
+ OSMO_ASSERT(!tlli_info->tlli.bss_validated);
+ OSMO_ASSERT(!tlli_info->tlli.net_validated);
+ OSMO_ASSERT(tlli_info->sgsn_tlli.assigned == local_tlli);
+ OSMO_ASSERT(tlli_info->sgsn_tlli.current != local_tlli);
+ OSMO_ASSERT(!tlli_info->sgsn_tlli.bss_validated);
+ OSMO_ASSERT(!tlli_info->sgsn_tlli.net_validated);
+
+ send_llc_ul_ui(nsi, "ATTACH COMPLETE", &bss_peer[0], 0x1002,
+ local_tlli, &rai_bss, cell_id,
+ GPRS_SAPI_GMM, 4,
+ dtap_attach_complete, sizeof(dtap_attach_complete));
+
+ tlli_info = 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);
+ OSMO_ASSERT(tlli_info->tlli.bss_validated);
+ OSMO_ASSERT(!tlli_info->tlli.net_validated);
+ OSMO_ASSERT(tlli_info->sgsn_tlli.assigned == local_tlli);
+ OSMO_ASSERT(tlli_info->sgsn_tlli.current != local_tlli);
+ OSMO_ASSERT(tlli_info->sgsn_tlli.bss_validated);
+ OSMO_ASSERT(!tlli_info->sgsn_tlli.net_validated);
/* Replace APN (1) */
- send_ns_unitdata(nsi, "ACT PDP CTX REQ (REPLACE APN)",
- &bss_peer[0], 0x1002,
- bssgp_act_pdp_ctx_req, sizeof(bssgp_act_pdp_ctx_req));
-
- send_ns_unitdata(nsi, "GMM INFO", &sgsn_peer, 0x1002,
- bssgp_gmm_information, sizeof(bssgp_gmm_information));
+ send_llc_ul_ui(nsi, "ACT PDP CTX REQ (REPLACE APN)", &bss_peer[0], 0x1002,
+ local_tlli, &rai_bss, cell_id,
+ GPRS_SAPI_GMM, 3,
+ dtap_act_pdp_ctx_req, sizeof(dtap_act_pdp_ctx_req));
+
+ tlli_info = 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);
+ OSMO_ASSERT(tlli_info->tlli.bss_validated);
+ OSMO_ASSERT(!tlli_info->tlli.net_validated);
+ OSMO_ASSERT(tlli_info->sgsn_tlli.assigned == local_tlli);
+ OSMO_ASSERT(tlli_info->sgsn_tlli.current != local_tlli);
+ OSMO_ASSERT(tlli_info->sgsn_tlli.bss_validated);
+ OSMO_ASSERT(!tlli_info->sgsn_tlli.net_validated);
+
+ send_llc_dl_ui(nsi, "GMM INFO", &sgsn_peer, 0x1002,
+ local_tlli, 1, imsi, sizeof(imsi),
+ GPRS_SAPI_GMM, 2,
+ dtap_gmm_information, sizeof(dtap_gmm_information));
+
+ tlli_info = 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);
+ OSMO_ASSERT(tlli_info->sgsn_tlli.assigned == 0);
+ OSMO_ASSERT(tlli_info->sgsn_tlli.current == local_tlli);
/* Replace APN (2) */
- send_ns_unitdata(nsi, "ACT PDP CTX REQ (REPLACE APN)",
- &bss_peer[0], 0x1002,
- bssgp_act_pdp_ctx_req, sizeof(bssgp_act_pdp_ctx_req));
+ send_llc_ul_ui(nsi, "ACT PDP CTX REQ (REPLACE APN)", &bss_peer[0], 0x1002,
+ local_tlli, &rai_bss, cell_id,
+ GPRS_SAPI_GMM, 3,
+ dtap_act_pdp_ctx_req, sizeof(dtap_act_pdp_ctx_req));
gbcfg.core_apn[0] = 0;
gbcfg.core_apn_size = 0;
/* Remove APN */
- send_ns_unitdata(nsi, "ACT PDP CTX REQ (REMOVE APN)",
- &bss_peer[0], 0x1002,
- bssgp_act_pdp_ctx_req, sizeof(bssgp_act_pdp_ctx_req));
+ send_llc_ul_ui(nsi, "ACT PDP CTX REQ (REMOVE APN)", &bss_peer[0], 0x1002,
+ local_tlli, &rai_bss, cell_id,
+ GPRS_SAPI_GMM, 3,
+ dtap_act_pdp_ctx_req, sizeof(dtap_act_pdp_ctx_req));
dump_peers(stdout, 0, 0, &gbcfg);
/* Detach */
- send_ns_unitdata(nsi, "DETACH REQ", &bss_peer[0], 0x1002,
- bssgp_detach_req, sizeof(bssgp_detach_req));
+ send_llc_ul_ui(nsi, "DETACH REQ", &bss_peer[0], 0x1002,
+ local_tlli, &rai_bss, cell_id,
+ GPRS_SAPI_GMM, 6,
+ dtap_detach_req, sizeof(dtap_detach_req));
- send_ns_unitdata(nsi, "DETACH ACC", &sgsn_peer, 0x1002,
- bssgp_detach_acc, sizeof(bssgp_detach_acc));
+ send_llc_dl_ui(nsi, "DETACH ACC", &sgsn_peer, 0x1002,
+ local_tlli, 1, imsi, sizeof(imsi),
+ GPRS_SAPI_GMM, 5,
+ dtap_detach_acc, sizeof(dtap_detach_acc));
dump_peers(stdout, 0, 0, &gbcfg);
printf("--- RA update ---\n\n");
- send_ns_unitdata(nsi, "RA UPD REQ", &bss_peer[0], 0x1002,
- bssgp_ra_upd_req, sizeof(bssgp_ra_upd_req));
+ send_llc_ul_ui(nsi, "RA UPD REQ", &bss_peer[0], 0x1002,
+ foreign_tlli, &rai_bss, 0x7080,
+ GPRS_SAPI_GMM, 5,
+ dtap_ra_upd_req, sizeof(dtap_ra_upd_req));
- send_ns_unitdata(nsi, "RA UPD ACC", &sgsn_peer, 0x1002,
- bssgp_ra_upd_acc, sizeof(bssgp_ra_upd_acc));
+ send_llc_dl_ui(nsi, "RA UPD ACC", &sgsn_peer, 0x1002,
+ foreign_tlli, 1, imsi, sizeof(imsi),
+ GPRS_SAPI_GMM, 6,
+ dtap_ra_upd_acc, sizeof(dtap_ra_upd_acc));
/* Remove APN */
- send_ns_unitdata(nsi, "ACT PDP CTX REQ (REMOVE APN)",
- &bss_peer[0], 0x1002,
- bssgp_act_pdp_ctx_req, sizeof(bssgp_act_pdp_ctx_req));
+ send_llc_ul_ui(nsi, "ACT PDP CTX REQ (REMOVE APN)", &bss_peer[0], 0x1002,
+ local_tlli, &rai_bss, cell_id,
+ GPRS_SAPI_GMM, 3,
+ dtap_act_pdp_ctx_req, sizeof(dtap_act_pdp_ctx_req));
dump_peers(stdout, 0, 0, &gbcfg);
- /* Detach */
- send_ns_unitdata(nsi, "DETACH REQ", &bss_peer[0], 0x1002,
- bssgp_detach_req, sizeof(bssgp_detach_req));
-
- send_ns_unitdata(nsi, "DETACH ACC", &sgsn_peer, 0x1002,
- bssgp_detach_acc, sizeof(bssgp_detach_acc));
-
+ /* Detach (power off -> no Detach Accept) */
+ send_llc_ul_ui(nsi, "DETACH REQ (PWR OFF)", &bss_peer[0], 0x1002,
+ local_tlli, &rai_bss, cell_id,
+ GPRS_SAPI_GMM, 6,
+ dtap_detach_po_req, sizeof(dtap_detach_po_req));
dump_global(stdout, 0);
dump_peers(stdout, 0, 0, &gbcfg);
@@ -1074,8 +1354,10 @@ static void test_gbproxy_ra_patching()
printf("--- Bad cases ---\n\n");
printf("TLLI is already detached, shouldn't patch\n");
- send_ns_unitdata(nsi, "ACT PDP CTX REQ", &bss_peer[0], 0x1002,
- bssgp_act_pdp_ctx_req, sizeof(bssgp_act_pdp_ctx_req));
+ send_llc_ul_ui(nsi, "ACT PDP CTX REQ", &bss_peer[0], 0x1002,
+ local_tlli, &rai_bss, cell_id,
+ GPRS_SAPI_GMM, 3,
+ dtap_act_pdp_ctx_req, sizeof(dtap_act_pdp_ctx_req));
printf("Invalid RAI, shouldn't patch\n");
send_bssgp_suspend_ack(nsi, &sgsn_peer, &rai_unknown);
@@ -1088,6 +1370,188 @@ static void test_gbproxy_ra_patching()
nsi = NULL;
}
+static void test_gbproxy_ptmsi_patching()
+{
+ struct gprs_ns_inst *nsi = gprs_ns_instantiate(gprs_ns_callback, NULL);
+ struct sockaddr_in bss_peer[1] = {{0},};
+ struct sockaddr_in sgsn_peer= {0};
+ struct gprs_ra_id rai_bss =
+ {.mcc = 112, .mnc = 332, .lac = 16464, .rac = 96};
+ struct gprs_ra_id rai_sgsn =
+ {.mcc = 123, .mnc = 456, .lac = 16464, .rac = 96};
+ struct gprs_ra_id rai_unknown =
+ {.mcc = 1, .mnc = 99, .lac = 99, .rac = 96};
+ uint16_t cell_id = 0x1234;
+
+ const uint32_t sgsn_ptmsi = 0xefe2b700;
+ const uint32_t local_sgsn_tlli = 0xefe2b700;
+ const uint32_t random_sgsn_tlli = 0x7c69fb81;
+
+ const uint32_t bss_ptmsi = 0xc00f7304;
+ const uint32_t local_bss_tlli = 0xc00f7304;
+ const uint32_t foreign_bss_tlli = 0x8000dead;
+
+ const uint8_t imsi[] = {0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18};
+ struct gbproxy_tlli_info *tlli_info;
+ struct gbproxy_peer *peer;
+ unsigned bss_nu = 0;
+ unsigned sgsn_nu = 0;
+
+ OSMO_ASSERT(local_sgsn_tlli == gprs_tmsi2tlli(sgsn_ptmsi, TLLI_LOCAL));
+
+ bssgp_nsi = nsi;
+ gbcfg.nsi = bssgp_nsi;
+ gbcfg.nsip_sgsn_nsei = SGSN_NSEI;
+ gbcfg.core_mcc = 123;
+ gbcfg.core_mnc = 456;
+ gbcfg.core_apn = talloc_zero_size(NULL, 100);
+ gbcfg.core_apn_size = gprs_str_to_apn(gbcfg.core_apn, 100, "foo.bar");
+ gbcfg.patch_ptmsi = 1;
+ gbcfg.bss_ptmsi_state = 0;
+ gbcfg.sgsn_tlli_state = 1;
+
+ configure_sgsn_peer(&sgsn_peer);
+ configure_bss_peers(bss_peer, ARRAY_SIZE(bss_peer));
+
+ printf("=== %s ===\n", __func__);
+ printf("--- Initialise SGSN ---\n\n");
+
+ connect_sgsn(nsi, &sgsn_peer);
+
+ printf("--- Initialise BSS 1 ---\n\n");
+
+ setup_ns(nsi, &bss_peer[0], 0x1001, 0x1000);
+ setup_bssgp(nsi, &bss_peer[0], 0x1002);
+
+ peer = gbproxy_peer_by_nsei(&gbcfg, 0x1000);
+ OSMO_ASSERT(peer != NULL);
+
+ send_bssgp_reset_ack(nsi, &sgsn_peer, 0x1002);
+
+ send_bssgp_suspend(nsi, &bss_peer[0], &rai_bss);
+ send_bssgp_suspend_ack(nsi, &sgsn_peer, &rai_sgsn);
+
+ gprs_dump_nsi(nsi);
+ dump_global(stdout, 0);
+ dump_peers(stdout, 0, 0, &gbcfg);
+
+ printf("--- Send message from BSS 1 to SGSN, BVCI 0x1002 ---\n\n");
+
+ send_llc_ul_ui(nsi, "ATTACH REQUEST", &bss_peer[0], 0x1002,
+ foreign_bss_tlli, &rai_unknown, cell_id,
+ GPRS_SAPI_GMM, bss_nu++,
+ dtap_attach_req, sizeof(dtap_attach_req));
+
+ dump_peers(stdout, 0, 0, &gbcfg);
+
+ send_llc_dl_ui(nsi, "IDENT REQUEST", &sgsn_peer, 0x1002,
+ random_sgsn_tlli, 0, NULL, 0,
+ GPRS_SAPI_GMM, sgsn_nu++,
+ dtap_identity_req, sizeof(dtap_identity_req));
+
+ dump_peers(stdout, 0, 0, &gbcfg);
+
+ send_llc_ul_ui(nsi, "IDENT RESPONSE", &bss_peer[0], 0x1002,
+ foreign_bss_tlli, &rai_bss, cell_id,
+ GPRS_SAPI_GMM, bss_nu++,
+ dtap_identity_resp, sizeof(dtap_identity_resp));
+
+ dump_peers(stdout, 0, 0, &gbcfg);
+
+ send_llc_dl_ui(nsi, "ATTACH ACCEPT", &sgsn_peer, 0x1002,
+ random_sgsn_tlli, 1, imsi, sizeof(imsi),
+ GPRS_SAPI_GMM, sgsn_nu++,
+ dtap_attach_acc, sizeof(dtap_attach_acc));
+
+ dump_peers(stdout, 0, 0, &gbcfg);
+
+ tlli_info = 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);
+ OSMO_ASSERT(!tlli_info->tlli.bss_validated);
+ OSMO_ASSERT(!tlli_info->tlli.net_validated);
+ OSMO_ASSERT(tlli_info->tlli.ptmsi == bss_ptmsi);
+ OSMO_ASSERT(tlli_info->sgsn_tlli.assigned == local_sgsn_tlli);
+ OSMO_ASSERT(tlli_info->sgsn_tlli.current == random_sgsn_tlli);
+ OSMO_ASSERT(!tlli_info->sgsn_tlli.bss_validated);
+ OSMO_ASSERT(!tlli_info->sgsn_tlli.net_validated);
+ OSMO_ASSERT(tlli_info->sgsn_tlli.ptmsi == sgsn_ptmsi);
+
+ send_llc_ul_ui(nsi, "ATTACH COMPLETE", &bss_peer[0], 0x1002,
+ local_bss_tlli, &rai_bss, cell_id,
+ GPRS_SAPI_GMM, bss_nu++,
+ dtap_attach_complete, sizeof(dtap_attach_complete));
+
+ dump_peers(stdout, 0, 0, &gbcfg);
+
+ tlli_info = 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);
+ OSMO_ASSERT(tlli_info->tlli.bss_validated);
+ OSMO_ASSERT(!tlli_info->tlli.net_validated);
+ OSMO_ASSERT(tlli_info->sgsn_tlli.assigned == local_sgsn_tlli);
+ OSMO_ASSERT(tlli_info->sgsn_tlli.current == random_sgsn_tlli);
+ OSMO_ASSERT(tlli_info->sgsn_tlli.bss_validated);
+ OSMO_ASSERT(!tlli_info->sgsn_tlli.net_validated);
+
+ send_llc_dl_ui(nsi, "GMM INFO", &sgsn_peer, 0x1002,
+ local_sgsn_tlli, 1, imsi, sizeof(imsi),
+ GPRS_SAPI_GMM, sgsn_nu++,
+ dtap_gmm_information, sizeof(dtap_gmm_information));
+
+ dump_peers(stdout, 0, 0, &gbcfg);
+
+ tlli_info = 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);
+ OSMO_ASSERT(tlli_info->sgsn_tlli.current == local_sgsn_tlli);
+ OSMO_ASSERT(tlli_info->sgsn_tlli.assigned == 0);
+
+ /* Non-DTAP */
+ send_bssgp_ul_unitdata(nsi, "XID (UL)", &bss_peer[0], 0x1002,
+ local_bss_tlli, &rai_bss, cell_id,
+ llc_u_xid_ul, sizeof(llc_u_xid_ul));
+
+ send_bssgp_dl_unitdata(nsi, "XID (DL)", &sgsn_peer, 0x1002,
+ local_sgsn_tlli, 1, imsi, sizeof(imsi),
+ llc_u_xid_dl, sizeof(llc_u_xid_dl));
+
+ send_bssgp_ul_unitdata(nsi, "LL11 DNS QUERY (UL)", &bss_peer[0], 0x1002,
+ local_bss_tlli, &rai_bss, cell_id,
+ llc_ui_ll11_dns_query_ul,
+ sizeof(llc_ui_ll11_dns_query_ul));
+
+ send_bssgp_dl_unitdata(nsi, "LL11 DNS RESP (DL)", &sgsn_peer, 0x1002,
+ local_sgsn_tlli, 1, imsi, sizeof(imsi),
+ llc_ui_ll11_dns_resp_dl,
+ sizeof(llc_ui_ll11_dns_resp_dl));
+
+ dump_peers(stdout, 0, 0, &gbcfg);
+
+ /* Detach */
+ send_llc_ul_ui(nsi, "DETACH REQ", &bss_peer[0], 0x1002,
+ local_bss_tlli, &rai_bss, cell_id,
+ GPRS_SAPI_GMM, bss_nu++,
+ dtap_detach_req, sizeof(dtap_detach_req));
+
+ dump_peers(stdout, 0, 0, &gbcfg);
+
+ send_llc_dl_ui(nsi, "DETACH ACC", &sgsn_peer, 0x1002,
+ local_sgsn_tlli, 1, imsi, sizeof(imsi),
+ GPRS_SAPI_GMM, sgsn_nu++,
+ dtap_detach_acc, sizeof(dtap_detach_acc));
+
+ dump_peers(stdout, 0, 0, &gbcfg);
+ dump_global(stdout, 0);
+
+ gbprox_reset(&gbcfg);
+ gprs_ns_destroy(nsi);
+ nsi = NULL;
+}
+
/* TODO: Move tlv testing to libosmocore */
int v_fixed_shift(uint8_t **data, size_t *data_len, size_t len, uint8_t **value);
int tv_fixed_match(uint8_t **data, size_t *data_len, uint8_t tag, size_t len,
@@ -1341,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);
@@ -1358,27 +1822,27 @@ 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 == tlli1);
+ 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 == tlli2);
+ OSMO_ASSERT(tlli_info->tlli.current == tlli2);
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);
- OSMO_ASSERT(tlli_info->tlli == tlli2);
- tlli_info = gbprox_find_tlli_by_mi(peer, imsi2, ARRAY_SIZE(imsi2));
+ OSMO_ASSERT(tlli_info->tlli.current == tlli2);
+ tlli_info = gbproxy_find_tlli_by_mi(peer, imsi2, ARRAY_SIZE(imsi2));
OSMO_ASSERT(!tlli_info);
printf("\n");
@@ -1397,28 +1861,28 @@ 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 == tlli1);
+ 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 == tlli1);
+ OSMO_ASSERT(tlli_info->tlli.current == tlli1);
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 == tlli1);
+ OSMO_ASSERT(tlli_info->tlli.current == tlli1);
printf("\n");
@@ -1437,26 +1901,26 @@ 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 == tlli2);
+ OSMO_ASSERT(tlli_info->tlli.current == tlli2);
printf("\n");
@@ -1464,6 +1928,7 @@ static void test_gbproxy_tlli_expire(void)
}
{
+ struct gbproxy_tlli_info *tlli_info;
int num_removed;
printf("Test TLLI expiry, max_age == 1:\n");
@@ -1474,26 +1939,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 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 = gbproxy_find_tlli_by_mi(peer, imsi1, ARRAY_SIZE(imsi1));
+ OSMO_ASSERT(!tlli_info);
+ tlli_info = gbproxy_find_tlli_by_mi(peer, imsi2, ARRAY_SIZE(imsi2));
+ OSMO_ASSERT(tlli_info);
+ OSMO_ASSERT(tlli_info->tlli.current == tlli2);
+
printf("\n");
gbproxy_peer_free(peer);
}
{
+ struct gbproxy_tlli_info *tlli_info;
int num_removed;
printf("Test TLLI expiry, max_len == 2, max_age == 1:\n");
@@ -1504,28 +1977,37 @@ 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 = gbproxy_find_tlli_by_mi(peer, imsi1, ARRAY_SIZE(imsi1));
+ OSMO_ASSERT(!tlli_info);
+ tlli_info = gbproxy_find_tlli_by_mi(peer, imsi2, ARRAY_SIZE(imsi2));
+ OSMO_ASSERT(!tlli_info);
+ tlli_info = gbproxy_find_tlli_by_mi(peer, imsi3, ARRAY_SIZE(imsi3));
+ OSMO_ASSERT(tlli_info);
+ OSMO_ASSERT(tlli_info->tlli.current == tlli3);
+
printf("\n");
gbproxy_peer_free(peer);
@@ -1554,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 */
@@ -1654,6 +2136,7 @@ int main(int argc, char **argv)
test_gbproxy_ident_changes();
test_gbproxy_imsi_matching();
test_gbproxy_ra_patching();
+ test_gbproxy_ptmsi_patching();
test_gbproxy_tlli_expire();
printf("===== GbProxy test END\n\n");
diff --git a/openbsc/tests/gbproxy/gbproxy_test.ok b/openbsc/tests/gbproxy/gbproxy_test.ok
index 363a6e9be..4dd4e7e5d 100644
--- a/openbsc/tests/gbproxy/gbproxy_test.ok
+++ b/openbsc/tests/gbproxy/gbproxy_test.ok
@@ -1666,10 +1666,10 @@ MESSAGE to SGSN at 0x05060708:32000, msg length 44
result (IDENT RESPONSE) = 44
PROCESSING ATTACH ACCEPT from 0x05060708:32000
-00 00 10 02 00 bb c5 46 79 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 9e 41 c0 05 08 02 01 49 04 21 63 54 40 50 60 19 cd d7 08 17 16 18 05 f4 ef e2 b7 00 42 67 9a
+00 00 10 02 00 bb c5 46 79 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 9e 41 c0 05 08 02 01 49 04 21 63 54 40 50 60 19 cd d7 08 17 16 18 05 f4 ef e2 b7 00 53 62 f1
CALLBACK, event 0, msg length 88, bvci 0x1002
-00 00 10 02 00 bb c5 46 79 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 9e 41 c0 05 08 02 01 49 04 21 63 54 40 50 60 19 cd d7 08 17 16 18 05 f4 ef e2 b7 00 42 67 9a
+00 00 10 02 00 bb c5 46 79 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 9e 41 c0 05 08 02 01 49 04 21 63 54 40 50 60 19 cd d7 08 17 16 18 05 f4 ef e2 b7 00 53 62 f1
NS UNITDATA MESSAGE to BSS, BVCI 0x1002, msg length 88 (gprs_ns_sendmsg)
MESSAGE to BSS at 0x01020304:1111, msg length 92
@@ -1677,6 +1677,18 @@ MESSAGE to BSS at 0x01020304:1111, msg length 92
result (ATTACH ACCEPT) = 92
+PROCESSING ATTACH COMPLETE from 0x01020304:1111
+00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 75 30 00 80 0e 00 08 01 c0 11 08 03 ea 67 11
+
+CALLBACK, event 0, msg length 31, bvci 0x1002
+00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 75 30 00 80 0e 00 08 01 c0 11 08 03 ea 67 11
+
+NS UNITDATA MESSAGE to SGSN, BVCI 0x1002, msg length 31 (gprs_ns_sendmsg)
+MESSAGE to SGSN at 0x05060708:32000, msg length 35
+00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 21 63 54 40 50 60 75 30 00 80 0e 00 08 01 c0 11 08 03 ea 67 11
+
+result (ATTACH COMPLETE) = 35
+
PROCESSING ACT PDP CTX REQ (REPLACE APN) from 0x01020304:1111
00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 75 30 00 80 0e 00 35 01 c0 0d 0a 41 05 03 0c 00 00 1f 10 00 00 00 00 00 00 00 00 02 01 21 28 03 02 61 62 27 14 80 80 21 10 01 00 00 10 81 06 00 00 00 00 83 06 00 00 00 00 5a ff 02
@@ -1727,13 +1739,13 @@ result (ACT PDP CTX REQ (REMOVE APN)) = 75
Peers:
NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96
- RAID patched (BSS ): 8
+ RAID patched (BSS ): 9
RAID patched (SGSN): 2
APN patched : 3
Attach Request count : 1
TLLI cache size : 1
TLLI-Cache: 1
- TLLI efe2b700, IMSI 12131415161718, AGE 0
+ TLLI efe2b700 -> efe2b700, IMSI 12131415161718, AGE 0
PROCESSING DETACH REQ from 0x01020304:1111
00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 75 30 00 80 0e 00 15 01 c0 19 08 05 01 18 05 f4 ef e2 b7 00 19 03 b9 97 cb 7e e1 41
@@ -1760,7 +1772,7 @@ result (DETACH ACC) = 71
Peers:
NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96
- RAID patched (BSS ): 9
+ RAID patched (BSS ): 10
RAID patched (SGSN): 2
APN patched : 3
Attach Request count : 1
@@ -1780,16 +1792,16 @@ MESSAGE to SGSN at 0x05060708:32000, msg length 89
result (RA UPD REQ) = 89
PROCESSING RA UPD ACC from 0x05060708:32000
-00 00 10 02 00 bb c5 46 79 00 50 20 16 82 02 58 13 9d 19 13 42 33 57 2b f7 c8 48 02 13 48 50 c8 48 02 14 48 50 c8 48 02 17 49 10 c8 48 02 00 0a 82 07 04 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 9d 41 c0 19 08 09 00 49 21 63 54 40 50 60 19 54 ab b3 18 05 f4 ef e2 81 17 17 16 c3 bf cc
+00 00 10 02 00 bb c5 46 79 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 9d 41 c0 19 08 09 00 49 21 63 54 40 50 60 19 54 ab b3 18 05 f4 ef e2 b7 00 17 16 d7 59 65
-CALLBACK, event 0, msg length 91, bvci 0x1002
-00 00 10 02 00 bb c5 46 79 00 50 20 16 82 02 58 13 9d 19 13 42 33 57 2b f7 c8 48 02 13 48 50 c8 48 02 14 48 50 c8 48 02 17 49 10 c8 48 02 00 0a 82 07 04 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 9d 41 c0 19 08 09 00 49 21 63 54 40 50 60 19 54 ab b3 18 05 f4 ef e2 81 17 17 16 c3 bf cc
+CALLBACK, event 0, msg length 87, bvci 0x1002
+00 00 10 02 00 bb c5 46 79 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 9d 41 c0 19 08 09 00 49 21 63 54 40 50 60 19 54 ab b3 18 05 f4 ef e2 b7 00 17 16 d7 59 65
-NS UNITDATA MESSAGE to BSS, BVCI 0x1002, msg length 91 (gprs_ns_sendmsg)
-MESSAGE to BSS at 0x01020304:1111, msg length 95
-00 00 10 02 00 bb c5 46 79 00 50 20 16 82 02 58 13 9d 19 13 42 33 57 2b f7 c8 48 02 13 48 50 c8 48 02 14 48 50 c8 48 02 17 49 10 c8 48 02 00 0a 82 07 04 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 9d 41 c0 19 08 09 00 49 11 22 33 40 50 60 19 54 ab b3 18 05 f4 ef e2 81 17 17 16 2e e5 fd
+NS UNITDATA MESSAGE to BSS, BVCI 0x1002, msg length 87 (gprs_ns_sendmsg)
+MESSAGE to BSS at 0x01020304:1111, msg length 91
+00 00 10 02 00 bb c5 46 79 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 9d 41 c0 19 08 09 00 49 11 22 33 40 50 60 19 54 ab b3 18 05 f4 ef e2 b7 00 17 16 3a 03 54
-result (RA UPD ACC) = 95
+result (RA UPD ACC) = 91
PROCESSING ACT PDP CTX REQ (REMOVE APN) from 0x01020304:1111
00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 75 30 00 80 0e 00 35 01 c0 0d 0a 41 05 03 0c 00 00 1f 10 00 00 00 00 00 00 00 00 02 01 21 28 03 02 61 62 27 14 80 80 21 10 01 00 00 10 81 06 00 00 00 00 83 06 00 00 00 00 5a ff 02
@@ -1797,56 +1809,41 @@ PROCESSING ACT PDP CTX REQ (REMOVE APN) from 0x01020304:1111
CALLBACK, event 0, msg length 76, bvci 0x1002
00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 75 30 00 80 0e 00 35 01 c0 0d 0a 41 05 03 0c 00 00 1f 10 00 00 00 00 00 00 00 00 02 01 21 28 03 02 61 62 27 14 80 80 21 10 01 00 00 10 81 06 00 00 00 00 83 06 00 00 00 00 5a ff 02
-NS UNITDATA MESSAGE to SGSN, BVCI 0x1002, msg length 76 (gprs_ns_sendmsg)
-MESSAGE to SGSN at 0x05060708:32000, msg length 80
-00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 21 63 54 40 50 60 75 30 00 80 0e 00 35 01 c0 0d 0a 41 05 03 0c 00 00 1f 10 00 00 00 00 00 00 00 00 02 01 21 28 03 02 61 62 27 14 80 80 21 10 01 00 00 10 81 06 00 00 00 00 83 06 00 00 00 00 5a ff 02
+NS UNITDATA MESSAGE to SGSN, BVCI 0x1002, msg length 71 (gprs_ns_sendmsg)
+MESSAGE to SGSN at 0x05060708:32000, msg length 75
+00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 21 63 54 40 50 60 75 30 00 80 0e 00 30 01 c0 0d 0a 41 05 03 0c 00 00 1f 10 00 00 00 00 00 00 00 00 02 01 21 27 14 80 80 21 10 01 00 00 10 81 06 00 00 00 00 83 06 00 00 00 00 85 fa 60
-result (ACT PDP CTX REQ (REMOVE APN)) = 80
+result (ACT PDP CTX REQ (REMOVE APN)) = 75
Peers:
NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96
- RAID patched (BSS ): 12
+ RAID patched (BSS ): 13
RAID patched (SGSN): 3
- APN patched : 3
+ APN patched : 4
Attach Request count : 1
- TLLI cache size : 2
- TLLI-Cache: 2
- TLLI efe2b700, IMSI (none), AGE 0
- TLLI efe28117, IMSI 12131415161718, AGE 0
-PROCESSING DETACH REQ from 0x01020304:1111
-00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 75 30 00 80 0e 00 15 01 c0 19 08 05 01 18 05 f4 ef e2 b7 00 19 03 b9 97 cb 7e e1 41
+ TLLI cache size : 1
+ TLLI-Cache: 1
+ TLLI bbc54679/efe2b700 -> bbc54679/efe2b700, IMSI 12131415161718, AGE 0
+PROCESSING DETACH REQ (PWR OFF) from 0x01020304:1111
+00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 75 30 00 80 0e 00 15 01 c0 19 08 05 09 18 05 f4 ef e2 b7 00 19 03 b9 97 cb 84 0c eb
CALLBACK, event 0, msg length 44, bvci 0x1002
-00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 75 30 00 80 0e 00 15 01 c0 19 08 05 01 18 05 f4 ef e2 b7 00 19 03 b9 97 cb 7e e1 41
+00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 75 30 00 80 0e 00 15 01 c0 19 08 05 09 18 05 f4 ef e2 b7 00 19 03 b9 97 cb 84 0c eb
NS UNITDATA MESSAGE to SGSN, BVCI 0x1002, msg length 44 (gprs_ns_sendmsg)
MESSAGE to SGSN at 0x05060708:32000, msg length 48
-00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 21 63 54 40 50 60 75 30 00 80 0e 00 15 01 c0 19 08 05 01 18 05 f4 ef e2 b7 00 19 03 b9 97 cb 7e e1 41
-
-result (DETACH REQ) = 48
-
-PROCESSING DETACH ACC from 0x05060708:32000
-00 00 10 02 00 ef e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 89 41 c0 15 08 06 00 f7 35 f0
-
-CALLBACK, event 0, msg length 67, bvci 0x1002
-00 00 10 02 00 ef e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 89 41 c0 15 08 06 00 f7 35 f0
-
-NS UNITDATA MESSAGE to BSS, BVCI 0x1002, msg length 67 (gprs_ns_sendmsg)
-MESSAGE to BSS at 0x01020304:1111, msg length 71
-00 00 10 02 00 ef e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 89 41 c0 15 08 06 00 f7 35 f0
+00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 21 63 54 40 50 60 75 30 00 80 0e 00 15 01 c0 19 08 05 09 18 05 f4 ef e2 b7 00 19 03 b9 97 cb 84 0c eb
-result (DETACH ACC) = 71
+result (DETACH REQ (PWR OFF)) = 48
Gbproxy global:
Peers:
NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96
- RAID patched (BSS ): 13
+ RAID patched (BSS ): 14
RAID patched (SGSN): 3
- APN patched : 3
+ APN patched : 4
Attach Request count : 1
- TLLI cache size : 1
- TLLI-Cache: 1
- TLLI efe28117, IMSI 12131415161718, AGE 0
+ TLLI-Cache: 0
--- Bad cases ---
TLLI is already detached, shouldn't patch
@@ -1880,14 +1877,391 @@ Gbproxy global:
Patch error: no peer : 1
Peers:
NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96
- RAID patched (BSS ): 14
+ RAID patched (BSS ): 15
RAID patched (SGSN): 3
- APN patched : 3
+ APN patched : 4
Attach Request count : 1
- TLLI cache size : 2
- TLLI-Cache: 2
- TLLI efe2b700, IMSI (none), AGE 0
- TLLI efe28117, IMSI 12131415161718, AGE 0
+ TLLI cache size : 1
+ TLLI-Cache: 1
+ TLLI efe2b700 -> efe2b700, IMSI (none), AGE 0
+=== test_gbproxy_ptmsi_patching ===
+--- Initialise SGSN ---
+
+MESSAGE to SGSN at 0x05060708:32000, msg length 12
+02 00 81 01 01 82 01 01 04 82 01 00
+
+PROCESSING RESET_ACK from 0x05060708:32000
+03 01 82 01 01 04 82 01 00
+
+MESSAGE to SGSN at 0x05060708:32000, msg length 1
+0a
+
+result (RESET_ACK) = 1
+
+PROCESSING ALIVE_ACK from 0x05060708:32000
+0b
+
+MESSAGE to SGSN at 0x05060708:32000, msg length 1
+06
+
+result (ALIVE_ACK) = 1
+
+PROCESSING UNBLOCK_ACK from 0x05060708:32000
+07
+
+==> got signal NS_UNBLOCK, NS-VC 0x0101/5.6.7.8:32000
+
+result (UNBLOCK_ACK) = 0
+
+PROCESSING ALIVE from 0x05060708:32000
+0a
+
+MESSAGE to SGSN at 0x05060708:32000, msg length 1
+0b
+
+result (ALIVE) = 1
+
+--- Initialise BSS 1 ---
+
+Setup NS-VC: remote 0x01020304:1111, NSVCI 0x1001(4097), NSEI 0x1000(4096)
+
+PROCESSING RESET from 0x01020304:1111
+02 00 81 01 01 82 10 01 04 82 10 00
+
+==> got signal NS_RESET, NS-VC 0x1001/1.2.3.4:1111
+
+MESSAGE to BSS at 0x01020304:1111, msg length 9
+03 01 82 10 01 04 82 10 00
+
+MESSAGE to BSS at 0x01020304:1111, msg length 1
+0a
+
+result (RESET) = 9
+
+PROCESSING ALIVE from 0x01020304:1111
+0a
+
+MESSAGE to BSS at 0x01020304:1111, msg length 1
+0b
+
+result (ALIVE) = 1
+
+PROCESSING UNBLOCK from 0x01020304:1111
+06
+
+==> got signal NS_UNBLOCK, NS-VC 0x1001/1.2.3.4:1111
+
+MESSAGE to BSS at 0x01020304:1111, msg length 1
+07
+
+result (UNBLOCK) = 1
+
+PROCESSING ALIVE_ACK from 0x01020304:1111
+0b
+
+result (ALIVE_ACK) = 0
+
+Setup BSSGP: remote 0x01020304:1111, BVCI 0x1002(4098)
+
+PROCESSING BVC_RESET from 0x01020304:1111
+00 00 00 00 22 04 82 10 02 07 81 08 08 88 11 22 33 40 50 60 10 00
+
+CALLBACK, event 0, msg length 18, bvci 0x0000
+00 00 00 00 22 04 82 10 02 07 81 08 08 88 11 22 33 40 50 60 10 00
+
+NS UNITDATA MESSAGE to SGSN, BVCI 0x0000, msg length 18 (gprs_ns_sendmsg)
+MESSAGE to SGSN at 0x05060708:32000, msg length 22
+00 00 00 00 22 04 82 10 02 07 81 08 08 88 21 63 54 40 50 60 10 00
+
+result (BVC_RESET) = 22
+
+PROCESSING BVC_RESET_ACK from 0x05060708:32000
+00 00 00 00 23 04 82 10 02
+
+CALLBACK, event 0, msg length 5, bvci 0x0000
+00 00 00 00 23 04 82 10 02
+
+NS UNITDATA MESSAGE to BSS, BVCI 0x0000, msg length 5 (gprs_ns_sendmsg)
+MESSAGE to BSS at 0x01020304:1111, msg length 9
+00 00 00 00 23 04 82 10 02
+
+result (BVC_RESET_ACK) = 9
+
+PROCESSING BVC_SUSPEND from 0x01020304:1111
+00 00 00 00 0b 1f 84 cc d1 75 8b 1b 86 11 22 33 40 50 60
+
+CALLBACK, event 0, msg length 15, bvci 0x0000
+00 00 00 00 0b 1f 84 cc d1 75 8b 1b 86 11 22 33 40 50 60
+
+NS UNITDATA MESSAGE to SGSN, BVCI 0x0000, msg length 15 (gprs_ns_sendmsg)
+MESSAGE to SGSN at 0x05060708:32000, msg length 19
+00 00 00 00 0b 1f 84 cc d1 75 8b 1b 86 21 63 54 40 50 60
+
+result (BVC_SUSPEND) = 19
+
+PROCESSING BVC_SUSPEND_ACK from 0x05060708:32000
+00 00 00 00 0c 1f 84 cc d1 75 8b 1b 86 21 63 54 40 50 60 1d 81 01
+
+CALLBACK, event 0, msg length 18, bvci 0x0000
+00 00 00 00 0c 1f 84 cc d1 75 8b 1b 86 21 63 54 40 50 60 1d 81 01
+
+NS UNITDATA MESSAGE to BSS, BVCI 0x0000, msg length 18 (gprs_ns_sendmsg)
+MESSAGE to BSS at 0x01020304:1111, msg length 22
+00 00 00 00 0c 1f 84 cc d1 75 8b 1b 86 11 22 33 40 50 60 1d 81 01
+
+result (BVC_SUSPEND_ACK) = 22
+
+Current NS-VCIs:
+ VCI 0x1001, NSEI 0x1000, peer 0x01020304:1111
+ VCI 0x0101, NSEI 0x0100, peer 0x05060708:32000
+ NS-VC Block count : 1
+
+Gbproxy global:
+Peers:
+ NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96
+ RAID patched (BSS ): 2
+ RAID patched (SGSN): 1
+ TLLI-Cache: 0
+--- Send message from BSS 1 to SGSN, BVCI 0x1002 ---
+
+PROCESSING ATTACH REQUEST from 0x01020304:1111
+00 00 10 02 01 80 00 de ad 00 00 04 08 88 00 f1 99 00 63 60 12 34 00 80 0e 00 34 01 c0 01 08 01 02 f5 e0 21 08 02 05 f4 fb c5 46 79 11 22 33 40 50 60 19 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 16 6d 01
+
+CALLBACK, event 0, msg length 75, bvci 0x1002
+00 00 10 02 01 80 00 de ad 00 00 04 08 88 00 f1 99 00 63 60 12 34 00 80 0e 00 34 01 c0 01 08 01 02 f5 e0 21 08 02 05 f4 fb c5 46 79 11 22 33 40 50 60 19 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 16 6d 01
+
+NS UNITDATA MESSAGE to SGSN, BVCI 0x1002, msg length 75 (gprs_ns_sendmsg)
+MESSAGE to SGSN at 0x05060708:32000, msg length 79
+00 00 10 02 01 7c 69 fb 81 00 00 04 08 88 21 63 54 00 63 60 12 34 00 80 0e 00 34 01 c0 01 08 01 02 f5 e0 21 08 02 05 f4 fb c5 46 79 11 22 33 40 50 60 19 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 16 6d 01
+
+result (ATTACH REQUEST) = 79
+
+Peers:
+ NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96
+ RAID patched (BSS ): 3
+ RAID patched (SGSN): 1
+ TLLI patched (BSS ): 1
+ Attach Request count : 1
+ TLLI cache size : 1
+ TLLI-Cache: 1
+ TLLI 8000dead -> 7c69fb81, IMSI (none), AGE 0
+PROCESSING IDENT REQUEST from 0x05060708:32000
+00 00 10 02 00 7c 69 fb 81 00 50 20 16 82 02 58 0e 89 41 c0 01 08 15 01 ff 6c ba
+
+CALLBACK, event 0, msg length 23, bvci 0x1002
+00 00 10 02 00 7c 69 fb 81 00 50 20 16 82 02 58 0e 89 41 c0 01 08 15 01 ff 6c ba
+
+NS UNITDATA MESSAGE to BSS, BVCI 0x1002, msg length 23 (gprs_ns_sendmsg)
+MESSAGE to BSS at 0x01020304:1111, msg length 27
+00 00 10 02 00 80 00 de ad 00 50 20 16 82 02 58 0e 89 41 c0 01 08 15 01 ff 6c ba
+
+result (IDENT REQUEST) = 27
+
+Peers:
+ NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96
+ RAID patched (BSS ): 3
+ RAID patched (SGSN): 1
+ TLLI patched (BSS ): 1
+ TLLI patched (SGSN): 1
+ Attach Request count : 1
+ TLLI cache size : 1
+ TLLI-Cache: 1
+ TLLI 8000dead -> 7c69fb81, IMSI (none), AGE 0
+PROCESSING IDENT RESPONSE from 0x01020304:1111
+00 00 10 02 01 80 00 de ad 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 11 01 c0 05 08 16 08 11 12 13 14 15 16 17 18 ad 05 28
+
+CALLBACK, event 0, msg length 40, bvci 0x1002
+00 00 10 02 01 80 00 de ad 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 11 01 c0 05 08 16 08 11 12 13 14 15 16 17 18 ad 05 28
+
+NS UNITDATA MESSAGE to SGSN, BVCI 0x1002, msg length 40 (gprs_ns_sendmsg)
+MESSAGE to SGSN at 0x05060708:32000, msg length 44
+00 00 10 02 01 7c 69 fb 81 00 00 04 08 88 21 63 54 40 50 60 12 34 00 80 0e 00 11 01 c0 05 08 16 08 11 12 13 14 15 16 17 18 ad 05 28
+
+result (IDENT RESPONSE) = 44
+
+Peers:
+ NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96
+ RAID patched (BSS ): 4
+ RAID patched (SGSN): 1
+ TLLI patched (BSS ): 2
+ TLLI patched (SGSN): 1
+ Attach Request count : 1
+ TLLI cache size : 1
+ TLLI-Cache: 1
+ TLLI 8000dead -> 7c69fb81, IMSI 12131415161718, AGE 0
+PROCESSING ATTACH ACCEPT from 0x05060708:32000
+00 00 10 02 00 7c 69 fb 81 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 9e 41 c0 05 08 02 01 49 04 21 63 54 40 50 60 19 cd d7 08 17 16 18 05 f4 ef e2 b7 00 53 62 f1
+
+CALLBACK, event 0, msg length 88, bvci 0x1002
+00 00 10 02 00 7c 69 fb 81 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 9e 41 c0 05 08 02 01 49 04 21 63 54 40 50 60 19 cd d7 08 17 16 18 05 f4 ef e2 b7 00 53 62 f1
+
+NS UNITDATA MESSAGE to BSS, BVCI 0x1002, msg length 88 (gprs_ns_sendmsg)
+MESSAGE to BSS at 0x01020304:1111, msg length 92
+00 00 10 02 00 80 00 de ad 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 9e 41 c0 05 08 02 01 49 04 11 22 33 40 50 60 19 cd d7 08 17 16 18 05 f4 c0 0f 73 04 50 22 97
+
+result (ATTACH ACCEPT) = 92
+
+Peers:
+ NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96
+ RAID patched (BSS ): 4
+ RAID patched (SGSN): 2
+ TLLI patched (BSS ): 2
+ TLLI patched (SGSN): 2
+ P-TMSI patched (SGSN): 1
+ Attach Request count : 1
+ TLLI cache size : 1
+ TLLI-Cache: 1
+ TLLI 8000dead/c00f7304 -> 7c69fb81/efe2b700, IMSI 12131415161718, AGE 0
+PROCESSING ATTACH COMPLETE from 0x01020304:1111
+00 00 10 02 01 c0 0f 73 04 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 08 01 c0 09 08 03 39 d7 bc
+
+CALLBACK, event 0, msg length 31, bvci 0x1002
+00 00 10 02 01 c0 0f 73 04 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 08 01 c0 09 08 03 39 d7 bc
+
+NS UNITDATA MESSAGE to SGSN, BVCI 0x1002, msg length 31 (gprs_ns_sendmsg)
+MESSAGE to SGSN at 0x05060708:32000, msg length 35
+00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 21 63 54 40 50 60 12 34 00 80 0e 00 08 01 c0 09 08 03 39 d7 bc
+
+result (ATTACH COMPLETE) = 35
+
+Peers:
+ NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96
+ RAID patched (BSS ): 5
+ RAID patched (SGSN): 2
+ TLLI patched (BSS ): 3
+ TLLI patched (SGSN): 2
+ P-TMSI patched (SGSN): 1
+ Attach Request count : 1
+ TLLI cache size : 1
+ TLLI-Cache: 1
+ TLLI 8000dead/c00f7304 -> 7c69fb81/efe2b700, IMSI 12131415161718, AGE 0
+PROCESSING GMM INFO from 0x05060708:32000
+00 00 10 02 00 ef e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 88 41 c0 09 08 21 04 ba 3d
+
+CALLBACK, event 0, msg length 66, bvci 0x1002
+00 00 10 02 00 ef e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 88 41 c0 09 08 21 04 ba 3d
+
+NS UNITDATA MESSAGE to BSS, BVCI 0x1002, msg length 66 (gprs_ns_sendmsg)
+MESSAGE to BSS at 0x01020304:1111, msg length 70
+00 00 10 02 00 c0 0f 73 04 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 88 41 c0 09 08 21 04 ba 3d
+
+result (GMM INFO) = 70
+
+Peers:
+ NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96
+ RAID patched (BSS ): 5
+ RAID patched (SGSN): 2
+ TLLI patched (BSS ): 3
+ TLLI patched (SGSN): 3
+ P-TMSI patched (SGSN): 1
+ Attach Request count : 1
+ TLLI cache size : 1
+ TLLI-Cache: 1
+ TLLI c00f7304 -> efe2b700, IMSI 12131415161718, AGE 0
+PROCESSING XID (UL) from 0x01020304:1111
+00 00 10 02 01 c0 0f 73 04 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 0f 41 fb 01 00 0e 00 64 11 05 16 01 90 66 b3 28
+
+CALLBACK, event 0, msg length 38, bvci 0x1002
+00 00 10 02 01 c0 0f 73 04 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 0f 41 fb 01 00 0e 00 64 11 05 16 01 90 66 b3 28
+
+NS UNITDATA MESSAGE to SGSN, BVCI 0x1002, msg length 38 (gprs_ns_sendmsg)
+MESSAGE to SGSN at 0x05060708:32000, msg length 42
+00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 21 63 54 40 50 60 12 34 00 80 0e 00 0f 41 fb 01 00 0e 00 64 11 05 16 01 90 66 b3 28
+
+result (XID (UL)) = 42
+
+PROCESSING XID (DL) from 0x05060708:32000
+00 00 10 02 00 ef e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 8c 41 fb 30 84 10 61 b6 64 e4 a9 1a 9e
+
+CALLBACK, event 0, msg length 70, bvci 0x1002
+00 00 10 02 00 ef e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 8c 41 fb 30 84 10 61 b6 64 e4 a9 1a 9e
+
+NS UNITDATA MESSAGE to BSS, BVCI 0x1002, msg length 70 (gprs_ns_sendmsg)
+MESSAGE to BSS at 0x01020304:1111, msg length 74
+00 00 10 02 00 c0 0f 73 04 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 8c 41 fb 30 84 10 61 b6 64 e4 a9 1a 9e
+
+result (XID (DL)) = 74
+
+PROCESSING LL11 DNS QUERY (UL) from 0x01020304:1111
+00 00 10 02 01 c0 0f 73 04 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 42 0b c0 01 65 00 00 00 45 00 00 38 95 72 00 00 45 11 20 85 0a c0 07 e4 ac 10 01 0a ad ab 00 35 00 24 0e 1c 3b e0 01 00 00 01 00 00 00 00 00 00 01 6d 05 68 65 69 73 65 02 64 65 00 00 01 00 01 47 8f 07
+
+CALLBACK, event 0, msg length 89, bvci 0x1002
+00 00 10 02 01 c0 0f 73 04 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 42 0b c0 01 65 00 00 00 45 00 00 38 95 72 00 00 45 11 20 85 0a c0 07 e4 ac 10 01 0a ad ab 00 35 00 24 0e 1c 3b e0 01 00 00 01 00 00 00 00 00 00 01 6d 05 68 65 69 73 65 02 64 65 00 00 01 00 01 47 8f 07
+
+NS UNITDATA MESSAGE to SGSN, BVCI 0x1002, msg length 89 (gprs_ns_sendmsg)
+MESSAGE to SGSN at 0x05060708:32000, msg length 93
+00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 21 63 54 40 50 60 12 34 00 80 0e 00 42 0b c0 01 65 00 00 00 45 00 00 38 95 72 00 00 45 11 20 85 0a c0 07 e4 ac 10 01 0a ad ab 00 35 00 24 0e 1c 3b e0 01 00 00 01 00 00 00 00 00 00 01 6d 05 68 65 69 73 65 02 64 65 00 00 01 00 01 47 8f 07
+
+result (LL11 DNS QUERY (UL)) = 93
+
+PROCESSING LL11 DNS RESP (DL) from 0x05060708:32000
+00 00 10 02 00 ef e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 00 d0 4b c0 01 65 00 00 00 45 00 00 c6 00 00 40 00 3e 11 7c 69 ac 10 01 0a 0a c0 07 e4 00 35 ad ab 00 b2 74 4e 3b e0 81 80 00 01 00 01 00 05 00 00 01 6d 05 68 65 69 73 65 02 64 65 00 00 01 00 01 c0 0c 00 01 00 01 00 00 0e 10 00 04 c1 63 90 58 c0 0e 00 02 00 01 00 00 0e 10 00 16 03 6e 73 32 0c 70 6f 70 2d 68 61 6e 6e 6f 76 65 72 03 6e 65 74 00 c0 0e 00 02 00 01 00 00 0e 10 00 10 02 6e 73 01 73 08 70 6c 75 73 6c 69 6e 65 c0 14 c0 0e 00 02 00 01 00 00 0e 10 00 05 02 6e 73 c0 0e c0 0e 00 02 00 01 00 00 0e 10 00 05 02 6e 73 c0 5f c0 0e 00 02 00 01 00 00 0e 10 00 12 02 6e 73 0c 70 6f 70 2d 68 61 6e 6e 6f 76 65 72 c0 14 aa df 31
+
+CALLBACK, event 0, msg length 267, bvci 0x1002
+00 00 10 02 00 ef e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 00 d0 4b c0 01 65 00 00 00 45 00 00 c6 00 00 40 00 3e 11 7c 69 ac 10 01 0a 0a c0 07 e4 00 35 ad ab 00 b2 74 4e 3b e0 81 80 00 01 00 01 00 05 00 00 01 6d 05 68 65 69 73 65 02 64 65 00 00 01 00 01 c0 0c 00 01 00 01 00 00 0e 10 00 04 c1 63 90 58 c0 0e 00 02 00 01 00 00 0e 10 00 16 03 6e 73 32 0c 70 6f 70 2d 68 61 6e 6e 6f 76 65 72 03 6e 65 74 00 c0 0e 00 02 00 01 00 00 0e 10 00 10 02 6e 73 01 73 08 70 6c 75 73 6c 69 6e 65 c0 14 c0 0e 00 02 00 01 00 00 0e 10 00 05 02 6e 73 c0 0e c0 0e 00 02 00 01 00 00 0e 10 00 05 02 6e 73 c0 5f c0 0e 00 02 00 01 00 00 0e 10 00 12 02 6e 73 0c 70 6f 70 2d 68 61 6e 6e 6f 76 65 72 c0 14 aa df 31
+
+NS UNITDATA MESSAGE to BSS, BVCI 0x1002, msg length 267 (gprs_ns_sendmsg)
+MESSAGE to BSS at 0x01020304:1111, msg length 271
+00 00 10 02 00 c0 0f 73 04 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 00 d0 4b c0 01 65 00 00 00 45 00 00 c6 00 00 40 00 3e 11 7c 69 ac 10 01 0a 0a c0 07 e4 00 35 ad ab 00 b2 74 4e 3b e0 81 80 00 01 00 01 00 05 00 00 01 6d 05 68 65 69 73 65 02 64 65 00 00 01 00 01 c0 0c 00 01 00 01 00 00 0e 10 00 04 c1 63 90 58 c0 0e 00 02 00 01 00 00 0e 10 00 16 03 6e 73 32 0c 70 6f 70 2d 68 61 6e 6e 6f 76 65 72 03 6e 65 74 00 c0 0e 00 02 00 01 00 00 0e 10 00 10 02 6e 73 01 73 08 70 6c 75 73 6c 69 6e 65 c0 14 c0 0e 00 02 00 01 00 00 0e 10 00 05 02 6e 73 c0 0e c0 0e 00 02 00 01 00 00 0e 10 00 05 02 6e 73 c0 5f c0 0e 00 02 00 01 00 00 0e 10 00 12 02 6e 73 0c 70 6f 70 2d 68 61 6e 6e 6f 76 65 72 c0 14 aa df 31
+
+result (LL11 DNS RESP (DL)) = 271
+
+Peers:
+ NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96
+ RAID patched (BSS ): 7
+ RAID patched (SGSN): 2
+ TLLI patched (BSS ): 5
+ TLLI patched (SGSN): 5
+ P-TMSI patched (SGSN): 1
+ Attach Request count : 1
+ TLLI cache size : 1
+ TLLI-Cache: 1
+ TLLI c00f7304 -> efe2b700, IMSI 12131415161718, AGE 0
+PROCESSING DETACH REQ from 0x01020304:1111
+00 00 10 02 01 c0 0f 73 04 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 15 01 c0 0d 08 05 01 18 05 f4 ef e2 b7 00 19 03 b9 97 cb 37 67 c6
+
+CALLBACK, event 0, msg length 44, bvci 0x1002
+00 00 10 02 01 c0 0f 73 04 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 15 01 c0 0d 08 05 01 18 05 f4 ef e2 b7 00 19 03 b9 97 cb 37 67 c6
+
+NS UNITDATA MESSAGE to SGSN, BVCI 0x1002, msg length 44 (gprs_ns_sendmsg)
+MESSAGE to SGSN at 0x05060708:32000, msg length 48
+00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 21 63 54 40 50 60 12 34 00 80 0e 00 15 01 c0 0d 08 05 01 18 05 f4 ef e2 b7 00 19 03 b9 97 cb 37 67 c6
+
+result (DETACH REQ) = 48
+
+Peers:
+ NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96
+ RAID patched (BSS ): 8
+ RAID patched (SGSN): 2
+ TLLI patched (BSS ): 6
+ TLLI patched (SGSN): 5
+ P-TMSI patched (SGSN): 1
+ Attach Request count : 1
+ TLLI cache size : 1
+ TLLI-Cache: 1
+ TLLI c00f7304 -> efe2b700, IMSI 12131415161718, AGE 0
+PROCESSING DETACH ACC from 0x05060708:32000
+00 00 10 02 00 ef e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 89 41 c0 0d 08 06 00 aa ab ee
+
+CALLBACK, event 0, msg length 67, bvci 0x1002
+00 00 10 02 00 ef e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 89 41 c0 0d 08 06 00 aa ab ee
+
+NS UNITDATA MESSAGE to BSS, BVCI 0x1002, msg length 67 (gprs_ns_sendmsg)
+MESSAGE to BSS at 0x01020304:1111, msg length 71
+00 00 10 02 00 c0 0f 73 04 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 89 41 c0 0d 08 06 00 aa ab ee
+
+result (DETACH ACC) = 71
+
+Peers:
+ NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96
+ RAID patched (BSS ): 8
+ RAID patched (SGSN): 2
+ TLLI patched (BSS ): 6
+ TLLI patched (SGSN): 6
+ P-TMSI patched (SGSN): 1
+ Attach Request count : 1
+ TLLI-Cache: 0
+Gbproxy global:
Test TLLI info expiry
Test TLLI replacement: