sms: Implement encoding the address as alphanumeric type

The number of digits is the number of used octets times two (two
digits per octet). The result has been successfully dissected by
wireshark. It has not been tested with real phones.
diff --git a/include/Makefile.am b/include/Makefile.am
index b1a818d..42a2dc2 100644
--- a/include/Makefile.am
+++ b/include/Makefile.am
@@ -59,6 +59,7 @@
                        osmocom/gsm/mncc.h \
                        osmocom/gsm/prim.h \
                        osmocom/gsm/l1sap.h \
+                       osmocom/gsm/protocol/gsm_03_40.h \
                        osmocom/gsm/protocol/gsm_03_41.h \
                        osmocom/gsm/protocol/gsm_04_08.h \
                        osmocom/gsm/protocol/gsm_04_11.h \
diff --git a/include/osmocom/gsm/protocol/gsm_03_40.h b/include/osmocom/gsm/protocol/gsm_03_40.h
new file mode 100644
index 0000000..32d5c2c
--- /dev/null
+++ b/include/osmocom/gsm/protocol/gsm_03_40.h
@@ -0,0 +1,32 @@
+#pragma once
+
+/* GSM TS 03.40 */
+
+/**
+ * 9.1.2.5 Type Of Number
+ */
+enum {
+	GSM340_TYPE_UNKNOWN		= 0,
+	GSM340_TYPE_INTERNATIONAL	= 1,
+	GSM340_TYPE_NATIONAL		= 2,
+	GSM340_TYPE_NETWORK		= 3,
+	GSM340_TYPE_SUBSCRIBER		= 4,
+	GSM340_TYPE_ALPHA_NUMERIC	= 5,
+	GSM340_TYPE_ABBREVIATED		= 6,
+	GSM340_TYPE_RESERVED		= 7,
+};
+
+/**
+ * 9.1.2.5 Type of Numbering plan.
+ * Applies for numbering plans (Unknown, International, National)
+ */
+enum {
+	GSM340_PLAN_UNKNOWN		= 0,
+	GSM340_PLAN_ISDN		= 1,
+	GSM340_PLAN_DATA		= 3,
+	GSM340_PLAN_TELEX		= 4,
+	GSM340_PLAN_NATIONAL		= 8,
+	GSM340_PLAN_PRIVATE		= 9,
+	GSM340_PLAN_ERMES		= 10,
+	GSM340_PLAN_RESERVED		= 15,
+};
diff --git a/src/gsm/gsm0411_utils.c b/src/gsm/gsm0411_utils.c
index fe69bf4..a8ba810 100644
--- a/src/gsm/gsm0411_utils.c
+++ b/src/gsm/gsm0411_utils.c
@@ -4,7 +4,7 @@
 
 /* (C) 2008 by Daniel Willmann <daniel@totalueberwachung.de>
  * (C) 2009 by Harald Welte <laforge@gnumonks.org>
- * (C) 2010 by Holger Hans Peter Freyther <zecke@selfish.org>
+ * (C) 2010-2013 by Holger Hans Peter Freyther <zecke@selfish.org>
  * (C) 2010 by On-Waves
  * (C) 2011 by Andreas Eversberg <jolly@eversberg.eu>
  *
@@ -33,6 +33,8 @@
 #include <osmocom/core/logging.h>
 
 #include <osmocom/gsm/gsm48.h>
+#include <osmocom/gsm/gsm_utils.h>
+#include <osmocom/gsm/protocol/gsm_03_40.h>
 #include <osmocom/gsm/protocol/gsm_04_11.h>
 
 #define GSM411_ALLOC_SIZE	1024
@@ -269,16 +271,26 @@
 {
 	int len_in_bytes;
 
-	/* prevent buffer overflows */
-	if (strlen(number) > 20)
-		number = "";
-
 	oa[1] = 0x80 | (type << 4) | plan;
 
