import gsm48 utility functions from OpenBSC

* gsm48_generate_lai() gsm48_generate_mid_from_tmsi() gsm48_generate_mid_from_imsi()
* gsm48_cc_msg_names[]
diff --git a/src/gsm48.c b/src/gsm48.c
index 2ded209..ff989ea 100644
--- a/src/gsm48.c
+++ b/src/gsm48.c
@@ -26,6 +26,8 @@
 #include <stdio.h>
 #include <string.h>
 
+#include <arpa/inet.h>
+
 #include <osmocore/utils.h>
 #include <osmocore/tlv.h>
 #include <osmocore/gsm48.h>
@@ -93,7 +95,7 @@
 	[GSM48_RR_CAUSE_PROT_ERROR_UNSPC]	= "Protocol error unspecified",
 };
 
-const char *cc_state_names[] = {
+const char *cc_state_names[32] = {
 	"NULL",
 	"INITIATED",
 	"illegal state 2",
@@ -128,6 +130,73 @@
 	"illegal state 31",
 };
 
+const char *gsm48_cc_msg_names[0x40] = {
+	"unknown 0x00",
+	"ALERTING",
+	"CALL_PROC",
+	"PROGRESS",
+	"ESTAB",
+	"SETUP",
+	"ESTAB_CONF",
+	"CONNECT",
+	"CALL_CONF",
+	"START_CC",
+	"unknown 0x0a",
+	"RECALL",
+	"unknown 0x0c",
+	"unknown 0x0d",
+	"EMERG_SETUP",
+	"CONNECT_ACK",
+	"USER_INFO",
+	"unknown 0x11",
+	"unknown 0x12",
+	"MODIFY_REJECT",
+	"unknown 0x14",
+	"unknown 0x15",
+	"unknown 0x16",
+	"MODIFY",
+	"HOLD",
+	"HOLD_ACK",
+	"HOLD_REJ",
+	"unknown 0x1b",
+	"RETR",
+	"RETR_ACK",
+	"RETR_REJ",
+	"MODIFY_COMPL",
+	"unknown 0x20",
+	"unknown 0x21",
+	"unknown 0x22",
+	"unknown 0x23",
+	"unknown 0x24",
+	"DISCONNECT",
+	"unknown 0x26",
+	"unknown 0x27",
+	"unknown 0x28",
+	"unknown 0x29",
+	"RELEASE_COMPL",
+	"unknown 0x2b",
+	"unknown 0x2c",
+	"RELEASE",
+	"unknown 0x2e",
+	"unknown 0x2f",
+	"unknown 0x30",
+	"STOP_DTMF",
+	"STOP_DTMF_ACK",
+	"unknown 0x33",
+	"STATUS_ENQ",
+	"START_DTMF",
+	"START_DTMF_ACK",
+	"START_DTMF_REJ",
+	"unknown 0x38",
+	"CONG_CTRL",
+	"FACILITY",
+	"unknown 0x3b",
+	"STATUS",
+	"unknown 0x3d",
+	"NOTIFY",
+	"unknown 0x3f",
+};
+
 static char strbuf[64];
 
 const char *rr_cause_name(uint8_t cause)
@@ -140,4 +209,75 @@
 	return strbuf;
 }
 
+static void to_bcd(uint8_t *bcd, uint16_t val)
+{
+	bcd[2] = val % 10;
+	val = val / 10;
+	bcd[1] = val % 10;
+	val = val / 10;
+	bcd[0] = val % 10;
+	val = val / 10;
+}
 
+void gsm48_generate_lai(struct gsm48_loc_area_id *lai48, uint16_t mcc,
+			uint16_t mnc, uint16_t lac)
+{
+	uint8_t bcd[3];
+
+	to_bcd(bcd, mcc);
+	lai48->digits[0] = bcd[0] | (bcd[1] << 4);
+	lai48->digits[1] = bcd[2];
+
+	to_bcd(bcd, mnc);
+	/* FIXME: do we need three-digit MNC? See Table 10.5.3 */
+#if 0
+	lai48->digits[1] |= bcd[2] << 4;
+	lai48->digits[2] = bcd[0] | (bcd[1] << 4);
+#else
+	lai48->digits[1] |= 0xf << 4;
+	lai48->digits[2] = bcd[1] | (bcd[2] << 4);
+#endif
+
+	lai48->lac = htons(lac);
+}
+
+int gsm48_generate_mid_from_tmsi(uint8_t *buf, uint32_t tmsi)
+{
+	uint32_t *tptr = (uint32_t *) &buf[3];
+
+	buf[0] = GSM48_IE_MOBILE_ID;
+	buf[1] = GSM48_TMSI_LEN;
+	buf[2] = 0xf0 | GSM_MI_TYPE_TMSI;
+	*tptr = htonl(tmsi);
+
+	return 7;
+}
+
+int gsm48_generate_mid_from_imsi(uint8_t *buf, const char *imsi)
+{
+	unsigned int length = strlen(imsi), i, off = 0;
+	uint8_t odd = (length & 0x1) == 1;
+
+	buf[0] = GSM48_IE_MOBILE_ID;
+	buf[2] = char2bcd(imsi[0]) << 4 | GSM_MI_TYPE_IMSI | (odd << 3);
+
+	/* if the length is even we will fill half of the last octet */
+	if (odd)
+		buf[1] = (length + 1) >> 1;
+	else
+		buf[1] = (length + 2) >> 1;
+
+	for (i = 1; i < buf[1]; ++i) {
+		uint8_t lower, upper;
+
+		lower = char2bcd(imsi[++off]);
+		if (!odd && off + 1 == length)
+			upper = 0x0f;
+		else
+			upper = char2bcd(imsi[++off]) & 0x0f;
+
+		buf[2 + i] = (upper << 4) | lower;
+	}
+
+	return 2 + buf[1];
+}