mirror of https://gerrit.osmocom.org/libosmocore
gsm: add osmo_mnc_from_str(), osmo_mnc_cmp(), osmo_plmn_cmp() for 3-digit MNC
osmo_mnc_from_str() preserves leading zeros in the string and is useful for VTY config parsing (osmo-bsc, osmo-msc, osmo-sgsn, osmo-pcu). osmo_{plmn,mnc}_cmp() takes care of the slight intricacy of ignoring the 3-digit flag if the MNC is anyway >99. Will be used by osmo-sgsn.git and osmo-bsc.git. (All current users just care about identical MNC, but a proper cmp doesn't hurt.) Change-Id: Ib7176b1d65a03b76f41f94bc9d3293a8a07d24c6
This commit is contained in:
parent
6c7b3e21d6
commit
721aa6ded9
|
@ -95,3 +95,8 @@ const char *osmo_lai_name(const struct osmo_location_area_id *lai);
|
|||
|
||||
void osmo_plmn_to_bcd(uint8_t *bcd_dst, const struct osmo_plmn_id *plmn);
|
||||
void osmo_plmn_from_bcd(const uint8_t *bcd_src, struct osmo_plmn_id *plmn);
|
||||
|
||||
int osmo_mnc_from_str(const char *mnc_str, uint16_t *mnc, bool *mnc_3_digits);
|
||||
|
||||
int osmo_mnc_cmp(uint16_t a_mnc, bool a_mnc_3_digits, uint16_t b_mnc, bool b_mnc_3_digits);
|
||||
int osmo_plmn_cmp(const struct osmo_plmn_id *a, const struct osmo_plmn_id *b);
|
||||
|
|
|
@ -25,6 +25,9 @@
|
|||
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <osmocom/gsm/gsm23003.h>
|
||||
#include <osmocom/gsm/protocol/gsm_23_003.h>
|
||||
|
@ -195,3 +198,77 @@ void osmo_plmn_from_bcd(const uint8_t *bcd_src, struct osmo_plmn_id *plmn)
|
|||
plmn->mnc_3_digits = true;
|
||||
}
|
||||
}
|
||||
|
||||
/* Convert string to MNC, detecting 3-digit MNC with leading zeros.
|
||||
* Return mnc_3_digits as false if the MNC's most significant digit is encoded as 0xF, true
|
||||
* otherwise; i.e. true if MNC > 99 or if it is represented with leading zeros instead of 0xF.
|
||||
* \param mnc_str[in] String representation of an MNC, with or without leading zeros.
|
||||
* \param mnc[out] MNC result buffer, or NULL.
|
||||
* \param[out] mnc_3_digits Result buffer for 3-digit flag, or NULL.
|
||||
* \returns zero on success, -EINVAL in case of surplus characters, negative errno in case of conversion
|
||||
* errors.
|
||||
*/
|
||||
int osmo_mnc_from_str(const char *mnc_str, uint16_t *mnc, bool *mnc_3_digits)
|
||||
{
|
||||
long int _mnc = 0;
|
||||
bool _mnc_3_digits = false;
|
||||
char *endptr;
|
||||
int rc = 0;
|
||||
|
||||
if (!mnc_str || !isdigit(mnc_str[0]) || strlen(mnc_str) > 3) {
|
||||
/* return invalid, but give strtol a shot anyway, for callers that don't want to be
|
||||
* strict */
|
||||
rc = -EINVAL;
|
||||
}
|
||||
errno = 0;
|
||||
_mnc = strtol(mnc_str, &endptr, 10);
|
||||
if (errno)
|
||||
rc = -errno;
|
||||
else if (*endptr)
|
||||
rc = -EINVAL;
|
||||
if (_mnc < 0 || _mnc > 999)
|
||||
rc = -EINVAL;
|
||||
_mnc_3_digits = strlen(mnc_str) > 2;
|
||||
|
||||
if (mnc)
|
||||
*mnc = (uint16_t)_mnc;
|
||||
if (mnc_3_digits)
|
||||
*mnc_3_digits = _mnc_3_digits;
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Compare two MNC with three-digit flag.
|
||||
* The mnc_3_digits flags passed in only have an effect if the MNC are < 100, i.e. if they would amount
|
||||
* to a change in leading zeros in a BCD representation. An MNC >= 100 implies three digits, and the flag
|
||||
* is actually ignored.
|
||||
* \param a_mnc[in] "Left" side MNC.
|
||||
* \param a_mnc_3_digits[in] "Left" side three-digits flag.
|
||||
* \param b_mnc[in] "Right" side MNC.
|
||||
* \param b_mnc_3_digits[in] "Right" side three-digits flag.
|
||||
* \returns 0 if the MNC are equal, -1 if a < b or a shorter, 1 if a > b or a longer. */
|
||||
int osmo_mnc_cmp(uint16_t a_mnc, bool a_mnc_3_digits, uint16_t b_mnc, bool b_mnc_3_digits)
|
||||
{
|
||||
if (a_mnc < b_mnc)
|
||||
return -1;
|
||||
if (a_mnc > b_mnc)
|
||||
return 1;
|
||||
/* a_mnc == b_mnc, but same amount of leading zeros? */
|
||||
if (a_mnc < 100 && a_mnc_3_digits != b_mnc_3_digits)
|
||||
return a_mnc_3_digits ? 1 : -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Compare two PLMN.
|
||||
* \param a[in] "Left" side PLMN.
|
||||
* \param b[in] "Right" side PLMN.
|
||||
* \returns 0 if the PLMN are equal, -1 if a < b or a shorter, 1 if a > b or a longer. */
|
||||
int osmo_plmn_cmp(const struct osmo_plmn_id *a, const struct osmo_plmn_id *b)
|
||||
{
|
||||
if (a == b)
|
||||
return 0;
|
||||
if (a->mcc < b->mcc)
|
||||
return -1;
|
||||
if (a->mcc > b->mcc)
|
||||
return 1;
|
||||
return osmo_mnc_cmp(a->mnc, a->mnc_3_digits, b->mnc, b->mnc_3_digits);
|
||||
}
|
||||
|
|
|
@ -270,6 +270,9 @@ osmo_plmn_name;
|
|||
osmo_plmn_name2;
|
||||
osmo_lai_name;
|
||||
osmo_rai_name;
|
||||
osmo_mnc_from_str;
|
||||
osmo_mnc_cmp;
|
||||
osmo_plmn_cmp;
|
||||
gsm48_chan_mode_names;
|
||||
gsm_chan_t_names;
|
||||
gsm48_pdisc_names;
|
||||
|
|
|
@ -22,6 +22,8 @@
|
|||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <strings.h>
|
||||
|
||||
#include <osmocom/gsm/gsm23003.h>
|
||||
#include <osmocom/core/utils.h>
|
||||
|
@ -114,12 +116,65 @@ bool test_valid_msisdn()
|
|||
return pass;
|
||||
}
|
||||
|
||||
struct test_mnc_from_str_result {
|
||||
int rc;
|
||||
uint16_t mnc;
|
||||
bool mnc_3_digits;
|
||||
};
|
||||
|
||||
struct test_mnc_from_str {
|
||||
const char *mnc_str;
|
||||
struct test_mnc_from_str_result expect;
|
||||
};
|
||||
|
||||
static struct test_mnc_from_str test_mnc_from_strs[] = {
|
||||
{ "0", { 0, 0, false } },
|
||||
{ "00", { 0, 0, false } },
|
||||
{ "000", { 0, 0, true } },
|
||||
{ "1", { 0, 1, false } },
|
||||
{ "01", { 0, 1, false } },
|
||||
{ "001", { 0, 1, true } },
|
||||
{ "", { -EINVAL, 0, false } },
|
||||
{ " ", { -EINVAL, 0, false } },
|
||||
{ "-1", { -EINVAL, 65535, false } },
|
||||
{ "1000", { -EINVAL, 1000, true } },
|
||||
{ "0x", { -EINVAL, 0, false } },
|
||||
{ " 23", { -EINVAL, 23, true } }, /* technically not a 3-digit MNC, but it's EINVAL anyway */
|
||||
{ "23 ", { -EINVAL, 23, true } },
|
||||
{ " 023", { -EINVAL, 23, true } },
|
||||
{ "023 ", { -EINVAL, 23, true } },
|
||||
{ "023 ", { -EINVAL, 23, true } },
|
||||
};
|
||||
|
||||
static bool test_mnc_from_str()
|
||||
{
|
||||
int i;
|
||||
bool pass = true;
|
||||
printf("----- %s\n", __func__);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(test_mnc_from_strs); i++) {
|
||||
struct test_mnc_from_str *t = &test_mnc_from_strs[i];
|
||||
struct test_mnc_from_str_result result;
|
||||
bool ok;
|
||||
|
||||
result.rc = osmo_mnc_from_str(t->mnc_str, &result.mnc,
|
||||
&result.mnc_3_digits);
|
||||
ok = !bcmp(&result, &t->expect, sizeof(result));
|
||||
printf("%2d: \"%s\" rc=%d mnc=%u mnc_3_digits=%u %s\n",
|
||||
i, osmo_escape_str(t->mnc_str, -1), result.rc, result.mnc, result.mnc_3_digits,
|
||||
ok ? "pass" : "FAIL");
|
||||
pass = pass && ok;
|
||||
}
|
||||
return pass;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
bool pass = true;
|
||||
|
||||
pass = pass && test_valid_imsi();
|
||||
pass = pass && test_valid_msisdn();
|
||||
pass = pass && test_mnc_from_str();
|
||||
|
||||
OSMO_ASSERT(pass);
|
||||
|
||||
|
|
|
@ -42,3 +42,20 @@
|
|||
17: expect=false result=false msisdn='123456 123456'
|
||||
18: expect=false result=false msisdn='123456
123456'
|
||||
19: expect=false result=false msisdn='(null)'
|
||||
----- test_mnc_from_str
|
||||
0: "0" rc=0 mnc=0 mnc_3_digits=0 pass
|
||||
1: "00" rc=0 mnc=0 mnc_3_digits=0 pass
|
||||
2: "000" rc=0 mnc=0 mnc_3_digits=1 pass
|
||||
3: "1" rc=0 mnc=1 mnc_3_digits=0 pass
|
||||
4: "01" rc=0 mnc=1 mnc_3_digits=0 pass
|
||||
5: "001" rc=0 mnc=1 mnc_3_digits=1 pass
|
||||
6: "" rc=-22 mnc=0 mnc_3_digits=0 pass
|
||||
7: " " rc=-22 mnc=0 mnc_3_digits=0 pass
|
||||
8: "-1" rc=-22 mnc=65535 mnc_3_digits=0 pass
|
||||
9: "1000" rc=-22 mnc=1000 mnc_3_digits=1 pass
|
||||
10: "0x" rc=-22 mnc=0 mnc_3_digits=0 pass
|
||||
11: " 23" rc=-22 mnc=23 mnc_3_digits=1 pass
|
||||
12: "23 " rc=-22 mnc=23 mnc_3_digits=1 pass
|
||||
13: " 023" rc=-22 mnc=23 mnc_3_digits=1 pass
|
||||
14: "023 " rc=-22 mnc=23 mnc_3_digits=1 pass
|
||||
15: "023 " rc=-22 mnc=23 mnc_3_digits=1 pass
|
||||
|
|
Loading…
Reference in New Issue