Merge branch 'master' into sms
diff --git a/openbsc/include/openbsc/abis_nm.h b/openbsc/include/openbsc/abis_nm.h
index 47baafb..3dc5531 100644
--- a/openbsc/include/openbsc/abis_nm.h
+++ b/openbsc/include/openbsc/abis_nm.h
@@ -482,6 +482,12 @@
 	NM_CHANC_BCCH		= 0x06,
 	NM_CHANC_BCCH_CBCH	= 0x07,
 	NM_CHANC_SDCCH_CBCH	= 0x08,
+	/* ip.access */
+	NM_CHANC_IPAC_bPDCH	= 0x0b,	/* PBCCH + PCCCH + PDTCH/F + PACCH/F + PTCCH/F */
+	NM_CHANC_IPAC_cPDCH	= 0x0c, /* PBCCH + PDTCH/F + PACCH/F + PTCCH/F */
+	NM_CHANC_IPAC_PDCH	= 0x0d,	/* PDTCH/F + PACCH/F + PTCCH/F */
+	NM_CHANC_IPAC_TCHFull_PDCH = 0x80,
+	NM_CHANC_IPAC_TCHFull_TCHHalf = 0x81,
 };
 
 /* Section 9.4.16: Event Type */
@@ -672,6 +678,9 @@
 int abis_nm_software_activate(struct gsm_bts *bts, const char *fname,
 			      gsm_cbfn *cbfn, void *cb_data);
 
+int abis_nm_conn_mdrop_link(struct gsm_bts *bts, u_int8_t e1_port0, u_int8_t ts0,
+			    u_int8_t e1_port1, u_int8_t ts1);
+
 /* Siemens / BS-11 specific */
 int abis_nm_bs11_reset_resource(struct gsm_bts *bts);
 int abis_nm_bs11_db_transmission(struct gsm_bts *bts, int begin);
diff --git a/openbsc/include/openbsc/abis_rsl.h b/openbsc/include/openbsc/abis_rsl.h
index a2a01d3..201c77f 100644
--- a/openbsc/include/openbsc/abis_rsl.h
+++ b/openbsc/include/openbsc/abis_rsl.h
@@ -333,6 +333,7 @@
 #define RSL_ERR_TALKER_ACC_FAIL		0x03
 #define RSL_ERR_OM_INTERVENTION		0x07
 #define RSL_ERR_NORMAL_UNSPEC		0x0f
+#define RSL_ERR_T_MSRFPCI_EXP		0x18
 /* resource unavailable */
 #define RSL_ERR_EQUIPMENT_FAIL		0x20
 #define RSL_ERR_RR_UNAVAIL		0x21
diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h
index 50d24b6..52dec90 100644
--- a/openbsc/include/openbsc/gsm_data.h
+++ b/openbsc/include/openbsc/gsm_data.h
@@ -54,6 +54,11 @@
 #define HARDCODED_TSC	7
 #define HARDCODED_BSIC	0x3f	/* NCC = 7 / BCC = 7 */
 