-	len_in_bytes = gsm48_encode_bcd_number(oa, oa_len, 1, number);
-
-	/* GSM 03.40 tells us the length is in 'useful semi-octets' */
-	oa[0] = strlen(number) & 0xff;
+	if (type == GSM340_TYPE_ALPHA_NUMERIC) {
+		/*
+		 * TODO/FIXME: what is the 'useful semi-octets' excluding any
+		 * semi octet containing only fill bits.
+		 * The current code picks the number of bytes written by the
+		 * 7bit encoding routines and multiplies it by two.
+		 */
+		gsm_7bit_encode_n(&oa[2], oa_len - 2, number, &len_in_bytes);
+		oa[0] = len_in_bytes * 2;
+		len_in_bytes += 2;
+	} else {
+		/* prevent buffer overflows */
+		if (strlen(number) > 20)
+			number = "";
+		len_in_bytes = gsm48_encode_bcd_number(oa, oa_len, 1, number);
+		/* GSM 03.40 tells us the length is in 'useful semi-octets' */
+		oa[0] = strlen(number) & 0xff;
+	}
 
 	return len_in_bytes;
 }
diff --git a/tests/sms/sms_test.c b/tests/sms/sms_test.c
index 3188a18..a79d454 100644
--- a/tests/sms/sms_test.c
+++ b/tests/sms/sms_test.c
@@ -22,8 +22,13 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <osmocom/core/msgb.h>
+
+#include <osmocom/gsm/protocol/gsm_03_40.h>
+
 #include <osmocom/gsm/gsm_utils.h>
+#include <osmocom/gsm/gsm0411_utils.h>
+
+#include <osmocom/core/msgb.h>
 #include <osmocom/core/utils.h>
 
 struct test_case {
@@ -222,6 +227,42 @@
 	printf("Done\n");
 }
 
+static void test_gen_oa(void)
+{
+	uint8_t oa[12];
+	int len;
+
+	printf("Testing gsm340_gen_oa\n");
+
+	/* first try... */
+	len = gsm340_gen_oa(oa, ARRAY_SIZE(oa), GSM340_TYPE_UNKNOWN,
+			GSM340_PLAN_ISDN, "12345678901234567891");
+	OSMO_ASSERT(len == 12);
+	printf("Result: len(%d) data(%s)\n", len, osmo_hexdump(oa, len));
+	len = gsm340_gen_oa(oa, ARRAY_SIZE(oa), GSM340_TYPE_NATIONAL,
+			GSM340_PLAN_ISDN, "12345678901234567891");
+	OSMO_ASSERT(len == 12);
+	printf("Result: len(%d) data(%s)\n", len, osmo_hexdump(oa, len));
+
+	/* long input.. will fail and just prints the header*/
+	len = gsm340_gen_oa(oa, ARRAY_SIZE(oa), GSM340_TYPE_INTERNATIONAL,
+			GSM340_PLAN_ISDN, "123456789123456789120");
+	OSMO_ASSERT(len == 2);
+	printf("Result: len(%d) data(%s)\n", len, osmo_hexdump(oa, len));
+
+	/* try the alpha numeric encoding */
+	len = gsm340_gen_oa(oa, ARRAY_SIZE(oa), GSM340_TYPE_ALPHA_NUMERIC,
+			GSM340_PLAN_UNKNOWN, "OpenBSC");
+	OSMO_ASSERT(len == 9);
+	printf("Result: len(%d) data(%s)\n", len, osmo_hexdump(oa, len));
+
+	/* long alpha numeric text */
+	len = gsm340_gen_oa(oa, ARRAY_SIZE(oa), GSM340_TYPE_ALPHA_NUMERIC,
+			GSM340_PLAN_UNKNOWN, "OpenBSCabcdefghijklm");
+	OSMO_ASSERT(len == 12);
+	printf("Result: len(%d) data(%s)\n", len, osmo_hexdump(oa, len));
+}
+
 int main(int argc, char** argv)
 {
 	printf("SMS testing\n");
@@ -344,6 +385,7 @@
 	}
 
 	test_octet_return();
+	test_gen_oa();
 
 	printf("OK\n");
 	return 0;
diff --git a/tests/sms/sms_test.ok b/tests/sms/sms_test.ok
index 915a59c..a71567d 100644
--- a/tests/sms/sms_test.ok
+++ b/tests/sms/sms_test.ok
@@ -12,4 +12,10 @@
 Encoding some tests and printing number of septets/octets
 SEPTETS: 8 OCTETS: 7
 Done
+Testing gsm340_gen_oa
+Result: len(12) data(14 81 21 43 65 87 09 21 43 65 87 19 )
+Result: len(12) data(14 a1 21 43 65 87 09 21 43 65 87 19 )
+Result: len(2) data(00 91 )
+Result: len(9) data(0e d0 4f 78 d9 2d 9c 0e 01 )
+Result: len(12) data(14 d0 4f 78 d9 2d 9c 0e c3 e2 31 19 )
 OK