Change in libosmocore[master]: add BSSLAP coding for Location Services

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

neels gerrit-no-reply at lists.osmocom.org
Thu Oct 1 01:40:20 UTC 2020


neels has uploaded this change for review. ( https://gerrit.osmocom.org/c/libosmocore/+/20333 )


Change subject: add BSSLAP coding for Location Services
......................................................................

add BSSLAP coding for Location Services

BSSLAP: there are APDUs transferred in BSSMAP-LE Connection Oriented
Information messages on Lb between BSC and SMLC.
Add BSSLAP coding for these APDU messages:
- TA Layer3
- TA Request
- TA Response, possibly containing Location Estimate coded in GAD
- Reject
- Reset (for intra-BSS handover during TA Request)
- Abort (for inter-BSS handover)

Add encoding and decoding tests.

Change-Id: I6409c4bcac402dc7626a3afce9081c59cd715fe8
---
M include/Makefile.am
A include/osmocom/gsm/bsslap.h
M src/gsm/Makefile.am
A src/gsm/bsslap.c
M src/gsm/libosmogsm.map
M tests/Makefile.am
A tests/bsslap/bsslap_test.c
A tests/bsslap/bsslap_test.ok
M tests/testsuite.at
9 files changed, 691 insertions(+), 1 deletion(-)



  git pull ssh://gerrit.osmocom.org:29418/libosmocore refs/changes/33/20333/1

diff --git a/include/Makefile.am b/include/Makefile.am
index a505952..7aa6442 100644
--- a/include/Makefile.am
+++ b/include/Makefile.am
@@ -92,6 +92,7 @@
                        osmocom/coding/gsm0503_interleaving.h \
                        osmocom/coding/gsm0503_coding.h \
                        osmocom/coding/gsm0503_amr_dtx.h \
+                       osmocom/gsm/bsslap.h \
                        osmocom/gsm/gad.h \
                        osmocom/gsm/gsm0808.h \
                        osmocom/gsm/gsm29205.h \
diff --git a/include/osmocom/gsm/bsslap.h b/include/osmocom/gsm/bsslap.h
new file mode 100644
index 0000000..135a943
--- /dev/null
+++ b/include/osmocom/gsm/bsslap.h
@@ -0,0 +1,105 @@
+/*! \defgroup bsslap Message encoding and decoding for 3GPP TS 48.071 BSS LCS Assistance Protocol (BSSLAP).
+ *  @{
+ *  \file bsslap.h
+ */
+/*
+ * (C) 2020 by sysmocom - s.f.m.c. GmbH <info at sysmocom.de>
+ * All Rights Reserved
+ *
+ * Author: Neels Hofmeyr <neels at hofmeyr.de>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ *
+ * 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.
+ *
+ */
+#pragma once
+
+#include <errno.h>
+
+#include <osmocom/core/utils.h>
+#include <osmocom/gsm/protocol/gsm_08_08.h>
+#include <osmocom/gsm/gsm0808.h>
+#include <osmocom/gsm/tlv.h>
+
+enum osmo_bsslap_msgt {
+	OSMO_BSSLAP_MSGT_TA_REQUEST = 0x1,
+	OSMO_BSSLAP_MSGT_TA_RESPONSE = 0x2,
+	OSMO_BSSLAP_MSGT_REJECT = 0xa,
+	OSMO_BSSLAP_MSGT_RESET = 0xb,
+	OSMO_BSSLAP_MSGT_ABORT = 0xc,
+	OSMO_BSSLAP_MSGT_TA_LAYER3 = 0xd,
+	OSMO_BSSLAP_MSGT_MS_POS_CMD = 0xf,
+	OSMO_BSSLAP_MSGT_MS_POS_RESP = 0x10,
+	OSMO_BSSLAP_MSGT_UTDOA_REQ = 0x11,
+	OSMO_BSSLAP_MSGT_UTDOA_RESP = 0x12,
+};
+
+extern const struct value_string osmo_bsslap_msgt_names[];
+static inline const char *osmo_bsslap_msgt_name(enum osmo_bsslap_msgt val)
+{ return get_value_string(osmo_bsslap_msgt_names, val); }
+
+enum osmo_bsslap_cause {
+	OSMO_BSSLAP_CAUSE_CONGESTION = 0x0,
+	OSMO_BSSLAP_CAUSE_CHAN_MODE_NOT_SUPP = 0x1,
+	OSMO_BSSLAP_CAUSE_POS_PROC_NOT_SUPP = 0x2,
+	OSMO_BSSLAP_CAUSE_OTHER_RADIO_EVT_FAIL = 0x3,
+	OSMO_BSSLAP_CAUSE_INTRA_BSS_HO = 0x4,
+	OSMO_BSSLAP_CAUSE_SUPERV_TIMER_EXPIRED = 0x5,
+	OSMO_BSSLAP_CAUSE_INTER_BSS_HO = 0x6,
+	OSMO_BSSLAP_CAUSE_LOSS_SIG_CONN_MS = 0x7,
+	OSMO_BSSLAP_CAUSE_INCORR_SERV_CELL_ID = 0x8,
+	OSMO_BSSLAP_CAUSE_BSSAP_LE_SEGMENT_ERR = 0x9,
+	OSMO_BSSLAP_CAUSE_CONCUR_POS_PROC_NOT_EN = 0xa,
+};
+
+struct osmo_bsslap_ta_response {
+	uint16_t cell_id;
+	uint8_t ta;
+
+	bool more_items; /*!< always set this to false */
+};
+
+struct osmo_bsslap_ta_layer3 {
+	uint8_t ta;
+
+	bool more_items; /*!< always set this to false */
+};
+
+struct osmo_bsslap_reset {
+	uint16_t cell_id;
+	uint8_t ta;
+	struct gsm48_chan_desc chan_desc;
+	enum osmo_bsslap_cause cause;
+
+	bool more_items; /*!< always set this to false */
+};
+
+struct osmo_bsslap_pdu {
+	enum osmo_bsslap_msgt msg_type;
+	union {
+		/* ta_request: a TA Request message consists only of the message type. */
+		struct osmo_bsslap_ta_response ta_response;
+		enum osmo_bsslap_cause reject;
+		struct osmo_bsslap_reset reset;
+		enum osmo_bsslap_cause abort;
+		struct osmo_bsslap_ta_layer3 ta_layer3;
+	};
+};
+
+int osmo_bsslap_enc(struct msgb *msg, const struct osmo_bsslap_pdu *pdu);
+const char *osmo_bsslap_dec(struct osmo_bsslap_pdu *pdu, const uint8_t *data, size_t len);
+
+/*! @} */
diff --git a/src/gsm/Makefile.am b/src/gsm/Makefile.am
index 4fa940b..465bae1 100644
--- a/src/gsm/Makefile.am
+++ b/src/gsm/Makefile.am
@@ -33,7 +33,7 @@
 			gsup.c gsup_sms.c gprs_gea.c gsm0503_conv.c oap.c gsm0808_utils.c \
 			gsm23003.c gsm23236.c mncc.c bts_features.c oap_client.c \
 			gsm29118.c gsm48_rest_octets.c cbsp.c gsm48049.c i460_mux.c \
-			gad.c
+			gad.c bsslap.c
 libgsmint_la_LDFLAGS = -no-undefined
 libgsmint_la_LIBADD = $(top_builddir)/src/libosmocore.la
 
diff --git a/src/gsm/bsslap.c b/src/gsm/bsslap.c
new file mode 100644
index 0000000..a874789
--- /dev/null
+++ b/src/gsm/bsslap.c
@@ -0,0 +1,461 @@
+/* 3GPP TS 48.071 BSSLAP protocol definitions */
+/*
+ * (C) 2020 by sysmocom - s.f.m.c. GmbH <info at sysmocom.de>
+ * All Rights Reserved
+ *
+ * Author: Neels Hofmeyr <neels at hofmeyr.de>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ *
+ * 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/msgb.h>
+#include <osmocom/gsm/bsslap.h>
+
+#include <osmocom/core/logging.h>
+
+/*! \addtogroup bsslap
+ *  @{
+ *  \file bsslap.c
+ *  Message encoding and decoding for 3GPP TS 48.071 BSSLAP protocol.
+ */
+
+enum osmo_bsslap_iei {
+	OSMO_BSSLAP_IEI_TA = 0x1,
+	OSMO_BSSLAP_IEI_CELL_ID = 0x9,
+	OSMO_BSSLAP_IEI_CHAN_DESC = 0x10,
+	OSMO_BSSLAP_IEI_MEAS_REP = 0x14,
+	OSMO_BSSLAP_IEI_CAUSE = 0x18,
+	OSMO_BSSLAP_IEI_RRLP_FLAG = 0x19,
+	OSMO_BSSLAP_IEI_RRLP = 0x1b,
+	OSMO_BSSLAP_IEI_CELL_ID_LIST = 0x1c,
+	OSMO_BSSLAP_IEI_ENH_MEAS_REP = 0x1d,
+	OSMO_BSSLAP_IEI_LAC = 0x1e,
+	OSMO_BSSLAP_IEI_FREQ_LIST = 0x21,
+	OSMO_BSSLAP_IEI_MS_POWER = 0x22,
+	OSMO_BSSLAP_IEI_DELTA_TIMER = 0x23,
+	OSMO_BSSLAP_IEI_SERVING_CELL_ID = 0x24,
+	OSMO_BSSLAP_IEI_ENCR_KEY = 0x25,
+	OSMO_BSSLAP_IEI_CIPH_MODE_SET = 0x26,
+	OSMO_BSSLAP_IEI_CHAN_MODE = 0x27,
+	OSMO_BSSLAP_IEI_MR_CONFIG = 0x28,
+	OSMO_BSSLAP_IEI_POLLING_REPETITION = 0x29,
+	OSMO_BSSLAP_IEI_PACKET_CHAN_DESC = 0x2a,
+	OSMO_BSSLAP_IEI_TLLI = 0x2b,
+	OSMO_BSSLAP_IEI_TFI = 0x2c,
+	OSMO_BSSLAP_IEI_TBF_START_TIME = 0x2d,
+	OSMO_BSSLAP_IEI_PWRUP_START_TIME = 0x2e,
+	OSMO_BSSLAP_IEI_LONG_ENCR_KEY = 0x2f,
+	OSMO_BSSLAP_IEI_CONCUR_POS_PROC_F = 0x30,
+};
+
+static const struct tlv_definition osmo_bsslap_tlvdef = {
+	.def = {
+	[OSMO_BSSLAP_IEI_TA] = { TLV_TYPE_TV },
+	[OSMO_BSSLAP_IEI_CELL_ID] = { TLV_TYPE_FIXED, 2 },
+	[OSMO_BSSLAP_IEI_CHAN_DESC] = { TLV_TYPE_FIXED, 3 },
+	[OSMO_BSSLAP_IEI_MEAS_REP] = { TLV_TYPE_TLV },
+	[OSMO_BSSLAP_IEI_CAUSE] = { TLV_TYPE_TV },
+	[OSMO_BSSLAP_IEI_RRLP_FLAG] = { TLV_TYPE_TV },
+	[OSMO_BSSLAP_IEI_RRLP] = { TLV_TYPE_TLV },
+	[OSMO_BSSLAP_IEI_CELL_ID_LIST] = { TLV_TYPE_TLV },
+	[OSMO_BSSLAP_IEI_ENH_MEAS_REP] = { TLV_TYPE_TLV },
+	[OSMO_BSSLAP_IEI_LAC] = { TLV_TYPE_TLV },
+	[OSMO_BSSLAP_IEI_FREQ_LIST] = { TLV_TYPE_TLV },
+	[OSMO_BSSLAP_IEI_MS_POWER] = { TLV_TYPE_TV },
+	[OSMO_BSSLAP_IEI_DELTA_TIMER] = { TLV_TYPE_TV },
+	[OSMO_BSSLAP_IEI_SERVING_CELL_ID] = { TLV_TYPE_TLV },
+	[OSMO_BSSLAP_IEI_ENCR_KEY] = { TLV_TYPE_FIXED, 8 },
+	[OSMO_BSSLAP_IEI_CIPH_MODE_SET] = { TLV_TYPE_TV },
+	[OSMO_BSSLAP_IEI_CHAN_MODE] = { TLV_TYPE_TV, 2 },
+	[OSMO_BSSLAP_IEI_MR_CONFIG] = { TLV_TYPE_TLV },
+	[OSMO_BSSLAP_IEI_POLLING_REPETITION] = { TLV_TYPE_TV },
+	[OSMO_BSSLAP_IEI_PACKET_CHAN_DESC] = { TLV_TYPE_FIXED, 4 },
+	[OSMO_BSSLAP_IEI_TLLI] = { TLV_TYPE_FIXED, 4 },
+	[OSMO_BSSLAP_IEI_TFI] = { TLV_TYPE_TLV },
+	[OSMO_BSSLAP_IEI_TBF_START_TIME] = { TLV_TYPE_FIXED, 2 },
+	[OSMO_BSSLAP_IEI_PWRUP_START_TIME] = { TLV_TYPE_TLV },
+	[OSMO_BSSLAP_IEI_LONG_ENCR_KEY] = { TLV_TYPE_FIXED, 16 },
+	[OSMO_BSSLAP_IEI_CONCUR_POS_PROC_F] = { TLV_TYPE_TV },
+	},
+};
+
+static enum osmo_bsslap_msgt osmo_bsslap_msgt(const uint8_t *data, uint8_t len)
+{
+	if (!data || len < 1)
+		return -EINVAL;
+	return data[0];
+}
+
+static int osmo_bsslap_parse_tlv(struct tlv_parsed *tp, const uint8_t *data, size_t len)
+{
+	enum osmo_bsslap_msgt msg_type;
+	const uint8_t *ies_start;
+	int ies_len;
+
+	msg_type = osmo_bsslap_msgt(data, len);
+	if (msg_type < 0)
+		return -EBADMSG;
+
+	ies_start = &data[1];
+	ies_len = len - 1;
+
+	if (tlv_parse2(tp, 1, &osmo_bsslap_tlvdef, ies_start, ies_len, 0, 0) <= 0)
+		return -EBADMSG;
+
+	return msg_type;
+}
+
+static int osmo_bsslap_ie_dec_cell_id(uint16_t *cell_id, const uint8_t *data, size_t len)
+{
+	if (len != 2)
+		return -EINVAL;
+	*cell_id = osmo_load16be(data);
+	return 0;
+}
+
+static int osmo_bsslap_ie_dec_ta(uint8_t *ta, const uint8_t *data, size_t len)
+{
+	if (len != 1)
+		return -EINVAL;
+	*ta = data[0];
+	return 0;
+}
+
+static int osmo_bsslap_ie_dec_cause(enum osmo_bsslap_cause *cause, const uint8_t *data, size_t len)
+{
+	if (len != 1)
+		return -EINVAL;
+	*cause = data[0];
+	return 0;
+}
+
+static int osmo_bsslap_ie_dec_chan_desc(struct gsm48_chan_desc *chan_desc, const uint8_t *data, size_t len)
+{
+	if (len != sizeof(*chan_desc))
+		return -EINVAL;
+	*chan_desc = *(struct gsm48_chan_desc*)data;
+	return 0;
+}
+
+static int osmo_bsslap_enc_ta_request(struct msgb *msg)
+{
+	msgb_put_u8(msg, OSMO_BSSLAP_MSGT_TA_REQUEST);
+	return 1;
+}
+
+static int osmo_bsslap_enc_ta_response(struct msgb *msg, const struct osmo_bsslap_ta_response *params)
+{
+	uint8_t *old_tail = msg->tail;
+
+	msgb_put_u8(msg, OSMO_BSSLAP_MSGT_TA_RESPONSE);
+
+	msgb_put_u8(msg, OSMO_BSSLAP_IEI_CELL_ID);
+	msgb_put_u16(msg, params->cell_id);
+
+	msgb_put_u8(msg, OSMO_BSSLAP_IEI_TA);
+	msgb_put_u8(msg, params->ta);
+
+	return (msg->tail - old_tail);
+}
+
+static const char *osmo_bsslap_dec_ta_response(struct osmo_bsslap_ta_response *pdu, const uint8_t *data, size_t len)
+{
+	struct tlv_parsed _tp;
+	struct tlv_parsed *tp = &_tp;
+	struct tlv_p_entry *e;
+	int t;
+
+#define PARSE_ERR(errmsg) \
+		return "Decoding BSSLAP TA Response: " errmsg;
+
+	*pdu = (struct osmo_bsslap_ta_response){};
+
+	t = osmo_bsslap_parse_tlv(tp, data, len);
+	if (t < 0)
+		PARSE_ERR("failed to parse TLV structure");
+
+	if (t != OSMO_BSSLAP_MSGT_TA_RESPONSE)
+		PARSE_ERR("unexpected message type");
+
+	if (!(e = TLVP_GET(tp, OSMO_BSSLAP_IEI_CELL_ID)))
+		PARSE_ERR("missing mandatory Cell Identity IE");
+	if (osmo_bsslap_ie_dec_cell_id(&pdu->cell_id, e->val, e->len))
+		PARSE_ERR("cannot parse Cell Identity IE");
+
+	if (!(e = TLVP_GET(tp, OSMO_BSSLAP_IEI_TA)))
+		PARSE_ERR("missing mandatory TA IE");
+	if (osmo_bsslap_ie_dec_ta(&pdu->ta, e->val, e->len))
+		PARSE_ERR("cannot parse TA IE");
+
+	return NULL;
+#undef PARSE_ERR
+}
+
+static int osmo_bsslap_enc_ta_layer3(struct msgb *msg, const struct osmo_bsslap_ta_layer3 *params)
+{
+	uint8_t *old_tail = msg->tail;
+
+	msgb_put_u8(msg, OSMO_BSSLAP_MSGT_TA_LAYER3);
+
+	msgb_put_u8(msg, OSMO_BSSLAP_IEI_TA);
+	msgb_put_u8(msg, params->ta);
+
+	return (msg->tail - old_tail);
+}
+
+static const char *osmo_bsslap_dec_ta_layer3(struct osmo_bsslap_ta_layer3 *pdu, const uint8_t *data, size_t len)
+{
+	struct tlv_parsed _tp;
+	struct tlv_parsed *tp = &_tp;
+	struct tlv_p_entry *e;
+	int t;
+
+#define PARSE_ERR(errmsg) \
+		return "Decoding BSSLAP TA Layer3: " errmsg;
+
+	*pdu = (struct osmo_bsslap_ta_layer3){};
+
+	t = osmo_bsslap_parse_tlv(tp, data, len);
+	if (t < 0)
+		PARSE_ERR("failed to parse TLV structure");
+
+	if (t != OSMO_BSSLAP_MSGT_TA_LAYER3)
+		PARSE_ERR("unexpected message type");
+
+	if (!(e = TLVP_GET(tp, OSMO_BSSLAP_IEI_TA)))
+		PARSE_ERR("missing mandatory TA IE");
+	if (osmo_bsslap_ie_dec_ta(&pdu->ta, e->val, e->len))
+		PARSE_ERR("cannot parse TA IE");
+
+	return NULL;
+#undef PARSE_ERR
+}
+
+static int osmo_bsslap_enc_reject(struct msgb *msg, enum osmo_bsslap_cause cause)
+{
+	msgb_put_u8(msg, OSMO_BSSLAP_MSGT_REJECT);
+	msgb_put_u8(msg, OSMO_BSSLAP_IEI_CAUSE);
+	msgb_put_u8(msg, cause);
+	return 3;
+}
+
+static const char *osmo_bsslap_dec_reject(enum osmo_bsslap_cause *cause, const uint8_t *data, size_t len)
+{
+	struct tlv_parsed _tp;
+	struct tlv_parsed *tp = &_tp;
+	struct tlv_p_entry *e;
+	int t;
+
+#define PARSE_ERR(errmsg) \
+		return "Decoding BSSLAP Reject: " errmsg;
+
+	*cause = -1;
+
+	t = osmo_bsslap_parse_tlv(tp, data, len);
+	if (t < 0)
+		PARSE_ERR("failed to parse TLV structure");
+
+	if (t != OSMO_BSSLAP_MSGT_REJECT)
+		PARSE_ERR("unexpected message type");
+
+	if (!(e = TLVP_GET(tp, OSMO_BSSLAP_IEI_CAUSE)))
+		PARSE_ERR("missing mandatory Cause IE");
+	if (osmo_bsslap_ie_dec_cause(cause, e->val, e->len))
+		PARSE_ERR("cannot parse Cause IE");
+
+	return NULL;
+#undef PARSE_ERR
+}
+
+static int osmo_bsslap_enc_abort(struct msgb *msg, enum osmo_bsslap_cause cause)
+{
+	msgb_put_u8(msg, OSMO_BSSLAP_MSGT_ABORT);
+	msgb_put_u8(msg, OSMO_BSSLAP_IEI_CAUSE);
+	msgb_put_u8(msg, cause);
+	return 3;
+}
+
+static const char *osmo_bsslap_dec_abort(enum osmo_bsslap_cause *cause, const uint8_t *data, size_t len)
+{
+	struct tlv_parsed _tp;
+	struct tlv_parsed *tp = &_tp;
+	struct tlv_p_entry *e;
+	int t;
+
+#define PARSE_ERR(errmsg) \
+		return "Decoding BSSLAP TA Abort: " errmsg;
+
+	*cause = -1;
+
+	t = osmo_bsslap_parse_tlv(tp, data, len);
+	if (t < 0)
+		PARSE_ERR("failed to parse TLV structure");
+
+	if (t != OSMO_BSSLAP_MSGT_ABORT)
+		PARSE_ERR("unexpected message type");
+
+	if (!(e = TLVP_GET(tp, OSMO_BSSLAP_IEI_CAUSE)))
+		PARSE_ERR("missing mandatory Cause IE");
+	if (osmo_bsslap_ie_dec_cause(cause, e->val, e->len))
+		PARSE_ERR("cannot parse Cause IE");
+
+	return NULL;
+#undef PARSE_ERR
+}
+
+static int osmo_bsslap_enc_reset(struct msgb *msg, const struct osmo_bsslap_reset *params)
+{
+	struct gsm48_chan_desc *chan_desc;
+	uint8_t *old_tail = msg->tail;
+
+	msgb_put_u8(msg, OSMO_BSSLAP_MSGT_RESET);
+
+	msgb_put_u8(msg, OSMO_BSSLAP_IEI_CELL_ID);
+	msgb_put_u16(msg, params->cell_id);
+
+	msgb_put_u8(msg, OSMO_BSSLAP_IEI_TA);
+	msgb_put_u8(msg, params->ta);
+
+	msgb_put_u8(msg, OSMO_BSSLAP_IEI_CHAN_DESC);
+	chan_desc = (void*)msgb_put(msg, sizeof(params->chan_desc));
+	*chan_desc = params->chan_desc;
+
+	msgb_put_u8(msg, OSMO_BSSLAP_IEI_CAUSE);
+	msgb_put_u8(msg, params->cause);
+
+	return (msg->tail - old_tail);
+}
+
+static const char *osmo_bsslap_dec_reset(struct osmo_bsslap_reset *pdu, const uint8_t *data, size_t len)
+{
+	struct tlv_parsed _tp;
+	struct tlv_parsed *tp = &_tp;
+	struct tlv_p_entry *e;
+	int t;
+
+#define PARSE_ERR(errmsg) \
+		return "Decoding BSSLAP Reset: " errmsg;
+
+	*pdu = (struct osmo_bsslap_reset){};
+
+	t = osmo_bsslap_parse_tlv(tp, data, len);
+	if (t < 0)
+		PARSE_ERR("failed to parse TLV structure");
+
+	if (t != OSMO_BSSLAP_MSGT_RESET)
+		PARSE_ERR("unexpected message type");
+
+	if (!(e = TLVP_GET(tp, OSMO_BSSLAP_IEI_CELL_ID)))
+		PARSE_ERR("missing mandatory Cell Identity IE");
+	if (osmo_bsslap_ie_dec_cell_id(&pdu->cell_id, e->val, e->len))
+		PARSE_ERR("cannot parse Cell Identity IE");
+
+	if (!(e = TLVP_GET(tp, OSMO_BSSLAP_IEI_TA)))
+		PARSE_ERR("missing mandatory TA IE");
+	if (osmo_bsslap_ie_dec_ta(&pdu->ta, e->val, e->len))
+		PARSE_ERR("cannot parse TA IE");
+
+	if (!(e = TLVP_GET(tp, OSMO_BSSLAP_IEI_CHAN_DESC)))
+		PARSE_ERR("missing mandatory Channel Description IE");
+	if (osmo_bsslap_ie_dec_chan_desc(&pdu->chan_desc, e->val, e->len))
+		PARSE_ERR("cannot parse Channel Description IE");
+
+	if (!(e = TLVP_GET(tp, OSMO_BSSLAP_IEI_CAUSE)))
+		PARSE_ERR("missing mandatory Cause IE");
+	if (osmo_bsslap_ie_dec_cause(&pdu->cause, e->val, e->len))
+		PARSE_ERR("cannot parse Cause IE");
+
+	return NULL;
+#undef PARSE_ERR
+}
+
+/*! Encode BSSLAP PDU and add to msgb (3GPP TS 48.071).
+ * \param[out] msg  msgb to append to.
+ * \param[in] pdu  PDU data to encode.
+ * \return number of bytes written, negative on error.
+ */
+int osmo_bsslap_enc(struct msgb *msg, const struct osmo_bsslap_pdu *pdu)
+{
+	switch (pdu->msg_type) {
+	case OSMO_BSSLAP_MSGT_TA_REQUEST:
+		return osmo_bsslap_enc_ta_request(msg);
+	case OSMO_BSSLAP_MSGT_TA_RESPONSE:
+		return osmo_bsslap_enc_ta_response(msg, &pdu->ta_response);
+	case OSMO_BSSLAP_MSGT_REJECT:
+		return osmo_bsslap_enc_reject(msg, pdu->reject);
+	case OSMO_BSSLAP_MSGT_RESET:
+		return osmo_bsslap_enc_reset(msg, &pdu->reset);
+	case OSMO_BSSLAP_MSGT_ABORT:
+		return osmo_bsslap_enc_abort(msg, pdu->abort);
+	case OSMO_BSSLAP_MSGT_TA_LAYER3:
+		return osmo_bsslap_enc_ta_layer3(msg, &pdu->ta_layer3);
+	default:
+		return -ENOTSUP;
+	}
+}
+
+/*! Decode BSSLAP PDU (3GPP TS 48.071).
+ * \param[out] pdu  Write decoded values here.
+ * \param[in] data  Pointer to BSSLAP PDU raw data.
+ * \param[in] len  Data length to decode.
+ * \return NULL upon success, a human readable error message on failure.
+ */
+const char *osmo_bsslap_dec(struct osmo_bsslap_pdu *pdu, const uint8_t *data, size_t len)
+{
+	*pdu = (struct osmo_bsslap_pdu){};
+
+	pdu->msg_type = osmo_bsslap_msgt(data, len);
+	if (pdu->msg_type < 0)
+		return "BSSLAP PDU too short";
+
+	switch (pdu->msg_type) {
+	case OSMO_BSSLAP_MSGT_TA_REQUEST:
+		/* The TA Request message contains only the message type. */
+		return NULL;
+	case OSMO_BSSLAP_MSGT_TA_RESPONSE:
+		return osmo_bsslap_dec_ta_response(&pdu->ta_response, data, len);
+	case OSMO_BSSLAP_MSGT_REJECT:
+		return osmo_bsslap_dec_reject(&pdu->reject, data, len);
+	case OSMO_BSSLAP_MSGT_RESET:
+		return osmo_bsslap_dec_reset(&pdu->reset, data, len);
+	case OSMO_BSSLAP_MSGT_ABORT:
+		return osmo_bsslap_dec_abort(&pdu->abort, data, len);
+	case OSMO_BSSLAP_MSGT_TA_LAYER3:
+		return osmo_bsslap_dec_ta_layer3(&pdu->ta_layer3, data, len);
+	default:
+		return "Unsupported BSSLAP message type";
+	}
+
+	return NULL;
+}
+
+const struct value_string osmo_bsslap_msgt_names[] = {
+	{ OSMO_BSSLAP_MSGT_TA_REQUEST, "TA_REQUEST" },
+	{ OSMO_BSSLAP_MSGT_TA_RESPONSE, "TA_RESPONSE" },
+	{ OSMO_BSSLAP_MSGT_REJECT, "REJECT" },
+	{ OSMO_BSSLAP_MSGT_RESET, "RESET" },
+	{ OSMO_BSSLAP_MSGT_ABORT, "ABORT" },
+	{ OSMO_BSSLAP_MSGT_TA_LAYER3, "TA_LAYER3" },
+	{ OSMO_BSSLAP_MSGT_MS_POS_CMD, "MS_POS_CMD" },
+	{ OSMO_BSSLAP_MSGT_MS_POS_RESP, "MS_POS_RESP" },
+	{ OSMO_BSSLAP_MSGT_UTDOA_REQ, "UTDOA_REQ" },
+	{ OSMO_BSSLAP_MSGT_UTDOA_RESP, "UTDOA_RESP" },
+	{}
+};
+
+/*! @} */
diff --git a/src/gsm/libosmogsm.map b/src/gsm/libosmogsm.map
index a31f73a..257c3fa 100644
--- a/src/gsm/libosmogsm.map
+++ b/src/gsm/libosmogsm.map
@@ -705,6 +705,10 @@
 osmo_nri_ranges_to_str_buf;
 osmo_nri_ranges_to_str_c;
 
+osmo_bsslap_enc;
+osmo_bsslap_dec;
+osmo_bsslap_msgt_names;
+
 osmo_gad_enc;
 osmo_gad_dec;
 osmo_gad_to_str_buf;
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 9a2f217..4dfad1b 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -39,6 +39,7 @@
                  i460_mux/i460_mux_test					\
 		 bitgen/bitgen_test					\
 		 gad/gad_test						\
+		 bsslap/bsslap_test					\
 		 $(NULL)
 
 if ENABLE_MSGFILE
@@ -285,6 +286,9 @@
 gad_gad_test_SOURCES = gad/gad_test.c
 gad_gad_test_LDADD = $(LDADD) $(top_builddir)/src/gsm/gad.o
 
+bsslap_bsslap_test_SOURCES = bsslap/bsslap_test.c
+bsslap_bsslap_test_LDADD = $(LDADD) $(top_builddir)/src/gsm/libosmogsm.la
+
 # The `:;' works around a Bash 3.2 bug when the output is not writeable.
 $(srcdir)/package.m4: $(top_srcdir)/configure.ac
 	:;{ \
@@ -366,6 +370,7 @@
 	     i460_mux/i460_mux_test.ok \
 	     bitgen/bitgen_test.ok \
 	     gad/gad_test.ok \
+	     bsslap/bsslap_test.ok \
 	     $(NULL)
 
 if ENABLE_LIBSCTP
diff --git a/tests/bsslap/bsslap_test.c b/tests/bsslap/bsslap_test.c
new file mode 100644
index 0000000..2b6c35e
--- /dev/null
+++ b/tests/bsslap/bsslap_test.c
@@ -0,0 +1,101 @@
+#include <stdio.h>
+
+#include <osmocom/core/utils.h>
+#include <osmocom/gsm/bsslap.h>
+
+struct osmo_bsslap_pdu bsslap_test_pdus[] = {
+	{
+		.msg_type = OSMO_BSSLAP_MSGT_TA_REQUEST,
+	},
+	{
+		.msg_type = OSMO_BSSLAP_MSGT_TA_RESPONSE,
+		.ta_response = {
+			.cell_id = 23,
+			.ta = 42,
+		},
+	},
+	{
+		.msg_type = OSMO_BSSLAP_MSGT_REJECT,
+		.reject = OSMO_BSSLAP_CAUSE_OTHER_RADIO_EVT_FAIL,
+	},
+	{
+		.msg_type = OSMO_BSSLAP_MSGT_RESET,
+		.reset = {
+			.cell_id = 23,
+			.ta = 42,
+			.chan_desc =  {
+				.chan_nr = 23,
+				.h0 = {
+					.tsc = 5,
+					.h = 1,
+					.arfcn_high = 2,
+					.arfcn_low = 3,
+				},
+			},
+			.cause = OSMO_BSSLAP_CAUSE_INTRA_BSS_HO,
+		},
+	},
+	{
+		.msg_type = OSMO_BSSLAP_MSGT_ABORT,
+		.abort = OSMO_BSSLAP_CAUSE_LOSS_SIG_CONN_MS,
+	},
+	{
+		.msg_type = OSMO_BSSLAP_MSGT_TA_LAYER3,
+		.ta_layer3 = {
+			.ta = 23,
+		},
+	},
+};
+
+void test_bsslap_enc_dec()
+{
+	struct osmo_bsslap_pdu *pdu;
+	printf("--- %s\n", __func__);
+
+	for (pdu = bsslap_test_pdus; (pdu - bsslap_test_pdus) < ARRAY_SIZE(bsslap_test_pdus); pdu++) {
+		struct msgb *msg = msgb_alloc(1024, __func__);
+		struct osmo_bsslap_pdu dec_pdu;
+		int rc;
+		const char *errmsg;
+		rc = osmo_bsslap_enc(msg, pdu);
+		if (rc <= 0) {
+			printf("[%ld] %s: ERROR: failed to encode pdu\n", (pdu - bsslap_test_pdus),
+			       osmo_bsslap_msgt_name(pdu->msg_type));
+			goto loop_end;
+		}
+		if (rc != msg->len) {
+			printf("[%ld] %s: ERROR: osmo_bsslap_enc() returned length %d but msgb has %d bytes\n",
+			       (pdu - bsslap_test_pdus), osmo_bsslap_msgt_name(pdu->msg_type),
+			       rc, msg->len);
+			goto loop_end;
+		}
+
+		memset(&dec_pdu, 0xff, sizeof(dec_pdu));
+		errmsg = osmo_bsslap_dec(&dec_pdu, msg->data, msg->len);
+		if (errmsg) {
+			printf("[%ld] %s: ERROR: failed to decode pdu: %s\n", (pdu - bsslap_test_pdus),
+			       osmo_bsslap_msgt_name(pdu->msg_type), errmsg);
+			printf("     encoded data: %s\n", osmo_hexdump(msg->data, msg->len));
+			goto loop_end;
+		}
+
+		if (memcmp(pdu, &dec_pdu, sizeof(dec_pdu))) {
+			printf("[%ld] %s: ERROR: decoded PDU != encoded PDU\n", (pdu - bsslap_test_pdus),
+			       osmo_bsslap_msgt_name(pdu->msg_type));
+			printf("     original struct: %s\n", osmo_hexdump((void*)pdu, sizeof(*pdu)));
+			printf("      decoded struct: %s\n", osmo_hexdump((void*)&dec_pdu, sizeof(dec_pdu)));
+			goto loop_end;
+		}
+
+		printf("[%ld] %s: ok\n", (pdu - bsslap_test_pdus), osmo_bsslap_msgt_name(pdu->msg_type));
+
+loop_end:
+		msgb_free(msg);
+	}
+}
+
+int main()
+{
+	test_bsslap_enc_dec();
+	return 0;
+}
diff --git a/tests/bsslap/bsslap_test.ok b/tests/bsslap/bsslap_test.ok
new file mode 100644
index 0000000..8e4643c
--- /dev/null
+++ b/tests/bsslap/bsslap_test.ok
@@ -0,0 +1,7 @@
+--- test_bsslap_enc_dec
+[0] TA_REQUEST: ok
+[1] TA_RESPONSE: ok
+[2] REJECT: ok
+[3] RESET: ok
+[4] ABORT: ok
+[5] TA_LAYER3: ok
diff --git a/tests/testsuite.at b/tests/testsuite.at
index 10cf74b..1fa9a07 100644
--- a/tests/testsuite.at
+++ b/tests/testsuite.at
@@ -408,3 +408,9 @@
 cat $abs_srcdir/gad/gad_test.ok > expout
 AT_CHECK([$abs_top_builddir/tests/gad/gad_test], [0], [expout], [ignore])
 AT_CLEANUP
+
+AT_SETUP([bsslap])
+AT_KEYWORDS([bsslap])
+cat $abs_srcdir/bsslap/bsslap_test.ok > expout
+AT_CHECK([$abs_top_builddir/tests/bsslap/bsslap_test], [0], [expout], [ignore])
+AT_CLEANUP

-- 
To view, visit https://gerrit.osmocom.org/c/libosmocore/+/20333
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings

Gerrit-Project: libosmocore
Gerrit-Branch: master
Gerrit-Change-Id: I6409c4bcac402dc7626a3afce9081c59cd715fe8
Gerrit-Change-Number: 20333
Gerrit-PatchSet: 1
Gerrit-Owner: neels <nhofmeyr at sysmocom.de>
Gerrit-MessageType: newchange
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.osmocom.org/pipermail/gerrit-log/attachments/20201001/f7280aa4/attachment.htm>


More information about the gerrit-log mailing list