[OML] parse attributes depending on BTS type

Some NM attributes are defined differently depending on
the BTS type.  Having one big nm_att_tlvdef[] table for
all BTS types is no longer sufficient.  This patch

* introduces 'struct gsm_bts_model' to describe a BTS model
* adds definitions of gsm_bts_model for BS-11 and nanoBTS
* changes the abis_nm_tlv_parse() function: include a bts pointer
diff --git a/openbsc/include/openbsc/abis_nm.h b/openbsc/include/openbsc/abis_nm.h
index d6469c4..81b4eda 100644
--- a/openbsc/include/openbsc/abis_nm.h
+++ b/openbsc/include/openbsc/abis_nm.h
@@ -719,6 +719,8 @@
 	u_int8_t ca_list_si1[16];
 };
 
+extern const struct tlv_definition nm_att_tlvdef;
+
 /* PUBLIC */
 
 struct msgb;
@@ -733,7 +735,7 @@
 
 extern int abis_nm_rcvmsg(struct msgb *msg);
 
-int abis_nm_tlv_parse(struct tlv_parsed *tp, const u_int8_t *buf, int len);
+int abis_nm_tlv_parse(struct tlv_parsed *tp, struct gsm_bts *bts, const u_int8_t *buf, int len);
 int abis_nm_rx(struct msgb *msg);
 int abis_nm_opstart(struct gsm_bts *bts, u_int8_t obj_class, u_int8_t i0, u_int8_t i1, u_int8_t i2);
 int abis_nm_chg_adm_state(struct gsm_bts *bts, u_int8_t obj_class, u_int8_t i0,
diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h
index 573ce5f..5567d89 100644
--- a/openbsc/include/openbsc/gsm_data.h
+++ b/openbsc/include/openbsc/gsm_data.h
@@ -335,6 +335,15 @@
 	GSM_BTS_TYPE_NANOBTS,
 };
 
+struct gsm_bts_model {
+	struct llist_head list;
+
+	enum gsm_bts_type type;
+	const char *name;
+
+	struct tlv_definition nm_att_tlvdef;
+};
+
 /**
  * A pending paging request 
  */
@@ -402,6 +411,7 @@
 	u_int8_t bsic;
 	/* type of BTS */
 	enum gsm_bts_type type;
+	struct gsm_bts_model *model;
 	enum gsm_band band;
 	/* should the channel allocator allocate channels from high TRX to TRX0,
 	 * rather than starting from TRX0 and go upwards? */
@@ -619,7 +629,7 @@
 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_trx *gsm_bts_trx_alloc(struct gsm_bts *bts);
-void gsm_set_bts_type(struct gsm_bts *bts, enum gsm_bts_type type);
+int gsm_set_bts_type(struct gsm_bts *bts, enum gsm_bts_type type);
 
 struct gsm_bts *gsm_bts_num(struct gsm_network *net, int num);
 
diff --git a/openbsc/src/Makefile.am b/openbsc/src/Makefile.am
index 7d7fee7..aa50b8c 100644
--- a/openbsc/src/Makefile.am
+++ b/openbsc/src/Makefile.am
@@ -12,7 +12,7 @@
 		trau_frame.c trau_mux.c paging.c e1_config.c e1_input.c tlv_parser.c \
 		input/misdn.c input/ipaccess.c signal.c gsm_utils.c talloc.c \
 		talloc_ctx.c system_information.c bitvec.c rest_octets.c \
-		rtp_proxy.c statistics.c
+		rtp_proxy.c statistics.c bts_siemens_bs11.c bts_ipaccess_nanobts.c
 
 libmsc_a_SOURCES = gsm_subscriber.c db.c telnet_interface.c \
 		mncc.c gsm_04_08.c gsm_04_11.c transaction.c \
@@ -27,7 +27,8 @@
 bsc_hack_LDADD = libmsc.a libbsc.a libmsc.a libvty.a -ldl -ldbi $(LIBCRYPT)
 
 bs11_config_SOURCES = bs11_config.c abis_nm.c gsm_data.c msgb.c debug.c \
-		      select.c timer.c rs232.c tlv_parser.c signal.c talloc.c
+		      select.c timer.c rs232.c tlv_parser.c signal.c talloc.c \
+		      bts_siemens_bs11.c
 
 ipaccess_find_SOURCES = ipaccess/ipaccess-find.c select.c timer.c
 
