[PATCH] openbsc[master]: OML: Improve OML attribute handling

This is merely a historical archive of years 2008-2021, before the migration to mailman3.

A maintained and still updated list archive can be found at https://lists.osmocom.org/hyperkitty/list/gerrit-log@lists.osmocom.org/.

dexter gerrit-no-reply at lists.osmocom.org
Thu Oct 13 15:24:23 UTC 2016


Hello Neels Hofmeyr, Harald Welte, Jenkins Builder,

I'd like you to reexamine a change.  Please visit

    https://gerrit.osmocom.org/973

to look at the new patch set (#4).

OML: Improve OML attribute handling

the OML attribute tables are hardcoded. To set variable parameters,
the hardcoded data structure (tlv) is patched on byte level during
runtime. This patch replaces this mechanism.

- Replace hardcoded OML attribute tables with dynamically
  generated TLV structures.

- Add unit tests to check if the OML attribute tables are
  generated correctly

- Put OML attribute table generator code in a separate file:
  bts_ipaccess_nanobts_omlattr.c

Change-Id: Ibeb34a84912d6cf695f553a34c69320fca7d08fa
---
M openbsc/.gitignore
M openbsc/configure.ac
M openbsc/include/openbsc/Makefile.am
A openbsc/include/openbsc/bts_ipaccess_nanobts_omlattr.h
M openbsc/src/libbsc/Makefile.am
M openbsc/src/libbsc/bts_ipaccess_nanobts.c
A openbsc/src/libbsc/bts_ipaccess_nanobts_omlattr.c
M openbsc/tests/Makefile.am
A openbsc/tests/nanobts_omlattr/Makefile.am
A openbsc/tests/nanobts_omlattr/nanobts_omlattr_test.c
A openbsc/tests/nanobts_omlattr/nanobts_omlattr_test.ok
M openbsc/tests/testsuite.at
12 files changed, 638 insertions(+), 221 deletions(-)


  git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/73/973/4

diff --git a/openbsc/.gitignore b/openbsc/.gitignore
index 6fbd463..3324069 100644
--- a/openbsc/.gitignore
+++ b/openbsc/.gitignore
@@ -85,6 +85,7 @@
 tests/sndcp_xid/sndcp_xid_test
 tests/slhc/slhc_test
 tests/v42bis/v42bis_test
+tests/nanobts_omlattr/nanobts_omlattr_test
 
 tests/atconfig
 tests/atlocal
diff --git a/openbsc/configure.ac b/openbsc/configure.ac
index e2575c1..b18ecc1 100644
--- a/openbsc/configure.ac
+++ b/openbsc/configure.ac
@@ -244,6 +244,7 @@
     tests/sndcp_xid/Makefile
     tests/slhc/Makefile
     tests/v42bis/Makefile
+    tests/nanobts_omlattr/Makefile
     doc/Makefile
     doc/examples/Makefile
     Makefile)
diff --git a/openbsc/include/openbsc/Makefile.am b/openbsc/include/openbsc/Makefile.am
index c6a0149..5737a4b 100644
--- a/openbsc/include/openbsc/Makefile.am
+++ b/openbsc/include/openbsc/Makefile.am
@@ -11,6 +11,7 @@
 	bsc_nat_sccp.h \
 	bsc_rll.h \
 	bss.h \
+	bts_ipaccess_nanobts_omlattr.h \
 	chan_alloc.h \
 	crc24.h \
 	ctrl.h \
