aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNeels Hofmeyr <neels@hofmeyr.de>2020-09-18 18:00:50 +0200
committerNeels Hofmeyr <neels@hofmeyr.de>2020-10-07 15:19:43 +0200
commitc6848f41455068a3bb59ca937293d2c0da0af14d (patch)
tree395339bc1d2d68cf7202f45ac9c69f961fdba94c
parent086bd33f18fa79eb239a06e404915f3ba3c20e3f (diff)
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
-rw-r--r--include/Makefile.am3
-rw-r--r--include/osmocom/gsm/bsslap.h57
-rw-r--r--include/osmocom/gsm/protocol/gsm_48_071.h122
-rw-r--r--include/osmocom/gsm/protocol/gsm_49_031.h61
-rw-r--r--src/gsm/Makefile.am2
-rw-r--r--src/gsm/bsslap.c329
-rw-r--r--src/gsm/libosmogsm.map4
-rw-r--r--tests/Makefile.am5
-rw-r--r--tests/bsslap/bsslap_test.c103
-rw-r--r--tests/bsslap/bsslap_test.ok7
-rw-r--r--tests/testsuite.at6
11 files changed, 698 insertions, 1 deletions
diff --git a/include/Makefile.am b/include/Makefile.am
index fc1eec33..19d4043a 100644
--- a/include/Makefile.am
+++ b/include/Makefile.am
@@ -92,6 +92,7 @@ nobase_include_HEADERS = \
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 @@ nobase_include_HEADERS = \
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 00000000..b2174b3a
--- /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@sysmocom.de>
+ * All Rights Reserved
+ *
+ * Author: Neels Hofmeyr <neels@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 00000000..fb9653ab
--- /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@sysmocom.de>
+ * All Rights Reserved
+ *
+ * Author: Neels Hofmeyr <neels@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 00000000..b44a07eb
--- /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@sysmocom.de>
+ * All Rights Reserved
+ *
+ * Author: Neels Hofmeyr <neels@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 4fa940be..465bae1d 100644
--- a/src/gsm/Makefile.am
+++ b/src/gsm/Makefile.am
@@ -33,7 +33,7 @@ libgsmint_la_SOURCES = a5.c rxlev_stat.c tlv_parser.c comp128.c comp128v23.c \
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 00000000..7886da68
--- /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@sysmocom.de>
+ * All Rights Reserved
+ *
+ * Author: Neels Hofmeyr <neels@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 a31f73aa..257c3fa5 100644
--- a/src/gsm/libosmogsm.map
+++ b/src/gsm/libosmogsm.map
@@ -705,6 +705,10 @@ osmo_nri_ranges_vty_del;
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 c4e6b9f5..fc994852 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -39,6 +39,7 @@ check_PROGRAMS = timer/timer_test sms/sms_test ussd/ussd_test \
i460_mux/i460_mux_test \
bitgen/bitgen_test \
gad/gad_test \
+ bsslap/bsslap_test \
$(NULL)
if ENABLE_MSGFILE
@@ -285,6 +286,9 @@ bitgen_bitgen_test_LDADD = $(LDADD)
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 @@ EXTRA_DIST = testsuite.at $(srcdir)/package.m4 $(TESTSUITE) \
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 00000000..43ea0d44
--- /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 00000000..f3199e11
--- /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 e29c1312..0923c251 100644
--- a/tests/testsuite.at
+++ b/tests/testsuite.at
@@ -409,3 +409,9 @@ AT_KEYWORDS([gad])
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