[PATCH] libosmocore[master]: Add SW Description (de)marshalling

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/.

Max gerrit-no-reply at lists.osmocom.org
Tue Apr 4 16:27:19 UTC 2017


Hello Neels Hofmeyr, Jenkins Builder,

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

    https://gerrit.osmocom.org/2165

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

Add SW Description (de)marshalling

* data structure representing 3GPP TS 52.021 §9.4.62 SW Description
* function to serialize it into msgb
* function to deserialize it from buffer
* functions to extract/estimate buffer size for SW Description
* test harness (partially taken from OpenBSC)

There are several similar functions to deal with SW Description in
OpenBSC, there's also need to use similar functionality in
OsmoBTS. Hence it's better to put the code into common library with
proper tests and documentation.

Change-Id: Ib63b6b5e83b8914864fc7edd789f8958cdc993cd
Related: OS#1614
---
M .gitignore
M include/osmocom/gsm/protocol/gsm_12_21.h
M src/gsm/abis_nm.c
M src/gsm/libosmogsm.map
M tests/Makefile.am
A tests/abis/abis_test.c
A tests/abis/abis_test.ok
M tests/testsuite.at
8 files changed, 436 insertions(+), 1 deletion(-)


  git pull ssh://gerrit.osmocom.org:29418/libosmocore refs/changes/65/2165/11

diff --git a/.gitignore b/.gitignore
index ecbcedd..4c6a78f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -60,6 +60,7 @@
 tests/testsuite
 tests/testsuite.dir/
 tests/testsuite.log
+tests/abis/abis_test
 tests/ctrl/ctrl_test
 tests/utils/utils_test
 tests/stats/stats_test
diff --git a/include/osmocom/gsm/protocol/gsm_12_21.h b/include/osmocom/gsm/protocol/gsm_12_21.h
index c88f0b1..09d8432 100644
--- a/include/osmocom/gsm/protocol/gsm_12_21.h
+++ b/include/osmocom/gsm/protocol/gsm_12_21.h
@@ -29,6 +29,7 @@
 /*! \file gsm_12_21.h */
 
 #include <stdint.h>
+#include <stdbool.h>
 #include <osmocom/gsm/tlv.h>
 
 /*! \brief generic header in front of every OML message according to TS 08.59 */
@@ -791,6 +792,22 @@
 	IPAC_BINF_CELL_ALLOC		= (1 << 2),
 };
 
+/*! \brief 3GPP TS 52.021 §9.4.62 SW Description */
+struct abis_nm_sw_descr {
+	uint8_t file_id[UINT8_MAX];
+	uint8_t file_id_len;
+
+	uint8_t file_version[UINT8_MAX];
+	uint8_t file_version_len;
+};
+
+uint16_t abis_nm_sw_descr_len(const struct abis_nm_sw_descr *sw,
+			      bool put_sw_descr);
+uint16_t abis_nm_put_sw_descr(struct msgb *msg, const struct abis_nm_sw_descr *sw,
+			      bool put_sw_descr);
+uint32_t abis_nm_get_sw_descr_len(const uint8_t * buf, size_t len);
+int abis_nm_get_sw_conf(const uint8_t * buf, size_t buf_len,
+			struct abis_nm_sw_descr *sw, uint16_t sw_len);
 struct msgb *abis_nm_fail_evt_rep(enum abis_nm_event_type t,
 				  enum abis_nm_severity s,
 				  enum abis_nm_pcause_type ct,
diff --git a/src/gsm/abis_nm.c b/src/gsm/abis_nm.c
index 934d7ce..4acd322 100644
--- a/src/gsm/abis_nm.c
+++ b/src/gsm/abis_nm.c
@@ -751,6 +751,148 @@
 	return nmsg;
 }
 
