now we get up to the SETUP of MO calls

diff --git a/src/abis_rsl.c b/src/abis_rsl.c
index df34929..f6f5f2f 100644
--- a/src/abis_rsl.c
+++ b/src/abis_rsl.c
@@ -336,6 +336,62 @@
 	return rsl_chan_activate(ts->trx->bts, chan_nr, 0x00, &cm, &ci, 0x01, 0x0f, 0x00);
 }
 
+int rsl_chan_activate_lchan(struct gsm_lchan *lchan, u_int8_t act_type, u_int8_t ta)
+{
+	struct abis_rsl_dchan_hdr *dh;
+	struct msgb *msg = rsl_msgb_alloc();
+	/* FXIME: don't hardcode these!! */
+	u_int8_t encr_info = 0x01;
+	u_int8_t ms_power = 0x0f;
+	u_int8_t bs_power = 0x01;
+
+	u_int8_t chan_nr = lchan2chan_nr(lchan);
+	u_int16_t arfcn = lchan->ts->trx->arfcn;
+	struct rsl_ie_chan_mode cm;
+	struct rsl_ie_chan_ident ci;
+
+	/* FIXME: what to do with data calls ? */
+	cm.dtx_dtu = 0x00;
+	switch (lchan->type) {
+	case GSM_LCHAN_SDCCH:
+		cm.spd_ind = RSL_CMOD_SPD_SIGN;
+		cm.chan_rt = RSL_CMOD_CRT_SDCCH;
+		cm.chan_rate = 0x00;
+		break;
+	case GSM_LCHAN_TCH_F:
+		cm.spd_ind = RSL_CMOD_SPD_SPEECH;
+		cm.chan_rt = RSL_CMOD_CRT_TCH_Bm;
+		cm.chan_rate = 0x11; /* speech coding alg version 2*/
+		break;
+	}
+
+	ci.chan_desc.iei = 0x64;
+	ci.chan_desc.chan_nr = chan_nr;
+	ci.chan_desc.oct3 = (TSC << 5) | ((arfcn & 0x3ff) >> 8);
+	ci.chan_desc.oct4 = arfcn & 0xff;
+
+	dh = (struct abis_rsl_dchan_hdr *) msgb_put(msg, sizeof(*dh));
+	init_dchan_hdr(dh, RSL_MT_CHAN_ACTIV);
+	dh->chan_nr = chan_nr;
+
+	msgb_tv_put(msg, RSL_IE_ACT_TYPE, act_type);
+	/* For compatibility with Phase 1 */
+	msgb_tlv_put(msg, RSL_IE_CHAN_MODE, sizeof(cm),
+		     (u_int8_t *) &cm);
+	msgb_tlv_put(msg, RSL_IE_CHAN_IDENT, 4,
+		     (u_int8_t *) &ci);
+	/* FIXME: this shoould be optional */
+#if 0
+	msgb_tlv_put(msg, RSL_IE_ENCR_INFO, 1,
+		     (u_int8_t *) &encr_info);
+	msgb_tv_put(msg, RSL_IE_BS_POWER, bs_power);
+#endif
+	msgb_tv_put(msg, RSL_IE_MS_POWER, ms_power);
+	msgb_tv_put(msg, RSL_IE_TIMING_ADVANCE, ta);
+
+	return abis_rsl_sendmsg(msg);
+}
+
 int rsl_chan_release(struct gsm_lchan *lchan)
 {
 	struct abis_rsl_dchan_hdr *dh;
@@ -427,7 +483,7 @@
 	}
 
 	/* First push the L3 IE tag and length */
-	msgb_tv_push(msg, RSL_IE_L3_INFO, l3_len);
+	msgb_tv16_push(msg, RSL_IE_L3_INFO, l3_len);
 
 	/* Then push the RSL header */
 	rh = (struct abis_rsl_rll_hdr *) msgb_push(msg, sizeof(*rh));
@@ -447,8 +503,27 @@
 
 	/* BTS has confirmed channel activation, we now need
 	 * to assign the activated channel to the MS */
+	if (rslh->ie_chan != RSL_IE_CHAN_NR)
+		return -EINVAL;
+	
+	DEBUGP(DRSL, "Channel Activate ACK Channel 0x%02x\n", rslh->chan_nr);
 
+	return 0;
+}
 
+/* Chapter 8.4.3: Channel Activate NACK */
+static int rsl_rx_chan_act_nack(struct msgb *msg)
+{
+	struct abis_rsl_dchan_hdr *rslh = msgb_l2(msg);
+
+	/* BTS has confirmed channel activation, we now need
+	 * to assign the activated channel to the MS */
+	if (rslh->ie_chan != RSL_IE_CHAN_NR)
+		return -EINVAL;
+	
+	DEBUGP(DRSL, "Channel Activate NACK Channel 0x%02x\n", rslh->chan_nr);
+
+	return 0;
 }
 
 static int abis_rsl_rx_dchan(struct msgb *msg)