diff --git a/openbsc/src/abis_nm.c b/openbsc/src/abis_nm.c
index aaa7dd5..82d7b02 100644
--- a/openbsc/src/abis_nm.c
+++ b/openbsc/src/abis_nm.c
@@ -264,7 +264,7 @@
 	NM_ATT_MEAS_TYPE,
 };
 
-static const struct tlv_definition nm_att_tlvdef = {
+const struct tlv_definition nm_att_tlvdef = {
 	.def = {
 		[NM_ATT_ABIS_CHANNEL] =		{ TLV_TYPE_FIXED, 3 },
 		[NM_ATT_ADD_INFO] =		{ TLV_TYPE_TL16V },
@@ -330,77 +330,6 @@
 		[NM_ATT_HW_CONF_CHG] = 		{ TLV_TYPE_TL16V },
 		[NM_ATT_OUTST_ALARM] =		{ TLV_TYPE_TV },
 		[NM_ATT_MEAS_RES] =		{ TLV_TYPE_TL16V },
-		/* BS11 specifics */
-		[NM_ATT_BS11_ESN_FW_CODE_NO] =	{ TLV_TYPE_TLV },
-		[NM_ATT_BS11_ESN_HW_CODE_NO] =	{ TLV_TYPE_TLV },
-		[NM_ATT_BS11_ESN_PCB_SERIAL] =	{ TLV_TYPE_TLV },
-		[NM_ATT_BS11_BOOT_SW_VERS] =	{ TLV_TYPE_TLV },
-		[0xd5] =			{ TLV_TYPE_TLV },
-		[0xa8] =			{ TLV_TYPE_TLV },
-		[NM_ATT_BS11_PASSWORD] =	{ TLV_TYPE_TLV },
-		[NM_ATT_BS11_TXPWR] =		{ TLV_TYPE_TLV },
-		[NM_ATT_BS11_RSSI_OFFS] =	{ TLV_TYPE_TLV },
-		[NM_ATT_BS11_LINE_CFG] = 	{ TLV_TYPE_TV },
-		[NM_ATT_BS11_L1_PROT_TYPE] =	{ TLV_TYPE_TV },
-		[NM_ATT_BS11_BIT_ERR_THESH] =	{ TLV_TYPE_FIXED, 2 },
-		[NM_ATT_BS11_DIVERSITY] =	{ TLV_TYPE_TLV },
-		[NM_ATT_BS11_LMT_LOGON_SESSION]={ TLV_TYPE_TLV },	
-		[NM_ATT_BS11_LMT_LOGIN_TIME] =	{ TLV_TYPE_TLV },
-		[NM_ATT_BS11_LMT_USER_ACC_LEV] ={ TLV_TYPE_TLV },
-		[NM_ATT_BS11_LMT_USER_NAME] =	{ TLV_TYPE_TLV },
-		[NM_ATT_BS11_BTS_STATE]	=	{ TLV_TYPE_TLV },
-		[NM_ATT_BS11_E1_STATE]	=	{ TLV_TYPE_TLV },
-		[NM_ATT_BS11_PLL_MODE]	=	{ TLV_TYPE_TLV },
-		[NM_ATT_BS11_PLL]	=	{ TLV_TYPE_TLV },
-		[NM_ATT_BS11_CCLK_ACCURACY] =	{ TLV_TYPE_TV },
-		[NM_ATT_BS11_CCLK_TYPE] =	{ TLV_TYPE_TV },
-		/* 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_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 },
-
 	},
 };
 
@@ -423,9 +352,11 @@
 	return -EINVAL;
 }
 
-int abis_nm_tlv_parse(struct tlv_parsed *tp, const u_int8_t *buf, int len)
+int abis_nm_tlv_parse(struct tlv_parsed *tp, struct gsm_bts *bts, const u_int8_t *buf, int len)
 {
-	return tlv_parse(tp, &nm_att_tlvdef, buf, len, 0, 0);
+	if (!bts->model)
+		return -EIO;
+	return tlv_parse(tp, &bts->model->nm_att_tlvdef, buf, len, 0, 0);
 }
 
 static int is_in_arr(enum abis_nm_msgtype mt, const enum abis_nm_msgtype *arr, int size)
@@ -801,7 +732,7 @@
 
 	new_state = *nm_state;
 	
-	abis_nm_tlv_parse(&tp, foh->data, oh->length-sizeof(*foh));
+	abis_nm_tlv_parse(&tp, bts, foh->data, oh->length-sizeof(*foh));
 	if (TLVP_PRESENT(&tp, NM_ATT_OPER_STATE)) {
 		new_state.operational = *TLVP_VAL(&tp, NM_ATT_OPER_STATE);
 		DEBUGPC(DNM, "OP_STATE=%s ", nm_opstate_name(new_state.operational));
@@ -853,7 +784,7 @@
 
 	DEBUGPC(DNM, "Failure Event Report ");
 	
-	abis_nm_tlv_parse(&tp, foh->data, oh->length-sizeof(*foh));
+	abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
 
 	if (TLVP_PRESENT(&tp, NM_ATT_EVENT_TYPE))
 		DEBUGPC(DNM, "Type=%s ", event_type_name(*TLVP_VAL(&tp, NM_ATT_EVENT_TYPE)));
@@ -947,7 +878,7 @@
 	if (nack)
 		return ret;
 
-	abis_nm_tlv_parse(&tp, foh->data, oh->length-sizeof(*foh));
+	abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
 	sw_config = TLVP_VAL(&tp, NM_ATT_SW_CONFIG);
 	sw_config_len = TLVP_LEN(&tp, NM_ATT_SW_CONFIG);
 	if (!TLVP_PRESENT(&tp, NM_ATT_SW_CONFIG)) {
@@ -981,7 +912,7 @@
 	struct tlv_parsed tp;
 	u_int8_t adm_state;
 
-	abis_nm_tlv_parse(&tp, foh->data, oh->length-sizeof(*foh));
+	abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
 	if (!TLVP_PRESENT(&tp, NM_ATT_ADM_STATE))
 		return -EINVAL;
 
@@ -997,7 +928,7 @@
 	struct tlv_parsed tp;
 
 	DEBUGP(DNM, "LMT Event ");
-	abis_nm_tlv_parse(&tp, foh->data, oh->length-sizeof(*foh));
+	abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
 	if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) &&
 	    TLVP_LEN(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) >= 1) {
 		u_int8_t onoff = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_LOGON_SESSION);
@@ -1043,7 +974,7 @@
 		else
 			DEBUGPC(DNM, "NACK 0x%02x ", mt);
 
-		abis_nm_tlv_parse(&tp, foh->data, oh->length-sizeof(*foh));
+		abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
 		if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
 			DEBUGPC(DNM, "CAUSE=%s\n", 
 				nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
@@ -2770,7 +2701,7 @@
 	}
 
 	foh = (struct abis_om_fom_hdr *) (oh->data + 1 + idstrlen);
-	abis_nm_tlv_parse(&tp, foh->data, oh->length-sizeof(*foh));
+	abis_nm_tlv_parse(&tp, msg->trx->bts, foh->data, oh->length-sizeof(*foh));
 
 	debugp_foh(foh);
 
diff --git a/openbsc/src/bs11_config.c b/openbsc/src/bs11_config.c
index 6a76b96..703591e 100644
--- a/openbsc/src/bs11_config.c
+++ b/openbsc/src/bs11_config.c
@@ -649,7 +649,7 @@
 		exit(0);
 		break;
 	case NM_MT_BS11_GET_STATE_ACK:
-		rc = abis_nm_tlv_parse(&tp, foh->data, oh->length-sizeof(*foh));
+		rc = abis_nm_tlv_parse(&tp, g_bts, foh->data, oh->length-sizeof(*foh));
 		print_state(&tp);
 		if (TLVP_PRESENT(&tp, NM_ATT_BS11_BTS_STATE) &&
 		    TLVP_LEN(&tp, NM_ATT_BS11_BTS_STATE) >= 1)
@@ -657,7 +657,7 @@
 		break;
 	case NM_MT_GET_ATTR_RESP:
 		printf("\n%sATTRIBUTES:\n", obj_name(foh));
-		abis_nm_tlv_parse(&tp, foh->data, oh->length-sizeof(*foh));
+		abis_nm_tlv_parse(&tp, g_bts, foh->data, oh->length-sizeof(*foh));
 		rc = print_attr(&tp);
 		//hexdump(foh->data, oh->length-sizeof(*foh));
 		break;
@@ -839,6 +839,7 @@
 	debug_add_target(stderr_target);
 	debug_set_all_filter(stderr_target, 1);
 	handle_options(argc, argv);
+	bts_model_bs11_init();
 
 	gsmnet = gsm_network_init(1, 1, NULL);
 	if (!gsmnet) {
diff --git a/openbsc/src/bsc_hack.c b/openbsc/src/bsc_hack.c
index 3122fae..581e9be 100644
--- a/openbsc/src/bsc_hack.c
+++ b/openbsc/src/bsc_hack.c
@@ -178,6 +178,9 @@
 	bsc_schedule_timer(&db_sync_timer, DB_SYNC_INTERVAL);
 }
 
+extern int bts_model_bs11_init(void);
+extern int bts_model_nanobts_init(void);
+
 int main(int argc, char **argv)
 {
 	int rc;
@@ -191,6 +194,9 @@
 	stderr_target = debug_target_create_stderr();
 	debug_add_target(stderr_target);
 
+	bts_model_bs11_init();
+	bts_model_nanobts_init();
+
 	/* enable filters */
 	debug_set_all_filter(stderr_target, 1);
 
diff --git a/openbsc/src/bts_ipaccess_nanobts.c b/openbsc/src/bts_ipaccess_nanobts.c
new file mode 100644
index 0000000..6765517
--- /dev/null
+++ b/openbsc/src/bts_ipaccess_nanobts.c
@@ -0,0 +1,84 @@
+/* ip.access nanoBTS specific code */
+
+/* (C) 2009-2010 by Harald Welte <laforge@gnumonks.org>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <sys/types.h>
+
+#include <openbsc/gsm_data.h>
+#include <openbsc/tlv.h>
+#include <openbsc/abis_nm.h>
+
+static struct gsm_bts_model model_nanobts = {
+	.type = GSM_BTS_TYPE_NANOBTS,
+	.nm_att_tlvdef = {
+		.def = {
+			/* 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_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 },
+		},
+	},
+};
+
+int bts_model_nanobts_init(void)
+{
+	return gsm_bts_model_register(&model_nanobts);
+}
diff --git a/openbsc/src/bts_siemens_bs11.c b/openbsc/src/bts_siemens_bs11.c
new file mode 100644
index 0000000..1c8f889
--- /dev/null
+++ b/openbsc/src/bts_siemens_bs11.c
@@ -0,0 +1,66 @@
+/* Siemens BS-11 specific code */
+
+/* (C) 2009-2010 by Harald Welte <laforge@gnumonks.org>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <sys/types.h>
+
+#include <openbsc/gsm_data.h>
+#include <openbsc/tlv.h>
+#include <openbsc/abis_nm.h>
+
+static struct gsm_bts_model model_bs11 = {
+	.type = GSM_BTS_TYPE_BS11,
+	.nm_att_tlvdef = {
+		.def = {
+			[NM_ATT_AVAIL_STATUS] =		{ TLV_TYPE_TLV },
+			/* BS11 specifics */
+			[NM_ATT_BS11_ESN_FW_CODE_NO] =	{ TLV_TYPE_TLV },
+			[NM_ATT_BS11_ESN_HW_CODE_NO] =	{ TLV_TYPE_TLV },
+			[NM_ATT_BS11_ESN_PCB_SERIAL] =	{ TLV_TYPE_TLV },
+			[NM_ATT_BS11_BOOT_SW_VERS] =	{ TLV_TYPE_TLV },
+			[0xd5] =			{ TLV_TYPE_TLV },
+			[0xa8] =			{ TLV_TYPE_TLV },
+			[NM_ATT_BS11_PASSWORD] =	{ TLV_TYPE_TLV },
+			[NM_ATT_BS11_TXPWR] =		{ TLV_TYPE_TLV },
+			[NM_ATT_BS11_RSSI_OFFS] =	{ TLV_TYPE_TLV },
+			[NM_ATT_BS11_LINE_CFG] = 	{ TLV_TYPE_TV },
+			[NM_ATT_BS11_L1_PROT_TYPE] =	{ TLV_TYPE_TV },
+			[NM_ATT_BS11_BIT_ERR_THESH] =	{ TLV_TYPE_FIXED, 2 },
+			[NM_ATT_BS11_DIVERSITY] =	{ TLV_TYPE_TLV },
+			[NM_ATT_BS11_LMT_LOGON_SESSION]={ TLV_TYPE_TLV },	
+			[NM_ATT_BS11_LMT_LOGIN_TIME] =	{ TLV_TYPE_TLV },
+			[NM_ATT_BS11_LMT_USER_ACC_LEV] ={ TLV_TYPE_TLV },
+			[NM_ATT_BS11_LMT_USER_NAME] =	{ TLV_TYPE_TLV },
+			[NM_ATT_BS11_BTS_STATE]	=	{ TLV_TYPE_TLV },
+			[NM_ATT_BS11_E1_STATE]	=	{ TLV_TYPE_TLV },
+			[NM_ATT_BS11_PLL_MODE]	=	{ TLV_TYPE_TLV },
+			[NM_ATT_BS11_PLL]	=	{ TLV_TYPE_TLV },
+			[NM_ATT_BS11_CCLK_ACCURACY] =	{ TLV_TYPE_TV },
+			[NM_ATT_BS11_CCLK_TYPE] =	{ TLV_TYPE_TV },
+			[0x95] =			{ TLV_TYPE_FIXED, 2 },
+		},
+	},
+};
+
+int bts_model_bs11_init(void)
+{
+	return gsm_bts_model_register(&model_bs11);
+}
diff --git a/openbsc/src/gsm_data.c b/openbsc/src/gsm_data.c
index d2676db..694ae06 100644
--- a/openbsc/src/gsm_data.c
+++ b/openbsc/src/gsm_data.c
@@ -32,6 +32,8 @@
 
 void *tall_bsc_ctx;
 
