Merge branch 'holger/merge-msc-bsc-split'
diff --git a/openbsc/.gitignore b/openbsc/.gitignore
new file mode 100644
index 0000000..7b7b11a
--- /dev/null
+++ b/openbsc/.gitignore
@@ -0,0 +1,39 @@
+*.o
+*.a
+.deps
+Makefile
+Makefile.in
+bsc_hack
+bsc_msc_ip
+*.*~
+*.sw?
+
+#configure
+aclocal.m4
+autom4te.cache/
+config.log
+config.status
+configure
+depcomp
+install-sh
+missing
+stamp-h1
+
+
+
+# apps and app data
+hlr.sqlite3
+bs11_config
+ipaccess-config
+ipaccess-find
+isdnsync
+
+#tests
+tests/channel/channel_test
+tests/db/db_test
+tests/debug/debug_test
+tests/gsm0408/gsm0408_test
+tests/sccp/sccp_test
+tests/sms/sms_test
+tests/timer/timer_test
+
diff --git a/openbsc/include/openbsc/debug.h b/openbsc/include/openbsc/debug.h
index f99ce60..089132e 100644
--- a/openbsc/include/openbsc/debug.h
+++ b/openbsc/include/openbsc/debug.h
@@ -30,7 +30,7 @@
 
 #define static_assert(exp, name) typedef int dummy##name [(exp) ? 1 : -1];
 
-char *hexdump(unsigned char *buf, int len);
+char *hexdump(const unsigned char *buf, int len);
 void debugp(unsigned int subsys, char *file, int line, int cont, const char *format, ...);
 void debug_parse_category_mask(const char* mask);
 void debug_use_color(int use_color);
diff --git a/openbsc/include/openbsc/gsm_04_08.h b/openbsc/include/openbsc/gsm_04_08.h
index 2518dfd..6f36786 100644
--- a/openbsc/include/openbsc/gsm_04_08.h
+++ b/openbsc/include/openbsc/gsm_04_08.h
@@ -684,6 +684,7 @@
 
 #define GSM48_TMSI_LEN	5
 #define GSM48_MID_TMSI_LEN	(GSM48_TMSI_LEN + 2)
+#define GSM48_MI_SIZE 32
 
 
 struct msgb;
@@ -707,7 +708,9 @@
 int gsm48_tx_mm_auth_rej(struct gsm_lchan *lchan);
 struct msgb *gsm48_msgb_alloc(void);
 int gsm48_sendmsg(struct msgb *msg, struct gsm_trans *trans);
-int generate_mid_from_tmsi(u_int8_t *buf, u_int32_t tmsi);
+int gsm48_generate_mid_from_tmsi(u_int8_t *buf, u_int32_t tmsi);
+int gsm48_generate_mid_from_imsi(u_int8_t *buf, const char* imsi);
+int gsm48_mi_to_string(char *string, const int str_len, const u_int8_t *mi, const int mi_len);
 
 int gsm48_send_rr_release(struct gsm_lchan *lchan);
 int gsm48_send_rr_app_info(struct gsm_lchan *lchan, u_int8_t apdu_id,
diff --git a/openbsc/include/openbsc/gsm_subscriber.h b/openbsc/include/openbsc/gsm_subscriber.h
index f01a47f..aaf261e 100644
--- a/openbsc/include/openbsc/gsm_subscriber.h
+++ b/openbsc/include/openbsc/gsm_subscriber.h
@@ -80,8 +80,7 @@
 int subscr_update(struct gsm_subscriber *s, struct gsm_bts *bts, int reason);
 void subscr_put_channel(struct gsm_lchan *lchan);
 void subscr_get_channel(struct gsm_subscriber *subscr,
-                        struct gsm_network *network, int type,
-		        gsm_cbfn *cbfn, void *param);
+                        int type, gsm_cbfn *cbfn, void *param);
 
 /* internal */
 struct gsm_subscriber *subscr_alloc(void);