@@ -460,11 +535,11 @@
 
 	switch (rslh->c.msg_type) {
 	case RSL_MT_CHAN_ACTIV_ACK:
-		DEBUGP(DRSL, "rsl_rx_dchan: Channel Activate ACK\n");
+		rc = rsl_rx_chan_act_ack(msg);
 		rc = rsl_rx_chan_act_ack(msg);
 		break;
 	case RSL_MT_CHAN_ACTIV_NACK:
-		DEBUGP(DRSL, "rsl_rx_dchan: Channel Activate NACK\n");
+		rc = rsl_rx_chan_act_nack(msg);
 		break;
 	case RSL_MT_CONN_FAIL:
 		DEBUGP(DRSL, "rsl_rx_dchan: Connection Fail\n");
@@ -503,7 +578,7 @@
 		return -EINVAL;
 
 	cause_len = rslh->data[1];
-	printf(stdout, "RSL ERROR REPORT, Cause ");
+	fprintf(stdout, "RSL ERROR REPORT, Cause ");
 	hexdump(&rslh->data[2], cause_len);
 
 	return 0;
@@ -577,11 +652,15 @@
 	DEBUGP(DRSL, "Activating ARFCN(%u) TS(%u) SS(%u) lctype %u\n",
 		arfcn, ts_number, subch, lchan->type);
 
+#if 0
 	/* send CHANNEL ACTIVATION on RSL to BTS */
 	if (lchan->ts->pchan == GSM_PCHAN_CCCH_SDCCH4)
 		rsl_chan_activate_sdcch4(lchan->ts, subch);
 	else
 		rsl_chan_activate_tch_f(lchan->ts);
+#else
+	rsl_chan_activate_lchan(lchan, 0x00, rqd_ta);
+#endif
 
 	/* create IMMEDIATE ASSIGN 04.08 messge */
 	memset(&ia, 0, sizeof(ia));
@@ -589,7 +668,7 @@
 	ia.proto_discr = GSM48_PDISC_RR;
 	ia.msg_type = GSM48_MT_RR_IMM_ASS;
 	ia.page_mode = GSM48_PM_NORMAL;
-	ia.chan_desc.chan_nr = rsl_enc_chan_nr(RSL_CHAN_SDCCH4_ACCH, subch, ts_number);
+	ia.chan_desc.chan_nr = lchan2chan_nr(lchan);
 	ia.chan_desc.h0.h = 0;
 	ia.chan_desc.h0.arfcn_high = arfcn >> 8;
 	ia.chan_desc.h0.arfcn_low = arfcn & 0xff;
@@ -633,6 +712,16 @@
 	return rc;
 }
 
+static int rsl_rx_rll_err_ind(struct msgb *msg)
+{
+	struct abis_rsl_rll_hdr *rllh = msgb_l2(msg);
+	u_int8_t *rlm_cause = rllh->data;
+
+	DEBUGP(DRLL, "RLL ERROR INDICATION: chan_nr=0x%02x cause=0x%02x\n",
+		rllh->chan_nr, rlm_cause[1]);
+		
+	return 0;
+}
 /*	ESTABLISH INDICATION, LOCATION AREA UPDATE REQUEST 
 	0x02, 0x06,
 	0x01, 0x20,
@@ -648,19 +737,25 @@
 	
 	switch (rllh->c.msg_type) {
 	case RSL_MT_DATA_IND:
-		DEBUGP(DRLL, "DATA INDICATION\n");
+		DEBUGP(DRLL, "DATA INDICATION chan_nr=0x%02x\n", rllh->chan_nr);
 		/* FIXME: Verify L3 info element */
 		msg->l3h = &rllh->data[3];
 		rc = gsm0408_rcvmsg(msg);
 		break;
 	case RSL_MT_EST_IND:
-		DEBUGP(DRLL, "ESTABLISH INDICATION\n");
+		DEBUGP(DRLL, "ESTABLISH INDICATION chan_nr=0x%02x\n", rllh->chan_nr);
 		/* FIXME: Verify L3 info element */
 		msg->l3h = &rllh->data[3];
 		rc = gsm0408_rcvmsg(msg);
 		break;
-	case RSL_MT_ERROR_IND:
 	case RSL_MT_REL_IND:
