Merge branch 'zecke/features/alpha-numeric'
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