diff --git a/openbsc/src/debug.c b/openbsc/src/debug.c
index 6483710..fa903af 100644
--- a/openbsc/src/debug.c
+++ b/openbsc/src/debug.c
@@ -143,7 +143,7 @@
 
 static char hexd_buff[4096];
 
-char *hexdump(unsigned char *buf, int len)
+char *hexdump(const unsigned char *buf, int len)
 {
 	int i;
 	char *cur = hexd_buff;
diff --git a/openbsc/src/gsm_04_08.c b/openbsc/src/gsm_04_08.c
index 94f9ef4..eeabc0f 100644
--- a/openbsc/src/gsm_04_08.c
+++ b/openbsc/src/gsm_04_08.c
@@ -899,7 +899,7 @@
 		     bts->network->network_code, bts->location_area_code);
 
 	mid = msgb_put(msg, GSM48_MID_TMSI_LEN);
-	generate_mid_from_tmsi(mid, tmsi);
+	gsm48_generate_mid_from_tmsi(mid, tmsi);
 
 	DEBUGP(DMM, "-> LOCATION UPDATE ACCEPT\n");
 
@@ -911,57 +911,6 @@
 	return ret;
 }
 
-static char bcd2char(u_int8_t bcd)
-{
-	if (bcd < 0xa)
-		return '0' + bcd;
-	else
-		return 'A' + (bcd - 0xa);
-}
-
-/* Convert Mobile Identity (10.5.1.4) to string */
-static int mi_to_string(char *string, int str_len, u_int8_t *mi, int mi_len)
-{
-	int i;
-	u_int8_t mi_type;
-	char *str_cur = string;
-	u_int32_t tmsi;
-
-	mi_type = mi[0] & GSM_MI_TYPE_MASK;
-
-	switch (mi_type) {
-	case GSM_MI_TYPE_NONE:
-		break;
-	case GSM_MI_TYPE_TMSI:
-		/* Table 10.5.4.3, reverse generate_mid_from_tmsi */
-		if (mi_len == GSM48_TMSI_LEN && mi[0] == (0xf0 | GSM_MI_TYPE_TMSI)) {
-			memcpy(&tmsi, &mi[1], 4);
-			tmsi = ntohl(tmsi);
-			return snprintf(string, str_len, "%u", tmsi);
-		}
-		break;
-	case GSM_MI_TYPE_IMSI:
-	case GSM_MI_TYPE_IMEI:
-	case GSM_MI_TYPE_IMEISV:
-		*str_cur++ = bcd2char(mi[0] >> 4);
-		
-                for (i = 1; i < mi_len; i++) {
-			if (str_cur + 2 >= string + str_len)
-				return str_cur - string;
-			*str_cur++ = bcd2char(mi[i] & 0xf);
-			/* skip last nibble in last input byte when GSM_EVEN */
-			if( (i != mi_len-1) || (mi[0] & GSM_MI_ODD))
-				*str_cur++ = bcd2char(mi[i] >> 4);
-		}
-		break;
-	default:
-		break;
-	}
-	*str_cur++ = '\0';
-
-	return str_cur - string;
-}
-
 /* Transmit Chapter 9.2.10 Identity Request */
 static int mm_tx_identity_req(struct gsm_lchan *lchan, u_int8_t id_type)
 {
@@ -978,7 +927,6 @@
 	return gsm48_sendmsg(msg, NULL);
 }
 
-#define MI_SIZE 32
 
 /* Parse Chapter 9.2.11 Identity Response */
 static int mm_rx_id_resp(struct msgb *msg)
@@ -988,9 +936,9 @@
 	struct gsm_bts *bts = lchan->ts->trx->bts;
 	struct gsm_network *net = bts->network;
 	u_int8_t mi_type = gh->data[1] & GSM_MI_TYPE_MASK;
-	char mi_string[MI_SIZE];
+	char mi_string[GSM48_MI_SIZE];
 
-	mi_to_string(mi_string, sizeof(mi_string), &gh->data[1], gh->data[0]);
+	gsm48_mi_to_string(mi_string, sizeof(mi_string), &gh->data[1], gh->data[0]);
 	DEBUGP(DMM, "IDENTITY RESPONSE: mi_type=0x%02x MI(%s)\n",
 		mi_type, mi_string);
 