+		DEBUGP(DRLL, "RELEASE INDICATION chan_nr=0x%02x\n", rllh->chan_nr);
+		lchan_free(msg->lchan);
+		rc = 0;
+		break;
+	case RSL_MT_ERROR_IND:
+		rc = rsl_rx_rll_err_ind(msg);
+		break;
 	case RSL_MT_UNIT_DATA_IND:
 		fprintf(stderr, "unimplemented Abis RLL message type 0x%02x\n",
 			rllh->c.msg_type);
diff --git a/src/chan_alloc.c b/src/chan_alloc.c
index ca86908..4ef5ff9 100644
--- a/src/chan_alloc.c
+++ b/src/chan_alloc.c
@@ -27,6 +27,7 @@
 
 #include <openbsc/gsm_data.h>
 #include <openbsc/chan_alloc.h>
+#include <openbsc/abis_nm.h>
 
 struct gsm_bts_trx_ts *ts_c0_alloc(struct gsm_bts *bts,
 				   enum gsm_phys_chan_config pchan)
@@ -46,6 +47,14 @@
 	return ts;
 }
 
+static const enum abis_nm_chan_comb chcomb4pchan[] = {
+	[GSM_PCHAN_CCCH]	= NM_CHANC_mainBCCH,
+	[GSM_PCHAN_CCCH_SDCCH4]	= NM_CHANC_BCCCHComb,
+	[GSM_PCHAN_TCH_F]	= NM_CHANC_TCHFull,
+	[GSM_PCHAN_TCH_H]	= NM_CHANC_TCHHalf,
+	[GSM_PCHAN_SDCCH8_SACCH8C] = NM_CHANC_SDCCH,
+	/* FIXME: bounds check */
+};
 
 /* Allocate a logical channel (TS) */
 struct gsm_bts_trx_ts *ts_alloc(struct gsm_bts *bts,
@@ -58,6 +67,8 @@
 			struct gsm_bts_trx_ts *ts = &trx->ts[j];
 			if (ts->pchan == GSM_PCHAN_NONE) {
 				ts->pchan = pchan;
+				/* set channel attribute on OML */
+				abis_nm_set_channel_attr(ts, chcomb4pchan[pchan]);
 				return ts;
 			}
 		}
diff --git a/src/gsm_04_08.c b/src/gsm_04_08.c
index 212b4ad..b478bc7 100644
--- a/src/gsm_04_08.c
+++ b/src/gsm_04_08.c
@@ -26,6 +26,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <errno.h>
+#include <netinet/in.h>
 
 #include <openbsc/msgb.h>
 #include <openbsc/debug.h>
@@ -64,11 +65,11 @@
 
 static void to_bcd(u_int8_t *bcd, u_int16_t val)
 {
-	bcd[0] = val % 10;
+	bcd[2] = val % 10;
 	val = val / 10;
 	bcd[1] = val % 10;
 	val = val / 10;
-	bcd[2] = val % 10;
+	bcd[0] = val % 10;
 	val = val / 10;
 }
 
@@ -82,10 +83,16 @@
 	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 = lac;
+	lai48->lac = htons(lac);
 }
 
 #define TMSI_LEN	4
@@ -93,12 +100,13 @@
 
 static void generate_mid_from_tmsi(u_int8_t *buf, u_int8_t *tmsi_bcd)
 {
-	buf[0] = MID_TMSI_LEN;
-	buf[1] = 0xf0 | GSM_MI_TYPE_TMSI;
-	buf[2] = tmsi_bcd[0];
-	buf[3] = tmsi_bcd[1];
-	buf[4] = tmsi_bcd[2];
-	buf[5] = tmsi_bcd[3];
+	buf[0] = GSM48_IE_MOBILE_ID;
+	buf[1] = MID_TMSI_LEN;
+	buf[2] = 0xf0 | GSM_MI_TYPE_TMSI;
+	buf[3] = tmsi_bcd[0];
+	buf[4] = tmsi_bcd[1];
+	buf[5] = tmsi_bcd[2];
+	buf[6] = tmsi_bcd[3];
 }
 
 static struct msgb *gsm48_msgb_alloc(void)
@@ -111,14 +119,45 @@
 	if (msg->lchan)
 		msg->trx = msg->lchan->ts->trx;
 
+	msg->l3h = msg->data;
+
 	return rsl_data_request(msg, 0);
 }
 