+/*! \brief Compute length of given 3GPP TS 52.021 §9.4.62 SW Description.
+ *  \param[in] sw SW Description struct
+ *  \param[in] put_sw_descr boolean, whether to put NM_ATT_SW_DESCR IE or not
+ *  \returns length of buffer space necessary to store sw
+ */
+uint16_t abis_nm_sw_descr_len(const struct abis_nm_sw_descr *sw,
+			      bool put_sw_descr)
+{
+	/* +3: type is 1-byte, length is 2-byte */
+	return (put_sw_descr ? 1 : 0) + (sw->file_id_len + 3) +
+	       (sw->file_version_len + 3);
+}
+
+/*! \brief Put given 3GPP TS 52.021 §9.4.62 SW Description into msgb.
+ *  \param[out] msg message buffer
+ *  \param[in] sw SW Description struct
+ *  \param[in] put_sw_descr boolean, whether to put NM_ATT_SW_DESCR IE or not
+ *  \param[in] simulate boolean, whether to actually modify msg or not
+ *  \returns length of buffer space necessary to store sw
+ */
+uint16_t abis_nm_put_sw_descr(struct msgb *msg, const struct abis_nm_sw_descr *sw,
+			      bool put_sw_descr)
+{
+	if (put_sw_descr)
+		msgb_v_put(msg, NM_ATT_SW_DESCR);
+	msgb_tl16v_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
+	msgb_tl16v_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
+		       sw->file_version);
+
+	return abis_nm_sw_descr_len(sw, put_sw_descr);
+}
+
+/*! \brief Get length of first 3GPP TS 52.021 §9.4.62 SW Description from buffer.
+ *  \param[in] buf buffer, may contain several SW Descriptions
+ *  \param[in] len buffer length
+ *  \returns length if parsing succeeded, 0 otherwise
+ */
+uint32_t abis_nm_get_sw_descr_len(const uint8_t *buf, size_t len)
+{
+	uint16_t sw = 2; /* 1-byte SW tag + 1-byte FILE_* tag */
+
+	if (buf[0] != NM_ATT_SW_DESCR)
+		sw = 1; /* 1-byte FILE_* tag */
+
+	if (buf[sw - 1] != NM_ATT_FILE_ID && buf[sw - 1] != NM_ATT_FILE_VERSION)
+		return 0;
+
+	/* + length of 1st FILE_* element + 1-byte tag + 2-byte length field of
+	   1st FILE_* element */
+	sw += (osmo_load16be(buf + sw) + 3);
+
+	/* + length of 2nd FILE_* element */
+	sw += osmo_load16be(buf + sw);
+
+	return sw + 2; /* +  2-byte length field of 2nd FILE_* element */
+}
+
+/*! \brief Parse single 3GPP TS 52.021 §9.4.62 SW Description from buffer.
+ *  \param[out] sw SW Description struct
+ *  \param[in] buf buffer
+ *  \param[in] len buffer length
+ *  \returns 0 if parsing succeeded, negative error code otherwise
+ */
+static inline int abis_nm_get_sw_descr(struct abis_nm_sw_descr *sw,
+				       const uint8_t *buf, size_t length)
+{
+	int rc;
+	uint32_t len = abis_nm_get_sw_descr_len(buf, length);
+	static struct tlv_parsed tp;
+	const struct tlv_definition sw_tlvdef = {
+		.def = {
+			[NM_ATT_SW_DESCR] =		{ TLV_TYPE_TV },
+			[NM_ATT_FILE_ID] =		{ TLV_TYPE_TL16V },
+			[NM_ATT_FILE_VERSION] =		{ TLV_TYPE_TL16V },
+		},
+	};
+
+	/* Basic sanity check */
+	if (len > length)
+		return -EFBIG;
+
+	/* Note: current implementation of TLV parser fails on multilpe SW Descr:
+	   we will only parse the first one */
+	if (!len)
+		return -EINVAL;
+
+	/* Note: the return value is ignored here because SW Description tag
+	   itself is considered optional. */
+	tlv_parse(&tp, &sw_tlvdef, buf, len, 0, 0);
+
+	/* Parsing SW Description is tricky for current implementation of TLV
+	   parser which fails to properly handle TV when V has following
+	   structure: | TL16V | TL16V |. Hence, the need for 2nd call: */
+	rc = tlv_parse(&tp, &sw_tlvdef, buf + TLVP_LEN(&tp, NM_ATT_SW_DESCR),
+		       len - TLVP_LEN(&tp, NM_ATT_SW_DESCR), 0, 0);
+
+	if (rc < 0)
+		return rc;
+
+	if (!TLVP_PRESENT(&tp, NM_ATT_FILE_ID))
+		return -EBADF;
+
+	if (!TLVP_PRESENT(&tp, NM_ATT_FILE_VERSION))
+		return -EBADMSG;
+
+	sw->file_id_len = TLVP_LEN(&tp, NM_ATT_FILE_ID);
+	sw->file_version_len = TLVP_LEN(&tp, NM_ATT_FILE_VERSION);
+
+	memcpy(sw->file_id, TLVP_VAL(&tp, NM_ATT_FILE_ID), sw->file_id_len);
+	memcpy(sw->file_version, TLVP_VAL(&tp, NM_ATT_FILE_VERSION),
+	       sw->file_version_len);
+
+	return 0;
+}
+
+/*! \brief Parse 3GPP TS 52.021 §9.4.61 SW Configuration from buffer.
+ *  \param[in] buf buffer
+ *  \param[in] buf_len buffer length
+ *  \param[out] sw SW Description struct array
+ *  \param[in] sw_len Expected number of SW Description entries
+ *  \returns 0 if parsing succeeded, negative error code otherwise
+ */
+int abis_nm_get_sw_conf(const uint8_t * buf, size_t buf_len,
+			struct abis_nm_sw_descr *sw, uint16_t sw_len)
+{
+	int rc;
+	uint16_t len = 0, i;
+	for (i = 0; i < sw_len; i++) {
+		memset(&sw[i], 0, sizeof(sw[i]));
+		rc = abis_nm_get_sw_descr(&sw[i], buf + len, buf_len - len);
+		if (rc < 0)
+			return rc;
+
+		len += abis_nm_get_sw_descr_len(buf + len, buf_len - len);
+
+		if (len >= buf_len)
+			return i + 1;
+	}
+
+	return i;
+}
+
 /*! \brief Obtain OML Channel Combination for phnsical channel config */
 int abis_nm_chcomb4pchan(enum gsm_phys_chan_config pchan)
 {
diff --git a/src/gsm/libosmogsm.map b/src/gsm/libosmogsm.map
index 5649e71..f9c75c3 100644
--- a/src/gsm/libosmogsm.map
+++ b/src/gsm/libosmogsm.map
@@ -31,6 +31,10 @@
 abis_nm_pcause_type_names;
 abis_nm_msgtype_names;
 abis_nm_att_names;
+abis_nm_sw_descr_len;
+abis_nm_put_sw_descr;
+abis_nm_get_sw_conf;
+abis_nm_get_sw_descr_len;
 
 osmo_sitype_strs;
 osmo_c4;
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 352b5a7..a50e6b2 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -15,7 +15,7 @@
 		 bitvec/bitvec_test msgb/msgb_test bits/bitcomp_test	\
 		 tlv/tlv_test gsup/gsup_test oap/oap_test fsm/fsm_test	\
 		 write_queue/wqueue_test socket/socket_test		\
-		 coding/coding_test
+		 coding/coding_test abis/abis_test
 
 if ENABLE_MSGFILE
 check_PROGRAMS += msgfile/msgfile_test
@@ -43,6 +43,9 @@
 auth_milenage_test_SOURCES = auth/milenage_test.c
 auth_milenage_test_LDADD = $(top_builddir)/src/libosmocore.la $(top_builddir)/src/gsm/libosmogsm.la
 
+abis_abis_test_SOURCES = abis/abis_test.c
+abis_abis_test_LDADD = $(top_builddir)/src/libosmocore.la $(top_builddir)/src/gsm/libosmogsm.la
+
 ctrl_ctrl_test_SOURCES = ctrl/ctrl_test.c
 ctrl_ctrl_test_LDADD = $(top_builddir)/src/libosmocore.la $(top_builddir)/src/ctrl/libosmoctrl.la
 
diff --git a/tests/abis/abis_test.c b/tests/abis/abis_test.c
new file mode 100644
index 0000000..beb50f2
--- /dev/null
+++ b/tests/abis/abis_test.c
@@ -0,0 +1,221 @@
+/*
+ * (C) 2012 by Holger Hans Peter Freyther <zecke at selfish.org>
+ * (C) 2017 by sysmocom s.m.f.c. GmbH <info at sysmocom.de>
+ * 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 <osmocom/core/application.h>
+#include <osmocom/core/logging.h>
+#include <osmocom/core/utils.h>
+#include <osmocom/gsm/lapdm.h>
+#include <osmocom/gsm/rsl.h>
+#include <osmocom/gsm/protocol/gsm_12_21.h>
+
+#include <errno.h>
+#include <stdbool.h>
+#include <string.h>
+
+static struct log_info info = {};
+
+static const uint8_t simple_config[] = { 66, 18, 0, 3, 1, 2, 3, 19, 0, 3, 3, 4, 5 };
+
+static const uint8_t dual_config[] = {
+	66, 18, 0, 3, 1, 2, 3, 19, 0, 3, 3, 4, 5,
+	66, 18, 0, 3, 9, 7, 5, 19, 0, 3, 6, 7, 8,
+};
+
+static void test_simple_sw_config(void)
+{
+	struct abis_nm_sw_descr descr[1];
+	uint16_t len;
+	int rc;
+
+	rc = abis_nm_get_sw_conf(simple_config, ARRAY_SIZE(simple_config),
+				&descr[0], ARRAY_SIZE(descr));
+	if (rc != 1) {
+		printf("%s(): FAILED to parse the File Id/File version: %d\n",
+		       __func__, rc);
+		abort();
+	}
+
+	len = abis_nm_sw_descr_len(&descr[0], true);
+	if (len != 13) {
+		printf("WRONG SIZE: %u\n", len);
+		abort();
+	}
+
+	printf("len: %u\n", len);
+	printf("file_id:  %s\n", osmo_hexdump(descr[0].file_id, descr[0].file_id_len));
+	printf("file_ver: %s\n", osmo_hexdump(descr[0].file_version, descr[0].file_version_len));
+	printf("%s(): OK\n", __func__);
+}
+
+static void test_simple_sw_short(void)
+{
+	struct abis_nm_sw_descr descr[1];
+	int i;
+
+	for (i = 1; i < ARRAY_SIZE(simple_config); ++i) {
+		int rc = abis_nm_get_sw_conf(simple_config,
+				ARRAY_SIZE(simple_config) - i, &descr[0],
+				ARRAY_SIZE(descr));
+		if (rc >= 1) {
+			printf("SHOULD not have parsed: %d\n", rc);
+			abort();
+		}
+	}
+	printf("%s(): OK\n", __func__);
+}
+
+static void test_dual_sw_config(void)
+{
+	struct abis_nm_sw_descr descr[2];
+	uint16_t len0, len1;
+	int rc;
+
+	rc = abis_nm_get_sw_conf(dual_config, ARRAY_SIZE(dual_config),
+				&descr[0], ARRAY_SIZE(descr));
+	if (rc != 2) {
+		printf("%s(): FAILED to parse the File Id/File version: %d (%d,%d)\n",
+		       __func__, -rc, EBADF, EBADMSG);
+		abort();
+	}
+
+	len0 = abis_nm_sw_descr_len(&descr[0], true);
+	if (len0 != 13) {
+		printf("WRONG SIZE0: %u\n", len0);
+		abort();
+	}
+
+	len1 = abis_nm_sw_descr_len(&descr[1], true);
+	if (len1 != 13) {
+		printf("WRONG SIZE1: %u\n", len1);
+		abort();
+	}
+
+	printf("len: %u\n", len0);
+	printf("file_id:  %s\n", osmo_hexdump(descr[0].file_id, descr[0].file_id_len));
+	printf("file_ver: %s\n", osmo_hexdump(descr[0].file_version, descr[0].file_version_len));
+
+	printf("len: %u\n", len1);
+	printf("file_id:  %s\n", osmo_hexdump(descr[1].file_id, descr[1].file_id_len));
+	printf("file_ver: %s\n", osmo_hexdump(descr[1].file_version, descr[1].file_version_len));
+	printf("%s(): OK\n", __func__);
+}
+
+static inline void print_chk(const char *what, uint8_t len1, uint8_t len2,
+			     const uint8_t *x1, const uint8_t *x2)
+{
+	int cmp = memcmp(x1, x2, len2);
+	printf("\tFILE %s [%u == %u -> %d, %s] %d => %s\n", what, len1, len2,
+	       len1 == len2, len1 != len2 ? "fail" : "ok",
+	       cmp, cmp != 0 ? "FAIL" : "OK");
+}
+
+static inline void chk_descr(struct msgb *msg, struct abis_nm_sw_descr *put,
+			     const char *descr, bool header)
+{
+	int res;
+	struct abis_nm_sw_descr sw = { 0 };
+	uint16_t len = abis_nm_put_sw_descr(msg, put, header);
+
+	printf("msgb[%u] :: {msgb->len} %u == %u {len}  - %s]:\n\t"
+	       "SW DESCR (%s)\n\t"
+	       "length: {extracted} %u = %u {expected} - %s, failsafe - %s\n",
+	       msg->data_len, msg->len, len, len != msg->len ? "fail" : "ok",
+	       descr, abis_nm_get_sw_descr_len(msgb_data(msg), msg->len),
+	       msg->len,
+	       abis_nm_get_sw_descr_len(msgb_data(msg), msg->len) != msg->len ? "FAIL" : "OK",
+	       len > put->file_version_len + put->file_id_len ? "OK" : "FAIL");
+
+	res = abis_nm_get_sw_conf(msgb_data(msg), msg->len, &sw, 1);
+	if (res < 0)
+		printf("\tSW DESCR (%s) parsing error code %d!\n", descr, -res);
+	else {
+		print_chk("ID", sw.file_id_len, put->file_id_len, sw.file_id,
+			  put->file_id);
+		print_chk("VERSION", sw.file_version_len,
+			  put->file_version_len, sw.file_version,
+			  put->file_version);
+	}
+}
+
+static inline void chk_raw(const char *what, const uint8_t *data, uint16_t len)
+{
+	struct abis_nm_sw_descr sw = { 0 };
+	int res = abis_nm_get_sw_conf(data, len, &sw, 1);
+	uint16_t xlen = abis_nm_get_sw_descr_len(data, len);
+
+	printf("parsing chained %s <1st: %d, total: %d>\n\tSW Descr (%s)\n",
+	       osmo_hexdump(data, len), xlen, len, what);
+
+	if (res < 0)
+		printf("\tFAIL: %d\n", -res);
+	else {
+		printf("\tFILE ID: [%d] %s => OK\n", sw.file_id_len,
+		       osmo_hexdump(sw.file_id, sw.file_id_len));
+		printf("\tFILE VERSION: [%d] %s => OK\n", sw.file_version_len,
+		       osmo_hexdump(sw.file_version, sw.file_version_len));
+	}
+
+	if (len != xlen)
+		chk_raw(" 2nd", data + xlen, len - xlen);
+}
+
+static void test_sw_descr()
+{
+	const char *f_id = "TEST.L0L", *f_ver = "0.1.666~deadbeeffacefeed-dirty";
+	uint8_t lf_id = strlen(f_id), lf_ver = strlen(f_ver);
+	uint8_t chain[] = { 0x42, 0x12, 0x00, 0x03, 0x01, 0x02, 0x03, 0x13, 0x00, 0x03, 0x03, 0x04, 0x05, 0x42, 0x12, 0x00, 0x03, 0x09, 0x07, 0x05, 0x13, 0x00, 0x03, 0x06, 0x07, 0x08 };
+	struct msgb *msg = msgb_alloc_headroom(4096, 128, "sw");
+	struct abis_nm_sw_descr sw_put = {
+		.file_id_len = lf_id,
+		.file_version_len = lf_ver,
+	};
+
+	printf("Testing SW Description (de)serialization...\n");
+
+	memcpy(sw_put.file_id, f_id, lf_id);
+	memcpy(sw_put.file_version, f_ver, lf_ver);
+
+	/* check that parsing |SW|ID|VER| works: */
+	chk_descr(msg, &sw_put, "with header", true);
+	msgb_reset(msg);
+	/* check that parsing |ID|VER| works: */
+	chk_descr(msg, &sw_put, "without header", false);
+	/* check that parsing |ID|VER|SW|ID|VER| fails - notice the lack of
+	   msgb_reset() to create bogus msgb data: */
+	chk_descr(msg, &sw_put, "expected failure", true);
+	/* check multiple, chained SW-descr: */
+	chk_raw("half", chain, sizeof(chain) / 2);
+	chk_raw("full", chain, sizeof(chain));
+}
+
+int main(int argc, char **argv)
+{
+	osmo_init_logging(&info);
+
+	test_sw_descr();
+	test_simple_sw_config();
+	test_simple_sw_short();
+	test_dual_sw_config();
+
+	printf("OK.\n");
+
+	return 0;
+}
diff --git a/tests/abis/abis_test.ok b/tests/abis/abis_test.ok
new file mode 100644
index 0000000..e6b626b
--- /dev/null
+++ b/tests/abis/abis_test.ok
@@ -0,0 +1,41 @@
+Testing SW Description (de)serialization...
+msgb[4096] :: {msgb->len} 45 == 45 {len}  - ok]:
+	SW DESCR (with header)
+	length: {extracted} 45 = 45 {expected} - OK, failsafe - OK
+	FILE ID [8 == 8 -> 1, ok] 0 => OK
+	FILE VERSION [30 == 30 -> 1, ok] 0 => OK
+msgb[4096] :: {msgb->len} 44 == 44 {len}  - ok]:
+	SW DESCR (without header)
+	length: {extracted} 44 = 44 {expected} - OK, failsafe - OK
+	FILE ID [8 == 8 -> 1, ok] 0 => OK
+	FILE VERSION [30 == 30 -> 1, ok] 0 => OK
+msgb[4096] :: {msgb->len} 89 == 45 {len}  - fail]:
+	SW DESCR (expected failure)
+	length: {extracted} 44 = 89 {expected} - FAIL, failsafe - OK
+	FILE ID [8 == 8 -> 1, ok] 0 => OK
+	FILE VERSION [30 == 30 -> 1, ok] 0 => OK
+parsing chained 42 12 00 03 01 02 03 13 00 03 03 04 05  <1st: 13, total: 13>
+	SW Descr (half)
+	FILE ID: [3] 01 02 03  => OK
+	FILE VERSION: [3] 03 04 05  => OK
+parsing chained 42 12 00 03 01 02 03 13 00 03 03 04 05 42 12 00 03 09 07 05 13 00 03 06 07 08  <1st: 13, total: 26>
+	SW Descr (full)
+	FILE ID: [3] 01 02 03  => OK
+	FILE VERSION: [3] 03 04 05  => OK
+parsing chained 42 12 00 03 09 07 05 13 00 03 06 07 08  <1st: 13, total: 13>
+	SW Descr ( 2nd)
+	FILE ID: [3] 09 07 05  => OK
+	FILE VERSION: [3] 06 07 08  => OK
+len: 13
+file_id:  01 02 03 
+file_ver: 03 04 05 
+test_simple_sw_config(): OK
+test_simple_sw_short(): OK
+len: 13
+file_id:  01 02 03 
+file_ver: 03 04 05 
+len: 13
+file_id:  09 07 05 
+file_ver: 06 07 08 
+test_dual_sw_config(): OK
+OK.
diff --git a/tests/testsuite.at b/tests/testsuite.at
index 64df724..7ee0164 100644
--- a/tests/testsuite.at
+++ b/tests/testsuite.at
@@ -9,6 +9,12 @@
 AT_CHECK([$abs_top_builddir/tests/a5/a5_test], [0], [expout])
 AT_CLEANUP
 
+AT_SETUP([abis])
+AT_KEYWORDS([abis])
+cat $abs_srcdir/abis/abis_test.ok > expout
+AT_CHECK([$abs_top_builddir/tests/abis/abis_test], [0], [expout], [ignore])
+AT_CLEANUP
+
 AT_SETUP([ctrl])
 AT_KEYWORDS([ctrl])
 cat $abs_srcdir/ctrl/ctrl_test.ok > expout

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

Gerrit-MessageType: newpatchset
Gerrit-Change-Id: Ib63b6b5e83b8914864fc7edd789f8958cdc993cd
Gerrit-PatchSet: 11
Gerrit-Project: libosmocore
Gerrit-Branch: master
Gerrit-Owner: Max <msuraev at sysmocom.de>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: Max <msuraev at sysmocom.de>
Gerrit-Reviewer: Neels Hofmeyr <nhofmeyr at sysmocom.de>



More information about the gerrit-log mailing list