@@ -1052,7 +1000,6 @@
 	}
 }
 
-#define MI_SIZE 32
 /* Chapter 9.2.15: Receive Location Updating Request */
 static int mm_rx_loc_upd_req(struct msgb *msg)
 {
@@ -1062,14 +1009,14 @@
 	struct gsm_lchan *lchan = msg->lchan;
 	struct gsm_bts *bts = lchan->ts->trx->bts;
 	u_int8_t mi_type;
-	char mi_string[MI_SIZE];
+	char mi_string[GSM48_MI_SIZE];
 	int rc;
 
  	lu = (struct gsm48_loc_upd_req *) gh->data;
 
 	mi_type = lu->mi[0] & GSM_MI_TYPE_MASK;
 
-	mi_to_string(mi_string, sizeof(mi_string), lu->mi, lu->mi_len);
+	gsm48_mi_to_string(mi_string, sizeof(mi_string), lu->mi, lu->mi_len);
 
 	DEBUGPC(DMM, "mi_type=0x%02x MI(%s) type=%s ", mi_type, mi_string,
 		lupd_name(lu->type));
@@ -1363,7 +1310,7 @@
 static int gsm48_rx_mm_serv_req(struct msgb *msg)
 {
 	u_int8_t mi_type;
-	char mi_string[MI_SIZE];
+	char mi_string[GSM48_MI_SIZE];
 
 	struct gsm_bts *bts = msg->lchan->ts->trx->bts;
 	struct gsm_subscriber *subscr;
@@ -1396,7 +1343,7 @@
 					    GSM48_REJECT_INCORRECT_MESSAGE);
 	}
 
-	mi_to_string(mi_string, sizeof(mi_string), mi, mi_len);
+	gsm48_mi_to_string(mi_string, sizeof(mi_string), mi, mi_len);
 	DEBUGPC(DMM, "serv_type=0x%02x mi_type=0x%02x M(%s)\n",
 		req->cm_service_type, mi_type, mi_string);
 
@@ -1431,10 +1378,10 @@
 	struct gsm48_imsi_detach_ind *idi =
 				(struct gsm48_imsi_detach_ind *) gh->data;
 	u_int8_t mi_type = idi->mi[0] & GSM_MI_TYPE_MASK;
-	char mi_string[MI_SIZE];
+	char mi_string[GSM48_MI_SIZE];
 	struct gsm_subscriber *subscr = NULL;
 
-	mi_to_string(mi_string, sizeof(mi_string), idi->mi, idi->mi_len);
+	gsm48_mi_to_string(mi_string, sizeof(mi_string), idi->mi, idi->mi_len);
 	DEBUGP(DMM, "IMSI DETACH INDICATION: mi_type=0x%02x MI(%s): ",
 		mi_type, mi_string);
 
@@ -1532,12 +1479,12 @@
 	u_int8_t *classmark2_lv = gh->data + 1;
 	u_int8_t *mi_lv = gh->data + 2 + *classmark2_lv;
 	u_int8_t mi_type = mi_lv[1] & GSM_MI_TYPE_MASK;
-	char mi_string[MI_SIZE];
+	char mi_string[GSM48_MI_SIZE];
 	struct gsm_subscriber *subscr = NULL;
 	struct paging_signal_data sig_data;
 	int rc = 0;
 
-	mi_to_string(mi_string, sizeof(mi_string), mi_lv+1, *mi_lv);
+	gsm48_mi_to_string(mi_string, sizeof(mi_string), mi_lv+1, *mi_lv);
 	DEBUGP(DRR, "PAGING RESPONSE: mi_type=0x%02x MI(%s)\n",
 		mi_type, mi_string);
 
diff --git a/openbsc/src/gsm_04_08_utils.c b/openbsc/src/gsm_04_08_utils.c
index 50deb2b..c62f04d 100644
--- a/openbsc/src/gsm_04_08_utils.c
+++ b/openbsc/src/gsm_04_08_utils.c
@@ -156,6 +156,21 @@
 	val = val / 10;
 }
 