+/* for multi-drop config */
+#define HARDCODED_BTS0_TS	1
+#define HARDCODED_BTS1_TS	6
+#define HARDCODED_BTS2_TS	11
+
 enum gsm_hooks {
 	GSM_HOOK_NM_SWLOAD,
 	GSM_HOOK_RR_PAGING,
diff --git a/openbsc/src/abis_nm.c b/openbsc/src/abis_nm.c
index dec4b29..0eb8657 100644
--- a/openbsc/src/abis_nm.c
+++ b/openbsc/src/abis_nm.c
@@ -357,18 +357,47 @@
 		/* ip.access specifics */
 		[NM_ATT_IPACC_DST_IP] =		{ TLV_TYPE_FIXED, 4 },
 		[NM_ATT_IPACC_DST_IP_PORT] =	{ TLV_TYPE_FIXED, 2 },
+		[NM_ATT_IPACC_STREAM_ID] =	{ TLV_TYPE_TV, },
+		[NM_ATT_IPACC_FREQ_CTRL] =	{ TLV_TYPE_TV, },
+		[NM_ATT_IPACC_SEC_OML_CFG] =	{ TLV_TYPE_FIXED, 6 },
+		[NM_ATT_IPACC_IP_IF_CFG] =	{ TLV_TYPE_FIXED, 8 },
+		[NM_ATT_IPACC_IP_GW_CFG] =	{ TLV_TYPE_FIXED, 12 },
+		[NM_ATT_IPACC_IN_SERV_TIME] =	{ TLV_TYPE_FIXED, 4 },
+		[NM_ATT_IPACC_LOCATION] =	{ TLV_TYPE_TL16V },
+		[NM_ATT_IPACC_PAGING_CFG] =	{ TLV_TYPE_FIXED, 2 },
+		[NM_ATT_IPACC_UNIT_ID] =	{ TLV_TYPE_TL16V },
+		[NM_ATT_IPACC_UNIT_NAME] =	{ TLV_TYPE_TL16V },
+		[NM_ATT_IPACC_SNMP_CFG] =	{ TLV_TYPE_TL16V },
 		[NM_ATT_IPACC_PRIM_OML_CFG_LIST] = { TLV_TYPE_TL16V },
 		[NM_ATT_IPACC_NV_FLAGS] =	{ TLV_TYPE_TL16V },
 		[NM_ATT_IPACC_FREQ_CTRL] =	{ TLV_TYPE_FIXED, 2 },
 		[NM_ATT_IPACC_PRIM_OML_FB_TOUT] = { TLV_TYPE_TL16V },
-		[NM_ATT_IPACC_SEC_OML_CFG] =	{ TLV_TYPE_FIXED, 6 },
-		[NM_ATT_IPACC_IP_IF_CFG] =	{ TLV_TYPE_FIXED, 8 },
-		[NM_ATT_IPACC_IP_GW_CFG] =	{ TLV_TYPE_FIXED, 12 },
-		[NM_ATT_IPACC_LOCATION] =	{ TLV_TYPE_TL16V },
-		[NM_ATT_IPACC_UNIT_ID] =	{ TLV_TYPE_TL16V },
-		[NM_ATT_IPACC_UNIT_NAME] =	{ TLV_TYPE_TL16V },
-		[NM_ATT_IPACC_SNMP_CFG] =	{ TLV_TYPE_TL16V },
+		[NM_ATT_IPACC_CUR_SW_CFG] =	{ TLV_TYPE_TL16V },
+		[NM_ATT_IPACC_TIMING_BUS] =	{ TLV_TYPE_TL16V },
+		[NM_ATT_IPACC_CGI] =		{ TLV_TYPE_TL16V },
+		[NM_ATT_IPACC_RAC] =		{ TLV_TYPE_TL16V },
+		[NM_ATT_IPACC_OBJ_VERSION] =	{ TLV_TYPE_TL16V },
+		[NM_ATT_IPACC_GPRS_PAGING_CFG]= { TLV_TYPE_TL16V },
+		[NM_ATT_IPACC_NSEI] =		{ TLV_TYPE_TL16V },
+		[NM_ATT_IPACC_BVCI] =		{ TLV_TYPE_TL16V },
+		[NM_ATT_IPACC_NSVCI] =		{ TLV_TYPE_TL16V },
+		[NM_ATT_IPACC_NS_CFG] =		{ TLV_TYPE_TL16V },
+		[NM_ATT_IPACC_BSSGP_CFG] =	{ TLV_TYPE_TL16V },
+		[NM_ATT_IPACC_NS_LINK_CFG] =	{ TLV_TYPE_TL16V },
+		[NM_ATT_IPACC_RLC_CFG] =	{ TLV_TYPE_TL16V },
 		[NM_ATT_IPACC_ALM_THRESH_LIST]=	{ TLV_TYPE_TL16V },
+		[NM_ATT_IPACC_MONIT_VAL_LIST] = { TLV_TYPE_TL16V },
+		[NM_ATT_IPACC_TIB_CONTROL] =	{ TLV_TYPE_TL16V },
+		[NM_ATT_IPACC_SUPP_FEATURES] =	{ TLV_TYPE_TL16V },
+		[NM_ATT_IPACC_CODING_SCHEMES] =	{ TLV_TYPE_TL16V },
+		[NM_ATT_IPACC_RLC_CFG_2] =	{ TLV_TYPE_TL16V },
+		[NM_ATT_IPACC_HEARTB_TOUT] =	{ TLV_TYPE_TL16V },
+		[NM_ATT_IPACC_UPTIME] =		{ TLV_TYPE_TL16V },
+		[NM_ATT_IPACC_RLC_CFG_3] =	{ TLV_TYPE_TL16V },
+		[NM_ATT_IPACC_SSL_CFG] =	{ TLV_TYPE_TL16V },
+		[NM_ATT_IPACC_SEC_POSSIBLE] =	{ TLV_TYPE_TL16V },
+		[NM_ATT_IPACC_IML_SSL_STATE] =	{ TLV_TYPE_TL16V },
+		[NM_ATT_IPACC_REVOC_DATE] =	{ TLV_TYPE_TL16V },
 		//[0x95] =			{ TLV_TYPE_FIXED, 2 },
 		[0x85] =			{ TLV_TYPE_TV },
 
@@ -937,6 +966,9 @@
 	case NM_MT_BS11_LMT_SESSION:
 		return abis_nm_rx_lmt_event(mb);
 		break;
+	case NM_MT_CONN_MDROP_LINK_ACK:
+		DEBUGP(DNM, "CONN MDROP LINK ACK\n");
+		break;
 	}
 
 	return 0;
@@ -1731,6 +1763,32 @@
 	return abis_nm_sendmsg(bts, msg);
 }
 
+int abis_nm_conn_mdrop_link(struct gsm_bts *bts, u_int8_t e1_port0, u_int8_t ts0,
+			    u_int8_t e1_port1, u_int8_t ts1)
+{
+	struct abis_om_hdr *oh;
+	struct msgb *msg = nm_msgb_alloc();
+	u_int8_t *attr;
+
+	DEBUGP(DNM, "CONNECT MDROP LINK E1=(%u,%u) -> E1=(%u, %u)\n",
+		e1_port0, ts0, e1_port1, ts1);
+
+	oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
+	fill_om_fom_hdr(oh, 6, NM_MT_CONN_MDROP_LINK,
+			NM_OC_SITE_MANAGER, 0x00, 0x00, 0x00);
+
+	attr = msgb_put(msg, 3);
+	attr[0] = NM_ATT_MDROP_LINK;
+	attr[1] = e1_port0;
+	attr[2] = ts0;
+
+	attr = msgb_put(msg, 3);
+	attr[0] = NM_ATT_MDROP_NEXT;
+	attr[1] = e1_port1;
+	attr[2] = ts1;
+
+	return abis_nm_sendmsg(bts, msg);
+}
 
 int abis_nm_event_reports(struct gsm_bts *bts, int on)
 {
@@ -2121,7 +2179,7 @@
 						   bs11_sw->win_size,
 						   bs11_sw->forced,
 						   &bs11_swload_cbfn, bs11_sw);
