Merge branch 'on-waves/mgcp'
diff --git a/openbsc/include/openbsc/abis_rsl.h b/openbsc/include/openbsc/abis_rsl.h
index e6973ee..8e6774d 100644
--- a/openbsc/include/openbsc/abis_rsl.h
+++ b/openbsc/include/openbsc/abis_rsl.h
@@ -70,10 +70,11 @@
 u_int8_t lchan2chan_nr(const struct gsm_lchan *lchan);
 int rsl_release_request(struct gsm_lchan *lchan, u_int8_t link_id);
 
+int rsl_lchan_set_state(struct gsm_lchan *lchan, int);
+
 /* to be provided by external code */
 int abis_rsl_sendmsg(struct msgb *msg);
 int rsl_deact_sacch(struct gsm_lchan *lchan);
-int rsl_chan_release(struct gsm_lchan *lchan);
 
 /* BCCH related code */
 int rsl_ccch_conf_to_bs_cc_chans(int ccch_conf);
diff --git a/openbsc/include/openbsc/chan_alloc.h b/openbsc/include/openbsc/chan_alloc.h
index f564e9e..d4f5858 100644
--- a/openbsc/include/openbsc/chan_alloc.h
+++ b/openbsc/include/openbsc/chan_alloc.h
@@ -45,6 +45,7 @@
 
 /* Free a logical channel (SDCCH, TCH, ...) */
 void lchan_free(struct gsm_lchan *lchan);
+void lchan_reset(struct gsm_lchan *lchan);
 
 /* Consider releasing the channel */
 int lchan_auto_release(struct gsm_lchan *lchan);
diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h
index 8dfa588..52b82c0 100644
--- a/openbsc/include/openbsc/gsm_data.h
+++ b/openbsc/include/openbsc/gsm_data.h
@@ -73,6 +73,12 @@
 	GSM_PAGING_OOM,
 };
 
+enum bts_gprs_mode {
+	BTS_GPRS_NONE = 0,
+	BTS_GPRS_GPRS = 1,
+	BTS_GPRS_EGPRS = 2,
+};
+
 struct msgb;
 typedef int gsm_cbfn(unsigned int hooknum,
 		     unsigned int event,
@@ -250,6 +256,7 @@
 		u_int16_t bound_port;
 		u_int16_t connect_port;
 		u_int16_t conn_id;
+		u_int8_t rtp_payload;
 		u_int8_t rtp_payload2;
 		u_int8_t speech_mode;
 		struct rtp_socket *rtp_socket;
@@ -368,7 +375,6 @@
 struct gsm_bts_paging_state {
 	/* pending requests */
 	struct llist_head pending_requests;
-	struct gsm_paging_request *last_request;
 	struct gsm_bts *bts;
 
 	struct timer_list work_timer;
@@ -476,7 +482,7 @@
 
 	/* Not entirely sure how ip.access specific this is */
 	struct {
-		int enabled;
+		enum bts_gprs_mode mode;
 		struct {
 			struct gsm_nm_state nm_state;
 			u_int16_t nsei;
@@ -535,6 +541,14 @@
 		struct counter *alerted;	/* we alerted the other end */
 		struct counter *connected;/* how many calls were accepted */
 	} call;
+	struct {
+		struct counter *rf_fail;
+		struct counter *rll_err;
+	} chan;
+	struct {
+		struct counter *oml_fail;
+		struct counter *rsl_fail;
+	} bts;
 };
 
 enum gsm_auth_policy {
@@ -697,6 +711,9 @@
 enum rrlp_mode rrlp_mode_parse(const char *arg);
 const char *rrlp_mode_name(enum rrlp_mode mode);
 
+enum bts_gprs_mode bts_gprs_mode_parse(const char *arg);
+const char *bts_gprs_mode_name(enum bts_gprs_mode mode);
+
 void gsm_trx_lock_rf(struct gsm_bts_trx *trx, int locked);
 
 /* A parsed GPRS routing area */
diff --git a/openbsc/include/openbsc/ipaccess.h b/openbsc/include/openbsc/ipaccess.h
index 86248aa..f8ddfd4 100644
--- a/openbsc/include/openbsc/ipaccess.h
+++ b/openbsc/include/openbsc/ipaccess.h
@@ -53,6 +53,8 @@
 
 int ipaccess_idtag_parse(struct tlv_parsed *dec, unsigned char *buf, int len);
 
+int ipaccess_drop_oml(struct gsm_bts *bts);
+int ipaccess_drop_rsl(struct gsm_bts_trx *trx);
 
 /*
  * Firmware specific header
diff --git a/openbsc/include/openbsc/rest_octets.h b/openbsc/include/openbsc/rest_octets.h
index 4e72c0f..6d90119 100644
--- a/openbsc/include/openbsc/rest_octets.h
+++ b/openbsc/include/openbsc/rest_octets.h
@@ -71,6 +71,7 @@
 	GPRS_NMO_III	= 2,	/* no paging coordination */
 };
 
+/* TS 04.60 12.24 */
 struct gprs_cell_options {
 	enum gprs_nmo nmo;
 	/* T3168: wait for packet uplink assignment message */
@@ -79,6 +80,16 @@
 	u_int32_t t3192;	/* in milliseconds */
 	u_int32_t drx_timer_max;/* in seconds */
 	u_int32_t bs_cv_max;
+
+	u_int8_t ext_info_present;
+	struct {
+		u_int8_t egprs_supported;
+			u_int8_t use_egprs_p_ch_req;
+			u_int8_t bep_period;
+		u_int8_t pfc_supported;
+		u_int8_t dtm_supported;
+		u_int8_t bss_paging_coordination;
+	} ext_info;
 };
 
 /* TS 04.60 Table 12.9.2 */
diff --git a/openbsc/include/openbsc/rtp_proxy.h b/openbsc/include/openbsc/rtp_proxy.h
index f82711a..65b1a5f 100644
--- a/openbsc/include/openbsc/rtp_proxy.h
+++ b/openbsc/include/openbsc/rtp_proxy.h
@@ -28,6 +28,12 @@
 #include <osmocore/linuxlist.h>
 #include <osmocore/select.h>
 
+#define RTP_PT_GSM_FULL 3
+#define RTP_PT_GSM_HALF 96
+#define RTP_PT_GSM_EFR 97
+#define RTP_PT_AMR_FULL 98
+#define RTP_PT_AMR_HALF 99
+
 enum rtp_rx_action {
 	RTP_NONE,
 	RTP_PROXY,
diff --git a/openbsc/include/openbsc/vty.h b/openbsc/include/openbsc/vty.h
index 40e2191..f1b1148 100644
--- a/openbsc/include/openbsc/vty.h
+++ b/openbsc/include/openbsc/vty.h
@@ -1,6 +1,10 @@
 #ifndef OPENBSC_VTY_H
 #define OPENBSC_VTY_H
 
+struct gsm_network;
+struct vty;
+
 void openbsc_vty_add_cmds(void);
+void openbsc_vty_print_statistics(struct vty *vty, struct gsm_network *);
 
 #endif
diff --git a/openbsc/src/abis_nm.c b/openbsc/src/abis_nm.c
index 5e6e819..c78ee56 100644
--- a/openbsc/src/abis_nm.c
+++ b/openbsc/src/abis_nm.c
@@ -822,15 +822,56 @@
 	return abis_nm_sendmsg(bts, msg);
 }
 
+static int abis_nm_parse_sw_descr(const u_int8_t *sw_descr, int sw_descr_len)
+{
+	static const struct tlv_definition sw_descr_def = {
+		.def = {
+			[NM_ATT_FILE_ID] =		{ TLV_TYPE_TL16V, },
+			[NM_ATT_FILE_VERSION] =		{ TLV_TYPE_TL16V, },
+		},
+	};
+
+	u_int8_t tag;
+	u_int16_t tag_len;
+	const u_int8_t *val;
+	int ofs = 0, len;
+
+	/* Classic TLV parsing doesn't work well with SW_DESCR because of it's
+	 * nested nature and the fact you have to assume it contains only two sub
+	 * tags NM_ATT_FILE_VERSION & NM_ATT_FILE_ID to parse it */
+
+	if (sw_descr[0] != NM_ATT_SW_DESCR) {
+		DEBUGP(DNM, "SW_DESCR attribute identifier not found!\n");
+		return -1;
+	}
+	ofs += 1;
+
+	len = tlv_parse_one(&tag, &tag_len, &val,
+		&sw_descr_def, &sw_descr[ofs], sw_descr_len-ofs);
+	if (len < 0 || (tag != NM_ATT_FILE_ID)) {
+		DEBUGP(DNM, "FILE_ID attribute identifier not found!\n");
+		return -2;
+	}
+	ofs += len;
+
+	len = tlv_parse_one(&tag, &tag_len, &val,
+		&sw_descr_def, &sw_descr[ofs], sw_descr_len-ofs);
+	if (len < 0 || (tag != NM_ATT_FILE_VERSION)) {
+		DEBUGP(DNM, "FILE_VERSION attribute identifier not found!\n");
+		return -3;
+	}
+	ofs += len;
+
+	return ofs;
+}
+
 static int abis_nm_rx_sw_act_req(struct msgb *mb)
 {
 	struct abis_om_hdr *oh = msgb_l2(mb);
 	struct abis_om_fom_hdr *foh = msgb_l3(mb);
 	struct tlv_parsed tp;
 	const u_int8_t *sw_config;
-	int sw_config_len;
-	int file_id_len;
-	int ret;
+	int ret, sw_config_len, sw_descr_len;
 
 	debugp_foh(foh);
 
@@ -854,20 +895,16 @@
 		DEBUGP(DNM, "Found SW config: %s\n", hexdump(sw_config, sw_config_len));
 	}
 
-	if (sw_config[0] != NM_ATT_SW_DESCR)
-		DEBUGP(DNM, "SW_DESCR attribute identifier not found!\n");
-	if (sw_config[1] != NM_ATT_FILE_ID)
-		DEBUGP(DNM, "FILE_ID attribute identifier not found!\n");
-	file_id_len = sw_config[2] * 256 + sw_config[3];
+		/* Use the first SW_DESCR present in SW config */
+	sw_descr_len = abis_nm_parse_sw_descr(sw_config, sw_config_len);
+	if (sw_descr_len < 0)
+		return -EINVAL;
 
-	/* Assumes first SW file in list is the one to be activated */
-	/* sw_config + 4 to skip over 2 attribute ID bytes and 16-bit length field */
 	return ipacc_sw_activate(mb->trx->bts, foh->obj_class,
 				 foh->obj_inst.bts_nr,
 				 foh->obj_inst.trx_nr,
 				 foh->obj_inst.ts_nr,
-				 sw_config + 4,
-				 file_id_len);
+				 sw_config, sw_descr_len);
 }
 
 /* Receive a CHANGE_ADM_STATE_ACK, parse the TLV and update local state */
