<p>laforge <strong>submitted</strong> this change.</p><p><a href="https://gerrit.osmocom.org/c/libosmocore/+/20334">View Change</a></p><div style="white-space:pre-wrap">Approvals:
  Jenkins Builder: Verified
  laforge: Looks good to me, approved

</div><pre style="font-family: monospace,monospace; white-space: pre-wrap;">add BSSMAP-LE coding for Location Services<br><br>BSSMAP-LE: add Lb-interface messages between BSC and SMLC:<br>- Reset<br>- Reset Acknowledge<br>- Perform Location Request, possibly containing BSSLAP TA Layer3<br>- Perform Location Response<br>- Perform Location Abort<br>- Connection Oriented Information containing any BSSLAP APDU<br><br>Add encoding and decoding tests.<br><br>Change-Id: I271e59b794bafc0a7ae0eabbf58918f6d7df431d<br>---<br>M include/Makefile.am<br>A include/osmocom/gsm/bssmap_le.h<br>M include/osmocom/gsm/protocol/gsm_49_031.h<br>M src/gsm/Makefile.am<br>A src/gsm/bssmap_le.c<br>M src/gsm/libosmogsm.map<br>M tests/Makefile.am<br>A tests/bssmap_le/bssmap_le_test.c<br>A tests/bssmap_le/bssmap_le_test.ok<br>M tests/testsuite.at<br>10 files changed, 1,320 insertions(+), 1 deletion(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/include/Makefile.am b/include/Makefile.am</span><br><span>index 19d4043..90f448a 100644</span><br><span>--- a/include/Makefile.am</span><br><span>+++ b/include/Makefile.am</span><br><span>@@ -93,6 +93,7 @@</span><br><span>                        osmocom/coding/gsm0503_coding.h \</span><br><span>                        osmocom/coding/gsm0503_amr_dtx.h \</span><br><span>                        osmocom/gsm/bsslap.h \</span><br><span style="color: hsl(120, 100%, 40%);">+                       osmocom/gsm/bssmap_le.h \</span><br><span>                        osmocom/gsm/gad.h \</span><br><span>                        osmocom/gsm/gsm0808.h \</span><br><span>                        osmocom/gsm/gsm29205.h \</span><br><span>diff --git a/include/osmocom/gsm/bssmap_le.h b/include/osmocom/gsm/bssmap_le.h</span><br><span>new file mode 100644</span><br><span>index 0000000..1c750c8</span><br><span>--- /dev/null</span><br><span>+++ b/include/osmocom/gsm/bssmap_le.h</span><br><span>@@ -0,0 +1,81 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/*! \addtogroup bssmap_le</span><br><span style="color: hsl(120, 100%, 40%);">+ *  @{</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \file bssmap_le.h</span><br><span style="color: hsl(120, 100%, 40%);">+ * Message encoding and decoding for 3GPP TS 49.031 BSSMAP-LE.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+/*</span><br><span style="color: hsl(120, 100%, 40%);">+ * (C) 2020 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de></span><br><span style="color: hsl(120, 100%, 40%);">+ * All Rights Reserved</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * Author: Neels Hofmeyr <neels@hofmeyr.de></span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * SPDX-License-Identifier: GPL-2.0+</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This program is free software; you can redistribute it and/or modify</span><br><span style="color: hsl(120, 100%, 40%);">+ * it under the terms of the GNU General Public License as published by</span><br><span style="color: hsl(120, 100%, 40%);">+ * the Free Software Foundation; either version 2 of the License, or</span><br><span style="color: hsl(120, 100%, 40%);">+ * (at your option) any later version.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This program is distributed in the hope that it will be useful,</span><br><span style="color: hsl(120, 100%, 40%);">+ * but WITHOUT ANY WARRANTY; without even the implied warranty of</span><br><span style="color: hsl(120, 100%, 40%);">+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the</span><br><span style="color: hsl(120, 100%, 40%);">+ * GNU General Public License for more details.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * You should have received a copy of the GNU General Public License along</span><br><span style="color: hsl(120, 100%, 40%);">+ * with this program; if not, write to the Free Software Foundation, Inc.,</span><br><span style="color: hsl(120, 100%, 40%);">+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+#pragma once</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/gsm/protocol/gsm_49_031.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct osmo_bsslap_err;</span><br><span style="color: hsl(120, 100%, 40%);">+struct osmo_gad_err;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct osmo_bssmap_le_err {</span><br><span style="color: hsl(120, 100%, 40%);">+     int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+       enum bssmap_le_msgt msg_type;</span><br><span style="color: hsl(120, 100%, 40%);">+ enum bssmap_le_iei iei;</span><br><span style="color: hsl(120, 100%, 40%);">+       enum lcs_cause cause;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_bsslap_err *bsslap_err;</span><br><span style="color: hsl(120, 100%, 40%);">+   struct osmo_gad_err *gad_err;</span><br><span style="color: hsl(120, 100%, 40%);">+ char *logmsg;</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct osmo_bssap_le_err {</span><br><span style="color: hsl(120, 100%, 40%);">+       int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+       struct osmo_bssmap_le_err *bssmap_le_err;</span><br><span style="color: hsl(120, 100%, 40%);">+     void *dtap_err;</span><br><span style="color: hsl(120, 100%, 40%);">+       char *logmsg;</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+enum bssmap_le_msgt osmo_bssmap_le_msgt(const uint8_t *data, uint8_t len);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+extern const struct value_string osmo_bssmap_le_msgt_names[];</span><br><span style="color: hsl(120, 100%, 40%);">+static inline const char *osmo_bssmap_le_msgt_name(enum bssmap_le_msgt val)</span><br><span style="color: hsl(120, 100%, 40%);">+{ return get_value_string(osmo_bssmap_le_msgt_names, val); }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+extern const struct value_string osmo_bssmap_le_iei_names[];</span><br><span style="color: hsl(120, 100%, 40%);">+static inline const char *osmo_bssmap_le_iei_name(enum bssmap_le_iei val)</span><br><span style="color: hsl(120, 100%, 40%);">+{ return get_value_string(osmo_bssmap_le_iei_names, val); }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int osmo_lcs_cause_enc(struct msgb *msg, const struct lcs_cause_ie *lcs_cause);</span><br><span style="color: hsl(120, 100%, 40%);">+int osmo_lcs_cause_dec(struct lcs_cause_ie *lcs_cause,</span><br><span style="color: hsl(120, 100%, 40%);">+                       enum bssmap_le_msgt msgt, enum bssmap_le_iei iei,</span><br><span style="color: hsl(120, 100%, 40%);">+                     struct osmo_bssmap_le_err **err, void *err_ctx,</span><br><span style="color: hsl(120, 100%, 40%);">+                       const uint8_t *data, uint8_t len);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int osmo_bssap_le_pdu_to_str_buf(char *buf, size_t buflen, const struct bssap_le_pdu *bssap_le);</span><br><span style="color: hsl(120, 100%, 40%);">+char *osmo_bssap_le_pdu_to_str_c(void *ctx, const struct bssap_le_pdu *bssap_le);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct msgb *osmo_bssap_le_enc(const struct bssap_le_pdu *pdu);</span><br><span style="color: hsl(120, 100%, 40%);">+int osmo_bssap_le_dec(struct bssap_le_pdu *pdu, struct osmo_bssap_le_err **err, void *err_ctx, struct msgb *msg);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+uint8_t osmo_bssmap_le_ie_enc_location_type(struct msgb *msg, const struct bssmap_le_location_type *location_type);</span><br><span style="color: hsl(120, 100%, 40%);">+int osmo_bssmap_le_ie_dec_location_type(struct bssmap_le_location_type *lt,</span><br><span style="color: hsl(120, 100%, 40%);">+                                    enum bssmap_le_msgt msgt, enum bssmap_le_iei iei,</span><br><span style="color: hsl(120, 100%, 40%);">+                                     struct osmo_bssmap_le_err **err, void *err_ctx,</span><br><span style="color: hsl(120, 100%, 40%);">+                                       const uint8_t *elem, uint8_t len);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! @} */</span><br><span>diff --git a/include/osmocom/gsm/protocol/gsm_49_031.h b/include/osmocom/gsm/protocol/gsm_49_031.h</span><br><span>index b44a07e..c6152e1 100644</span><br><span>--- a/include/osmocom/gsm/protocol/gsm_49_031.h</span><br><span>+++ b/include/osmocom/gsm/protocol/gsm_49_031.h</span><br><span>@@ -29,6 +29,10 @@</span><br><span> </span><br><span> #include <stdint.h></span><br><span> #include <stdbool.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/gsm/protocol/gsm_48_071.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/gsm/protocol/gsm_23_032.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/gsm/gsm0808_utils.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/gsm/gsm48.h></span><br><span> </span><br><span> /*! 3GPP TS 49.031 10.13 LCS Cause, also in 3GPP TS 48.008 3.2.2.66, which simply refers to the former. */</span><br><span> enum lcs_cause {</span><br><span>@@ -58,4 +62,151 @@</span><br><span>         uint8_t diag_val;</span><br><span> };</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+enum bssap_le_msg_discr {</span><br><span style="color: hsl(120, 100%, 40%);">+        BSSAP_LE_MSG_DISCR_BSSMAP_LE = 0,</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+enum bssmap_le_msgt {</span><br><span style="color: hsl(120, 100%, 40%);">+        BSSMAP_LE_MSGT_PERFORM_LOC_REQ = 0x2b,</span><br><span style="color: hsl(120, 100%, 40%);">+        BSSMAP_LE_MSGT_PERFORM_LOC_RESP = 0x2d,</span><br><span style="color: hsl(120, 100%, 40%);">+       BSSMAP_LE_MSGT_PERFORM_LOC_ABORT = 0x2e,</span><br><span style="color: hsl(120, 100%, 40%);">+      BSSMAP_LE_MSGT_PERFORM_LOC_INFO = 0x2f,</span><br><span style="color: hsl(120, 100%, 40%);">+       BSSMAP_LE_MSGT_ASSIST_INFO_REQ = 0x20,</span><br><span style="color: hsl(120, 100%, 40%);">+        BSSMAP_LE_MSGT_ASSIST_INFO_RESP = 0x21,</span><br><span style="color: hsl(120, 100%, 40%);">+       BSSMAP_LE_MSGT_CONN_ORIENTED_INFO = 0x2a,</span><br><span style="color: hsl(120, 100%, 40%);">+     BSSMAP_LE_MSGT_CONN_LESS_INFO = 0x3a,</span><br><span style="color: hsl(120, 100%, 40%);">+ BSSMAP_LE_MSGT_RESET = 0x30,</span><br><span style="color: hsl(120, 100%, 40%);">+  BSSMAP_LE_MSGT_RESET_ACK = 0x31,</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+enum bssmap_le_iei {</span><br><span style="color: hsl(120, 100%, 40%);">+  BSSMAP_LE_IEI_LCS_QoS = 0x3e,</span><br><span style="color: hsl(120, 100%, 40%);">+ BSSMAP_LE_IEI_LCS_PRIORITY = 0x43,</span><br><span style="color: hsl(120, 100%, 40%);">+    BSSMAP_LE_IEI_LOCATION_TYPE = 0x44,</span><br><span style="color: hsl(120, 100%, 40%);">+   BSSMAP_LE_IEI_GANSS_LOCATION_TYPE = 0x82,</span><br><span style="color: hsl(120, 100%, 40%);">+     BSSMAP_LE_IEI_GEO_LOCATION = 0x45,</span><br><span style="color: hsl(120, 100%, 40%);">+    BSSMAP_LE_IEI_POSITIONING_DATA = 0x46,</span><br><span style="color: hsl(120, 100%, 40%);">+        BSSMAP_LE_IEI_GANSS_POS_DATA = 0x83,</span><br><span style="color: hsl(120, 100%, 40%);">+  BSSMAP_LE_IEI_VELOCITY_DATA = 0x55,</span><br><span style="color: hsl(120, 100%, 40%);">+   BSSMAP_LE_IEI_LCS_CAUSE = 0x47,</span><br><span style="color: hsl(120, 100%, 40%);">+       BSSMAP_LE_IEI_LCS_CLIENT_TYPE = 0x48,</span><br><span style="color: hsl(120, 100%, 40%);">+ BSSMAP_LE_IEI_APDU = 0x49,</span><br><span style="color: hsl(120, 100%, 40%);">+    BSSMAP_LE_IEI_NET_ELEM_ID = 0x4a,</span><br><span style="color: hsl(120, 100%, 40%);">+     BSSMAP_LE_IEI_REQ_GPS_ASS_D = 0x4b,</span><br><span style="color: hsl(120, 100%, 40%);">+   BSSMAP_LE_IEI_REQ_GANSS_ASS_D = 0x41,</span><br><span style="color: hsl(120, 100%, 40%);">+ BSSMAP_LE_IEI_DECIPH_KEYS = 0x4c,</span><br><span style="color: hsl(120, 100%, 40%);">+     BSSMAP_LE_IEI_RET_ERR_REQ = 0x4d,</span><br><span style="color: hsl(120, 100%, 40%);">+     BSSMAP_LE_IEI_RET_ERR_CAUSE = 0x4e,</span><br><span style="color: hsl(120, 100%, 40%);">+   BSSMAP_LE_IEI_SEGMENTATION = 0x4f,</span><br><span style="color: hsl(120, 100%, 40%);">+    BSSMAP_LE_IEI_CLASSMARK3_INFO = 0x13,</span><br><span style="color: hsl(120, 100%, 40%);">+ BSSMAP_LE_IEI_CAUSE = 0x4,</span><br><span style="color: hsl(120, 100%, 40%);">+    BSSMAP_LE_IEI_CELL_ID = 0x5,</span><br><span style="color: hsl(120, 100%, 40%);">+  BSSMAP_LE_IEI_CHOSEN_CHAN = 0x21,</span><br><span style="color: hsl(120, 100%, 40%);">+     BSSMAP_LE_IEI_IMSI = 0x0,</span><br><span style="color: hsl(120, 100%, 40%);">+     BSSMAP_LE_IEI_LCS_CAPABILITY = 0x50,</span><br><span style="color: hsl(120, 100%, 40%);">+  BSSMAP_LE_IEI_PKT_MEAS_REP = 0x51,</span><br><span style="color: hsl(120, 100%, 40%);">+    BSSMAP_LE_IEI_CELL_ID_LIST = 0x52,</span><br><span style="color: hsl(120, 100%, 40%);">+    BSSMAP_LE_IEI_IMEI = 0x80,</span><br><span style="color: hsl(120, 100%, 40%);">+    BSSMAP_LE_IEI_BSS_MLAT_CAP = 0x84,</span><br><span style="color: hsl(120, 100%, 40%);">+    BSSMAP_LE_IEI_CELL_INFO_LIST = 0x85,</span><br><span style="color: hsl(120, 100%, 40%);">+  BSSMAP_LE_IEI_BTS_RX_ACC_LVL = 0x86,</span><br><span style="color: hsl(120, 100%, 40%);">+  BSSMAP_LE_IEI_MLAT_METHOD = 0x87,</span><br><span style="color: hsl(120, 100%, 40%);">+     BSSMAP_LE_IEI_MLAT_TA = 0x88,</span><br><span style="color: hsl(120, 100%, 40%);">+ BSSMAP_LE_IEI_MS_SYNC_ACC = 0x89,</span><br><span style="color: hsl(120, 100%, 40%);">+     BSSMAP_LE_IEI_SHORT_ID_SET = 0x8a,</span><br><span style="color: hsl(120, 100%, 40%);">+    BSSMAP_LE_IEI_RANDOM_ID_SET = 0x8b,</span><br><span style="color: hsl(120, 100%, 40%);">+   BSSMAP_LE_IEI_SHORT_BSS_ID = 0x8c,</span><br><span style="color: hsl(120, 100%, 40%);">+    BSSMAP_LE_IEI_RANDOM_ID = 0x8d,</span><br><span style="color: hsl(120, 100%, 40%);">+       BSSMAP_LE_IEI_SHORT_ID = 0x8e,</span><br><span style="color: hsl(120, 100%, 40%);">+        BSSMAP_LE_IEI_COVERAGE_CLASS = 0x8f,</span><br><span style="color: hsl(120, 100%, 40%);">+  BSSMAP_LE_IEI_MTA_ACC_SEC_RQD = 0x90,</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+enum bssmap_le_apdu_proto {</span><br><span style="color: hsl(120, 100%, 40%);">+      BSSMAP_LE_APDU_PROT_RESERVED = 0,</span><br><span style="color: hsl(120, 100%, 40%);">+     BSSMAP_LE_APDU_PROT_BSSLAP = 1,</span><br><span style="color: hsl(120, 100%, 40%);">+       BSSMAP_LE_APDU_PROT_LLP = 2,</span><br><span style="color: hsl(120, 100%, 40%);">+  BSSMAP_LE_APDU_PROT_SMLCPP = 3,</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+enum bssmap_le_location_information {</span><br><span style="color: hsl(120, 100%, 40%);">+  BSSMAP_LE_LOC_INFO_CURRENT_GEOGRAPHIC = 0x0,</span><br><span style="color: hsl(120, 100%, 40%);">+  BSSMAP_LE_LOC_INFO_ASSIST_TARGET_MS = 0x1,</span><br><span style="color: hsl(120, 100%, 40%);">+    BSSMAP_LE_LOC_INFO_BC_DECIPHER_KEYS = 0x2,</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+enum bssmap_le_positioning_method {</span><br><span style="color: hsl(120, 100%, 40%);">+ BSSMAP_LE_POS_METHOD_OMITTED = 0x0,</span><br><span style="color: hsl(120, 100%, 40%);">+   BSSMAP_LE_POS_METHOD_MOBILE_ASSISTED_E_OTD = 0x1,</span><br><span style="color: hsl(120, 100%, 40%);">+     BSSMAP_LE_POS_METHOD_MOBILE_BASED_E_OTD = 0x2,</span><br><span style="color: hsl(120, 100%, 40%);">+        BSSMAP_LE_POS_METHOD_ASSISTED_GPS = 0x3,</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct bssmap_le_location_type {</span><br><span style="color: hsl(120, 100%, 40%);">+      enum bssmap_le_location_information location_information;</span><br><span style="color: hsl(120, 100%, 40%);">+     enum bssmap_le_positioning_method positioning_method;</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+enum bssmap_le_lcs_client_type {</span><br><span style="color: hsl(120, 100%, 40%);">+ BSSMAP_LE_LCS_CTYPE_VALUE_ADDED_UNSPECIFIED = 0x0,</span><br><span style="color: hsl(120, 100%, 40%);">+    BSSMAP_LE_LCS_CTYPE_PLMN_OPER_UNSPECIFIED = 0x20,</span><br><span style="color: hsl(120, 100%, 40%);">+     BSSMAP_LE_LCS_CTYPE_PLMN_OPER_BCAST_SERVICE = 0x21,</span><br><span style="color: hsl(120, 100%, 40%);">+   BSSMAP_LE_LCS_CTYPE_PLMN_OPER_OAM = 0x22,</span><br><span style="color: hsl(120, 100%, 40%);">+     BSSMAP_LE_LCS_CTYPE_PLMN_OPER_ANON_STATS = 0x23,</span><br><span style="color: hsl(120, 100%, 40%);">+      BSSMAP_LE_LCS_CTYPE_PLMN_OPER_TGT_MS_SVC = 0x24,</span><br><span style="color: hsl(120, 100%, 40%);">+      BSSMAP_LE_LCS_CTYPE_EMERG_SVC_UNSPECIFIED = 0x30,</span><br><span style="color: hsl(120, 100%, 40%);">+     BSSMAP_LE_LCS_CTYPE_LI_UNSPECIFIED = 0x40,</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct bssmap_le_perform_loc_req {</span><br><span style="color: hsl(120, 100%, 40%);">+  struct bssmap_le_location_type location_type;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct gsm0808_cell_id cell_id;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     bool lcs_client_type_present;</span><br><span style="color: hsl(120, 100%, 40%);">+ enum bssmap_le_lcs_client_type lcs_client_type;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     struct osmo_mobile_identity imsi;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct osmo_mobile_identity imei;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   bool apdu_present;</span><br><span style="color: hsl(120, 100%, 40%);">+    struct bsslap_pdu apdu;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     bool more_items; /*!< always set this to false */</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct bssmap_le_perform_loc_resp {</span><br><span style="color: hsl(120, 100%, 40%);">+       bool location_estimate_present;</span><br><span style="color: hsl(120, 100%, 40%);">+       union gad_raw location_estimate;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    struct lcs_cause_ie lcs_cause;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      bool more_items; /*!< always set this to false */</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct bssmap_le_conn_oriented_info {</span><br><span style="color: hsl(120, 100%, 40%);">+     struct bsslap_pdu apdu;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     bool more_items; /*!< always set this to false */</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct bssmap_le_pdu {</span><br><span style="color: hsl(120, 100%, 40%);">+    enum bssmap_le_msgt msg_type;</span><br><span style="color: hsl(120, 100%, 40%);">+ union {</span><br><span style="color: hsl(120, 100%, 40%);">+               enum gsm0808_cause reset;</span><br><span style="color: hsl(120, 100%, 40%);">+             /* reset_ack consists only of the message type */</span><br><span style="color: hsl(120, 100%, 40%);">+             struct bssmap_le_perform_loc_req perform_loc_req;</span><br><span style="color: hsl(120, 100%, 40%);">+             struct bssmap_le_perform_loc_resp perform_loc_resp;</span><br><span style="color: hsl(120, 100%, 40%);">+           struct lcs_cause_ie perform_loc_abort;</span><br><span style="color: hsl(120, 100%, 40%);">+                struct bssmap_le_conn_oriented_info conn_oriented_info;</span><br><span style="color: hsl(120, 100%, 40%);">+       };</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct bssap_le_pdu {</span><br><span style="color: hsl(120, 100%, 40%);">+       enum bssap_le_msg_discr discr;</span><br><span style="color: hsl(120, 100%, 40%);">+        union {</span><br><span style="color: hsl(120, 100%, 40%);">+               struct bssmap_le_pdu bssmap_le;</span><br><span style="color: hsl(120, 100%, 40%);">+               /* future: add DTAP PDU, currently not implemented */</span><br><span style="color: hsl(120, 100%, 40%);">+ };</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /*! @} */</span><br><span>diff --git a/src/gsm/Makefile.am b/src/gsm/Makefile.am</span><br><span>index 465bae1..ccb2456 100644</span><br><span>--- a/src/gsm/Makefile.am</span><br><span>+++ b/src/gsm/Makefile.am</span><br><span>@@ -33,7 +33,7 @@</span><br><span>                   gsup.c gsup_sms.c gprs_gea.c gsm0503_conv.c oap.c gsm0808_utils.c \</span><br><span>                  gsm23003.c gsm23236.c mncc.c bts_features.c oap_client.c \</span><br><span>                   gsm29118.c gsm48_rest_octets.c cbsp.c gsm48049.c i460_mux.c \</span><br><span style="color: hsl(0, 100%, 40%);">-                   gad.c bsslap.c</span><br><span style="color: hsl(120, 100%, 40%);">+                        gad.c bsslap.c bssmap_le.c</span><br><span> libgsmint_la_LDFLAGS = -no-undefined</span><br><span> libgsmint_la_LIBADD = $(top_builddir)/src/libosmocore.la</span><br><span> </span><br><span>diff --git a/src/gsm/bssmap_le.c b/src/gsm/bssmap_le.c</span><br><span>new file mode 100644</span><br><span>index 0000000..7954653</span><br><span>--- /dev/null</span><br><span>+++ b/src/gsm/bssmap_le.c</span><br><span>@@ -0,0 +1,876 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/* 3GPP TS 49.031 BSSMAP-LE protocol definitions */</span><br><span style="color: hsl(120, 100%, 40%);">+/*</span><br><span style="color: hsl(120, 100%, 40%);">+ * (C) 2020 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de></span><br><span style="color: hsl(120, 100%, 40%);">+ * All Rights Reserved</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * Author: Neels Hofmeyr <neels@hofmeyr.de></span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * SPDX-License-Identifier: GPL-2.0+</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This program is free software; you can redistribute it and/or modify</span><br><span style="color: hsl(120, 100%, 40%);">+ * it under the terms of the GNU General Public License as published by</span><br><span style="color: hsl(120, 100%, 40%);">+ * the Free Software Foundation; either version 2 of the License, or</span><br><span style="color: hsl(120, 100%, 40%);">+ * (at your option) any later version.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This program is distributed in the hope that it will be useful,</span><br><span style="color: hsl(120, 100%, 40%);">+ * but WITHOUT ANY WARRANTY; without even the implied warranty of</span><br><span style="color: hsl(120, 100%, 40%);">+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the</span><br><span style="color: hsl(120, 100%, 40%);">+ * GNU General Public License for more details.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * You should have received a copy of the GNU General Public License along</span><br><span style="color: hsl(120, 100%, 40%);">+ * with this program; if not, write to the Free Software Foundation, Inc.,</span><br><span style="color: hsl(120, 100%, 40%);">+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <string.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/byteswap.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/endian.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/msgb.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/gsm/bssmap_le.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/gsm/bsslap.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/gsm/gad.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/gsm/gsm48.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/gsm/gsm0808.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! \addtogroup bssmap_le</span><br><span style="color: hsl(120, 100%, 40%);">+ *  @{</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \file bssmap_le.c</span><br><span style="color: hsl(120, 100%, 40%);">+ *  Message encoding and decoding for 3GPP TS 49.031 BSSMAP-LE.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define BSSAP_LE_MSG_SIZE BSSMAP_MSG_SIZE</span><br><span style="color: hsl(120, 100%, 40%);">+#define BSSAP_LE_MSG_HEADROOM BSSMAP_MSG_HEADROOM</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static const struct tlv_definition osmo_bssmap_le_tlvdef = {</span><br><span style="color: hsl(120, 100%, 40%);">+    .def = {</span><br><span style="color: hsl(120, 100%, 40%);">+      [BSSMAP_LE_IEI_LCS_QoS] = { TLV_TYPE_TLV },</span><br><span style="color: hsl(120, 100%, 40%);">+   [BSSMAP_LE_IEI_LCS_PRIORITY] = { TLV_TYPE_TLV },</span><br><span style="color: hsl(120, 100%, 40%);">+      [BSSMAP_LE_IEI_LOCATION_TYPE] = { TLV_TYPE_TLV },</span><br><span style="color: hsl(120, 100%, 40%);">+     [BSSMAP_LE_IEI_GANSS_LOCATION_TYPE] = { TLV_TYPE_TLV },</span><br><span style="color: hsl(120, 100%, 40%);">+       [BSSMAP_LE_IEI_GEO_LOCATION] = { TLV_TYPE_TLV },</span><br><span style="color: hsl(120, 100%, 40%);">+      [BSSMAP_LE_IEI_POSITIONING_DATA] = { TLV_TYPE_TLV },</span><br><span style="color: hsl(120, 100%, 40%);">+  [BSSMAP_LE_IEI_GANSS_POS_DATA] = { TLV_TYPE_TLV },</span><br><span style="color: hsl(120, 100%, 40%);">+    [BSSMAP_LE_IEI_VELOCITY_DATA] = { TLV_TYPE_TLV },</span><br><span style="color: hsl(120, 100%, 40%);">+     [BSSMAP_LE_IEI_LCS_CAUSE] = { TLV_TYPE_TLV },</span><br><span style="color: hsl(120, 100%, 40%);">+ [BSSMAP_LE_IEI_LCS_CLIENT_TYPE] = { TLV_TYPE_TLV },</span><br><span style="color: hsl(120, 100%, 40%);">+   [BSSMAP_LE_IEI_APDU] = { TLV_TYPE_TL16V },</span><br><span style="color: hsl(120, 100%, 40%);">+    [BSSMAP_LE_IEI_NET_ELEM_ID] = { TLV_TYPE_TLV },</span><br><span style="color: hsl(120, 100%, 40%);">+       [BSSMAP_LE_IEI_REQ_GPS_ASS_D] = { TLV_TYPE_TLV },</span><br><span style="color: hsl(120, 100%, 40%);">+     [BSSMAP_LE_IEI_REQ_GANSS_ASS_D] = { TLV_TYPE_TLV },</span><br><span style="color: hsl(120, 100%, 40%);">+   [BSSMAP_LE_IEI_DECIPH_KEYS] = { TLV_TYPE_TLV },</span><br><span style="color: hsl(120, 100%, 40%);">+       [BSSMAP_LE_IEI_RET_ERR_REQ] = { TLV_TYPE_TLV },</span><br><span style="color: hsl(120, 100%, 40%);">+       [BSSMAP_LE_IEI_RET_ERR_CAUSE] = { TLV_TYPE_TLV },</span><br><span style="color: hsl(120, 100%, 40%);">+     [BSSMAP_LE_IEI_SEGMENTATION] = { TLV_TYPE_TLV },</span><br><span style="color: hsl(120, 100%, 40%);">+      [BSSMAP_LE_IEI_CLASSMARK3_INFO] = { TLV_TYPE_TLV },</span><br><span style="color: hsl(120, 100%, 40%);">+   [BSSMAP_LE_IEI_CAUSE] = { TLV_TYPE_TLV },</span><br><span style="color: hsl(120, 100%, 40%);">+     [BSSMAP_LE_IEI_CELL_ID] = { TLV_TYPE_TLV },</span><br><span style="color: hsl(120, 100%, 40%);">+   [BSSMAP_LE_IEI_CHOSEN_CHAN] = { TLV_TYPE_TLV },</span><br><span style="color: hsl(120, 100%, 40%);">+       [BSSMAP_LE_IEI_IMSI] = { TLV_TYPE_TLV },</span><br><span style="color: hsl(120, 100%, 40%);">+      [BSSMAP_LE_IEI_LCS_CAPABILITY] = { TLV_TYPE_TLV },</span><br><span style="color: hsl(120, 100%, 40%);">+    [BSSMAP_LE_IEI_PKT_MEAS_REP] = { TLV_TYPE_TLV },</span><br><span style="color: hsl(120, 100%, 40%);">+      [BSSMAP_LE_IEI_CELL_ID_LIST] = { TLV_TYPE_TLV },</span><br><span style="color: hsl(120, 100%, 40%);">+      [BSSMAP_LE_IEI_IMEI] = { TLV_TYPE_TLV },</span><br><span style="color: hsl(120, 100%, 40%);">+      [BSSMAP_LE_IEI_BSS_MLAT_CAP] = { TLV_TYPE_TLV },</span><br><span style="color: hsl(120, 100%, 40%);">+      [BSSMAP_LE_IEI_CELL_INFO_LIST] = { TLV_TYPE_TLV },</span><br><span style="color: hsl(120, 100%, 40%);">+    [BSSMAP_LE_IEI_BTS_RX_ACC_LVL] = { TLV_TYPE_TLV },</span><br><span style="color: hsl(120, 100%, 40%);">+    [BSSMAP_LE_IEI_MLAT_METHOD] = { TLV_TYPE_TLV },</span><br><span style="color: hsl(120, 100%, 40%);">+       [BSSMAP_LE_IEI_MLAT_TA] = { TLV_TYPE_TLV },</span><br><span style="color: hsl(120, 100%, 40%);">+   [BSSMAP_LE_IEI_MS_SYNC_ACC] = { TLV_TYPE_TLV },</span><br><span style="color: hsl(120, 100%, 40%);">+       [BSSMAP_LE_IEI_SHORT_ID_SET] = { TLV_TYPE_TLV },</span><br><span style="color: hsl(120, 100%, 40%);">+      [BSSMAP_LE_IEI_RANDOM_ID_SET] = { TLV_TYPE_TLV },</span><br><span style="color: hsl(120, 100%, 40%);">+     [BSSMAP_LE_IEI_SHORT_BSS_ID] = { TLV_TYPE_TLV },</span><br><span style="color: hsl(120, 100%, 40%);">+      [BSSMAP_LE_IEI_RANDOM_ID] = { TLV_TYPE_TLV },</span><br><span style="color: hsl(120, 100%, 40%);">+ [BSSMAP_LE_IEI_SHORT_ID] = { TLV_TYPE_TLV },</span><br><span style="color: hsl(120, 100%, 40%);">+  [BSSMAP_LE_IEI_COVERAGE_CLASS] = { TLV_TYPE_TLV },</span><br><span style="color: hsl(120, 100%, 40%);">+    [BSSMAP_LE_IEI_MTA_ACC_SEC_RQD] = { TLV_TYPE_TLV },</span><br><span style="color: hsl(120, 100%, 40%);">+   },</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define DEC_ERR_NO_RETURN(RC, MSG_TYPE, IEI, CAUSE, fmt, args...) do { \</span><br><span style="color: hsl(120, 100%, 40%);">+            if (err && !*err) { \</span><br><span style="color: hsl(120, 100%, 40%);">+                 *err = talloc_zero(err_ctx, struct osmo_bssmap_le_err); \</span><br><span style="color: hsl(120, 100%, 40%);">+                     **err = (struct osmo_bssmap_le_err){ \</span><br><span style="color: hsl(120, 100%, 40%);">+                                .rc = (RC), \</span><br><span style="color: hsl(120, 100%, 40%);">+                         .msg_type = (MSG_TYPE), \</span><br><span style="color: hsl(120, 100%, 40%);">+                             .iei = (IEI), \</span><br><span style="color: hsl(120, 100%, 40%);">+                               .cause = (CAUSE), \</span><br><span style="color: hsl(120, 100%, 40%);">+                   }; \</span><br><span style="color: hsl(120, 100%, 40%);">+                  (*err)->logmsg = talloc_asprintf(*err, "Error decoding BSSMAP-LE%s%s%s%s%s: " fmt, \</span><br><span style="color: hsl(120, 100%, 40%);">+                                                      (MSG_TYPE) >= 0 ? " " : "", \</span><br><span style="color: hsl(120, 100%, 40%);">+                                                  (MSG_TYPE) >= 0 ? osmo_bssmap_le_msgt_name(MSG_TYPE) : "", \</span><br><span style="color: hsl(120, 100%, 40%);">+                                                     (IEI) >= 0 ? ": " : "", \</span><br><span style="color: hsl(120, 100%, 40%);">+                                                      (IEI) >= 0 ? osmo_bssmap_le_iei_name(IEI) : "", \</span><br><span style="color: hsl(120, 100%, 40%);">+                                                        (IEI) >= 0 ? " IE" : "", \</span><br><span style="color: hsl(120, 100%, 40%);">+                                                     ##args); \</span><br><span style="color: hsl(120, 100%, 40%);">+           } \</span><br><span style="color: hsl(120, 100%, 40%);">+   } while(0)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define DEC_ERR(RC, MSG_TYPE, IEI, CAUSE, fmt, args...) do { \</span><br><span style="color: hsl(120, 100%, 40%);">+          DEC_ERR_NO_RETURN(RC, MSG_TYPE, IEI, CAUSE, fmt, ##args); \</span><br><span style="color: hsl(120, 100%, 40%);">+           return RC; \</span><br><span style="color: hsl(120, 100%, 40%);">+  } while(0)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define DEC_IE_MANDATORY(MSG_TYPE, IEI, DEC_FUN, DEC_FUN_ARG) do { \</span><br><span style="color: hsl(120, 100%, 40%);">+            const struct tlv_p_entry *e; \</span><br><span style="color: hsl(120, 100%, 40%);">+                int rc; \</span><br><span style="color: hsl(120, 100%, 40%);">+             if (!(e = TLVP_GET(tp, IEI))) \</span><br><span style="color: hsl(120, 100%, 40%);">+                       DEC_ERR(-EINVAL, MSG_TYPE, IEI, LCS_CAUSE_DATA_MISSING_IN_REQ, "missing mandatory IE"); \</span><br><span style="color: hsl(120, 100%, 40%);">+           rc = DEC_FUN(DEC_FUN_ARG, MSG_TYPE, IEI, err, err_ctx, e->val, e->len); \</span><br><span style="color: hsl(120, 100%, 40%);">+               if (rc) \</span><br><span style="color: hsl(120, 100%, 40%);">+                     DEC_ERR(rc, MSG_TYPE, IEI, LCS_CAUSE_UNSPECIFIED, "cannot parse IE"); \</span><br><span style="color: hsl(120, 100%, 40%);">+     } while (0)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define DEC_IE_OPTIONAL_FLAG(MSG_TYPE, IEI, DEC_FUN, DEC_FUN_ARG, PRESENCE_FLAG) do { \</span><br><span style="color: hsl(120, 100%, 40%);">+                const struct tlv_p_entry *e; \</span><br><span style="color: hsl(120, 100%, 40%);">+                int rc; \</span><br><span style="color: hsl(120, 100%, 40%);">+             if ((e = TLVP_GET(tp, IEI))) {\</span><br><span style="color: hsl(120, 100%, 40%);">+                       rc = DEC_FUN(DEC_FUN_ARG, MSG_TYPE, IEI, err, err_ctx, e->val, e->len); \</span><br><span style="color: hsl(120, 100%, 40%);">+                       if (rc) \</span><br><span style="color: hsl(120, 100%, 40%);">+                             DEC_ERR(rc, MSG_TYPE, IEI, LCS_CAUSE_UNSPECIFIED, "cannot parse IE"); \</span><br><span style="color: hsl(120, 100%, 40%);">+                     PRESENCE_FLAG = true; \</span><br><span style="color: hsl(120, 100%, 40%);">+               } \</span><br><span style="color: hsl(120, 100%, 40%);">+   } while (0)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define DEC_IE_OPTIONAL(MSG_TYPE, IEI, DEC_FUN, DEC_FUN_ARG) do { \</span><br><span style="color: hsl(120, 100%, 40%);">+            const struct tlv_p_entry *e; \</span><br><span style="color: hsl(120, 100%, 40%);">+                int rc; \</span><br><span style="color: hsl(120, 100%, 40%);">+             if ((e = TLVP_GET(tp, IEI))) {\</span><br><span style="color: hsl(120, 100%, 40%);">+                       rc = DEC_FUN(DEC_FUN_ARG, MSG_TYPE, IEI, err, err_ctx, e->val, e->len); \</span><br><span style="color: hsl(120, 100%, 40%);">+                       if (rc) \</span><br><span style="color: hsl(120, 100%, 40%);">+                             DEC_ERR(rc, MSG_TYPE, IEI, LCS_CAUSE_UNSPECIFIED, "cannot parse IE"); \</span><br><span style="color: hsl(120, 100%, 40%);">+             } \</span><br><span style="color: hsl(120, 100%, 40%);">+   } while (0)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! Encode full BSSMAP-LE Location Type IE, including IEI tag and length.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[inout] msg  Message buffer to append to.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[in] location_type  Values to enconde.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \returns length of bytes written to the msgb.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+uint8_t osmo_bssmap_le_ie_enc_location_type(struct msgb *msg,</span><br><span style="color: hsl(120, 100%, 40%);">+                                       const struct bssmap_le_location_type *location_type)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   uint8_t *old_tail;</span><br><span style="color: hsl(120, 100%, 40%);">+    uint8_t *tlv_len;</span><br><span style="color: hsl(120, 100%, 40%);">+     OSMO_ASSERT(msg);</span><br><span style="color: hsl(120, 100%, 40%);">+     msgb_put_u8(msg, BSSMAP_LE_IEI_LOCATION_TYPE);</span><br><span style="color: hsl(120, 100%, 40%);">+        tlv_len = msgb_put(msg, 1);</span><br><span style="color: hsl(120, 100%, 40%);">+   old_tail = msg->tail;</span><br><span style="color: hsl(120, 100%, 40%);">+      msgb_put_u8(msg, location_type->location_information);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   switch (location_type->location_information) {</span><br><span style="color: hsl(120, 100%, 40%);">+     case BSSMAP_LE_LOC_INFO_ASSIST_TARGET_MS:</span><br><span style="color: hsl(120, 100%, 40%);">+     case BSSMAP_LE_LOC_INFO_BC_DECIPHER_KEYS:</span><br><span style="color: hsl(120, 100%, 40%);">+             msgb_put_u8(msg, location_type->positioning_method);</span><br><span style="color: hsl(120, 100%, 40%);">+               break;</span><br><span style="color: hsl(120, 100%, 40%);">+        default:</span><br><span style="color: hsl(120, 100%, 40%);">+              break;</span><br><span style="color: hsl(120, 100%, 40%);">+        }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   *tlv_len = (uint8_t) (msg->tail - old_tail);</span><br><span style="color: hsl(120, 100%, 40%);">+       return *tlv_len + 2;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! Decode BSSMAP-LE Location Type IE value part.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[out] lt  Buffer to write decoded values to.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[in] elem  Pointer to the value part, the V of a TLV.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[in] len  Length, the L of a TLV.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \returns 0 on success, negative on error; lt is always overwritten: cleared on error, populated with values on</span><br><span style="color: hsl(120, 100%, 40%);">+ * success.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+int osmo_bssmap_le_ie_dec_location_type(struct bssmap_le_location_type *lt,</span><br><span style="color: hsl(120, 100%, 40%);">+                                     enum bssmap_le_msgt msgt, enum bssmap_le_iei iei,</span><br><span style="color: hsl(120, 100%, 40%);">+                                     struct osmo_bssmap_le_err **err, void *err_ctx,</span><br><span style="color: hsl(120, 100%, 40%);">+                                       const uint8_t *elem, uint8_t len)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  *lt = (struct bssmap_le_location_type){};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!elem || len < 1)</span><br><span style="color: hsl(120, 100%, 40%);">+              DEC_ERR(-EINVAL, msgt, iei, LCS_CAUSE_UNSPECIFIED, "zero length");</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        lt->location_information = elem[0];</span><br><span style="color: hsl(120, 100%, 40%);">+        switch (lt->location_information) {</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      case BSSMAP_LE_LOC_INFO_CURRENT_GEOGRAPHIC:</span><br><span style="color: hsl(120, 100%, 40%);">+           if (len != 1)</span><br><span style="color: hsl(120, 100%, 40%);">+                 DEC_ERR(-EINVAL, msgt, iei, LCS_CAUSE_UNSPECIFIED,</span><br><span style="color: hsl(120, 100%, 40%);">+                            "location info type 'Current Geographic': length should be 1 byte, got %u", len);</span><br><span style="color: hsl(120, 100%, 40%);">+           lt->positioning_method = BSSMAP_LE_POS_METHOD_OMITTED;</span><br><span style="color: hsl(120, 100%, 40%);">+             return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   case BSSMAP_LE_LOC_INFO_ASSIST_TARGET_MS:</span><br><span style="color: hsl(120, 100%, 40%);">+     case BSSMAP_LE_LOC_INFO_BC_DECIPHER_KEYS:</span><br><span style="color: hsl(120, 100%, 40%);">+             if (len != 2)</span><br><span style="color: hsl(120, 100%, 40%);">+                 DEC_ERR(-EINVAL, msgt, iei, LCS_CAUSE_UNSPECIFIED,</span><br><span style="color: hsl(120, 100%, 40%);">+                            "location info type %d: length should be 2 bytes, got %u",</span><br><span style="color: hsl(120, 100%, 40%);">+                          lt->location_information, len);</span><br><span style="color: hsl(120, 100%, 40%);">+            lt->positioning_method = elem[1];</span><br><span style="color: hsl(120, 100%, 40%);">+          switch (lt->positioning_method) {</span><br><span style="color: hsl(120, 100%, 40%);">+          case BSSMAP_LE_POS_METHOD_MOBILE_ASSISTED_E_OTD:</span><br><span style="color: hsl(120, 100%, 40%);">+              case BSSMAP_LE_POS_METHOD_MOBILE_BASED_E_OTD:</span><br><span style="color: hsl(120, 100%, 40%);">+         case BSSMAP_LE_POS_METHOD_ASSISTED_GPS:</span><br><span style="color: hsl(120, 100%, 40%);">+                       return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+             default:</span><br><span style="color: hsl(120, 100%, 40%);">+                      DEC_ERR(-EINVAL, msgt, iei, LCS_CAUSE_UNSPECIFIED,</span><br><span style="color: hsl(120, 100%, 40%);">+                            "location info type %d: unknown Positioning Method: %d",</span><br><span style="color: hsl(120, 100%, 40%);">+                            lt->location_information, lt->positioning_method);</span><br><span style="color: hsl(120, 100%, 40%);">+              }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   default:</span><br><span style="color: hsl(120, 100%, 40%);">+              DEC_ERR(-EINVAL, msgt, iei, LCS_CAUSE_UNSPECIFIED, "unknown location info type %d",</span><br><span style="color: hsl(120, 100%, 40%);">+                 lt->location_information);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! Encode full BSSMAP-LE LCS Client Type IE, including IEI tag and length.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[inout] msg  Message buffer to append to.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[in] client_type  Value to enconde.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \returns length of bytes written to the msgb.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+static uint8_t osmo_bssmap_le_ie_enc_lcs_client_type(struct msgb *msg, enum bssmap_le_lcs_client_type client_type)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   OSMO_ASSERT(msg);</span><br><span style="color: hsl(120, 100%, 40%);">+     msgb_put_u8(msg, BSSMAP_LE_IEI_LCS_CLIENT_TYPE);</span><br><span style="color: hsl(120, 100%, 40%);">+      /* length */</span><br><span style="color: hsl(120, 100%, 40%);">+  msgb_put_u8(msg, 1);</span><br><span style="color: hsl(120, 100%, 40%);">+  msgb_put_u8(msg, client_type);</span><br><span style="color: hsl(120, 100%, 40%);">+        return 3;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int osmo_bssmap_le_ie_dec_lcs_client_type(enum bssmap_le_lcs_client_type *client_type,</span><br><span style="color: hsl(120, 100%, 40%);">+                                          enum bssmap_le_msgt msgt, enum bssmap_le_iei iei,</span><br><span style="color: hsl(120, 100%, 40%);">+                                             struct osmo_bssmap_le_err **err, void *err_ctx,</span><br><span style="color: hsl(120, 100%, 40%);">+                                               const uint8_t *elem, uint8_t len)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ *client_type = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!elem || len < 1)</span><br><span style="color: hsl(120, 100%, 40%);">+              DEC_ERR(-EINVAL, msgt, iei, LCS_CAUSE_UNSPECIFIED, "zero length");</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        *client_type = elem[0];</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     switch (*client_type) {</span><br><span style="color: hsl(120, 100%, 40%);">+       case BSSMAP_LE_LCS_CTYPE_VALUE_ADDED_UNSPECIFIED:</span><br><span style="color: hsl(120, 100%, 40%);">+     case BSSMAP_LE_LCS_CTYPE_PLMN_OPER_UNSPECIFIED:</span><br><span style="color: hsl(120, 100%, 40%);">+       case BSSMAP_LE_LCS_CTYPE_PLMN_OPER_BCAST_SERVICE:</span><br><span style="color: hsl(120, 100%, 40%);">+     case BSSMAP_LE_LCS_CTYPE_PLMN_OPER_OAM:</span><br><span style="color: hsl(120, 100%, 40%);">+       case BSSMAP_LE_LCS_CTYPE_PLMN_OPER_ANON_STATS:</span><br><span style="color: hsl(120, 100%, 40%);">+        case BSSMAP_LE_LCS_CTYPE_PLMN_OPER_TGT_MS_SVC:</span><br><span style="color: hsl(120, 100%, 40%);">+        case BSSMAP_LE_LCS_CTYPE_EMERG_SVC_UNSPECIFIED:</span><br><span style="color: hsl(120, 100%, 40%);">+       case BSSMAP_LE_LCS_CTYPE_LI_UNSPECIFIED:</span><br><span style="color: hsl(120, 100%, 40%);">+              return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+     default:</span><br><span style="color: hsl(120, 100%, 40%);">+              DEC_ERR(-EINVAL, msgt, iei, LCS_CAUSE_UNSPECIFIED, "unknown LCS Client Type: %d", *client_type);</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! Encode the value part of 3GPP TS 49.031 10.13 LCS Cause, without IEI and len.</span><br><span style="color: hsl(120, 100%, 40%);">+ * Identically used in 3GPP TS 48.008 3.2.2.66. Usage example:</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ *  uint8_t *l = msgb_tl_put(msg, BSSMAP_LE_IEI_LCS_CAUSE);</span><br><span style="color: hsl(120, 100%, 40%);">+ *  int rc = osmo_lcs_cause_enc(msg, &lcs_cause);</span><br><span style="color: hsl(120, 100%, 40%);">+ *  if (rc < 0)</span><br><span style="color: hsl(120, 100%, 40%);">+ *      goto error;</span><br><span style="color: hsl(120, 100%, 40%);">+ *  *l = rc;</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[inout] msg  Message buffer to append the LCS Cause values to.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[in] lcs_cause  LCS Cause values to enconde.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \returns length of bytes written to the msgb.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+int osmo_lcs_cause_enc(struct msgb *msg, const struct lcs_cause_ie *lcs_cause)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        msgb_put_u8(msg, lcs_cause->cause_val);</span><br><span style="color: hsl(120, 100%, 40%);">+    if (lcs_cause->cause_val == LCS_CAUSE_POS_METH_FAILURE && lcs_cause->diag_val_present) {</span><br><span style="color: hsl(120, 100%, 40%);">+                msgb_put_u8(msg, lcs_cause->diag_val);</span><br><span style="color: hsl(120, 100%, 40%);">+             return 2;</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+     return 1;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! Decode the value part of 3GPP TS 49.031 10.13 LCS Cause, without IEI and len.</span><br><span style="color: hsl(120, 100%, 40%);">+ * Identically used in 3GPP TS 48.008 3.2.2.66.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[out] lcs_cause  Write decoded LCS Cause values here.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[in] data  Encoded cause bytes.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[in] len  Length of data in bytes.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \returns 0 on success, negative on error.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+int osmo_lcs_cause_dec(struct lcs_cause_ie *lcs_cause,</span><br><span style="color: hsl(120, 100%, 40%);">+                     enum bssmap_le_msgt msgt, enum bssmap_le_iei iei,</span><br><span style="color: hsl(120, 100%, 40%);">+                     struct osmo_bssmap_le_err **err, void *err_ctx,</span><br><span style="color: hsl(120, 100%, 40%);">+                       const uint8_t *data, uint8_t len)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   *lcs_cause = (struct lcs_cause_ie){};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       if (!data || len < 1)</span><br><span style="color: hsl(120, 100%, 40%);">+              DEC_ERR(-EINVAL, msgt, iei, LCS_CAUSE_UNSPECIFIED, "zero length");</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        lcs_cause->present = true;</span><br><span style="color: hsl(120, 100%, 40%);">+ lcs_cause->cause_val = data[0];</span><br><span style="color: hsl(120, 100%, 40%);">+    if (len > 1) {</span><br><span style="color: hsl(120, 100%, 40%);">+             lcs_cause->diag_val_present = true;</span><br><span style="color: hsl(120, 100%, 40%);">+                lcs_cause->diag_val = data[1];</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+     if (len > 2)</span><br><span style="color: hsl(120, 100%, 40%);">+               DEC_ERR(-EINVAL, msgt, iei, LCS_CAUSE_UNSPECIFIED, "expected length <= 2, got %u", len);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int osmo_bssmap_le_ie_enc_apdu(struct msgb *msg, const struct bsslap_pdu *bsslap)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   uint8_t *old_tail;</span><br><span style="color: hsl(120, 100%, 40%);">+    void *l;</span><br><span style="color: hsl(120, 100%, 40%);">+      msgb_put_u8(msg, BSSMAP_LE_IEI_APDU);</span><br><span style="color: hsl(120, 100%, 40%);">+ l = msgb_put(msg, 2);</span><br><span style="color: hsl(120, 100%, 40%);">+ old_tail = msg->tail;</span><br><span style="color: hsl(120, 100%, 40%);">+      msgb_put_u8(msg, BSSMAP_LE_APDU_PROT_BSSLAP);</span><br><span style="color: hsl(120, 100%, 40%);">+ int rc = osmo_bsslap_enc(msg, bsslap);</span><br><span style="color: hsl(120, 100%, 40%);">+        if (rc <= 0)</span><br><span style="color: hsl(120, 100%, 40%);">+               return -EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+       osmo_store16be(msg->tail - old_tail, l);</span><br><span style="color: hsl(120, 100%, 40%);">+   return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int osmo_bssmap_le_ie_dec_apdu(struct bsslap_pdu *bsslap,</span><br><span style="color: hsl(120, 100%, 40%);">+                                    enum bssmap_le_msgt msgt, enum bssmap_le_iei iei,</span><br><span style="color: hsl(120, 100%, 40%);">+                                     struct osmo_bssmap_le_err **err, void *err_ctx,</span><br><span style="color: hsl(120, 100%, 40%);">+                               const uint8_t *data, size_t len)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     enum bssmap_le_apdu_proto proto;</span><br><span style="color: hsl(120, 100%, 40%);">+      struct osmo_bsslap_err *bsslap_err;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!data || len < 1)</span><br><span style="color: hsl(120, 100%, 40%);">+              DEC_ERR(-EINVAL, msgt, iei, LCS_CAUSE_UNSPECIFIED, "zero length");</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        proto = data[0];</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    switch (proto) {</span><br><span style="color: hsl(120, 100%, 40%);">+      case BSSMAP_LE_APDU_PROT_BSSLAP:</span><br><span style="color: hsl(120, 100%, 40%);">+              if (osmo_bsslap_dec(bsslap, &bsslap_err, err_ctx, data + 1, len - 1)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                   DEC_ERR_NO_RETURN(bsslap_err ? bsslap_err->rc : -EINVAL,</span><br><span style="color: hsl(120, 100%, 40%);">+                                     msgt, iei, LCS_CAUSE_UNSPECIFIED,</span><br><span style="color: hsl(120, 100%, 40%);">+                                     "Error decoding BSSLAP%s%s",</span><br><span style="color: hsl(120, 100%, 40%);">+                                        bsslap_err && bsslap_err->logmsg ? ": " : "",</span><br><span style="color: hsl(120, 100%, 40%);">+                                          bsslap_err && bsslap_err->logmsg ? bsslap_err->logmsg : "");</span><br><span style="color: hsl(120, 100%, 40%);">+                        (*err)->bsslap_err = bsslap_err;</span><br><span style="color: hsl(120, 100%, 40%);">+                   return (*err)->rc;</span><br><span style="color: hsl(120, 100%, 40%);">+         }</span><br><span style="color: hsl(120, 100%, 40%);">+             return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+     case BSSMAP_LE_APDU_PROT_LLP:</span><br><span style="color: hsl(120, 100%, 40%);">+ case BSSMAP_LE_APDU_PROT_SMLCPP:</span><br><span style="color: hsl(120, 100%, 40%);">+              DEC_ERR(-EINVAL, msgt, iei, LCS_CAUSE_UNSPECIFIED, "Unimplemented APDU type: %d", proto);</span><br><span style="color: hsl(120, 100%, 40%);">+   default:</span><br><span style="color: hsl(120, 100%, 40%);">+              DEC_ERR(-EINVAL, msgt, iei, LCS_CAUSE_UNSPECIFIED, "Invalid APDU type: %d", proto);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int osmo_bssmap_le_ie_dec_cell_id(struct gsm0808_cell_id *cell_id,</span><br><span style="color: hsl(120, 100%, 40%);">+                                      enum bssmap_le_msgt msgt, enum bssmap_le_iei iei,</span><br><span style="color: hsl(120, 100%, 40%);">+                                     struct osmo_bssmap_le_err **err, void *err_ctx,</span><br><span style="color: hsl(120, 100%, 40%);">+                                       const uint8_t *elem, uint8_t len)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+       rc = gsm0808_dec_cell_id(cell_id, elem, len);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (rc <= 0)</span><br><span style="color: hsl(120, 100%, 40%);">+               DEC_ERR(rc, msgt, iei, LCS_CAUSE_UNSPECIFIED, "Error decoding Cell Identifier %s",</span><br><span style="color: hsl(120, 100%, 40%);">+                  osmo_hexdump_c(err_ctx, elem, len));</span><br><span style="color: hsl(120, 100%, 40%);">+  return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int osmo_bssmap_le_ie_dec_imsi(struct osmo_mobile_identity *imsi,</span><br><span style="color: hsl(120, 100%, 40%);">+                                    enum bssmap_le_msgt msgt, enum bssmap_le_iei iei,</span><br><span style="color: hsl(120, 100%, 40%);">+                                     struct osmo_bssmap_le_err **err, void *err_ctx,</span><br><span style="color: hsl(120, 100%, 40%);">+                               const uint8_t *elem, uint8_t len)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+       rc = osmo_mobile_identity_decode(imsi, elem, len, false);</span><br><span style="color: hsl(120, 100%, 40%);">+     if (rc || imsi->type != GSM_MI_TYPE_IMSI)</span><br><span style="color: hsl(120, 100%, 40%);">+          DEC_ERR(-EINVAL, msgt, iei, LCS_CAUSE_UNSPECIFIED,</span><br><span style="color: hsl(120, 100%, 40%);">+                    "cannot parse IMSI identity %s", osmo_hexdump_c(err_ctx, elem, len));</span><br><span style="color: hsl(120, 100%, 40%);">+       return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int osmo_bssmap_le_ie_dec_imei(struct osmo_mobile_identity *imei,</span><br><span style="color: hsl(120, 100%, 40%);">+                                    enum bssmap_le_msgt msgt, enum bssmap_le_iei iei,</span><br><span style="color: hsl(120, 100%, 40%);">+                                     struct osmo_bssmap_le_err **err, void *err_ctx,</span><br><span style="color: hsl(120, 100%, 40%);">+                               const uint8_t *elem, uint8_t len)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+       rc = osmo_mobile_identity_decode(imei, elem, len, false);</span><br><span style="color: hsl(120, 100%, 40%);">+     if (rc || imei->type != GSM_MI_TYPE_IMEI)</span><br><span style="color: hsl(120, 100%, 40%);">+          DEC_ERR(-EINVAL, msgt, iei, LCS_CAUSE_UNSPECIFIED,</span><br><span style="color: hsl(120, 100%, 40%);">+                    "cannot parse IMEI identity %s", osmo_hexdump_c(err_ctx, elem, len));</span><br><span style="color: hsl(120, 100%, 40%);">+       return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int osmo_bssmap_le_ie_dec_gad(union gad_raw *gad,</span><br><span style="color: hsl(120, 100%, 40%);">+                                   enum bssmap_le_msgt msgt, enum bssmap_le_iei iei,</span><br><span style="color: hsl(120, 100%, 40%);">+                                     struct osmo_bssmap_le_err **err, void *err_ctx,</span><br><span style="color: hsl(120, 100%, 40%);">+                               const uint8_t *elem, uint8_t len)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     struct osmo_gad_err *gad_err;</span><br><span style="color: hsl(120, 100%, 40%);">+ if (osmo_gad_raw_read(gad, &gad_err, err_ctx, elem, len)) {</span><br><span style="color: hsl(120, 100%, 40%);">+               DEC_ERR_NO_RETURN(gad_err ? gad_err->rc : -EINVAL,</span><br><span style="color: hsl(120, 100%, 40%);">+                           msgt, BSSMAP_LE_IEI_GEO_LOCATION, LCS_CAUSE_UNSPECIFIED,</span><br><span style="color: hsl(120, 100%, 40%);">+                              "Error decoding GAD%s%s",</span><br><span style="color: hsl(120, 100%, 40%);">+                           gad_err && gad_err->logmsg ? ": " : "",</span><br><span style="color: hsl(120, 100%, 40%);">+                                gad_err && gad_err->logmsg ? gad_err->logmsg : "");</span><br><span style="color: hsl(120, 100%, 40%);">+         (*err)->gad_err = gad_err;</span><br><span style="color: hsl(120, 100%, 40%);">+         return (*err)->rc;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+     return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct osmo_bssap_le_header {</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t type;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t length;</span><br><span style="color: hsl(120, 100%, 40%);">+       uint8_t data[0];</span><br><span style="color: hsl(120, 100%, 40%);">+} __attribute__((packed));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! Return the BSSMAP-LE msg_type from a BSSAP-LE PDU, e.g. from a msgb_l3().</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[in] data  BSSAP-LE PDU data, starting with BSSAP-LE discriminator.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[in] len  Length of data in bytes.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \returns bssmap_le_msgt or negative on error or non-BSSMAP-LE discriminator. */</span><br><span style="color: hsl(120, 100%, 40%);">+enum bssmap_le_msgt osmo_bssmap_le_msgt(const uint8_t *data, uint8_t len)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    const struct osmo_bssap_le_header *h = (void*)data;</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!data || len < sizeof(struct osmo_bssap_le_header) + 1)</span><br><span style="color: hsl(120, 100%, 40%);">+                return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+    if (h->type != BSSAP_LE_MSG_DISCR_BSSMAP_LE)</span><br><span style="color: hsl(120, 100%, 40%);">+               return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+    return h->data[0];</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int osmo_bssmap_le_enc_reset(struct msgb *msg, enum gsm0808_cause cause)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        /* The BSSMAP-LE Reset Cause is defined as identical to the 3GPP TS 48.008 Cause. */</span><br><span style="color: hsl(120, 100%, 40%);">+  gsm0808_enc_cause(msg, cause);</span><br><span style="color: hsl(120, 100%, 40%);">+        return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int osmo_bssmap_le_dec_reset(enum gsm0808_cause *cause,</span><br><span style="color: hsl(120, 100%, 40%);">+                                    enum bssmap_le_msgt msgt,</span><br><span style="color: hsl(120, 100%, 40%);">+                             struct osmo_bssmap_le_err **err, void *err_ctx,</span><br><span style="color: hsl(120, 100%, 40%);">+                               const struct tlv_parsed *tp)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   const struct tlv_p_entry *e;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        if (!(e = TLVP_GET(tp, BSSMAP_LE_IEI_CAUSE)))</span><br><span style="color: hsl(120, 100%, 40%);">+         DEC_ERR(-EINVAL, msgt, BSSMAP_LE_IEI_CAUSE, LCS_CAUSE_DATA_MISSING_IN_REQ, "missing mandatory IE");</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       *cause = gsm0808_get_cause(tp);</span><br><span style="color: hsl(120, 100%, 40%);">+       if (*cause < 0)</span><br><span style="color: hsl(120, 100%, 40%);">+            DEC_ERR(-EINVAL, msgt, BSSMAP_LE_IEI_CAUSE, LCS_CAUSE_UNSPECIFIED, "cannot parse IE");</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int osmo_bssmap_le_enc_perform_loc_req(struct msgb *msg, const struct bssmap_le_perform_loc_req *params)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    osmo_bssmap_le_ie_enc_location_type(msg, &params->location_type);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    gsm0808_enc_cell_id(msg, &params->cell_id);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  if (params->lcs_client_type_present)</span><br><span style="color: hsl(120, 100%, 40%);">+               osmo_bssmap_le_ie_enc_lcs_client_type(msg, params->lcs_client_type);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     if (params->apdu_present) {</span><br><span style="color: hsl(120, 100%, 40%);">+                int rc = osmo_bssmap_le_ie_enc_apdu(msg, &params->apdu);</span><br><span style="color: hsl(120, 100%, 40%);">+               if (rc < 0)</span><br><span style="color: hsl(120, 100%, 40%);">+                        return rc;</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (params->imsi.type == GSM_MI_TYPE_IMSI) {</span><br><span style="color: hsl(120, 100%, 40%);">+               uint8_t *l = msgb_tl_put(msg, BSSMAP_LE_IEI_IMSI);</span><br><span style="color: hsl(120, 100%, 40%);">+            int rc = osmo_mobile_identity_encode_msgb(msg, &params->imsi, false);</span><br><span style="color: hsl(120, 100%, 40%);">+          if (rc < 0)</span><br><span style="color: hsl(120, 100%, 40%);">+                        return rc;</span><br><span style="color: hsl(120, 100%, 40%);">+            *l = rc;</span><br><span style="color: hsl(120, 100%, 40%);">+      }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (params->imei.type == GSM_MI_TYPE_IMEI) {</span><br><span style="color: hsl(120, 100%, 40%);">+               uint8_t *l = msgb_tl_put(msg, BSSMAP_LE_IEI_IMEI);</span><br><span style="color: hsl(120, 100%, 40%);">+            int rc = osmo_mobile_identity_encode_msgb(msg, &params->imei, false);</span><br><span style="color: hsl(120, 100%, 40%);">+          if (rc < 0)</span><br><span style="color: hsl(120, 100%, 40%);">+                        return rc;</span><br><span style="color: hsl(120, 100%, 40%);">+            *l = rc;</span><br><span style="color: hsl(120, 100%, 40%);">+      }</span><br><span style="color: hsl(120, 100%, 40%);">+     return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int osmo_bssmap_le_dec_perform_loc_req(struct bssmap_le_perform_loc_req *params,</span><br><span style="color: hsl(120, 100%, 40%);">+                                             enum bssmap_le_msgt msgt,</span><br><span style="color: hsl(120, 100%, 40%);">+                                             struct osmo_bssmap_le_err **err, void *err_ctx,</span><br><span style="color: hsl(120, 100%, 40%);">+                                       const struct tlv_parsed *tp)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ *params = (struct bssmap_le_perform_loc_req){};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     DEC_IE_MANDATORY(msgt, BSSMAP_LE_IEI_LOCATION_TYPE, osmo_bssmap_le_ie_dec_location_type,</span><br><span style="color: hsl(120, 100%, 40%);">+                       &params->location_type);</span><br><span style="color: hsl(120, 100%, 40%);">+      DEC_IE_MANDATORY(msgt, BSSMAP_LE_IEI_CELL_ID, osmo_bssmap_le_ie_dec_cell_id,</span><br><span style="color: hsl(120, 100%, 40%);">+                   &params->cell_id);</span><br><span style="color: hsl(120, 100%, 40%);">+    DEC_IE_OPTIONAL_FLAG(msgt, BSSMAP_LE_IEI_LCS_CLIENT_TYPE, osmo_bssmap_le_ie_dec_lcs_client_type,</span><br><span style="color: hsl(120, 100%, 40%);">+                      &params->lcs_client_type, params->lcs_client_type_present);</span><br><span style="color: hsl(120, 100%, 40%);">+ DEC_IE_OPTIONAL_FLAG(msgt, BSSMAP_LE_IEI_APDU, osmo_bssmap_le_ie_dec_apdu, &params->apdu,</span><br><span style="color: hsl(120, 100%, 40%);">+                      params->apdu_present);</span><br><span style="color: hsl(120, 100%, 40%);">+     DEC_IE_OPTIONAL(msgt, BSSMAP_LE_IEI_IMSI, osmo_bssmap_le_ie_dec_imsi, &params->imsi);</span><br><span style="color: hsl(120, 100%, 40%);">+  DEC_IE_OPTIONAL(msgt, BSSMAP_LE_IEI_IMEI, osmo_bssmap_le_ie_dec_imei, &params->imei);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int osmo_bssmap_le_enc_perform_loc_resp(struct msgb *msg, const struct bssmap_le_perform_loc_resp *params)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  if (params->location_estimate_present) {</span><br><span style="color: hsl(120, 100%, 40%);">+           uint8_t *l = msgb_tl_put(msg, BSSMAP_LE_IEI_GEO_LOCATION);</span><br><span style="color: hsl(120, 100%, 40%);">+            int rc = osmo_gad_raw_write(msg, &params->location_estimate);</span><br><span style="color: hsl(120, 100%, 40%);">+          if (rc < 0)</span><br><span style="color: hsl(120, 100%, 40%);">+                        return rc;</span><br><span style="color: hsl(120, 100%, 40%);">+            *l = rc;</span><br><span style="color: hsl(120, 100%, 40%);">+      }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (params->lcs_cause.present) {</span><br><span style="color: hsl(120, 100%, 40%);">+           uint8_t *l = msgb_tl_put(msg, BSSMAP_LE_IEI_LCS_CAUSE);</span><br><span style="color: hsl(120, 100%, 40%);">+               int rc = osmo_lcs_cause_enc(msg, &params->lcs_cause);</span><br><span style="color: hsl(120, 100%, 40%);">+          if (rc < 0)</span><br><span style="color: hsl(120, 100%, 40%);">+                        return rc;</span><br><span style="color: hsl(120, 100%, 40%);">+            *l = rc;</span><br><span style="color: hsl(120, 100%, 40%);">+      }</span><br><span style="color: hsl(120, 100%, 40%);">+     return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int osmo_bssmap_le_dec_perform_loc_resp(struct bssmap_le_perform_loc_resp *params,</span><br><span style="color: hsl(120, 100%, 40%);">+                                            enum bssmap_le_msgt msgt,</span><br><span style="color: hsl(120, 100%, 40%);">+                                             struct osmo_bssmap_le_err **err, void *err_ctx,</span><br><span style="color: hsl(120, 100%, 40%);">+                                               const struct tlv_parsed *tp)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        *params = (struct bssmap_le_perform_loc_resp){};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    DEC_IE_OPTIONAL_FLAG(msgt, BSSMAP_LE_IEI_GEO_LOCATION, osmo_bssmap_le_ie_dec_gad, &params->location_estimate,</span><br><span style="color: hsl(120, 100%, 40%);">+                       params->location_estimate_present);</span><br><span style="color: hsl(120, 100%, 40%);">+   DEC_IE_OPTIONAL(msgt, BSSMAP_LE_IEI_LCS_CAUSE, osmo_lcs_cause_dec, &params->lcs_cause);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int osmo_bssmap_le_enc_perform_loc_abort(struct msgb *msg, const struct lcs_cause_ie *params)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       uint8_t *l = msgb_tl_put(msg, BSSMAP_LE_IEI_LCS_CAUSE);</span><br><span style="color: hsl(120, 100%, 40%);">+       int rc = osmo_lcs_cause_enc(msg, params);</span><br><span style="color: hsl(120, 100%, 40%);">+     if (rc < 0)</span><br><span style="color: hsl(120, 100%, 40%);">+                return rc;</span><br><span style="color: hsl(120, 100%, 40%);">+    *l = rc;</span><br><span style="color: hsl(120, 100%, 40%);">+      return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int osmo_bssmap_le_dec_perform_loc_abort(struct lcs_cause_ie *params,</span><br><span style="color: hsl(120, 100%, 40%);">+                                          enum bssmap_le_msgt msgt,</span><br><span style="color: hsl(120, 100%, 40%);">+                                             struct osmo_bssmap_le_err **err, void *err_ctx,</span><br><span style="color: hsl(120, 100%, 40%);">+                                               const struct tlv_parsed *tp)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       *params = (struct lcs_cause_ie){};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  DEC_IE_MANDATORY(msgt, BSSMAP_LE_IEI_LCS_CAUSE, osmo_lcs_cause_dec, params);</span><br><span style="color: hsl(120, 100%, 40%);">+  return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int osmo_bssmap_le_enc_conn_oriented_info(struct msgb *msg,</span><br><span style="color: hsl(120, 100%, 40%);">+                                             const struct bssmap_le_conn_oriented_info *params)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        return osmo_bssmap_le_ie_enc_apdu(msg, &params->apdu);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int osmo_bssmap_le_dec_conn_oriented_info(struct bssmap_le_conn_oriented_info *params,</span><br><span style="color: hsl(120, 100%, 40%);">+                                              enum bssmap_le_msgt msgt,</span><br><span style="color: hsl(120, 100%, 40%);">+                                             struct osmo_bssmap_le_err **err, void *err_ctx,</span><br><span style="color: hsl(120, 100%, 40%);">+                                               const struct tlv_parsed *tp)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      *params = (struct bssmap_le_conn_oriented_info){};</span><br><span style="color: hsl(120, 100%, 40%);">+    DEC_IE_MANDATORY(msgt, BSSMAP_LE_IEI_APDU, osmo_bssmap_le_ie_dec_apdu, &params->apdu);</span><br><span style="color: hsl(120, 100%, 40%);">+ return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! Encode BSSMAP-LE PDU and add to msgb (3GPP TS 49.031).</span><br><span style="color: hsl(120, 100%, 40%);">+ * See also osmo_bssap_le_enc().</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[out] msg  msgb to append to.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[in] pdu  PDU data to encode.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \return number of bytes written, negative on error.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+static int osmo_bssmap_le_enc(struct msgb *msg, const struct bssmap_le_pdu *pdu)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+       uint8_t *old_tail;</span><br><span style="color: hsl(120, 100%, 40%);">+    old_tail = msg->tail;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    msgb_v_put(msg, pdu->msg_type);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  switch (pdu->msg_type) {</span><br><span style="color: hsl(120, 100%, 40%);">+   case BSSMAP_LE_MSGT_RESET:</span><br><span style="color: hsl(120, 100%, 40%);">+            rc = osmo_bssmap_le_enc_reset(msg, pdu->reset);</span><br><span style="color: hsl(120, 100%, 40%);">+            break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case BSSMAP_LE_MSGT_RESET_ACK:</span><br><span style="color: hsl(120, 100%, 40%);">+                /* Consists only of the message type. */</span><br><span style="color: hsl(120, 100%, 40%);">+              rc = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+               break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case BSSMAP_LE_MSGT_PERFORM_LOC_REQ:</span><br><span style="color: hsl(120, 100%, 40%);">+          rc = osmo_bssmap_le_enc_perform_loc_req(msg, &pdu->perform_loc_req);</span><br><span style="color: hsl(120, 100%, 40%);">+           break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case BSSMAP_LE_MSGT_PERFORM_LOC_RESP:</span><br><span style="color: hsl(120, 100%, 40%);">+         rc = osmo_bssmap_le_enc_perform_loc_resp(msg, &pdu->perform_loc_resp);</span><br><span style="color: hsl(120, 100%, 40%);">+         break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case BSSMAP_LE_MSGT_PERFORM_LOC_ABORT:</span><br><span style="color: hsl(120, 100%, 40%);">+                rc = osmo_bssmap_le_enc_perform_loc_abort(msg, &pdu->perform_loc_abort);</span><br><span style="color: hsl(120, 100%, 40%);">+               break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case BSSMAP_LE_MSGT_CONN_ORIENTED_INFO:</span><br><span style="color: hsl(120, 100%, 40%);">+               rc = osmo_bssmap_le_enc_conn_oriented_info(msg, &pdu->conn_oriented_info);</span><br><span style="color: hsl(120, 100%, 40%);">+             break;</span><br><span style="color: hsl(120, 100%, 40%);">+        default:</span><br><span style="color: hsl(120, 100%, 40%);">+              rc = -ENOTSUP;</span><br><span style="color: hsl(120, 100%, 40%);">+        }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (rc < 0)</span><br><span style="color: hsl(120, 100%, 40%);">+                return rc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  return (msg->tail - old_tail);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! Decode BSSMAP-LE PDU (3GPP TS 49.031).</span><br><span style="color: hsl(120, 100%, 40%);">+ * See also osmo_bssap_le_dec().</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[out] pdu  Write decoded values here.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[in] data  Pointer to BSSMAP-LE PDU raw data.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[in] len  Data length to decode.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \return NULL upon success, a human readable error message on failure.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+static int osmo_bssmap_le_dec(struct bssmap_le_pdu *pdu,</span><br><span style="color: hsl(120, 100%, 40%);">+                            struct osmo_bssmap_le_err **err, void *err_ctx,</span><br><span style="color: hsl(120, 100%, 40%);">+                       const uint8_t *data, size_t len)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     const uint8_t *ies_start;</span><br><span style="color: hsl(120, 100%, 40%);">+     int ies_len;</span><br><span style="color: hsl(120, 100%, 40%);">+  struct tlv_parsed tp;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       *pdu = (struct bssmap_le_pdu){};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    if (len < 1)</span><br><span style="color: hsl(120, 100%, 40%);">+               DEC_ERR(-EINVAL, -1, -1, LCS_CAUSE_UNSPECIFIED, "zero length");</span><br><span style="color: hsl(120, 100%, 40%);">+     pdu->msg_type = data[0];</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* BSSMAP-LE IEs */</span><br><span style="color: hsl(120, 100%, 40%);">+   ies_start = &data[1];</span><br><span style="color: hsl(120, 100%, 40%);">+     ies_len = len - 1;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  if (tlv_parse(&tp, &osmo_bssmap_le_tlvdef, ies_start, ies_len, 0, 0) < 0)</span><br><span style="color: hsl(120, 100%, 40%);">+          DEC_ERR(-EINVAL, pdu->msg_type, -1, LCS_CAUSE_UNSPECIFIED, "failed to parse TLV structure");</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   switch (pdu->msg_type) {</span><br><span style="color: hsl(120, 100%, 40%);">+   case BSSMAP_LE_MSGT_RESET:</span><br><span style="color: hsl(120, 100%, 40%);">+            return osmo_bssmap_le_dec_reset(&pdu->reset, pdu->msg_type, err, err_ctx, &tp);</span><br><span style="color: hsl(120, 100%, 40%);">+ case BSSMAP_LE_MSGT_RESET_ACK:</span><br><span style="color: hsl(120, 100%, 40%);">+                /* Consists only of the message type. */</span><br><span style="color: hsl(120, 100%, 40%);">+              return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+     case BSSMAP_LE_MSGT_PERFORM_LOC_REQ:</span><br><span style="color: hsl(120, 100%, 40%);">+          return osmo_bssmap_le_dec_perform_loc_req(&pdu->perform_loc_req, pdu->msg_type, err, err_ctx, &tp);</span><br><span style="color: hsl(120, 100%, 40%);">+     case BSSMAP_LE_MSGT_PERFORM_LOC_RESP:</span><br><span style="color: hsl(120, 100%, 40%);">+         return osmo_bssmap_le_dec_perform_loc_resp(&pdu->perform_loc_resp, pdu->msg_type, err, err_ctx, &tp);</span><br><span style="color: hsl(120, 100%, 40%);">+   case BSSMAP_LE_MSGT_PERFORM_LOC_ABORT:</span><br><span style="color: hsl(120, 100%, 40%);">+                return osmo_bssmap_le_dec_perform_loc_abort(&pdu->perform_loc_abort, pdu->msg_type, err, err_ctx, &tp);</span><br><span style="color: hsl(120, 100%, 40%);">+ case BSSMAP_LE_MSGT_CONN_ORIENTED_INFO:</span><br><span style="color: hsl(120, 100%, 40%);">+               return osmo_bssmap_le_dec_conn_oriented_info(&pdu->conn_oriented_info, pdu->msg_type, err, err_ctx,</span><br><span style="color: hsl(120, 100%, 40%);">+                                                      &tp);</span><br><span style="color: hsl(120, 100%, 40%);">+        default:</span><br><span style="color: hsl(120, 100%, 40%);">+              DEC_ERR(-EINVAL, pdu->msg_type, -1, LCS_CAUSE_UNSPECIFIED, "Unsupported BSSMAP-LE message type");</span><br><span style="color: hsl(120, 100%, 40%);">+        }</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! Encode BSSAP-LE PDU returned in new msgb (3GPP TS 49.031).</span><br><span style="color: hsl(120, 100%, 40%);">+ * By spec, BSSAP-LE contains either BSSMAP-LE or DTAP.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[in] pdu  PDU data to encode.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \return msgb with encoded data and l2h set to the start.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+struct msgb *osmo_bssap_le_enc(const struct bssap_le_pdu *pdu)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  struct msgb *msg;</span><br><span style="color: hsl(120, 100%, 40%);">+     int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     if (pdu->discr != BSSAP_LE_MSG_DISCR_BSSMAP_LE)</span><br><span style="color: hsl(120, 100%, 40%);">+            return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        msg = msgb_alloc_headroom(BSSAP_LE_MSG_SIZE, BSSAP_LE_MSG_HEADROOM,</span><br><span style="color: hsl(120, 100%, 40%);">+                             osmo_bssmap_le_msgt_name(pdu->bssmap_le.msg_type));</span><br><span style="color: hsl(120, 100%, 40%);">+      if (!msg)</span><br><span style="color: hsl(120, 100%, 40%);">+             return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        rc = osmo_bssmap_le_enc(msg, &pdu->bssmap_le);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (rc <= 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+             msgb_free(msg);</span><br><span style="color: hsl(120, 100%, 40%);">+               return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* prepend header with final length */</span><br><span style="color: hsl(120, 100%, 40%);">+        msg->l2h = msgb_tv_push(msg, pdu->discr, msgb_length(msg));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return msg;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! Decode BSSAP-LE PDU (3GPP TS 49.031).</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[out] pdu  Write decoded values here.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[in] data  Pointer to BSSMAP-LE PDU raw data.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[in] len  Data length to decode.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \return NULL upon success, a human readable error message on failure.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+int osmo_bssap_le_dec(struct bssap_le_pdu *pdu, struct osmo_bssap_le_err **err, void *err_ctx, struct msgb *msg)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    struct osmo_bssap_le_header *h;</span><br><span style="color: hsl(120, 100%, 40%);">+       unsigned int check_len;</span><br><span style="color: hsl(120, 100%, 40%);">+       struct osmo_bssmap_le_err *bssmap_le_err = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+      int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define BSSAP_LE_DEC_ERR(RC, fmt, args...) do { \</span><br><span style="color: hsl(120, 100%, 40%);">+          if (err && !*err) { \</span><br><span style="color: hsl(120, 100%, 40%);">+                 *err = talloc_zero(err_ctx, struct osmo_bssap_le_err); \</span><br><span style="color: hsl(120, 100%, 40%);">+                      **err = (struct osmo_bssap_le_err){ \</span><br><span style="color: hsl(120, 100%, 40%);">+                         .rc = (RC), \</span><br><span style="color: hsl(120, 100%, 40%);">+                         .logmsg = talloc_asprintf(*err, "Error decoding BSSAP-LE: " fmt, ##args), \</span><br><span style="color: hsl(120, 100%, 40%);">+                 }; \</span><br><span style="color: hsl(120, 100%, 40%);">+          } \</span><br><span style="color: hsl(120, 100%, 40%);">+           return RC; \</span><br><span style="color: hsl(120, 100%, 40%);">+  } while(0)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  *pdu = (struct bssap_le_pdu){};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     h = msgb_l2(msg);</span><br><span style="color: hsl(120, 100%, 40%);">+     if (!h)</span><br><span style="color: hsl(120, 100%, 40%);">+               BSSAP_LE_DEC_ERR(-EINVAL, "missing msgb_l2() pointer");</span><br><span style="color: hsl(120, 100%, 40%);">+     if (msgb_l2len(msg) < sizeof(*h))</span><br><span style="color: hsl(120, 100%, 40%);">+          BSSAP_LE_DEC_ERR(-EINVAL, "message too short for header");</span><br><span style="color: hsl(120, 100%, 40%);">+  check_len = msgb_l2len(msg) - sizeof(*h);</span><br><span style="color: hsl(120, 100%, 40%);">+     if (h->length < check_len)</span><br><span style="color: hsl(120, 100%, 40%);">+              BSSAP_LE_DEC_ERR(-EINVAL, "message truncated, header length (%u) longer than message (%u)",</span><br><span style="color: hsl(120, 100%, 40%);">+                          h->length, check_len);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  switch (h->type) {</span><br><span style="color: hsl(120, 100%, 40%);">+ case BSSAP_LE_MSG_DISCR_BSSMAP_LE:</span><br><span style="color: hsl(120, 100%, 40%);">+            break;</span><br><span style="color: hsl(120, 100%, 40%);">+        default:</span><br><span style="color: hsl(120, 100%, 40%);">+              BSSAP_LE_DEC_ERR(-EINVAL, "unsupported discr %u, only BSSMAP-LE is implemented", h->type);</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   rc = osmo_bssmap_le_dec(&pdu->bssmap_le, err ? &bssmap_le_err : NULL, err_ctx,</span><br><span style="color: hsl(120, 100%, 40%);">+                             h->data, h->length);</span><br><span style="color: hsl(120, 100%, 40%);">+    if (rc)</span><br><span style="color: hsl(120, 100%, 40%);">+               BSSAP_LE_DEC_ERR(rc, "%s",</span><br><span style="color: hsl(120, 100%, 40%);">+                           (bssmap_le_err && bssmap_le_err->logmsg) ?</span><br><span style="color: hsl(120, 100%, 40%);">+                                         bssmap_le_err->logmsg : "unknown error in BSSMAP-LE part");</span><br><span style="color: hsl(120, 100%, 40%);">+     return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+const struct value_string osmo_bssmap_le_msgt_names[] = {</span><br><span style="color: hsl(120, 100%, 40%);">+     { BSSMAP_LE_MSGT_PERFORM_LOC_REQ, "PERFORM LOCATION REQUEST" },</span><br><span style="color: hsl(120, 100%, 40%);">+     { BSSMAP_LE_MSGT_PERFORM_LOC_RESP, "PERFORM LOCATION RESPONSE" },</span><br><span style="color: hsl(120, 100%, 40%);">+   { BSSMAP_LE_MSGT_PERFORM_LOC_ABORT, "PERFORM LOCATION ABORT" },</span><br><span style="color: hsl(120, 100%, 40%);">+     { BSSMAP_LE_MSGT_PERFORM_LOC_INFO, "PERFORM LOCATION INFO" },</span><br><span style="color: hsl(120, 100%, 40%);">+       { BSSMAP_LE_MSGT_ASSIST_INFO_REQ, "ASSISTANCE INFORMATION REQUEST" },</span><br><span style="color: hsl(120, 100%, 40%);">+       { BSSMAP_LE_MSGT_ASSIST_INFO_RESP, "ASSISTANCE INFORMATION RESPONSE" },</span><br><span style="color: hsl(120, 100%, 40%);">+     { BSSMAP_LE_MSGT_CONN_ORIENTED_INFO, "CONNECTION ORIENTED INFORMATON" },</span><br><span style="color: hsl(120, 100%, 40%);">+    { BSSMAP_LE_MSGT_CONN_LESS_INFO, "CONNECTIONLESS INFORMATION" },</span><br><span style="color: hsl(120, 100%, 40%);">+    { BSSMAP_LE_MSGT_RESET, "RESET" },</span><br><span style="color: hsl(120, 100%, 40%);">+  { BSSMAP_LE_MSGT_RESET_ACK, "RESET ACKNOWLEDGE" },</span><br><span style="color: hsl(120, 100%, 40%);">+  {}</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+const struct value_string osmo_bssmap_le_iei_names[] = {</span><br><span style="color: hsl(120, 100%, 40%);">+    { BSSMAP_LE_IEI_LCS_QoS, "LCS_QoS" },</span><br><span style="color: hsl(120, 100%, 40%);">+       { BSSMAP_LE_IEI_LCS_PRIORITY, "LCS_PRIORITY" },</span><br><span style="color: hsl(120, 100%, 40%);">+     { BSSMAP_LE_IEI_LOCATION_TYPE, "LOCATION_TYPE" },</span><br><span style="color: hsl(120, 100%, 40%);">+   { BSSMAP_LE_IEI_GANSS_LOCATION_TYPE, "GANSS_LOCATION_TYPE" },</span><br><span style="color: hsl(120, 100%, 40%);">+       { BSSMAP_LE_IEI_GEO_LOCATION, "GEO_LOCATION" },</span><br><span style="color: hsl(120, 100%, 40%);">+     { BSSMAP_LE_IEI_POSITIONING_DATA, "POSITIONING_DATA" },</span><br><span style="color: hsl(120, 100%, 40%);">+     { BSSMAP_LE_IEI_GANSS_POS_DATA, "GANSS_POS_DATA" },</span><br><span style="color: hsl(120, 100%, 40%);">+ { BSSMAP_LE_IEI_VELOCITY_DATA, "VELOCITY_DATA" },</span><br><span style="color: hsl(120, 100%, 40%);">+   { BSSMAP_LE_IEI_LCS_CAUSE, "LCS_CAUSE" },</span><br><span style="color: hsl(120, 100%, 40%);">+   { BSSMAP_LE_IEI_LCS_CLIENT_TYPE, "LCS_CLIENT_TYPE" },</span><br><span style="color: hsl(120, 100%, 40%);">+       { BSSMAP_LE_IEI_APDU, "APDU" },</span><br><span style="color: hsl(120, 100%, 40%);">+     { BSSMAP_LE_IEI_NET_ELEM_ID, "NET_ELEM_ID" },</span><br><span style="color: hsl(120, 100%, 40%);">+       { BSSMAP_LE_IEI_REQ_GPS_ASS_D, "REQ_GPS_ASS_D" },</span><br><span style="color: hsl(120, 100%, 40%);">+   { BSSMAP_LE_IEI_REQ_GANSS_ASS_D, "REQ_GANSS_ASS_D" },</span><br><span style="color: hsl(120, 100%, 40%);">+       { BSSMAP_LE_IEI_DECIPH_KEYS, "DECIPH_KEYS" },</span><br><span style="color: hsl(120, 100%, 40%);">+       { BSSMAP_LE_IEI_RET_ERR_REQ, "RET_ERR_REQ" },</span><br><span style="color: hsl(120, 100%, 40%);">+       { BSSMAP_LE_IEI_RET_ERR_CAUSE, "RET_ERR_CAUSE" },</span><br><span style="color: hsl(120, 100%, 40%);">+   { BSSMAP_LE_IEI_SEGMENTATION, "SEGMENTATION" },</span><br><span style="color: hsl(120, 100%, 40%);">+     { BSSMAP_LE_IEI_CLASSMARK3_INFO, "CLASSMARK3_INFO" },</span><br><span style="color: hsl(120, 100%, 40%);">+       { BSSMAP_LE_IEI_CAUSE, "CAUSE" },</span><br><span style="color: hsl(120, 100%, 40%);">+   { BSSMAP_LE_IEI_CELL_ID, "CELL_ID" },</span><br><span style="color: hsl(120, 100%, 40%);">+       { BSSMAP_LE_IEI_CHOSEN_CHAN, "CHOSEN_CHAN" },</span><br><span style="color: hsl(120, 100%, 40%);">+       { BSSMAP_LE_IEI_IMSI, "IMSI" },</span><br><span style="color: hsl(120, 100%, 40%);">+     { BSSMAP_LE_IEI_LCS_CAPABILITY, "LCS_CAPABILITY" },</span><br><span style="color: hsl(120, 100%, 40%);">+ { BSSMAP_LE_IEI_PKT_MEAS_REP, "PKT_MEAS_REP" },</span><br><span style="color: hsl(120, 100%, 40%);">+     { BSSMAP_LE_IEI_CELL_ID_LIST, "CELL_ID_LIST" },</span><br><span style="color: hsl(120, 100%, 40%);">+     { BSSMAP_LE_IEI_IMEI, "IMEI" },</span><br><span style="color: hsl(120, 100%, 40%);">+     { BSSMAP_LE_IEI_BSS_MLAT_CAP, "BSS_MLAT_CAP" },</span><br><span style="color: hsl(120, 100%, 40%);">+     { BSSMAP_LE_IEI_CELL_INFO_LIST, "CELL_INFO_LIST" },</span><br><span style="color: hsl(120, 100%, 40%);">+ { BSSMAP_LE_IEI_BTS_RX_ACC_LVL, "BTS_RX_ACC_LVL" },</span><br><span style="color: hsl(120, 100%, 40%);">+ { BSSMAP_LE_IEI_MLAT_METHOD, "MLAT_METHOD" },</span><br><span style="color: hsl(120, 100%, 40%);">+       { BSSMAP_LE_IEI_MLAT_TA, "MLAT_TA" },</span><br><span style="color: hsl(120, 100%, 40%);">+       { BSSMAP_LE_IEI_MS_SYNC_ACC, "MS_SYNC_ACC" },</span><br><span style="color: hsl(120, 100%, 40%);">+       { BSSMAP_LE_IEI_SHORT_ID_SET, "SHORT_ID_SET" },</span><br><span style="color: hsl(120, 100%, 40%);">+     { BSSMAP_LE_IEI_RANDOM_ID_SET, "RANDOM_ID_SET" },</span><br><span style="color: hsl(120, 100%, 40%);">+   { BSSMAP_LE_IEI_SHORT_BSS_ID, "SHORT_BSS_ID" },</span><br><span style="color: hsl(120, 100%, 40%);">+     { BSSMAP_LE_IEI_RANDOM_ID, "RANDOM_ID" },</span><br><span style="color: hsl(120, 100%, 40%);">+   { BSSMAP_LE_IEI_SHORT_ID, "SHORT_ID" },</span><br><span style="color: hsl(120, 100%, 40%);">+     { BSSMAP_LE_IEI_COVERAGE_CLASS, "COVERAGE_CLASS" },</span><br><span style="color: hsl(120, 100%, 40%);">+ { BSSMAP_LE_IEI_MTA_ACC_SEC_RQD, "MTA_ACC_SEC_RQD" },</span><br><span style="color: hsl(120, 100%, 40%);">+       {}</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! Return a human readable string describing a BSSAP-LE PDU.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[out] buf  String buffer to write to.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[in] buflen  sizeof(buf).</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[in] bssap_le  Decoded BSSAP-LE PDU data.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \returns number of chars that would be written, like snprintf().</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+int osmo_bssap_le_pdu_to_str_buf(char *buf, size_t buflen, const struct bssap_le_pdu *bssap_le)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_strbuf sb = { .buf = buf, .len = buflen };</span><br><span style="color: hsl(120, 100%, 40%);">+        const struct bssmap_le_pdu *bssmap_le;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      switch (bssap_le->discr) {</span><br><span style="color: hsl(120, 100%, 40%);">+ case BSSAP_LE_MSG_DISCR_BSSMAP_LE:</span><br><span style="color: hsl(120, 100%, 40%);">+            bssmap_le = &bssap_le->bssmap_le;</span><br><span style="color: hsl(120, 100%, 40%);">+              OSMO_STRBUF_PRINTF(sb, "BSSMAP-LE %s", osmo_bssmap_le_msgt_name(bssmap_le->msg_type));</span><br><span style="color: hsl(120, 100%, 40%);">+           switch (bssmap_le->msg_type) {</span><br><span style="color: hsl(120, 100%, 40%);">+             case BSSMAP_LE_MSGT_PERFORM_LOC_REQ:</span><br><span style="color: hsl(120, 100%, 40%);">+                  if (bssmap_le->perform_loc_req.apdu_present)</span><br><span style="color: hsl(120, 100%, 40%);">+                               OSMO_STRBUF_PRINTF(sb, " with BSSLAP %s",</span><br><span style="color: hsl(120, 100%, 40%);">+                                              osmo_bsslap_msgt_name(bssmap_le->perform_loc_req.apdu.msg_type));</span><br><span style="color: hsl(120, 100%, 40%);">+                       break;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+              case BSSMAP_LE_MSGT_CONN_ORIENTED_INFO:</span><br><span style="color: hsl(120, 100%, 40%);">+                       OSMO_STRBUF_PRINTF(sb, " with BSSLAP %s",</span><br><span style="color: hsl(120, 100%, 40%);">+                                      osmo_bsslap_msgt_name(bssmap_le->conn_oriented_info.apdu.msg_type));</span><br><span style="color: hsl(120, 100%, 40%);">+                    break;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+              default:</span><br><span style="color: hsl(120, 100%, 40%);">+                      break;</span><br><span style="color: hsl(120, 100%, 40%);">+                }</span><br><span style="color: hsl(120, 100%, 40%);">+             break;</span><br><span style="color: hsl(120, 100%, 40%);">+        default:</span><br><span style="color: hsl(120, 100%, 40%);">+              OSMO_STRBUF_PRINTF(sb, "BSSAP-LE discr %d not implemented", bssap_le->discr);</span><br><span style="color: hsl(120, 100%, 40%);">+            break;</span><br><span style="color: hsl(120, 100%, 40%);">+        }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return sb.chars_needed;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! Return a human readable string describing a BSSAP-LE PDU.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[in] ctx  Talloc context to allocate string buffer from.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[in] bssap_le  Decoded BSSAP-LE PDU data.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \returns string.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+char *osmo_bssap_le_pdu_to_str_c(void *ctx, const struct bssap_le_pdu *bssap_le)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     OSMO_NAME_C_IMPL(ctx, 32, "ERROR", osmo_bssap_le_pdu_to_str_buf, bssap_le)</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! @} */</span><br><span>diff --git a/src/gsm/libosmogsm.map b/src/gsm/libosmogsm.map</span><br><span>index 257c3fa..89d81b3 100644</span><br><span>--- a/src/gsm/libosmogsm.map</span><br><span>+++ b/src/gsm/libosmogsm.map</span><br><span>@@ -705,6 +705,17 @@</span><br><span> osmo_nri_ranges_to_str_buf;</span><br><span> osmo_nri_ranges_to_str_c;</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+osmo_bssmap_le_msgt_names;</span><br><span style="color: hsl(120, 100%, 40%);">+osmo_bssap_le_enc;</span><br><span style="color: hsl(120, 100%, 40%);">+osmo_bssap_le_dec;</span><br><span style="color: hsl(120, 100%, 40%);">+osmo_lcs_cause_enc;</span><br><span style="color: hsl(120, 100%, 40%);">+osmo_lcs_cause_dec;</span><br><span style="color: hsl(120, 100%, 40%);">+osmo_bssmap_le_ie_enc_location_type;</span><br><span style="color: hsl(120, 100%, 40%);">+osmo_bssmap_le_ie_dec_location_type;</span><br><span style="color: hsl(120, 100%, 40%);">+osmo_bssmap_le_msgt;</span><br><span style="color: hsl(120, 100%, 40%);">+osmo_bssap_le_pdu_to_str_buf;</span><br><span style="color: hsl(120, 100%, 40%);">+osmo_bssap_le_pdu_to_str_c;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> osmo_bsslap_enc;</span><br><span> osmo_bsslap_dec;</span><br><span> osmo_bsslap_msgt_names;</span><br><span>diff --git a/tests/Makefile.am b/tests/Makefile.am</span><br><span>index fc99485..152eb60 100644</span><br><span>--- a/tests/Makefile.am</span><br><span>+++ b/tests/Makefile.am</span><br><span>@@ -40,6 +40,7 @@</span><br><span>                bitgen/bitgen_test                                     \</span><br><span>             gad/gad_test                                           \</span><br><span>             bsslap/bsslap_test                                     \</span><br><span style="color: hsl(120, 100%, 40%);">+              bssmap_le/bssmap_le_test                               \</span><br><span>             $(NULL)</span><br><span> </span><br><span> if ENABLE_MSGFILE</span><br><span>@@ -289,6 +290,9 @@</span><br><span> bsslap_bsslap_test_SOURCES = bsslap/bsslap_test.c</span><br><span> bsslap_bsslap_test_LDADD = $(LDADD) $(top_builddir)/src/gsm/libosmogsm.la</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+bssmap_le_bssmap_le_test_SOURCES = bssmap_le/bssmap_le_test.c</span><br><span style="color: hsl(120, 100%, 40%);">+bssmap_le_bssmap_le_test_LDADD = $(LDADD) $(top_builddir)/src/gsm/libosmogsm.la</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> # The `:;' works around a Bash 3.2 bug when the output is not writeable.</span><br><span> $(srcdir)/package.m4: $(top_srcdir)/configure.ac</span><br><span>  :;{ \</span><br><span>@@ -371,6 +375,7 @@</span><br><span>       bitgen/bitgen_test.ok \</span><br><span>              gad/gad_test.ok \</span><br><span>            bsslap/bsslap_test.ok \</span><br><span style="color: hsl(120, 100%, 40%);">+       bssmap_le/bssmap_le_test.ok \</span><br><span>        $(NULL)</span><br><span> </span><br><span> if ENABLE_LIBSCTP</span><br><span>diff --git a/tests/bssmap_le/bssmap_le_test.c b/tests/bssmap_le/bssmap_le_test.c</span><br><span>new file mode 100644</span><br><span>index 0000000..59c7ed2</span><br><span>--- /dev/null</span><br><span>+++ b/tests/bssmap_le/bssmap_le_test.c</span><br><span>@@ -0,0 +1,177 @@</span><br><span style="color: hsl(120, 100%, 40%);">+#include <stdio.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/utils.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/gsm/bssmap_le.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct bssmap_le_pdu bssmap_le_test_pdus[] = {</span><br><span style="color: hsl(120, 100%, 40%);">+  {</span><br><span style="color: hsl(120, 100%, 40%);">+             .msg_type = BSSMAP_LE_MSGT_RESET,</span><br><span style="color: hsl(120, 100%, 40%);">+             .reset = GSM0808_CAUSE_EQUIPMENT_FAILURE,</span><br><span style="color: hsl(120, 100%, 40%);">+     },</span><br><span style="color: hsl(120, 100%, 40%);">+    {</span><br><span style="color: hsl(120, 100%, 40%);">+             .msg_type = BSSMAP_LE_MSGT_RESET_ACK,</span><br><span style="color: hsl(120, 100%, 40%);">+ },</span><br><span style="color: hsl(120, 100%, 40%);">+    {</span><br><span style="color: hsl(120, 100%, 40%);">+             .msg_type = BSSMAP_LE_MSGT_PERFORM_LOC_REQ,</span><br><span style="color: hsl(120, 100%, 40%);">+           .perform_loc_req = {</span><br><span style="color: hsl(120, 100%, 40%);">+                  .location_type = {</span><br><span style="color: hsl(120, 100%, 40%);">+                            .location_information = BSSMAP_LE_LOC_INFO_CURRENT_GEOGRAPHIC,</span><br><span style="color: hsl(120, 100%, 40%);">+                        },</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                  .cell_id = {</span><br><span style="color: hsl(120, 100%, 40%);">+                          .id_discr = CELL_IDENT_LAC_AND_CI,</span><br><span style="color: hsl(120, 100%, 40%);">+                            .id.lac_and_ci = {</span><br><span style="color: hsl(120, 100%, 40%);">+                                    .lac = 23,</span><br><span style="color: hsl(120, 100%, 40%);">+                                    .ci = 42,</span><br><span style="color: hsl(120, 100%, 40%);">+                             },</span><br><span style="color: hsl(120, 100%, 40%);">+                    },</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                  .lcs_client_type_present = true,</span><br><span style="color: hsl(120, 100%, 40%);">+                      .lcs_client_type = BSSMAP_LE_LCS_CTYPE_VALUE_ADDED_UNSPECIFIED,</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                     .imsi = {</span><br><span style="color: hsl(120, 100%, 40%);">+                             .type = GSM_MI_TYPE_IMSI,</span><br><span style="color: hsl(120, 100%, 40%);">+                             .imsi = "1234567890",</span><br><span style="color: hsl(120, 100%, 40%);">+                       },</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                  .imei = {</span><br><span style="color: hsl(120, 100%, 40%);">+                             .type = GSM_MI_TYPE_IMEI,</span><br><span style="color: hsl(120, 100%, 40%);">+                             .imei = "123456789012345",</span><br><span style="color: hsl(120, 100%, 40%);">+                  },</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                  .apdu_present = true,</span><br><span style="color: hsl(120, 100%, 40%);">+                 .apdu = {</span><br><span style="color: hsl(120, 100%, 40%);">+                             .msg_type = BSSLAP_MSGT_TA_LAYER3,</span><br><span style="color: hsl(120, 100%, 40%);">+                            .ta_layer3 = {</span><br><span style="color: hsl(120, 100%, 40%);">+                                        .ta = 23,</span><br><span style="color: hsl(120, 100%, 40%);">+                             },</span><br><span style="color: hsl(120, 100%, 40%);">+                    },</span><br><span style="color: hsl(120, 100%, 40%);">+            },</span><br><span style="color: hsl(120, 100%, 40%);">+    },</span><br><span style="color: hsl(120, 100%, 40%);">+    {</span><br><span style="color: hsl(120, 100%, 40%);">+             .msg_type = BSSMAP_LE_MSGT_PERFORM_LOC_RESP,</span><br><span style="color: hsl(120, 100%, 40%);">+          .perform_loc_resp = {</span><br><span style="color: hsl(120, 100%, 40%);">+                 .location_estimate_present = true,</span><br><span style="color: hsl(120, 100%, 40%);">+                    .location_estimate = {</span><br><span style="color: hsl(120, 100%, 40%);">+                                .ell_point_unc_circle = {</span><br><span style="color: hsl(120, 100%, 40%);">+                                     .h = { .type = GAD_TYPE_ELL_POINT_UNC_CIRCLE },</span><br><span style="color: hsl(120, 100%, 40%);">+                                       .lat = { 1, 2, 3 },</span><br><span style="color: hsl(120, 100%, 40%);">+                                   .lon = { 4, 5, 6 },</span><br><span style="color: hsl(120, 100%, 40%);">+                                   .unc = 123,</span><br><span style="color: hsl(120, 100%, 40%);">+                           },</span><br><span style="color: hsl(120, 100%, 40%);">+                    },</span><br><span style="color: hsl(120, 100%, 40%);">+            },</span><br><span style="color: hsl(120, 100%, 40%);">+    },</span><br><span style="color: hsl(120, 100%, 40%);">+    {</span><br><span style="color: hsl(120, 100%, 40%);">+             .msg_type = BSSMAP_LE_MSGT_PERFORM_LOC_RESP,</span><br><span style="color: hsl(120, 100%, 40%);">+          .perform_loc_resp = {</span><br><span style="color: hsl(120, 100%, 40%);">+                 .lcs_cause = {</span><br><span style="color: hsl(120, 100%, 40%);">+                                .present = true,</span><br><span style="color: hsl(120, 100%, 40%);">+                              .cause_val = LCS_CAUSE_REQUEST_ABORTED,</span><br><span style="color: hsl(120, 100%, 40%);">+                       },</span><br><span style="color: hsl(120, 100%, 40%);">+            },</span><br><span style="color: hsl(120, 100%, 40%);">+    },</span><br><span style="color: hsl(120, 100%, 40%);">+    {</span><br><span style="color: hsl(120, 100%, 40%);">+             .msg_type = BSSMAP_LE_MSGT_PERFORM_LOC_RESP,</span><br><span style="color: hsl(120, 100%, 40%);">+          .perform_loc_resp = {</span><br><span style="color: hsl(120, 100%, 40%);">+                 .lcs_cause = {</span><br><span style="color: hsl(120, 100%, 40%);">+                                .present = true,</span><br><span style="color: hsl(120, 100%, 40%);">+                              .cause_val = LCS_CAUSE_POS_METH_FAILURE,</span><br><span style="color: hsl(120, 100%, 40%);">+                              .diag_val_present = true,</span><br><span style="color: hsl(120, 100%, 40%);">+                             .diag_val = 23,</span><br><span style="color: hsl(120, 100%, 40%);">+                       },</span><br><span style="color: hsl(120, 100%, 40%);">+            },</span><br><span style="color: hsl(120, 100%, 40%);">+    },</span><br><span style="color: hsl(120, 100%, 40%);">+    {</span><br><span style="color: hsl(120, 100%, 40%);">+             .msg_type = BSSMAP_LE_MSGT_PERFORM_LOC_ABORT,</span><br><span style="color: hsl(120, 100%, 40%);">+         .perform_loc_abort = {</span><br><span style="color: hsl(120, 100%, 40%);">+                        .present = true,</span><br><span style="color: hsl(120, 100%, 40%);">+                      .cause_val = LCS_CAUSE_REQUEST_ABORTED,</span><br><span style="color: hsl(120, 100%, 40%);">+               },</span><br><span style="color: hsl(120, 100%, 40%);">+    },</span><br><span style="color: hsl(120, 100%, 40%);">+    {</span><br><span style="color: hsl(120, 100%, 40%);">+             .msg_type = BSSMAP_LE_MSGT_CONN_ORIENTED_INFO,</span><br><span style="color: hsl(120, 100%, 40%);">+                .conn_oriented_info = {</span><br><span style="color: hsl(120, 100%, 40%);">+                       .apdu = {</span><br><span style="color: hsl(120, 100%, 40%);">+                             .msg_type = BSSLAP_MSGT_TA_REQUEST,</span><br><span style="color: hsl(120, 100%, 40%);">+                   },</span><br><span style="color: hsl(120, 100%, 40%);">+            },</span><br><span style="color: hsl(120, 100%, 40%);">+    },</span><br><span style="color: hsl(120, 100%, 40%);">+    {</span><br><span style="color: hsl(120, 100%, 40%);">+             .msg_type = BSSMAP_LE_MSGT_CONN_ORIENTED_INFO,</span><br><span style="color: hsl(120, 100%, 40%);">+                .conn_oriented_info = {</span><br><span style="color: hsl(120, 100%, 40%);">+                       .apdu = {</span><br><span style="color: hsl(120, 100%, 40%);">+                             .msg_type = BSSLAP_MSGT_TA_RESPONSE,</span><br><span style="color: hsl(120, 100%, 40%);">+                          .ta_response = {</span><br><span style="color: hsl(120, 100%, 40%);">+                                      .cell_id = 23,</span><br><span style="color: hsl(120, 100%, 40%);">+                                        .ta = 42,</span><br><span style="color: hsl(120, 100%, 40%);">+                             },</span><br><span style="color: hsl(120, 100%, 40%);">+                    },</span><br><span style="color: hsl(120, 100%, 40%);">+            },</span><br><span style="color: hsl(120, 100%, 40%);">+    },</span><br><span style="color: hsl(120, 100%, 40%);">+    {</span><br><span style="color: hsl(120, 100%, 40%);">+             .msg_type = BSSMAP_LE_MSGT_CONN_ORIENTED_INFO,</span><br><span style="color: hsl(120, 100%, 40%);">+                .conn_oriented_info = {</span><br><span style="color: hsl(120, 100%, 40%);">+                       .apdu = {</span><br><span style="color: hsl(120, 100%, 40%);">+                             .msg_type = BSSLAP_MSGT_REJECT,</span><br><span style="color: hsl(120, 100%, 40%);">+                               .reject = BSSLAP_CAUSE_CONGESTION,</span><br><span style="color: hsl(120, 100%, 40%);">+                    },</span><br><span style="color: hsl(120, 100%, 40%);">+            },</span><br><span style="color: hsl(120, 100%, 40%);">+    },</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void test_bssmap_le_enc_dec()</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    struct bssmap_le_pdu *pdu;</span><br><span style="color: hsl(120, 100%, 40%);">+    printf("--- %s\n", __func__);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     for (pdu = bssmap_le_test_pdus; (pdu - bssmap_le_test_pdus) < ARRAY_SIZE(bssmap_le_test_pdus); pdu++) {</span><br><span style="color: hsl(120, 100%, 40%);">+            struct msgb *msg;</span><br><span style="color: hsl(120, 100%, 40%);">+             struct bssap_le_pdu enc_pdu = {</span><br><span style="color: hsl(120, 100%, 40%);">+                       .discr = BSSAP_LE_MSG_DISCR_BSSMAP_LE,</span><br><span style="color: hsl(120, 100%, 40%);">+                        .bssmap_le = *pdu,</span><br><span style="color: hsl(120, 100%, 40%);">+            };</span><br><span style="color: hsl(120, 100%, 40%);">+            struct bssap_le_pdu dec_pdu;</span><br><span style="color: hsl(120, 100%, 40%);">+          struct osmo_bssap_le_err *err;</span><br><span style="color: hsl(120, 100%, 40%);">+                void *loop_ctx;</span><br><span style="color: hsl(120, 100%, 40%);">+               int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+             msg = osmo_bssap_le_enc(&enc_pdu);</span><br><span style="color: hsl(120, 100%, 40%);">+                if (!msg) {</span><br><span style="color: hsl(120, 100%, 40%);">+                   printf("[%ld] %s: ERROR: failed to encode pdu\n", (pdu - bssmap_le_test_pdus),</span><br><span style="color: hsl(120, 100%, 40%);">+                             osmo_bssmap_le_msgt_name(pdu->msg_type));</span><br><span style="color: hsl(120, 100%, 40%);">+                   goto loop_end;</span><br><span style="color: hsl(120, 100%, 40%);">+                }</span><br><span style="color: hsl(120, 100%, 40%);">+             loop_ctx = msg;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+             memset(&dec_pdu, 0xff, sizeof(dec_pdu));</span><br><span style="color: hsl(120, 100%, 40%);">+          rc = osmo_bssap_le_dec(&dec_pdu, &err, loop_ctx, msg);</span><br><span style="color: hsl(120, 100%, 40%);">+                if (rc) {</span><br><span style="color: hsl(120, 100%, 40%);">+                     printf("[%ld] %s: ERROR: failed to decode pdu: %s\n", (pdu - bssmap_le_test_pdus),</span><br><span style="color: hsl(120, 100%, 40%);">+                         osmo_bssmap_le_msgt_name(pdu->msg_type), err->logmsg);</span><br><span style="color: hsl(120, 100%, 40%);">+                   printf("     encoded data: %s\n", osmo_hexdump(msg->data, msg->len));</span><br><span style="color: hsl(120, 100%, 40%);">+                 goto loop_end;</span><br><span style="color: hsl(120, 100%, 40%);">+                }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           if (memcmp(&enc_pdu, &dec_pdu, sizeof(dec_pdu))) {</span><br><span style="color: hsl(120, 100%, 40%);">+                    printf("[%ld] %s: ERROR: decoded PDU != encoded PDU\n", (pdu - bssmap_le_test_pdus),</span><br><span style="color: hsl(120, 100%, 40%);">+                               osmo_bssmap_le_msgt_name(pdu->msg_type));</span><br><span style="color: hsl(120, 100%, 40%);">+                   printf("     original struct: %s\n", osmo_hexdump((void*)&enc_pdu, sizeof(enc_pdu)));</span><br><span style="color: hsl(120, 100%, 40%);">+                   printf("      decoded struct: %s\n", osmo_hexdump((void*)&dec_pdu, sizeof(dec_pdu)));</span><br><span style="color: hsl(120, 100%, 40%);">+                   printf("        encoded data: %s\n", osmo_hexdump(msg->data, msg->len));</span><br><span style="color: hsl(120, 100%, 40%);">+                      goto loop_end;</span><br><span style="color: hsl(120, 100%, 40%);">+                }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           printf("[%ld] %s: ok (encoded len = %d)\n", (pdu - bssmap_le_test_pdus),</span><br><span style="color: hsl(120, 100%, 40%);">+                   osmo_bssmap_le_msgt_name(pdu->msg_type), msg->len);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+loop_end:</span><br><span style="color: hsl(120, 100%, 40%);">+         msgb_free(msg);</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int main()</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ test_bssmap_le_enc_dec();</span><br><span style="color: hsl(120, 100%, 40%);">+     return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span>diff --git a/tests/bssmap_le/bssmap_le_test.ok b/tests/bssmap_le/bssmap_le_test.ok</span><br><span>new file mode 100644</span><br><span>index 0000000..a6f0dee</span><br><span>--- /dev/null</span><br><span>+++ b/tests/bssmap_le/bssmap_le_test.ok</span><br><span>@@ -0,0 +1,11 @@</span><br><span style="color: hsl(120, 100%, 40%);">+--- test_bssmap_le_enc_dec</span><br><span style="color: hsl(120, 100%, 40%);">+[0] RESET: ok (encoded len = 6)</span><br><span style="color: hsl(120, 100%, 40%);">+[1] RESET ACKNOWLEDGE: ok (encoded len = 3)</span><br><span style="color: hsl(120, 100%, 40%);">+[2] PERFORM LOCATION REQUEST: ok (encoded len = 41)</span><br><span style="color: hsl(120, 100%, 40%);">+[3] PERFORM LOCATION RESPONSE: ok (encoded len = 13)</span><br><span style="color: hsl(120, 100%, 40%);">+[4] PERFORM LOCATION RESPONSE: ok (encoded len = 6)</span><br><span style="color: hsl(120, 100%, 40%);">+[5] PERFORM LOCATION RESPONSE: ok (encoded len = 7)</span><br><span style="color: hsl(120, 100%, 40%);">+[6] PERFORM LOCATION ABORT: ok (encoded len = 6)</span><br><span style="color: hsl(120, 100%, 40%);">+[7] CONNECTION ORIENTED INFORMATON: ok (encoded len = 8)</span><br><span style="color: hsl(120, 100%, 40%);">+[8] CONNECTION ORIENTED INFORMATON: ok (encoded len = 13)</span><br><span style="color: hsl(120, 100%, 40%);">+[9] CONNECTION ORIENTED INFORMATON: ok (encoded len = 10)</span><br><span>diff --git a/tests/testsuite.at b/tests/testsuite.at</span><br><span>index 0923c25..43f515a 100644</span><br><span>--- a/tests/testsuite.at</span><br><span>+++ b/tests/testsuite.at</span><br><span>@@ -415,3 +415,9 @@</span><br><span> cat $abs_srcdir/bsslap/bsslap_test.ok > expout</span><br><span> AT_CHECK([$abs_top_builddir/tests/bsslap/bsslap_test], [0], [expout], [ignore])</span><br><span> AT_CLEANUP</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+AT_SETUP([bssmap_le])</span><br><span style="color: hsl(120, 100%, 40%);">+AT_KEYWORDS([bssmap_le])</span><br><span style="color: hsl(120, 100%, 40%);">+cat $abs_srcdir/bssmap_le/bssmap_le_test.ok > expout</span><br><span style="color: hsl(120, 100%, 40%);">+AT_CHECK([$abs_top_builddir/tests/bssmap_le/bssmap_le_test], [0], [expout], [ignore])</span><br><span style="color: hsl(120, 100%, 40%);">+AT_CLEANUP</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.osmocom.org/c/libosmocore/+/20334">change 20334</a>. To unsubscribe, or for help writing mail filters, visit <a href="https://gerrit.osmocom.org/settings">settings</a>.</p><div itemscope itemtype="http://schema.org/EmailMessage"><div itemscope itemprop="action" itemtype="http://schema.org/ViewAction"><link itemprop="url" href="https://gerrit.osmocom.org/c/libosmocore/+/20334"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: libosmocore </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-Change-Id: I271e59b794bafc0a7ae0eabbf58918f6d7df431d </div>
<div style="display:none"> Gerrit-Change-Number: 20334 </div>
<div style="display:none"> Gerrit-PatchSet: 6 </div>
<div style="display:none"> Gerrit-Owner: neels <nhofmeyr@sysmocom.de> </div>
<div style="display:none"> Gerrit-Reviewer: Jenkins Builder </div>
<div style="display:none"> Gerrit-Reviewer: laforge <laforge@osmocom.org> </div>
<div style="display:none"> Gerrit-Reviewer: neels <nhofmeyr@sysmocom.de> </div>
<div style="display:none"> Gerrit-MessageType: merged </div>