-			free(fle);
+			talloc_free(fle);
 		} else {
 			/* activate the SWL */
 			rc = abis_nm_software_activate(bs11_sw->bts,
@@ -2175,7 +2233,7 @@
 	/* start download the next file of our file list */
 	rc = abis_nm_software_load(bts, fle->fname, win_size, forced,
 				   bs11_swload_cbfn, bs11_sw);
-	free(fle);
+	talloc_free(fle);
 	return rc;
 }
 
diff --git a/openbsc/src/abis_rsl.c b/openbsc/src/abis_rsl.c
index eb43bd5..1a2c58b 100644
--- a/openbsc/src/abis_rsl.c
+++ b/openbsc/src/abis_rsl.c
@@ -321,6 +321,7 @@
 	[RSL_ERR_TALKER_ACC_FAIL] =	"Talker Access Failure",
 	[RSL_ERR_OM_INTERVENTION] =	"O&M Intervention",
 	[RSL_ERR_NORMAL_UNSPEC] =	"Normal event, unspecified",
+	[RSL_ERR_T_MSRFPCI_EXP] =	"Siemens: T_MSRFPCI Expired",
 	[RSL_ERR_EQUIPMENT_FAIL] =	"Equipment Failure",
 	[RSL_ERR_RR_UNAVAIL] =		"Radio Resource not available",
 	[RSL_ERR_TERR_CH_FAIL] =	"Terrestrial Channel Failure",
@@ -1089,7 +1090,8 @@
 	arfcn = lchan->ts->trx->arfcn;
 	subch = lchan->nr;
 	
-	lchan->ms_power = lchan->bs_power = 0x0f; /* 30dB reduction */
+	lchan->ms_power = ms_pwr_ctl_lvl(bts, 20 /* dBm == 100mW */);
+	lchan->bs_power = 0x0f; /* 30dB reduction */
 	lchan->rsl_cmode = RSL_CMOD_SPD_SIGN;
 	rsl_chan_activate_lchan(lchan, 0x00, rqd_ta);
 
@@ -1188,7 +1190,7 @@
 	struct abis_rsl_rll_hdr *rllh = msgb_l2(msg);
 	u_int8_t *rlm_cause = rllh->data;
 
-	DEBUGPC(DRLL, "cause=0x%02x", rlm_cause[1]);
+	DEBUGPC(DRLL, "ERROR INDICATION cause=0x%02x\n", rlm_cause[1]);
 		
 	if (rlm_cause[1] == RLL_CAUSE_T200_EXPIRED)
 		return rsl_chan_release(msg->lchan);
@@ -1232,24 +1234,22 @@
 		}
 		break;
 	case RSL_MT_REL_IND:
-		DEBUGPC(DRLL, "RELEASE INDICATION ");
+		DEBUGPC(DRLL, "RELEASE INDICATION\n");
 		break;
 	case RSL_MT_REL_CONF:
-		DEBUGPC(DRLL, "RELEASE CONFIRMATION ");
+		DEBUGPC(DRLL, "RELEASE CONFIRMATION\n");
 		break;
 	case RSL_MT_ERROR_IND:
-		DEBUGPC(DRLL, "ERROR INDICATION ");
 		rc = rsl_rx_rll_err_ind(msg);
 		break;
 	case RSL_MT_UNIT_DATA_IND:
-		DEBUGPC(DRLL, "unimplemented Abis RLL message type 0x%02x ",
+		DEBUGPC(DRLL, "unimplemented Abis RLL message type 0x%02x\n",
 			rllh->c.msg_type);
 		break;
 	default:
-		DEBUGPC(DRLL, "unknown Abis RLL message type 0x%02x ",
+		DEBUGPC(DRLL, "unknown Abis RLL message type 0x%02x\n",
 			rllh->c.msg_type);
 	}
-	DEBUGPC(DRLL, "\n");
 	return rc;
 }
 
diff --git a/openbsc/src/bsc_hack.c b/openbsc/src/bsc_hack.c
index b762f8c..82cb788 100644
--- a/openbsc/src/bsc_hack.c
+++ b/openbsc/src/bsc_hack.c
@@ -62,6 +62,7 @@
 static int cardnr = 0;
 static int release_l2 = 0;
 static int bs11_has_trx1 = 0;
+static int bs11_has_bts1 = 0;
 static enum gsm_bts_type BTS_TYPE = GSM_BTS_TYPE_BS11;
 static enum gsm_band BAND = GSM_BAND_900;
 static const char *database_name = "hlr.sqlite3";