diff --git a/openbsc/src/abis_rsl.c b/openbsc/src/abis_rsl.c
index 0e572cc..53b2982 100644
--- a/openbsc/src/abis_rsl.c
+++ b/openbsc/src/abis_rsl.c
@@ -727,7 +727,6 @@
 			     link_id, 0);
 	msgb_tv_put(msg, RSL_IE_RELEASE_MODE, 0);	/* normal release */
 
-	lchan->state = LCHAN_S_REL_REQ;
 	/* FIXME: start some timer in case we don't receive a REL ACK ? */
 
 	msg->trx = lchan->ts->trx;
@@ -735,6 +734,12 @@
 	return abis_rsl_sendmsg(msg);
 }
 
+int rsl_lchan_set_state(struct gsm_lchan *lchan, int state)
+{
+	lchan->state = state;
+	return 0;
+}
+
 /* Chapter 8.4.2: Channel Activate Acknowledge */
 static int rsl_rx_chan_act_ack(struct msgb *msg)
 {
@@ -749,7 +754,7 @@
 		LOGP(DRSL, LOGL_NOTICE, "%s CHAN ACT ACK, but state %s\n",
 			gsm_lchan_name(msg->lchan),
 			gsm_lchans_name(msg->lchan->state));
-	msg->lchan->state = LCHAN_S_ACTIVE;
+	rsl_lchan_set_state(msg->lchan, LCHAN_S_ACTIVE);
 
 	dispatch_signal(SS_LCHAN, S_LCHAN_ACTIVATE_ACK, msg->lchan);
 
@@ -775,9 +780,9 @@
 		print_rsl_cause(LOGL_ERROR, cause,
 				TLVP_LEN(&tp, RSL_IE_CAUSE));
 		if (*cause != RSL_ERR_RCH_ALR_ACTV_ALLOC)
-			msg->lchan->state = LCHAN_S_NONE;
+			rsl_lchan_set_state(msg->lchan, LCHAN_S_NONE);
 	} else
-		msg->lchan->state = LCHAN_S_NONE;
+		rsl_lchan_set_state(msg->lchan, LCHAN_S_NONE);
 
 	LOGPC(DRSL, LOGL_ERROR, "\n");
 
@@ -805,6 +810,7 @@
 
 	LOGPC(DRSL, LOGL_NOTICE, "\n");
 	/* FIXME: only free it after channel release ACK */
+	counter_inc(msg->lchan->ts->trx->bts->network->stats.chan.rf_fail);
 	return rsl_rf_chan_release(msg->lchan);
 }
 
@@ -981,7 +987,7 @@
 			LOGP(DRSL, LOGL_NOTICE, "%s CHAN REL ACK but state %s\n",
 				gsm_lchan_name(msg->lchan),
 				gsm_lchans_name(msg->lchan->state));
-		msg->lchan->state = LCHAN_S_NONE;
+		rsl_lchan_set_state(msg->lchan, LCHAN_S_NONE);
 		lchan_free(msg->lchan);
 		break;
 	case RSL_MT_MODE_MODIFY_ACK:
@@ -1124,7 +1130,7 @@
 		LOGP(DRSL, LOGL_NOTICE, "%s lchan_alloc() returned channel "
 		     "in state %s\n", gsm_lchan_name(lchan),
 		     gsm_lchans_name(lchan->state));
-	lchan->state = LCHAN_S_ACT_REQ;
+	rsl_lchan_set_state(lchan, LCHAN_S_ACT_REQ);
 
 	ts_number = lchan->ts->nr;
 	arfcn = lchan->ts->trx->arfcn;
@@ -1181,6 +1187,10 @@
 	switch (rslh->data[0]) {
 	case RSL_IE_PAGING_LOAD:
 		pg_buf_space = rslh->data[1] << 8 | rslh->data[2];
+		if (is_ipaccess_bts(msg->trx->bts) && pg_buf_space == 0xffff) {
+			/* paging load below configured threshold, use 50 as default */
+			pg_buf_space = 50;
+		}
 		paging_update_buffer_space(msg->trx->bts, pg_buf_space);
 		break;
 	case RSL_IE_RACH_LOAD:
@@ -1240,8 +1250,10 @@
 
 	rll_indication(msg->lchan, rllh->link_id, BSC_RLLR_IND_ERR_IND);
 
-	if (rlm_cause[1] == RLL_CAUSE_T200_EXPIRED)
+	if (rlm_cause[1] == RLL_CAUSE_T200_EXPIRED) {
+		counter_inc(msg->lchan->ts->trx->bts->network->stats.chan.rll_err);
 		return rsl_rf_chan_release(msg->lchan);
+	}
 
 	return 0;
 }
@@ -1363,6 +1375,44 @@
 	return 0;
 }
 
