gprs_bssgp: add IE parser/generator for RIM Routing Information

The RIM Routing Information IE (see also 3GPP TS 48.018, section
11.3.70) is used to control the flow of BSSGP rim messages at the SGSN.

Change-Id: I6f88a9aeeb50a612d32e9efd23040c9740bc4f11
Related: SYS#5103
This commit is contained in:
Philipp Maier 2020-12-14 22:28:19 +01:00
parent 8806796976
commit bd10c21cc4
8 changed files with 324 additions and 1 deletions

View File

@ -76,6 +76,7 @@ nobase_include_HEADERS = \
osmocom/gprs/protocol/gsm_04_60.h \
osmocom/gprs/protocol/gsm_08_16.h \
osmocom/gprs/protocol/gsm_08_18.h \
osmocom/gprs/protocol/gsm_24_301.h \
osmocom/gsm/a5.h \
osmocom/gsm/abis_nm.h \
osmocom/gsm/apn.h \

View File

@ -10,6 +10,7 @@
#include <osmocom/gsm/prim.h>
#include <osmocom/gprs/protocol/gsm_08_18.h>
#include <osmocom/gprs/protocol/gsm_24_301.h>
/* gprs_bssgp_util.c */
@ -175,6 +176,37 @@ uint16_t bssgp_parse_cell_id(struct gprs_ra_id *raid, const uint8_t *buf);
int bssgp_create_cell_id(uint8_t *buf, const struct gprs_ra_id *raid,
uint16_t cid);
enum bssgp_rim_routing_info_discr {
BSSGP_RIM_ROUTING_INFO_GERAN,
BSSGP_RIM_ROUTING_INFO_UTRAN,
BSSGP_RIM_ROUTING_INFO_EUTRAN,
};
/*! BSSGP RIM Routing information, see also 3GPP TS 48.018, section 11.3.70 */
struct bssgp_rim_routing_info {
enum bssgp_rim_routing_info_discr discr;
union {
struct {
struct gprs_ra_id raid;
uint16_t cid;
} geran;
struct {
struct gprs_ra_id raid;
uint16_t rncid;
} utran;
struct {
struct osmo_eutran_tai tai;
/* See also 3GPP TS 36.413 9.2.1.37 and 3GPP TS 36.401 */
uint8_t global_enb_id[8];
uint8_t global_enb_id_len;
} eutran;
};
};
int bssgp_parse_rim_ri(struct bssgp_rim_routing_info *ri, const uint8_t *buf,
unsigned int len);
int bssgp_create_rim_ri(uint8_t *buf, const struct bssgp_rim_routing_info *ri);
/* Wrapper around TLV parser to parse BSSGP IEs */
static inline int bssgp_tlv_parse(struct tlv_parsed *tp, const uint8_t *buf, int len)
{

View File

@ -0,0 +1,11 @@
/*! \file gsm_24_301.h */
#pragma once
/*! Tracking area TS 24.301, section 9.9.3.32 */
struct osmo_eutran_tai {
uint16_t mcc;
uint16_t mnc;
bool mnc_3_digits;
uint16_t tac;
};

View File

@ -326,6 +326,93 @@ int bssgp_create_cell_id(uint8_t *buf, const struct gprs_ra_id *raid,
return 8;
}
/*! Parse a RIM Routing information IE (3GPP TS 48.018, chapter 11.3.70).
* \param[out] ri user provided memory to store the parsed results.
* \param[in] buf input buffer of the value part of the IE.
* \returns length of parsed octets, -EINVAL on error. */
int bssgp_parse_rim_ri(struct bssgp_rim_routing_info *ri, const uint8_t *buf,
unsigned int len)
{
struct gprs_ra_id raid_temp;
memset(ri, 0, sizeof(*ri));
if (len < 2)
return -EINVAL;
ri->discr = buf[0] & 0x0f;
switch (ri->discr) {
case BSSGP_RIM_ROUTING_INFO_GERAN:
if (len < 9)
return -EINVAL;
ri->geran.cid = bssgp_parse_cell_id(&ri->geran.raid, buf + 1);
return 9;
case BSSGP_RIM_ROUTING_INFO_UTRAN:
if (len < 9)
return -EINVAL;
gsm48_parse_ra(&ri->utran.raid, buf + 1);
ri->utran.rncid = osmo_load16be(buf + 7);
return 9;
case BSSGP_RIM_ROUTING_INFO_EUTRAN:
if (len < 7 || len > 14)
return -EINVAL;
/* Note: 3GPP TS 24.301 Figure 9.9.3.32.1 and 3GPP TS 24.008
* Figure 10.5.130 specify MCC/MNC encoding in the same way,
* so we can re-use gsm48_parse_ra() for that. */
gsm48_parse_ra(&raid_temp, buf + 1);
ri->eutran.tai.mcc = raid_temp.mcc;
ri->eutran.tai.mnc = raid_temp.mnc;
ri->eutran.tai.mnc_3_digits = raid_temp.mnc_3_digits;
ri->eutran.tai.tac = osmo_load16be(buf + 4);
memcpy(ri->eutran.global_enb_id, buf + 6, len - 6);
ri->eutran.global_enb_id_len = len - 6;
return len;
default:
return -EINVAL;
}
}
/*! Encode a RIM Routing information IE (3GPP TS 48.018, chapter 11.3.70).
* \param[out] buf user provided memory (at least 14 byte) for the generated value part of the IE.
* \param[in] ri user provided input data struct.
* \returns length of encoded octets, -EINVAL on error. */
int bssgp_create_rim_ri(uint8_t *buf, const struct bssgp_rim_routing_info *ri)
{
int rc;
struct gprs_ra_id raid_temp;
buf[0] = ri->discr & 0x0f;
buf++;
switch (ri->discr) {
case BSSGP_RIM_ROUTING_INFO_GERAN:
rc = bssgp_create_cell_id(buf, &ri->geran.raid, ri->geran.cid);
if (rc < 0)
return -EINVAL;
return rc + 1;
case BSSGP_RIM_ROUTING_INFO_UTRAN:
gsm48_encode_ra((struct gsm48_ra_id *)buf, &ri->utran.raid);
osmo_store16be(ri->utran.rncid, buf + 6);
return 9;
case BSSGP_RIM_ROUTING_INFO_EUTRAN:
/* Note: 3GPP TS 24.301 Figure 9.9.3.32.1 and 3GPP TS 24.008
* Figure 10.5.130 specify MCC/MNC encoding in the same way,
* so we can re-use gsm48_encode_ra() for that. */
raid_temp.mcc = ri->eutran.tai.mcc;
raid_temp.mnc = ri->eutran.tai.mnc;
raid_temp.mnc_3_digits = ri->eutran.tai.mnc_3_digits;
gsm48_encode_ra((struct gsm48_ra_id *)buf, &raid_temp);
osmo_store16be(ri->eutran.tai.tac, buf + 3);
OSMO_ASSERT(ri->eutran.global_enb_id_len <=
sizeof(ri->eutran.global_enb_id));
memcpy(buf + 5, ri->eutran.global_enb_id,
ri->eutran.global_enb_id_len);
return ri->eutran.global_enb_id_len + 6;
default:
return -EINVAL;
}
}
/* Chapter 8.4 BVC-Reset Procedure */
static int bssgp_rx_bvc_reset(struct msgb *msg, struct tlv_parsed *tp,
uint16_t ns_bvci)

View File

@ -2,6 +2,7 @@ LIBOSMOGB_1.0 {
global:
bssgp_cause_str;
bssgp_create_cell_id;
bssgp_create_rim_ri;
bssgp_pdu_str;
bssgp_fc_in;
bssgp_fc_init;
@ -13,6 +14,7 @@ bssgp_msgb_copy;
bssgp_msgb_tlli_put;
bssgp_msgb_ra_put;
bssgp_parse_cell_id;
bssgp_parse_rim_ri;
bssgp_set_bssgp_callback;
bssgp_tx_bvc_block;
bssgp_tx_bvc_reset;

View File

@ -172,7 +172,8 @@ gb_bssgp_fc_test_LDADD = $(LDADD) $(top_builddir)/src/gb/libosmogb.la \
gb_gprs_bssgp_test_SOURCES = gb/gprs_bssgp_test.c
gb_gprs_bssgp_test_LDADD = $(LDADD) $(top_builddir)/src/gb/libosmogb.la $(LIBRARY_DLSYM) \
$(top_builddir)/src/vty/libosmovty.la \
$(top_builddir)/src/gsm/libosmogsm.la
$(top_builddir)/src/gsm/libosmogsm.la \
$(top_builddir)/src/gb/libosmogb.la
gb_gprs_ns_test_SOURCES = gb/gprs_ns_test.c
gb_gprs_ns_test_LDADD = $(LDADD) $(top_builddir)/src/gb/libosmogb.la $(LIBRARY_DLSYM) \

View File

@ -289,6 +289,137 @@ static void test_bssgp_msgb_copy()
printf("----- %s END\n", __func__);
}
void dump_rim_ri(struct bssgp_rim_routing_info *ri)
{
switch (ri->discr) {
case BSSGP_RIM_ROUTING_INFO_GERAN:
printf("GERAN cell identifier\n");
printf(" * mcc: %u\n", ri->geran.raid.mcc);
printf(" mnc: %u\n", ri->geran.raid.mnc);
printf(" mnc 3 digits: %u\n", ri->geran.raid.mnc_3_digits);
printf(" lac: %u\n", ri->geran.raid.lac);
printf(" rac: %u\n", ri->geran.raid.rac);
printf(" * cell id: %04x\n", ri->geran.cid);
break;
case BSSGP_RIM_ROUTING_INFO_UTRAN:
printf("UTRAN RNC identifier\n");
printf(" * mcc: %u\n", ri->utran.raid.mcc);
printf(" mnc: %u\n", ri->utran.raid.mnc);
printf(" mnc 3 digits: %u\n", ri->utran.raid.mnc_3_digits);
printf(" lac: %u\n", ri->utran.raid.lac);
printf(" rac: %u\n", ri->utran.raid.rac);
printf(" * rnc id: %04x\n", ri->utran.rncid);
break;
case BSSGP_RIM_ROUTING_INFO_EUTRAN:
printf("EUTRAN eNB identifier\n");
printf(" * mcc: %u\n", ri->eutran.tai.mcc);
printf(" mnc: %u\n", ri->eutran.tai.mnc);
printf(" mnc 3 digits: %u\n", ri->eutran.tai.mnc_3_digits);
printf(" tac: %u\n", ri->eutran.tai.tac);
printf(" * global_enb_id: %s\n",
osmo_hexdump_nospc(ri->eutran.global_enb_id,
ri->eutran.global_enb_id_len));
break;
default:
OSMO_ASSERT(false);
}
}
static void test_bssgp_parse_rim_ri()
{
int rc;
struct bssgp_rim_routing_info result;
uint8_t testvec_geran[] =
{ 0x00, 0x62, 0xf2, 0x24, 0x33, 0x90, 0x00, 0x51, 0xe1 };
uint8_t testvec_utran[] =
{ 0x01, 0x62, 0xf2, 0x24, 0x33, 0x90, 0x00, 0x51, 0xe1 };
uint8_t testvec_eutran[] =
{ 0x02, 0x62, 0xf2, 0x24, 0x33, 0x90, 0x00, 0x51, 0xe1 };
printf("----- %s START\n", __func__);
rc = bssgp_parse_rim_ri(&result, testvec_geran,
sizeof(testvec_geran));
printf("rc=%d\n", rc);
dump_rim_ri(&result);
printf("\n");
rc = bssgp_parse_rim_ri(&result, testvec_utran,
sizeof(testvec_utran));
printf("rc=%d\n", rc);
dump_rim_ri(&result);
printf("\n");
rc = bssgp_parse_rim_ri(&result, testvec_eutran,
sizeof(testvec_eutran));
printf("rc=%d\n", rc);
dump_rim_ri(&result);
printf("\n");
printf("----- %s END\n", __func__);
}
static void test_bssgp_create_rim_ri()
{
int rc;
struct bssgp_rim_routing_info ri;
uint8_t result[15];
printf("----- %s START\n", __func__);
memset(&ri, 0, sizeof(ri));
memset(result, 0, sizeof(result));
ri.discr = BSSGP_RIM_ROUTING_INFO_GERAN;
ri.geran.raid.mcc = 262;
ri.geran.raid.mnc = 42;
ri.geran.raid.mnc_3_digits = false;
ri.geran.raid.lac = 13200;
ri.geran.raid.rac = 0;
ri.geran.cid = 0x51e1;
dump_rim_ri(&ri);
rc = bssgp_create_rim_ri(result, &ri);
printf("rc=%d, ", rc);
if (rc > 0)
printf("result=%s", osmo_hexdump_nospc(result, rc));
printf("\n\n");
memset(&ri, 0, sizeof(ri));
memset(result, 0, sizeof(result));
ri.discr = BSSGP_RIM_ROUTING_INFO_UTRAN;
ri.utran.raid.mcc = 262;
ri.utran.raid.mnc = 42;
ri.utran.raid.mnc_3_digits = 0;
ri.utran.raid.lac = 13200;
ri.utran.raid.rac = 0;
ri.utran.rncid = 0x51e1;
dump_rim_ri(&ri);
rc = bssgp_create_rim_ri(result, &ri);
printf("rc=%d, ", rc);
if (rc > 0)
printf("result=%s", osmo_hexdump_nospc(result, rc));
printf("\n\n");
memset(&ri, 0, sizeof(ri));
memset(result, 0, sizeof(result));
ri.discr = BSSGP_RIM_ROUTING_INFO_EUTRAN;
ri.eutran.tai.mcc = 262;
ri.eutran.tai.mnc = 42;
ri.eutran.tai.mnc_3_digits = 0;
ri.eutran.tai.tac = 13200;
ri.eutran.global_enb_id[0] = 0x00;
ri.eutran.global_enb_id[1] = 0x51;
ri.eutran.global_enb_id[2] = 0xe1;
ri.eutran.global_enb_id_len = 3;
dump_rim_ri(&ri);
rc = bssgp_create_rim_ri(result, &ri);
printf("rc=%d, ", rc);
if (rc > 0)
printf("result=%s", osmo_hexdump_nospc(result, rc));
printf("\n\n");
printf("----- %s END\n", __func__);
}
static struct log_info info = {};
int main(int argc, char **argv)
@ -317,6 +448,8 @@ int main(int argc, char **argv)
test_bssgp_bad_reset();
test_bssgp_flow_control_bvc();
test_bssgp_msgb_copy();
test_bssgp_parse_rim_ri();
test_bssgp_create_rim_ri();
printf("===== BSSGP test END\n\n");
exit(EXIT_SUCCESS);

View File

@ -17,5 +17,61 @@ Got message: 26 1e 81 2a 05 82 10 22 03 82 c0 40 01 82 08 11 1c 82 60 20 3c 81 7
Old msgb: [L3]> 22 04 82 00 02 07 81 08
New msgb: [L3]> 22 04 82 00 02 07 81 08
----- test_bssgp_msgb_copy END
----- test_bssgp_parse_rim_ri START
rc=9
GERAN cell identifier
* mcc: 262
mnc: 42
mnc 3 digits: 0
lac: 13200
rac: 0
* cell id: 51e1
rc=9
UTRAN RNC identifier
* mcc: 262
mnc: 42
mnc 3 digits: 0
lac: 13200
rac: 0
* rnc id: 51e1
rc=9
EUTRAN eNB identifier
* mcc: 262
mnc: 42
mnc 3 digits: 0
tac: 13200
* global_enb_id: 0051e1
----- test_bssgp_parse_rim_ri END
----- test_bssgp_create_rim_ri START
GERAN cell identifier
* mcc: 262
mnc: 42
mnc 3 digits: 0
lac: 13200
rac: 0
* cell id: 51e1
rc=9, result=0062f22433900051e1
UTRAN RNC identifier
* mcc: 262
mnc: 42
mnc 3 digits: 0
lac: 13200
rac: 0
* rnc id: 51e1
rc=9, result=0162f22433900051e1
EUTRAN eNB identifier
* mcc: 262
mnc: 42
mnc 3 digits: 0
tac: 13200
* global_enb_id: 0051e1
rc=9, result=0262f22433900051e1
----- test_bssgp_create_rim_ri END
===== BSSGP test END