+static char bcd2char(u_int8_t bcd)
+{
+	if (bcd < 0xa)
+		return '0' + bcd;
+	else
+		return 'A' + (bcd - 0xa);
+}
+
+/* only works for numbers in ascci */
+static u_int8_t char2bcd(char c)
+{
+	return c - 0x30;
+}
+
+
 void gsm0408_generate_lai(struct gsm48_loc_area_id *lai48, u_int16_t mcc,
 			 u_int16_t mnc, u_int16_t lac)
 {
@@ -178,7 +193,7 @@
 	lai48->lac = htons(lac);
 }
 
-int generate_mid_from_tmsi(u_int8_t *buf, u_int32_t tmsi)
+int gsm48_generate_mid_from_tmsi(u_int8_t *buf, u_int32_t tmsi)
 {
 	u_int32_t *tptr = (u_int32_t *) &buf[3];
 
@@ -190,6 +205,35 @@
 	return 7;
 }
 
+int gsm48_generate_mid_from_imsi(u_int8_t *buf, const char *imsi)
+{
+	unsigned int length = strlen(imsi), i, off = 0;
+	u_int8_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) {
+		u_int8_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];
+}
+
 /* Section 9.1.8 / Table 9.9 */
 struct chreq {
 	u_int8_t val;
@@ -308,3 +352,46 @@
 	return rsl_deact_sacch(lchan);
 }
 
+/* Convert Mobile Identity (10.5.1.4) to string */
+int gsm48_mi_to_string(char *string, const int str_len, const u_int8_t *mi, const int mi_len)
+{
+	int i;
+	u_int8_t mi_type;
+	char *str_cur = string;
+	u_int32_t tmsi;
+
+	mi_type = mi[0] & GSM_MI_TYPE_MASK;
+
+	switch (mi_type) {
+	case GSM_MI_TYPE_NONE:
+		break;
+	case GSM_MI_TYPE_TMSI:
+		/* Table 10.5.4.3, reverse generate_mid_from_tmsi */
+		if (mi_len == GSM48_TMSI_LEN && mi[0] == (0xf0 | GSM_MI_TYPE_TMSI)) {
+			memcpy(&tmsi, &mi[1], 4);
+			tmsi = ntohl(tmsi);
+			return snprintf(string, str_len, "%u", tmsi);
+		}
+		break;
+	case GSM_MI_TYPE_IMSI:
+	case GSM_MI_TYPE_IMEI:
+	case GSM_MI_TYPE_IMEISV:
+		*str_cur++ = bcd2char(mi[0] >> 4);
+
+                for (i = 1; i < mi_len; i++) {
+			if (str_cur + 2 >= string + str_len)
+				return str_cur - string;
+			*str_cur++ = bcd2char(mi[i] & 0xf);
+			/* skip last nibble in last input byte when GSM_EVEN */
+			if( (i != mi_len-1) || (mi[0] & GSM_MI_ODD))
+				*str_cur++ = bcd2char(mi[i] >> 4);
+		}
+		break;
+	default:
+		break;
+	}
+	*str_cur++ = '\0';
+
+	return str_cur - string;
+}
+
diff --git a/openbsc/src/gsm_subscriber_base.c b/openbsc/src/gsm_subscriber_base.c
index 83addd0..d6a179b 100644
--- a/openbsc/src/gsm_subscriber_base.c
+++ b/openbsc/src/gsm_subscriber_base.c
@@ -58,9 +58,6 @@
 	/* the requested channel type */
 	int channel_type;
 
-	/* the bts we have decided to use */
-	struct gsm_network *network;
-
 	/* the callback data */
 	gsm_cbfn *cbfn;
 	void *param;
@@ -100,7 +97,7 @@
 	assert(!llist_empty(&subscr->requests));
 
 	request = (struct subscr_request *)subscr->requests.next;
