diff options
Diffstat (limited to 'openbsc/src/gprs')
-rw-r--r-- | openbsc/src/gprs/Makefile.am | 3 | ||||
-rw-r--r-- | openbsc/src/gprs/gb_proxy.c | 132 | ||||
-rw-r--r-- | openbsc/src/gprs/gb_proxy_main.c | 2 | ||||
-rw-r--r-- | openbsc/src/gprs/gb_proxy_vty.c | 52 |
4 files changed, 187 insertions, 2 deletions
diff --git a/openbsc/src/gprs/Makefile.am b/openbsc/src/gprs/Makefile.am index 049d41ddd..87dbc3059 100644 --- a/openbsc/src/gprs/Makefile.am +++ b/openbsc/src/gprs/Makefile.am @@ -13,7 +13,8 @@ else bin_PROGRAMS = osmo-gbproxy endif -osmo_gbproxy_SOURCES = gb_proxy.c gb_proxy_main.c gb_proxy_vty.c +osmo_gbproxy_SOURCES = gb_proxy.c gb_proxy_main.c gb_proxy_vty.c \ + gprs_llc_parse.c crc24.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 9de2ca9c4..82e9e8c70 100644 --- a/openbsc/src/gprs/gb_proxy.c +++ b/openbsc/src/gprs/gb_proxy.c @@ -43,6 +43,10 @@ #include <openbsc/debug.h> #include <openbsc/gb_proxy.h> +#include <openbsc/gprs_llc.h> +#include <openbsc/gsm_04_08.h> +#include <openbsc/gsm_04_08_gprs.h> + enum gbprox_global_ctr { GBPROX_GLOB_CTR_INV_BVCI, GBPROX_GLOB_CTR_INV_LAI, @@ -55,6 +59,9 @@ enum gbprox_global_ctr { GBPROX_GLOB_CTR_RESTART_RESET_SGSN, GBPROX_GLOB_CTR_TX_ERR_SGSN, GBPROX_GLOB_CTR_OTHER_ERR, + GBPROX_GLOB_CTR_RAID_PATCHED_BSS, + GBPROX_GLOB_CTR_RAID_PATCHED_SGSN, + GBPROX_GLOB_CTR_PATCH_ERR, }; static const struct rate_ctr_desc global_ctr_description[] = { @@ -69,6 +76,9 @@ static const struct rate_ctr_desc global_ctr_description[] = { { "restart.sgsn", "Restarted RESET procedure (SGSN)" }, { "tx-err.sgsn", "NS Transmission error (SGSN)" }, { "error", "Other error " }, + { "raid-mod.bss", "RAID patched (BSS )" }, + { "raid-mod.sgsn", "RAID patched (SGSN)" }, + { "mod-err", "Patching error " }, }; static const struct rate_ctr_group_desc global_ctrg_desc = { @@ -112,6 +122,11 @@ static const struct rate_ctr_group_desc peer_ctrg_desc = { .ctr_desc = peer_ctr_description, }; +static struct gbprox_patch_state { + int local_mnc; + int local_mcc; +} gbprox_patch_state = {0}; + struct gbprox_peer { struct llist_head list; @@ -260,6 +275,118 @@ static void strip_ns_hdr(struct msgb *msg) msgb_pull(msg, strip_len); } +/* patch RA identifier in place, update peer accordingly */ +static void gbprox_patch_raid(uint8_t *raid_enc, struct gbprox_patch_state *state, + int to_bss, const char *log_text) +{ + 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 (!to_bss) { + /* BSS -> SGSN */ + /* save BSS side MCC/MNC */ + if (!gbcfg.core_mcc || raid.mcc == gbcfg.core_mcc) { + state->local_mcc = 0; + } else { + state->local_mcc = raid.mcc; + raid.mcc = gbcfg.core_mcc; + } + + if (!gbcfg.core_mnc || raid.mnc == gbcfg.core_mnc) { + state->local_mnc = 0; + } else { + state->local_mnc = raid.mnc; + raid.mnc = gbcfg.core_mnc; + } + } else { + /* SGSN -> BSS */ + if (state->local_mcc) + raid.mcc = state->local_mcc; + + if (state->local_mnc) + raid.mnc = state->local_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", + state->local_mcc || state->local_mnc ? + "" : "de", + log_text, + state->local_mcc, state->local_mnc, + gbcfg.core_mcc, gbcfg.core_mnc, + to_bss ? "BSS" : "SGSN"); + + if (state->local_mcc || state->local_mnc) { + enum gbprox_global_ctr counter = + to_bss ? + GBPROX_GLOB_CTR_RAID_PATCHED_SGSN : + GBPROX_GLOB_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(&get_global_ctrg()->ctr[counter]); + } +} + +/* patch BSSGP message to use core_mcc/mnc on the SGSN side */ +static void gbprox_patch_bssgp_message(struct msgb *msg, int to_bss) +{ + struct bssgp_normal_hdr *bgph; + struct bssgp_ud_hdr *budh; + struct tlv_parsed tp; + uint8_t pdu_type; + struct gbprox_patch_state *state = &gbprox_patch_state; + uint8_t *data; + size_t data_len; + + if (!gbcfg.core_mcc && !gbcfg.core_mnc) + return; + + bgph = (struct bssgp_normal_hdr *) msgb_bssgph(msg); + budh = (struct bssgp_ud_hdr *) msgb_bssgph(msg); + pdu_type = bgph->pdu_type; + + if (to_bss && !state->local_mcc && !state->local_mnc) + return; + + if (pdu_type == BSSGP_PDUT_UL_UNITDATA || + pdu_type == BSSGP_PDUT_DL_UNITDATA) { + data = budh->data; + data_len = msgb_bssgp_len(msg) - sizeof(*budh); + } else { + data = bgph->data; + data_len = msgb_bssgp_len(msg) - sizeof(*bgph); + } + + bssgp_tlv_parse(&tp, data, data_len); + + if (TLVP_PRESENT(&tp, BSSGP_IE_ROUTEING_AREA)) + gbprox_patch_raid((uint8_t *)TLVP_VAL(&tp, BSSGP_IE_ROUTEING_AREA), + state, to_bss, "ROUTING_AREA"); + + if (TLVP_PRESENT(&tp, BSSGP_IE_CELL_ID)) + gbprox_patch_raid((uint8_t *)TLVP_VAL(&tp, BSSGP_IE_CELL_ID), + state, to_bss, "CELL_ID"); +} + /* feed a message down the NS-VC associated with the specified peer */ static int gbprox_relay2sgsn(struct msgb *old_msg, uint16_t ns_bvci) { @@ -276,6 +403,8 @@ static int gbprox_relay2sgsn(struct msgb *old_msg, uint16_t ns_bvci) strip_ns_hdr(msg); + gbprox_patch_bssgp_message(msg, 0); + rc = gprs_ns_sendmsg(bssgp_nsi, msg); if (rc < 0) rate_ctr_inc(&get_global_ctrg()->ctr[GBPROX_GLOB_CTR_TX_ERR_SGSN]); @@ -679,6 +808,9 @@ int gbprox_rcvmsg(struct msgb *msg, uint16_t nsei, uint16_t ns_bvci, uint16_t ns struct gbprox_peer *peer; int remote_end_is_sgsn = nsei == gbcfg.nsip_sgsn_nsei; + if (remote_end_is_sgsn) + gbprox_patch_bssgp_message(msg, 1); + /* Only BVCI=0 messages need special treatment */ if (ns_bvci == 0 || ns_bvci == 1) { if (remote_end_is_sgsn) diff --git a/openbsc/src/gprs/gb_proxy_main.c b/openbsc/src/gprs/gb_proxy_main.c index ff2e14b5c..1f140d48d 100644 --- a/openbsc/src/gprs/gb_proxy_main.c +++ b/openbsc/src/gprs/gb_proxy_main.c @@ -66,7 +66,7 @@ const char *openbsc_copyright = "There is NO WARRANTY, to the extent permitted by law.\r\n"; static char *config_file = "osmo_gbproxy.cfg"; -struct gbproxy_config gbcfg; +struct gbproxy_config gbcfg = {0}; static int daemonize = 0; /* Pointer to the SGSN peer */ diff --git a/openbsc/src/gprs/gb_proxy_vty.c b/openbsc/src/gprs/gb_proxy_vty.c index 2de0d3bc5..04431f0e3 100644 --- a/openbsc/src/gprs/gb_proxy_vty.c +++ b/openbsc/src/gprs/gb_proxy_vty.c @@ -51,6 +51,13 @@ static int config_write_gbproxy(struct vty *vty) vty_out(vty, " sgsn nsei %u%s", g_cfg->nsip_sgsn_nsei, VTY_NEWLINE); + if (g_cfg->core_mcc > 0) + vty_out(vty, " core-mobile-country-code %d%s", + g_cfg->core_mcc, VTY_NEWLINE); + if (g_cfg->core_mnc > 0) + vty_out(vty, " core-mobile-network-code %d%s", + g_cfg->core_mnc, VTY_NEWLINE); + return CMD_SUCCESS; } @@ -76,6 +83,47 @@ DEFUN(cfg_nsip_sgsn_nsei, return CMD_SUCCESS; } +#define GBPROXY_CORE_MNC_STR "Use this network code for the core network\n" + +DEFUN(cfg_gbproxy_core_mnc, + cfg_gbproxy_core_mnc_cmd, + "core-mobile-network-code <1-999>", + GBPROXY_CORE_MNC_STR "NCC value\n") +{ + g_cfg->core_mnc = atoi(argv[0]); + return CMD_SUCCESS; +} + +DEFUN(cfg_gbproxy_no_core_mnc, + cfg_gbproxy_no_core_mnc_cmd, + "no core-mobile-network-code", + NO_STR GBPROXY_CORE_MNC_STR) +{ + g_cfg->core_mnc = 0; + return CMD_SUCCESS; +} + +#define GBPROXY_CORE_MCC_STR "Use this country code for the core network\n" + +DEFUN(cfg_gbproxy_core_mcc, + cfg_gbproxy_core_mcc_cmd, + "core-mobile-country-code <1-999>", + GBPROXY_CORE_MCC_STR "MCC value\n") +{ + g_cfg->core_mcc = atoi(argv[0]); + return CMD_SUCCESS; +} + +DEFUN(cfg_gbproxy_no_core_mcc, + cfg_gbproxy_no_core_mcc_cmd, + "no core-mobile-country-code", + NO_STR GBPROXY_CORE_MCC_STR) +{ + g_cfg->core_mcc = 0; + return CMD_SUCCESS; +} + + int gbproxy_vty_init(void) { install_element_ve(&show_gbproxy_cmd); @@ -87,6 +135,10 @@ int gbproxy_vty_init(void) install_node(&gbproxy_node, config_write_gbproxy); vty_install_default(GBPROXY_NODE); install_element(GBPROXY_NODE, &cfg_nsip_sgsn_nsei_cmd); + install_element(GBPROXY_NODE, &cfg_gbproxy_core_mcc_cmd); + install_element(GBPROXY_NODE, &cfg_gbproxy_core_mnc_cmd); + install_element(GBPROXY_NODE, &cfg_gbproxy_no_core_mcc_cmd); + install_element(GBPROXY_NODE, &cfg_gbproxy_no_core_mnc_cmd); return 0; } |