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

laforge gerrit-no-reply at lists.osmocom.org
Thu Oct 8 07:00:40 UTC 2020


laforge has submitted this change. ( 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
A include/osmocom/gsm/protocol/gsm_48_071.h
A include/osmocom/gsm/protocol/gsm_49_031.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
11 files changed, 698 insertions(+), 1 deletion(-)

Approvals:
  Jenkins Builder: Verified
  laforge: Looks good to me, approved



diff --git a/include/Makefile.am b/include/Makefile.am
index fc1eec3..19d4043 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 \
@@ -134,6 +135,8 @@
 		       osmocom/gsm/protocol/gsm_29_118.h \
                        osmocom/gsm/protocol/gsm_44_318.h \
                        osmocom/gsm/protocol/gsm_48_049.h \
+                       osmocom/gsm/protocol/gsm_48_071.h \
+                       osmocom/gsm/protocol/gsm_49_031.h \
                        osmocom/gsm/protocol/ipaccess.h \
                        osmocom/gsm/protocol/smpp34_osmocom.h \
                        osmocom/gsm/rsl.h \
diff --git a/include/osmocom/gsm/bsslap.h b/include/osmocom/gsm/bsslap.h
new file mode 100644
index 0000000..b2174b3
--- /dev/null
+++ b/include/osmocom/gsm/bsslap.h
@@ -0,0 +1,57 @@
+/*! \addtogroup bsslap
+ *  @{
+ *  \file bsslap.h
+ * Message encoding and decoding for 3GPP TS 48.071 BSS LCS Assistance Protocol (BSSLAP).
+ */
+/*
+ * (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 <osmocom/gsm/protocol/gsm_48_071.h>
+#include <osmocom/gsm/protocol/gsm_49_031.h>
+
+struct msgb;
+
+struct osmo_bsslap_err {
+	int rc;
+	enum bsslap_msgt msg_type;
+	enum bsslap_iei iei;
+	enum lcs_cause cause;
+	char *logmsg;
+};
+
+extern const struct value_string osmo_bsslap_msgt_names[];
+static inline const char *osmo_bsslap_msgt_name(enum bsslap_msgt val)
+{ return get_value_string(osmo_bsslap_msgt_names, val); }
+
+extern const struct value_string osmo_bsslap_iei_names[];
+static inline const char *osmo_bsslap_iei_name(enum bsslap_iei val)
+{ return get_value_string(osmo_bsslap_iei_names, val); }
+
+int osmo_bsslap_enc(struct msgb *msg, const struct bsslap_pdu *pdu);
+int osmo_bsslap_dec(struct bsslap_pdu *pdu,
+		    struct osmo_bsslap_err **err, void *err_ctx,
+		    const uint8_t *data, size_t len);
+
+/*! @} */
diff --git a/include/osmocom/gsm/protocol/gsm_48_071.h b/include/osmocom/gsm/protocol/gsm_48_071.h
new file mode 100644
index 0000000..fb9653a
--- /dev/null
+++ b/include/osmocom/gsm/protocol/gsm_48_071.h
@@ -0,0 +1,122 @@
+/*! \defgroup bsslap 3GPP TS 48.071 BSS LCS Assistance Protocol (BSSLAP).
+ *  @{
+ *  \file gsm_48_071.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 <osmocom/gsm/protocol/gsm_04_08.h>
+
+enum bsslap_msgt {
+	BSSLAP_MSGT_TA_REQUEST = 0x1,
+	BSSLAP_MSGT_TA_RESPONSE = 0x2,
+	BSSLAP_MSGT_REJECT = 0xa,
+	BSSLAP_MSGT_RESET = 0xb,
+	BSSLAP_MSGT_ABORT = 0xc,
+	BSSLAP_MSGT_TA_LAYER3 = 0xd,
+	BSSLAP_MSGT_MS_POS_CMD = 0xf,
+	BSSLAP_MSGT_MS_POS_RESP = 0x10,
+	BSSLAP_MSGT_UTDOA_REQ = 0x11,
+	BSSLAP_MSGT_UTDOA_RESP = 0x12,
+};
+
+enum bsslap_cause {
+	BSSLAP_CAUSE_CONGESTION = 0x0,
+	BSSLAP_CAUSE_CHAN_MODE_NOT_SUPP = 0x1,
+	BSSLAP_CAUSE_POS_PROC_NOT_SUPP = 0x2,
+	BSSLAP_CAUSE_OTHER_RADIO_EVT_FAIL = 0x3,
+	BSSLAP_CAUSE_INTRA_BSS_HO = 0x4,
+	BSSLAP_CAUSE_SUPERV_TIMER_EXPIRED = 0x5,
+	BSSLAP_CAUSE_INTER_BSS_HO = 0x6,
+	BSSLAP_CAUSE_LOSS_SIG_CONN_MS = 0x7,
+	BSSLAP_CAUSE_INCORR_SERV_CELL_ID = 0x8,
+	BSSLAP_CAUSE_BSSAP_LE_SEGMENT_ERR = 0x9,
+	BSSLAP_CAUSE_CONCUR_POS_PROC_NOT_EN = 0xa,
+};
+
+enum bsslap_iei {
+	BSSLAP_IEI_TA = 0x1,
+	BSSLAP_IEI_CELL_ID = 0x9,
+	BSSLAP_IEI_CHAN_DESC = 0x10,
+	BSSLAP_IEI_MEAS_REP = 0x14,
+	BSSLAP_IEI_CAUSE = 0x18,
+	BSSLAP_IEI_RRLP_FLAG = 0x19,
+	BSSLAP_IEI_RRLP = 0x1b,
+	BSSLAP_IEI_CELL_ID_LIST = 0x1c,
+	BSSLAP_IEI_ENH_MEAS_REP = 0x1d,
+	BSSLAP_IEI_LAC = 0x1e,
+	BSSLAP_IEI_FREQ_LIST = 0x21,
+	BSSLAP_IEI_MS_POWER = 0x22,
+	BSSLAP_IEI_DELTA_TIMER = 0x23,
+	BSSLAP_IEI_SERVING_CELL_ID = 0x24,
+	BSSLAP_IEI_ENCR_KEY = 0x25,
+	BSSLAP_IEI_CIPH_MODE_SET = 0x26,
+	BSSLAP_IEI_CHAN_MODE = 0x27,
+	BSSLAP_IEI_MR_CONFIG = 0x28,
+	BSSLAP_IEI_POLLING_REPETITION = 0x29,
+	BSSLAP_IEI_PACKET_CHAN_DESC = 0x2a,
+	BSSLAP_IEI_TLLI = 0x2b,
+	BSSLAP_IEI_TFI = 0x2c,
+	BSSLAP_IEI_TBF_START_TIME = 0x2d,
+	BSSLAP_IEI_PWRUP_START_TIME = 0x2e,
+	BSSLAP_IEI_LONG_ENCR_KEY = 0x2f,
+	BSSLAP_IEI_CONCUR_POS_PROC_F = 0x30,
+};
+
+struct bsslap_ta_response {
+	uint16_t cell_id;
+	uint8_t ta;
+
+	bool more_items; /*!< always set this to false */
+};
+
+struct bsslap_ta_layer3 {
+	uint8_t ta;
+
+	bool more_items; /*!< always set this to false */
+};
+
+struct bsslap_reset {
+	uint16_t cell_id;
+	uint8_t ta;
+	struct gsm48_chan_desc chan_desc;
+	enum bsslap_cause cause;
+
+	bool more_items; /*!< always set this to false */
+};
+
+struct bsslap_pdu {
+	enum bsslap_msgt msg_type;
+	union {
+		/* ta_request: a TA Request message consists only of the message type. */
+		struct bsslap_ta_response ta_response;
+		enum bsslap_cause reject;
+		struct bsslap_reset reset;
+		enum bsslap_cause abort;
+		struct bsslap_ta_layer3 ta_layer3;
+	};
+};
+
+/*! @} */
diff --git a/include/osmocom/gsm/protocol/gsm_49_031.h b/include/osmocom/gsm/protocol/gsm_49_031.h
new file mode 100644
index 0000000..b44a07e
--- /dev/null
+++ b/include/osmocom/gsm/protocol/gsm_49_031.h
@@ -0,0 +1,61 @@
+/*! \defgroup bssmap_le 3GPP TS 49.031 BSSMAP-LE.
+ *  @{
+ *  \file gsm_49_031.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 <stdint.h>
+#include <stdbool.h>
+
+/*! 3GPP TS 49.031 10.13 LCS Cause, also in 3GPP TS 48.008 3.2.2.66, which simply refers to the former. */
+enum lcs_cause {
+	LCS_CAUSE_UNSPECIFIED = 0,
+	LCS_CAUSE_SYSTEM_FAILURE = 1,
+	LCS_CAUSE_PROTOCOL_ERROR = 2,
+	LCS_CAUSE_DATA_MISSING_IN_REQ = 3,
+	LCS_CAUSE_UNEXP_DATA_IN_REQ = 4,
+	LCS_CAUSE_POS_METH_FAILURE = 5,
+	LCS_CAUSE_TGT_MS_UNREACHABLE = 6,
+	LCS_CAUSE_REQUEST_ABORTED = 7,
+	LCS_CAUSE_FACILITY_NOTSUPP = 8,
+	LCS_CAUSE_INTER_BSC_HO = 9,
+	LCS_CAUSE_INTRA_BSC_HO = 10,
+	LCS_CAUSE_CONGESTION = 11,
+	LCS_CAUSE_INTER_NSE_CHG = 12,
+	LCS_CAUSE_RA_UPDAT = 13,
+	LCS_CAUSE_PTMSI_REALLOC = 14,
+	LCS_CAUSE_GPRS_SUSPENSION = 15,
+};
+
+/*! 3GPP TS 49.031 10.13 LCS Cause, also in 3GPP TS 48.008 3.2.2.66, which simply refers to the former. */
+struct lcs_cause_ie {
+	bool present;
+	enum lcs_cause cause_val;
+	bool diag_val_present;
+	uint8_t diag_val;
+};
+
+/*! @} */
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..7886da6
--- /dev/null
+++ b/src/gsm/bsslap.c
@@ -0,0 +1,329 @@
+/* 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 <errno.h>
+
+#include <osmocom/core/msgb.h>
+#include <osmocom/gsm/bsslap.h>
+#include <osmocom/gsm/tlv.h>
+
+#include <osmocom/core/logging.h>
+
+/*! \addtogroup bsslap
+ *  @{
+ *  \file bsslap.c
+ *  Message encoding and decoding for 3GPP TS 48.071 BSSLAP protocol.
+ */
+
+static const struct tlv_definition osmo_bsslap_tlvdef = {
+	.def = {
+	[BSSLAP_IEI_TA] = { TLV_TYPE_TV },
+	[BSSLAP_IEI_CELL_ID] = { TLV_TYPE_FIXED, 2 },
+	[BSSLAP_IEI_CHAN_DESC] = { TLV_TYPE_FIXED, 3 },
+	[BSSLAP_IEI_MEAS_REP] = { TLV_TYPE_TLV },
+	[BSSLAP_IEI_CAUSE] = { TLV_TYPE_TV },
+	[BSSLAP_IEI_RRLP_FLAG] = { TLV_TYPE_TV },
+	[BSSLAP_IEI_RRLP] = { TLV_TYPE_TLV },
+	[BSSLAP_IEI_CELL_ID_LIST] = { TLV_TYPE_TLV },
+	[BSSLAP_IEI_ENH_MEAS_REP] = { TLV_TYPE_TLV },
+	[BSSLAP_IEI_LAC] = { TLV_TYPE_TLV },
+	[BSSLAP_IEI_FREQ_LIST] = { TLV_TYPE_TLV },
+	[BSSLAP_IEI_MS_POWER] = { TLV_TYPE_TV },
+	[BSSLAP_IEI_DELTA_TIMER] = { TLV_TYPE_TV },
+	[BSSLAP_IEI_SERVING_CELL_ID] = { TLV_TYPE_TLV },
+	[BSSLAP_IEI_ENCR_KEY] = { TLV_TYPE_FIXED, 8 },
+	[BSSLAP_IEI_CIPH_MODE_SET] = { TLV_TYPE_TV },
+	[BSSLAP_IEI_CHAN_MODE] = { TLV_TYPE_TV, 2 },
+	[BSSLAP_IEI_MR_CONFIG] = { TLV_TYPE_TLV },
+	[BSSLAP_IEI_POLLING_REPETITION] = { TLV_TYPE_TV },
+	[BSSLAP_IEI_PACKET_CHAN_DESC] = { TLV_TYPE_FIXED, 4 },
+	[BSSLAP_IEI_TLLI] = { TLV_TYPE_FIXED, 4 },
+	[BSSLAP_IEI_TFI] = { TLV_TYPE_TLV },
+	[BSSLAP_IEI_TBF_START_TIME] = { TLV_TYPE_FIXED, 2 },
+	[BSSLAP_IEI_PWRUP_START_TIME] = { TLV_TYPE_TLV },
+	[BSSLAP_IEI_LONG_ENCR_KEY] = { TLV_TYPE_FIXED, 16 },
+	[BSSLAP_IEI_CONCUR_POS_PROC_F] = { TLV_TYPE_TV },
+	},
+};
+
+#define DEC_ERR(RC, MSG_TYPE, IEI, CAUSE, fmt, args...) do { \
+		if (err && !*err) { \
+			*err = talloc_zero(err_ctx, struct osmo_bsslap_err); \
+			**err = (struct osmo_bsslap_err){ \
+				.rc = (RC), \
+				.msg_type = (MSG_TYPE), \
+				.iei = (IEI), \
+				.cause = (CAUSE), \
+				.logmsg = talloc_asprintf(*err, "Error decoding BSSLAP%s%s%s%s%s: " fmt, \
+							  (MSG_TYPE) >= 0 ? " " : "", \
+							  (MSG_TYPE) >= 0 ? osmo_bsslap_msgt_name(MSG_TYPE) : "", \
+							  (IEI) >= 0 ? ": " : "", \
+							  (IEI) >= 0 ? osmo_bsslap_iei_name(IEI) : "", \
+							  (IEI) >= 0 ? " IE" : "", \
+##args), \
+			}; \
+		} \
+		return RC; \
+	} while(0)
+
+static void osmo_bsslap_ie_enc_cell_id(struct msgb *msg, uint16_t cell_id)
+{
+	msgb_put_u8(msg, BSSLAP_IEI_CELL_ID);
+	msgb_put_u16(msg, cell_id);
+}
+
+static int osmo_bsslap_ie_dec_cell_id(uint16_t *cell_id,
+				      enum bsslap_msgt msgt, enum bsslap_iei iei,
+				      struct osmo_bsslap_err **err, void *err_ctx,
+				      const uint8_t *data, size_t len)
+{
+	if (len != 2)
+		DEC_ERR(-EINVAL, msgt, iei, LCS_CAUSE_UNSPECIFIED, "Expected 2 bytes, got %zu", len);
+	*cell_id = osmo_load16be(data);
+	return 0;
+}
+
+static void osmo_bsslap_ie_enc_ta(struct msgb *msg, uint8_t ta)
+{
+	msgb_put_u8(msg, BSSLAP_IEI_TA);
+	msgb_put_u8(msg, ta);
+}
+
+static int osmo_bsslap_ie_dec_ta(uint8_t *ta,
+				 enum bsslap_msgt msgt, enum bsslap_iei iei,
+				 struct osmo_bsslap_err **err, void *err_ctx,
+				 const uint8_t *data, size_t len)
+{
+	if (len != 1)
+		DEC_ERR(-EINVAL, msgt, iei, LCS_CAUSE_UNSPECIFIED, "Expected 1 byte, got %zu", len);
+	*ta = data[0];
+	return 0;
+}
+
+static void osmo_bsslap_ie_enc_cause(struct msgb *msg, enum bsslap_cause cause)
+{
+	msgb_put_u8(msg, BSSLAP_IEI_CAUSE);
+	msgb_put_u8(msg, cause);
+}
+
+static int osmo_bsslap_ie_dec_cause(enum bsslap_cause *cause,
+				    enum bsslap_msgt msgt, enum bsslap_iei iei,
+				    struct osmo_bsslap_err **err, void *err_ctx,
+				    const uint8_t *data, size_t len)
+{
+	if (len != 1)
+		DEC_ERR(-EINVAL, msgt, iei, LCS_CAUSE_UNSPECIFIED, "Expected 1 byte, got %zu", len);
+	*cause = data[0];
+	return 0;
+}
+
+static void osmo_bsslap_ie_enc_chan_desc(struct msgb *msg, const struct gsm48_chan_desc *chan_desc)
+{
+	struct gsm48_chan_desc *put_chan_desc;
+	msgb_put_u8(msg, BSSLAP_IEI_CHAN_DESC);
+	put_chan_desc = (void*)msgb_put(msg, sizeof(*chan_desc));
+	*put_chan_desc = *chan_desc;
+}
+
+static int osmo_bsslap_ie_dec_chan_desc(struct gsm48_chan_desc *chan_desc,
+					enum bsslap_msgt msgt, enum bsslap_iei iei,
+					struct osmo_bsslap_err **err, void *err_ctx,
+					const uint8_t *data, size_t len)
+{
+	if (len != sizeof(*chan_desc))
+		DEC_ERR(-EINVAL, msgt, iei, LCS_CAUSE_UNSPECIFIED, "Expected %zu bytes, got %zu",
+			sizeof(*chan_desc), len);
+	*chan_desc = *(struct gsm48_chan_desc*)data;
+	return 0;
+}
+
+/*! Encode BSSLAP PDU and append 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 bsslap_pdu *pdu)
+{
+	uint8_t *old_tail = msg->tail;
+
+	msgb_put_u8(msg, pdu->msg_type);
+
+	switch (pdu->msg_type) {
+	case BSSLAP_MSGT_TA_REQUEST:
+		/* The TA Request message contains only the message type. */
+		break;
+
+	case BSSLAP_MSGT_TA_RESPONSE:
+		osmo_bsslap_ie_enc_cell_id(msg, pdu->ta_response.cell_id);
+		osmo_bsslap_ie_enc_ta(msg, pdu->ta_response.ta);
+		break;
+
+	case BSSLAP_MSGT_REJECT:
+		osmo_bsslap_ie_enc_cause(msg, pdu->reject);
+		break;
+
+	case BSSLAP_MSGT_RESET:
+		osmo_bsslap_ie_enc_cell_id(msg, pdu->reset.cell_id);
+		osmo_bsslap_ie_enc_ta(msg, pdu->reset.ta);
+		osmo_bsslap_ie_enc_chan_desc(msg, &pdu->reset.chan_desc);
+		osmo_bsslap_ie_enc_cause(msg, pdu->reset.cause);
+		break;
+
+	case BSSLAP_MSGT_ABORT:
+		osmo_bsslap_ie_enc_cause(msg, pdu->abort);
+		break;
+
+	case BSSLAP_MSGT_TA_LAYER3:
+		osmo_bsslap_ie_enc_ta(msg, pdu->ta_layer3.ta);
+		break;
+
+	default:
+		return -ENOTSUP;
+	}
+	return (msg->tail - old_tail);
+}
+
+/*! Decode BSSLAP PDU (3GPP TS 48.071).
+ * \param[out] pdu  Write decoded values here.
+ * \param[out] err  Returned pointer to error info, dynamically allocated; NULL to not return any.
+ * \param[in] err_ctx  Talloc context to allocate err from, if required.
+ * \param[in] data  Pointer to BSSLAP PDU raw data.
+ * \param[in] len  Data length to decode.
+ * \return 0 on success, negative on error.
+ */
+int osmo_bsslap_dec(struct bsslap_pdu *pdu,
+		    struct osmo_bsslap_err **err, void *err_ctx,
+		    const uint8_t *data, size_t len)
+{
+	const uint8_t *ies_start;
+	int ies_len;
+	struct tlv_parsed tp;
+
+	*pdu = (struct bsslap_pdu){};
+	if (err)
+		*err = NULL;
+
+#define DEC_IE_MANDATORY(IEI, DEC_FUN, DEC_FUN_ARG) do { \
+		const struct tlv_p_entry *e; \
+		int rc; \
+		if (!(e = TLVP_GET(&tp, IEI))) \
+			DEC_ERR(-EINVAL, pdu->msg_type, IEI, LCS_CAUSE_DATA_MISSING_IN_REQ, "missing mandatory IE"); \
+		rc = DEC_FUN(DEC_FUN_ARG, pdu->msg_type, IEI, err, err_ctx, e->val, e->len); \
+		if (rc) \
+			DEC_ERR(rc, pdu->msg_type, IEI, LCS_CAUSE_UNSPECIFIED, "cannot parse IE"); \
+	} while (0)
+
+	if (len < 1)
+		DEC_ERR(-EINVAL, -1, -1, LCS_CAUSE_UNSPECIFIED, "PDU too short: %zu b", len);
+
+	pdu->msg_type = data[0];
+
+	if (pdu->msg_type == BSSLAP_MSGT_TA_REQUEST) {
+		/* The TA Request message contains only the message type. */
+		return 0;
+	}
+
+	ies_start = &data[1];
+	ies_len = len - 1;
+
+	if (tlv_parse2(&tp, 1, &osmo_bsslap_tlvdef, ies_start, ies_len, 0, 0) <= 0)
+		DEC_ERR(-EINVAL, pdu->msg_type, -1, LCS_CAUSE_UNSPECIFIED, "failed to parse TLV structure");
+
+	switch (pdu->msg_type) {
+
+	case BSSLAP_MSGT_TA_RESPONSE:
+		DEC_IE_MANDATORY(BSSLAP_IEI_CELL_ID, osmo_bsslap_ie_dec_cell_id, &pdu->ta_response.cell_id);
+		DEC_IE_MANDATORY(BSSLAP_IEI_TA, osmo_bsslap_ie_dec_ta, &pdu->ta_response.ta);
+		return 0;
+
+	case BSSLAP_MSGT_REJECT:
+		DEC_IE_MANDATORY(BSSLAP_IEI_CAUSE, osmo_bsslap_ie_dec_cause, &pdu->reject);
+		return 0;
+
+	case BSSLAP_MSGT_RESET:
+		DEC_IE_MANDATORY(BSSLAP_IEI_CELL_ID, osmo_bsslap_ie_dec_cell_id, &pdu->reset.cell_id);
+		DEC_IE_MANDATORY(BSSLAP_IEI_TA, osmo_bsslap_ie_dec_ta, &pdu->reset.ta);
+		DEC_IE_MANDATORY(BSSLAP_IEI_CHAN_DESC, osmo_bsslap_ie_dec_chan_desc, &pdu->reset.chan_desc);
+		DEC_IE_MANDATORY(BSSLAP_IEI_CAUSE, osmo_bsslap_ie_dec_cause, &pdu->reset.cause);
+		return 0;
+
+	case BSSLAP_MSGT_ABORT:
+		DEC_IE_MANDATORY(BSSLAP_IEI_CAUSE, osmo_bsslap_ie_dec_cause, &pdu->abort);
+		return 0;
+
+	case BSSLAP_MSGT_TA_LAYER3:
+		DEC_IE_MANDATORY(BSSLAP_IEI_TA, osmo_bsslap_ie_dec_ta, &pdu->ta_layer3.ta);
+		return 0;
+
+	default:
+		DEC_ERR(-EINVAL, pdu->msg_type, -1, LCS_CAUSE_UNSPECIFIED, "Unsupported message type");
+	}
+}
+
+const struct value_string osmo_bsslap_msgt_names[] = {
+	{ BSSLAP_MSGT_TA_REQUEST, "TA Request" },
+	{ BSSLAP_MSGT_TA_RESPONSE, "TA Response" },
+	{ BSSLAP_MSGT_REJECT, "Reject" },
+	{ BSSLAP_MSGT_RESET, "Reset" },
+	{ BSSLAP_MSGT_ABORT, "Abort" },
+	{ BSSLAP_MSGT_TA_LAYER3, "TA Layer3" },
+	{ BSSLAP_MSGT_MS_POS_CMD, "MS Position Command" },
+	{ BSSLAP_MSGT_MS_POS_RESP, "MS Position Response" },
+	{ BSSLAP_MSGT_UTDOA_REQ, "U-TDOA Request" },
+	{ BSSLAP_MSGT_UTDOA_RESP, "U-TDOA Response" },
+	{}
+};
+
+const struct value_string osmo_bsslap_iei_names[] = {
+	{ BSSLAP_IEI_TA, "Timing Advance" },
+	{ BSSLAP_IEI_CELL_ID, "Cell Identity" },
+	{ BSSLAP_IEI_CHAN_DESC, "Channel Description" },
+	{ BSSLAP_IEI_MEAS_REP, "Measurement Report" },
+	{ BSSLAP_IEI_CAUSE, "Cause" },
+	{ BSSLAP_IEI_RRLP_FLAG, "RRLP Flag" },
+	{ BSSLAP_IEI_RRLP, "RRLP" },
+	{ BSSLAP_IEI_CELL_ID_LIST, "Cell Identity List" },
+	{ BSSLAP_IEI_ENH_MEAS_REP, "Enhanced Measurement Report" },
+	{ BSSLAP_IEI_LAC, "Location Area Code" },
+	{ BSSLAP_IEI_FREQ_LIST, "Frequency List" },
+	{ BSSLAP_IEI_MS_POWER, "MS Power" },
+	{ BSSLAP_IEI_DELTA_TIMER, "Delta Timer" },
+	{ BSSLAP_IEI_SERVING_CELL_ID, "Serving Cell Identifier" },
+	{ BSSLAP_IEI_ENCR_KEY, "Encryption Key" },
+	{ BSSLAP_IEI_CIPH_MODE_SET, "Cipher Mode Setting" },
+	{ BSSLAP_IEI_CHAN_MODE, "Channel Mode" },
+	{ BSSLAP_IEI_MR_CONFIG, "MultiRate Configuration" },
+	{ BSSLAP_IEI_POLLING_REPETITION, "Polling Repetition" },
+	{ BSSLAP_IEI_PACKET_CHAN_DESC, "Packet Channel Description" },
+	{ BSSLAP_IEI_TLLI, "TLLI" },
+	{ BSSLAP_IEI_TFI, "TFI" },
+	{ BSSLAP_IEI_TBF_START_TIME, "TBF Starting Time" },
+	{ BSSLAP_IEI_PWRUP_START_TIME, "Powerup Starting Time" },
+	{ BSSLAP_IEI_LONG_ENCR_KEY, "Long Encryption Key" },
+	{ BSSLAP_IEI_CONCUR_POS_PROC_F, "Concurrent Positioning Flag" },
+	{}
+};
+
+/*! @} */
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 c4e6b9f..fc99485 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..43ea0d4
--- /dev/null
+++ b/tests/bsslap/bsslap_test.c
@@ -0,0 +1,103 @@
+#include <stdio.h>
+
+#include <osmocom/core/utils.h>
+#include <osmocom/core/msgb.h>
+#include <osmocom/gsm/bsslap.h>
+
+struct bsslap_pdu bsslap_test_pdus[] = {
+	{
+		.msg_type = BSSLAP_MSGT_TA_REQUEST,
+	},
+	{
+		.msg_type = BSSLAP_MSGT_TA_RESPONSE,
+		.ta_response = {
+			.cell_id = 23,
+			.ta = 42,
+		},
+	},
+	{
+		.msg_type = BSSLAP_MSGT_REJECT,
+		.reject = BSSLAP_CAUSE_OTHER_RADIO_EVT_FAIL,
+	},
+	{
+		.msg_type = 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 = BSSLAP_CAUSE_INTRA_BSS_HO,
+		},
+	},
+	{
+		.msg_type = BSSLAP_MSGT_ABORT,
+		.abort = BSSLAP_CAUSE_LOSS_SIG_CONN_MS,
+	},
+	{
+		.msg_type = BSSLAP_MSGT_TA_LAYER3,
+		.ta_layer3 = {
+			.ta = 23,
+		},
+	},
+};
+
+void test_bsslap_enc_dec()
+{
+	struct 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 bsslap_pdu dec_pdu;
+		struct osmo_bsslap_err *err;
+		int rc;
+		void *loop_ctx = msg;
+		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));
+		rc = osmo_bsslap_dec(&dec_pdu, &err, loop_ctx, msg->data, msg->len);
+		if (rc) {
+			printf("[%ld] %s: ERROR: failed to decode pdu: %s\n", (pdu - bsslap_test_pdus),
+			       osmo_bsslap_msgt_name(pdu->msg_type), err->logmsg);
+			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..f3199e1
--- /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 e29c131..0923c25 100644
--- a/tests/testsuite.at
+++ b/tests/testsuite.at
@@ -409,3 +409,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: 5
Gerrit-Owner: neels <nhofmeyr at sysmocom.de>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: laforge <laforge at osmocom.org>
Gerrit-Reviewer: neels <nhofmeyr at sysmocom.de>
Gerrit-Reviewer: pespin <pespin at sysmocom.de>
Gerrit-MessageType: merged
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.osmocom.org/pipermail/gerrit-log/attachments/20201008/755042b3/attachment.htm>


More information about the gerrit-log mailing list