diff --git a/openbsc/include/openbsc/bts_ipaccess_nanobts_omlattr.h b/openbsc/include/openbsc/bts_ipaccess_nanobts_omlattr.h
new file mode 100644
index 0000000..bc7860b
--- /dev/null
+++ b/openbsc/include/openbsc/bts_ipaccess_nanobts_omlattr.h
@@ -0,0 +1,32 @@
+/* OML attribute table generator for ipaccess nanobts */
+
+/* (C) 2016 by sysmocom s.f.m.c. GmbH <info at sysmocom.de>
+ * All Rights Reserved
+ *
+ * Author: Philipp Maier
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation; either version 3 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include <stdint.h>
+#include <osmocom/core/msgb.h>
+
+struct msgb *nanobts_attr_bts_get(struct gsm_bts *bts);
+struct msgb *nanobts_attr_nse_get(struct gsm_bts *bts);
+struct msgb *nanobts_attr_cell_get(struct gsm_bts *bts);
+struct msgb *nanobts_attr_nscv_get(struct gsm_bts *bts);
+struct msgb *nanobts_attr_radio_get(struct gsm_bts *bts,
+				    struct gsm_bts_trx *trx);
diff --git a/openbsc/src/libbsc/Makefile.am b/openbsc/src/libbsc/Makefile.am
index 4728e23..8c53817 100644
--- a/openbsc/src/libbsc/Makefile.am
+++ b/openbsc/src/libbsc/Makefile.am
@@ -49,5 +49,6 @@
 	bsc_ctrl_lookup.c \
 	net_init.c \
 	bsc_dyn_ts.c \
+	bts_ipaccess_nanobts_omlattr.c \
 	$(NULL)
 
diff --git a/openbsc/src/libbsc/bts_ipaccess_nanobts.c b/openbsc/src/libbsc/bts_ipaccess_nanobts.c
index a6c8e29..a1bde77 100644
--- a/openbsc/src/libbsc/bts_ipaccess_nanobts.c
+++ b/openbsc/src/libbsc/bts_ipaccess_nanobts.c
@@ -39,6 +39,7 @@
 #include <osmocom/abis/ipaccess.h>
 #include <osmocom/core/logging.h>
 #include <openbsc/ipaccess.h>
+#include <openbsc/bts_ipaccess_nanobts_omlattr.h>
 
 extern struct gsm_network *bsc_gsmnet;
 
@@ -100,211 +101,6 @@
 	},
 };
 
-static unsigned char nanobts_attr_bts[] = {
-	NM_ATT_INTERF_BOUND, 0x55, 0x5b, 0x61, 0x67, 0x6d, 0x73,
-	/* interference avg. period in numbers of SACCH multifr */
-	NM_ATT_INTAVE_PARAM, 0x06,
-	/* conn fail based on SACCH error rate */
-	NM_ATT_CONN_FAIL_CRIT, 0x00, 0x02, 0x01, 0x10,
-	NM_ATT_T200, 0x1e, 0x24, 0x24, 0xa8, 0x34, 0x21, 0xa8,
-	NM_ATT_MAX_TA, 0x3f,
-	NM_ATT_OVERL_PERIOD, 0x00, 0x01, 10, /* seconds */
-	NM_ATT_CCCH_L_T, 10, /* percent */
-	NM_ATT_CCCH_L_I_P, 1, /* seconds */
-	NM_ATT_RACH_B_THRESH, 10, /* busy threshold in - dBm */
-	NM_ATT_LDAVG_SLOTS, 0x03, 0xe8, /* rach load averaging 1000 slots */
-	NM_ATT_BTS_AIR_TIMER, 128, /* miliseconds */
-	NM_ATT_NY1, 10, /* 10 retransmissions of physical config */
-	NM_ATT_BCCH_ARFCN, HARDCODED_ARFCN >> 8, HARDCODED_ARFCN & 0xff,
-	NM_ATT_BSIC, HARDCODED_BSIC,
-	NM_ATT_IPACC_CGI, 0, 7,  0x00, 0xf1, 0x10, 0x00, 0x01, 0x00, 0x00,
-};
-
-static unsigned char nanobts_attr_radio[] = {
-	NM_ATT_RF_MAXPOWR_R, 0x0c, /* number of -2dB reduction steps / Pn */
-	NM_ATT_ARFCN_LIST, 0x00, 0x02, HARDCODED_ARFCN >> 8, HARDCODED_ARFCN & 0xff,
-};
-
-static unsigned char nanobts_attr_nse[] = {
-	NM_ATT_IPACC_NSEI, 0, 2,  0x03, 0x9d, /* NSEI 925 */
-	/* all timers in seconds */
-	NM_ATT_IPACC_NS_CFG, 0, 7,  3,  /* (un)blocking timer (Tns-block) */
-				    3,  /* (un)blocking retries */
-				    3,  /* reset timer (Tns-reset) */
-				    3,  /* reset retries */
-				    30,  /* test timer (Tns-test) */
-				    3,  /* alive timer (Tns-alive) */
-				    10, /* alive retrires */
-	/* all timers in seconds, unless otherwise stated */
-	NM_ATT_IPACC_BSSGP_CFG, 0, 11,
-				    3,  /* blockimg timer (T1) */
-				    3,  /* blocking retries */
-				    3,  /* unblocking retries */
-				    3,  /* reset timer (T2) */
-				    3,  /* reset retries */
-				    10, /* suspend timer (T3) in 100ms */
-				    3,  /* suspend retries */
-				    10, /* resume timer (T4) in 100ms */
-				    3,  /* resume retries */
-				    10, /* capability update timer (T5) */
-				    3,  /* capability update retries */
-};
-
-static unsigned char nanobts_attr_cell[] = {
-	NM_ATT_IPACC_RAC, 0, 1,  1, /* routing area code */
-	NM_ATT_IPACC_GPRS_PAGING_CFG, 0, 2,
-		5,	/* repeat time (50ms) */
-		3,	/* repeat count */
-	NM_ATT_IPACC_BVCI, 0, 2,  0x03, 0x9d, /* BVCI 925 */
-	/* all timers in seconds, unless otherwise stated */
-	NM_ATT_IPACC_RLC_CFG, 0, 9,
-		20, 	/* T3142 */
-		5, 	/* T3169 */
-		5,	/* T3191 */
-		160,	/* T3193 (units of 10ms) */
-		5,	/* T3195 */
-		10,	/* N3101 */
-		4,	/* N3103 */
-		8,	/* N3105 */
-		15,	/* RLC CV countdown */
-	NM_ATT_IPACC_CODING_SCHEMES, 0, 2,  0x0f, 0x00,	/* CS1..CS4 */
-	NM_ATT_IPACC_RLC_CFG_2, 0, 5,
-		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 */
-	NM_ATT_IPACC_RLC_CFG_3, 0, 1,
-		2,	/* MCS2 */
-#endif
-};
-
-static unsigned char nanobts_attr_nsvc0[] = {
-	NM_ATT_IPACC_NSVCI, 0, 2,  0x03, 0x9d, /* 925 */
-	NM_ATT_IPACC_NS_LINK_CFG, 0, 8,
-		0x59, 0xd8, /* remote udp port (23000) */
-		192, 168, 100, 11, /* remote ip address */
-		0x59, 0xd8, /* local udp port (23000) */
-};
-
-static void patch_16(uint8_t *data, const uint16_t val)
-{
-	memcpy(data, &val, sizeof(val));
-}
-
-static void patch_32(uint8_t *data, const uint32_t val)
-{
-	memcpy(data, &val, sizeof(val));
-}
-
-/*
- * Patch the various SYSTEM INFORMATION tables to update
- * the LAI
- */
-static void patch_nm_tables(struct gsm_bts *bts)
-{
-	uint8_t arfcn_low = bts->c0->arfcn & 0xff;
-	uint8_t arfcn_high = (bts->c0->arfcn >> 8) & 0x0f;
-
-	/* patch ARFCN into BTS Attributes */
-	nanobts_attr_bts[42] &= 0xf0;
-	nanobts_attr_bts[42] |= arfcn_high;
-	nanobts_attr_bts[43] = arfcn_low;
-
-	/* patch the RACH attributes */
-	if (bts->rach_b_thresh != -1) {
-		nanobts_attr_bts[33] = bts->rach_b_thresh & 0xff;
-	}
-
-	if (bts->rach_ldavg_slots != -1) {
-		uint8_t avg_high = bts->rach_ldavg_slots & 0xff;
-		uint8_t avg_low = (bts->rach_ldavg_slots >> 8) & 0x0f;
-
-		nanobts_attr_bts[35] = avg_high;
-		nanobts_attr_bts[36] = avg_low;
-	}
-
-	/* patch BSIC */
-	nanobts_attr_bts[sizeof(nanobts_attr_bts)-11] = bts->bsic;
-
-	/* patch CGI */
-	abis_nm_ipaccess_cgi(nanobts_attr_bts+sizeof(nanobts_attr_bts)-7, bts);
-
-	/* patch CON_FAIL_CRIT */
-	nanobts_attr_bts[13] =
-		get_radio_link_timeout(&bts->si_common.cell_options);
-
-	/* patch the power reduction */
-	nanobts_attr_radio[1] = bts->c0->max_power_red / 2;
-
-	/* patch NSEI */
-	nanobts_attr_nse[3] = bts->gprs.nse.nsei >> 8;
-	nanobts_attr_nse[4] = bts->gprs.nse.nsei & 0xff;
-	memcpy(nanobts_attr_nse+8, bts->gprs.nse.timer,
-		ARRAY_SIZE(bts->gprs.nse.timer));
-	memcpy(nanobts_attr_nse+18, bts->gprs.cell.timer,
-		ARRAY_SIZE(bts->gprs.cell.timer));
-
-	/* patch NSVCI */
-	nanobts_attr_nsvc0[3] = bts->gprs.nsvc[0].nsvci >> 8;
-	nanobts_attr_nsvc0[4] = bts->gprs.nsvc[0].nsvci & 0xff;
-
-	/* patch IP address as SGSN IP */
-	patch_16(nanobts_attr_nsvc0 + 8, 
-			htons(bts->gprs.nsvc[0].remote_port));
-	patch_32(nanobts_attr_nsvc0 + 10,
-			htonl(bts->gprs.nsvc[0].remote_ip));
-	patch_16(nanobts_attr_nsvc0 + 14,
-			htons(bts->gprs.nsvc[0].local_port));
-
-	/* patch BVCI */
-	nanobts_attr_cell[12] = bts->gprs.cell.bvci >> 8;
-	nanobts_attr_cell[13] = bts->gprs.cell.bvci & 0xff;
-	/* 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 uint8_t *nanobts_attr_bts_get(struct gsm_bts *bts, size_t *data_len)
-{
-	patch_nm_tables(bts);
-	*data_len = sizeof(nanobts_attr_bts);
-	return nanobts_attr_bts;
-}
-
-static uint8_t *nanobts_attr_nse_get(struct gsm_bts *bts, size_t *data_len)
-{
-	patch_nm_tables(bts);
-	*data_len = sizeof(nanobts_attr_nse);
-	return nanobts_attr_nse;
-}
-
-static uint8_t *nanobts_attr_cell_get(struct gsm_bts *bts, size_t *data_len)
-{
-	patch_nm_tables(bts);
-	*data_len = sizeof(nanobts_attr_cell);
-	return nanobts_attr_cell;
-}
-
-static uint8_t *nanobts_attr_nscv_get(struct gsm_bts *bts, size_t *data_len)
-{
-	patch_nm_tables(bts);
-	*data_len = sizeof(nanobts_attr_nsvc0);
-	return nanobts_attr_nsvc0;
-}
-
-static uint8_t *nanobts_attr_radio_get(struct gsm_bts *bts, size_t *data_len)
-{
-	patch_nm_tables(bts);
-	*data_len = sizeof(nanobts_attr_radio);
-	return nanobts_attr_radio;
-}
 
 /* Callback function to be called whenever we get a GSM 12.21 state change event */
 static int nm_statechg_event(int evt, struct nm_statechg_signal_data *nsd)
@@ -318,8 +114,7 @@
 	struct gsm_bts_trx_ts *ts;
 	struct gsm_bts_gprs_nsvc *nsvc;
 
-	uint8_t *data;
-	size_t data_len;
+	struct msgb *msgb;
 
 	if (!is_ipaccess_bts(nsd->bts))
 		return 0;
@@ -343,8 +138,9 @@
 	case NM_OC_BTS:
 		bts = obj;
 		if (new_state->availability == NM_AVSTATE_DEPENDENCY) {
-			data = nanobts_attr_bts_get(bts, &data_len);
-			abis_nm_set_bts_attr(bts, data, data_len);
+			msgb = nanobts_attr_bts_get(bts);
+			abis_nm_set_bts_attr(bts, msgb->data, msgb->len);
+			msgb_free(msgb);
 			abis_nm_chg_adm_state(bts, obj_class,
 					      bts->bts_nr, 0xff, 0xff,
 					      NM_STATE_UNLOCKED);
@@ -385,9 +181,11 @@
 		if (bts->gprs.mode == BTS_GPRS_NONE)
 			break;
 		if (new_state->availability == NM_AVSTATE_DEPENDENCY) {
-			data = nanobts_attr_nse_get(bts, &data_len);
+			msgb = nanobts_attr_nse_get(bts);
 			abis_nm_ipaccess_set_attr(bts, obj_class, bts->bts_nr,
-						  0xff, 0xff, data, data_len);
+						  0xff, 0xff, msgb->data,
+						  msgb->len);
+			msgb_free(msgb);
 			abis_nm_opstart(bts, obj_class, bts->bts_nr,
 					0xff, 0xff);
 		}
@@ -397,9 +195,11 @@
 		if (bts->gprs.mode == BTS_GPRS_NONE)
 			break;
 		if (new_state->availability == NM_AVSTATE_DEPENDENCY) {
-			data = nanobts_attr_cell_get(bts, &data_len);
+			msgb = nanobts_attr_cell_get(bts);
 			abis_nm_ipaccess_set_attr(bts, obj_class, bts->bts_nr,
-						  0, 0xff, data, data_len);
+						  0, 0xff, msgb->data,
+						  msgb->len);
+			msgb_free(msgb);
 			abis_nm_opstart(bts, obj_class, bts->bts_nr,
 					0, 0xff);
 			abis_nm_chg_adm_state(bts, obj_class, bts->bts_nr,
@@ -418,10 +218,11 @@
 			break;
 		if ((new_state->availability == NM_AVSTATE_OFF_LINE) ||
 		    (new_state->availability == NM_AVSTATE_DEPENDENCY)) {
-			data = nanobts_attr_nscv_get(bts, &data_len);
+			msgb = nanobts_attr_nscv_get(bts);
 			abis_nm_ipaccess_set_attr(bts, obj_class, bts->bts_nr,
 						  nsvc->id, 0xff,
-						  data, data_len);
+						  msgb->data, msgb->len);
+			msgb_free(msgb);
 			abis_nm_opstart(bts, obj_class, bts->bts_nr,
 					nsvc->id, 0xff);
 			abis_nm_chg_adm_state(bts, obj_class, bts->bts_nr,
@@ -471,12 +272,9 @@
 		 */
 		int rc_state = trx->mo.nm_state.administrative;
 		/* Patch ARFCN into radio attribute */
-		size_t data_len;
-		uint8_t *data = nanobts_attr_radio_get(trx->bts, &data_len);
-		data[5] &= 0xf0;
-		data[5] |= trx->arfcn >> 8;
-		data[6] = trx->arfcn & 0xff;
-		abis_nm_set_radio_attr(trx, data, data_len);
+		struct msgb *msgb = nanobts_attr_radio_get(trx->bts, trx);
+		abis_nm_set_radio_attr(trx, msgb->data, msgb->len);
+		msgb_free(msgb);
 		abis_nm_chg_adm_state(trx->bts, foh->obj_class,
 				      trx->bts->bts_nr, trx->nr, 0xff,
 				      rc_state);
diff --git a/openbsc/src/libbsc/bts_ipaccess_nanobts_omlattr.c b/openbsc/src/libbsc/bts_ipaccess_nanobts_omlattr.c
new file mode 100644
index 0000000..0291129
--- /dev/null
+++ b/openbsc/src/libbsc/bts_ipaccess_nanobts_omlattr.c
@@ -0,0 +1,232 @@
+/* ip.access nanoBTS specific code, OML attribute table generator */
+
+/* (C) 2016 by sysmocom s.f.m.c. GmbH <info at sysmocom.de>
+ * All Rights Reserved
+ *
+ * Author: Philipp Maier
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation; either version 3 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <arpa/inet.h>
+#include <osmocom/core/msgb.h>
+#include <openbsc/gsm_data.h>
+#include <openbsc/abis_nm.h>
+
+static void patch_16(uint8_t *data, const uint16_t val)
+{
+	memcpy(data, &val, sizeof(val));
+}
+
+static void patch_32(uint8_t *data, const uint32_t val)
+{
+	memcpy(data, &val, sizeof(val));
+}
+
+struct msgb *nanobts_attr_bts_get(struct gsm_bts *bts)
+{
+	struct msgb *msgb;
+	uint8_t buf[256];
+	msgb = msgb_alloc(1024, "nanobts_attr_bts");
+
+	memcpy(buf, "\x55\x5b\x61\x67\x6d\x73", 6);
+	msgb_tv_fixed_put(msgb, NM_ATT_INTERF_BOUND, 6, buf);
+
+	/* interference avg. period in numbers of SACCH multifr */
+	msgb_tv_put(msgb, NM_ATT_INTAVE_PARAM, 0x06);
+
+	/* conn fail based on SACCH error rate */
+	buf[0] = 0x01;
+	buf[1] = get_radio_link_timeout(&bts->si_common.cell_options);
+	msgb_tl16v_put(msgb, NM_ATT_CONN_FAIL_CRIT, 2, buf);
+
+	memcpy(buf, "\x1e\x24\x24\xa8\x34\x21\xa8", 7);
+	msgb_tv_fixed_put(msgb, NM_ATT_T200, 7, buf);
+
+	msgb_tv_put(msgb, NM_ATT_MAX_TA, 0x3f);
+
+	/* seconds */
+	memcpy(buf, "\x00\x01\x0a", 3);
+	msgb_tv_fixed_put(msgb, NM_ATT_OVERL_PERIOD, 3, buf);
+
+	/* percent */
+	msgb_tv_put(msgb, NM_ATT_CCCH_L_T, 10);
+
+	/* seconds */
+	msgb_tv_put(msgb, NM_ATT_CCCH_L_I_P, 1);
+
+	/* busy threshold in - dBm */
+	buf[0] = 10;
+	if (bts->rach_b_thresh != -1)
+		buf[0] = bts->rach_b_thresh & 0xff;
+	msgb_tv_put(msgb, NM_ATT_RACH_B_THRESH, buf[0]);
+
+	/* rach load averaging 1000 slots */
+	buf[0] = 0x03;
+	buf[1] = 0xe8;
+	if (bts->rach_ldavg_slots != -1) {
+		buf[0] = (bts->rach_ldavg_slots >> 8) & 0x0f;
+		buf[1] = bts->rach_ldavg_slots & 0xff;
+	}
+	msgb_tv_fixed_put(msgb, NM_ATT_LDAVG_SLOTS, 2, buf);
+
+	/* miliseconds */
+	msgb_tv_put(msgb, NM_ATT_BTS_AIR_TIMER, 128);
+
+	/* 10 retransmissions of physical config */
+	msgb_tv_put(msgb, NM_ATT_NY1, 10);
+
+	buf[0] = (bts->c0->arfcn >> 8) & 0x0f;
+	buf[1] = bts->c0->arfcn & 0xff;
+	msgb_tv_fixed_put(msgb, NM_ATT_BCCH_ARFCN, 2, buf);
+
+	msgb_tv_put(msgb, NM_ATT_BSIC, bts->bsic);
+
+	abis_nm_ipaccess_cgi(buf, bts);
+	msgb_tl16v_put(msgb, NM_ATT_IPACC_CGI, 7, buf);
+
+	return msgb;
+}
+
+struct msgb *nanobts_attr_nse_get(struct gsm_bts *bts)
+{
+	struct msgb *msgb;
+	uint8_t buf[256];
+	msgb = msgb_alloc(1024, "nanobts_attr_bts");
+
+	/* NSEI 925 */
+	buf[0] = bts->gprs.nse.nsei >> 8;
+	buf[1] = bts->gprs.nse.nsei & 0xff;
+	msgb_tl16v_put(msgb, NM_ATT_IPACC_NSEI, 2, buf);
+
+	/* all timers in seconds */
+	OSMO_ASSERT(ARRAY_SIZE(bts->gprs.nse.timer) < sizeof(buf));
+	memcpy(buf, bts->gprs.nse.timer, ARRAY_SIZE(bts->gprs.nse.timer));
+	msgb_tl16v_put(msgb, NM_ATT_IPACC_NS_CFG, 7, buf);
+
+	/* all timers in seconds */
+	buf[0] = 3;	/* blockimg timer (T1) */
+	buf[1] = 3;	/* blocking retries */
+	buf[2] = 3;	/* unblocking retries */
+	buf[3] = 3;	/* reset timer (T2) */
+	buf[4] = 3;	/* reset retries */
+	buf[5] = 10;	/* suspend timer (T3) in 100ms */
+	buf[6] = 3;	/* suspend retries */
+	buf[7] = 10;	/* resume timer (T4) in 100ms */
+	buf[8] = 3;	/* resume retries */
+	buf[9] = 10;	/* capability update timer (T5) */
+	buf[10] = 3;	/* capability update retries */
+
+	OSMO_ASSERT(ARRAY_SIZE(bts->gprs.cell.timer) < sizeof(buf));
+	memcpy(buf, bts->gprs.cell.timer, ARRAY_SIZE(bts->gprs.cell.timer));
+	msgb_tl16v_put(msgb, NM_ATT_IPACC_BSSGP_CFG, 11, buf);
+
+	return msgb;
+}
+
+struct msgb *nanobts_attr_cell_get(struct gsm_bts *bts)
+{
+	struct msgb *msgb;
+	uint8_t buf[256];
+	msgb = msgb_alloc(1024, "nanobts_attr_bts");
+
+	/* routing area code */
+	buf[0] = bts->gprs.rac;
+	msgb_tl16v_put(msgb, NM_ATT_IPACC_RAC, 1, buf);
+
+	buf[0] = 5;	/* repeat time (50ms) */
+	buf[1] = 3;	/* repeat count */
+	msgb_tl16v_put(msgb, NM_ATT_IPACC_GPRS_PAGING_CFG, 2, buf);
+
+	/* BVCI 925 */
+	buf[0] = bts->gprs.cell.bvci >> 8;
+	buf[1] = bts->gprs.cell.bvci & 0xff;
+	msgb_tl16v_put(msgb, NM_ATT_IPACC_BVCI, 2, buf);
+
+	/* all timers in seconds, unless otherwise stated */
+	buf[0] = 20;	/* T3142 */
+	buf[1] = 5;	/* T3169 */
+	buf[2] = 5;	/* T3191 */
+	buf[3] = 160;	/* T3193 (units of 10ms) */
+	buf[4] = 5;	/* T3195 */
+	buf[5] = 10;	/* N3101 */
+	buf[6] = 4;	/* N3103 */
+	buf[7] = 8;	/* N3105 */
+	buf[8] = 15;	/* RLC CV countdown */
+	msgb_tl16v_put(msgb, NM_ATT_IPACC_RLC_CFG, 9, buf);
+
+	if (bts->gprs.mode == BTS_GPRS_EGPRS) {
+		buf[0] = 0x8f;
+		buf[1] = 0xff;
+	} else {
+		buf[0] = 0x0f;
+		buf[1] = 0x00;
+	}
+	msgb_tl16v_put(msgb, NM_ATT_IPACC_CODING_SCHEMES, 2, buf);
+
+	buf[0] = 0;	/* T downlink TBF extension (0..500, high byte) */
+	buf[1] = 250;	/* T downlink TBF extension (0..500, low byte) */
+	buf[2] = 0;	/* T uplink TBF extension (0..500, high byte) */
+	buf[3] = 250;	/* T uplink TBF extension (0..500, low byte) */
+	buf[4] = 2;	/* CS2 */
+	msgb_tl16v_put(msgb, NM_ATT_IPACC_RLC_CFG_2, 5, buf);
+
+#if 0
+	/* EDGE model only, breaks older models.
+	 * Should inquire the BTS capabilities */
+	buf[0] = 2;		/* MCS2 */
+	msgb_tl16v_put(msgb, NM_ATT_IPACC_RLC_CFG_3, 1, buf);
+#endif
+
+	return msgb;
+}
+
+struct msgb *nanobts_attr_nscv_get(struct gsm_bts *bts)
+{
+	struct msgb *msgb;
+	uint8_t buf[256];
+	msgb = msgb_alloc(1024, "nanobts_attr_bts");
+
+	/* 925 */
+	buf[0] = bts->gprs.nsvc[0].nsvci >> 8;
+	buf[1] = bts->gprs.nsvc[0].nsvci & 0xff;
+	msgb_tl16v_put(msgb, NM_ATT_IPACC_NSVCI, 2, buf);
+
+	/* remote udp port */
+	patch_16(&buf[0], htons(bts->gprs.nsvc[0].remote_port));
+	/* remote ip address */
+	patch_32(&buf[2], htonl(bts->gprs.nsvc[0].remote_ip));
+	/* local udp port */
+	patch_16(&buf[6], htons(bts->gprs.nsvc[0].local_port));
+	msgb_tl16v_put(msgb, NM_ATT_IPACC_NS_LINK_CFG, 8, buf);
+
+	return msgb;
+}
+
+struct msgb *nanobts_attr_radio_get(struct gsm_bts *bts,
+				    struct gsm_bts_trx *trx)
+{
+	struct msgb *msgb;
+	uint8_t buf[256];
+	msgb = msgb_alloc(1024, "nanobts_attr_bts");
+
+	/* number of -2dB reduction steps / Pn */
+	msgb_tv_put(msgb, NM_ATT_RF_MAXPOWR_R, trx->max_power_red / 2);
+
+	buf[0] = trx->arfcn >> 8;
+	buf[1] = trx->arfcn & 0xff;
+	msgb_tl16v_put(msgb, NM_ATT_ARFCN_LIST, 2, buf);
+
+	return msgb;
+}
diff --git a/openbsc/tests/Makefile.am b/openbsc/tests/Makefile.am
index 468edd2..9cbc1c1 100644
--- a/openbsc/tests/Makefile.am
+++ b/openbsc/tests/Makefile.am
@@ -9,6 +9,7 @@
 	trau \
 	subscr \
 	mm_auth \
+	nanobts_omlattr \
 	$(NULL)
 
 if BUILD_NAT
diff --git a/openbsc/tests/nanobts_omlattr/Makefile.am b/openbsc/tests/nanobts_omlattr/Makefile.am
new file mode 100644
index 0000000..b03d50c
--- /dev/null
+++ b/openbsc/tests/nanobts_omlattr/Makefile.am
@@ -0,0 +1,34 @@
+AM_CPPFLAGS = \
+	$(all_includes) \
+	-I$(top_srcdir)/include \
+	$(NULL)
+
+AM_CFLAGS = \
+	-Wall \
+	$(LIBOSMOCORE_CFLAGS) \
+	$(LIBOSMOGSM_CFLAGS) \
+	$(LIBOSMOABIS_CFLAGS) \
+	$(NULL)
+
+noinst_PROGRAMS = \
+	nanobts_omlattr_test \
+	$(NULL)
+
+EXTRA_DIST = \
+	nanobts_omlattr_test.ok \
+	$(NULL)
+
+nanobts_omlattr_test_SOURCES = \
+	nanobts_omlattr_test.c \
+	$(NULL)
+
+nanobts_omlattr_test_LDADD = \
+	$(top_builddir)/src/libbsc/libbsc.a \
+	$(top_builddir)/src/libmsc/libmsc.a \
+	$(top_builddir)/src/libtrau/libtrau.a \
+	$(top_builddir)/src/libcommon/libcommon.a \
+	$(LIBOSMOCORE_LIBS) \
+	$(LIBOSMOGSM_LIBS) \
+	$(LIBOSMOABIS_LIBS) \
+	-ldbi \
+	$(NULL)
diff --git a/openbsc/tests/nanobts_omlattr/nanobts_omlattr_test.c b/openbsc/tests/nanobts_omlattr/nanobts_omlattr_test.c
new file mode 100644
index 0000000..ee138b8
--- /dev/null
+++ b/openbsc/tests/nanobts_omlattr/nanobts_omlattr_test.c
@@ -0,0 +1,284 @@
+/* Test OML attribute generator */
+
+/* (C) 2016 by sysmocom s.f.m.c. GmbH <info at sysmocom.de>
+ * All Rights Reserved
+ *
+ * Author: Philipp Maier
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation; either version 3 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <openbsc/gprs_llc_xid.h>
+#include <openbsc/debug.h>
+#include <openbsc/gsm_data.h>
+#include <openbsc/bts_ipaccess_nanobts_omlattr.h>
+
+#include <osmocom/core/talloc.h>
+#include <osmocom/core/utils.h>
+#include <osmocom/core/application.h>
+
+#include <stdio.h>
+#include <string.h>
+
+struct gsm_bts_model bts_model_nanobts = {
+	.type = GSM_BTS_TYPE_NANOBTS,
+	.name = "nanobts",
+	.start = NULL,
+	.oml_rcvmsg = NULL,
+	.e1line_bind_ops = NULL,
+	.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_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},
+				  },
+			  },
+};
+
+static void test_nanobts_attr_bts_get(struct gsm_bts *bts, uint8_t *expected)
+{
+	struct msgb *msgb;
+
+	printf("Testing nanobts_attr_bts_get()...\n");
+
+	msgb = nanobts_attr_bts_get(bts);
+	printf("result=  %s\n", osmo_hexdump_nospc(msgb->data, msgb->len));
+	printf("expected=%s\n", osmo_hexdump_nospc(expected, msgb->len));
+	OSMO_ASSERT(memcmp(msgb->data, expected, msgb->len) == 0);
+	msgb_free(msgb);
+
+	printf("ok.\n");
+	printf("\n");
+}
+
+static void test_nanobts_attr_nse_get(struct gsm_bts *bts, uint8_t *expected)
+{
+	struct msgb *msgb;
+
+	printf("Testing nanobts_attr_nse_get()...\n");
+
+	msgb = nanobts_attr_nse_get(bts);
+	printf("result=  %s\n", osmo_hexdump_nospc(msgb->data, msgb->len));
+	printf("expected=%s\n", osmo_hexdump_nospc(expected, msgb->len));
+	OSMO_ASSERT(memcmp(msgb->data, expected, msgb->len) == 0);
+	msgb_free(msgb);
+
+	printf("ok.\n");
+	printf("\n");
+}
+
+static void test_nanobts_attr_cell_get(struct gsm_bts *bts, uint8_t *expected)
+{
+	struct msgb *msgb;
+
+	printf("Testing nanobts_attr_cell_get()...\n");
+
+	msgb = nanobts_attr_cell_get(bts);
+	printf("result=  %s\n", osmo_hexdump_nospc(msgb->data, msgb->len));
+	printf("expected=%s\n", osmo_hexdump_nospc(expected, msgb->len));
+	OSMO_ASSERT(memcmp(msgb->data, expected, msgb->len) == 0);
+	msgb_free(msgb);
+
+	printf("ok.\n");
+	printf("\n");
+}
+
+static void test_nanobts_attr_nscv_get(struct gsm_bts *bts, uint8_t *expected)
+{
+	struct msgb *msgb;
+
+	printf("Testing nanobts_attr_nscv_get()...\n");
+
+	msgb = nanobts_attr_nscv_get(bts);
+	printf("result=  %s\n", osmo_hexdump_nospc(msgb->data, msgb->len));
+	printf("expected=%s\n", osmo_hexdump_nospc(expected, msgb->len));
+	OSMO_ASSERT(memcmp(msgb->data, expected, msgb->len) == 0);
+	msgb_free(msgb);
+
+	printf("ok.\n");
+	printf("\n");
+}
+
+static void test_nanobts_attr_radio_get(struct gsm_bts *bts,
+					struct gsm_bts_trx *trx,
+					uint8_t *expected)
+{
+	struct msgb *msgb;
+
+	printf("Testing nanobts_attr_nscv_get()...\n");
+
+	msgb = nanobts_attr_radio_get(bts, trx);
+	printf("result=  %s\n", osmo_hexdump_nospc(msgb->data, msgb->len));
+	printf("expected=%s\n", osmo_hexdump_nospc(expected, msgb->len));
+	OSMO_ASSERT(memcmp(msgb->data, expected, msgb->len) == 0);
+	msgb_free(msgb);
+
+	printf("ok.\n");
+	printf("\n");
+}
+
+int main(int argc, char **argv)
+{
+	void *ctx;
+
+	struct gsm_bts *bts;
+	struct gsm_network *net;
+	struct gsm_bts_trx *trx;
+
+	ctx = talloc_named_const(NULL, 0, "ctx");
+
+	/* Allocate environmental structs (bts, net, trx) */
+	net = talloc_zero(ctx, struct gsm_network);
+	INIT_LLIST_HEAD(&net->bts_list);
+	gsm_bts_model_register(&bts_model_nanobts);
+	bts = gsm_bts_alloc_register(net, GSM_BTS_TYPE_NANOBTS, 63);
+	OSMO_ASSERT(bts);
+	trx = talloc_zero(ctx, struct gsm_bts_trx);
+
+	/* Parameters needed by nanobts_attr_bts_get() */
+	bts->rach_b_thresh = -1;
+	bts->rach_ldavg_slots = -1;
+	bts->c0->arfcn = 866;
+	bts->cell_identity = 1337;
+	bts->network->country_code = 1;
+	bts->network->network_code = 1;
+	bts->location_area_code = 1;
+	bts->gprs.rac = 0;
+	uint8_t attr_bts_expected[] =
+	    { 0x19, 0x55, 0x5b, 0x61, 0x67, 0x6d, 0x73, 0x18, 0x06, 0x0e, 0x00,
+		0x02, 0x01, 0x20, 0x33, 0x1e, 0x24, 0x24, 0xa8, 0x34, 0x21,
+		0xa8, 0x1f, 0x3f, 0x25,
+		0x00, 0x01, 0x0a, 0x0c, 0x0a, 0x0b, 0x01, 0x2a, 0x0a, 0x2b,
+		0x03, 0xe8, 0x0a, 0x80,
+		0x23, 0x0a, 0x08, 0x03, 0x62, 0x09, 0x3f, 0x99, 0x00, 0x07,
+		0x00, 0xf1, 0x10, 0x00,
+		0x01, 0x05, 0x39
+	};
+
+	/* Parameters needed to test nanobts_attr_nse_get() */
+	bts->gprs.nse.nsei = 101;
+	uint8_t attr_nse_expected[] =
+	    { 0x9d, 0x00, 0x02, 0x00, 0x65, 0xa0, 0x00, 0x07, 0x03, 0x03, 0x03,
+		0x03, 0x1e, 0x03, 0x0a, 0xa1, 0x00, 0x0b, 0x03, 0x03, 0x03,
+		0x03, 0x03, 0x0a, 0x03,
+		0x0a, 0x03, 0x0a, 0x03
+	};
+
+	/* Parameters needed to test nanobts_attr_cell_get() */
+	bts->gprs.rac = 0x00;
+	bts->gprs.cell.bvci = 2;
+	bts->gprs.mode = BTS_GPRS_GPRS;
+	uint8_t attr_cell_expected[] =
+	    { 0x9a, 0x00, 0x01, 0x00, 0x9c, 0x00, 0x02, 0x05, 0x03, 0x9e, 0x00,
+		0x02, 0x00, 0x02, 0xa3, 0x00, 0x09, 0x14, 0x05, 0x05, 0xa0,
+		0x05, 0x0a, 0x04, 0x08,
+		0x0f, 0xa8, 0x00, 0x02, 0x0f, 0x00, 0xa9, 0x00, 0x05, 0x00,
+		0xfa, 0x00, 0xfa, 0x02
+	};
+
+	/* Parameters needed to test nanobts_attr_nscv_get() */
+	bts->gprs.nsvc[0].nsvci = 0x65;
+	bts->gprs.nsvc[0].remote_port = 0x59d8;
+	bts->gprs.nsvc[0].remote_ip = 0x0a090165;
+	bts->gprs.nsvc[0].local_port = 0x5a3c;
+	uint8_t attr_nscv_expected[] =
+	    { 0x9f, 0x00, 0x02, 0x00, 0x65, 0xa2, 0x00, 0x08, 0x59, 0xd8, 0x0a,
+		0x09, 0x01, 0x65, 0x5a, 0x3c
+	};
+
+	/* Parameters needed to test nanobts_attr_radio_get() */
+	trx->arfcn = 866;
+	trx->max_power_red = 22;
+	bts->c0->max_power_red = 22;
+	uint8_t attr_radio_expected[] =
+	    { 0x2d, 0x0b, 0x05, 0x00, 0x02, 0x03, 0x62 };
+
+	/* Run tests */
+	test_nanobts_attr_bts_get(bts, attr_bts_expected);
+	test_nanobts_attr_nse_get(bts, attr_nse_expected);
+	test_nanobts_attr_cell_get(bts, attr_cell_expected);
+	test_nanobts_attr_nscv_get(bts, attr_nscv_expected);
+	test_nanobts_attr_radio_get(bts, trx, attr_radio_expected);
+
+	printf("Done\n");
+	talloc_free(bts);
+	talloc_free(net);
+	talloc_free(trx);
+	talloc_report_full(ctx, stderr);
+	OSMO_ASSERT(talloc_total_blocks(ctx) == 1);
+	return 0;
+}
+
+/* stubs */
+struct osmo_prim_hdr;
+int bssgp_prim_cb(struct osmo_prim_hdr *oph, void *ctx)
+{
+	abort();
+}
diff --git a/openbsc/tests/nanobts_omlattr/nanobts_omlattr_test.ok b/openbsc/tests/nanobts_omlattr/nanobts_omlattr_test.ok
new file mode 100644
index 0000000..91b655f
--- /dev/null
+++ b/openbsc/tests/nanobts_omlattr/nanobts_omlattr_test.ok
@@ -0,0 +1,26 @@
+Testing nanobts_attr_bts_get()...
+result=  19555b61676d7318060e00020120331e2424a83421a81f3f2500010a0c0a0b012a0a2b03e80a80230a080362093f99000700f11000010539
+expected=19555b61676d7318060e00020120331e2424a83421a81f3f2500010a0c0a0b012a0a2b03e80a80230a080362093f99000700f11000010539
+ok.
+
+Testing nanobts_attr_nse_get()...
+result=  9d00020065a00007030303031e030aa1000b03030303030a030a030a03
+expected=9d00020065a00007030303031e030aa1000b03030303030a030a030a03
+ok.
+
+Testing nanobts_attr_cell_get()...
+result=  9a0001009c000205039e00020002a30009140505a0050a04080fa800020f00a9000500fa00fa02
+expected=9a0001009c000205039e00020002a30009140505a0050a04080fa800020f00a9000500fa00fa02
+ok.
+
+Testing nanobts_attr_nscv_get()...
+result=  9f00020065a2000859d80a0901655a3c
+expected=9f00020065a2000859d80a0901655a3c
+ok.
+
+Testing nanobts_attr_nscv_get()...
+result=  2d0b0500020362
+expected=2d0b0500020362
+ok.
+
+Done
diff --git a/openbsc/tests/testsuite.at b/openbsc/tests/testsuite.at
index 4905cd1..b44d595 100644
--- a/openbsc/tests/testsuite.at
+++ b/openbsc/tests/testsuite.at
@@ -151,3 +151,9 @@
 cat $abs_srcdir/v42bis/v42bis_test.ok > expout
 AT_CHECK([$abs_top_builddir/tests/v42bis/v42bis_test], [], [expout], [ignore])
 AT_CLEANUP
+
+AT_SETUP([nanobts_omlattr])
+AT_KEYWORDS([nanobts_omlattr])
+cat $abs_srcdir/nanobts_omlattr/nanobts_omlattr_test.ok > expout
+AT_CHECK([$abs_top_builddir/tests/nanobts_omlattr/nanobts_omlattr_test], [], [expout], [ignore])
+AT_CLEANUP

-- 
To view, visit https://gerrit.osmocom.org/973
To unsubscribe, visit https://gerrit.osmocom.org/settings

Gerrit-MessageType: newpatchset
Gerrit-Change-Id: Ibeb34a84912d6cf695f553a34c69320fca7d08fa
Gerrit-PatchSet: 4
Gerrit-Project: openbsc
Gerrit-Branch: master
Gerrit-Owner: dexter <pmaier at sysmocom.de>
Gerrit-Reviewer: Harald Welte <laforge at gnumonks.org>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: Neels Hofmeyr <nhofmeyr at sysmocom.de>



More information about the gerrit-log mailing list