+static int gsm48_cc_tx_status(struct gsm_lchan *lchan)
+{
+	struct msgb *msg = gsm48_msgb_alloc();
+	struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
+	u_int8_t *cause, *call_state;
+
+	msg->lchan = lchan;
+
+	gh->proto_discr = GSM48_PDISC_CC;
+	gh->msg_type = GSM48_MT_CC_STATUS;
+
+	cause = msgb_put(msg, 3);
+	cause[0] = 2;
+	cause[1] = GSM48_CAUSE_CS_GSM | GSM48_CAUSE_LOC_USER;
+	cause[2] = 0x80 | 30;	/* response to status inquiry */
+
+	call_state = msgb_put(msg, 1);
+	call_state[0] = 0xc0 | 0x00;
+
+	return gsm0408_sendmsg(msg);
+}
+
+static int gsm48_cc_rx_status_enq(struct msgb *msg)
+{
+	return gsm48_cc_tx_status(msg->lchan);
+}
+
 static int gsm0408_rcv_cc(struct msgb *msg)
 {
 	struct gsm48_hdr *gh = msgb_l3(msg);
+	u_int8_t msg_type = gh->msg_type & 0xbf;
+	int rc = 0;
 
-	switch (gh->msg_type & 0xbf) {
+	switch (msg_type) {
 	case GSM48_MT_CC_CALL_CONF:
 		/* Response to SETUP */
 		DEBUGP(DCC, "CALL CONFIRM\n");
@@ -137,18 +176,27 @@
 		DEBUGP(DCC, "RELEASE\n");
 		/* need to respond with RELEASE_COMPLETE */
 		break;
-	case GSM48_MT_CC_EMERG_SETUP:
-		//DEBUGP(DCC, "EMERGENCY SETUP\n");
+	case GSM48_MT_CC_STATUS_ENQ:
+		rc = gsm48_cc_rx_status_enq(msg);
+		break;
+	case GSM48_MT_CC_DISCONNECT:
+		DEBUGP(DCC, "DISCONNECT\n");
+		break;
 	case GSM48_MT_CC_SETUP:
-		//DEBUGP(DCC, "SETUP\n");
+		DEBUGP(DCC, "SETUP\n");
 		/* FIXME: continue with CALL_PROCEEDING, ALERTING, CONNECT, RELEASE_COMPLETE */
+		break;
+	case GSM48_MT_CC_EMERG_SETUP:
+		DEBUGP(DCC, "EMERGENCY SETUP\n");
+		/* FIXME: continue with CALL_PROCEEDING, ALERTING, CONNECT, RELEASE_COMPLETE */
+		break;
 	default:
 		fprintf(stderr, "Unimplemented GSM 04.08 msg type 0x%02x\n",
-			gh->msg_type);
+			msg_type);
 		break;
 	}
 
-	return 0;
+	return rc;
 }
 
 /* Chapter 9.2.14 : Send LOCATION UPDATE REJECT */
@@ -209,11 +257,12 @@
 
 	mi_type = lu->mi[0] & GSM_MI_TYPE_MASK;
 
+	DEBUGP(DMM, "LUPDREQ: mi_type = 0x%02x\n", mi_type);
 	switch (mi_type) {
 	case GSM_MI_TYPE_IMSI:
 		/* look up subscriber based on IMSI */
 		subscr = subscr_get_by_imsi(&lu->mi[1]);
-		break;	
+		break;
 	case GSM_MI_TYPE_TMSI:
 		/* look up the subscriber based on TMSI, request IMSI if it fails */
 		subscr = subscr_get_by_tmsi(&lu->mi[1]);
@@ -244,6 +293,29 @@
 	return gsm0408_loc_upd_acc(msg->lchan, subscr->tmsi);
 }
 
+static int gsm48_tx_mm_serv_ack(struct gsm_lchan *lchan)
+{
+	struct msgb *msg = gsm48_msgb_alloc();
+	struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
+
+	msg->lchan = lchan;
+
+	gh->proto_discr = GSM48_PDISC_MM;
+	gh->msg_type = GSM48_MT_MM_CM_SERV_ACC;
+
+	DEBUGP(DMM, "-> CM SERVICE ACK\n");
+
+	return gsm0408_sendmsg(msg);
+}
+		
+static int gsm48_rx_mm_serv_req(struct msgb *msg)
+{
+	struct gsm48_hdr *gh = msgb_l3(msg);
+
+	DEBUGP(DMM, "CM SERVICE REQUEST\n");
+	return gsm48_tx_mm_serv_ack(msg->lchan);
+}
+
 static int gsm0408_rcv_mm(struct msgb *msg)
 {
 	struct gsm48_hdr *gh = msgb_l3(msg);
@@ -259,6 +331,8 @@
 	case GSM48_MT_MM_AUTH_RESP:
 	case GSM48_MT_MM_IMSI_DETACH_IND:
 	case GSM48_MT_MM_CM_SERV_REQ:
+		rc = gsm48_rx_mm_serv_req(msg);
+		break;
 	case GSM48_MT_MM_CM_REEST_REQ:
 		fprintf(stderr, "Unimplemented GSM 04.08 MM msg type 0x%02x\n",
 			gh->msg_type);