+static LLIST_HEAD(bts_models);
+
 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)
 {
@@ -118,6 +120,29 @@
 	return chreq_names[c];
 }
 
+static struct gsm_bts_model *bts_model_find(enum gsm_bts_type type)
+{
+	struct gsm_bts_model *model;
+
+	llist_for_each_entry(model, &bts_models, list) {
+		if (model->type == type)
+			return model;
+	}
+
+	return NULL;
+}
+
+int gsm_bts_model_register(struct gsm_bts_model *model)
+{
+	if (bts_model_find(model->type))
+		return -EEXIST;
+
+	tlv_def_patch(&model->nm_att_tlvdef, &nm_att_tlvdef);
+	llist_add_tail(&model->list, &bts_models);
+	return 0;
+}
+
+
 struct gsm_bts_trx *gsm_bts_trx_alloc(struct gsm_bts *bts)
 {
 	struct gsm_bts_trx *trx = talloc_zero(bts, struct gsm_bts_trx);
@@ -160,14 +185,21 @@
 			      u_int8_t tsc, u_int8_t bsic)
 {
 	struct gsm_bts *bts = talloc_zero(net, struct gsm_bts);
+	struct gsm_bts_model *model = bts_model_find(type);
 	int i;
 
 	if (!bts)
 		return NULL;
 
+	if (!model) {
+		talloc_free(bts);
+		return NULL;
+	}
+
 	bts->network = net;
 	bts->nr = net->num_bts++;
 	bts->type = type;
+	bts->model = model;
 	bts->tsc = tsc;
 	bts->bsic = bsic;
 	bts->num_trx = 0;
@@ -504,9 +536,16 @@
 	return meas_rep;
 }
 
-void gsm_set_bts_type(struct gsm_bts *bts, enum gsm_bts_type type)
+int gsm_set_bts_type(struct gsm_bts *bts, enum gsm_bts_type type)
 {
+	struct gsm_bts_model *model;
+
+	model = bts_model_find(type);
+	if (!model)
+		return -EINVAL;
+
 	bts->type = type;
+	bts->model = model;
 
 	switch (bts->type) {
 	case GSM_BTS_TYPE_NANOBTS:
@@ -517,4 +556,6 @@
 	case GSM_BTS_TYPE_BS11:
 		break;
 	}
+
+	return 0;
 }
diff --git a/openbsc/src/vty_interface.c b/openbsc/src/vty_interface.c
index 8d6e202..2654447 100644
--- a/openbsc/src/vty_interface.c
+++ b/openbsc/src/vty_interface.c
@@ -1339,8 +1339,11 @@
       "Set the BTS type\n")
 {
 	struct gsm_bts *bts = vty->index;
+	int rc;
 
-	gsm_set_bts_type(bts, parse_btstype(argv[0]));
+	rc = gsm_set_bts_type(bts, parse_btstype(argv[0]));
+	if (rc < 0)
+		return CMD_WARNING;
 
 	return CMD_SUCCESS;
 }