add osmo_imsi_str_valid() and osmo_msisdn_str_valid()

Add GSM23003_IMSI_MIN_DIGITS definition.
Add regression test gsm23003_test.c to test the two new functions.

Will be used by OsmoHLR to validate VTY and CTRL input.

Change-Id: I1e94f5b0717b947d2a7a7d36bacdf04a75cb3522
diff --git a/src/gsm/Makefile.am b/src/gsm/Makefile.am
index 08cd5e6..48b8b2c 100644
--- a/src/gsm/Makefile.am
+++ b/src/gsm/Makefile.am
@@ -29,7 +29,8 @@
 			auth_milenage.c milenage/aes-encblock.c gea.c \
 			milenage/aes-internal.c milenage/aes-internal-enc.c \
 			milenage/milenage.c gan.c ipa.c gsm0341.c apn.c \
-			gsup.c gprs_gea.c gsm0503_conv.c oap.c gsm0808_utils.c
+			gsup.c gprs_gea.c gsm0503_conv.c oap.c gsm0808_utils.c \
+			gsm23003.c
 libgsmint_la_LDFLAGS = -no-undefined
 libgsmint_la_LIBADD = $(top_builddir)/src/libosmocore.la
 
diff --git a/src/gsm/gsm23003.c b/src/gsm/gsm23003.c
new file mode 100644
index 0000000..004e20f
--- /dev/null
+++ b/src/gsm/gsm23003.c
@@ -0,0 +1,65 @@
+/*! \file gsm23003.c
+ * Utility function implementations related to 3GPP TS 23.003 */
+/*
+ * (C) 2017 sysmocom s.f.m.c. GmbH <info@sysmocom.de>
+ * All Rights Reserved
+ *
+ * Author: Neels Hofmeyr <nhofmeyr@sysmocom.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <ctype.h>
+
+#include <osmocom/gsm/gsm23003.h>
+#include <osmocom/gsm/protocol/gsm_23_003.h>
+
+static bool is_n_digits(const char *str, int min_digits, int max_digits)
+{
+	int len;
+	/* Use unsigned char * to avoid a compiler warning of
+	 * "error: array subscript has type 'char' [-Werror=char-subscripts]" */
+	const unsigned char *pos = (const unsigned char *)str;
+	for (len = 0; *pos && len < max_digits; len++, pos++)
+		if (!isdigit(*pos))
+			return false;
+	if (len < min_digits)
+		return false;
+	/* With not too many digits, we should have reached *str == nul */
+	if (*pos)
+		return false;
+	return true;
+}
+
+/*! Determine whether the given IMSI is valid according to 3GPP TS 23.003.
+ * \param imsi  IMSI digits in ASCII string representation.
+ * \returns true when the IMSI is valid, false for invalid characters or number
+ *          of digits.
+ */
+bool osmo_imsi_str_valid(const char *imsi)
+{
+	return is_n_digits(imsi, GSM23003_IMSI_MIN_DIGITS, GSM23003_IMSI_MAX_DIGITS);
+}
+
+/*! Determine whether the given MSISDN is valid according to 3GPP TS 23.003.
+ * \param msisdn  MSISDN digits in ASCII string representation.
+ * \returns true when the MSISDN is valid, false for invalid characters or number
+ *          of digits.
+ */
+bool osmo_msisdn_str_valid(const char *msisdn)
+{
+	return is_n_digits(msisdn, 1, 15);
+}
diff --git a/src/gsm/libosmogsm.map b/src/gsm/libosmogsm.map
index 066f410..95b2ca9 100644
--- a/src/gsm/libosmogsm.map
+++ b/src/gsm/libosmogsm.map
@@ -418,5 +418,8 @@
 osmo_oap_encode;
 osmo_oap_decode;
 
+osmo_imsi_str_valid;
+osmo_msisdn_str_valid;
+
 local: *;
 };