diff options
author | Oliver Smith <osmith@sysmocom.de> | 2019-01-11 13:13:37 +0100 |
---|---|---|
committer | osmith <osmith@sysmocom.de> | 2019-01-14 14:39:57 +0000 |
commit | 894be2d9da60a8e0f7ffc0224e3f294ce49b70be (patch) | |
tree | a1dd3ddf90c21f61af54514243ef75071db94835 /src | |
parent | bd6e7a9f2dd5d4e881a0a21ebdb29b7a76ebdc9a (diff) |
gsm23003: add osmo_imei_str_valid()
Verify 14 digit and 15 digit IMEI strings. OsmoHLR will use the 14
digit version to check IMEIs before writing them to the DB.
Place the Luhn checksum code in a dedicated osmo_luhn() function, so
it can be used elsewhere.
Related: OS#2541
Change-Id: Id2d2a3a93b033bafc74c62e15297034bf4aafe61
Diffstat (limited to 'src')
-rw-r--r-- | src/gsm/gsm23003.c | 18 | ||||
-rw-r--r-- | src/gsm/libosmogsm.map | 1 | ||||
-rw-r--r-- | src/utils.c | 31 |
3 files changed, 50 insertions, 0 deletions
diff --git a/src/gsm/gsm23003.c b/src/gsm/gsm23003.c index 4fdad48a..1d9cefe6 100644 --- a/src/gsm/gsm23003.c +++ b/src/gsm/gsm23003.c @@ -31,6 +31,7 @@ #include <osmocom/gsm/gsm23003.h> #include <osmocom/gsm/protocol/gsm_23_003.h> +#include <osmocom/core/utils.h> static bool is_n_digits(const char *str, int min_digits, int max_digits) { @@ -71,6 +72,23 @@ bool osmo_msisdn_str_valid(const char *msisdn) return is_n_digits(msisdn, 1, 15); } +/*! Determine whether the given IMEI is valid according to 3GPP TS 23.003, + * Section 6.2.1. It consists of 14 digits, the 15th check digit is not + * intended for digital transmission. + * \param imei IMEI digits in ASCII string representation. + * \param with_15th_digit when true, expect the 15th digit to be present and + * verify it. + * \returns true when the IMEI is valid, false for invalid characters or number + * of digits. + */ +bool osmo_imei_str_valid(const char *imei, bool with_15th_digit) +{ + if (with_15th_digit) + return is_n_digits(imei, 15, 15) && osmo_luhn(imei, 14) == imei[14]; + else + return is_n_digits(imei, 14, 14); +} + /*! Return MCC string as standardized 3-digit with leading zeros. * \param[in] mcc MCC value. * \returns string in static buffer. diff --git a/src/gsm/libosmogsm.map b/src/gsm/libosmogsm.map index a9037870..331c3f0f 100644 --- a/src/gsm/libosmogsm.map +++ b/src/gsm/libosmogsm.map @@ -551,6 +551,7 @@ osmo_oap_decode; osmo_imsi_str_valid; osmo_msisdn_str_valid; +osmo_imei_str_valid; osmo_mncc_stringify; osmo_mncc_names; diff --git a/src/utils.c b/src/utils.c index 35d70ace..d1da4fa8 100644 --- a/src/utils.c +++ b/src/utils.c @@ -765,4 +765,35 @@ const char *osmo_str_toupper(const char *src) return buf; } +/*! Calculate the Luhn checksum (as used for IMEIs). + * \param[in] in Input digits in ASCII string representation. + * \param[in] in_len Count of digits to use for the input (14 for IMEI). + * \returns checksum char (e.g. '3'); negative on error + */ +const char osmo_luhn(const char* in, int in_len) +{ + int i, sum = 0; + + /* All input must be numbers */ + for (i = 0; i < in_len; i++) { + if (!isdigit(in[i])) + return -EINVAL; + } + + /* Double every second digit and add it to sum */ + for (i = in_len - 1; i >= 0; i -= 2) { + int dbl = (in[i] - '0') * 2; + if (dbl > 9) + dbl -= 9; + sum += dbl; + } + + /* Add other digits to sum */ + for (i = in_len - 2; i >= 0; i -= 2) + sum += in[i] - '0'; + + /* Final checksum */ + return (sum * 9) % 10 + '0'; +} + /*! @} */ |