+static u_int8_t ipa_rtp_pt_for_lchan(struct gsm_lchan *lchan)
+{
+	switch (lchan->tch_mode) {
+	case GSM48_CMODE_SPEECH_V1:
+		switch (lchan->type) {
+		case GSM_LCHAN_TCH_F:
+			return RTP_PT_GSM_FULL;
+		case GSM_LCHAN_TCH_H:
+			return RTP_PT_GSM_HALF;
+		default:
+			break;
+		}
+	case GSM48_CMODE_SPEECH_EFR:
+		switch (lchan->type) {
+		case GSM_LCHAN_TCH_F:
+			return RTP_PT_GSM_EFR;
+		/* there's no half-rate EFR */
+		default:
+			break;
+		}
+	case GSM48_CMODE_SPEECH_AMR:
+		switch (lchan->type) {
+		case GSM_LCHAN_TCH_F:
+			return RTP_PT_AMR_FULL;
+		case GSM_LCHAN_TCH_H:
+			return RTP_PT_AMR_HALF;
+		default:
+			break;
+		}
+	default:
+		break;
+	}
+	LOGP(DRSL, LOGL_ERROR, "Cannot determine ip.access rtp payload type for "
+		"tch_mode == 0x%02x\n & lchan_type == %d",
+		lchan->tch_mode, lchan->type);
+	return 0;
+}
+
 /* ip.access specific RSL extensions */
 static void ipac_parse_rtp(struct gsm_lchan *lchan, struct tlv_parsed *tv)
 {
@@ -1429,10 +1479,13 @@
 
 	/* 0x1- == receive-only, 0x-1 == EFR codec */
 	lchan->abis_ip.speech_mode = 0x10 | ipa_smod_s_for_lchan(lchan);
+	lchan->abis_ip.rtp_payload = ipa_rtp_pt_for_lchan(lchan);
 	msgb_tv_put(msg, RSL_IE_IPAC_SPEECH_MODE, lchan->abis_ip.speech_mode);
+	msgb_tv_put(msg, RSL_IE_IPAC_RTP_PAYLOAD, lchan->abis_ip.rtp_payload);
 
-	DEBUGP(DRSL, "%s IPAC_BIND speech_mode=0x%02x\n",
-		gsm_lchan_name(lchan), lchan->abis_ip.speech_mode);
+	DEBUGP(DRSL, "%s IPAC_BIND speech_mode=0x%02x RTP_PAYLOAD=%d\n",
+		gsm_lchan_name(lchan), lchan->abis_ip.speech_mode,
+		lchan->abis_ip.rtp_payload);
 
 	msg->trx = lchan->ts->trx;
 
@@ -1459,11 +1512,13 @@
 
 	/* 0x0- == both directions, 0x-1 == EFR codec */
 	lchan->abis_ip.speech_mode = 0x00 | ipa_smod_s_for_lchan(lchan);
+	lchan->abis_ip.rtp_payload = ipa_rtp_pt_for_lchan(lchan);
 
 	ia.s_addr = htonl(ip);
-	DEBUGP(DRSL, "%s IPAC_MDCX IP=%s PORT=%d RTP_PAYLOAD2=%d CONN_ID=%d "
-		"speech_mode=0x%02x\n", gsm_lchan_name(lchan), inet_ntoa(ia), port,
-		rtp_payload2, lchan->abis_ip.conn_id, lchan->abis_ip.speech_mode);
+	DEBUGP(DRSL, "%s IPAC_MDCX IP=%s PORT=%d RTP_PAYLOAD=%d RTP_PAYLOAD2=%d "
+		"CONN_ID=%d speech_mode=0x%02x\n", gsm_lchan_name(lchan),
+		inet_ntoa(ia), port, lchan->abis_ip.rtp_payload, rtp_payload2,
+		lchan->abis_ip.conn_id, lchan->abis_ip.speech_mode);
 
 	msgb_tv16_put(msg, RSL_IE_IPAC_CONN_ID, lchan->abis_ip.conn_id);
 	msgb_v_put(msg, RSL_IE_IPAC_REMOTE_IP);
@@ -1471,6 +1526,7 @@
 	*att_ip = ia.s_addr;
 	msgb_tv16_put(msg, RSL_IE_IPAC_REMOTE_PORT, port);
 	msgb_tv_put(msg, RSL_IE_IPAC_SPEECH_MODE, lchan->abis_ip.speech_mode);
+	msgb_tv_put(msg, RSL_IE_IPAC_RTP_PAYLOAD, lchan->abis_ip.rtp_payload);
 	if (rtp_payload2)
 		msgb_tv_put(msg, RSL_IE_IPAC_RTP_PAYLOAD2, rtp_payload2);
 	
@@ -1652,9 +1708,21 @@
 /* Entry-point where L2 RSL from BTS enters */
 int abis_rsl_rcvmsg(struct msgb *msg)
 {
-	struct abis_rsl_common_hdr *rslh = msgb_l2(msg)	;
+	struct abis_rsl_common_hdr *rslh;
 	int rc = 0;
 
+	if (!msg) {
+		DEBUGP(DRSL, "Empty RSL msg?..\n");
+		return -1;
+	}
+
+	if (msgb_l2len(msg) < sizeof(*rslh)) {
+		DEBUGP(DRSL, "Truncated RSL message with l2len: %u\n", msgb_l2len(msg));
+		return -1;
+	}
+
+	rslh = msgb_l2(msg);
+
 	switch (rslh->msg_discr & 0xfe) {
 	case ABIS_RSL_MDISC_RLL:
 		rc = abis_rsl_rx_rll(msg);
diff --git a/openbsc/src/bsc_init.c b/openbsc/src/bsc_init.c
index f343662..a39bc19 100644
--- a/openbsc/src/bsc_init.c
+++ b/openbsc/src/bsc_init.c
@@ -31,6 +31,7 @@
 #include <openbsc/system_information.h>
 #include <openbsc/paging.h>
 #include <openbsc/signal.h>
+#include <openbsc/chan_alloc.h>
 #include <osmocore/talloc.h>
 
 /* global pointer to the gsm network data structure */
@@ -377,11 +378,11 @@
 		4,	/* N3103 */
 		8,	/* N3105 */
 		15,	/* RLC CV countdown */
-	NM_ATT_IPACC_CODING_SCHEMES, 0, 2,  0x0f, 0x00,
+	NM_ATT_IPACC_CODING_SCHEMES, 0, 2,  0x0f, 0x00,	/* CS1..CS4 */
 	NM_ATT_IPACC_RLC_CFG_2, 0, 5,
-		0x00, 250,
-		0x00, 250,
-		2,	/* MCS2 */
+		0x00, 250,	/* T downlink TBF extension (0..500) */
+		0x00, 250,	/* T uplink TBF extension (0..500) */
+		2,	/* CS2 */
 #if 0
 	/* EDGE model only, breaks older models.
 	 * Should inquire the BTS capabilities */
@@ -461,7 +462,7 @@
 		break;
 	case NM_OC_GPRS_NSE:
 		bts = container_of(obj, struct gsm_bts, gprs.nse);
-		if (!bts->gprs.enabled)
+		if (bts->gprs.mode == BTS_GPRS_NONE)
 			break;
 		if (new_state->availability == 5) {
 			abis_nm_ipaccess_set_attr(bts, obj_class, bts->bts_nr,
@@ -475,7 +476,7 @@
 		break;
 	case NM_OC_GPRS_CELL:
 		bts = container_of(obj, struct gsm_bts, gprs.cell);
-		if (!bts->gprs.enabled)
+		if (bts->gprs.mode == BTS_GPRS_NONE)
 			break;
 		if (new_state->availability == 5) {
 			abis_nm_ipaccess_set_attr(bts, obj_class, bts->bts_nr,
@@ -490,7 +491,7 @@
 	case NM_OC_GPRS_NSVC:
 		nsvc = obj;
 		bts = nsvc->bts;
-		if (!bts->gprs.enabled)
+		if (bts->gprs.mode == BTS_GPRS_NONE)
 			break;
 	        /* We skip NSVC1 since we only use NSVC0 */
 		if (nsvc->id == 1)
@@ -798,7 +799,7 @@
 			DEBUGP(DRR, "SI%2u: %s\n", i, hexdump(si_tmp, rc));
 			rsl_bcch_info(trx, i, si_tmp, sizeof(si_tmp));
 		}
-		if (bts->gprs.enabled) {
+		if (bts->gprs.mode != BTS_GPRS_NONE) {
 			i = 13;
 			rc = gsm_generate_si(si_tmp, trx->bts, RSL_SYSTEM_INFO_13);
 			if (rc < 0)
@@ -885,6 +886,11 @@
 	/* patch RAC */
 	nanobts_attr_cell[3] = bts->gprs.rac;
 
+	if (bts->gprs.mode == BTS_GPRS_EGPRS) {
+		/* patch EGPRS coding schemes MCS 1..9 */
+		nanobts_attr_cell[29] = 0x8f;
+		nanobts_attr_cell[30] = 0xff;
+	}
 }
 
 static void bootstrap_rsl(struct gsm_bts_trx *trx)
@@ -899,6 +905,8 @@
 
 void input_event(int event, enum e1inp_sign_type type, struct gsm_bts_trx *trx)
 {
+	int ts_no, lchan_no;
+
 	switch (event) {
 	case EVT_E1_TEI_UP:
 		switch (type) {
@@ -913,8 +921,35 @@
 		}
 		break;
 	case EVT_E1_TEI_DN:
-		LOGP(DMI, LOGL_NOTICE, "Lost some E1 TEI link\n");
-		/* FIXME: deal with TEI or L1 link loss */
+		LOGP(DMI, LOGL_ERROR, "Lost some E1 TEI link: %d %p\n", type, trx);
+
+		if (type == E1INP_SIGN_OML)
+			counter_inc(trx->bts->network->stats.bts.oml_fail);
+		else if (type == E1INP_SIGN_RSL)
+			counter_inc(trx->bts->network->stats.bts.rsl_fail);
+
+		/*
+		 * free all allocated channels. change the nm_state so the
+		 * trx and trx_ts becomes unusable and chan_alloc.c can not
+		 * allocate from it.
+		 */
+		for (ts_no = 0; ts_no < ARRAY_SIZE(trx->ts); ++ts_no) {
+			struct gsm_bts_trx_ts *ts = &trx->ts[ts_no];
+
+			for (lchan_no = 0; lchan_no < ARRAY_SIZE(ts->lchan); ++lchan_no) {
+				if (ts->lchan[lchan_no].state != GSM_LCHAN_NONE)
+					lchan_free(&ts->lchan[lchan_no]);
+				lchan_reset(&ts->lchan[lchan_no]);
+			}
+
+			ts->nm_state.operational = 0;
+			ts->nm_state.availability = 0;
+		}
+
+		trx->nm_state.operational = 0;
+		trx->nm_state.availability = 0;
+		trx->bb_transc.nm_state.operational = 0;
+		trx->bb_transc.nm_state.availability = 0;
 		break;
 	default:
 		break;
diff --git a/openbsc/src/chan_alloc.c b/openbsc/src/chan_alloc.c
index cd48e43..107abdc 100644
--- a/openbsc/src/chan_alloc.c
+++ b/openbsc/src/chan_alloc.c
@@ -330,6 +330,20 @@
 	 * channel using it */
 }
 
+/*
+ * There was an error with the TRX and we need to forget
+ * any state so that a lchan can be allocated again after
+ * the trx is fully usable.
+ */
+void lchan_reset(struct gsm_lchan *lchan)
+{
+	bsc_del_timer(&lchan->T3101);
+
+	lchan->type = GSM_LCHAN_NONE;
+	lchan->state = LCHAN_S_NONE;
+}
+
+
 /* Consider releasing the channel now */
 int lchan_auto_release(struct gsm_lchan *lchan)
 {
@@ -348,6 +362,7 @@
 			lchan->conn.use_count);
 
 	DEBUGP(DRLL, "%s Recycling Channel\n", gsm_lchan_name(lchan));
+	rsl_lchan_set_state(lchan, LCHAN_S_REL_REQ);
 	rsl_release_request(lchan, 0);
 	return 1;
 }
diff --git a/openbsc/src/gsm_data.c b/openbsc/src/gsm_data.c
index 176367d..4d8fa17 100644
--- a/openbsc/src/gsm_data.c
+++ b/openbsc/src/gsm_data.c
@@ -280,6 +280,10 @@
 	net->stats.call.dialled = counter_alloc("net.call.dialled");
 	net->stats.call.alerted = counter_alloc("net.call.alerted");
 	net->stats.call.connected = counter_alloc("net.call.connected");
+	net->stats.chan.rf_fail = counter_alloc("net.chan.rf_fail");
+	net->stats.chan.rll_err = counter_alloc("net.chan.rll_err");
+	net->stats.bts.oml_fail = counter_alloc("net.bts.oml_fail");
+	net->stats.bts.rsl_fail = counter_alloc("net.bts.rsl_fail");
 
 	net->mncc_recv = mncc_recv;
 
@@ -498,6 +502,23 @@
 	return get_value_string(rrlp_mode_names, mode);
 }
 
+static const struct value_string bts_gprs_mode_names[] = {
+	{ BTS_GPRS_NONE,	"none" },
+	{ BTS_GPRS_GPRS,	"gprs" },
+	{ BTS_GPRS_EGPRS,	"egprs" },
+	{ 0,			NULL }
+};
+
+enum bts_gprs_mode bts_gprs_mode_parse(const char *arg)
+{
+	return get_string_value(bts_gprs_mode_names, arg);
+}
+
+const char *bts_gprs_mode_name(enum bts_gprs_mode mode)
+{
+	return get_value_string(bts_gprs_mode_names, mode);
+}
+
 struct gsm_meas_rep *lchan_next_meas_rep(struct gsm_lchan *lchan)
 {
 	struct gsm_meas_rep *meas_rep;
diff --git a/openbsc/src/handover_logic.c b/openbsc/src/handover_logic.c
index 7fb0b13..b2ffe46 100644
--- a/openbsc/src/handover_logic.c
+++ b/openbsc/src/handover_logic.c
@@ -134,6 +134,7 @@
 		return rc;
 	}
 
+	rsl_lchan_set_state(new_lchan, LCHAN_S_ACT_REQ);
 	llist_add(&ho->list, &bsc_handovers);
 	/* we continue in the SS_LCHAN handler / ho_chan_activ_ack */
 
@@ -229,7 +230,7 @@
 	/* update lchan pointer of transaction */
 	trans_lchan_change(&ho->old_lchan->conn, &new_lchan->conn);
 
-	ho->old_lchan->state = LCHAN_S_INACTIVE;
+	rsl_lchan_set_state(ho->old_lchan, LCHAN_S_INACTIVE);
 	lchan_auto_release(ho->old_lchan);
 
 	/* do something to re-route the actual speech frames ! */
diff --git a/openbsc/src/input/ipaccess.c b/openbsc/src/input/ipaccess.c
index 323540f..8a8a198 100644
--- a/openbsc/src/input/ipaccess.c
+++ b/openbsc/src/input/ipaccess.c
@@ -1,6 +1,8 @@
 /* OpenBSC Abis input driver for ip.access */
 
 /* (C) 2009 by Harald Welte <laforge@gnumonks.org>
+ * (C) 2010 by Holger Hans Peter Freyther
+ * (C) 2010 by On-Waves
  *
  * All Rights Reserved
  *
@@ -57,7 +59,7 @@
 static struct ia_e1_handle *e1h;
 
 
-#define TS1_ALLOC_SIZE	300
+#define TS1_ALLOC_SIZE	900
 
 static const u_int8_t pong[] = { 0, 1, IPAC_PROTO_IPACCESS, IPAC_MSGT_PONG };
 static const u_int8_t id_ack[] = { 0, 1, IPAC_PROTO_IPACCESS, IPAC_MSGT_ID_ACK };
@@ -234,6 +236,8 @@
 		}
 		DEBUGP(DINP, "Identified BTS %u/%u/%u\n", site_id, bts_id, trx_id);
 		if (bfd->priv_nr == PRIV_OML) {
+			/* drop any old oml connection */
+			ipaccess_drop_oml(bts);
 			bts->oml_link = e1inp_sign_link_create(&line->ts[PRIV_OML - 1],
 						  E1INP_SIGN_OML, bts->c0,
 						  bts->oml_tei, 0);
@@ -241,7 +245,18 @@
 			struct e1inp_ts *e1i_ts;
 			struct bsc_fd *newbfd;
 			struct gsm_bts_trx *trx = gsm_bts_trx_num(bts, trx_id);
-			
+
+			/* drop any old rsl connection */
+			ipaccess_drop_rsl(trx);
+
+			if (!bts->oml_link) {
+				bsc_unregister_fd(bfd);
+				close(bfd->fd);
+				bfd->fd = -1;
+				talloc_free(bfd);
+				return 0;
+			}
+
 			bfd->data = line = bts->oml_link->ts->line;
 			e1i_ts = &line->ts[PRIV_RSL + trx_id - 1];
 			newbfd = &e1i_ts->driver.ipaccess.fd;
@@ -251,19 +266,13 @@
 							E1INP_SIGN_RSL, trx,
 							trx->rsl_tei, 0);
 
-			if (newbfd->fd >= 0) {
-				LOGP(DINP, LOGL_ERROR, "BTS is still registered. Closing old connection.\n");
-				bsc_unregister_fd(newbfd);
-				close(newbfd->fd);
-				newbfd->fd = -1;
-			}
-
 			/* get rid of our old temporary bfd */
 			memcpy(newbfd, bfd, sizeof(*newbfd));
 			newbfd->priv_nr = PRIV_RSL + trx_id;
 			bsc_unregister_fd(bfd);
-			bsc_register_fd(newbfd);
+			bfd->fd = -1;
 			talloc_free(bfd);
+			bsc_register_fd(newbfd);
 		}
 		break;
 	}
@@ -328,6 +337,103 @@
 	return msg;
 }
 
+int ipaccess_drop_oml(struct gsm_bts *bts)
+{
+	struct gsm_bts_trx *trx;
+	struct e1inp_ts *ts;
+	struct e1inp_line *line;
+	struct bsc_fd *bfd;
+
+	if (!bts || !bts->oml_link)
+		return -1;
+
+	/* send OML down */
+	ts = bts->oml_link->ts;
+	line = ts->line;
+	e1inp_event(ts, EVT_E1_TEI_DN, bts->oml_link->tei, bts->oml_link->sapi);
+
+	bfd = &ts->driver.ipaccess.fd;
+	bsc_unregister_fd(bfd);
+	close(bfd->fd);
+	bfd->fd = -1;
+
+	/* clean up OML and RSL */
+	e1inp_sign_link_destroy(bts->oml_link);
+	bts->oml_link = NULL;
+	bts->ip_access.flags = 0;
+
+	/* drop all RSL connections too */
+	llist_for_each_entry(trx, &bts->trx_list, list)
+		ipaccess_drop_rsl(trx);
+
+	/* kill the E1 line now... as we have no one left to use it */
+	talloc_free(line);
+
+	return -1;
+}
+
+static int ipaccess_drop(struct e1inp_ts *ts, struct bsc_fd *bfd)
+{
+	struct e1inp_sign_link *link;
+	int bts_nr;
+
+	if (!ts) {
+		/*
+		 * If we don't have a TS this means that this is a RSL
+		 * connection but we are not past the authentication
+		 * handling yet. So we can safely delete this bfd and
+		 * wait for a reconnect.
+		 */
+		bsc_unregister_fd(bfd);
+		close(bfd->fd);
+		bfd->fd = -1;
+		talloc_free(bfd);
+		return -1;
+	}
+
+	/* attempt to find a signalling link */
+	if (ts->type == E1INP_TS_TYPE_SIGN) {
+		llist_for_each_entry(link, &ts->sign.sign_links, list) {
+			bts_nr = link->trx->bts->bts_nr;
+			/* we have issues just reconnecting RLS so we drop OML */
+			ipaccess_drop_oml(link->trx->bts);
+			return bts_nr;
+		}
+	}
+
+	/* error case */
+	LOGP(DINP, LOGL_ERROR, "Failed to find a signalling link for ts: %p\n", ts);
+	bsc_unregister_fd(bfd);
+	close(bfd->fd);
+	bfd->fd = -1;
+	return -1;
+}
+
+int ipaccess_drop_rsl(struct gsm_bts_trx *trx)
+{
+	struct bsc_fd *bfd;
+	struct e1inp_ts *ts;
+
+	if (!trx || !trx->rsl_link)
+		return -1;
+
+	/* send RSL down */
+	ts = trx->rsl_link->ts;
+	e1inp_event(ts, EVT_E1_TEI_DN, trx->rsl_link->tei, trx->rsl_link->sapi);
+
+	/* close the socket */
+	bfd = &ts->driver.ipaccess.fd;
+	bsc_unregister_fd(bfd);
+	close(bfd->fd);
+	bfd->fd = -1;
+
+	/* destroy */
+	e1inp_sign_link_destroy(trx->rsl_link);
+	trx->rsl_link = NULL;
+
+	return -1;
+}
+
 static int handle_ts1_read(struct bsc_fd *bfd)
 {
 	struct e1inp_line *line = bfd->data;
@@ -341,18 +447,12 @@
 	msg = ipaccess_read_msg(bfd, &error);
 	if (!msg) {
 		if (error == 0) {
-			link = e1inp_lookup_sign_link(e1i_ts, IPAC_PROTO_OML, 0);
-			if (link) {
-				link->trx->bts->ip_access.flags = 0;
+			int ret = ipaccess_drop(e1i_ts, bfd);
+			if (ret >= 0)
 				LOGP(DINP, LOGL_NOTICE, "BTS %u disappeared, dead socket\n",
-					link->trx->bts->nr);
-			} else
+					ret);
+			else
 				LOGP(DINP, LOGL_NOTICE, "unknown BTS disappeared, dead socket\n");
-			e1inp_event(e1i_ts, EVT_E1_TEI_DN, 0, IPAC_PROTO_RSL);
-			e1inp_event(e1i_ts, EVT_E1_TEI_DN, 0, IPAC_PROTO_OML);
-			bsc_unregister_fd(bfd);
-			close(bfd->fd);
-			bfd->fd = -1;
 		}
 		return error;
 	}
@@ -362,13 +462,8 @@
 	hh = (struct ipaccess_head *) msg->data;
 	if (hh->proto == IPAC_PROTO_IPACCESS) {
 		ret = ipaccess_rcvmsg(line, msg, bfd);
-		if (ret < 0) {
-			e1inp_event(e1i_ts, EVT_E1_TEI_DN, 0, IPAC_PROTO_RSL);
-			e1inp_event(e1i_ts, EVT_E1_TEI_DN, 0, IPAC_PROTO_OML);
-			bsc_unregister_fd(bfd);
-			close(bfd->fd);
-			bfd->fd = -1;
-		}
+		if (ret < 0)
+			ipaccess_drop(e1i_ts, bfd);
 		msgb_free(msg);
 		return ret;
 	}
@@ -475,7 +570,9 @@
 	/* set tx delay timer for next event */
 	e1i_ts->sign.tx_timer.cb = timeout_ts1_write;
 	e1i_ts->sign.tx_timer.data = e1i_ts;
-	bsc_schedule_timer(&e1i_ts->sign.tx_timer, 0, 100);
+
+	/* Reducing this might break the nanoBTS 900 init. */
+	bsc_schedule_timer(&e1i_ts->sign.tx_timer, 0, 100000);
 
 	return ret;
 }
diff --git a/openbsc/src/openbsc.cfg.nanobts b/openbsc/src/openbsc.cfg.nanobts
index a1ceaec..da0ba74 100644
--- a/openbsc/src/openbsc.cfg.nanobts
+++ b/openbsc/src/openbsc.cfg.nanobts
@@ -1,6 +1,6 @@
 !
 ! OpenBSC configuration saved from vty
-!
+!   !
 password foo
 !
 line vty
@@ -11,17 +11,52 @@
  mobile network code 1
  short name OpenBSC
  long name OpenBSC
+ auth policy closed
+ location updating reject cause 13
+ encryption a5 0
+ neci 0
+ rrlp mode none
+ mm info 1
+ handover 0
+ handover window rxlev averaging 10
+ handover window rxqual averaging 1
+ handover window rxlev neighbor averaging 10
+ handover power budget interval 6
+ handover power budget hysteresis 3
+ handover maximum distance 9999
  timer t3101 10
+ timer t3103 0
+ timer t3105 0
+ timer t3107 0
+ timer t3109 0
+ timer t3111 0
  timer t3113 60
+ timer t3115 0
+ timer t3117 0
+ timer t3119 0
+ timer t3141 0
  bts 0
   type nanobts
-  ip.access unit_id 1801 0
-  band GSM1800
+  band DCS1800
+  cell_identity 0
   location_area_code 1
   training_sequence_code 7
   base_station_id_code 63
+  ms max power 15
+  cell reselection hysteresis 4
+  rxlev access min 0
+  channel allocator ascending
+  rach tx integer 9
+  rach max transmission 7
+  ip.access unit_id 1801 0
+  oml ip.access stream_id 255
+  gprs mode none
   trx 0
+   rf_locked 0
    arfcn 514
+   nominal power 23
+   max_power_red 20
+   rsl e1 tei 0
     timeslot 0
      phys_chan_config CCCH+SDCCH4
     timeslot 1
diff --git a/openbsc/src/openbsc.cfg.nanobts.multitrx b/openbsc/src/openbsc.cfg.nanobts.multitrx
new file mode 100644
index 0000000..d9fb54b
--- /dev/null
+++ b/openbsc/src/openbsc.cfg.nanobts.multitrx
@@ -0,0 +1,97 @@
+!
+! OpenBSC configuration saved from vty
+!   !
+password foo
+!
+line vty
+ no login
+!
+network
+ network country code 1
+ mobile network code 1
+ short name OpenBSC
+ long name OpenBSC
+ auth policy closed
+ location updating reject cause 13
+ encryption a5 0
+ neci 0
+ rrlp mode none
+ mm info 0
+ handover 0
+ handover window rxlev averaging 10
+ handover window rxqual averaging 1
+ handover window rxlev neighbor averaging 10
+ handover power budget interval 6
+ handover power budget hysteresis 3
+ handover maximum distance 9999
+ timer t3101 10
+ timer t3103 0
+ timer t3105 0
+ timer t3107 0
+ timer t3109 0
+ timer t3111 0
+ timer t3113 60
+ timer t3115 0
+ timer t3117 0
+ timer t3119 0
+ timer t3141 0
+ bts 0
+  type nanobts
+  band DCS1800
+  cell_identity 0
+  location_area_code 1
+  training_sequence_code 7
+  base_station_id_code 63
+  ms max power 15
+  cell reselection hysteresis 4
+  rxlev access min 0
+  channel allocator ascending
+  rach tx integer 9
+  rach max transmission 7
+  ip.access unit_id 1800 0
+  oml ip.access stream_id 255
+  gprs mode none
+  trx 0
+   rf_locked 0
+   arfcn 871
+   nominal power 23
+   max_power_red 0
+   rsl e1 tei 0
+    timeslot 0
+     phys_chan_config CCCH+SDCCH4
+    timeslot 1
+     phys_chan_config SDCCH8
+    timeslot 2
+     phys_chan_config TCH/F
+    timeslot 3
+     phys_chan_config TCH/F
+    timeslot 4
+     phys_chan_config TCH/F
+    timeslot 5
+     phys_chan_config TCH/F
+    timeslot 6
+     phys_chan_config TCH/F
+    timeslot 7
+     phys_chan_config TCH/F
+  trx 1
+   rf_locked 0
+   arfcn 873
+   nominal power 23
+   max_power_red 0
+   rsl e1 tei 0
+    timeslot 0
+     phys_chan_config CCCH+SDCCH4
+    timeslot 1
+     phys_chan_config SDCCH8
+    timeslot 2
+     phys_chan_config TCH/F
+    timeslot 3
+     phys_chan_config TCH/F
+    timeslot 4
+     phys_chan_config TCH/F
+    timeslot 5
+     phys_chan_config TCH/F
+    timeslot 6
+     phys_chan_config TCH/F
+    timeslot 7
+     phys_chan_config TCH/F
diff --git a/openbsc/src/paging.c b/openbsc/src/paging.c
index 7c3750d..314d3d1 100644
--- a/openbsc/src/paging.c
+++ b/openbsc/src/paging.c
@@ -45,6 +45,7 @@
 #include <openbsc/signal.h>
 #include <openbsc/abis_rsl.h>
 #include <openbsc/gsm_data.h>
+#include <openbsc/chan_alloc.h>
 
 void *tall_paging_ctx;
 
@@ -70,14 +71,6 @@
 static void paging_remove_request(struct gsm_bts_paging_state *paging_bts,
 				struct gsm_paging_request *to_be_deleted)
 {
-	/* Update the last_request if that is necessary */
-	if (to_be_deleted == paging_bts->last_request) {
-		paging_bts->last_request =
-			(struct gsm_paging_request *)paging_bts->last_request->entry.next;
-		if (&to_be_deleted->entry == &paging_bts->pending_requests)
-			paging_bts->last_request = NULL;
-	}
-
 	bsc_del_timer(&to_be_deleted->T3113);
 	llist_del(&to_be_deleted->entry);
 	subscr_put(to_be_deleted->subscr);
@@ -90,7 +83,7 @@
 	unsigned int mi_len;
 	unsigned int page_group;
 
-	DEBUGP(DPAG, "Going to send paging commands: imsi: '%s' tmsi: '0x%x'\n",
+	LOGP(DPAG, LOGL_INFO, "Going to send paging commands: imsi: '%s' tmsi: '0x%x'\n",
 		request->subscr->imsi, request->subscr->tmsi);
 
 	if (request->subscr->tmsi == GSM_RESERVED_TMSI)
@@ -103,14 +96,6 @@
 			request->chan_type);
 }
 
-static void paging_move_to_next(struct gsm_bts_paging_state *paging_bts)
-{
-	paging_bts->last_request =
-		(struct gsm_paging_request *)paging_bts->last_request->entry.next;
-	if (&paging_bts->last_request->entry == &paging_bts->pending_requests)
-		paging_bts->last_request = NULL;
-}
-
 /*
  * This is kicked by the periodic PAGING LOAD Indicator
  * coming from abis_rsl.c
@@ -128,17 +113,26 @@
 	 * return then.
 	 */
 	if (llist_empty(&paging_bts->pending_requests)) {
-		paging_bts->last_request = NULL;
 		/* since the list is empty, no need to reschedule the timer */
 		return;
 	}
 
-	if (!paging_bts->last_request)
-		paging_bts->last_request =
-			(struct gsm_paging_request *)paging_bts->pending_requests.next;
+	/*
+	 * In case the BTS does not provide us with load indication just fill
+	 * up our slots for this round. We should be able to page 20 subscribers
+	 * every two seconds. So we will just give the BTS some extra credit.
+	 * We will have to see how often we run out of this credit, so we might
+	 * need a low watermark and then add credit or give 20 every run when
+	 * the bts sets an option for that.
+	 */
+	if (paging_bts->available_slots == 0) {
+		LOGP(DPAG, LOGL_NOTICE, "No slots available on bts nr %d\n",
+		     paging_bts->bts->nr);
+		paging_bts->available_slots = 20;
+	}
 
-	assert(paging_bts->last_request);
-	initial_request = paging_bts->last_request;
+	initial_request = llist_entry(paging_bts->pending_requests.next,
+				      struct gsm_paging_request, entry);
 	current_request = initial_request;
 
 	do {
@@ -146,21 +140,17 @@
 		page_ms(current_request);
 		paging_bts->available_slots--;
 
-		/*
-		 * move to the next item. We might wrap around
-		 * this means last_request will be NULL and we just
-		 * call paging_page_to_next again. It it guranteed
-		 * that the list is not empty.
-		 */
-		paging_move_to_next(paging_bts);
-		if (!paging_bts->last_request)
-			paging_bts->last_request =
-				(struct gsm_paging_request *)paging_bts->pending_requests.next;
-		current_request = paging_bts->last_request;
+		/* take the current and add it to the back */
+		llist_del(&current_request->entry);
+		llist_add_tail(&current_request->entry, &paging_bts->pending_requests);
+
+		/* take the next request */
+		current_request = llist_entry(paging_bts->pending_requests.next,
+					      struct gsm_paging_request, entry);
 	} while (paging_bts->available_slots > 0
 		    &&  initial_request != current_request);
 
-	bsc_schedule_timer(&paging_bts->work_timer, 1, 0);
+	bsc_schedule_timer(&paging_bts->work_timer, 2, 0);
 }
 
 static void paging_worker(void *data)