@@ -503,6 +504,23 @@
 static void bootstrap_om_bs11(struct gsm_bts *bts)
 {
 	struct gsm_bts_trx *trx = bts->c0;
+	int base_ts;
+
+	switch (bts->nr) {
+	case 0:
+		/* First BTS uses E1 TS 01,02,03,04,05 */
+		base_ts = HARDCODED_BTS0_TS - 1;
+		break;
+	case 1:
+		/* Second BTS uses E1 TS 06,07,08,09,10 */
+		base_ts = HARDCODED_BTS1_TS - 1;
+		break;
+	case 2:
+		/* Third BTS uses E1 TS 11,12,13,14,15 */
+		base_ts = HARDCODED_BTS2_TS - 1;
+	default:
+		return;
+	}
 
 	/* stop sending event reports */
 	abis_nm_event_reports(bts, 0);
@@ -525,47 +543,47 @@
 	abis_nm_raw_msg(bts, sizeof(msg_4), msg_4); /* set BTS power control attr */
 
 	/* Connect signalling of bts0/trx0 to e1_0/ts1/64kbps */
-	abis_nm_conn_terr_sign(trx, 0, 1, 0xff);
+	abis_nm_conn_terr_sign(trx, 0, base_ts+1, 0xff);
 	abis_nm_set_radio_attr(trx, bs11_attr_radio, sizeof(bs11_attr_radio));
 
 	/* Use TEI 1 for signalling */
-	abis_nm_establish_tei(bts, 0, 0, 1, 0xff, 0x01);
+	abis_nm_establish_tei(bts, 0, 0, base_ts+1, 0xff, 0x01);
 	abis_nm_set_channel_attr(&trx->ts[0], NM_CHANC_SDCCH_CBCH);
 
 	/* SET CHANNEL ATTRIBUTE TS1 */
 	abis_nm_set_channel_attr(&trx->ts[1], NM_CHANC_TCHFull);
 	/* Connect traffic of bts0/trx0/ts1 to e1_0/ts2/b */
-	abis_nm_conn_terr_traf(&trx->ts[1], 0, 2, 1);
+	abis_nm_conn_terr_traf(&trx->ts[1], 0, base_ts+2, 1);
 	
 	/* SET CHANNEL ATTRIBUTE TS2 */
 	abis_nm_set_channel_attr(&trx->ts[2], NM_CHANC_TCHFull);
 	/* Connect traffic of bts0/trx0/ts2 to e1_0/ts2/c */
-	abis_nm_conn_terr_traf(&trx->ts[2], 0, 2, 2);
+	abis_nm_conn_terr_traf(&trx->ts[2], 0, base_ts+2, 2);
 
 	/* SET CHANNEL ATTRIBUTE TS3 */
 	abis_nm_set_channel_attr(&trx->ts[3], NM_CHANC_TCHFull);
 	/* Connect traffic of bts0/trx0/ts3 to e1_0/ts2/d */
-	abis_nm_conn_terr_traf(&trx->ts[3], 0, 2, 3);
+	abis_nm_conn_terr_traf(&trx->ts[3], 0, base_ts+2, 3);
 
 	/* SET CHANNEL ATTRIBUTE TS4 */
 	abis_nm_set_channel_attr(&trx->ts[4], NM_CHANC_TCHFull);
 	/* Connect traffic of bts0/trx0/ts4 to e1_0/ts3/a */
-	abis_nm_conn_terr_traf(&trx->ts[4], 0, 3, 0);
+	abis_nm_conn_terr_traf(&trx->ts[4], 0, base_ts+3, 0);
 
 	/* SET CHANNEL ATTRIBUTE TS5 */
 	abis_nm_set_channel_attr(&trx->ts[5], NM_CHANC_TCHFull);
 	/* Connect traffic of bts0/trx0/ts5 to e1_0/ts3/b */
-	abis_nm_conn_terr_traf(&trx->ts[5], 0, 3, 1);
+	abis_nm_conn_terr_traf(&trx->ts[5], 0, base_ts+3, 1);
 
 	/* SET CHANNEL ATTRIBUTE TS6 */
 	abis_nm_set_channel_attr(&trx->ts[6], NM_CHANC_TCHFull);
 	/* Connect traffic of bts0/trx0/ts6 to e1_0/ts3/c */
-	abis_nm_conn_terr_traf(&trx->ts[6], 0, 3, 2);
+	abis_nm_conn_terr_traf(&trx->ts[6], 0, base_ts+3, 2);
 
 	/* SET CHANNEL ATTRIBUTE TS7 */
 	abis_nm_set_channel_attr(&trx->ts[7], NM_CHANC_TCHFull);
 	/* Connect traffic of bts0/trx0/ts7 to e1_0/ts3/d */
-	abis_nm_conn_terr_traf(&trx->ts[7], 0, 3, 3);
+	abis_nm_conn_terr_traf(&trx->ts[7], 0, base_ts+3, 3);
 
 	trx = gsm_bts_trx_num(bts, 1);
 	if (trx) {	
@@ -581,53 +599,53 @@
 		trx1_attr_radio[3] = arfcn_low;
 	
 		/* Connect signalling of TRX1 to e1_0/ts1/64kbps */
-		abis_nm_conn_terr_sign(trx, 0, 1, 0xff);
+		abis_nm_conn_terr_sign(trx, 0, base_ts+1, 0xff);
 		/* FIXME: TRX ATTRIBUTE */
 		abis_nm_set_radio_attr(trx, trx1_attr_radio,
 					sizeof(trx1_attr_radio));
 
 		/* Use TEI 2 for signalling */
-		abis_nm_establish_tei(bts, 1, 0, 1, 0xff, 0x02);
+		abis_nm_establish_tei(bts, 1, 0, base_ts+1, 0xff, 0x02);
 
-		/* SET CHANNEL ATTRIBUTE TS1 */
-		abis_nm_set_channel_attr(&trx->ts[1], NM_CHANC_TCHFull);
-		/* Connect traffic of bts0/trx0/ts1 to e1_0/ts4/a */
-		abis_nm_conn_terr_traf(&trx->ts[1], 0, 4, 0);
+		/* SET CHANNEL ATTRIBUTE TS0 */
+		abis_nm_set_channel_attr(&trx->ts[0], NM_CHANC_TCHFull);
+		/* Connect traffic of bts0/trx0/ts0 to e1_0/ts4/a */
+		abis_nm_conn_terr_traf(&trx->ts[0], 0, base_ts+4, 0);
 	
 		/* SET CHANNEL ATTRIBUTE TS1 */
 		abis_nm_set_channel_attr(&trx->ts[1], NM_CHANC_TCHFull);
 		/* Connect traffic of bts0/trx0/ts1 to e1_0/ts4/b */
-		abis_nm_conn_terr_traf(&trx->ts[1], 0, 4, 1);
+		abis_nm_conn_terr_traf(&trx->ts[1], 0, base_ts+4, 1);
 	
 		/* SET CHANNEL ATTRIBUTE TS2 */
 		abis_nm_set_channel_attr(&trx->ts[2], NM_CHANC_TCHFull);
 		/* Connect traffic of bts0/trx0/ts2 to e1_0/ts4/c */
-		abis_nm_conn_terr_traf(&trx->ts[2], 0, 4, 2);
+		abis_nm_conn_terr_traf(&trx->ts[2], 0, base_ts+4, 2);
 
 		/* SET CHANNEL ATTRIBUTE TS3 */
 		abis_nm_set_channel_attr(&trx->ts[3], NM_CHANC_TCHFull);
 		/* Connect traffic of bts0/trx0/ts3 to e1_0/ts4/d */
-		abis_nm_conn_terr_traf(&trx->ts[3], 0, 4, 3);
+		abis_nm_conn_terr_traf(&trx->ts[3], 0, base_ts+4, 3);
 
 		/* SET CHANNEL ATTRIBUTE TS4 */
 		abis_nm_set_channel_attr(&trx->ts[4], NM_CHANC_TCHFull);
 		/* Connect traffic of bts0/trx0/ts4 to e1_0/ts5/a */
-		abis_nm_conn_terr_traf(&trx->ts[4], 0, 5, 0);
+		abis_nm_conn_terr_traf(&trx->ts[4], 0, base_ts+5, 0);
 
 		/* SET CHANNEL ATTRIBUTE TS5 */
 		abis_nm_set_channel_attr(&trx->ts[5], NM_CHANC_TCHFull);
 		/* Connect traffic of bts0/trx0/ts5 to e1_0/ts5/b */
-		abis_nm_conn_terr_traf(&trx->ts[5], 0, 5, 1);
+		abis_nm_conn_terr_traf(&trx->ts[5], 0, base_ts+5, 1);
 
 		/* SET CHANNEL ATTRIBUTE TS6 */
 		abis_nm_set_channel_attr(&trx->ts[6], NM_CHANC_TCHFull);
 		/* Connect traffic of bts0/trx0/ts6 to e1_0/ts5/c */
-		abis_nm_conn_terr_traf(&trx->ts[6], 0, 5, 2);
+		abis_nm_conn_terr_traf(&trx->ts[6], 0, base_ts+5, 2);
 
 		/* SET CHANNEL ATTRIBUTE TS7 */
 		abis_nm_set_channel_attr(&trx->ts[7], NM_CHANC_TCHFull);
 		/* Connect traffic of bts0/trx0/ts7 to e1_0/ts5/d */
-		abis_nm_conn_terr_traf(&trx->ts[7], 0, 5, 3);
+		abis_nm_conn_terr_traf(&trx->ts[7], 0, base_ts+5, 3);
 	}
 
 	/* end DB transmission */
@@ -659,6 +677,8 @@
 
 static int shutdown_om(struct gsm_bts *bts)
 {
+	fprintf(stdout, "shutting down OML for BTS %u\n", bts->nr);
+
 	/* stop sending event reports */
 	abis_nm_event_reports(bts, 0);
 
@@ -890,10 +910,12 @@
 {
 	int i;
 
-	for (i = 0; i < ARRAY_SIZE(bcch_infos); i++) {
-		rsl_bcch_info(trx, bcch_infos[i].type,
-			      bcch_infos[i].data,
-			      bcch_infos[i].len);
+	if (trx == trx->bts->c0) {
+		for (i = 0; i < ARRAY_SIZE(bcch_infos); i++) {
+			rsl_bcch_info(trx, bcch_infos[i].type,
+				      bcch_infos[i].data,
+				      bcch_infos[i].len);
+		}
 	}
 	rsl_sacch_filling(trx, RSL_SYSTEM_INFO_5, si5, sizeof(si5));
 	rsl_sacch_filling(trx, RSL_SYSTEM_INFO_6, si6, sizeof(si6));
@@ -964,7 +986,7 @@
 {
 	fprintf(stdout, "bootstrapping RSL for BTS/TRX (%u/%u) "
 		"using MCC=%u MNC=%u BSIC=%u TSC=%u\n",
-		trx->nr, trx->bts->nr, MCC, MNC, BSIC, TSC);
+		trx->bts->nr, trx->nr, MCC, MNC, BSIC, TSC);
 	set_system_infos(trx);
 }
 
@@ -1040,6 +1062,8 @@
 
 static int bootstrap_network(void)
 {
+	int rc;
+
 	switch(BTS_TYPE) {
 	case GSM_BTS_TYPE_NANOBTS_1800:
 		if (ARFCN < 512 || ARFCN > 885) {
@@ -1093,11 +1117,26 @@
 			trx1 = gsm_bts_trx_alloc(bts);
 			trx1->arfcn = ARFCN + 2;
 		}
-
 		bootstrap_bts(bts);
+		rc = e1_config(bts, cardnr, release_l2);
+		if (rc < 0) {
+			fprintf(stderr, "Error during E1 config of BTS 0\n");
+			return rc;
+		}
 
-		gsmnet->num_bts = 1;
-		return e1_config(bts, cardnr, release_l2);
+		if (bs11_has_bts1) {
+			bts = gsm_bts_alloc(gsmnet, BTS_TYPE, TSC, BSIC);
+			if (bs11_has_trx1) {
+				struct gsm_bts_trx *trx1;
+				trx1 = gsm_bts_trx_alloc(bts);
+				trx1->arfcn = ARFCN + 2;
+			}
+			bootstrap_bts(bts);
+			rc = e1_config(bts, cardnr+1, release_l2);
+			if (rc < 0)
+				fprintf(stderr, "Error during E1 config of BTS 1\n");
+		}
+		return rc;
 	} else {
 		struct nano_bts_id *bts_id;
 		struct gsm_bts *bts;
@@ -1153,6 +1192,7 @@
 	printf("  -i --bts-id=NUMBER The known nanoBTS device numbers. Can be specified multiple times.\n");
 	printf("  -C --cardnr number  For bs11 select E1 card number other than 0\n");
 	printf("  -R --release-l2 Releases mISDN layer 2 after exit, to unload driver.\n");
+	printf("  -2 --second-bs11 Configure + Use a second BS-11\n");
 	printf("  -h --help this text\n");
 }
 
@@ -1182,10 +1222,11 @@
 			{"bsic", 1, 0, 'B'},
 			{"rtp-proxy", 0, 0, 'P'},
 			{"trx1", 0, 0, '1'},
+			{"second-bs11", 0, 0, '2'},
 			{0, 0, 0, 0}
 		};
 
-		c = getopt_long(argc, argv, "hc:n:d:sar:p:f:t:C:RL:l:Tb:i:S:B:P1",
+		c = getopt_long(argc, argv, "hc:n:d:sar:p:f:t:C:RL:l:Tb:i:S:B:P12",
 				long_options, &option_index);
 		if (c == -1)
 			break;
@@ -1262,6 +1303,9 @@
 		case '1':
 			bs11_has_trx1 = 1;
 			break;
+		case '2':
+			bs11_has_bts1 = 1;
+			break;
 		}
 		default:
 			/* ignore */
@@ -1275,9 +1319,11 @@
 	fprintf(stdout, "signal %u received\n", signal);
 
 	switch (signal) {
-	case SIGHUP:
+	case SIGINT:
 	case SIGABRT:
 		shutdown_net(gsmnet);
+		sleep(3);
+		exit(0);
 		break;
 	case SIGUSR1:
 		talloc_report_full(tall_bsc_ctx, stderr);
@@ -1303,7 +1349,7 @@
 	if (rc < 0)
 		exit(1);
 
-	signal(SIGHUP, &signal_handler);
+	signal(SIGINT, &signal_handler);
 	signal(SIGABRT, &signal_handler);
 	signal(SIGUSR1, &signal_handler);
 
diff --git a/openbsc/src/e1_config.c b/openbsc/src/e1_config.c
index addc9fe..8987803 100644
--- a/openbsc/src/e1_config.c
+++ b/openbsc/src/e1_config.c
@@ -25,18 +25,35 @@
 	struct e1inp_ts *sign_ts;
 	struct e1inp_sign_link *oml_link, *rsl_link;
 	struct gsm_bts_trx *trx = bts->c0;
+	int base_ts;
+
+	switch (bts->nr) {
+	case 0:
+		/* First BTS uses E1 TS 01,02,03,04,05 */
+		base_ts = HARDCODED_BTS0_TS - 1;
+		break;
+	case 1:
+		/* Second BTS uses E1 TS 06,07,08,09,10 */
+		base_ts = HARDCODED_BTS1_TS - 1;
+		break;
+	case 2:
+		/* Third BTS uses E1 TS 11,12,13,14,15 */
+		base_ts = HARDCODED_BTS2_TS - 1;
+	default:
+		return -EINVAL;
+	}
 
 	line = talloc_zero(tall_bsc_ctx, struct e1inp_line);
 	if (!line)
 		return -ENOMEM;
 
 	/* create E1 timeslots for signalling and TRAU frames */
-	e1inp_ts_config(&line->ts[1-1], line, E1INP_TS_TYPE_SIGN);
-	e1inp_ts_config(&line->ts[2-1], line, E1INP_TS_TYPE_TRAU);
-	e1inp_ts_config(&line->ts[3-1], line, E1INP_TS_TYPE_TRAU);
+	e1inp_ts_config(&line->ts[base_ts+1-1], line, E1INP_TS_TYPE_SIGN);
+	e1inp_ts_config(&line->ts[base_ts+2-1], line, E1INP_TS_TYPE_TRAU);
+	e1inp_ts_config(&line->ts[base_ts+3-1], line, E1INP_TS_TYPE_TRAU);
 
 	/* create signalling links for TS1 */
-	sign_ts = &line->ts[1-1];
+	sign_ts = &line->ts[base_ts+1-1];
 	oml_link = e1inp_sign_link_create(sign_ts, E1INP_SIGN_OML,
 					  trx, TEI_OML, SAPI_OML);
 	rsl_link = e1inp_sign_link_create(sign_ts, E1INP_SIGN_RSL,
@@ -47,40 +64,40 @@
 	trx->rsl_link = rsl_link;
 
 	/* enable subchannel demuxer on TS2 */
-	subch_demux_activate(&line->ts[2-1].trau.demux, 1);
-	subch_demux_activate(&line->ts[2-1].trau.demux, 2);
-	subch_demux_activate(&line->ts[2-1].trau.demux, 3);
+	subch_demux_activate(&line->ts[base_ts+2-1].trau.demux, 1);
+	subch_demux_activate(&line->ts[base_ts+2-1].trau.demux, 2);
+	subch_demux_activate(&line->ts[base_ts+2-1].trau.demux, 3);
 
 	/* enable subchannel demuxer on TS3 */
-	subch_demux_activate(&line->ts[3-1].trau.demux, 0);
-	subch_demux_activate(&line->ts[3-1].trau.demux, 1);
-	subch_demux_activate(&line->ts[3-1].trau.demux, 2);
-	subch_demux_activate(&line->ts[3-1].trau.demux, 3);
+	subch_demux_activate(&line->ts[base_ts+3-1].trau.demux, 0);
+	subch_demux_activate(&line->ts[base_ts+3-1].trau.demux, 1);
+	subch_demux_activate(&line->ts[base_ts+3-1].trau.demux, 2);
+	subch_demux_activate(&line->ts[base_ts+3-1].trau.demux, 3);
 
 	trx = gsm_bts_trx_num(bts, 1);
 	if (trx) {
 		/* create E1 timeslots for TRAU frames of TRX1 */
-		e1inp_ts_config(&line->ts[4-1], line, E1INP_TS_TYPE_TRAU);
-		e1inp_ts_config(&line->ts[5-1], line, E1INP_TS_TYPE_TRAU);
+		e1inp_ts_config(&line->ts[base_ts+4-1], line, E1INP_TS_TYPE_TRAU);
+		e1inp_ts_config(&line->ts[base_ts+5-1], line, E1INP_TS_TYPE_TRAU);
 
 		/* create RSL signalling link for TRX1 */
-		sign_ts = &line->ts[1-1];
+		sign_ts = &line->ts[base_ts+1-1];
 		rsl_link = e1inp_sign_link_create(sign_ts, E1INP_SIGN_RSL,
 					  trx, TEI_RSL+1, SAPI_RSL);
 		/* create back-links from trx */
 		trx->rsl_link = rsl_link;
 
 		/* enable subchannel demuxer on TS2 */
-		subch_demux_activate(&line->ts[4-1].trau.demux, 0);
-		subch_demux_activate(&line->ts[4-1].trau.demux, 1);
-		subch_demux_activate(&line->ts[4-1].trau.demux, 2);
-		subch_demux_activate(&line->ts[4-1].trau.demux, 3);
+		subch_demux_activate(&line->ts[base_ts+4-1].trau.demux, 0);
+		subch_demux_activate(&line->ts[base_ts+4-1].trau.demux, 1);
+		subch_demux_activate(&line->ts[base_ts+4-1].trau.demux, 2);
+		subch_demux_activate(&line->ts[base_ts+4-1].trau.demux, 3);
 
 		/* enable subchannel demuxer on TS3 */
-		subch_demux_activate(&line->ts[5-1].trau.demux, 0);
-		subch_demux_activate(&line->ts[5-1].trau.demux, 1);
-		subch_demux_activate(&line->ts[5-1].trau.demux, 2);
-		subch_demux_activate(&line->ts[5-1].trau.demux, 3);
+		subch_demux_activate(&line->ts[base_ts+5-1].trau.demux, 0);
+		subch_demux_activate(&line->ts[base_ts+5-1].trau.demux, 1);
+		subch_demux_activate(&line->ts[base_ts+5-1].trau.demux, 2);
+		subch_demux_activate(&line->ts[base_ts+5-1].trau.demux, 3);
 	}
 
 	return mi_setup(cardnr, line, release_l2);
diff --git a/openbsc/src/gsm_data.c b/openbsc/src/gsm_data.c
index c21c6b4..285b758 100644
--- a/openbsc/src/gsm_data.c
+++ b/openbsc/src/gsm_data.c
@@ -117,7 +117,7 @@
 		}
 	}
 
-	llist_add(&trx->list, &bts->trx_list);
+	llist_add_tail(&trx->list, &bts->trx_list);
 
 	return trx;
 }
@@ -147,7 +147,7 @@
 	}
 	bts->c0->ts[0].pchan = GSM_PCHAN_CCCH_SDCCH4;
 
-	llist_add(&bts->list, &net->bts_list);
+	llist_add_tail(&bts->list, &net->bts_list);
 
 	return bts;
 }
