aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/Makefile.am1
-rw-r--r--include/osmocom/gprs/gprs_bssgp_rim.h182
-rw-r--r--src/gb/Makefile.am2
-rw-r--r--src/gb/gprs_bssgp_rim.c763
-rw-r--r--src/gb/libosmogb.map16
-rw-r--r--tests/Makefile.am7
-rw-r--r--tests/gb/gprs_bssgp_rim_test.c664
-rw-r--r--tests/gb/gprs_bssgp_rim_test.ok220
-rw-r--r--tests/testsuite.at6
9 files changed, 1859 insertions, 2 deletions
diff --git a/include/Makefile.am b/include/Makefile.am
index c1ae6440..10f02215 100644
--- a/include/Makefile.am
+++ b/include/Makefile.am
@@ -69,6 +69,7 @@ nobase_include_HEADERS = \
osmocom/gprs/gprs_bssgp.h \
osmocom/gprs/gprs_bssgp2.h \
osmocom/gprs/gprs_bssgp_bss.h \
+ osmocom/gprs/gprs_bssgp_rim.h \
osmocom/gprs/gprs_msgb.h \
osmocom/gprs/gprs_ns.h \
osmocom/gprs/gprs_ns_frgre.h \
diff --git a/include/osmocom/gprs/gprs_bssgp_rim.h b/include/osmocom/gprs/gprs_bssgp_rim.h
new file mode 100644
index 00000000..0612a910
--- /dev/null
+++ b/include/osmocom/gprs/gprs_bssgp_rim.h
@@ -0,0 +1,182 @@
+/*! \file gprs_bssgp.h
+ * GPRS BSSGP RIM protocol implementation as per 3GPP TS 48.018. */
+/*
+ * (C) 2020-2021 by sysmocom - s.f.m.c. GmbH
+ * Author: Philipp Maier <pmaier@sysmocom.de>
+ *
+ * All Rights Reserved
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#pragma once
+
+#include <osmocom/gprs/protocol/gsm_08_18.h>
+
+/* 3GPP TS 48.018, table 11.3.63.1.1: RAN-INFORMATION-REQUEST Application Container coding for NACC */
+struct bssgp_ran_inf_req_app_cont_nacc {
+ struct osmo_cell_global_id_ps reprt_cell;
+};
+
+int bssgp_dec_ran_inf_req_app_cont_nacc(struct bssgp_ran_inf_req_app_cont_nacc *cont, const uint8_t *buf, size_t len);
+int bssgp_enc_ran_inf_req_app_cont_nacc(uint8_t *buf, size_t len, const struct bssgp_ran_inf_req_app_cont_nacc *cont);
+
+/* Length of NACC system information, see also: 3GPP TS 48.018 11.3.63.2.1 */
+#define BSSGP_RIM_SI_LEN 21
+#define BSSGP_RIM_PSI_LEN 22
+
+/* 3GPP TS 48.018, table 11.3.63.2.1.a: RAN-INFORMATION Application Container coding for NACC */
+struct bssgp_ran_inf_app_cont_nacc {
+ struct osmo_cell_global_id_ps reprt_cell;
+ bool type_psi;
+ uint8_t num_si;
+
+ /* Pointer to system information messages */
+ const uint8_t *si[127];
+};
+
+int bssgp_dec_ran_inf_app_cont_nacc(struct bssgp_ran_inf_app_cont_nacc *cont, const uint8_t *buf, size_t len);
+int bssgp_enc_ran_inf_app_cont_nacc(uint8_t *buf, size_t len, const struct bssgp_ran_inf_app_cont_nacc *cont);
+
+/* 3GPP TS 48.018, table 11.3.64.1.b, NACC Cause coding */
+enum bssgp_nacc_cause {
+ BSSGP_NACC_CAUSE_UNSPEC,
+ BSSGP_NACC_CAUSE_SYNTAX_ERR,
+ BSSGP_NACC_CAUSE_RPRT_CELL_MISSMTCH,
+ BSSGP_NACC_CAUSE_SIPSI_TYPE_ERR,
+ BSSGP_NACC_CAUSE_SIPSI_LEN_ERR,
+ BSSGP_NACC_CAUSE_SIPSI_SET_ERR,
+};
+
+/* 3GPP TS 48.018, table 11.3.64.1.a, Application Error Container coding for NACC */
+struct bssgp_app_err_cont_nacc {
+ enum bssgp_nacc_cause nacc_cause;
+
+ /* Pointer to errornous application container */
+ const uint8_t *err_app_cont;
+ size_t err_app_cont_len;
+};
+
+int bssgp_dec_app_err_cont_nacc(struct bssgp_app_err_cont_nacc *cont, const uint8_t *buf, size_t len);
+int bssgp_enc_app_err_cont_nacc(uint8_t *buf, size_t len, const struct bssgp_app_err_cont_nacc *cont);
+
+/* 3GPP TS 48.018, table 11.3.61.b: RIM Application Identity coding */
+enum bssgp_ran_inf_app_id {
+ BSSGP_RAN_INF_APP_ID_NACC = 1,
+ BSSGP_RAN_INF_APP_ID_SI3 = 2,
+ BSSGP_RAN_INF_APP_ID_MBMS = 3,
+ BSSGP_RAN_INF_APP_ID_SON = 4,
+ BSSGP_RAN_INF_APP_ID_UTRA_SI = 5,
+};
+
+/* 3GPP TS 48.018, table 11.3.62a.1.b: RAN-INFORMATION-REQUEST RIM Container Contents */
+struct bssgp_ran_inf_req_rim_cont {
+ enum bssgp_ran_inf_app_id app_id;
+ uint32_t seq_num;
+ struct bssgp_rim_pdu_ind pdu_ind;
+ uint8_t prot_ver;
+
+ /* Nested application container */
+ union {
+ struct bssgp_ran_inf_req_app_cont_nacc app_cont_nacc;
+ /* TODO: add containers for Si3, MBMS, SON, UTRA-SI */
+ } u;
+
+ /* Pointer to SON-transfer application identity, only present if app_id is indicating "son-transfer",
+ * see also 3GPP TS 48.018, section 11.3.108 and 3GPP TS 36.413 annex B.1.1 */
+ const uint8_t *son_trans_app_id;
+ size_t son_trans_app_id_len;
+};
+
+int bssgp_dec_ran_inf_req_rim_cont(struct bssgp_ran_inf_req_rim_cont *cont, const uint8_t *buf, size_t len);
+int bssgp_enc_ran_inf_req_rim_cont(uint8_t *buf, size_t len, const struct bssgp_ran_inf_req_rim_cont *cont);
+
+/* 3GPP TS 48.018, table 11.3.62a.2.b: RAN-INFORMATION RIM Container Contents */
+struct bssgp_ran_inf_rim_cont {
+ enum bssgp_ran_inf_app_id app_id;
+ uint32_t seq_num;
+ struct bssgp_rim_pdu_ind pdu_ind;
+ uint8_t prot_ver;
+ bool app_err;
+
+ /* Nested application container */
+ union {
+ struct bssgp_ran_inf_app_cont_nacc app_cont_nacc;
+ struct bssgp_app_err_cont_nacc app_err_cont_nacc;
+ /* TODO: add containers for Si3, MBMS, SON, UTRA-SI */
+ } u;
+
+ /* Pointer to SON-transfer application identity, only present if app_id is indicating "son-transfer",
+ * see also 3GPP TS 48.018, section 11.3.108 and 3GPP TS 36.413 annex B.1.1 */
+ const uint8_t *son_trans_app_id;
+ size_t son_trans_app_id_len;
+};
+
+int bssgp_dec_ran_inf_rim_cont(struct bssgp_ran_inf_rim_cont *cont, const uint8_t *buf, size_t len);
+int bssgp_enc_ran_inf_rim_cont(uint8_t *buf, size_t len, const struct bssgp_ran_inf_rim_cont *cont);
+
+/* 3GPP TS 48.018, table 11.3.62a.3.b: RAN-INFORMATION-ACK RIM Container Contents */
+struct bssgp_ran_inf_ack_rim_cont {
+ enum bssgp_ran_inf_app_id app_id;
+ uint32_t seq_num;
+ uint8_t prot_ver;
+
+ /* Pointer to SON-transfer application identity, only present if app_id is indicating "son-transfer",
+ * see also 3GPP TS 48.018, section 11.3.108 and 3GPP TS 36.413 annex B.1.1 */
+ const uint8_t *son_trans_app_id;
+ size_t son_trans_app_id_len;
+};
+
+int bssgp_dec_ran_inf_ack_rim_cont(struct bssgp_ran_inf_ack_rim_cont *cont, const uint8_t *buf, size_t len);
+int bssgp_enc_ran_inf_ack_rim_cont(uint8_t *buf, size_t len, const struct bssgp_ran_inf_ack_rim_cont *cont);
+
+/* 3GPP TS 48.018, table 11.3.62a.4.b: RAN-INFORMATION-ERROR RIM Container Contents */
+struct bssgp_ran_inf_err_rim_cont {
+ enum bssgp_ran_inf_app_id app_id;
+ uint8_t cause;
+ uint8_t prot_ver;
+
+ /* Pointer to (encoded) errornous PDU,
+ * see also: 3GPP TS 48.018, section 11.3.24 */
+ const uint8_t *err_pdu;
+ size_t err_pdu_len;
+
+ /* Pointer to SON-transfer application identity, only present if app_id is indicating "son-transfer",
+ * see also 3GPP TS 48.018, section 11.3.108 and 3GPP TS 36.413 annex B.1.1 */
+ const uint8_t *son_trans_app_id;
+ size_t son_trans_app_id_len;
+};
+
+int bssgp_dec_ran_inf_err_rim_cont(struct bssgp_ran_inf_err_rim_cont *cont, const uint8_t *buf, size_t len);
+int bssgp_enc_ran_inf_err_rim_cont(uint8_t *buf, size_t len, const struct bssgp_ran_inf_err_rim_cont *cont);
+
+/* 3GPP TS 48.018, table 11.3.62a.5.b: RAN-INFORMATION-APPLICATION-ERROR RIM Container Contents */
+struct bssgp_ran_inf_app_err_rim_cont {
+ enum bssgp_ran_inf_app_id app_id;
+ uint32_t seq_num;
+ struct bssgp_rim_pdu_ind pdu_ind;
+ uint8_t prot_ver;
+
+ /* Nested application container */
+ union {
+ struct bssgp_app_err_cont_nacc app_err_cont_nacc;
+ /* TODO: add containers for Si3, MBMS, SON, UTRA-SI */
+ } u;
+};
+
+int bssgp_dec_ran_inf_app_err_rim_cont(struct bssgp_ran_inf_app_err_rim_cont *cont, const uint8_t *buf, size_t len);
+int bssgp_enc_ran_inf_app_err_rim_cont(uint8_t *buf, size_t len, const struct bssgp_ran_inf_app_err_rim_cont *cont);
diff --git a/src/gb/Makefile.am b/src/gb/Makefile.am
index cbee3338..031971b6 100644
--- a/src/gb/Makefile.am
+++ b/src/gb/Makefile.am
@@ -22,7 +22,7 @@ libosmogb_la_LIBADD = $(TALLOC_LIBS) \
$(top_builddir)/src/gsm/libosmogsm.la
libosmogb_la_SOURCES = gprs_ns.c gprs_ns_frgre.c gprs_ns_vty.c gprs_ns_sns.c \
- gprs_bssgp.c gprs_bssgp_util.c gprs_bssgp_vty.c \
+ gprs_bssgp.c gprs_bssgp_util.c gprs_bssgp_vty.c gprs_bssgp_rim.c \
gprs_bssgp_bss.c \
gprs_ns2.c gprs_ns2_udp.c gprs_ns2_frgre.c gprs_ns2_fr.c gprs_ns2_vc_fsm.c gprs_ns2_sns.c \
gprs_ns2_message.c gprs_ns2_vty.c gprs_ns2_vty2.c \
diff --git a/src/gb/gprs_bssgp_rim.c b/src/gb/gprs_bssgp_rim.c
new file mode 100644
index 00000000..3ac405eb
--- /dev/null
+++ b/src/gb/gprs_bssgp_rim.c
@@ -0,0 +1,763 @@
+/*! \file gprs_bssgp.c
+ * GPRS BSSGP RIM protocol implementation as per 3GPP TS 48.018. */
+/*
+ * (C) 2020-2021 by sysmocom - s.f.m.c. GmbH
+ * Author: Philipp Maier <pmaier@sysmocom.de>
+ *
+ * All Rights Reserved
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <errno.h>
+#include <osmocom/gprs/gprs_bssgp.h>
+#include <osmocom/gprs/gprs_bssgp_rim.h>
+#include <osmocom/gsm/gsm0808_utils.h>
+
+/* TVLV IEs use a variable length field. To be sure we will do all buffer
+ * length checks with the maximum possible header length, which is
+ * 1 octet tag + 2 octets length = 3 */
+#define TVLV_HDR_MAXLEN 3
+
+/* Usually RIM application containers and their surrounding RIM containers
+ * are not likely to exceed 128 octets, so the usual header length will be 2 */
+#define TVLV_HDR_LEN 2
+
+/* The reporting cell identifier is encoded as a cell identifier IE
+ * (3GPP TS 48.018, sub-clause 11.3.9) but without IE and length octets. */
+#define REP_CELL_ID_LEN 8
+
+/*! Decode a RAN Information Request Application Container for NACC (3GPP TS 48.018, section 11.3.63.1.1).
+ * \param[out] user provided memory for decoded data struct.
+ * \param[in] buf user provided memory with the encoded value data of the IE.
+ * \returns 0 on success, -EINVAL on error. */
+int bssgp_dec_ran_inf_req_app_cont_nacc(struct bssgp_ran_inf_req_app_cont_nacc *cont, const uint8_t *buf, size_t len)
+{
+ int rc;
+
+ if (len < REP_CELL_ID_LEN)
+ return -EINVAL;
+
+ rc = gsm0808_decode_cell_id_u((union gsm0808_cell_id_u*)&cont->reprt_cell,
+ CELL_IDENT_WHOLE_GLOBAL_PS, buf, len);
+ if (rc < 0)
+ return -EINVAL;
+
+ return 0;
+}
+
+/*! Encode a RAN Information Request Application Container for NACC (3GPP TS 48.018, section 11.3.63.1.1).
+ * \param[out] buf user provided memory for the generated value part of the IE.
+ * \param[in] cont user provided input data struct.
+ * \returns length of encoded octets, -EINVAL on error. */
+int bssgp_enc_ran_inf_req_app_cont_nacc(uint8_t *buf, size_t len, const struct bssgp_ran_inf_req_app_cont_nacc *cont)
+{
+ int rc;
+ struct gprs_ra_id *raid;
+
+ if (len < REP_CELL_ID_LEN)
+ return -EINVAL;
+
+ raid = (struct gprs_ra_id *)&cont->reprt_cell.rai;
+ rc = bssgp_create_cell_id(buf, raid, cont->reprt_cell.cell_identity);
+ if (rc < 0)
+ return -EINVAL;
+ return rc;
+}
+
+/*! Decode a RAN Information Application Container (3GPP TS 48.018, section 11.3.63.2.1).
+ * \param[out] user provided memory for decoded data struct.
+ * \param[in] buf user provided memory with the encoded value data of the IE.
+ * \returns 0 on success, -EINVAL on error. */
+int bssgp_dec_ran_inf_app_cont_nacc(struct bssgp_ran_inf_app_cont_nacc *cont, const uint8_t *buf, size_t len)
+{
+ unsigned int i;
+ int remaining_buf_len;
+ int rc;
+
+ /* The given buffer must at least contain a reporting cell identifer
+ * plus one octet that defines number/type of attached sysinfo messages. */
+ if (len < REP_CELL_ID_LEN + 1)
+ return -EINVAL;
+
+ rc = gsm0808_decode_cell_id_u((union gsm0808_cell_id_u*)&cont->reprt_cell,
+ CELL_IDENT_WHOLE_GLOBAL_PS, buf, len);
+ if (rc < 0)
+ return -EINVAL;
+
+ buf += REP_CELL_ID_LEN;
+
+ cont->type_psi = buf[0] & 1;
+ cont->num_si = buf[0] >> 1;
+ buf++;
+
+ /* The number of sysinfo messages may be zero */
+ if (cont->num_si == 0)
+ return 0;
+
+ /* Check if the prospected system information messages fit in the
+ * remaining buffer space */
+ remaining_buf_len = len - REP_CELL_ID_LEN - 1;
+ if (remaining_buf_len <= 0)
+ return -EINVAL;
+ if (cont->type_psi && remaining_buf_len / BSSGP_RIM_PSI_LEN < cont->num_si)
+ return -EINVAL;
+ else if (remaining_buf_len / BSSGP_RIM_SI_LEN < cont->num_si)
+ return -EINVAL;
+
+ for (i = 0; i < cont->num_si; i++) {
+ cont->si[i] = buf;
+ if (cont->type_psi)
+ buf += BSSGP_RIM_PSI_LEN;
+ else
+ buf += BSSGP_RIM_SI_LEN;
+ }
+
+ return 0;
+}
+
+/*! Encode a RAN Information Application Container (3GPP TS 48.018, section 11.3.63.2.1).
+ * \param[out] buf user provided memory for the generated value part of the IE.
+ * \param[in] cont user provided input data struct.
+ * \returns length of encoded octets, -EINVAL on error. */
+int bssgp_enc_ran_inf_app_cont_nacc(uint8_t *buf, size_t len, const struct bssgp_ran_inf_app_cont_nacc *cont)
+{
+ uint8_t *buf_ptr = buf;
+ int rc;
+ unsigned int silen;
+ unsigned int i;
+ struct gprs_ra_id *raid;
+
+ if (cont->type_psi)
+ silen = BSSGP_RIM_PSI_LEN;
+ else
+ silen = BSSGP_RIM_SI_LEN;
+
+ /* The buffer must accept the reporting cell id, plus 1 byte to define
+ * the type and number of sysinfo messages. */
+ if (len < REP_CELL_ID_LEN + 1 + silen * cont->num_si)
+ return -EINVAL;
+
+ raid = (struct gprs_ra_id *)&cont->reprt_cell.rai;
+ rc = bssgp_create_cell_id(buf_ptr, raid, cont->reprt_cell.cell_identity);
+ if (rc < 0)
+ return -EINVAL;
+ buf_ptr += rc;
+
+ buf_ptr[0] = 0x00;
+ if (cont->type_psi)
+ buf_ptr[0] |= 0x01;
+ buf_ptr[0] |= (cont->num_si << 1);
+ buf_ptr++;
+
+ for (i = 0; i < cont->num_si; i++) {
+ memcpy(buf_ptr, cont->si[i], silen);
+ buf_ptr += silen;
+ }
+
+ return (int)(buf_ptr - buf);
+}
+
+/*! Decode a Application Error Container for NACC (3GPP TS 48.018, section 11.3.64.1).
+ * \param[out] user provided memory for decoded data struct.
+ * \param[in] buf user provided memory with the encoded value data of the IE.
+ * \returns 0 on success, -EINVAL on error. */
+int bssgp_dec_app_err_cont_nacc(struct bssgp_app_err_cont_nacc *cont, const uint8_t *buf, size_t len)
+{
+ /* The buffer must at least contain the NACC cause code, it should also
+ * contain the application container, but we won't error if it is missing. */
+ if (len < 1)
+ return -EINVAL;
+
+ cont->nacc_cause = buf[0];
+
+ if (len > 1) {
+ cont->err_app_cont = buf + 1;
+ cont->err_app_cont_len = len - 1;
+ } else {
+ cont->err_app_cont = NULL;
+ cont->err_app_cont_len = 0;
+ }
+
+ return 0;
+}
+
+/*! Encode Application Error Container for NACC (3GPP TS 48.018, section 11.3.64.1).
+ * \param[out] buf user provided memory for the generated value part of the IE.
+ * \param[in] cont user provided input data struct.
+ * \returns length of encoded octets, -EINVAL on error. */
+int bssgp_enc_app_err_cont_nacc(uint8_t *buf, size_t len, const struct bssgp_app_err_cont_nacc *cont)
+{
+ uint8_t *buf_ptr = buf;
+
+ /* The buffer must accept the length of the application container and the NACC
+ * cause code, which is one octet in length. */
+ if (len < cont->err_app_cont_len + 1)
+ return -EINVAL;
+
+ buf_ptr[0] = cont->nacc_cause;
+ buf_ptr++;
+
+ memcpy(buf_ptr, cont->err_app_cont, cont->err_app_cont_len);
+ buf_ptr += cont->err_app_cont_len;
+
+ return (int)(buf_ptr - buf);
+}
+
+/* The structs bssgp_ran_inf_req_rim_cont, bssgp_ran_inf_rim_cont and bssgp_ran_inf_app_err_rim_cont *cont
+ * share four common fields at the beginning, we use the following struct as parameter type for the common
+ * encoder/decoder functions. (See also 3GPP TS 48.018 table 11.3.62a.1.b, table 11.3.62a.2.b, and
+ * table 11.3.62a.5.b) */
+struct bssgp_ran_inf_x_cont {
+ enum bssgp_ran_inf_app_id app_id;
+ uint32_t seq_num;
+ struct bssgp_rim_pdu_ind pdu_ind;
+ uint8_t prot_ver;
+};
+
+static int dec_rim_cont_common(struct bssgp_ran_inf_x_cont *cont, struct tlv_parsed *tp)
+{
+ if (TLVP_PRES_LEN(tp, BSSGP_IE_RIM_APP_IDENTITY, sizeof(uint8_t)))
+ cont->app_id = TLVP_VAL(tp, BSSGP_IE_RIM_APP_IDENTITY)[0];
+ else
+ return -EINVAL;
+
+ if (TLVP_PRES_LEN(tp, BSSGP_IE_RIM_SEQ_NR, sizeof(cont->seq_num)))
+ cont->seq_num = tlvp_val32be(tp, BSSGP_IE_RIM_SEQ_NR);
+ else
+ return -EINVAL;
+
+ if (TLVP_PRES_LEN(tp, BSSGP_IE_RIM_PDU_INDICATIONS, sizeof(cont->pdu_ind)))
+ memcpy(&cont->pdu_ind, TLVP_VAL(tp, BSSGP_IE_RIM_PDU_INDICATIONS), sizeof(cont->pdu_ind));
+ else
+ return -EINVAL;
+
+ if (TLVP_PRES_LEN(tp, BSSGP_IE_RIM_PROTOCOL_VERSION, sizeof(cont->prot_ver)))
+ cont->prot_ver = TLVP_VAL(tp, BSSGP_IE_RIM_PROTOCOL_VERSION)[0];
+ else
+ cont->prot_ver = 1;
+
+ return 0;
+}
+
+static uint8_t *enc_rim_cont_common(uint8_t *buf, size_t len, const struct bssgp_ran_inf_x_cont *cont)
+{
+
+ uint32_t seq_num = osmo_htonl(cont->seq_num);
+ uint8_t app_id_temp;
+ uint8_t *buf_ptr = buf;
+
+ if (len <
+ TVLV_HDR_MAXLEN * 4 + sizeof(app_id_temp) + sizeof(seq_num) + sizeof(cont->pdu_ind) +
+ sizeof(cont->prot_ver))
+ return NULL;
+
+ app_id_temp = cont->app_id;
+ buf_ptr = tvlv_put(buf_ptr, BSSGP_IE_RIM_APP_IDENTITY, sizeof(app_id_temp), &app_id_temp);
+ buf_ptr = tvlv_put(buf_ptr, BSSGP_IE_RIM_SEQ_NR, sizeof(seq_num), (uint8_t *) & seq_num);
+ buf_ptr = tvlv_put(buf_ptr, BSSGP_IE_RIM_PDU_INDICATIONS, sizeof(cont->pdu_ind), (uint8_t *) & cont->pdu_ind);
+ if (cont->prot_ver > 0)
+ buf_ptr = tvlv_put(buf_ptr, BSSGP_IE_RIM_PROTOCOL_VERSION, sizeof(cont->prot_ver), &cont->prot_ver);
+
+ return buf_ptr;
+}
+
+/*! Decode a RAN Information Request RIM Container (3GPP TS 48.018, table 11.3.62a.1.b).
+ * \param[out] user provided memory for decoded data struct.
+ * \param[in] buf user provided memory with the encoded value data of the IE.
+ * \returns 0 on success, -EINVAL on error. */
+int bssgp_dec_ran_inf_req_rim_cont(struct bssgp_ran_inf_req_rim_cont *cont, const uint8_t *buf, size_t len)
+{
+ int rc;
+ struct tlv_parsed tp;
+
+ memset(cont, 0, sizeof(*cont));
+
+ rc = tlv_parse(&tp, &tvlv_att_def, buf, len, 0, 0);
+ if (rc < 0)
+ return -EINVAL;
+
+ rc = dec_rim_cont_common((struct bssgp_ran_inf_x_cont *)cont, &tp);
+ if (rc < 0)
+ return -EINVAL;
+
+ if (TLVP_PRESENT(&tp, BSSGP_IE_RIM_REQ_APP_CONTAINER)) {
+ switch (cont->app_id) {
+ case BSSGP_RAN_INF_APP_ID_NACC:
+ rc = bssgp_dec_ran_inf_req_app_cont_nacc(&cont->u.app_cont_nacc,
+ TLVP_VAL(&tp, BSSGP_IE_RIM_REQ_APP_CONTAINER),
+ TLVP_LEN(&tp, BSSGP_IE_RIM_REQ_APP_CONTAINER));
+ break;
+ case BSSGP_RAN_INF_APP_ID_SI3:
+ case BSSGP_RAN_INF_APP_ID_MBMS:
+ case BSSGP_RAN_INF_APP_ID_SON:
+ case BSSGP_RAN_INF_APP_ID_UTRA_SI:
+ /* TODO: add parsers for Si3, MBMS, SON, UTRA-SI app containers */
+ return -EINVAL;
+ default:
+ return -EINVAL;
+ }
+
+ if (rc < 0)
+ return rc;
+ }
+
+ if (TLVP_PRES_LEN(&tp, BSSGP_IE_SON_TRANSFER_APP_ID, 1)) {
+ cont->son_trans_app_id = TLVP_VAL(&tp, BSSGP_IE_SON_TRANSFER_APP_ID);
+ cont->son_trans_app_id_len = TLVP_LEN(&tp, BSSGP_IE_SON_TRANSFER_APP_ID);
+ }
+
+ return 0;
+}
+
+/* Dub a TLVP header into a given buffer. The value part of the IE must start
+ * at the 2nd octet. Should the length field make a 3 octet TLVP header
+ * necessary (unlikely, but possible) the value part is moved ahead by one
+ * octet. The function returns a pointer to the end of value part. */
+static uint8_t *dub_tlvp_header(uint8_t *buf, uint8_t iei, uint16_t len)
+{
+ uint8_t *buf_ptr = buf;
+
+ buf_ptr[0] = iei;
+ if (len <= TVLV_MAX_ONEBYTE) {
+ buf_ptr[1] = (uint8_t) len;
+ buf_ptr[1] |= 0x80;
+ buf_ptr += TVLV_HDR_LEN;
+ } else {
+ memmove(buf_ptr + 1, buf_ptr, len);
+ buf_ptr[1] = len >> 8;
+ buf_ptr[1] = len & 0xff;
+ buf_ptr += TVLV_HDR_MAXLEN;
+ }
+ buf_ptr += len;
+
+ return buf_ptr;
+}
+
+/*! Encode a RAN Information Request RIM Container (3GPP TS 48.018, table 11.3.62a.1.b).
+ * \param[out] buf user provided memory for the generated value part of the IE.
+ * \param[in] cont user provided input data struct.
+ * \returns length of encoded octets, -EINVAL on error. */
+int bssgp_enc_ran_inf_req_rim_cont(uint8_t *buf, size_t len, const struct bssgp_ran_inf_req_rim_cont *cont)
+{
+ uint8_t *buf_ptr = buf;
+ int app_cont_len = 0;
+ int remaining_buf_len;
+
+ buf_ptr = enc_rim_cont_common(buf_ptr, len, (struct bssgp_ran_inf_x_cont *)cont);
+ if (!buf_ptr)
+ return -EINVAL;
+
+ remaining_buf_len = len - (int)(buf_ptr - buf);
+ if (remaining_buf_len <= 0)
+ return -EINVAL;
+
+ switch (cont->app_id) {
+ case BSSGP_RAN_INF_APP_ID_NACC:
+ app_cont_len =
+ bssgp_enc_ran_inf_req_app_cont_nacc(buf_ptr + TVLV_HDR_LEN, remaining_buf_len - TVLV_HDR_MAXLEN,
+ &cont->u.app_cont_nacc);
+ break;
+ case BSSGP_RAN_INF_APP_ID_SI3:
+ case BSSGP_RAN_INF_APP_ID_MBMS:
+ case BSSGP_RAN_INF_APP_ID_SON:
+ case BSSGP_RAN_INF_APP_ID_UTRA_SI:
+ /* TODO: add encoders for Si3, MBMS, SON, UTRA-SI app containers */
+ return -EINVAL;
+ default:
+ return -EINVAL;
+ }
+
+ if (app_cont_len < 0)
+ return -EINVAL;
+ buf_ptr = dub_tlvp_header(buf_ptr, BSSGP_IE_RIM_REQ_APP_CONTAINER, app_cont_len);
+
+ remaining_buf_len = len - (int)(buf_ptr - buf);
+ if (remaining_buf_len < 0)
+ return -EINVAL;
+
+ if (cont->son_trans_app_id && cont->son_trans_app_id_len > 0) {
+ if (remaining_buf_len < cont->son_trans_app_id_len + TVLV_HDR_MAXLEN)
+ return -EINVAL;
+ buf_ptr =
+ tvlv_put(buf_ptr, BSSGP_IE_SON_TRANSFER_APP_ID, cont->son_trans_app_id_len, cont->son_trans_app_id);
+ }
+ return (int)(buf_ptr - buf);
+}
+
+/*! Decode a RAN Information RIM Container (3GPP TS 48.018, table 11.3.62a.2.b).
+ * \param[out] user provided memory for decoded data struct.
+ * \param[in] buf user provided memory with the encoded value data of the IE.
+ * \returns 0 on success, -EINVAL on error. */
+int bssgp_dec_ran_inf_rim_cont(struct bssgp_ran_inf_rim_cont *cont, const uint8_t *buf, size_t len)
+{
+ int rc;
+ struct tlv_parsed tp;
+
+ memset(cont, 0, sizeof(*cont));
+
+ rc = tlv_parse(&tp, &tvlv_att_def, buf, len, 0, 0);
+ if (rc < 0)
+ return -EINVAL;
+
+ rc = dec_rim_cont_common((struct bssgp_ran_inf_x_cont *)cont, &tp);
+ if (rc < 0)
+ return -EINVAL;
+
+ if (TLVP_PRESENT(&tp, BSSGP_IE_RAN_INFO_APP_CONTAINER)) {
+ switch (cont->app_id) {
+ case BSSGP_RAN_INF_APP_ID_NACC:
+ rc = bssgp_dec_ran_inf_app_cont_nacc(&cont->u.app_cont_nacc,
+ TLVP_VAL(&tp, BSSGP_IE_RAN_INFO_APP_CONTAINER),
+ TLVP_LEN(&tp, BSSGP_IE_RAN_INFO_APP_CONTAINER));
+ break;
+ case BSSGP_RAN_INF_APP_ID_SI3:
+ case BSSGP_RAN_INF_APP_ID_MBMS:
+ case BSSGP_RAN_INF_APP_ID_SON:
+ case BSSGP_RAN_INF_APP_ID_UTRA_SI:
+ /* TODO: add parsers for Si3, MBMS, SON, UTRA-SI app containers */
+ return -EINVAL;
+ default:
+ return -EINVAL;
+ }
+
+ if (rc < 0)
+ return rc;
+ } else if (TLVP_PRESENT(&tp, BSSGP_IE_APP_ERROR_CONTAINER)) {
+ switch (cont->app_id) {
+ case BSSGP_RAN_INF_APP_ID_NACC:
+ rc = bssgp_dec_app_err_cont_nacc(&cont->u.app_err_cont_nacc,
+ TLVP_VAL(&tp, BSSGP_IE_APP_ERROR_CONTAINER), TLVP_LEN(&tp,
+ BSSGP_IE_APP_ERROR_CONTAINER));
+ break;
+ case BSSGP_RAN_INF_APP_ID_SI3:
+ case BSSGP_RAN_INF_APP_ID_MBMS:
+ case BSSGP_RAN_INF_APP_ID_SON:
+ case BSSGP_RAN_INF_APP_ID_UTRA_SI:
+ /* TODO: add parsers for Si3, MBMS, SON, UTRA-SI app containers */
+ return -EINVAL;
+ default:
+ return -EINVAL;
+ }
+ if (rc < 0)
+ return rc;
+ cont->app_err = true;
+ }
+
+ if (TLVP_PRES_LEN(&tp, BSSGP_IE_SON_TRANSFER_APP_ID, 1)) {
+ cont->son_trans_app_id = TLVP_VAL(&tp, BSSGP_IE_SON_TRANSFER_APP_ID);
+ cont->son_trans_app_id_len = TLVP_LEN(&tp, BSSGP_IE_SON_TRANSFER_APP_ID);
+ }
+
+ return 0;
+}
+
+/*! Encode a RAN Information RIM Container (3GPP TS 48.018, table 11.3.62a.2.b).
+ * \param[out] buf user provided memory for the generated value part of the IE.
+ * \param[in] cont user provided input data struct.
+ * \returns length of encoded octets, -EINVAL on error. */
+int bssgp_enc_ran_inf_rim_cont(uint8_t *buf, size_t len, const struct bssgp_ran_inf_rim_cont *cont)
+{
+ uint8_t *buf_ptr = buf;
+ int app_cont_len = 0;
+ int remaining_buf_len;
+
+ buf_ptr = enc_rim_cont_common(buf_ptr, len, (struct bssgp_ran_inf_x_cont *)cont);
+ if (!buf_ptr)
+ return -EINVAL;
+
+ remaining_buf_len = len - (int)(buf_ptr - buf);
+ if (remaining_buf_len <= 0)
+ return -EINVAL;
+
+ if (cont->app_err) {
+ switch (cont->app_id) {
+ case BSSGP_RAN_INF_APP_ID_NACC:
+ app_cont_len =
+ bssgp_enc_app_err_cont_nacc(buf_ptr + TVLV_HDR_LEN, remaining_buf_len - TVLV_HDR_MAXLEN,
+ &cont->u.app_err_cont_nacc);
+ break;
+ case BSSGP_RAN_INF_APP_ID_SI3:
+ case BSSGP_RAN_INF_APP_ID_MBMS:
+ case BSSGP_RAN_INF_APP_ID_SON:
+ case BSSGP_RAN_INF_APP_ID_UTRA_SI:
+ /* TODO: add encoders for Si3, MBMS, SON, UTRA-SI app containers */
+ return -EINVAL;
+ default:
+ return -EINVAL;
+ }
+ if (app_cont_len < 0)
+ return -EINVAL;
+ buf_ptr = dub_tlvp_header(buf_ptr, BSSGP_IE_APP_ERROR_CONTAINER, app_cont_len);
+ } else {
+ switch (cont->app_id) {
+ case BSSGP_RAN_INF_APP_ID_NACC:
+ app_cont_len =
+ bssgp_enc_ran_inf_app_cont_nacc(buf_ptr + TVLV_HDR_LEN, remaining_buf_len - TVLV_HDR_MAXLEN,
+ &cont->u.app_cont_nacc);
+ break;
+ case BSSGP_RAN_INF_APP_ID_SI3:
+ case BSSGP_RAN_INF_APP_ID_MBMS:
+ case BSSGP_RAN_INF_APP_ID_SON:
+ case BSSGP_RAN_INF_APP_ID_UTRA_SI:
+ /* TODO: add encoders for Si3, MBMS, SON, UTRA-SI app containers */
+ return -EINVAL;
+ default:
+ return -EINVAL;
+ }
+ if (app_cont_len < 0)
+ return -EINVAL;
+ buf_ptr = dub_tlvp_header(buf_ptr, BSSGP_IE_RAN_INFO_APP_CONTAINER, app_cont_len);
+ }
+
+ remaining_buf_len = len - (int)(buf_ptr - buf);
+ if (remaining_buf_len < 0)
+ return -EINVAL;
+
+ if (cont->son_trans_app_id && cont->son_trans_app_id_len > 0) {
+ if (remaining_buf_len < cont->son_trans_app_id_len + TVLV_HDR_MAXLEN)
+ return -EINVAL;
+ buf_ptr =
+ tvlv_put(buf_ptr, BSSGP_IE_SON_TRANSFER_APP_ID, cont->son_trans_app_id_len, cont->son_trans_app_id);
+ }
+ return (int)(buf_ptr - buf);
+}
+
+/*! Decode a RAN Information ACK RIM Container (3GPP TS 48.018, table 11.3.62a.3.b).
+ * \param[out] user provided memory for decoded data struct.
+ * \param[in] buf user provided memory with the encoded value data of the IE.
+ * \returns 0 on success, -EINVAL on error. */
+int bssgp_dec_ran_inf_ack_rim_cont(struct bssgp_ran_inf_ack_rim_cont *cont, const uint8_t *buf, size_t len)
+{
+ int rc;
+ struct tlv_parsed tp;
+
+ memset(cont, 0, sizeof(*cont));
+
+ rc = tlv_parse(&tp, &tvlv_att_def, buf, len, 0, 0);
+ if (rc < 0)
+ return -EINVAL;
+
+ if (TLVP_PRES_LEN(&tp, BSSGP_IE_RIM_APP_IDENTITY, sizeof(uint8_t)))
+ cont->app_id = TLVP_VAL(&tp, BSSGP_IE_RIM_APP_IDENTITY)[0];
+ else
+ return -EINVAL;
+
+ if (TLVP_PRES_LEN(&tp, BSSGP_IE_RIM_SEQ_NR, sizeof(cont->seq_num)))
+ cont->seq_num = tlvp_val32be(&tp, BSSGP_IE_RIM_SEQ_NR);
+ else
+ return -EINVAL;
+
+ if (TLVP_PRES_LEN(&tp, BSSGP_IE_RIM_PROTOCOL_VERSION, sizeof(cont->prot_ver)))
+ cont->prot_ver = TLVP_VAL(&tp, BSSGP_IE_RIM_PROTOCOL_VERSION)[0];
+ else
+ cont->prot_ver = 1;
+
+ if (TLVP_PRES_LEN(&tp, BSSGP_IE_SON_TRANSFER_APP_ID, 1)) {
+ cont->son_trans_app_id = TLVP_VAL(&tp, BSSGP_IE_SON_TRANSFER_APP_ID);
+ cont->son_trans_app_id_len = TLVP_LEN(&tp, BSSGP_IE_SON_TRANSFER_APP_ID);
+ }
+
+ return 0;
+}
+
+/*! Encode a RAN Information ACK RIM Container (3GPP TS 48.018, table 11.3.62a.3.b).
+ * \param[out] buf user provided memory for the generated value part of the IE.
+ * \param[in] cont user provided input data struct.
+ * \returns length of encoded octets, -EINVAL on error. */
+int bssgp_enc_ran_inf_ack_rim_cont(uint8_t *buf, size_t len, const struct bssgp_ran_inf_ack_rim_cont *cont)
+{
+ uint8_t *buf_ptr = buf;
+ uint32_t seq_num = osmo_htonl(cont->seq_num);
+ uint8_t app_id_temp;
+
+ if (len <
+ 4 * TVLV_HDR_MAXLEN + sizeof(app_id_temp) + sizeof(seq_num) + sizeof(cont->prot_ver) +
+ cont->son_trans_app_id_len)
+ return -EINVAL;
+
+ app_id_temp = cont->app_id;
+ buf_ptr = tvlv_put(buf_ptr, BSSGP_IE_RIM_APP_IDENTITY, sizeof(app_id_temp), &app_id_temp);
+ buf_ptr = tvlv_put(buf_ptr, BSSGP_IE_RIM_SEQ_NR, sizeof(seq_num), (uint8_t *) & seq_num);
+
+ if (cont->prot_ver > 0)
+ buf_ptr = tvlv_put(buf_ptr, BSSGP_IE_RIM_PROTOCOL_VERSION, sizeof(cont->prot_ver), &cont->prot_ver);
+
+ if (cont->son_trans_app_id && cont->son_trans_app_id_len > 0)
+ buf_ptr =
+ tvlv_put(buf_ptr, BSSGP_IE_SON_TRANSFER_APP_ID, cont->son_trans_app_id_len, cont->son_trans_app_id);
+
+ return (int)(buf_ptr - buf);
+}
+
+/*! Decode a RAN Information Error RIM Container (3GPP TS 48.018, table 11.3.62a.4.b).
+ * \param[out] user provided memory for decoded data struct.
+ * \param[in] buf user provided memory with the encoded value data of the IE.
+ * \returns 0 on success, -EINVAL on error. */
+int bssgp_dec_ran_inf_err_rim_cont(struct bssgp_ran_inf_err_rim_cont *cont, const uint8_t *buf, size_t len)
+{
+ int rc;
+ struct tlv_parsed tp;
+
+ memset(cont, 0, sizeof(*cont));
+
+ rc = tlv_parse(&tp, &tvlv_att_def, buf, len, 0, 0);
+ if (rc < 0)
+ return -EINVAL;
+
+ if (TLVP_PRES_LEN(&tp, BSSGP_IE_RIM_APP_IDENTITY, sizeof(uint8_t)))
+ cont->app_id = TLVP_VAL(&tp, BSSGP_IE_RIM_APP_IDENTITY)[0];
+ else
+ return -EINVAL;
+
+ if (TLVP_PRES_LEN(&tp, BSSGP_IE_CAUSE, sizeof(cont->cause)))
+ cont->cause = TLVP_VAL(&tp, BSSGP_IE_CAUSE)[0];
+ else
+ return -EINVAL;
+
+ if (TLVP_PRES_LEN(&tp, BSSGP_IE_RIM_PROTOCOL_VERSION, sizeof(cont->prot_ver)))
+ cont->prot_ver = TLVP_VAL(&tp, BSSGP_IE_RIM_PROTOCOL_VERSION)[0];
+ else
+ cont->prot_ver = 1;
+
+ if (TLVP_PRESENT(&tp, BSSGP_IE_PDU_IN_ERROR)) {
+ cont->err_pdu = TLVP_VAL(&tp, BSSGP_IE_PDU_IN_ERROR);
+ cont->err_pdu_len = TLVP_LEN(&tp, BSSGP_IE_PDU_IN_ERROR);
+ } else {
+ return -EINVAL;
+ }
+
+ if (TLVP_PRES_LEN(&tp, BSSGP_IE_SON_TRANSFER_APP_ID, 1)) {
+ cont->son_trans_app_id = TLVP_VAL(&tp, BSSGP_IE_SON_TRANSFER_APP_ID);
+ cont->son_trans_app_id_len = TLVP_LEN(&tp, BSSGP_IE_SON_TRANSFER_APP_ID);
+ }
+
+ return 0;
+}
+
+/*! Encode a RAN Information Error RIM Container (3GPP TS 48.018, table 11.3.62a.4.b).
+ * \param[out] buf user provided memory for the generated value part of the IE.
+ * \param[in] cont user provided input data struct.
+ * \returns length of encoded octets, -EINVAL on error. */
+int bssgp_enc_ran_inf_err_rim_cont(uint8_t *buf, size_t len, const struct bssgp_ran_inf_err_rim_cont *cont)
+{
+ uint8_t *buf_ptr = buf;
+ uint8_t app_id_temp;
+
+ if (len <
+ TVLV_HDR_MAXLEN * 5 + sizeof(app_id_temp) + sizeof(cont->cause) + sizeof(cont->prot_ver) +
+ cont->err_pdu_len + cont->son_trans_app_id_len)
+ return -EINVAL;
+
+ app_id_temp = cont->app_id;
+ buf_ptr = tvlv_put(buf_ptr, BSSGP_IE_RIM_APP_IDENTITY, sizeof(app_id_temp), &app_id_temp);
+ buf_ptr = tvlv_put(buf_ptr, BSSGP_IE_CAUSE, sizeof(cont->cause), &cont->cause);
+
+ if (cont->prot_ver > 0)
+ buf_ptr = tvlv_put(buf_ptr, BSSGP_IE_RIM_PROTOCOL_VERSION, sizeof(cont->prot_ver), &cont->prot_ver);
+
+ if (cont->err_pdu && cont->err_pdu_len > 0)
+ buf_ptr = tvlv_put(buf_ptr, BSSGP_IE_PDU_IN_ERROR, cont->err_pdu_len, cont->err_pdu);
+ else
+ return -EINVAL;
+
+ if (cont->son_trans_app_id && cont->son_trans_app_id_len > 0)
+ buf_ptr =
+ tvlv_put(buf_ptr, BSSGP_IE_SON_TRANSFER_APP_ID, cont->son_trans_app_id_len, cont->son_trans_app_id);
+
+ return (int)(buf_ptr - buf);
+}
+
+/*! Decode a RAN Information Application Error RIM Container (3GPP TS 48.018, table 11.3.62a.5.b).
+ * \param[out] user provided memory for decoded data struct.
+ * \param[in] buf user provided memory with the encoded value data of the IE.
+ * \returns 0 on success, -EINVAL on error. */
+int bssgp_dec_ran_inf_app_err_rim_cont(struct bssgp_ran_inf_app_err_rim_cont *cont, const uint8_t *buf, size_t len)
+{
+ int rc;
+ struct tlv_parsed tp;
+
+ memset(cont, 0, sizeof(*cont));
+
+ rc = tlv_parse(&tp, &tvlv_att_def, buf, len, 0, 0);
+ if (rc < 0)
+ return -EINVAL;
+
+ rc = dec_rim_cont_common((struct bssgp_ran_inf_x_cont *)cont, &tp);
+ if (rc < 0)
+ return -EINVAL;
+
+ switch (cont->app_id) {
+ case BSSGP_RAN_INF_APP_ID_NACC:
+ rc = bssgp_dec_app_err_cont_nacc(&cont->u.app_err_cont_nacc,
+ TLVP_VAL(&tp, BSSGP_IE_APP_ERROR_CONTAINER), TLVP_LEN(&tp,
+ BSSGP_IE_APP_ERROR_CONTAINER));
+ break;
+ case BSSGP_RAN_INF_APP_ID_SI3:
+ case BSSGP_RAN_INF_APP_ID_MBMS:
+ case BSSGP_RAN_INF_APP_ID_SON:
+ case BSSGP_RAN_INF_APP_ID_UTRA_SI:
+ /* TODO: add parsers for Si3, MBMS, SON, UTRA-SI app containers */
+ return -EINVAL;
+ default:
+ return -EINVAL;
+ }
+ if (rc < 0)
+ return rc;
+
+ return 0;
+}
+
+/*! Encode a RAN Information Application Error RIM Container (3GPP TS 48.018, table 11.3.62a.5.b).
+ * \param[out] buf user provided memory for the generated value part of the IE.
+ * \param[in] cont user provided input data struct.
+ * \returns length of encoded octets, -EINVAL on error. */
+int bssgp_enc_ran_inf_app_err_rim_cont(uint8_t *buf, size_t len, const struct bssgp_ran_inf_app_err_rim_cont *cont)
+{
+ uint8_t *buf_ptr = buf;
+ int app_cont_len = 0;
+ int remaining_buf_len;
+
+ buf_ptr = enc_rim_cont_common(buf_ptr, len, (struct bssgp_ran_inf_x_cont *)cont);
+ if (!buf_ptr)
+ return -EINVAL;
+
+ remaining_buf_len = len - (int)(buf_ptr - buf);
+ if (remaining_buf_len <= 0)
+ return -EINVAL;
+
+ switch (cont->app_id) {
+ case BSSGP_RAN_INF_APP_ID_NACC:
+ app_cont_len =
+ bssgp_enc_app_err_cont_nacc(buf_ptr + TVLV_HDR_LEN, remaining_buf_len - TVLV_HDR_MAXLEN,
+ &cont->u.app_err_cont_nacc);
+ break;
+ case BSSGP_RAN_INF_APP_ID_SI3:
+ case BSSGP_RAN_INF_APP_ID_MBMS:
+ case BSSGP_RAN_INF_APP_ID_SON:
+ case BSSGP_RAN_INF_APP_ID_UTRA_SI:
+ /* TODO: add encoders for Si3, MBMS, SON, UTRA-SI app containers */
+ return -EINVAL;
+ default:
+ return -EINVAL;
+ }
+ if (app_cont_len < 0)
+ return -EINVAL;
+ buf_ptr = dub_tlvp_header(buf_ptr, BSSGP_IE_APP_ERROR_CONTAINER, app_cont_len);
+
+ return (int)(buf_ptr - buf);
+}
diff --git a/src/gb/libosmogb.map b/src/gb/libosmogb.map
index 5c029b04..b012184e 100644
--- a/src/gb/libosmogb.map
+++ b/src/gb/libosmogb.map
@@ -3,7 +3,23 @@ global:
bssgp_cause_str;
bssgp_create_cell_id;
bssgp_create_rim_ri;
+bssgp_dec_app_err_cont_nacc;
+bssgp_dec_ran_inf_ack_rim_cont;
+bssgp_dec_ran_inf_err_rim_cont;
+bssgp_dec_ran_inf_req_app_cont_nacc;
+bssgp_dec_ran_inf_req_rim_cont;
+bssgp_dec_ran_inf_app_cont_nacc;
+bssgp_dec_ran_inf_app_err_rim_cont;
+bssgp_dec_ran_inf_rim_cont;
bssgp_pdu_str;
+bssgp_enc_app_err_cont_nacc;
+bssgp_enc_ran_inf_ack_rim_cont;
+bssgp_enc_ran_inf_err_rim_cont;
+bssgp_enc_ran_inf_req_app_cont_nacc;
+bssgp_enc_ran_inf_req_rim_cont;
+bssgp_enc_ran_inf_app_cont_nacc;
+bssgp_enc_ran_inf_app_err_rim_cont;
+bssgp_enc_ran_inf_rim_cont;
bssgp_fc_in;
bssgp_fc_init;
bssgp_fc_ms_init;
diff --git a/tests/Makefile.am b/tests/Makefile.am
index e0220bd8..10306aab 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -75,7 +75,7 @@ check_PROGRAMS += \
endif
if ENABLE_GB
-check_PROGRAMS += gb/bssgp_fc_test gb/gprs_bssgp_test gb/gprs_ns_test gb/gprs_ns2_test fr/fr_test
+check_PROGRAMS += gb/bssgp_fc_test gb/gprs_bssgp_test gb/gprs_bssgp_rim_test gb/gprs_ns_test gb/gprs_ns2_test fr/fr_test
endif
utils_utils_test_SOURCES = utils/utils_test.c
@@ -176,6 +176,10 @@ gb_gprs_bssgp_test_LDADD = $(LDADD) $(top_builddir)/src/gb/libosmogb.la $(LIBRAR
$(top_builddir)/src/gsm/libosmogsm.la \
$(top_builddir)/src/gb/libosmogb.la
+gb_gprs_bssgp_rim_test_SOURCES = gb/gprs_bssgp_rim_test.c
+gb_gprs_bssgp_rim_test_LDADD = $(LDADD) $(top_builddir)/src/gb/libosmogb.la $(LIBRARY_DLSYM) \
+ $(top_builddir)/src/gb/libosmogb.la
+
gb_gprs_ns_test_SOURCES = gb/gprs_ns_test.c
gb_gprs_ns_test_LDADD = $(LDADD) $(top_builddir)/src/gb/libosmogb.la $(LIBRARY_DLSYM) \
$(top_builddir)/src/vty/libosmovty.la \
@@ -334,6 +338,7 @@ EXTRA_DIST = testsuite.at $(srcdir)/package.m4 $(TESTSUITE) \
gsm0808/gsm0808_test.ok gb/bssgp_fc_tests.err \
gb/bssgp_fc_tests.ok gb/bssgp_fc_tests.sh \
gb/gprs_bssgp_test.ok gb/gprs_ns_test.ok gea/gea_test.ok \
+ gb/gprs_bssgp_rim_test.ok \
gb/gprs_ns2_vty.vty gb/osmoappdesc.py gb/osmo-ns-dummy.cfg \
gb/gprs_ns2_test.ok \
gprs/gprs_test.ok kasumi/kasumi_test.ok \
diff --git a/tests/gb/gprs_bssgp_rim_test.c b/tests/gb/gprs_bssgp_rim_test.c
new file mode 100644
index 00000000..8c6a00d0
--- /dev/null
+++ b/tests/gb/gprs_bssgp_rim_test.c
@@ -0,0 +1,664 @@
+/* Test routines for the BSSGP implementation in libosmogb
+ *
+ * (C) 2020 by sysmocom - s.f.m.c. GmbH
+ * Author: Philipp Maier <pmaier@sysmocom.de>
+ *
+ * Skeleton based on bssgp_fc_test.c
+ * (C) 2012 by Harald Welte <laforge@gnumonks.org>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#undef _GNU_SOURCE
+#define _GNU_SOURCE
+
+#include <osmocom/core/application.h>
+#include <osmocom/core/utils.h>
+#include <osmocom/gprs/gprs_bssgp.h>
+#include <osmocom/gprs/gprs_ns.h>
+#include <osmocom/gprs/gprs_bssgp_rim.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+
+void dump_bssgp_ran_inf_req_app_cont_nacc(struct bssgp_ran_inf_req_app_cont_nacc *app_cont)
+{
+ printf(" app_cont: bssgp_ran_inf_req_app_cont_nacc:\n");
+ printf(" reprt_cell.rai.lac.plmn.mcc = %u\n", app_cont->reprt_cell.rai.lac.plmn.mcc);
+ printf(" reprt_cell.rai.lac.plmn.mnc = %u\n", app_cont->reprt_cell.rai.lac.plmn.mnc);
+ printf(" reprt_cell.rai.lac.plmn.mnc_3_digits = %u\n", app_cont->reprt_cell.rai.lac.plmn.mnc_3_digits);
+ printf(" reprt_cell.rai.lac.lac = %u\n", app_cont->reprt_cell.rai.lac.lac);
+ printf(" reprt_cell.rai.rac = %u\n", app_cont->reprt_cell.rai.rac);
+ printf(" reprt_cell.cell_identity = %04x\n", app_cont->reprt_cell.cell_identity);
+}
+
+void dump_bssgp_ran_inf_req_rim_cont(struct bssgp_ran_inf_req_rim_cont *rim_cont)
+{
+ printf("bssgp_ran_inf_req_rim_cont:\n");
+ printf(" app_id = %02x\n", rim_cont->app_id);
+ printf(" seq_num = %08x\n", rim_cont->seq_num);
+ printf(" pdu_ind.ack_requested = %u\n", rim_cont->pdu_ind.ack_requested);
+ printf(" pdu_ind.pdu_type_ext = %u\n", rim_cont->pdu_ind.pdu_type_ext);
+ printf(" prot_ver = %u\n", rim_cont->prot_ver);
+ switch (rim_cont->app_id) {
+ case BSSGP_RAN_INF_APP_ID_NACC:
+ dump_bssgp_ran_inf_req_app_cont_nacc(&rim_cont->u.app_cont_nacc);
+ break;
+ case BSSGP_RAN_INF_APP_ID_SI3:
+ case BSSGP_RAN_INF_APP_ID_MBMS:
+ case BSSGP_RAN_INF_APP_ID_SON:
+ case BSSGP_RAN_INF_APP_ID_UTRA_SI:
+ printf(" app_cont: (not implemented yet)\n");
+ break;
+ default:
+ printf(" app_cont: (illegal application identifier)\n");
+ }
+ if (rim_cont->son_trans_app_id) {
+ printf(" son_trans_app_id: %s\n",
+ osmo_hexdump_nospc(rim_cont->son_trans_app_id, rim_cont->son_trans_app_id_len));
+ printf(" son_trans_app_id_len: %lu\n", rim_cont->son_trans_app_id_len);
+ }
+}
+
+static void test_bssgp_dec_ran_inf_req_rim_cont_nacc()
+{
+ int rc;
+ struct bssgp_ran_inf_req_rim_cont rim_cont_dec;
+ uint8_t testvec[] =
+ { 0x4b, 0x81, 0x01, 0x4c, 0x84, 0x00, 0x00, 0x00, 0x01, 0x4f, 0x81, 0x02, 0x55, 0x81, 0x01, 0x4d, 0x88,
+ 0x62, 0xf2, 0x24, 0x33, 0x90, 0x00, 0x51, 0xe1 };
+
+ printf("----- %s START\n", __func__);
+
+ rc = bssgp_dec_ran_inf_req_rim_cont(&rim_cont_dec, testvec, sizeof(testvec));
+ printf("rc=%d, ", rc);
+ if (rc == 0)
+ dump_bssgp_ran_inf_req_rim_cont(&rim_cont_dec);
+
+ printf("----- %s END\n", __func__);
+}
+
+static void test_bssgp_enc_ran_inf_req_rim_cont_nacc()
+{
+ int rc;
+ struct bssgp_ran_inf_req_rim_cont rim_cont = { };
+ uint8_t result[256];
+ printf("----- %s START\n", __func__);
+
+ rim_cont.app_id = BSSGP_RAN_INF_APP_ID_NACC;
+ rim_cont.seq_num = 1;
+ rim_cont.pdu_ind.ack_requested = 0;
+ rim_cont.pdu_ind.pdu_type_ext = 1;
+ rim_cont.prot_ver = 1;
+ rim_cont.son_trans_app_id = NULL;
+ rim_cont.son_trans_app_id_len = 0;
+ rim_cont.u.app_cont_nacc.reprt_cell.rai.lac.plmn.mcc = 262;
+ rim_cont.u.app_cont_nacc.reprt_cell.rai.lac.plmn.mnc = 42;
+ rim_cont.u.app_cont_nacc.reprt_cell.rai.lac.plmn.mnc_3_digits = 0;
+ rim_cont.u.app_cont_nacc.reprt_cell.rai.lac.lac = 13200;
+ rim_cont.u.app_cont_nacc.reprt_cell.rai.rac = 0;
+ rim_cont.u.app_cont_nacc.reprt_cell.cell_identity = 0x51e1;
+
+ dump_bssgp_ran_inf_req_rim_cont(&rim_cont);
+
+ rc = bssgp_enc_ran_inf_req_rim_cont(result, sizeof(result), &rim_cont);
+ printf("rc=%d, ", rc);
+ if (rc > 0)
+ printf("result=%s", osmo_hexdump_nospc(result, rc));
+ printf("\n");
+ printf("----- %s END\n", __func__);
+}
+
+static void dump_bssgp_ran_inf_app_cont_nacc(struct bssgp_ran_inf_app_cont_nacc *app_cont)
+{
+ unsigned int i;
+ unsigned int silen;
+ printf(" app_cont: bssgp_ran_inf_app_cont_nacc:\n");
+ printf(" reprt_cell.rai.lac.plmn.mcc = %u\n", app_cont->reprt_cell.rai.lac.plmn.mcc);
+ printf(" reprt_cell.rai.lac.plmn.mnc = %u\n", app_cont->reprt_cell.rai.lac.plmn.mnc);
+ printf(" reprt_cell.rai.lac.plmn.mnc_3_digits = %u\n", app_cont->reprt_cell.rai.lac.plmn.mnc_3_digits);
+ printf(" reprt_cell.rai.lac.lac = %u\n", app_cont->reprt_cell.rai.lac.lac);
+ printf(" reprt_cell.rai.rac = %u\n", app_cont->reprt_cell.rai.rac);
+ printf(" reprt_cell.cell_identity = %04x\n", app_cont->reprt_cell.cell_identity);
+ printf(" type_psi = %u\n", app_cont->type_psi);
+ printf(" num_si = %u\n", app_cont->num_si);
+
+ if (app_cont->type_psi)
+ silen = 22;
+ else
+ silen = 21;
+
+ for (i = 0; i < app_cont->num_si; i++)
+ printf(" si[%u] = %s\n", i, osmo_hexdump_nospc(app_cont->si[i], silen));
+}
+
+static void dump_bssgp_app_err_cont_nacc(struct bssgp_app_err_cont_nacc *app_cont)
+{
+ printf(" app_err_cont: bssgp_app_err_cont_nacc:\n");
+ printf(" macc_cause = %02x\n", app_cont->nacc_cause);
+ if (app_cont->err_app_cont) {
+ printf(" err_app_cont: %s\n", osmo_hexdump_nospc(app_cont->err_app_cont, app_cont->err_app_cont_len));
+ printf(" err_app_cont_len: %lu\n", app_cont->err_app_cont_len);
+ }
+}
+
+static void dump_bssgp_ran_inf_rim_cont(struct bssgp_ran_inf_rim_cont *rim_cont)
+{
+ printf("bssgp_ran_inf_rim_cont:\n");
+ printf(" app_id = %02x\n", rim_cont->app_id);
+ printf(" seq_num = %08x\n", rim_cont->seq_num);
+ printf(" pdu_ind.ack_requested = %u\n", rim_cont->pdu_ind.ack_requested);
+ printf(" pdu_ind.pdu_type_ext = %u\n", rim_cont->pdu_ind.pdu_type_ext);
+ printf(" prot_ver = %u\n", rim_cont->prot_ver);
+ printf(" app_err = %u\n", rim_cont->app_err);
+ if (rim_cont->app_err) {
+ switch (rim_cont->app_id) {
+ case BSSGP_RAN_INF_APP_ID_NACC:
+ dump_bssgp_app_err_cont_nacc(&rim_cont->u.app_err_cont_nacc);
+ break;
+ case BSSGP_RAN_INF_APP_ID_SI3:
+ case BSSGP_RAN_INF_APP_ID_MBMS:
+ case BSSGP_RAN_INF_APP_ID_SON:
+ case BSSGP_RAN_INF_APP_ID_UTRA_SI:
+ printf(" app_err_cont: (not implemented yet)\n");
+ break;
+ default:
+ printf(" app_err_cont: (illegal application identifier)\n");
+ }
+ } else {
+ switch (rim_cont->app_id) {
+ case BSSGP_RAN_INF_APP_ID_NACC:
+ dump_bssgp_ran_inf_app_cont_nacc(&rim_cont->u.app_cont_nacc);
+ break;
+ case BSSGP_RAN_INF_APP_ID_SI3:
+ case BSSGP_RAN_INF_APP_ID_MBMS:
+ case BSSGP_RAN_INF_APP_ID_SON:
+ case BSSGP_RAN_INF_APP_ID_UTRA_SI:
+ printf(" app_cont: (not implemented yet)\n");
+ break;
+ default:
+ printf(" app_cont: (illegal application identifier)\n");
+ }
+ }
+ if (rim_cont->son_trans_app_id) {
+ printf(" son_trans_app_id: %s\n",
+ osmo_hexdump_nospc(rim_cont->son_trans_app_id, rim_cont->son_trans_app_id_len));
+ printf(" son_trans_app_id_len: %lu\n", rim_cont->son_trans_app_id_len);
+ }
+}
+
+static void test_bssgp_dec_ran_inf_rim_cont_nacc()
+{
+ int rc;
+ struct bssgp_ran_inf_rim_cont rim_cont_dec;
+ uint8_t testvec[] =
+ { 0x4b, 0x81, 0x01, 0x4c, 0x84, 0x00, 0x00, 0x00, 0x02, 0x4f, 0x81, 0x02, 0x55, 0x81, 0x01, 0x4e, 0xc8,
+ 0x62, 0xf2, 0x24, 0x33, 0x4f, 0x00, 0x51, 0xe0, 0x06, 0x19, 0x8f, 0xb1, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x79, 0x00, 0x00, 0x2b, 0x1b, 0x75, 0x30, 0x00, 0xf1, 0x10,
+ 0x23, 0x6e,
+ 0xc9, 0x03, 0x3c, 0x27, 0x47, 0x40, 0x79, 0x00, 0x00, 0x3c, 0x0b, 0x2b, 0x2b, 0x00, 0x90, 0x00, 0x18,
+ 0x5a, 0x6f,
+ 0xc9, 0xe0, 0x84, 0x10, 0xab, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b
+ };
+
+ printf("----- %s START\n", __func__);
+
+ rc = bssgp_dec_ran_inf_rim_cont(&rim_cont_dec, testvec, sizeof(testvec));
+ printf("rc=%d, ", rc);
+ if (rc == 0)
+ dump_bssgp_ran_inf_rim_cont(&rim_cont_dec);
+
+ printf("----- %s END\n", __func__);
+}
+
+static void test_bssgp_dec_ran_inf_rim_cont_err_nacc()
+{
+ int rc;
+ struct bssgp_ran_inf_rim_cont rim_cont_dec;
+ uint8_t testvec[] =
+ { 0x4b, 0x81, 0x01, 0x4c, 0x84, 0x00, 0x00, 0x00, 0x01, 0x4f, 0x81, 0x02, 0x55, 0x81, 0x01, 0x56, 0x86,
+ 0x01, 0xaa, 0xbb, 0xcc, 0xdd, 0xee };
+
+ printf("----- %s START\n", __func__);
+
+ rc = bssgp_dec_ran_inf_rim_cont(&rim_cont_dec, testvec, sizeof(testvec));
+ printf("rc=%d, ", rc);
+ if (rc == 0)
+ dump_bssgp_ran_inf_rim_cont(&rim_cont_dec);
+
+ printf("----- %s END\n", __func__);
+}
+
+static void test_bssgp_enc_ran_inf_rim_cont_nacc()
+{
+ int rc;
+ struct bssgp_ran_inf_rim_cont rim_cont = { };
+
+ uint8_t si1[] =
+ { 0x19, 0x8f, 0xb1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x79, 0x00, 0x00, 0x2b
+ };
+ uint8_t si3[] =
+ { 0x1b, 0x75, 0x30, 0x00, 0xf1, 0x10, 0x23, 0x6e, 0xc9, 0x03, 0x3c, 0x27, 0x47, 0x40, 0x79, 0x00, 0x00,
+ 0x3c, 0x0b, 0x2b, 0x2b
+ };
+ uint8_t si13[] =
+ { 0x00, 0x90, 0x00, 0x18, 0x5a, 0x6f, 0xc9, 0xe0, 0x84, 0x10, 0xab, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b,
+ 0x2b, 0x2b, 0x2b, 0x2b
+ };
+
+ uint8_t result[256];
+ printf("----- %s START\n", __func__);
+
+ rim_cont.app_id = BSSGP_RAN_INF_APP_ID_NACC;
+ rim_cont.seq_num = 1;
+ rim_cont.pdu_ind.ack_requested = 0;
+ rim_cont.pdu_ind.pdu_type_ext = 1;
+ rim_cont.prot_ver = 1;
+ rim_cont.son_trans_app_id = NULL;
+ rim_cont.son_trans_app_id_len = 0;
+ rim_cont.app_err = false;
+ rim_cont.u.app_cont_nacc.reprt_cell.rai.lac.plmn.mcc = 262;
+ rim_cont.u.app_cont_nacc.reprt_cell.rai.lac.plmn.mnc = 42;
+ rim_cont.u.app_cont_nacc.reprt_cell.rai.lac.plmn.mnc_3_digits = 0;
+ rim_cont.u.app_cont_nacc.reprt_cell.rai.lac.lac = 13135;
+ rim_cont.u.app_cont_nacc.reprt_cell.rai.rac = 0;
+ rim_cont.u.app_cont_nacc.reprt_cell.cell_identity = 0x51e0;
+ rim_cont.u.app_cont_nacc.type_psi = 0;
+ rim_cont.u.app_cont_nacc.num_si = 3;
+ rim_cont.u.app_cont_nacc.si[0] = si1;
+ rim_cont.u.app_cont_nacc.si[1] = si3;
+ rim_cont.u.app_cont_nacc.si[2] = si13;
+
+ dump_bssgp_ran_inf_rim_cont(&rim_cont);
+
+ rc = bssgp_enc_ran_inf_rim_cont(result, sizeof(result), &rim_cont);
+ printf("rc=%d, ", rc);
+ if (rc > 0)
+ printf("result=%s", osmo_hexdump_nospc(result, rc));
+ printf("\n");
+ printf("----- %s END\n", __func__);
+}
+
+static void test_bssgp_enc_ran_inf_rim_cont_err_nacc()
+{
+ int rc;
+ struct bssgp_ran_inf_rim_cont rim_cont = { };
+ uint8_t err_app_cont[] = { 0xaa, 0xbb, 0xcc, 0xdd, 0xee };
+
+ uint8_t result[256];
+ printf("----- %s START\n", __func__);
+
+ rim_cont.app_id = BSSGP_RAN_INF_APP_ID_NACC;
+ rim_cont.seq_num = 1;
+ rim_cont.pdu_ind.ack_requested = 0;
+ rim_cont.pdu_ind.pdu_type_ext = 1;
+ rim_cont.prot_ver = 1;
+ rim_cont.son_trans_app_id = NULL;
+ rim_cont.son_trans_app_id_len = 0;
+ rim_cont.app_err = true;
+ rim_cont.u.app_err_cont_nacc.nacc_cause = BSSGP_NACC_CAUSE_SYNTAX_ERR;
+ rim_cont.u.app_err_cont_nacc.err_app_cont = err_app_cont;
+ rim_cont.u.app_err_cont_nacc.err_app_cont_len = sizeof(err_app_cont);
+ dump_bssgp_ran_inf_rim_cont(&rim_cont);
+
+ rc = bssgp_enc_ran_inf_rim_cont(result, sizeof(result), &rim_cont);
+ printf("rc=%d, ", rc);
+ if (rc > 0)
+ printf("result=%s", osmo_hexdump_nospc(result, rc));
+ printf("\n");
+ printf("----- %s END\n", __func__);
+}
+
+static void dump_bssgp_ran_inf_ack_rim_cont(struct bssgp_ran_inf_ack_rim_cont *rim_cont)
+{
+ printf("bssgp_ran_inf_ack_rim_cont:\n");
+ printf(" app_id = %02x\n", rim_cont->app_id);
+ printf(" seq_num = %08x\n", rim_cont->seq_num);
+ printf(" prot_ver = %u\n", rim_cont->prot_ver);
+ if (rim_cont->son_trans_app_id) {
+ printf(" son_trans_app_id: %s\n",
+ osmo_hexdump_nospc(rim_cont->son_trans_app_id, rim_cont->son_trans_app_id_len));
+ printf(" son_trans_app_id_len: %lu\n", rim_cont->son_trans_app_id_len);
+ }
+}
+
+static void test_bssgp_dec_ran_inf_ack_rim_cont()
+{
+ int rc;
+ struct bssgp_ran_inf_ack_rim_cont rim_cont_dec;
+ uint8_t testvec[] = { 0x4b, 0x81, 0x01, 0x4c, 0x84, 0x00, 0x00, 0x00, 0x01, 0x55, 0x81, 0x01 };
+
+ printf("----- %s START\n", __func__);
+
+ rc = bssgp_dec_ran_inf_ack_rim_cont(&rim_cont_dec, testvec, sizeof(testvec));
+ printf("rc=%d, ", rc);
+ if (rc == 0)
+ dump_bssgp_ran_inf_ack_rim_cont(&rim_cont_dec);
+
+ printf("----- %s END\n", __func__);
+}
+
+static void test_bssgp_enc_ran_inf_ack_rim_cont()
+{
+ int rc;
+ struct bssgp_ran_inf_ack_rim_cont rim_cont = { };
+ uint8_t result[256];
+ printf("----- %s START\n", __func__);
+
+ rim_cont.app_id = BSSGP_RAN_INF_APP_ID_NACC;
+ rim_cont.seq_num = 1;
+ rim_cont.prot_ver = 1;
+ rim_cont.son_trans_app_id = NULL;
+ rim_cont.son_trans_app_id_len = 0;
+ dump_bssgp_ran_inf_ack_rim_cont(&rim_cont);
+
+ rc = bssgp_enc_ran_inf_ack_rim_cont(result, sizeof(result), &rim_cont);
+ printf("rc=%d, ", rc);
+ if (rc > 0)
+ printf("result=%s", osmo_hexdump_nospc(result, rc));
+ printf("\n");
+ printf("----- %s END\n", __func__);
+}
+
+void dump_bssgp_ran_inf_err_rim_cont(struct bssgp_ran_inf_err_rim_cont *rim_cont)
+{
+ printf("bssgp_ran_inf_err_rim_cont:\n");
+ printf(" app_id = %02x\n", rim_cont->app_id);
+ printf(" cause = %02x\n", rim_cont->cause);
+ printf(" prot_ver = %u\n", rim_cont->prot_ver);
+ if (rim_cont->err_pdu) {
+ printf(" err_pdu: %s\n", osmo_hexdump_nospc(rim_cont->err_pdu, rim_cont->err_pdu_len));
+ printf(" err_pdu_len: %lu\n", rim_cont->err_pdu_len);
+ }
+ if (rim_cont->son_trans_app_id) {
+ printf(" son_trans_app_id: %s\n",
+ osmo_hexdump_nospc(rim_cont->son_trans_app_id, rim_cont->son_trans_app_id_len));
+ printf(" son_trans_app_id_len: %lu\n", rim_cont->son_trans_app_id_len);
+ }
+}
+
+static void test_bssgp_dec_ran_inf_err_rim_cont()
+{
+ int rc;
+ struct bssgp_ran_inf_err_rim_cont rim_cont_dec;
+ uint8_t testvec[] =
+ { 0x4b, 0x81, 0x17, 0x07, 0x81, 0x2b, 0x55, 0x81, 0x01, 0x15, 0x85, 0xaa, 0xbb, 0xcc, 0xdd, 0xee };
+
+ printf("----- %s START\n", __func__);
+
+ rc = bssgp_dec_ran_inf_err_rim_cont(&rim_cont_dec, testvec, sizeof(testvec));
+ printf("rc=%d, ", rc);
+ if (rc == 0)
+ dump_bssgp_ran_inf_err_rim_cont(&rim_cont_dec);
+
+ printf("----- %s END\n", __func__);
+}
+
+static void test_bssgp_enc_ran_inf_err_rim_cont()
+{
+ int rc;
+ struct bssgp_ran_inf_err_rim_cont rim_cont = { };
+ uint8_t err_pdu[] = { 0xaa, 0xbb, 0xcc, 0xdd, 0xee };
+ uint8_t result[256];
+ printf("----- %s START\n", __func__);
+
+ rim_cont.app_id = 23;
+ rim_cont.cause = 0x2b;
+ rim_cont.prot_ver = 1;
+ rim_cont.err_pdu = err_pdu;
+ rim_cont.err_pdu_len = sizeof(err_pdu);
+ rim_cont.son_trans_app_id = NULL;
+ rim_cont.son_trans_app_id_len = 0;
+ dump_bssgp_ran_inf_err_rim_cont(&rim_cont);
+
+ rc = bssgp_enc_ran_inf_err_rim_cont(result, sizeof(result), &rim_cont);
+ printf("rc=%d, ", rc);
+ if (rc > 0)
+ printf("result=%s", osmo_hexdump_nospc(result, rc));
+ printf("\n");
+ printf("----- %s END\n", __func__);
+}
+
+void dump_bssgp_ran_inf_app_err_rim_cont(struct bssgp_ran_inf_app_err_rim_cont *rim_cont)
+{
+ printf("bssgp_ran_inf_app_err_rim_cont:\n");
+ printf(" app_id = %02x\n", rim_cont->app_id);
+ printf(" seq_num = %08x\n", rim_cont->seq_num);
+ printf(" pdu_ind.ack_requested = %u\n", rim_cont->pdu_ind.ack_requested);
+ printf(" pdu_ind.pdu_type_ext = %u\n", rim_cont->pdu_ind.pdu_type_ext);
+ printf(" prot_ver = %u\n", rim_cont->prot_ver);
+ switch (rim_cont->app_id) {
+ case BSSGP_RAN_INF_APP_ID_NACC:
+ dump_bssgp_app_err_cont_nacc(&rim_cont->u.app_err_cont_nacc);
+ break;
+ case BSSGP_RAN_INF_APP_ID_SI3:
+ case BSSGP_RAN_INF_APP_ID_MBMS:
+ case BSSGP_RAN_INF_APP_ID_SON:
+ case BSSGP_RAN_INF_APP_ID_UTRA_SI:
+ printf(" app_err_cont: (not implemented yet)\n");
+ break;
+ default:
+ printf(" app_err_cont: (illegal application identifier)\n");
+ }
+}
+
+static void test_bssgp_dec_ran_inf_app_err_rim_cont_nacc()
+{
+ int rc;
+ struct bssgp_ran_inf_app_err_rim_cont rim_cont_dec;
+ uint8_t testvec[] =
+ { 0x4b, 0x81, 0x01, 0x4c, 0x84, 0x00, 0x00, 0x00, 0x01, 0x4f, 0x81, 0x02, 0x55, 0x81, 0x01, 0x56, 0x85,
+ 0xaa, 0xbb, 0xcc, 0xdd, 0xee
+ };
+
+ printf("----- %s START\n", __func__);
+
+ rc = bssgp_dec_ran_inf_app_err_rim_cont(&rim_cont_dec, testvec, sizeof(testvec));
+ printf("rc=%d, ", rc);
+ if (rc == 0)
+ dump_bssgp_ran_inf_app_err_rim_cont(&rim_cont_dec);
+
+ printf("----- %s END\n", __func__);
+}
+
+static void test_bssgp_enc_ran_inf_app_err_rim_cont_nacc()
+{
+ int rc;
+ struct bssgp_ran_inf_app_err_rim_cont rim_cont = { };
+ uint8_t err_app_cont[] = { 0xaa, 0xbb, 0xcc, 0xdd, 0xee };
+ uint8_t result[256];
+
+ printf("----- %s START\n", __func__);
+ rim_cont.app_id = BSSGP_RAN_INF_APP_ID_NACC;
+ rim_cont.seq_num = 1;
+ rim_cont.pdu_ind.ack_requested = 0;
+ rim_cont.pdu_ind.pdu_type_ext = 1;
+ rim_cont.prot_ver = 1;
+ rim_cont.u.app_err_cont_nacc.nacc_cause = BSSGP_NACC_CAUSE_SYNTAX_ERR;
+ rim_cont.u.app_err_cont_nacc.err_app_cont = err_app_cont;
+ rim_cont.u.app_err_cont_nacc.err_app_cont_len = sizeof(err_app_cont);
+ dump_bssgp_ran_inf_app_err_rim_cont(&rim_cont);
+
+ rc = bssgp_enc_ran_inf_app_err_rim_cont(result, sizeof(result), &rim_cont);
+ printf("rc=%d, ", rc);
+ if (rc > 0)
+ printf("result=%s", osmo_hexdump_nospc(result, rc));
+ printf("\n");
+ printf("----- %s END\n", __func__);
+}
+
+static void test_bssgp_dec_ran_inf_req_app_cont_nacc()
+{
+ int rc;
+ struct bssgp_ran_inf_req_app_cont_nacc app_cont_dec;
+ uint8_t testvec[] = { 0x62, 0xf2, 0x24, 0x33, 0x90, 0x00, 0x51, 0xe1 };
+
+ printf("----- %s START\n", __func__);
+
+ rc = bssgp_dec_ran_inf_req_app_cont_nacc(&app_cont_dec, testvec, sizeof(testvec));
+ printf("rc=%d, ", rc);
+ if (rc == 0)
+ dump_bssgp_ran_inf_req_app_cont_nacc(&app_cont_dec);
+
+ printf("----- %s END\n", __func__);
+}
+
+static void test_bssgp_enc_ran_inf_req_app_cont_nacc()
+{
+ int rc;
+ struct bssgp_ran_inf_req_app_cont_nacc app_cont = { };
+ uint8_t result[256];
+ printf("----- %s START\n", __func__);
+
+ app_cont.reprt_cell.rai.lac.plmn.mcc = 262;
+ app_cont.reprt_cell.rai.lac.plmn.mnc = 42;
+ app_cont.reprt_cell.rai.lac.plmn.mnc_3_digits = 0;
+ app_cont.reprt_cell.rai.lac.lac = 13200;
+ app_cont.reprt_cell.rai.rac = 0;
+ app_cont.reprt_cell.cell_identity = 0x51e1;
+ dump_bssgp_ran_inf_req_app_cont_nacc(&app_cont);
+
+ rc = bssgp_enc_ran_inf_req_app_cont_nacc(result, sizeof(result), &app_cont);
+ printf("rc=%d, ", rc);
+ if (rc > 0)
+ printf("result=%s", osmo_hexdump_nospc(result, rc));
+ printf("\n");
+ printf("----- %s END\n", __func__);
+}
+
+static void test_bssgp_dec_ran_inf_app_cont_nacc()
+{
+ int rc;
+ struct bssgp_ran_inf_app_cont_nacc app_cont_dec;
+ uint8_t testvec[] =
+ { 0x62, 0xf2, 0x24, 0x33, 0x4f, 0x00, 0x51, 0xe0, 0x06, 0x19, 0x8f, 0xb1, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x79, 0x00, 0x00, 0x2b, 0x1b, 0x75, 0x30, 0x00, 0xf1, 0x10,
+ 0x23, 0x6e, 0xc9, 0x03, 0x3c, 0x27, 0x47, 0x40, 0x79, 0x00, 0x00, 0x3c, 0x0b, 0x2b, 0x2b, 0x00, 0x90, 0x00, 0x18,
+ 0x5a, 0x6f, 0xc9, 0xe0, 0x84, 0x10, 0xab, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b };
+
+ printf("----- %s START\n", __func__);
+
+ rc = bssgp_dec_ran_inf_app_cont_nacc(&app_cont_dec, testvec, sizeof(testvec));
+ printf("rc=%d, ", rc);
+ if (rc == 0)
+ dump_bssgp_ran_inf_app_cont_nacc(&app_cont_dec);
+
+ printf("----- %s END\n", __func__);
+}
+
+static void test_bssgp_enc_ran_inf_app_cont_nacc()
+{
+ int rc;
+ struct bssgp_ran_inf_app_cont_nacc app_cont = { };
+
+ uint8_t si1[] =
+ { 0x19, 0x8f, 0xb1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x79, 0x00, 0x00, 0x2b };
+ uint8_t si3[] =
+ { 0x1b, 0x75, 0x30, 0x00, 0xf1, 0x10, 0x23, 0x6e, 0xc9, 0x03, 0x3c, 0x27, 0x47, 0x40, 0x79, 0x00, 0x00,
+ 0x3c, 0x0b, 0x2b, 0x2b };
+ uint8_t si13[] =
+ { 0x00, 0x90, 0x00, 0x18, 0x5a, 0x6f, 0xc9, 0xe0, 0x84, 0x10, 0xab, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b,
+ 0x2b, 0x2b, 0x2b, 0x2b };
+
+ uint8_t result[256];
+ printf("----- %s START\n", __func__);
+
+ app_cont.reprt_cell.rai.lac.plmn.mcc = 262;
+ app_cont.reprt_cell.rai.lac.plmn.mnc = 42;
+ app_cont.reprt_cell.rai.lac.plmn.mnc_3_digits = 0;
+ app_cont.reprt_cell.rai.lac.lac = 13135;
+ app_cont.reprt_cell.rai.rac = 0;
+ app_cont.reprt_cell.cell_identity = 0x51e1;
+ app_cont.type_psi = false;
+ app_cont.num_si = 3;
+ app_cont.si[0] = si1;
+ app_cont.si[1] = si3;
+ app_cont.si[2] = si13;
+ dump_bssgp_ran_inf_app_cont_nacc(&app_cont);
+
+ rc = bssgp_enc_ran_inf_app_cont_nacc(result, sizeof(result), &app_cont);
+ printf("rc=%d, ", rc);
+ if (rc > 0)
+ printf("result=%s", osmo_hexdump_nospc(result, rc));
+ printf("\n");
+ printf("----- %s END\n", __func__);
+}
+
+static void test_bssgp_dec_app_err_cont_nacc()
+{
+ int rc;
+ struct bssgp_app_err_cont_nacc app_cont_dec;
+ uint8_t testvec[] = { 0x01, 0xaa, 0xbb, 0xcc, 0xdd, 0xee };
+
+ printf("----- %s START\n", __func__);
+
+ rc = bssgp_dec_app_err_cont_nacc(&app_cont_dec, testvec, sizeof(testvec));
+ printf("rc=%d, ", rc);
+ if (rc == 0)
+ dump_bssgp_app_err_cont_nacc(&app_cont_dec);
+
+ printf("----- %s END\n", __func__);
+}
+
+static void test_bssgp_enc_app_err_cont_nacc()
+{
+ int rc;
+ struct bssgp_app_err_cont_nacc app_cont = { };
+ uint8_t err_app_cont[] = { 0xaa, 0xbb, 0xcc, 0xdd, 0xee };
+ uint8_t result[256];
+ printf("----- %s START\n", __func__);
+
+ app_cont.nacc_cause = BSSGP_NACC_CAUSE_SYNTAX_ERR;
+ app_cont.err_app_cont = err_app_cont;
+ app_cont.err_app_cont_len = sizeof(err_app_cont);
+ dump_bssgp_app_err_cont_nacc(&app_cont);
+
+ rc = bssgp_enc_app_err_cont_nacc(result, sizeof(result), &app_cont);
+ printf("rc=%d, ", rc);
+ if (rc > 0)
+ printf("result=%s", osmo_hexdump_nospc(result, rc));
+ printf("\n");
+ printf("----- %s END\n", __func__);
+}
+
+int bssgp_prim_cb(struct osmo_prim_hdr *oph, void *ctx)
+{
+ return 0;
+}
+
+int main(int argc, char **argv)
+{
+ printf("===== BSSGP RIM test START\n");
+
+ /* RIM containers */
+ test_bssgp_dec_ran_inf_req_rim_cont_nacc();
+ test_bssgp_enc_ran_inf_req_rim_cont_nacc();
+ test_bssgp_dec_ran_inf_rim_cont_nacc();
+ test_bssgp_dec_ran_inf_rim_cont_err_nacc();
+ test_bssgp_enc_ran_inf_rim_cont_nacc();
+ test_bssgp_enc_ran_inf_rim_cont_err_nacc();
+ test_bssgp_dec_ran_inf_ack_rim_cont();
+ test_bssgp_enc_ran_inf_ack_rim_cont();
+ test_bssgp_dec_ran_inf_err_rim_cont();
+ test_bssgp_enc_ran_inf_err_rim_cont();
+ test_bssgp_dec_ran_inf_app_err_rim_cont_nacc();
+ test_bssgp_enc_ran_inf_app_err_rim_cont_nacc();
+
+ /* Application containers */
+ test_bssgp_dec_ran_inf_req_app_cont_nacc();
+ test_bssgp_enc_ran_inf_req_app_cont_nacc();
+ test_bssgp_dec_ran_inf_app_cont_nacc();
+ test_bssgp_enc_ran_inf_app_cont_nacc();
+ test_bssgp_dec_app_err_cont_nacc();
+ test_bssgp_enc_app_err_cont_nacc();
+
+ printf("===== BSSGP RIM test END\n\n");
+
+ exit(EXIT_SUCCESS);
+}
diff --git a/tests/gb/gprs_bssgp_rim_test.ok b/tests/gb/gprs_bssgp_rim_test.ok
new file mode 100644
index 00000000..d075ca3e
--- /dev/null
+++ b/tests/gb/gprs_bssgp_rim_test.ok
@@ -0,0 +1,220 @@
+===== BSSGP RIM test START
+----- test_bssgp_dec_ran_inf_req_rim_cont_nacc START
+rc=0, bssgp_ran_inf_req_rim_cont:
+ app_id = 01
+ seq_num = 00000001
+ pdu_ind.ack_requested = 0
+ pdu_ind.pdu_type_ext = 1
+ prot_ver = 1
+ app_cont: bssgp_ran_inf_req_app_cont_nacc:
+ reprt_cell.rai.lac.plmn.mcc = 262
+ reprt_cell.rai.lac.plmn.mnc = 42
+ reprt_cell.rai.lac.plmn.mnc_3_digits = 0
+ reprt_cell.rai.lac.lac = 13200
+ reprt_cell.rai.rac = 0
+ reprt_cell.cell_identity = 51e1
+----- test_bssgp_dec_ran_inf_req_rim_cont_nacc END
+----- test_bssgp_enc_ran_inf_req_rim_cont_nacc START
+bssgp_ran_inf_req_rim_cont:
+ app_id = 01
+ seq_num = 00000001
+ pdu_ind.ack_requested = 0
+ pdu_ind.pdu_type_ext = 1
+ prot_ver = 1
+ app_cont: bssgp_ran_inf_req_app_cont_nacc:
+ reprt_cell.rai.lac.plmn.mcc = 262
+ reprt_cell.rai.lac.plmn.mnc = 42
+ reprt_cell.rai.lac.plmn.mnc_3_digits = 0
+ reprt_cell.rai.lac.lac = 13200
+ reprt_cell.rai.rac = 0
+ reprt_cell.cell_identity = 51e1
+rc=25, result=4b81014c84000000014f81025581014d8862f22433900051e1
+----- test_bssgp_enc_ran_inf_req_rim_cont_nacc END
+----- test_bssgp_dec_ran_inf_rim_cont_nacc START
+rc=0, bssgp_ran_inf_rim_cont:
+ app_id = 01
+ seq_num = 00000002
+ pdu_ind.ack_requested = 0
+ pdu_ind.pdu_type_ext = 1
+ prot_ver = 1
+ app_err = 0
+ app_cont: bssgp_ran_inf_app_cont_nacc:
+ reprt_cell.rai.lac.plmn.mcc = 262
+ reprt_cell.rai.lac.plmn.mnc = 42
+ reprt_cell.rai.lac.plmn.mnc_3_digits = 0
+ reprt_cell.rai.lac.lac = 13135
+ reprt_cell.rai.rac = 0
+ reprt_cell.cell_identity = 51e0
+ type_psi = 0
+ num_si = 3
+ si[0] = 198fb100000000000000000000000000007900002b
+ si[1] = 1b753000f110236ec9033c2747407900003c0b2b2b
+ si[2] = 009000185a6fc9e08410ab2b2b2b2b2b2b2b2b2b2b
+----- test_bssgp_dec_ran_inf_rim_cont_nacc END
+----- test_bssgp_dec_ran_inf_rim_cont_err_nacc START
+rc=0, bssgp_ran_inf_rim_cont:
+ app_id = 01
+ seq_num = 00000001
+ pdu_ind.ack_requested = 0
+ pdu_ind.pdu_type_ext = 1
+ prot_ver = 1
+ app_err = 1
+ app_err_cont: bssgp_app_err_cont_nacc:
+ macc_cause = 01
+ err_app_cont: aabbccddee
+ err_app_cont_len: 5
+----- test_bssgp_dec_ran_inf_rim_cont_err_nacc END
+----- test_bssgp_enc_ran_inf_rim_cont_nacc START
+bssgp_ran_inf_rim_cont:
+ app_id = 01
+ seq_num = 00000001
+ pdu_ind.ack_requested = 0
+ pdu_ind.pdu_type_ext = 1
+ prot_ver = 1
+ app_err = 0
+ app_cont: bssgp_ran_inf_app_cont_nacc:
+ reprt_cell.rai.lac.plmn.mcc = 262
+ reprt_cell.rai.lac.plmn.mnc = 42
+ reprt_cell.rai.lac.plmn.mnc_3_digits = 0
+ reprt_cell.rai.lac.lac = 13135
+ reprt_cell.rai.rac = 0
+ reprt_cell.cell_identity = 51e0
+ type_psi = 0
+ num_si = 3
+ si[0] = 198fb100000000000000000000000000007900002b
+ si[1] = 1b753000f110236ec9033c2747407900003c0b2b2b
+ si[2] = 009000185a6fc9e08410ab2b2b2b2b2b2b2b2b2b2b
+rc=89, result=4b81014c84000000014f81025581014ec862f224334f0051e006198fb100000000000000000000000000007900002b1b753000f110236ec9033c2747407900003c0b2b2b009000185a6fc9e08410ab2b2b2b2b2b2b2b2b2b2b
+----- test_bssgp_enc_ran_inf_rim_cont_nacc END
+----- test_bssgp_enc_ran_inf_rim_cont_err_nacc START
+bssgp_ran_inf_rim_cont:
+ app_id = 01
+ seq_num = 00000001
+ pdu_ind.ack_requested = 0
+ pdu_ind.pdu_type_ext = 1
+ prot_ver = 1
+ app_err = 1
+ app_err_cont: bssgp_app_err_cont_nacc:
+ macc_cause = 01
+ err_app_cont: aabbccddee
+ err_app_cont_len: 5
+rc=23, result=4b81014c84000000014f8102558101568601aabbccddee
+----- test_bssgp_enc_ran_inf_rim_cont_err_nacc END
+----- test_bssgp_dec_ran_inf_ack_rim_cont START
+rc=0, bssgp_ran_inf_ack_rim_cont:
+ app_id = 01
+ seq_num = 00000001
+ prot_ver = 1
+----- test_bssgp_dec_ran_inf_ack_rim_cont END
+----- test_bssgp_enc_ran_inf_ack_rim_cont START
+bssgp_ran_inf_ack_rim_cont:
+ app_id = 01
+ seq_num = 00000001
+ prot_ver = 1
+rc=12, result=4b81014c8400000001558101
+----- test_bssgp_enc_ran_inf_ack_rim_cont END
+----- test_bssgp_dec_ran_inf_err_rim_cont START
+rc=0, bssgp_ran_inf_err_rim_cont:
+ app_id = 17
+ cause = 2b
+ prot_ver = 1
+ err_pdu: aabbccddee
+ err_pdu_len: 5
+----- test_bssgp_dec_ran_inf_err_rim_cont END
+----- test_bssgp_enc_ran_inf_err_rim_cont START
+bssgp_ran_inf_err_rim_cont:
+ app_id = 17
+ cause = 2b
+ prot_ver = 1
+ err_pdu: aabbccddee
+ err_pdu_len: 5
+rc=16, result=4b811707812b5581011585aabbccddee
+----- test_bssgp_enc_ran_inf_err_rim_cont END
+----- test_bssgp_dec_ran_inf_app_err_rim_cont_nacc START
+rc=0, bssgp_ran_inf_app_err_rim_cont:
+ app_id = 01
+ seq_num = 00000001
+ pdu_ind.ack_requested = 0
+ pdu_ind.pdu_type_ext = 1
+ prot_ver = 1
+ app_err_cont: bssgp_app_err_cont_nacc:
+ macc_cause = aa
+ err_app_cont: bbccddee
+ err_app_cont_len: 4
+----- test_bssgp_dec_ran_inf_app_err_rim_cont_nacc END
+----- test_bssgp_enc_ran_inf_app_err_rim_cont_nacc START
+bssgp_ran_inf_app_err_rim_cont:
+ app_id = 01
+ seq_num = 00000001
+ pdu_ind.ack_requested = 0
+ pdu_ind.pdu_type_ext = 1
+ prot_ver = 1
+ app_err_cont: bssgp_app_err_cont_nacc:
+ macc_cause = 01
+ err_app_cont: aabbccddee
+ err_app_cont_len: 5
+rc=23, result=4b81014c84000000014f8102558101568601aabbccddee
+----- test_bssgp_enc_ran_inf_app_err_rim_cont_nacc END
+----- test_bssgp_dec_ran_inf_req_app_cont_nacc START
+rc=0, app_cont: bssgp_ran_inf_req_app_cont_nacc:
+ reprt_cell.rai.lac.plmn.mcc = 262
+ reprt_cell.rai.lac.plmn.mnc = 42
+ reprt_cell.rai.lac.plmn.mnc_3_digits = 0
+ reprt_cell.rai.lac.lac = 13200
+ reprt_cell.rai.rac = 0
+ reprt_cell.cell_identity = 51e1
+----- test_bssgp_dec_ran_inf_req_app_cont_nacc END
+----- test_bssgp_enc_ran_inf_req_app_cont_nacc START
+ app_cont: bssgp_ran_inf_req_app_cont_nacc:
+ reprt_cell.rai.lac.plmn.mcc = 262
+ reprt_cell.rai.lac.plmn.mnc = 42
+ reprt_cell.rai.lac.plmn.mnc_3_digits = 0
+ reprt_cell.rai.lac.lac = 13200
+ reprt_cell.rai.rac = 0
+ reprt_cell.cell_identity = 51e1
+rc=8, result=62f22433900051e1
+----- test_bssgp_enc_ran_inf_req_app_cont_nacc END
+----- test_bssgp_dec_ran_inf_app_cont_nacc START
+rc=0, app_cont: bssgp_ran_inf_app_cont_nacc:
+ reprt_cell.rai.lac.plmn.mcc = 262
+ reprt_cell.rai.lac.plmn.mnc = 42
+ reprt_cell.rai.lac.plmn.mnc_3_digits = 0
+ reprt_cell.rai.lac.lac = 13135
+ reprt_cell.rai.rac = 0
+ reprt_cell.cell_identity = 51e0
+ type_psi = 0
+ num_si = 3
+ si[0] = 198fb100000000000000000000000000007900002b
+ si[1] = 1b753000f110236ec9033c2747407900003c0b2b2b
+ si[2] = 009000185a6fc9e08410ab2b2b2b2b2b2b2b2b2b2b
+----- test_bssgp_dec_ran_inf_app_cont_nacc END
+----- test_bssgp_enc_ran_inf_app_cont_nacc START
+ app_cont: bssgp_ran_inf_app_cont_nacc:
+ reprt_cell.rai.lac.plmn.mcc = 262
+ reprt_cell.rai.lac.plmn.mnc = 42
+ reprt_cell.rai.lac.plmn.mnc_3_digits = 0
+ reprt_cell.rai.lac.lac = 13135
+ reprt_cell.rai.rac = 0
+ reprt_cell.cell_identity = 51e1
+ type_psi = 0
+ num_si = 3
+ si[0] = 198fb100000000000000000000000000007900002b
+ si[1] = 1b753000f110236ec9033c2747407900003c0b2b2b
+ si[2] = 009000185a6fc9e08410ab2b2b2b2b2b2b2b2b2b2b
+rc=72, result=62f224334f0051e106198fb100000000000000000000000000007900002b1b753000f110236ec9033c2747407900003c0b2b2b009000185a6fc9e08410ab2b2b2b2b2b2b2b2b2b2b
+----- test_bssgp_enc_ran_inf_app_cont_nacc END
+----- test_bssgp_dec_app_err_cont_nacc START
+rc=0, app_err_cont: bssgp_app_err_cont_nacc:
+ macc_cause = 01
+ err_app_cont: aabbccddee
+ err_app_cont_len: 5
+----- test_bssgp_dec_app_err_cont_nacc END
+----- test_bssgp_enc_app_err_cont_nacc START
+ app_err_cont: bssgp_app_err_cont_nacc:
+ macc_cause = 01
+ err_app_cont: aabbccddee
+ err_app_cont_len: 5
+rc=6, result=01aabbccddee
+----- test_bssgp_enc_app_err_cont_nacc END
+===== BSSGP RIM test END
+
diff --git a/tests/testsuite.at b/tests/testsuite.at
index 75ce0393..d715a3ed 100644
--- a/tests/testsuite.at
+++ b/tests/testsuite.at
@@ -215,6 +215,12 @@ cat $abs_srcdir/gb/gprs_bssgp_test.ok > expout
AT_CHECK([$abs_top_builddir/tests/gb/gprs_bssgp_test], [0], [expout], [ignore])
AT_CLEANUP
+AT_SETUP([gprs-bssgp-rim])
+AT_KEYWORDS([gprs-bssgp-rim])
+cat $abs_srcdir/gb/gprs_bssgp_rim_test.ok > expout
+AT_CHECK([$abs_top_builddir/tests/gb/gprs_bssgp_rim_test], [0], [expout], [ignore])
+AT_CLEANUP
+
AT_SETUP([gprs-ns])
AT_KEYWORDS([gprs-ns])
cat $abs_srcdir/gb/gprs_ns_test.ok > expout