-	paging_request(request->network, subscr, request->channel_type,
+	paging_request(subscr->net, subscr, request->channel_type,
 		       subscr_paging_cb, subscr);
 }
 
@@ -146,8 +143,7 @@
 }
 
 void subscr_get_channel(struct gsm_subscriber *subscr,
-			struct gsm_network *network, int type,
-			gsm_cbfn *cbfn, void *param)
+			int type, gsm_cbfn *cbfn, void *param)
 {
 	struct subscr_request *request;
 
@@ -160,7 +156,6 @@
 	}
 
 	memset(request, 0, sizeof(*request));
-	request->network = network;
 	request->subscr = subscr;
 	request->channel_type = type;
 	request->cbfn = cbfn;
diff --git a/openbsc/src/paging.c b/openbsc/src/paging.c
index 87c5a54..fd0611a 100644
--- a/openbsc/src/paging.c
+++ b/openbsc/src/paging.c
@@ -99,7 +99,7 @@
 
 	page_group = calculate_group(request->bts, request->subscr);
 	tmsi = strtoul(request->subscr->tmsi, NULL, 10);
-	mi_len = generate_mid_from_tmsi(mi, tmsi);
+	mi_len = gsm48_generate_mid_from_tmsi(mi, tmsi);
 	rsl_paging_cmd(request->bts, page_group, mi_len, mi,
 			request->chan_type);
 }
@@ -202,9 +202,9 @@
 	DEBUGP(DPAG, "T3113 expired for request %p (%s)\n",
 		req, req->subscr->imsi);
 	
-	sig_data.subscr = req->subscr,
-	sig_data.bts	= req->bts,
-	sig_data.lchan	= NULL,
+	sig_data.subscr = req->subscr;
+	sig_data.bts	= req->bts;
+	sig_data.lchan	= NULL;
 
 	dispatch_signal(SS_PAGING, S_PAGING_COMPLETED, &sig_data);
 	if (req->cbfn)
diff --git a/openbsc/src/telnet_interface.c b/openbsc/src/telnet_interface.c
index ba57470..d7c9055 100644
--- a/openbsc/src/telnet_interface.c
+++ b/openbsc/src/telnet_interface.c
@@ -52,12 +52,6 @@
 
 /* per network data */
 static int telnet_new_connection(struct bsc_fd *fd, unsigned int what);
-#if 0
-static int telnet_paging_callback(unsigned int subsys, unsigned int signal,
-				  void *handler_data, void *signal_data);
-static int telnet_sms_callback(unsigned int subsys, unsigned int signal,
-				void *handler_data, void *signal_data);
-#endif
 
 static struct bsc_fd server_socket = {
 	.when	    = BSC_FD_READ,
@@ -101,12 +95,6 @@
 	server_socket.data = network;
 	server_socket.fd = fd;
 	bsc_register_fd(&server_socket);
-
-	/* register callbacks */
-#if 0
-	register_signal_handler(SS_PAGING, telnet_paging_callback, network);
-	register_signal_handler(SS_SMS, telnet_sms_callback, network);
-#endif
 }
 
 static void print_welcome(int fd) {
@@ -216,38 +204,3 @@
 	}
 }
 
-#if 0
-static int telnet_paging_callback(unsigned int subsys, unsigned int singal,
-				  void *handler_data, void *signal_data)
-{
-	struct paging_signal_data *paging = signal_data;
-	struct telnet_connection *con;
-
-	llist_for_each_entry(con, &active_connections, entry) {
-		if (paging->lchan) {
-			WRITE_CONNECTION(con->fd.fd, "Paging succeeded\n");
-			show_lchan(con->fd.fd, paging->lchan);
-		} else {
-			WRITE_CONNECTION(con->fd.fd, "Paging failed for subscriber: %s/%s/%s\n",
-				paging->subscr->imsi,
-				paging->subscr->tmsi,
-				paging->subscr->name);
-		}
-	}
-
-	return 0;
-}
-
-static int telnet_sms_callback(unsigned int subsys, unsigned int signal,
-				void *handler_data, void *signal_data)
-{
-	struct sms_submit *sms = signal_data;
-	struct telnet_connection *con;
-
-	llist_for_each_entry(con, &active_connections, entry) {
-		WRITE_CONNECTION(con->fd.fd, "Incoming SMS: %s\n", sms->user_data);
-	}
-
-	return 0;
-}
-#endif
diff --git a/openbsc/tests/channel/channel_test.c b/openbsc/tests/channel/channel_test.c
index 4dcf69a..1b01878 100644
--- a/openbsc/tests/channel/channel_test.c
+++ b/openbsc/tests/channel/channel_test.c
@@ -63,9 +63,10 @@
 	/* Create a dummy subscriber */
 	struct gsm_subscriber *subscr = subscr_alloc();
 	subscr->lac = 23;
