aboutsummaryrefslogtreecommitdiffstats
path: root/openbsc/src/gprs
diff options
context:
space:
mode:
authorJacob Erlbeck <jerlbeck@sysmocom.de>2014-05-19 10:14:58 +0200
committerHolger Hans Peter Freyther <holger@moiji-mobile.com>2014-07-22 16:04:54 +0200
commit67a4445675170c584be6b424e57b07b8c88b05b7 (patch)
tree5af5d41af928b2ce676dca323266e6c805ea90f6 /openbsc/src/gprs
parentfd636aed1ed266d68c0a8cec4750f068fc911cd2 (diff)
gprs: Implement BSSGP MCC/MNC patching
This adds a feature to patch the BSSGP MNC/MCC fields of messages going to and coming from the SGSN. To enable this feature, the gbproxy's VTY commands 'core-mobile-country-code' and/or 'core-mobile-network-code' must be used. All packets to the SGSN are patched to match the configured values. Packets received from the SGSN are patched to the corresponding values as last seen from the BSS side. Note that this will probably not work with a gbproxy used for several BSS simultaneously. Note also, that MCC/MNC contained in a LLC IE will not be patched. Ticket: OW#1185 Sponsored-by: On-Waves ehf
Diffstat (limited to 'openbsc/src/gprs')
-rw-r--r--openbsc/src/gprs/Makefile.am3
-rw-r--r--openbsc/src/gprs/gb_proxy.c132
-rw-r--r--openbsc/src/gprs/gb_proxy_main.c2
-rw-r--r--openbsc/src/gprs/gb_proxy_vty.c52
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;
}