switch to dynamically allocated BTS and TRX data structures

This makes it much easier to do run-time configuration using the vty
interface.
diff --git a/openbsc/src/abis_nm.c b/openbsc/src/abis_nm.c
index bd3ba19..5040541 100644
--- a/openbsc/src/abis_nm.c
+++ b/openbsc/src/abis_nm.c
@@ -544,19 +544,19 @@
 	case NM_OC_RADIO_CARRIER:
 		if (obj_inst->trx_nr >= bts->num_trx)
 			return NULL;
-		trx = &bts->trx[obj_inst->trx_nr];
+		trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
 		nm_state = &trx->nm_state;
 		break;
 	case NM_OC_BASEB_TRANSC:
 		if (obj_inst->trx_nr >= bts->num_trx)
 			return NULL;
-		trx = &bts->trx[obj_inst->trx_nr];
+		trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
 		nm_state = &trx->bb_transc.nm_state;
 		break;
 	case NM_OC_CHANNEL:
 		if (obj_inst->trx_nr > bts->num_trx)
 			return NULL;
-		trx = &bts->trx[obj_inst->trx_nr];
+		trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
 		if (obj_inst->ts_nr >= TRX_NR_TS)
 			return NULL;
 		nm_state = &trx->ts[obj_inst->ts_nr].nm_state;
@@ -572,13 +572,13 @@
 		case BS11_OBJ_BBSIG:
 			if (obj_inst->ts_nr > bts->num_trx)
 				return NULL;
-			trx = &bts->trx[obj_inst->ts_nr];
+			trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
 			nm_state = &trx->bs11.bbsig.nm_state;
 			break;
 		case BS11_OBJ_PA:
 			if (obj_inst->ts_nr > bts->num_trx)
 				return NULL;
-			trx = &bts->trx[obj_inst->ts_nr];
+			trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
 			nm_state = &trx->bs11.pa.nm_state;
 			break;
 		default:
@@ -611,19 +611,19 @@
 	case NM_OC_RADIO_CARRIER:
 		if (obj_inst->trx_nr >= bts->num_trx)
 			return NULL;
-		trx = &bts->trx[obj_inst->trx_nr];
+		trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
 		obj = trx;
 		break;
 	case NM_OC_BASEB_TRANSC:
 		if (obj_inst->trx_nr >= bts->num_trx)
 			return NULL;
-		trx = &bts->trx[obj_inst->trx_nr];
+		trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
 		obj = &trx->bb_transc;
 		break;
 	case NM_OC_CHANNEL:
 		if (obj_inst->trx_nr > bts->num_trx)
 			return NULL;
-		trx = &bts->trx[obj_inst->trx_nr];
+		trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
 		if (obj_inst->ts_nr >= TRX_NR_TS)
 			return NULL;
 		obj = &trx->ts[obj_inst->ts_nr];
diff --git a/openbsc/src/bs11_config.c b/openbsc/src/bs11_config.c
index 386b865..0fb7cd7 100644
--- a/openbsc/src/bs11_config.c
+++ b/openbsc/src/bs11_config.c
@@ -94,7 +94,7 @@
 
 	abis_nm_bs11_conn_oml_tei(bts, 0, 1, 0xff, TEI_OML);
 
-	abis_nm_bs11_set_trx_power(&bts->trx[0], BS11_TRX_POWER_GSM_30mW);
+	abis_nm_bs11_set_trx_power(bts->c0, BS11_TRX_POWER_GSM_30mW);
 	
 	sleep(1);
 
@@ -109,6 +109,10 @@
 {
 	u_int8_t bbsig1_attr[sizeof(obj_bbsig0_attr)+12];
 	u_int8_t *cur = bbsig1_attr;
+	struct gsm_bts_trx *trx = gsm_bts_trx_num(bts, 1);
+
+	if (!trx)
+		trx = gsm_bts_trx_alloc(bts);
 
 	fprintf(stdout, "Crating Objects for TRX1\n");
 
@@ -123,7 +127,7 @@
 				   sizeof(bbsig1_attr), bbsig1_attr);
 	abis_nm_bs11_create_object(bts, BS11_OBJ_PA, 1,
 				   sizeof(obj_pa0_attr), obj_pa0_attr);
