summaryrefslogtreecommitdiffstats
path: root/src/utils.c
diff options
context:
space:
mode:
authorOliver Smith <osmith@sysmocom.de>2019-01-11 13:13:37 +0100
committerosmith <osmith@sysmocom.de>2019-01-14 14:39:57 +0000
commit894be2d9da60a8e0f7ffc0224e3f294ce49b70be (patch)
treea1dd3ddf90c21f61af54514243ef75071db94835 /src/utils.c
parentbd6e7a9f2dd5d4e881a0a21ebdb29b7a76ebdc9a (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/utils.c')
-rw-r--r--src/utils.c31
1 files changed, 31 insertions, 0 deletions
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';
+}
+
/*! @} */