@@ -178,7 +168,7 @@
 	bts->paging.work_timer.data = &bts->paging;
 
 	/* Large number, until we get a proper message */
-	bts->paging.available_slots = 100;
+	bts->paging.available_slots = 20;
 }
 
 static int paging_pending_request(struct gsm_bts_paging_state *bts,
@@ -200,7 +190,7 @@
 	void *cbfn_param;
 	gsm_cbfn *cbfn;
 
-	DEBUGP(DPAG, "T3113 expired for request %p (%s)\n",
+	LOGP(DPAG, LOGL_INFO, "T3113 expired for request %p (%s)\n",
 		req, req->subscr->imsi);
 	
 	sig_data.subscr = req->subscr;
@@ -208,11 +198,11 @@
 	sig_data.lchan	= NULL;
 
 	/* must be destroyed before calling cbfn, to prevent double free */
+	counter_inc(req->bts->network->stats.paging.expired);
 	cbfn_param = req->cbfn_param;
 	cbfn = req->cbfn;
 	paging_remove_request(&req->bts->paging, req);
 
-	counter_inc(req->bts->network->stats.paging.expired);
 
 	dispatch_signal(SS_PAGING, S_PAGING_EXPIRED, &sig_data);
 	if (cbfn)
@@ -227,11 +217,11 @@
 	struct gsm_paging_request *req;
 
 	if (paging_pending_request(bts_entry, subscr)) {
-		DEBUGP(DPAG, "Paging request already pending\n");
+		LOGP(DPAG, LOGL_INFO, "Paging request already pending for %s\n", subscr->imsi);
 		return -EEXIST;
 	}
 
-	DEBUGP(DPAG, "Start paging of subscriber %llu on bts %d.\n",
+	LOGP(DPAG, LOGL_DEBUG, "Start paging of subscriber %llu on bts %d.\n",
 		subscr->id, bts->nr);
 	req = talloc_zero(tall_paging_ctx, struct gsm_paging_request);
 	req->subscr = subscr_get(subscr);
@@ -245,7 +235,7 @@
 	llist_add_tail(&req->entry, &bts_entry->pending_requests);
 
 	if (!bsc_timer_pending(&bts_entry->work_timer))
-		bsc_schedule_timer(&bts_entry->work_timer, 1, 0);
+		bsc_schedule_timer(&bts_entry->work_timer, 2, 0);
 
 	return 0;
 }
@@ -296,11 +286,11 @@
 				 entry) {
 		if (req->subscr == subscr) {
 			if (lchan && req->cbfn) {
-				DEBUGP(DPAG, "Stop paging on bts %d, calling cbfn.\n", bts->nr);
+				LOGP(DPAG, LOGL_DEBUG, "Stop paging on bts %d, calling cbfn.\n", bts->nr);
 				req->cbfn(GSM_HOOK_RR_PAGING, GSM_PAGING_SUCCEEDED,
 					  NULL, lchan, req->cbfn_param);
 			} else
-				DEBUGP(DPAG, "Stop paging on bts %d silently.\n", bts->nr);
+				LOGP(DPAG, LOGL_DEBUG, "Stop paging on bts %d silently.\n", bts->nr);
 			paging_remove_request(&bts->paging, req);
 			break;
 		}
diff --git a/openbsc/src/rest_octets.c b/openbsc/src/rest_octets.c
index 16996ce..039d2c8 100644
--- a/openbsc/src/rest_octets.c
+++ b/openbsc/src/rest_octets.c
@@ -133,6 +133,7 @@
 			     const struct gsm48_lsa_params *lsa_params)
 {
 	/* FIXME */
+	return -1;
 }
 
 /* Generate SI4 Rest Octets (Chapter 10.5.2.35) */
@@ -318,8 +319,31 @@
 	/* hard-code no PAN_{DEC,INC,MAX} */
 	bitvec_set_bit(bv, 0);
 
-	/* no extension information (EDGE) */
-	bitvec_set_bit(bv, 0);
+	if (!gco->ext_info_present) {
+		/* no extension information */
+		bitvec_set_bit(bv, 0);
+	} else {
+		/* extension information */
+		bitvec_set_bit(bv, 1);
+		if (!gco->ext_info.egprs_supported) {
+			/* 6bit length of extension */
+			bitvec_set_uint(bv, (1 + 3)-1, 6);
+			/* EGPRS supported in the cell */
+			bitvec_set_bit(bv, 0);
+		} else {
+			/* 6bit length of extension */
+			bitvec_set_uint(bv, (1 + 5 + 3)-1, 6);
+			/* EGPRS supported in the cell */
+			bitvec_set_bit(bv, 1);
+			/* 1bit EGPRS PACKET CHANNEL REQUEST */
+			bitvec_set_bit(bv, gco->ext_info.use_egprs_p_ch_req);
+			/* 4bit BEP PERIOD */
+			bitvec_set_uint(bv, gco->ext_info.bep_period, 4);
+		}
+		bitvec_set_bit(bv, gco->ext_info.pfc_supported);
+		bitvec_set_bit(bv, gco->ext_info.dtm_supported);
+		bitvec_set_bit(bv, gco->ext_info.bss_paging_coordination);
+	}
 
 	return 0;
 }