+	subscr->net = network;
 
 	/* Ask for a channel... */
-	subscr_get_channel(subscr, network, RSL_CHANNEED_TCH_F, subscr_cb, (void*)0x2342L);
+	subscr_get_channel(subscr, RSL_CHANNEED_TCH_F, subscr_cb, (void*)0x2342L);
 
 	while (1) {
 		bsc_select_main(0);
diff --git a/openbsc/tests/gsm0408/gsm0408_test.c b/openbsc/tests/gsm0408/gsm0408_test.c
index c99766a..bbf8129 100644
--- a/openbsc/tests/gsm0408/gsm0408_test.c
+++ b/openbsc/tests/gsm0408/gsm0408_test.c
@@ -24,13 +24,20 @@
 #include <stdlib.h>
 
 #include <openbsc/gsm_04_08.h>
+#include <openbsc/gsm_subscriber.h>
+#include <openbsc/debug.h>
 
 #define COMPARE(result, op, value) \
     if (!((result) op (value))) {\
 	fprintf(stderr, "Compare failed. Was %x should be %x in %s:%d\n",result, value, __FILE__, __LINE__); \
 	exit(-1); \
     }
-	
+
+#define COMPARE_STR(result, value) \
+	if (strcmp(result, value) != 0) { \
+		fprintf(stderr, "Compare failed. Was %s should be %s in %s:%d\n",result, value, __FILE__, __LINE__); \
+		exit(-1); \
+	}
 
 /*
  * Test Location Area Identifier formatting. Table 10.5.3 of 04.08
@@ -58,9 +65,38 @@
     COMPARE(lai48.lac, ==, htons(0x000f));
 }
 
+static void test_mi_functionality(void)
+{
+	const char *imsi_odd  = "987654321098763";
+	const char *imsi_even = "9876543210987654";
+	const u_int32_t tmsi = 0xfabeacd0;
+	u_int8_t mi[128];
+	unsigned int mi_len;
+	char mi_parsed[GSM48_MI_SIZE];
+
+	printf("Testing parsing and generating TMSI/IMSI\n");
+
+	/* tmsi code */
+	mi_len = gsm48_generate_mid_from_tmsi(mi, tmsi);
+	gsm48_mi_to_string(mi_parsed, sizeof(mi_parsed), mi + 2, mi_len - 2);
+	COMPARE((u_int32_t)strtoul(mi_parsed, NULL, 10), ==, tmsi);
+
+	/* imsi code */
+	mi_len = gsm48_generate_mid_from_imsi(mi, imsi_odd);
+	gsm48_mi_to_string(mi_parsed, sizeof(mi_parsed), mi + 2, mi_len -2);
+	printf("hex: %s\n", hexdump(mi, mi_len));
+	COMPARE_STR(mi_parsed, imsi_odd);
+
+	mi_len = gsm48_generate_mid_from_imsi(mi, imsi_even);
+	gsm48_mi_to_string(mi_parsed, sizeof(mi_parsed), mi + 2, mi_len -2);
+	printf("hex: %s\n", hexdump(mi, mi_len));
+	COMPARE_STR(mi_parsed, imsi_even);
+}
+
 int main(int argc, char** argv)
 {
-    test_location_area_identifier();
+	test_location_area_identifier();
+	test_mi_functionality();
 }