@@ -270,15 +270,15 @@
 {
 	switch (band) {
 	case GSM_BAND_400:
-		return "GSM 400";
+		return "GSM400";
 	case GSM_BAND_850:
-		return "GSM 850";
+		return "GSM850";
 	case GSM_BAND_900:
-		return "GSM 900";
+		return "GSM900";
 	case GSM_BAND_1800:
-		return "DCS 1800";
+		return "DCS1800";
 	case GSM_BAND_1900:
-		return "PCS 1900";
+		return "PCS1900";
 	}
 	return "invalid";
 }
diff --git a/openbsc/src/input/misdn.c b/openbsc/src/input/misdn.c
index a04c2ab..2ec74b8 100644
--- a/openbsc/src/input/misdn.c
+++ b/openbsc/src/input/misdn.c
@@ -477,14 +477,7 @@
 	int sk, ret, cnt;
 	struct mISDN_devinfo devinfo;
 
-	/* register the driver with the core */
-	/* FIXME: do this in the plugin initializer function */
-	ret = e1inp_driver_register(&misdn_driver);
-	if (ret)
-		return ret;
-
 	/* create the actual line instance */
-	/* FIXME: do this independent of driver registration */
 	e1h = talloc(tall_bsc_ctx, struct mi_e1_handle);
 	memset(e1h, 0, sizeof(*e1h));
 