@@ -334,7 +358,7 @@
 	bitvec_set_uint(bv, pcp->n_avg_i, 4);
 }
 
-/* Generate SI13 Rest Octests (Chapter 10.5.2.37b) */
+/* Generate SI13 Rest Octests (04.08 Chapter 10.5.2.37b) */
 int rest_octets_si13(u_int8_t *data, const struct gsm48_si13_info *si13)
 {
 	struct bitvec bv;
@@ -390,6 +414,11 @@
 				break;
 			}
 		}
+		/* 3GPP TS 44.018 Release 6 / 10.5.2.37b */
+		bitvec_set_bit(&bv, H);	/* added Release 99 */
+		/* claim our SGSN is compatible with Release 99, as EDGE and EGPRS
+		 * was only added in this Release */
+		bitvec_set_bit(&bv, 1);
 	}
 	bitvec_spare_padding(&bv, (bv.data_len*8)-1);
 	return bv.data_len;
diff --git a/openbsc/src/rtp_proxy.c b/openbsc/src/rtp_proxy.c
index 375204e..924173d 100644
--- a/openbsc/src/rtp_proxy.c
+++ b/openbsc/src/rtp_proxy.c
@@ -91,9 +91,6 @@
 
 #define RTP_VERSION	2
 
-#define RTP_PT_GSM_FULL	3
-#define RTP_PT_GSM_EFR	97
-
 /* decode an rtp frame and create a new buffer with payload */
 static int rtp_decode(struct msgb *msg, u_int32_t callref, struct msgb **data)
 {
diff --git a/openbsc/src/system_information.c b/openbsc/src/system_information.c
index 3f9d609..3bd833a 100644
--- a/openbsc/src/system_information.c
+++ b/openbsc/src/system_information.c
@@ -402,6 +402,16 @@
 		.t3192		= 500,
 		.drx_timer_max	= 3,
 		.bs_cv_max	= 15,
+		.ext_info_present = 0,
+		.ext_info = {
+			/* The values below are just guesses ! */
+			.egprs_supported = 0,
+			.use_egprs_p_ch_req = 1,
+			.bep_period = 4,
+			.pfc_supported = 0,
+			.dtm_supported = 0,
+			.bss_paging_coordination = 0,
+		},
 	},
 	.pwr_ctrl_pars = {
 		.alpha		= 10,	/* a = 1.0 */
@@ -448,7 +458,18 @@
 
 int gsm_generate_si(u_int8_t *output, struct gsm_bts *bts, int type)
 {
-	si_info.gprs_ind.present = bts->gprs.enabled;
+	switch (bts->gprs.mode) {
+	case BTS_GPRS_EGPRS:
+		si13_default.cell_opts.ext_info_present = 1;
+		si13_default.cell_opts.ext_info.egprs_supported = 1;
+		/* fallthrough */
+	case BTS_GPRS_GPRS:
+		si_info.gprs_ind.present = 1;
+		break;
+	case BTS_GPRS_NONE:
+		si_info.gprs_ind.present = 0;
+		break;
+	}
 
 	switch (type) {
 	case RSL_SYSTEM_INFO_1:
diff --git a/openbsc/src/vty_interface.c b/openbsc/src/vty_interface.c
index b5bdbc8..dd35372 100644
--- a/openbsc/src/vty_interface.c
+++ b/openbsc/src/vty_interface.c
@@ -266,6 +266,9 @@
 	int i;
 
 	vty_out(vty, "  trx %u%s", trx->nr, VTY_NEWLINE);
+	vty_out(vty, "   rf_locked %u%s",
+		trx->nm_state.administrative == NM_STATE_LOCKED ? 1 : 0,
+		VTY_NEWLINE);
 	vty_out(vty, "   arfcn %u%s", trx->arfcn, VTY_NEWLINE);
 	vty_out(vty, "   nominal power %u%s", trx->nominal_power, VTY_NEWLINE);
 	vty_out(vty, "   max_power_red %u%s", trx->max_power_red, VTY_NEWLINE);
@@ -315,8 +318,9 @@
 		config_write_e1_link(vty, &bts->oml_e1_link, "  oml ");
 		vty_out(vty, "  oml e1 tei %u%s", bts->oml_tei, VTY_NEWLINE);
 	}
-	vty_out(vty, "  gprs enabled %u%s", bts->gprs.enabled, VTY_NEWLINE);
-	if (bts->gprs.enabled) {
+	vty_out(vty, "  gprs mode %s%s", bts_gprs_mode_name(bts->gprs.mode),
+		VTY_NEWLINE);
+	if (bts->gprs.mode != BTS_GPRS_NONE) {
 		vty_out(vty, "  gprs routing area %u%s", bts->gprs.rac,
 			VTY_NEWLINE);
 		vty_out(vty, "  gprs cell bvci %u%s", bts->gprs.cell.bvci,
@@ -540,10 +544,6 @@
 
 static void subscr_dump_vty(struct vty *vty, struct gsm_subscriber *subscr)
 {
-	int rc;
-	struct gsm_auth_info ainfo;
-	struct gsm_auth_tuple atuple;
-
 	vty_out(vty, "    ID: %llu, Authorized: %d%s", subscr->id,
 		subscr->authorized, VTY_NEWLINE);
 	if (subscr->name)
@@ -879,46 +879,6 @@
 	return CMD_SUCCESS;
 }
 
-DEFUN(show_stats,
-      show_stats_cmd,
-      "show statistics",
-	SHOW_STR "Display network statistics\n")
-{
-	struct gsm_network *net = gsmnet;
-
-	vty_out(vty, "Channel Requests        : %lu total, %lu no channel%s",
-		counter_get(net->stats.chreq.total),
-		counter_get(net->stats.chreq.no_channel), VTY_NEWLINE);
-	vty_out(vty, "Location Update         : %lu attach, %lu normal, %lu periodic%s",
-		counter_get(net->stats.loc_upd_type.attach),
-		counter_get(net->stats.loc_upd_type.normal),
-		counter_get(net->stats.loc_upd_type.periodic), VTY_NEWLINE);
-	vty_out(vty, "IMSI Detach Indications : %lu%s",
-		counter_get(net->stats.loc_upd_type.detach), VTY_NEWLINE);
-	vty_out(vty, "Location Update Response: %lu accept, %lu reject%s",
-		counter_get(net->stats.loc_upd_resp.accept),
-		counter_get(net->stats.loc_upd_resp.reject), VTY_NEWLINE);
-	vty_out(vty, "Paging                  : %lu attempted, %lu complete, %lu expired%s",
-		counter_get(net->stats.paging.attempted),
-		counter_get(net->stats.paging.completed),
-		counter_get(net->stats.paging.expired), VTY_NEWLINE);
-	vty_out(vty, "Handover                : %lu attempted, %lu no_channel, %lu timeout, "
-		"%lu completed, %lu failed%s",
-		counter_get(net->stats.handover.attempted),
-		counter_get(net->stats.handover.no_channel),
-		counter_get(net->stats.handover.timeout),
-		counter_get(net->stats.handover.completed),
-		counter_get(net->stats.handover.failed), VTY_NEWLINE);
-	vty_out(vty, "SMS MO                  : %lu submitted, %lu no receiver%s",
-		counter_get(net->stats.sms.submitted),
-		counter_get(net->stats.sms.no_receiver), VTY_NEWLINE);
-	vty_out(vty, "SMS MT                  : %lu delivered, %lu no memory, %lu other error%s",
-		counter_get(net->stats.sms.delivered),
-		counter_get(net->stats.sms.rp_err_mem),
-		counter_get(net->stats.sms.rp_err_other), VTY_NEWLINE);
-	return CMD_SUCCESS;
-}
-
 DEFUN(cfg_net,
       cfg_net_cmd,
       "network",
@@ -1433,12 +1393,12 @@
 }
 
 DEFUN(cfg_bts_prs_bvci, cfg_bts_gprs_bvci_cmd,
-	"gprs cell bvci <0-65535>",
+	"gprs cell bvci <2-65535>",
 	"GPRS BSSGP VC Identifier")
 {
 	struct gsm_bts *bts = vty->index;
 
-	if (!bts->gprs.enabled) {
+	if (bts->gprs.mode == BTS_GPRS_NONE) {
 		vty_out(vty, "%% GPRS not enabled on this BTS%s", VTY_NEWLINE);
 		return CMD_WARNING;
 	}
@@ -1454,7 +1414,7 @@
 {
 	struct gsm_bts *bts = vty->index;
 
-	if (!bts->gprs.enabled) {
+	if (bts->gprs.mode == BTS_GPRS_NONE) {
 		vty_out(vty, "%% GPRS not enabled on this BTS%s", VTY_NEWLINE);
 		return CMD_WARNING;
 	}
@@ -1472,7 +1432,7 @@
 	struct gsm_bts *bts = vty->index;
 	int idx = atoi(argv[0]);
 
-	if (!bts->gprs.enabled) {
+	if (bts->gprs.mode == BTS_GPRS_NONE) {
 		vty_out(vty, "%% GPRS not enabled on this BTS%s", VTY_NEWLINE);
 		return CMD_WARNING;
 	}
@@ -1489,7 +1449,7 @@
 	struct gsm_bts *bts = vty->index;
 	int idx = atoi(argv[0]);
 
-	if (!bts->gprs.enabled) {
+	if (bts->gprs.mode == BTS_GPRS_NONE) {
 		vty_out(vty, "%% GPRS not enabled on this BTS%s", VTY_NEWLINE);
 		return CMD_WARNING;
 	}
@@ -1506,7 +1466,7 @@
 	struct gsm_bts *bts = vty->index;
 	int idx = atoi(argv[0]);
 
-	if (!bts->gprs.enabled) {
+	if (bts->gprs.mode == BTS_GPRS_NONE) {
 		vty_out(vty, "%% GPRS not enabled on this BTS%s", VTY_NEWLINE);
 		return CMD_WARNING;
 	}
@@ -1524,7 +1484,7 @@
 	int idx = atoi(argv[0]);
 	struct in_addr ia;
 
-	if (!bts->gprs.enabled) {
+	if (bts->gprs.mode == BTS_GPRS_NONE) {
 		vty_out(vty, "%% GPRS not enabled on this BTS%s", VTY_NEWLINE);
 		return CMD_WARNING;
 	}
@@ -1541,7 +1501,7 @@
 {
 	struct gsm_bts *bts = vty->index;
 
-	if (!bts->gprs.enabled) {
+	if (bts->gprs.mode == BTS_GPRS_NONE) {
 		vty_out(vty, "%% GPRS not enabled on this BTS%s", VTY_NEWLINE);
 		return CMD_WARNING;
 	}
@@ -1551,13 +1511,13 @@
 	return CMD_SUCCESS;
 }
 
-DEFUN(cfg_bts_gprs_enabled, cfg_bts_gprs_enabled_cmd,
-	"gprs enabled <0-1>",
-	"GPRS Enabled on this BTS")
+DEFUN(cfg_bts_gprs_mode, cfg_bts_gprs_mode_cmd,
+	"gprs mode (none|gprs|egprs)",
+	"GPRS Mode for this BTS")
 {
 	struct gsm_bts *bts = vty->index;
 
-	bts->gprs.enabled = atoi(argv[0]);
+	bts->gprs.mode = bts_gprs_mode_parse(argv[0]);
 
 	return CMD_SUCCESS;
 }
@@ -1740,6 +1700,8 @@
 	return CMD_SUCCESS;
 }
 
+extern int bsc_vty_init_extra(struct gsm_network *net);
+
 int bsc_vty_init(struct gsm_network *net)
 {
 	gsmnet = net;
@@ -1758,7 +1720,6 @@
 	install_element(VIEW_NODE, &show_e1ts_cmd);
 
 	install_element(VIEW_NODE, &show_paging_cmd);
-	install_element(VIEW_NODE, &show_stats_cmd);
 
 	openbsc_vty_add_cmds();
 
@@ -1815,7 +1776,7 @@
 	install_element(BTS_NODE, &cfg_bts_per_loc_upd_cmd);
 	install_element(BTS_NODE, &cfg_bts_cell_resel_hyst_cmd);
 	install_element(BTS_NODE, &cfg_bts_rxlev_acc_min_cmd);
-	install_element(BTS_NODE, &cfg_bts_gprs_enabled_cmd);
+	install_element(BTS_NODE, &cfg_bts_gprs_mode_cmd);
 	install_element(BTS_NODE, &cfg_bts_gprs_rac_cmd);
 	install_element(BTS_NODE, &cfg_bts_gprs_bvci_cmd);
 	install_element(BTS_NODE, &cfg_bts_gprs_nsei_cmd);
diff --git a/openbsc/src/vty_interface_cmds.c b/openbsc/src/vty_interface_cmds.c
index d494584..671351e 100644
--- a/openbsc/src/vty_interface_cmds.c
+++ b/openbsc/src/vty_interface_cmds.c
@@ -228,6 +228,23 @@
 	return CMD_SUCCESS;
 }
 
+void openbsc_vty_print_statistics(struct vty *vty, struct gsm_network *net)
+{
+	vty_out(vty, "Channel Requests        : %lu total, %lu no channel%s",
+		counter_get(net->stats.chreq.total),
+		counter_get(net->stats.chreq.no_channel), VTY_NEWLINE);
+	vty_out(vty, "Channel Failures        : %lu rf_failures, %lu rll failures%s",
+		counter_get(net->stats.chan.rf_fail),
+		counter_get(net->stats.chan.rll_err), VTY_NEWLINE);
+	vty_out(vty, "Paging                  : %lu attempted, %lu complete, %lu expired%s",
+		counter_get(net->stats.paging.attempted),
+		counter_get(net->stats.paging.completed),
+		counter_get(net->stats.paging.expired), VTY_NEWLINE);
+	vty_out(vty, "BTS failures            : %lu OML, %lu RSL%s",
+		counter_get(net->stats.bts.oml_fail),
+		counter_get(net->stats.bts.rsl_fail), VTY_NEWLINE);
+}
+
 void openbsc_vty_add_cmds()
 {
 	install_element(VIEW_NODE, &enable_logging_cmd);
diff --git a/openbsc/src/vty_interface_layer3.c b/openbsc/src/vty_interface_layer3.c
index b824c3d..5e30982 100644
--- a/openbsc/src/vty_interface_layer3.c
+++ b/openbsc/src/vty_interface_layer3.c
@@ -41,6 +41,7 @@
 #include <osmocore/talloc.h>
 #include <openbsc/signal.h>
 #include <openbsc/debug.h>
+#include <openbsc/vty.h>
 
 static struct gsm_network *gsmnet;
 
@@ -502,6 +503,41 @@
 	return 0;
 }
 
+DEFUN(show_stats,
+      show_stats_cmd,
+      "show statistics",
+	SHOW_STR "Display network statistics\n")
+{
+	struct gsm_network *net = gsmnet;
+
+	openbsc_vty_print_statistics(vty, net);
+	vty_out(vty, "Location Update         : %lu attach, %lu normal, %lu periodic%s",
+		counter_get(net->stats.loc_upd_type.attach),
+		counter_get(net->stats.loc_upd_type.normal),
+		counter_get(net->stats.loc_upd_type.periodic), VTY_NEWLINE);
+	vty_out(vty, "IMSI Detach Indications : %lu%s",
+		counter_get(net->stats.loc_upd_type.detach), VTY_NEWLINE);
+	vty_out(vty, "Location Update Response: %lu accept, %lu reject%s",
+		counter_get(net->stats.loc_upd_resp.accept),
+		counter_get(net->stats.loc_upd_resp.reject), VTY_NEWLINE);
+	vty_out(vty, "Handover                : %lu attempted, %lu no_channel, %lu timeout, "
+		"%lu completed, %lu failed%s",
+		counter_get(net->stats.handover.attempted),
+		counter_get(net->stats.handover.no_channel),
+		counter_get(net->stats.handover.timeout),
+		counter_get(net->stats.handover.completed),
+		counter_get(net->stats.handover.failed), VTY_NEWLINE);
+	vty_out(vty, "SMS MO                  : %lu submitted, %lu no receiver%s",
+		counter_get(net->stats.sms.submitted),
+		counter_get(net->stats.sms.no_receiver), VTY_NEWLINE);
+	vty_out(vty, "SMS MT                  : %lu delivered, %lu no memory, %lu other error%s",
+		counter_get(net->stats.sms.delivered),
+		counter_get(net->stats.sms.rp_err_mem),
+		counter_get(net->stats.sms.rp_err_other), VTY_NEWLINE);
+	return CMD_SUCCESS;
+}
+
+
 int bsc_vty_init_extra(struct gsm_network *net)
 {
 	gsmnet = net;
@@ -517,6 +553,7 @@
 	install_element(VIEW_NODE, &subscriber_silent_sms_cmd);
 	install_element(VIEW_NODE, &subscriber_silent_call_start_cmd);
 	install_element(VIEW_NODE, &subscriber_silent_call_stop_cmd);
+	install_element(VIEW_NODE, &show_stats_cmd);
 
 	install_element(CONFIG_NODE, &cfg_subscr_cmd);
 	install_node(&subscr_node, dummy_config_write);
diff --git a/wireshark/abis_oml.patch b/wireshark/abis_oml.patch
index 9f06b4d..4013211 100644
--- a/wireshark/abis_oml.patch
+++ b/wireshark/abis_oml.patch
@@ -1,8 +1,21 @@
-Index: wireshark/epan/dissectors/Makefile.common
-===================================================================
---- wireshark.orig/epan/dissectors/Makefile.common
-+++ wireshark/epan/dissectors/Makefile.common
-@@ -474,6 +474,7 @@
+From 5857518be87641fdab45e593bc9fd5ef5595e619 Mon Sep 17 00:00:00 2001
+From: Holger Hans Peter Freyther <zecke@selfish.org>
+Date: Mon, 19 Apr 2010 13:23:51 +0800
+Subject: [PATCH 1/2] Add the Abis OML patch.
+
+---
+ epan/dissectors/Makefile.common       |    1 +
+ epan/dissectors/packet-gsm_abis_oml.c | 1382 +++++++++++++++++++++++++++++++++
+ epan/dissectors/packet-gsm_abis_oml.h |  787 +++++++++++++++++++
+ 3 files changed, 2170 insertions(+), 0 deletions(-)
+ create mode 100644 epan/dissectors/packet-gsm_abis_oml.c
+ create mode 100644 epan/dissectors/packet-gsm_abis_oml.h
+
+diff --git a/epan/dissectors/Makefile.common b/epan/dissectors/Makefile.common
+index dbc3726..98dcdc3 100644
+--- a/epan/dissectors/Makefile.common
++++ b/epan/dissectors/Makefile.common
+@@ -481,6 +481,7 @@ DISSECTOR_SRC = \
  	packet-gsm_a_gm.c		\
  	packet-gsm_a_rp.c		\
  	packet-gsm_a_rr.c	\
@@ -12,7 +25,7 @@
  	packet-gsm_bssmap_le.c	\
 diff --git a/epan/dissectors/packet-gsm_abis_oml.c b/epan/dissectors/packet-gsm_abis_oml.c
 new file mode 100644
-index 0000000..2de9dca
+index 0000000..fa46ab5
 --- /dev/null
 +++ b/epan/dissectors/packet-gsm_abis_oml.c
 @@ -0,0 +1,1382 @@
@@ -1398,11 +1411,12 @@
 +	abis_oml_handle = create_dissector_handle(dissect_abis_oml, proto_abis_oml);
 +	dissector_add("lapd.gsm.sapi", LAPD_GSM_SAPI_OM_PROC, abis_oml_handle);
 +}
-Index: wireshark/epan/dissectors/packet-gsm_abis_oml.h
-===================================================================
+diff --git a/epan/dissectors/packet-gsm_abis_oml.h b/epan/dissectors/packet-gsm_abis_oml.h
+new file mode 100644
+index 0000000..d523e96
 --- /dev/null
-+++ wireshark/epan/dissectors/packet-gsm_abis_oml.h
-@@ -0,0 +1,786 @@
++++ b/epan/dissectors/packet-gsm_abis_oml.h
+@@ -0,0 +1,787 @@
 +/* GSM Network Management messages on the A-bis interface
 + * 3GPP TS 12.21 version 8.0.0 Release 1999 / ETSI TS 100 623 V8.0.0 */
 +
@@ -2190,3 +2204,6 @@
 +};
 +
 +#endif /* _NM_H */
+-- 
+1.7.0.1
+
diff --git a/wireshark/rsl-ipaccess.patch b/wireshark/rsl-ipaccess.patch
index 36c09c5..29220b8 100644
--- a/wireshark/rsl-ipaccess.patch
+++ b/wireshark/rsl-ipaccess.patch
@@ -1,16 +1,25 @@
-Index: wireshark/epan/dissectors/packet-rsl.c
-===================================================================
---- wireshark.orig/epan/dissectors/packet-rsl.c	2009-10-21 23:03:41.000000000 +0200
-+++ wireshark/epan/dissectors/packet-rsl.c	2009-10-22 10:02:51.000000000 +0200
+From 8f35d623641dbba90e6186604c11e892bf515ecc Mon Sep 17 00:00:00 2001
+From: Holger Hans Peter Freyther <zecke@selfish.org>
+Date: Mon, 19 Apr 2010 13:32:58 +0800
+Subject: [PATCH 2/2] RSL patch
+
+---
+ epan/dissectors/packet-rsl.c |  522 +++++++++++++++++++++++++++++++++++++++++-
+ 1 files changed, 515 insertions(+), 7 deletions(-)
+
+diff --git a/epan/dissectors/packet-rsl.c b/epan/dissectors/packet-rsl.c
+index b10a671..a455cf3 100644
+--- a/epan/dissectors/packet-rsl.c
++++ b/epan/dissectors/packet-rsl.c
 @@ -2,6 +2,7 @@
   * Routines for Radio Signalling Link (RSL) dissection.
   *
   * Copyright 2007, Anders Broman <anders.broman@ericsson.com>
 + * Copyright 2009, Harald Welte <laforge@gnumonks.org>
   *
-  * $Id: packet-rsl.c 29944 2009-09-16 13:39:37Z morriss $
+  * $Id$
   *
-@@ -44,6 +45,8 @@
+@@ -42,6 +43,8 @@
  #include <epan/lapd_sapi.h>
  
  #include "packet-gsm_a_common.h"
@@ -19,7 +28,7 @@
  
  /* Initialize the protocol and registered fields */
  static int proto_rsl		= -1;
-@@ -117,6 +120,24 @@
+@@ -115,6 +118,24 @@ static int hf_rsl_emlpp_prio		= -1;
  static int hf_rsl_rtd				= -1;
  static int hf_rsl_delay_ind			= -1;
  static int hf_rsl_tfo				= -1;
@@ -44,7 +53,7 @@
  
  /* Initialize the subtree pointers */
  static int ett_rsl = -1;
-@@ -174,6 +195,15 @@
+@@ -172,6 +193,15 @@ static int ett_ie_cause = -1;
  static int ett_ie_meas_res_no = -1;
  static int ett_ie_message_id = -1;
  static int ett_ie_sys_info_type = -1;
@@ -60,7 +69,7 @@
  
  proto_tree *top_tree;
  dissector_handle_t gsm_a_ccch_handle;
-@@ -209,8 +239,11 @@
+@@ -207,8 +237,11 @@ static const value_string rsl_msg_disc_vals[] = {
  	{  0x06,		"Common Channel Management messages" },
  	{  0x08,		"TRX Management messages" },
  	{  0x16,		"Location Services messages" },
@@ -72,7 +81,7 @@
  /*
   * 9.2 MESSAGE TYPE
   */
-@@ -277,6 +310,49 @@
+@@ -275,6 +308,49 @@ static const value_string rsl_msg_disc_vals[] = {
  	/* 	0 1 - - - - - - Location Services messages: */
  #define RSL_MSG_LOC_INF					65	/* 8.7.1 */
  
@@ -90,16 +99,16 @@
 +#define RSL_MSG_TYPE_IPAC_PDCH_DEACT_ACK 0x4c
 +#define RSL_MSG_TYPE_IPAC_PDCH_DEACT_NACK 0x4d
 +
-+#define RSL_MSG_TYPE_IPAC_BIND		0x70
-+#define RSL_MSG_TYPE_IPAC_BIND_ACK	0x71
-+#define RSL_MSG_TYPE_IPAC_BIND_NACK	0x72
-+#define RSL_MSG_TYPE_IPAC_CONNECT	0x73
-+#define RSL_MSG_TYPE_IPAC_CONNECT_ACK	0x74
-+#define RSL_MSG_TYPE_IPAC_CONNECT_NACK	0x75
-+#define RSL_MSG_TYPE_IPAC_DISC_IND	0x76
-+#define RSL_MSG_TYPE_IPAC_DISC		0x77
-+#define RSL_MSG_TYPE_IPAC_DISC_ACK	0x78
-+#define RSL_MSG_TYPE_IPAC_DISC_NACK	0x79
++#define RSL_MSG_TYPE_IPAC_CRCX		0x70
++#define RSL_MSG_TYPE_IPAC_CRCX_ACK	0x71
++#define RSL_MSG_TYPE_IPAC_CRCX_NACK	0x72
++#define RSL_MSG_TYPE_IPAC_MDCX		0x73
++#define RSL_MSG_TYPE_IPAC_MDCX_ACK	0x74
++#define RSL_MSG_TYPE_IPAC_MDCX_NACK	0x75
++#define RSL_MSG_TYPE_IPAC_DLCX_IND	0x76
++#define RSL_MSG_TYPE_IPAC_DLCX		0x77
++#define RSL_MSG_TYPE_IPAC_DLCX_ACK	0x78
++#define RSL_MSG_TYPE_IPAC_DLCX_NACK	0x79
 +
 +#define RSL_IE_IPAC_SRTP_CONFIG		0xe0
 +#define RSL_IE_IPAC_PROXY_UDP		0xe1
@@ -122,7 +131,7 @@
  
  static const value_string rsl_msg_type_vals[] = {
  	  /* 	0 0 0 0 - - - - Radio Link Layer Management messages: */
-@@ -339,6 +415,26 @@
+@@ -337,6 +413,26 @@ static const value_string rsl_msg_type_vals[] = {
  	{  0x3f,	"TFO MODification REQuest" },					/* 8.4.31 */
  	/* 	0 1 - - - - - - Location Services messages: */
  	{  0x41,	"Location Information" },						/* 8.7.1 */
@@ -149,7 +158,7 @@
  	{ 0,		NULL }
  };
  
-@@ -372,10 +468,10 @@ static const value_string rsl_msg_type_vals[] = {
+@@ -370,10 +466,10 @@ static const value_string rsl_msg_type_vals[] = {
  #define RSL_IE_MESSAGE_ID		28
  
  #define RSL_IE_SYS_INFO_TYPE	30
@@ -164,7 +173,7 @@
  #define RSL_IE_FULL_IMM_ASS_INF			35
  #define RSL_IE_SMSCB_INF				36
  #define RSL_IE_FULL_MS_TIMING_OFFSET	37
-@@ -478,6 +574,24 @@
+@@ -476,6 +572,24 @@ static const value_string rsl_ie_type_vals[] = {
  			Not used
  
  	*/
@@ -189,7 +198,7 @@
  	{ 0,			NULL }
  };
  
-@@ -514,6 +628,96 @@
+@@ -512,6 +626,96 @@ static const value_string rsl_ch_no_Cbits_vals[] = {
  	{ 0,			NULL }
  };
  
@@ -286,7 +295,7 @@
  /* 9.3.1 Channel number			9.3.1	M TV 2 */
  static int
  dissect_rsl_ie_ch_no(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset, gboolean is_mandatory)
-@@ -2044,7 +2248,6 @@
+@@ -2042,7 +2246,6 @@ dissect_rsl_ie_err_msg(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int
  	proto_item_set_len(ti, length+2);
  
  	proto_tree_add_item(ie_tree, hf_rsl_ie_length, tvb, offset, 1, FALSE);
@@ -294,7 +303,7 @@
  
  	/* Received Message */
  	offset = dissct_rsl_msg(tvb, pinfo, ie_tree, offset);
-@@ -2909,12 +3112,183 @@
+@@ -2907,12 +3110,184 @@ dissect_rsl_ie_tfo_transp_cont(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree
  }
  
  static int
@@ -310,16 +319,16 @@
 +
 +#if 0
 +	switch (msg_type) {
-+	case RSL_MSG_TYPE_IPAC_BIND:
-+	case RSL_MSG_TYPE_IPAC_BIND_ACK:
-+	case RSL_MSG_TYPE_IPAC_BIND_NACK:
-+	case RSL_MSG_TYPE_IPAC_CONNECT:
-+	case RSL_MSG_TYPE_IPAC_CONNECT_ACK:
-+	case RSL_MSG_TYPE_IPAC_CONNECT_NACK:
-+	case RSL_MSG_TYPE_IPAC_DISC_IND:
-+	case RSL_MSG_TYPE_IPAC_DISC:
-+	case RSL_MSG_TYPE_IPAC_DISC_ACK:
-+	case RSL_MSG_TYPE_IPAC_DISC_NACK:
++	case RSL_MSG_TYPE_IPAC_CRCX:
++	case RSL_MSG_TYPE_IPAC_CRCX_ACK:
++	case RSL_MSG_TYPE_IPAC_CRCX_NACK:
++	case RSL_MSG_TYPE_IPAC_MDCX:
++	case RSL_MSG_TYPE_IPAC_MDCX_ACK:
++	case RSL_MSG_TYPE_IPAC_MDCX_NACK:
++	case RSL_MSG_TYPE_IPAC_DLCX_IND:
++	case RSL_MSG_TYPE_IPAC_DLCX:
++	case RSL_MSG_TYPE_IPAC_DLCX_ACK:
++	case RSL_MSG_TYPE_IPAC_DLCX_NACK:
 +	case RSL_MSG_TYPE_IPAC_PDCH_ACT:
 +	case RSL_MSG_TYPE_IPAC_PDCH_ACT_ACK:
 +	case RSL_MSG_TYPE_IPAC_PDCH_ACT_NACK:
@@ -449,7 +458,7 @@
 +	}
 +
 +	switch (msg_type) {
-+	case RSL_MSG_TYPE_IPAC_BIND_ACK:
++	case RSL_MSG_TYPE_IPAC_CRCX_ACK:
 +		/* Notify the RTP and RTCP dissectors about a new RTP stream */
 +		src_addr.type = AT_IPv4;
 +		src_addr.len = 4;
@@ -480,7 +489,7 @@
  	offset++;
  
  	switch (msg_type){
-@@ -3482,6 +3856,18 @@
+@@ -3480,6 +3855,18 @@ dissct_rsl_msg(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset)
  		/* LLP APDU 9.3.58 M LV 2-N */
  		offset = dissect_rsl_ie_llp_apdu(tvb, pinfo, tree, offset, TRUE);
  		break;
@@ -499,7 +508,7 @@
  	default:
  		break;
  	}
-@@ -3489,6 +3875,40 @@
+@@ -3487,6 +3874,40 @@ dissct_rsl_msg(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset)
  	return offset;
  
  }
@@ -540,7 +549,7 @@
  static void
  dissect_rsl(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
  {
-@@ -3516,7 +3936,6 @@
+@@ -3514,7 +3935,6 @@ dissect_rsl(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
  		/* 9.1 Message discriminator */
  		proto_tree_add_item(rsl_tree, hf_rsl_msg_dsc, tvb, offset, 1, FALSE);
  		proto_tree_add_item(rsl_tree, hf_rsl_T_bit, tvb, offset, 1, FALSE);
@@ -548,7 +557,7 @@
  
  		offset = dissct_rsl_msg(tvb, pinfo, rsl_tree, offset);
  
-@@ -3886,6 +4305,86 @@
+@@ -3884,6 +4304,86 @@ void proto_register_rsl(void)
  			FT_UINT8, BASE_DEC, VALS(rsl_emlpp_prio_vals), 0x03,
  			NULL, HFILL }
  		},
@@ -635,7 +644,7 @@
  	};
  	static gint *ett[] = {
  		&ett_rsl,
-@@ -3943,6 +4442,14 @@
+@@ -3941,6 +4441,14 @@ void proto_register_rsl(void)
  		&ett_ie_meas_res_no,
  		&ett_ie_message_id,
  		&ett_ie_sys_info_type,
@@ -650,3 +659,6 @@
  	};
  
  	/* Register the protocol name and description */
+-- 
+1.7.0.1
+