improve API for osmo_routing_area_id

Code review for [1] has asked for providing proper API for struct
osmo_routing_area_id.

For historical reasons, we have struct gprs_ra_id and
struct osmo_routing_area_id serving the exact same purpose: represent a
decoded 3GPP TS 24.008 § 10.5.5.15 Routing area identification.

The "better" one is struct osmo_routing_area_id: it allows using API
like osmo_plmn_cmp(), because it is made up of meaningful sub-structs.

Implement de/coding using the functions already available for the
sub-struct osmo_location_area_id, and simply add the RAC.

Add a test in gsm0408_test.c.

Note that other utility functions are already available for struct
osmo_routing_area_id: osmo_rai_name2(), osmo_rai_cmp().

There is no real need to deprecate struct gprs_ra_id, because there is
not really anything wrong with it. It just isn't as well integrated with
other utility API as struct osmo_routing_area_id is. Just add comments.

[1] osmo-hnbgw.git:
    cnpool: extract Mobile Identity from RANAP payload
    https://gerrit.osmocom.org/c/osmo-hnbgw/+/33133
    I373d665c9684b607207f68094188eab63209db51

Change-Id: Ic5e0406d9e20b0d4e1372fa30ba11a1e69f5cc94
This commit is contained in:
Neels Hofmeyr 2023-06-08 00:35:41 +02:00
parent eb9edbab54
commit 8d42394c89
5 changed files with 267 additions and 2 deletions

View File