@@ -531,14 +524,15 @@
 		return -EINVAL;
 	}
 
-	if (devinfo.nrbchan != 30) {
-		fprintf(stderr, "error: E1 card has no 30 B-channels\n");
-		return -EINVAL;
-	}
-
 	ret = mi_e1_setup(line, release_l2);
 	if (ret)
 		return ret;
 
 	return e1inp_line_register(line);
 }
+
+static __attribute__((constructor)) void on_dso_load_sms(void)
+{
+	/* register the driver with the core */
+	e1inp_driver_register(&misdn_driver);
+}
diff --git a/openbsc/src/vty/command.c b/openbsc/src/vty/command.c
index e9b3652..44bdf26 100644
--- a/openbsc/src/vty/command.c
+++ b/openbsc/src/vty/command.c
@@ -34,6 +34,7 @@
 #include <ctype.h>
 #include <time.h>
 #include <sys/time.h>
+#include <sys/stat.h>
 
 //#include "memory.h"
 //#include "log.h"
@@ -474,6 +475,7 @@
 	cmd->cmdsize = cmd_cmdsize(cmd->strvec);
 }
 
+#ifdef VTY_CRYPT_PW
 static unsigned char itoa64[] =
     "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
 
@@ -499,6 +501,7 @@
 
 	return crypt(passwd, salt);
 }