-	abis_nm_bs11_set_trx_power(&bts->trx[1], BS11_TRX_POWER_GSM_30mW);
+	abis_nm_bs11_set_trx_power(trx, BS11_TRX_POWER_GSM_30mW);
 	
 	return 0;
 }
@@ -437,13 +441,17 @@
 
 static void cmd_query(void)
 {
+	struct gsm_bts_trx *trx = g_bts->c0;
+
 	bs11cfg_state = STATE_QUERY;
 	abis_nm_bs11_get_serno(g_bts);
 	abis_nm_bs11_get_oml_tei_ts(g_bts);
 	abis_nm_bs11_get_pll_mode(g_bts);
 	abis_nm_bs11_get_cclk(g_bts);
-	abis_nm_bs11_get_trx_power(&g_bts->trx[0]);
-	abis_nm_bs11_get_trx_power(&g_bts->trx[1]);
+	abis_nm_bs11_get_trx_power(trx);
+	trx = gsm_bts_trx_num(g_bts, 1);
+	if (trx)
+		abis_nm_bs11_get_trx_power(trx);
 	sleep(1);
 	abis_nm_bs11_factory_logon(g_bts, 0);
 	command = NULL;
@@ -775,12 +783,13 @@
 
 	handle_options(argc, argv);
 
-	gsmnet = gsm_network_init(1, 1, 1, GSM_BTS_TYPE_BS11, NULL);
+	gsmnet = gsm_network_init(1, 1, NULL);
 	if (!gsmnet) {
 		fprintf(stderr, "Unable to allocate gsm network\n");
 		exit(1);
 	}
-	g_bts = &gsmnet->bts[0];
+	g_bts = gsm_bts_alloc(gsmnet, GSM_BTS_TYPE_BS11, HARDCODED_TSC,
+				HARDCODED_BSIC);
 
 	rc = rs232_setup(serial_port, delay_ms, g_bts);
 	if (rc < 0) {
diff --git a/openbsc/src/bsc_hack.c b/openbsc/src/bsc_hack.c
index ae67ade..e3e3a40 100644
--- a/openbsc/src/bsc_hack.c
+++ b/openbsc/src/bsc_hack.c
@@ -490,7 +490,7 @@
 
 static void bootstrap_om_bs11(struct gsm_bts *bts)
 {
-	struct gsm_bts_trx *trx = &bts->trx[0];
+	struct gsm_bts_trx *trx = bts->c0;
 
 	/* stop sending event reports */
 	abis_nm_event_reports(bts, 0);
@@ -608,10 +608,11 @@
 
 static int shutdown_net(struct gsm_network *net)
 {
-	int i;
-	for (i = 0; i < net->num_bts; i++) {
+	struct gsm_bts *bts;
+
+	llist_for_each_entry(bts, &net->bts_list, list) {
 		int rc;
-		rc = shutdown_om(&net->bts[i]);
+		rc = shutdown_om(bts);
 		if (rc < 0)
 			return rc;
 	}
@@ -849,8 +850,8 @@
  */
 static void patch_tables(struct gsm_bts *bts)
 {
-	u_int8_t arfcn_low = bts->trx[0].arfcn & 0xff;
-	u_int8_t arfcn_high = (bts->trx[0].arfcn >> 8) & 0x0f;
+	u_int8_t arfcn_low = bts->c0->arfcn & 0xff;
+	u_int8_t arfcn_high = (bts->c0->arfcn >> 8) & 0x0f;
 	/* covert the raw packet to the struct */
 	struct gsm48_system_information_type_3 *type_3 =
 		(struct gsm48_system_information_type_3*)&si3;
@@ -933,7 +934,7 @@
 {
 	bts->band = BAND;
 	bts->location_area_code = LAC;
-	bts->trx[0].arfcn = ARFCN;
+	bts->c0->arfcn = ARFCN;
 
 	/* Control Channel Description */
 	memset(&bts->chan_desc, 0, sizeof(struct gsm48_control_channel_descr));
@@ -947,7 +948,7 @@
 	paging_init(bts);
 
 	if (bts->type == GSM_BTS_TYPE_BS11) {
-		struct gsm_bts_trx *trx = &bts->trx[0];
+		struct gsm_bts_trx *trx = bts->c0;
 		set_ts_e1link(&trx->ts[0], 0, 1, 0xff);
 		set_ts_e1link(&trx->ts[1], 0, 2, 1);
 		set_ts_e1link(&trx->ts[2], 0, 2, 2);
@@ -998,14 +999,14 @@
 	}
 
 	/* initialize our data structures */
-	gsmnet = gsm_network_init(2, BTS_TYPE, MCC, MNC, mncc_recv);
+	gsmnet = gsm_network_init(MCC, MNC, mncc_recv);
 	if (!gsmnet)
 		return -ENOMEM;
 
 	gsmnet->name_long = "OpenBSC";
 	gsmnet->name_short = "OpenBSC";
 
-	bts = &gsmnet->bts[0];
+	bts = gsm_bts_alloc(gsmnet, BTS_TYPE, HARDCODED_TSC, HARDCODED_BSIC);
 	bootstrap_bts(bts);
 
 	if (db_init(database_name)) {
@@ -1033,7 +1034,7 @@
 		bts->ip_access.site_id = 1801;
 		bts->ip_access.bts_id = 0;
 
-		bts = &gsmnet->bts[1];
+		bts = gsm_bts_alloc(gsmnet, BTS_TYPE, HARDCODED_TSC, HARDCODED_BSIC);
 		bootstrap_bts(bts);
 		bts->ip_access.site_id = 1800;
 		bts->ip_access.bts_id = 0;
diff --git a/openbsc/src/chan_alloc.c b/openbsc/src/chan_alloc.c
index 96632bc..241d589 100644
--- a/openbsc/src/chan_alloc.c
+++ b/openbsc/src/chan_alloc.c
@@ -38,7 +38,7 @@
 struct gsm_bts_trx_ts *ts_c0_alloc(struct gsm_bts *bts,
 				   enum gsm_phys_chan_config pchan)
 {
-	struct gsm_bts_trx *trx = &bts->trx[0];	
+	struct gsm_bts_trx *trx = bts->c0;
 	struct gsm_bts_trx_ts *ts = &trx->ts[0];
 
 	if (pchan != GSM_PCHAN_CCCH &&
@@ -68,7 +68,7 @@
 {
 	int i, j;
 	for (i = 0; i < bts->num_trx; i++) {
-		struct gsm_bts_trx *trx = &bts->trx[i];
+		struct gsm_bts_trx *trx = gsm_bts_trx_num(bts, i);
 		int from, to;
 
 		/* the following constraints are pure policy,
@@ -124,7 +124,7 @@
 	struct gsm_bts_trx_ts *ts;
 	int i, j, ss;
 	for (i = 0; i < bts->num_trx; i++) {
-		trx = &bts->trx[i];
+		trx = gsm_bts_trx_num(bts, i);
 		for (j = 0; j < 8; j++) {
 			ts = &trx->ts[j];
 			if (ts->pchan != pchan)
@@ -239,13 +239,14 @@
 }
 
 struct gsm_lchan* lchan_find(struct gsm_bts *bts, struct gsm_subscriber *subscr) {
-	int trx, ts_no, lchan_no; 
+	struct gsm_bts_trx *trx;
+	int ts_no, lchan_no; 
 
-	for (trx = 0; trx < bts->num_trx; ++trx) {
+	llist_for_each_entry(trx, &bts->trx_list, list) {
 		for (ts_no = 0; ts_no < 8; ++ts_no) {
 			for (lchan_no = 0; lchan_no < TS_MAX_LCHAN; ++lchan_no) {
 				struct gsm_lchan *lchan =
-					&bts->trx[trx].ts[ts_no].lchan[lchan_no];
+					&trx->ts[ts_no].lchan[lchan_no];
 				if (subscr == lchan->subscr)
 					return lchan;
 			}
diff --git a/openbsc/src/gsm_04_08.c b/openbsc/src/gsm_04_08.c
index 49234f8..c081b45 100644
--- a/openbsc/src/gsm_04_08.c
+++ b/openbsc/src/gsm_04_08.c
@@ -3444,9 +3444,9 @@
 		trans->subscr = subscr;
 		/* Find lchan */
 		for (i = 0; i < net->num_bts; i++) {
-			bts = &net->bts[i];
+			bts = gsm_bts_num(net, i);
 			for (j = 0; j < bts->num_trx; j++) {
-				trx = &bts->trx[j];
+				trx = gsm_bts_trx_num(bts, j);
 				for (k = 0; k < TRX_NR_TS; k++) {
 					ts = &trx->ts[k];
 					for (l = 0; l < TS_MAX_LCHAN; l++) {
diff --git a/openbsc/src/gsm_data.c b/openbsc/src/gsm_data.c
index 80020e5..81facdf 100644
--- a/openbsc/src/gsm_data.c
+++ b/openbsc/src/gsm_data.c
@@ -25,6 +25,7 @@
 #include <errno.h>
 
 #include <openbsc/gsm_data.h>
+#include <openbsc/talloc.h>
 
 void set_ts_e1link(struct gsm_bts_trx_ts *ts, u_int8_t e1_nr,
 		   u_int8_t e1_ts, u_int8_t e1_ts_ss)
@@ -84,76 +85,124 @@
 	return chreq_names[c];
 }
 
-struct gsm_network *gsm_network_init(unsigned int num_bts, enum gsm_bts_type bts_type,
-				     u_int16_t country_code, u_int16_t network_code,
-				     int (*mncc_recv)(struct gsm_network *, int, void *))
+struct gsm_bts_trx *gsm_bts_trx_alloc(struct gsm_bts *bts)
 {
-	int i;
-	struct gsm_network *net;
+	struct gsm_bts_trx *trx = talloc(bts, struct gsm_bts_trx);
+	int k;
 
-	if (num_bts > GSM_MAX_BTS)
+	if (!trx)
 		return NULL;
 
-	net = malloc(sizeof(*net));
+	memset(trx, 0, sizeof(*trx));
+	trx->bts = bts;
+	trx->nr = bts->num_trx++;
+
+	for (k = 0; k < TRX_NR_TS; k++) {
+		struct gsm_bts_trx_ts *ts = &trx->ts[k];
+		int l;
+		
+		ts->trx = trx;
+		ts->nr = k;
+		ts->pchan = GSM_PCHAN_NONE;
+
+		for (l = 0; l < TS_MAX_LCHAN; l++) {
+			struct gsm_lchan *lchan;
+			lchan = &ts->lchan[l];
+
+			lchan->ts = ts;
+			lchan->nr = l;
+			lchan->type = GSM_LCHAN_NONE;
+		}
+	}
+
+	llist_add(&trx->list, &bts->trx_list);
+
+	return trx;
+}
+
+struct gsm_bts *gsm_bts_alloc(struct gsm_network *net, enum gsm_bts_type type,
+			      u_int8_t tsc, u_int8_t bsic)
+{
+	struct gsm_bts *bts = talloc(net, struct gsm_bts);
+
+	if (!bts)
+		return NULL;
+
+	memset(bts, 0, sizeof(*bts));
+	bts->network = net;
+	bts->nr = net->num_bts++;
+	bts->type = type;
+	bts->tsc = tsc;
+	bts->bsic = bsic;
+	bts->num_trx = 0;
+	INIT_LLIST_HEAD(&bts->trx_list);
+
+	/* create our primary TRX */
+	bts->c0 = gsm_bts_trx_alloc(bts);
+	if (!bts->c0) {
+		talloc_free(bts);
+		return NULL;
+	}
+	bts->c0->ts[0].pchan = GSM_PCHAN_CCCH_SDCCH4;
+
+	llist_add(&bts->list, &net->bts_list);
+
+	return bts;
+}
+
+struct gsm_network *gsm_network_init(u_int16_t country_code, u_int16_t network_code,
+				     int (*mncc_recv)(struct gsm_network *, int, void *))
+{
+	struct gsm_network *net;
+
+	net = talloc(tall_bsc_ctx, struct gsm_network);
 	if (!net)
 		return NULL;
 	memset(net, 0, sizeof(*net));	
 
 	net->country_code = country_code;
 	net->network_code = network_code;
-	net->num_bts = num_bts;
+	net->num_bts = 0;
 
 	INIT_LLIST_HEAD(&net->trans_list);
 	INIT_LLIST_HEAD(&net->upqueue);
+	INIT_LLIST_HEAD(&net->bts_list);
 
 	net->mncc_recv = mncc_recv;
 
-	for (i = 0; i < num_bts; i++) {
-		struct gsm_bts *bts = &net->bts[i];
-		int j;
-		
-		bts->network = net;
-		bts->nr = i;
-		bts->type = bts_type;
-		bts->tsc = HARDCODED_TSC;
-		bts->bsic = HARDCODED_BSIC;
-
-		for (j = 0; j < BTS_MAX_TRX; j++) {
-			struct gsm_bts_trx *trx = &bts->trx[j];
-			int k;
-
-			trx->bts = bts;
-			trx->nr = j;
-
-			for (k = 0; k < TRX_NR_TS; k++) {
-				struct gsm_bts_trx_ts *ts = &trx->ts[k];
-				int l;
-				
-				ts->trx = trx;
-				ts->nr = k;
-				ts->pchan = GSM_PCHAN_NONE;
-
-				for (l = 0; l < TS_MAX_LCHAN; l++) {
-					struct gsm_lchan *lchan;
-					lchan = &ts->lchan[l];
-
-					lchan->ts = ts;
-					lchan->nr = l;
-					lchan->type = GSM_LCHAN_NONE;
-				}
-			}
-		}
-
-		bts->num_trx = 1;	/* FIXME */
-#ifdef HAVE_TRX1
-		bts->num_trx++;
-#endif
-		bts->c0 = &bts->trx[0];
-		bts->c0->ts[0].pchan = GSM_PCHAN_CCCH_SDCCH4;
-	}
 	return net;
 }
 
+struct gsm_bts *gsm_bts_num(struct gsm_network *net, int num)
+{
+	struct gsm_bts *bts;
+
+	if (num >= net->num_bts)
+		return NULL;
+
+	llist_for_each_entry(bts, &net->bts_list, list) {
+		if (bts->nr == num)
+			return bts;
+	}
+
+	return NULL;
+}
+
+struct gsm_bts_trx *gsm_bts_trx_num(struct gsm_bts *bts, int num)
+{
+	struct gsm_bts_trx *trx;
+
+	if (num >= bts->num_trx)
+		return NULL;
+
+	llist_for_each_entry(trx, &bts->trx_list, list) {
+		if (trx->nr == num)
+			return trx;
+	}
+
+	return NULL;
+}
+
 static char ts2str[255];
 
 char *gsm_ts_name(struct gsm_bts_trx_ts *ts)
@@ -201,7 +250,7 @@
 		skip = 1;
 
 	for (i = 0; i < net->num_bts; i++) {
-		bts = &net->bts[i];
+		bts = gsm_bts_num(net, i);
 
 		if (skip) {
 			if (start_bts == bts)
diff --git a/openbsc/src/input/ipaccess.c b/openbsc/src/input/ipaccess.c
index ccc178d..c16bf1b 100644
--- a/openbsc/src/input/ipaccess.c
+++ b/openbsc/src/input/ipaccess.c
@@ -112,10 +112,10 @@
 struct gsm_bts *find_bts_by_unitid(struct gsm_network *net,
 				   u_int16_t site_id, u_int16_t bts_id)
 {
+	struct gsm_bts *bts;
 	int i;
 
-	for (i = 0; i < net->num_bts; i++) {
-		struct gsm_bts *bts = &net->bts[i];
+	llist_for_each_entry(bts, &net->bts_list, list) {
 
 		if (!is_ipaccess_bts(bts))
 			continue;
diff --git a/openbsc/src/ipaccess-config.c b/openbsc/src/ipaccess-config.c
index cc8a6c9..d3f3176 100644
--- a/openbsc/src/ipaccess-config.c
+++ b/openbsc/src/ipaccess-config.c
@@ -170,11 +170,12 @@
 		exit(2);
 	}
 
-	gsmnet = gsm_network_init(1, GSM_BTS_TYPE_NANOBTS_900, 1, 1, NULL);
+	gsmnet = gsm_network_init(1, 1, NULL);
 	if (!gsmnet)
 		exit(1);
 
-	bts = &gsmnet->bts[0];
+	bts = gsm_bts_alloc(gsmnet, GSM_BTS_TYPE_NANOBTS_900, HARDCODED_TSC,
+				HARDCODED_BSIC);
 	
 	printf("Trying to connect to ip.access BTS ...\n");
 
diff --git a/openbsc/src/vty_interface.c b/openbsc/src/vty_interface.c
index 1b60046..12d5ae9 100644
--- a/openbsc/src/vty_interface.c
+++ b/openbsc/src/vty_interface.c
@@ -147,12 +147,12 @@
 				VTY_NEWLINE);
 			return CMD_WARNING;
 		}
-		bts_dump_vty(vty, &net->bts[bts_nr]);
+		bts_dump_vty(vty, gsm_bts_num(net, bts_nr));
 		return CMD_SUCCESS;
 	}
 	/* print all BTS's */
 	for (bts_nr = 0; bts_nr < net->num_bts; bts_nr++)
-		bts_dump_vty(vty, &net->bts[bts_nr]);
+		bts_dump_vty(vty, gsm_bts_num(net, bts_nr));
 
 	return CMD_SUCCESS;
 }
@@ -191,7 +191,7 @@
 				VTY_NEWLINE);
 			return CMD_WARNING;
 		}
-		bts = &net->bts[bts_nr];
+		bts = gsm_bts_num(net, bts_nr);
 	}
 	if (argc >= 2) {
 		trx_nr = atoi(argv[1]);
@@ -200,23 +200,23 @@
 				VTY_NEWLINE);
 			return CMD_WARNING;
 		}
-		trx = &bts->trx[trx_nr];
+		trx = gsm_bts_trx_num(bts, trx_nr);
 		trx_dump_vty(vty, trx);
 		return CMD_SUCCESS;
 	}
 	if (bts) {
 		/* print all TRX in this BTS */
 		for (trx_nr = 0; trx_nr < bts->num_trx; trx_nr++) {
-			trx = &bts->trx[trx_nr];
+			trx = gsm_bts_trx_num(bts, trx_nr);
 			trx_dump_vty(vty, trx);
 		}
 		return CMD_SUCCESS;
 	}
 
 	for (bts_nr = 0; bts_nr < net->num_bts; bts_nr++) {
-		bts = &net->bts[bts_nr];
+		bts = gsm_bts_num(net, bts_nr);
 		for (trx_nr = 0; trx_nr < bts->num_trx; trx_nr++) {
-			trx = &bts->trx[trx_nr];
+			trx = gsm_bts_trx_num(bts, trx_nr);
 			trx_dump_vty(vty, trx);
 		}
 	}
@@ -265,7 +265,7 @@
 				VTY_NEWLINE);
 			return CMD_WARNING;
 		}
-		bts = &net->bts[bts_nr];
+		bts = gsm_bts_num(net, bts_nr);
 	}
 	if (argc >= 2) {
 		trx_nr = atoi(argv[1]);
@@ -274,7 +274,7 @@
 				VTY_NEWLINE);
 			return CMD_WARNING;
 		}
-		trx = &bts->trx[trx_nr];
+		trx = gsm_bts_trx_num(bts, trx_nr);
 	}
 	if (argc >= 3) {
 		ts_nr = atoi(argv[2]);
@@ -288,9 +288,9 @@
 		return CMD_SUCCESS;
 	}
 	for (bts_nr = 0; bts_nr < net->num_bts; bts_nr++) {
-		bts = &net->bts[bts_nr];
+		bts = gsm_bts_num(net, bts_nr);
 		for (trx_nr = 0; trx_nr < bts->num_trx; trx_nr++) {
-			trx = &bts->trx[trx_nr];
+			trx = gsm_bts_trx_num(bts, trx_nr);
 			for (ts_nr = 0; ts_nr < TRX_NR_TS; ts_nr++) {
 				ts = &trx->ts[ts_nr];
 				ts_dump_vty(vty, ts);
@@ -379,7 +379,7 @@
 				VTY_NEWLINE);
 			return CMD_WARNING;
 		}
-		bts = &net->bts[bts_nr];
+		bts = gsm_bts_num(net, bts_nr);
 	}
 	if (argc >= 2) {
 		trx_nr = atoi(argv[1]);
@@ -388,7 +388,7 @@
 				VTY_NEWLINE);
 			return CMD_WARNING;
 		}
-		trx = &bts->trx[trx_nr];
+		trx = gsm_bts_trx_num(bts, trx_nr);
 	}
 	if (argc >= 3) {
 		ts_nr = atoi(argv[2]);
@@ -411,9 +411,9 @@
 		return CMD_SUCCESS;
 	}
 	for (bts_nr = 0; bts_nr < net->num_bts; bts_nr++) {
-		bts = &net->bts[bts_nr];
+		bts = gsm_bts_num(net, bts_nr);
 		for (trx_nr = 0; trx_nr < bts->num_trx; trx_nr++) {
-			trx = &bts->trx[trx_nr];
+			trx = gsm_bts_trx_num(bts, trx_nr);
 			for (ts_nr = 0; ts_nr < TRX_NR_TS; ts_nr++) {
 				ts = &trx->ts[ts_nr];
 				for (lchan_nr = 0; lchan_nr < TS_MAX_LCHAN;
@@ -567,13 +567,13 @@
 				VTY_NEWLINE);
 			return CMD_WARNING;
 		}
-		bts = &net->bts[bts_nr];
+		bts = gsm_bts_num(net, bts_nr);
 		bts_paging_dump_vty(vty, bts);
 		
 		return CMD_SUCCESS;
 	}
 	for (bts_nr = 0; bts_nr < net->num_bts; bts_nr++) {
-		bts = &net->bts[bts_nr];
+		bts = gsm_bts_num(net, bts_nr);
 		bts_paging_dump_vty(vty, bts);
 	}
 
@@ -612,14 +612,19 @@
 	int bts_nr = atoi(argv[0]);
 	struct gsm_bts *bts;
 
-	if (bts_nr >= GSM_MAX_BTS) {
-		vty_out(vty, "%% This Version of OpenBSC only supports %u BTS%s",
-			GSM_MAX_BTS, VTY_NEWLINE);
+	if (bts_nr > gsmnet->num_bts) {
+		vty_out(vty, "%% The next unused BTS number is %u%s",
+			gsmnet->num_bts, VTY_NEWLINE);
 		return CMD_WARNING;
-	}
-	bts = &gsmnet->bts[bts_nr];
-	if (bts_nr >= gsmnet->num_bts)
-		gsmnet->num_bts = bts_nr + 1;
+	} else if (bts_nr == gsmnet->num_bts) {
+		/* allocate a new one */
+		bts = gsm_bts_alloc(gsmnet, GSM_BTS_TYPE_UNKNOWN,
+				    HARDCODED_TSC, HARDCODED_BSIC);
+	} else 
+		bts = gsm_bts_num(gsmnet, bts_nr);
+
+	if (!bts)
+		return CMD_WARNING;
 
 	vty->index = bts;
 	vty->node = BTS_NODE;
@@ -748,16 +753,18 @@
 	struct gsm_bts *bts = vty->index;
 	struct gsm_bts_trx *trx;
 
-	if (trx_nr > BTS_MAX_TRX) {
-		vty_out(vty, "%% This version of OpenBSC only supports %u TRX%s",
-			BTS_MAX_TRX+1, VTY_NEWLINE);
+	if (trx_nr > bts->num_trx) {
+		vty_out(vty, "%% The next unused TRX number in this BTS is %u%s",
+			bts->num_trx, VTY_NEWLINE);
 		return CMD_WARNING;
-	}
-
-	if (trx_nr >= bts->num_trx)
-		bts->num_trx = trx_nr+1;
-
-	trx = &bts->trx[trx_nr];
+	} else if (trx_nr == bts->num_trx) {
+		/* we need to allocate a new one */
+		trx = gsm_bts_trx_alloc(bts);
+	} else 
+		trx = gsm_bts_trx_num(bts, trx_nr);
+	
+	if (!trx)
+		return CMD_WARNING;
 
 	vty->index = trx;
 	vty->node = TRX_NODE;