@ -20,7 +20,9 @@
* To mark an invalid / unset MNC, this value shall be used. */
#define GSM_MCC_MNC_INVALID 0xFFFF
/* A parsed GPRS routing area */
/* A parsed GPRS routing area.
* Preferably use struct osmo_routing_area_id, it is better integrated with API like osmo_plmn_cmp().
*/
struct gprs_ra_id {
uint16_t mcc;
uint16_t mnc;
@ -104,6 +106,9 @@ int osmo_mobile_identity_encode_buf(uint8_t *buf, size_t buflen, const struct os
int osmo_mobile_identity_encode_msgb(struct msgb *msg, const struct osmo_mobile_identity *mi, bool allow_hex);
/* Parse Routeing Area Identifier */
int osmo_routing_area_id_decode(struct osmo_routing_area_id *dst, const uint8_t *ra_data, size_t ra_data_len);
int osmo_routing_area_id_encode_buf(uint8_t *buf, size_t buflen, const struct osmo_routing_area_id *src);
int osmo_routing_area_id_encode_msgb(struct msgb *msg, const struct osmo_routing_area_id *src);
void gsm48_parse_ra(struct gprs_ra_id *raid, const uint8_t *buf);
void gsm48_encode_ra(struct gsm48_ra_id *out, const struct gprs_ra_id *raid);
int gsm48_construct_ra(uint8_t *buf, const struct gprs_ra_id *raid) OSMO_DEPRECATED("Use gsm48_encode_ra() instead");

View File

@ -1334,7 +1334,64 @@ int gsm48_mi_to_string(char *string, int str_len, const uint8_t *mi, int mi_len)
return 1;
}
/*! Parse TS 04.08 Routing Area Identifier
/*! Decode to struct osmo_routing_area_id from a 3GPP TS 24.008 § 10.5.5.15 Routing area identification.
* \param[out] dst Store the decoded result here.
* \param[in] ra_data The start of a Routing Area ID in encoded form, to be decoded.
* \param[in] ra_data_len Buffer size available to read from at *ra_data.
* \return the number of decoded bytes on success, or negative on error (if the input buffer is too small).
*/
int osmo_routing_area_id_decode(struct osmo_routing_area_id *dst, const uint8_t *ra_data, size_t ra_data_len)
{
const struct gsm48_ra_id *ra_id;
if (ra_data_len < sizeof(*ra_id))
return -ENOSPC;
gsm48_decode_lai2((void *)ra_data, &dst->lac);
ra_id = (void *)ra_data;
dst->rac = ra_id->rac;
return sizeof(*ra_id);
}
/*! Encode struct osmo_routing_area_id to a 3GPP TS 24.008 § 10.5.5.15 Routing area identification: write to a buffer.
* \param[out] buf Return buffer for encoded Mobile Identity.
* \param[in] buflen sizeof(buf).
* \param[in] src RA to encode.
* \return Amount of bytes written to buf, or negative on error.
*/
int osmo_routing_area_id_encode_buf(uint8_t *buf, size_t buflen, const struct osmo_routing_area_id *src)
{
struct gsm48_ra_id *ra_id;
if (buflen < sizeof(*ra_id))
return -ENOSPC;
gsm48_generate_lai2((void *)buf, &src->lac);
ra_id = (void *)buf;
ra_id->rac = src->rac;
return sizeof(*ra_id);
}
/*! Encode struct osmo_routing_area_id to a 3GPP TS 24.008 § 10.5.5.15 Routing area identification: append to msgb.
* To succeed, the msgb must have tailroom >= sizeof(struct gsm48_ra_id).
* \param[out] msg Append to this msgb.
* \param[in] src Encode this Routing Area ID.
* \return Number of bytes appended to msgb, or negative on error.
*/
int osmo_routing_area_id_encode_msgb(struct msgb *msg, const struct osmo_routing_area_id *src)
{
int rc = osmo_routing_area_id_encode_buf(msg->tail, msgb_tailroom(msg), src);
if (rc <= 0)
return rc;
msgb_put(msg, rc);
return rc;
}
/*! Parse TS 04.08 Routing Area Identifier.
* Preferably use osmo_routing_area_id_decode() instead: struct osmo_routing_area_id is better integrated with other API
* like osmo_plmn_cmp().
* \param[out] Caller-provided memory for decoded RA ID
* \param[in] buf Input buffer pointing to RAI IE value */
void gsm48_parse_ra(struct gprs_ra_id *raid, const uint8_t *buf)

View File

@ -415,6 +415,9 @@ osmo_mobile_identity_decode_from_l3;
osmo_mobile_identity_encoded_len;
osmo_mobile_identity_encode_buf;
osmo_mobile_identity_encode_msgb;
osmo_routing_area_id_decode;
osmo_routing_area_id_encode_buf;
osmo_routing_area_id_encode_msgb;
gsm48_mm_att_tlvdef;
gsm48_number_of_paging_subchannels;
gsm48_parse_ra;

View File

@ -341,6 +341,171 @@ static void test_lai_encode_decode(void)
}
}
static struct osmo_routing_area_id test_osmo_routing_area_id_items[] = {
{
.lac = {
.plmn = {
.mcc = 77,
.mnc = 121,
},
.lac = 666,
},
.rac = 5,
},
{
.lac = {
.plmn = {
.mcc = 84,
.mnc = 98,
},
.lac = 11,
},
.rac = 89,
},
{
.lac = {
.plmn = {
.mcc = 0,
.mnc = 0,
.mnc_3_digits = false,
/* expecting 000-00, BCD = 00 f0 00 */
},
.lac = 0,
},
.rac = 0,
},
{
.lac = {
.plmn = {
.mcc = 0,
.mnc = 0,
.mnc_3_digits = true,
/* expecting 000-000, BCD = 00 00 00 */
},
.lac = 0,
},
.rac = 0,
},
{
.lac = {
.plmn = {
.mcc = 999,
.mnc = 999,
},
.lac = 65535,
},
.rac = 255,
},
{
.lac = {
.plmn = {
.mcc = 1,
.mnc = 2,
.mnc_3_digits = false,
/* expecting 001-02, BCD = 00 f1 20 */
},
.lac = 23,
},
.rac = 42,
},
{
.lac = {
.plmn = {
.mcc = 1,
.mnc = 2,
.mnc_3_digits = true,
/* expecting 001-002, BCD = 00 21 00 */
},
.lac = 23,
},
.rac = 42,
},
{
.lac = {
.plmn = {
.mcc = 12,
.mnc = 34,
.mnc_3_digits = false,
/* expecting 012-34, BCD = 10 f2 43 */
},
.lac = 56,
},
.rac = 78,
},
{
.lac = {
.plmn = {
.mcc = 12,
.mnc = 34,
.mnc_3_digits = true,
/* expecting 012-034, BCD = 10 42 30 */
},
.lac = 23,
},
.rac = 42,
},
{
.lac = {
.plmn = {
.mcc = 123,
.mnc = 456,
.mnc_3_digits = false,
/* expecting 123-456, BCD = 21 63 54 (false flag has no effect) */
},
.lac = 23,
},
.rac = 42,
},
{
.lac = {
.plmn = {
.mcc = 123,
.mnc = 456,
.mnc_3_digits = true,
/* expecting 123-456, BCD = 21 63 54 (same) */
},
.lac = 23,
},
.rac = 42,
},
};
static inline void dump_osmo_routing_area_id(const struct osmo_routing_area_id *raid)
{
printf("%s%s", osmo_rai_name2(raid), raid->lac.plmn.mnc_3_digits ? " (3-digit MNC)" : "");
}
static inline void check_osmo_routing_area_id(const struct osmo_routing_area_id *raid)
{
uint8_t buf[sizeof(struct gsm48_ra_id)] = {};
struct osmo_routing_area_id raid0 = {};
int rc;
printf("RA ID: ");
dump_osmo_routing_area_id(raid);
rc = osmo_routing_area_id_encode_buf(buf, sizeof(buf), raid);
printf("osmo_routing_area_id_encode_buf(): %src=%d\n", osmo_hexdump(buf, sizeof(buf)), rc);
rc = osmo_routing_area_id_decode(&raid0, buf, sizeof(buf));
printf("osmo_routing_area_id_decode(): ");
dump_osmo_routing_area_id(&raid0);
printf(" rc=%d\n", rc);
if (osmo_rai_cmp(raid, &raid0))
printf("FAIL\n");
else
printf("ok\n");
}
static void test_osmo_routing_area_id(void)
{
int i;
printf("==%s()==\n", __func__);
for (i = 0; i < ARRAY_SIZE(test_osmo_routing_area_id_items); i++)
check_osmo_routing_area_id(&test_osmo_routing_area_id_items[i]);
}
static void dump_cm3(struct gsm48_classmark3 *cm3)
{
printf("mult_band_supp=%02x\n", cm3->mult_band_supp);
@ -1792,6 +1957,7 @@ int main(int argc, char **argv)
test_bcd_number_encode_decode();
test_ra_cap();
test_lai_encode_decode();
test_osmo_routing_area_id();
test_decode_classmark3();
test_si_range_helpers();

View File

@ -386,6 +386,40 @@ RA test...passed
Encoded 21 63 54 00 17
gsm48_decode_lai2() gives 123-456-23 (3-digit MNC)
passed
==test_osmo_routing_area_id()==
RA ID: 077-121-666-5osmo_routing_area_id_encode_buf(): 70 17 21 02 9a 05 rc=6
osmo_routing_area_id_decode(): 077-121-666-5 (3-digit MNC) rc=6
ok
RA ID: 084-98-11-89osmo_routing_area_id_encode_buf(): 80 f4 89 00 0b 59 rc=6
osmo_routing_area_id_decode(): 084-98-11-89 rc=6
ok
RA ID: 000-00-0-0osmo_routing_area_id_encode_buf(): 00 f0 00 00 00 00 rc=6
osmo_routing_area_id_decode(): 000-00-0-0 rc=6
ok
RA ID: 000-000-0-0 (3-digit MNC)osmo_routing_area_id_encode_buf(): 00 00 00 00 00 00 rc=6
osmo_routing_area_id_decode(): 000-000-0-0 (3-digit MNC) rc=6
ok
RA ID: 999-999-65535-255osmo_routing_area_id_encode_buf(): 99 99 99 ff ff ff rc=6
osmo_routing_area_id_decode(): 999-999-65535-255 (3-digit MNC) rc=6
ok
RA ID: 001-02-23-42osmo_routing_area_id_encode_buf(): 00 f1 20 00 17 2a rc=6
osmo_routing_area_id_decode(): 001-02-23-42 rc=6
ok
RA ID: 001-002-23-42 (3-digit MNC)osmo_routing_area_id_encode_buf(): 00 21 00 00 17 2a rc=6
osmo_routing_area_id_decode(): 001-002-23-42 (3-digit MNC) rc=6
ok
RA ID: 012-34-56-78osmo_routing_area_id_encode_buf(): 10 f2 43 00 38 4e rc=6
osmo_routing_area_id_decode(): 012-34-56-78 rc=6
ok
RA ID: 012-034-23-42 (3-digit MNC)osmo_routing_area_id_encode_buf(): 10 42 30 00 17 2a rc=6
osmo_routing_area_id_decode(): 012-034-23-42 (3-digit MNC) rc=6
ok
RA ID: 123-456-23-42osmo_routing_area_id_encode_buf(): 21 63 54 00 17 2a rc=6
osmo_routing_area_id_decode(): 123-456-23-42 (3-digit MNC) rc=6
ok
RA ID: 123-456-23-42 (3-digit MNC)osmo_routing_area_id_encode_buf(): 21 63 54 00 17 2a rc=6
osmo_routing_area_id_decode(): 123-456-23-42 (3-digit MNC) rc=6
ok
=====cm3_1=====
mult_band_supp=06
a5_bits=00