+#endif
 
 /* This function write configuration of this host. */
 static int config_write_host(struct vty *vty)
@@ -2216,7 +2219,6 @@
 	return (*matched_element->func) (matched_element, vty, argc, argv);
 }
 
-#if 0
 /* Configration make from file. */
 int config_from_file(struct vty *vty, FILE * fp)
 {
@@ -2248,7 +2250,6 @@
 	}
 	return CMD_SUCCESS;
 }
-#endif
 
 /* Configration from terminal */
 DEFUN(config_terminal,
@@ -2445,7 +2446,6 @@
 	return CMD_SUCCESS;
 }
 
-#if 0
 /* Write current configuration into file. */
 DEFUN(config_write_file,
       config_write_file_cmd,
@@ -2549,7 +2549,7 @@
 
 	if (chmod(config_file, CONFIGFILE_MASK) != 0) {
 		vty_out(vty, "Can't chmod configuration file %s: %s (%d).%s",
-			config_file, safe_strerror(errno), errno, VTY_NEWLINE);
+			config_file, strerror(errno), errno, VTY_NEWLINE);
 		return CMD_WARNING;
 	}
 
@@ -2640,7 +2640,6 @@
 
 	return CMD_SUCCESS;
 }
-#endif
 
 /* Hostname configuration */
 DEFUN(config_hostname,
@@ -3329,13 +3328,11 @@
 	install_element(node, &config_help_cmd);
 	install_element(node, &config_list_cmd);
 
-#if 0
 	install_element(node, &config_write_terminal_cmd);
 	install_element(node, &config_write_file_cmd);
 	install_element(node, &config_write_memory_cmd);
 	install_element(node, &config_write_cmd);
 	install_element(node, &show_running_config_cmd);
-#endif
 }
 
 /* Initialize command interface. Install basic nodes and commands. */
@@ -3379,9 +3376,9 @@
 		install_default(ENABLE_NODE);
 		install_element(ENABLE_NODE, &config_disable_cmd);
 		install_element(ENABLE_NODE, &config_terminal_cmd);
-		//install_element (ENABLE_NODE, &copy_runningconfig_startupconfig_cmd);
+		install_element (ENABLE_NODE, &copy_runningconfig_startupconfig_cmd);
 	}
-	//install_element (ENABLE_NODE, &show_startup_config_cmd);
+	install_element (ENABLE_NODE, &show_startup_config_cmd);
 	install_element(ENABLE_NODE, &show_version_cmd);
 
 	if (terminal) {
diff --git a/openbsc/src/vty_interface.c b/openbsc/src/vty_interface.c
index 11b2ff6..b480c3d 100644
--- a/openbsc/src/vty_interface.c
+++ b/openbsc/src/vty_interface.c
@@ -157,6 +157,56 @@
 	return CMD_SUCCESS;
 }
 
+static void config_write_ts_single(struct vty *vty, struct gsm_bts_trx_ts *ts)
+{
+	vty_out(vty, "\t\tts %u%s", ts->nr, VTY_NEWLINE);
+	vty_out(vty, "\t\t\tphys_chan_config %s%s", gsm_pchan_name(ts->pchan),
+		VTY_NEWLINE);
+	vty_out(vty, "\t\t\te1_subslot %u %u %u%s", ts->e1_link.e1_nr,
+		ts->e1_link.e1_ts, ts->e1_link.e1_ts_ss, VTY_NEWLINE);
+}
+
+static void config_write_trx_single(struct vty *vty, struct gsm_bts_trx *trx)
+{
+	int i;
+
+	vty_out(vty, "\ttrx %u%s", trx->nr, VTY_NEWLINE);
+	vty_out(vty, "\t\tarfcn %u%s", trx->arfcn, VTY_NEWLINE);
+	vty_out(vty, "\t\tmax_power_red %u%s", trx->max_power_red, VTY_NEWLINE);
+
+	for (i = 0; i < TRX_NR_TS; i++)
+		config_write_ts_single(vty, &trx->ts[i]);
+}
+
+static void config_write_bts_single(struct vty *vty, struct gsm_bts *bts)
+{
+	struct gsm_bts_trx *trx;
+
+	vty_out(vty, "bts %u%s", bts->nr, VTY_NEWLINE);
+	vty_out(vty, "\ttype %s%s", btstype2str(bts->type), VTY_NEWLINE);
+	vty_out(vty, "\tband %s%s", gsm_band_name(bts->band), VTY_NEWLINE);
+	vty_out(vty, "\tlocation_area_code %u%s", bts->location_area_code,
+		VTY_NEWLINE);
+	vty_out(vty, "\ttraining_sequence_code %u%s", bts->tsc, VTY_NEWLINE);
+	vty_out(vty, "\tbase_station_id_code %u%s", bts->bsic, VTY_NEWLINE);
+	vty_out(vty, "\tunit_id %u %u%s",
+		bts->ip_access.site_id, bts->ip_access.bts_id, VTY_NEWLINE);
+
+	llist_for_each_entry(trx, &bts->trx_list, list)
+		config_write_trx_single(vty, trx);
+}
+
+static int config_write_bts(struct vty *v)
+{
+	struct gsm_bts *bts;
+
+	llist_for_each_entry(bts, &gsmnet->bts_list, list)
+		config_write_bts_single(v, bts);
+
+	return CMD_SUCCESS;
+}
+
+
 static void trx_dump_vty(struct vty *vty, struct gsm_bts_trx *trx)
 {
 	vty_out(vty, "TRX %u of BTS %u is on ARFCN %u%s",
@@ -224,6 +274,7 @@
 	return CMD_SUCCESS;
 }
 
+
 static void ts_dump_vty(struct vty *vty, struct gsm_bts_trx_ts *ts)
 {
 	struct in_addr ia;
@@ -942,7 +993,7 @@
 	install_element(VIEW_NODE, &show_subscr_cmd);
 
 	install_element(CONFIG_NODE, &cfg_bts_cmd);
-	install_node(&bts_node, dummy_config_write);
+	install_node(&bts_node, config_write_bts);
 	install_default(BTS_NODE);
 	install_element(BTS_NODE, &cfg_bts_type_cmd);
 	install_element(BTS_NODE, &cfg_bts_band_cmd);