blob: 9c09e1ef5f4fc766a046285f0b817f8be3f7f2db [file] [log] [blame]
Philipp Maier9828d282021-01-06 20:40:23 +01001/*! \file gprs_bssgp.c
2 * GPRS BSSGP RIM protocol implementation as per 3GPP TS 48.018. */
3/*
4 * (C) 2020-2021 by sysmocom - s.f.m.c. GmbH
5 * Author: Philipp Maier <pmaier@sysmocom.de>
6 *
7 * All Rights Reserved
8 *
9 * SPDX-License-Identifier: GPL-2.0+
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program. If not, see <http://www.gnu.org/licenses/>.
23 *
24 */
25
26#include <errno.h>
27#include <osmocom/gprs/gprs_bssgp.h>
28#include <osmocom/gprs/gprs_bssgp_rim.h>
29#include <osmocom/gsm/gsm0808_utils.h>
Philipp Maier4d400472021-01-26 12:57:13 +010030#include "gprs_bssgp_internal.h"
Philipp Maier9828d282021-01-06 20:40:23 +010031
32/* TVLV IEs use a variable length field. To be sure we will do all buffer
33 * length checks with the maximum possible header length, which is
34 * 1 octet tag + 2 octets length = 3 */
35#define TVLV_HDR_MAXLEN 3
36
37/* Usually RIM application containers and their surrounding RIM containers
38 * are not likely to exceed 128 octets, so the usual header length will be 2 */
39#define TVLV_HDR_LEN 2
40
41/* The reporting cell identifier is encoded as a cell identifier IE
42 * (3GPP TS 48.018, sub-clause 11.3.9) but without IE and length octets. */
43#define REP_CELL_ID_LEN 8
44
Philipp Maiercf114112021-01-22 18:24:12 +010045const struct value_string bssgp_rim_routing_info_discr_strs[] = {
Philipp Maier0a7e85a2021-01-25 22:03:57 +010046 { BSSGP_RIM_ROUTING_INFO_GERAN, "GERAN-cell" },
47 { BSSGP_RIM_ROUTING_INFO_UTRAN, "UTRAN-RNC" },
48 { BSSGP_RIM_ROUTING_INFO_EUTRAN, "E-UTRAN-eNodeB/HeNB" },
Philipp Maiercf114112021-01-22 18:24:12 +010049 { 0, NULL }
50};
51
Philipp Maier3c577262023-08-10 11:47:54 +020052/*! Parse a RIM Routing address IE (3GPP TS 29.060, chapter 7.7.57 and 7.7.77).
Philipp Maier7450f772021-01-06 20:56:43 +010053 * \param[out] ri user provided memory to store the parsed results.
Philipp Maier3c577262023-08-10 11:47:54 +020054 * \param[in] buf input buffer of the value part of the RIM Routing address IE.
55 * \discr[in] discr value part (one byte) of the RIM Routing Address Discriminator IE.
Philipp Maier7450f772021-01-06 20:56:43 +010056 * \returns length of parsed octets, -EINVAL on error. */
Philipp Maier3c577262023-08-10 11:47:54 +020057int bssgp_parse_rim_ra(struct bssgp_rim_routing_info *ri, const uint8_t *buf,
58 unsigned int len, uint8_t discr)
Philipp Maier7450f772021-01-06 20:56:43 +010059{
60 struct gprs_ra_id raid_temp;
61
62 memset(ri, 0, sizeof(*ri));
63 if (len < 2)
64 return -EINVAL;
65
Philipp Maier3c577262023-08-10 11:47:54 +020066 ri->discr = discr;
Philipp Maier7450f772021-01-06 20:56:43 +010067
68 switch (ri->discr) {
69 case BSSGP_RIM_ROUTING_INFO_GERAN:
Philipp Maier3c577262023-08-10 11:47:54 +020070 if (len < 8)
Philipp Maier7450f772021-01-06 20:56:43 +010071 return -EINVAL;
72 ri->geran.cid = bssgp_parse_cell_id(&ri->geran.raid, buf);
Philipp Maier3c577262023-08-10 11:47:54 +020073 return 8;
Philipp Maier7450f772021-01-06 20:56:43 +010074 case BSSGP_RIM_ROUTING_INFO_UTRAN:
Philipp Maier3c577262023-08-10 11:47:54 +020075 if (len < 8)
Philipp Maier7450f772021-01-06 20:56:43 +010076 return -EINVAL;
77 gsm48_parse_ra(&ri->utran.raid, buf);
78 ri->utran.rncid = osmo_load16be(buf + 6);
Philipp Maier3c577262023-08-10 11:47:54 +020079 return 8;
Philipp Maier7450f772021-01-06 20:56:43 +010080 case BSSGP_RIM_ROUTING_INFO_EUTRAN:
Philipp Maier3c577262023-08-10 11:47:54 +020081 if (len < 6 || len > 13)
Philipp Maier7450f772021-01-06 20:56:43 +010082 return -EINVAL;
83 /* Note: 3GPP TS 24.301 Figure 9.9.3.32.1 and 3GPP TS 24.008
84 * Figure 10.5.130 specify MCC/MNC encoding in the same way,
85 * so we can re-use gsm48_parse_ra() for that. */
86 gsm48_parse_ra(&raid_temp, buf);
87 ri->eutran.tai.mcc = raid_temp.mcc;
88 ri->eutran.tai.mnc = raid_temp.mnc;
89 ri->eutran.tai.mnc_3_digits = raid_temp.mnc_3_digits;
90 ri->eutran.tai.tac = osmo_load16be(buf + 3);
Philipp Maier3c577262023-08-10 11:47:54 +020091 memcpy(ri->eutran.global_enb_id, buf + 5, len - 5);
92 ri->eutran.global_enb_id_len = len - 5;
Philipp Maier7450f772021-01-06 20:56:43 +010093 return len;
94 default:
95 return -EINVAL;
96 }
97}
98
Philipp Maier3c577262023-08-10 11:47:54 +020099/*! Parse a RIM Routing information IE (3GPP TS 48.018, chapter 11.3.70).
100 * \param[out] ri user provided memory to store the parsed results.
101 * \param[in] buf input buffer of the value part of the IE.
102 * \returns length of parsed octets, -EINVAL on error. */
103int bssgp_parse_rim_ri(struct bssgp_rim_routing_info *ri, const uint8_t *buf,
104 unsigned int len)
105{
106 uint8_t discr;
107 int rc;
108
109 if (len < 1)
110 return -EINVAL;
111
112 discr = buf[0] & 0x0f;
113
114 rc = bssgp_parse_rim_ra(ri, buf + 1, len - 1, discr);
115 if (rc < 0)
116 return rc;
117 return rc + 1;
118}
119
Philipp Maier7450f772021-01-06 20:56:43 +0100120/*! Encode a RIM Routing information IE (3GPP TS 48.018, chapter 11.3.70).
121 * \param[out] buf user provided memory (at least 14 byte) for the generated value part of the IE.
122 * \param[in] ri user provided input data struct.
123 * \returns length of encoded octets, -EINVAL on error. */
124int bssgp_create_rim_ri(uint8_t *buf, const struct bssgp_rim_routing_info *ri)
125{
126 int rc;
127 struct gprs_ra_id raid_temp;
Philipp Maier7741bc32021-01-07 21:55:48 +0100128 int len;
Philipp Maier7450f772021-01-06 20:56:43 +0100129
130 buf[0] = ri->discr & 0x0f;
131 buf++;
132
133 switch (ri->discr) {
134 case BSSGP_RIM_ROUTING_INFO_GERAN:
135 rc = bssgp_create_cell_id(buf, &ri->geran.raid, ri->geran.cid);
136 if (rc < 0)
137 return -EINVAL;
Philipp Maier7741bc32021-01-07 21:55:48 +0100138 len = rc + 1;
139 break;
Philipp Maier7450f772021-01-06 20:56:43 +0100140 case BSSGP_RIM_ROUTING_INFO_UTRAN:
141 gsm48_encode_ra((struct gsm48_ra_id *)buf, &ri->utran.raid);
142 osmo_store16be(ri->utran.rncid, buf + 6);
Philipp Maier7741bc32021-01-07 21:55:48 +0100143 len = 9;
144 break;
Philipp Maier7450f772021-01-06 20:56:43 +0100145 case BSSGP_RIM_ROUTING_INFO_EUTRAN:
146 /* Note: 3GPP TS 24.301 Figure 9.9.3.32.1 and 3GPP TS 24.008
147 * Figure 10.5.130 specify MCC/MNC encoding in the same way,
148 * so we can re-use gsm48_encode_ra() for that. */
149 raid_temp = (struct gprs_ra_id) {
150 .mcc = ri->eutran.tai.mcc,
151 .mnc = ri->eutran.tai.mnc,
152 .mnc_3_digits = ri->eutran.tai.mnc_3_digits,
153 };
154
155 gsm48_encode_ra((struct gsm48_ra_id *)buf, &raid_temp);
156 osmo_store16be(ri->eutran.tai.tac, buf + 3);
157 OSMO_ASSERT(ri->eutran.global_enb_id_len <=
158 sizeof(ri->eutran.global_enb_id));
159 memcpy(buf + 5, ri->eutran.global_enb_id,
160 ri->eutran.global_enb_id_len);
Philipp Maier7741bc32021-01-07 21:55:48 +0100161 len = ri->eutran.global_enb_id_len + 6;
162 break;
Philipp Maier7450f772021-01-06 20:56:43 +0100163 default:
164 return -EINVAL;
165 }
Philipp Maier7741bc32021-01-07 21:55:48 +0100166
167 OSMO_ASSERT(len <= BSSGP_RIM_ROUTING_INFO_MAXLEN);
168 return len;
Philipp Maier7450f772021-01-06 20:56:43 +0100169}
170
Philipp Maierc08a3fd2021-01-25 22:00:01 +0100171/*! Encode a RIM Routing information into a human readable string.
172 * \param[buf] user provided string buffer to store the resulting string.
173 * \param[buf_len] maximum length of string buffer.
174 * \param[in] ri user provided input data struct.
175 * \returns pointer to the beginning of the resulting string stored in string buffer. */
176char *bssgp_rim_ri_name_buf(char *buf, size_t buf_len, const struct bssgp_rim_routing_info *ri)
177{
178 char plmn_str[16];
179 char enb_id_str[16];
180 char g_id_ps_str[32];
181 struct osmo_plmn_id plmn;
182 struct osmo_cell_global_id_ps g_id_ps;
183
184 if (!ri)
185 return NULL;
186
187 switch (ri->discr) {
188 case BSSGP_RIM_ROUTING_INFO_GERAN:
189 g_id_ps.rai.rac = ri->geran.raid.rac;
190 g_id_ps.rai.lac.lac = ri->geran.raid.lac;
191 g_id_ps.rai.lac.plmn.mcc = ri->geran.raid.mcc;
192 g_id_ps.rai.lac.plmn.mnc_3_digits = ri->geran.raid.mnc_3_digits;
193 g_id_ps.rai.lac.plmn.mnc = ri->geran.raid.mnc;
194 g_id_ps.cell_identity = ri->geran.cid;
195 snprintf(buf, buf_len, "%s-%s", bssgp_rim_routing_info_discr_str(ri->discr),
196 osmo_cgi_ps_name_buf(g_id_ps_str, sizeof(g_id_ps_str), &g_id_ps));
197 break;
198 case BSSGP_RIM_ROUTING_INFO_UTRAN:
199 g_id_ps.rai.rac = ri->utran.raid.rac;
200 g_id_ps.rai.lac.lac = ri->utran.raid.lac;
201 g_id_ps.rai.lac.plmn.mcc = ri->utran.raid.mcc;
202 g_id_ps.rai.lac.plmn.mnc_3_digits = ri->utran.raid.mnc_3_digits;
203 g_id_ps.rai.lac.plmn.mnc = ri->utran.raid.mnc;
204 g_id_ps.cell_identity = ri->utran.rncid;
205 snprintf(buf, buf_len, "%s-%s", bssgp_rim_routing_info_discr_str(ri->discr),
206 osmo_cgi_ps_name_buf(g_id_ps_str, sizeof(g_id_ps_str), &g_id_ps));
207 break;
208 case BSSGP_RIM_ROUTING_INFO_EUTRAN:
209 plmn.mcc = ri->eutran.tai.mcc;
210 plmn.mnc = ri->eutran.tai.mnc;
211 plmn.mnc_3_digits = ri->eutran.tai.mnc_3_digits;
212 snprintf(buf, buf_len, "%s-%s-%u-%s", bssgp_rim_routing_info_discr_str(ri->discr),
213 osmo_plmn_name_buf(plmn_str, sizeof(plmn_str), &plmn), ri->eutran.tai.tac,
214 osmo_hexdump_buf(enb_id_str, sizeof(enb_id_str), ri->eutran.global_enb_id,
215 ri->eutran.global_enb_id_len, "", false));
216 break;
217 default:
218 snprintf(buf, buf_len, "invalid");
219 }
220
221 return buf;
222}
223
224/*! Encode a RIM Routing information into a human readable string.
225 * \param[in] ri user provided input data struct.
226 * \returns pointer to the resulting string. */
227const char *bssgp_rim_ri_name(const struct bssgp_rim_routing_info *ri)
228{
229 static __thread char rim_ri_buf[64];
230 return bssgp_rim_ri_name_buf(rim_ri_buf, sizeof(rim_ri_buf), ri);
231}
232
Philipp Maier9828d282021-01-06 20:40:23 +0100233/*! Decode a RAN Information Request Application Container for NACC (3GPP TS 48.018, section 11.3.63.1.1).
234 * \param[out] user provided memory for decoded data struct.
235 * \param[in] buf user provided memory with the encoded value data of the IE.
236 * \returns 0 on success, -EINVAL on error. */
237int bssgp_dec_ran_inf_req_app_cont_nacc(struct bssgp_ran_inf_req_app_cont_nacc *cont, const uint8_t *buf, size_t len)
238{
239 int rc;
240
241 if (len < REP_CELL_ID_LEN)
242 return -EINVAL;
243
244 rc = gsm0808_decode_cell_id_u((union gsm0808_cell_id_u*)&cont->reprt_cell,
245 CELL_IDENT_WHOLE_GLOBAL_PS, buf, len);
246 if (rc < 0)
247 return -EINVAL;
248
249 return 0;
250}
251
252/*! Encode a RAN Information Request Application Container for NACC (3GPP TS 48.018, section 11.3.63.1.1).
253 * \param[out] buf user provided memory for the generated value part of the IE.
254 * \param[in] cont user provided input data struct.
255 * \returns length of encoded octets, -EINVAL on error. */
256int bssgp_enc_ran_inf_req_app_cont_nacc(uint8_t *buf, size_t len, const struct bssgp_ran_inf_req_app_cont_nacc *cont)
257{
258 int rc;
259 struct gprs_ra_id *raid;
260
261 if (len < REP_CELL_ID_LEN)
262 return -EINVAL;
263
264 raid = (struct gprs_ra_id *)&cont->reprt_cell.rai;
265 rc = bssgp_create_cell_id(buf, raid, cont->reprt_cell.cell_identity);
266 if (rc < 0)
267 return -EINVAL;
268 return rc;
269}
270
271/*! Decode a RAN Information Application Container (3GPP TS 48.018, section 11.3.63.2.1).
272 * \param[out] user provided memory for decoded data struct.
273 * \param[in] buf user provided memory with the encoded value data of the IE.
274 * \returns 0 on success, -EINVAL on error. */
275int bssgp_dec_ran_inf_app_cont_nacc(struct bssgp_ran_inf_app_cont_nacc *cont, const uint8_t *buf, size_t len)
276{
277 unsigned int i;
278 int remaining_buf_len;
279 int rc;
280
281 /* The given buffer must at least contain a reporting cell identifer
282 * plus one octet that defines number/type of attached sysinfo messages. */
283 if (len < REP_CELL_ID_LEN + 1)
284 return -EINVAL;
285
286 rc = gsm0808_decode_cell_id_u((union gsm0808_cell_id_u*)&cont->reprt_cell,
287 CELL_IDENT_WHOLE_GLOBAL_PS, buf, len);
288 if (rc < 0)
289 return -EINVAL;
290
291 buf += REP_CELL_ID_LEN;
292
293 cont->type_psi = buf[0] & 1;
294 cont->num_si = buf[0] >> 1;
295 buf++;
296
297 /* The number of sysinfo messages may be zero */
298 if (cont->num_si == 0)
299 return 0;
300
301 /* Check if the prospected system information messages fit in the
302 * remaining buffer space */
303 remaining_buf_len = len - REP_CELL_ID_LEN - 1;
304 if (remaining_buf_len <= 0)
305 return -EINVAL;
306 if (cont->type_psi && remaining_buf_len / BSSGP_RIM_PSI_LEN < cont->num_si)
307 return -EINVAL;
308 else if (remaining_buf_len / BSSGP_RIM_SI_LEN < cont->num_si)
309 return -EINVAL;
310
311 for (i = 0; i < cont->num_si; i++) {
312 cont->si[i] = buf;
313 if (cont->type_psi)
314 buf += BSSGP_RIM_PSI_LEN;
315 else
316 buf += BSSGP_RIM_SI_LEN;
317 }
318
319 return 0;
320}
321
322/*! Encode a RAN Information Application Container (3GPP TS 48.018, section 11.3.63.2.1).
323 * \param[out] buf user provided memory for the generated value part of the IE.
324 * \param[in] cont user provided input data struct.
325 * \returns length of encoded octets, -EINVAL on error. */
326int bssgp_enc_ran_inf_app_cont_nacc(uint8_t *buf, size_t len, const struct bssgp_ran_inf_app_cont_nacc *cont)
327{
328 uint8_t *buf_ptr = buf;
329 int rc;
330 unsigned int silen;
331 unsigned int i;
332 struct gprs_ra_id *raid;
333
334 if (cont->type_psi)
335 silen = BSSGP_RIM_PSI_LEN;
336 else
337 silen = BSSGP_RIM_SI_LEN;
338
339 /* The buffer must accept the reporting cell id, plus 1 byte to define
340 * the type and number of sysinfo messages. */
341 if (len < REP_CELL_ID_LEN + 1 + silen * cont->num_si)
342 return -EINVAL;
343
344 raid = (struct gprs_ra_id *)&cont->reprt_cell.rai;
345 rc = bssgp_create_cell_id(buf_ptr, raid, cont->reprt_cell.cell_identity);
346 if (rc < 0)
347 return -EINVAL;
348 buf_ptr += rc;
349
350 buf_ptr[0] = 0x00;
351 if (cont->type_psi)
352 buf_ptr[0] |= 0x01;
353 buf_ptr[0] |= (cont->num_si << 1);
354 buf_ptr++;
355
356 for (i = 0; i < cont->num_si; i++) {
357 memcpy(buf_ptr, cont->si[i], silen);
358 buf_ptr += silen;
359 }
360
361 return (int)(buf_ptr - buf);
362}
363
Philipp Maier139c4ae2021-01-22 17:19:05 +0100364/* 3GPP TS 48.018, table 11.3.64.1.b, NACC Cause coding */
365const struct value_string bssgp_nacc_cause_strs[] = {
366 { BSSGP_NACC_CAUSE_UNSPEC, "unspecified error" },
367 { BSSGP_NACC_CAUSE_SYNTAX_ERR, "syntax error in app container" },
368 { BSSGP_NACC_CAUSE_RPRT_CELL_MISSMTCH, "reporting cell id mismatch" },
369 { BSSGP_NACC_CAUSE_SIPSI_TYPE_ERR, "SI/PSI type error" },
370 { BSSGP_NACC_CAUSE_SIPSI_LEN_ERR, "SI/PSI inconsistent length" },
371 { BSSGP_NACC_CAUSE_SIPSI_SET_ERR, "inconsistent set of msg" },
372 { 0, NULL }
373};
374
Philipp Maier9828d282021-01-06 20:40:23 +0100375/*! Decode a Application Error Container for NACC (3GPP TS 48.018, section 11.3.64.1).
376 * \param[out] user provided memory for decoded data struct.
377 * \param[in] buf user provided memory with the encoded value data of the IE.
378 * \returns 0 on success, -EINVAL on error. */
379int bssgp_dec_app_err_cont_nacc(struct bssgp_app_err_cont_nacc *cont, const uint8_t *buf, size_t len)
380{
381 /* The buffer must at least contain the NACC cause code, it should also
382 * contain the application container, but we won't error if it is missing. */
383 if (len < 1)
384 return -EINVAL;
385
386 cont->nacc_cause = buf[0];
387
388 if (len > 1) {
389 cont->err_app_cont = buf + 1;
390 cont->err_app_cont_len = len - 1;
391 } else {
392 cont->err_app_cont = NULL;
393 cont->err_app_cont_len = 0;
394 }
395
396 return 0;
397}
398
399/*! Encode Application Error Container for NACC (3GPP TS 48.018, section 11.3.64.1).
400 * \param[out] buf user provided memory for the generated value part of the IE.
401 * \param[in] cont user provided input data struct.
402 * \returns length of encoded octets, -EINVAL on error. */
403int bssgp_enc_app_err_cont_nacc(uint8_t *buf, size_t len, const struct bssgp_app_err_cont_nacc *cont)
404{
405 uint8_t *buf_ptr = buf;
406
407 /* The buffer must accept the length of the application container and the NACC
408 * cause code, which is one octet in length. */
409 if (len < cont->err_app_cont_len + 1)
410 return -EINVAL;
411
412 buf_ptr[0] = cont->nacc_cause;
413 buf_ptr++;
414
415 memcpy(buf_ptr, cont->err_app_cont, cont->err_app_cont_len);
416 buf_ptr += cont->err_app_cont_len;
417
418 return (int)(buf_ptr - buf);
419}
420
421/* The structs bssgp_ran_inf_req_rim_cont, bssgp_ran_inf_rim_cont and bssgp_ran_inf_app_err_rim_cont *cont
422 * share four common fields at the beginning, we use the following struct as parameter type for the common
423 * encoder/decoder functions. (See also 3GPP TS 48.018 table 11.3.62a.1.b, table 11.3.62a.2.b, and
424 * table 11.3.62a.5.b) */
425struct bssgp_ran_inf_x_cont {
426 enum bssgp_ran_inf_app_id app_id;
427 uint32_t seq_num;
428 struct bssgp_rim_pdu_ind pdu_ind;
429 uint8_t prot_ver;
430};
431
432static int dec_rim_cont_common(struct bssgp_ran_inf_x_cont *cont, struct tlv_parsed *tp)
433{
434 if (TLVP_PRES_LEN(tp, BSSGP_IE_RIM_APP_IDENTITY, sizeof(uint8_t)))
435 cont->app_id = TLVP_VAL(tp, BSSGP_IE_RIM_APP_IDENTITY)[0];
436 else
437 return -EINVAL;
438
439 if (TLVP_PRES_LEN(tp, BSSGP_IE_RIM_SEQ_NR, sizeof(cont->seq_num)))
440 cont->seq_num = tlvp_val32be(tp, BSSGP_IE_RIM_SEQ_NR);
441 else
442 return -EINVAL;
443
444 if (TLVP_PRES_LEN(tp, BSSGP_IE_RIM_PDU_INDICATIONS, sizeof(cont->pdu_ind)))
445 memcpy(&cont->pdu_ind, TLVP_VAL(tp, BSSGP_IE_RIM_PDU_INDICATIONS), sizeof(cont->pdu_ind));
446 else
447 return -EINVAL;
448
449 if (TLVP_PRES_LEN(tp, BSSGP_IE_RIM_PROTOCOL_VERSION, sizeof(cont->prot_ver)))
450 cont->prot_ver = TLVP_VAL(tp, BSSGP_IE_RIM_PROTOCOL_VERSION)[0];
451 else
452 cont->prot_ver = 1;
453
454 return 0;
455}
456
457static uint8_t *enc_rim_cont_common(uint8_t *buf, size_t len, const struct bssgp_ran_inf_x_cont *cont)
458{
459
460 uint32_t seq_num = osmo_htonl(cont->seq_num);
461 uint8_t app_id_temp;
462 uint8_t *buf_ptr = buf;
463
464 if (len <
465 TVLV_HDR_MAXLEN * 4 + sizeof(app_id_temp) + sizeof(seq_num) + sizeof(cont->pdu_ind) +
466 sizeof(cont->prot_ver))
467 return NULL;
468
469 app_id_temp = cont->app_id;
470 buf_ptr = tvlv_put(buf_ptr, BSSGP_IE_RIM_APP_IDENTITY, sizeof(app_id_temp), &app_id_temp);
471 buf_ptr = tvlv_put(buf_ptr, BSSGP_IE_RIM_SEQ_NR, sizeof(seq_num), (uint8_t *) & seq_num);
472 buf_ptr = tvlv_put(buf_ptr, BSSGP_IE_RIM_PDU_INDICATIONS, sizeof(cont->pdu_ind), (uint8_t *) & cont->pdu_ind);
473 if (cont->prot_ver > 0)
474 buf_ptr = tvlv_put(buf_ptr, BSSGP_IE_RIM_PROTOCOL_VERSION, sizeof(cont->prot_ver), &cont->prot_ver);
475
476 return buf_ptr;
477}
478
Philipp Maier8b19d062021-01-22 18:05:35 +0100479/* 3GPP TS 48.018, table 11.3.61.b: RIM Application Identity coding */
480const struct value_string bssgp_ran_inf_app_id_strs[] = {
481 { BSSGP_RAN_INF_APP_ID_NACC, "Network Assisted Cell Change (NACC)" },
482 { BSSGP_RAN_INF_APP_ID_SI3, "System Information 3 (SI3)" },
483 { BSSGP_RAN_INF_APP_ID_MBMS, "MBMS data channel" },
484 { BSSGP_RAN_INF_APP_ID_SON, "SON Transfer" },
485 { BSSGP_RAN_INF_APP_ID_UTRA_SI, "UTRA System Information (UTRA SI)" },
486 { 0, NULL }
487};
488
Philipp Maier9828d282021-01-06 20:40:23 +0100489/*! Decode a RAN Information Request RIM Container (3GPP TS 48.018, table 11.3.62a.1.b).
490 * \param[out] user provided memory for decoded data struct.
491 * \param[in] buf user provided memory with the encoded value data of the IE.
492 * \returns 0 on success, -EINVAL on error. */
493int bssgp_dec_ran_inf_req_rim_cont(struct bssgp_ran_inf_req_rim_cont *cont, const uint8_t *buf, size_t len)
494{
495 int rc;
496 struct tlv_parsed tp;
497
498 memset(cont, 0, sizeof(*cont));
499
500 rc = tlv_parse(&tp, &tvlv_att_def, buf, len, 0, 0);
501 if (rc < 0)
502 return -EINVAL;
503
504 rc = dec_rim_cont_common((struct bssgp_ran_inf_x_cont *)cont, &tp);
505 if (rc < 0)
506 return -EINVAL;
507
508 if (TLVP_PRESENT(&tp, BSSGP_IE_RIM_REQ_APP_CONTAINER)) {
509 switch (cont->app_id) {
510 case BSSGP_RAN_INF_APP_ID_NACC:
511 rc = bssgp_dec_ran_inf_req_app_cont_nacc(&cont->u.app_cont_nacc,
512 TLVP_VAL(&tp, BSSGP_IE_RIM_REQ_APP_CONTAINER),
513 TLVP_LEN(&tp, BSSGP_IE_RIM_REQ_APP_CONTAINER));
514 break;
515 case BSSGP_RAN_INF_APP_ID_SI3:
516 case BSSGP_RAN_INF_APP_ID_MBMS:
517 case BSSGP_RAN_INF_APP_ID_SON:
518 case BSSGP_RAN_INF_APP_ID_UTRA_SI:
519 /* TODO: add parsers for Si3, MBMS, SON, UTRA-SI app containers */
Philipp Maier836c6da2021-01-19 20:03:50 +0100520 return -EOPNOTSUPP;
Philipp Maier9828d282021-01-06 20:40:23 +0100521 default:
522 return -EINVAL;
523 }
524
525 if (rc < 0)
526 return rc;
527 }
528
529 if (TLVP_PRES_LEN(&tp, BSSGP_IE_SON_TRANSFER_APP_ID, 1)) {
530 cont->son_trans_app_id = TLVP_VAL(&tp, BSSGP_IE_SON_TRANSFER_APP_ID);
531 cont->son_trans_app_id_len = TLVP_LEN(&tp, BSSGP_IE_SON_TRANSFER_APP_ID);
532 }
533
534 return 0;
535}
536
537/* Dub a TLVP header into a given buffer. The value part of the IE must start
538 * at the 2nd octet. Should the length field make a 3 octet TLVP header
539 * necessary (unlikely, but possible) the value part is moved ahead by one
540 * octet. The function returns a pointer to the end of value part. */
541static uint8_t *dub_tlvp_header(uint8_t *buf, uint8_t iei, uint16_t len)
542{
543 uint8_t *buf_ptr = buf;
544
545 buf_ptr[0] = iei;
546 if (len <= TVLV_MAX_ONEBYTE) {
547 buf_ptr[1] = (uint8_t) len;
548 buf_ptr[1] |= 0x80;
549 buf_ptr += TVLV_HDR_LEN;
550 } else {
551 memmove(buf_ptr + 1, buf_ptr, len);
552 buf_ptr[1] = len >> 8;
Philipp Maier2b11fa92021-01-20 15:55:40 +0100553 buf_ptr[2] = len & 0xff;
Philipp Maier9828d282021-01-06 20:40:23 +0100554 buf_ptr += TVLV_HDR_MAXLEN;
555 }
556 buf_ptr += len;
557
558 return buf_ptr;
559}
560
561/*! Encode a RAN Information Request RIM Container (3GPP TS 48.018, table 11.3.62a.1.b).
562 * \param[out] buf user provided memory for the generated value part of the IE.
563 * \param[in] cont user provided input data struct.
564 * \returns length of encoded octets, -EINVAL on error. */
565int bssgp_enc_ran_inf_req_rim_cont(uint8_t *buf, size_t len, const struct bssgp_ran_inf_req_rim_cont *cont)
566{
567 uint8_t *buf_ptr = buf;
568 int app_cont_len = 0;
569 int remaining_buf_len;
570
571 buf_ptr = enc_rim_cont_common(buf_ptr, len, (struct bssgp_ran_inf_x_cont *)cont);
572 if (!buf_ptr)
573 return -EINVAL;
574
575 remaining_buf_len = len - (int)(buf_ptr - buf);
576 if (remaining_buf_len <= 0)
577 return -EINVAL;
578
579 switch (cont->app_id) {
580 case BSSGP_RAN_INF_APP_ID_NACC:
581 app_cont_len =
582 bssgp_enc_ran_inf_req_app_cont_nacc(buf_ptr + TVLV_HDR_LEN, remaining_buf_len - TVLV_HDR_MAXLEN,
583 &cont->u.app_cont_nacc);
584 break;
585 case BSSGP_RAN_INF_APP_ID_SI3:
586 case BSSGP_RAN_INF_APP_ID_MBMS:
587 case BSSGP_RAN_INF_APP_ID_SON:
588 case BSSGP_RAN_INF_APP_ID_UTRA_SI:
589 /* TODO: add encoders for Si3, MBMS, SON, UTRA-SI app containers */
Philipp Maier836c6da2021-01-19 20:03:50 +0100590 return -EOPNOTSUPP;
Philipp Maier9828d282021-01-06 20:40:23 +0100591 default:
592 return -EINVAL;
593 }
594
595 if (app_cont_len < 0)
596 return -EINVAL;
597 buf_ptr = dub_tlvp_header(buf_ptr, BSSGP_IE_RIM_REQ_APP_CONTAINER, app_cont_len);
598
599 remaining_buf_len = len - (int)(buf_ptr - buf);
600 if (remaining_buf_len < 0)
601 return -EINVAL;
602
603 if (cont->son_trans_app_id && cont->son_trans_app_id_len > 0) {
604 if (remaining_buf_len < cont->son_trans_app_id_len + TVLV_HDR_MAXLEN)
605 return -EINVAL;
606 buf_ptr =
607 tvlv_put(buf_ptr, BSSGP_IE_SON_TRANSFER_APP_ID, cont->son_trans_app_id_len, cont->son_trans_app_id);
608 }
609 return (int)(buf_ptr - buf);
610}
611
612/*! Decode a RAN Information RIM Container (3GPP TS 48.018, table 11.3.62a.2.b).
613 * \param[out] user provided memory for decoded data struct.
614 * \param[in] buf user provided memory with the encoded value data of the IE.
615 * \returns 0 on success, -EINVAL on error. */
616int bssgp_dec_ran_inf_rim_cont(struct bssgp_ran_inf_rim_cont *cont, const uint8_t *buf, size_t len)
617{
618 int rc;
619 struct tlv_parsed tp;
620
621 memset(cont, 0, sizeof(*cont));
622
623 rc = tlv_parse(&tp, &tvlv_att_def, buf, len, 0, 0);
624 if (rc < 0)
625 return -EINVAL;
626
627 rc = dec_rim_cont_common((struct bssgp_ran_inf_x_cont *)cont, &tp);
628 if (rc < 0)
629 return -EINVAL;
630
631 if (TLVP_PRESENT(&tp, BSSGP_IE_RAN_INFO_APP_CONTAINER)) {
632 switch (cont->app_id) {
633 case BSSGP_RAN_INF_APP_ID_NACC:
634 rc = bssgp_dec_ran_inf_app_cont_nacc(&cont->u.app_cont_nacc,
635 TLVP_VAL(&tp, BSSGP_IE_RAN_INFO_APP_CONTAINER),
636 TLVP_LEN(&tp, BSSGP_IE_RAN_INFO_APP_CONTAINER));
637 break;
638 case BSSGP_RAN_INF_APP_ID_SI3:
639 case BSSGP_RAN_INF_APP_ID_MBMS:
640 case BSSGP_RAN_INF_APP_ID_SON:
641 case BSSGP_RAN_INF_APP_ID_UTRA_SI:
642 /* TODO: add parsers for Si3, MBMS, SON, UTRA-SI app containers */
Philipp Maier836c6da2021-01-19 20:03:50 +0100643 return -EOPNOTSUPP;
Philipp Maier9828d282021-01-06 20:40:23 +0100644 default:
645 return -EINVAL;
646 }
647
648 if (rc < 0)
649 return rc;
650 } else if (TLVP_PRESENT(&tp, BSSGP_IE_APP_ERROR_CONTAINER)) {
651 switch (cont->app_id) {
652 case BSSGP_RAN_INF_APP_ID_NACC:
653 rc = bssgp_dec_app_err_cont_nacc(&cont->u.app_err_cont_nacc,
654 TLVP_VAL(&tp, BSSGP_IE_APP_ERROR_CONTAINER), TLVP_LEN(&tp,
655 BSSGP_IE_APP_ERROR_CONTAINER));
656 break;
657 case BSSGP_RAN_INF_APP_ID_SI3:
658 case BSSGP_RAN_INF_APP_ID_MBMS:
659 case BSSGP_RAN_INF_APP_ID_SON:
660 case BSSGP_RAN_INF_APP_ID_UTRA_SI:
661 /* TODO: add parsers for Si3, MBMS, SON, UTRA-SI app containers */
Philipp Maier836c6da2021-01-19 20:03:50 +0100662 return -EOPNOTSUPP;
Philipp Maier9828d282021-01-06 20:40:23 +0100663 default:
664 return -EINVAL;
665 }
666 if (rc < 0)
667 return rc;
668 cont->app_err = true;
669 }
670
671 if (TLVP_PRES_LEN(&tp, BSSGP_IE_SON_TRANSFER_APP_ID, 1)) {
672 cont->son_trans_app_id = TLVP_VAL(&tp, BSSGP_IE_SON_TRANSFER_APP_ID);
673 cont->son_trans_app_id_len = TLVP_LEN(&tp, BSSGP_IE_SON_TRANSFER_APP_ID);
674 }
675
676 return 0;
677}
678
679/*! Encode a RAN Information RIM Container (3GPP TS 48.018, table 11.3.62a.2.b).
680 * \param[out] buf user provided memory for the generated value part of the IE.
681 * \param[in] cont user provided input data struct.
682 * \returns length of encoded octets, -EINVAL on error. */
683int bssgp_enc_ran_inf_rim_cont(uint8_t *buf, size_t len, const struct bssgp_ran_inf_rim_cont *cont)
684{
685 uint8_t *buf_ptr = buf;
686 int app_cont_len = 0;
687 int remaining_buf_len;
688
689 buf_ptr = enc_rim_cont_common(buf_ptr, len, (struct bssgp_ran_inf_x_cont *)cont);
690 if (!buf_ptr)
691 return -EINVAL;
692
693 remaining_buf_len = len - (int)(buf_ptr - buf);
694 if (remaining_buf_len <= 0)
695 return -EINVAL;
696
697 if (cont->app_err) {
698 switch (cont->app_id) {
699 case BSSGP_RAN_INF_APP_ID_NACC:
700 app_cont_len =
701 bssgp_enc_app_err_cont_nacc(buf_ptr + TVLV_HDR_LEN, remaining_buf_len - TVLV_HDR_MAXLEN,
702 &cont->u.app_err_cont_nacc);
703 break;
704 case BSSGP_RAN_INF_APP_ID_SI3:
705 case BSSGP_RAN_INF_APP_ID_MBMS:
706 case BSSGP_RAN_INF_APP_ID_SON:
707 case BSSGP_RAN_INF_APP_ID_UTRA_SI:
708 /* TODO: add encoders for Si3, MBMS, SON, UTRA-SI app containers */
Philipp Maier836c6da2021-01-19 20:03:50 +0100709 return -EOPNOTSUPP;
Philipp Maier9828d282021-01-06 20:40:23 +0100710 default:
711 return -EINVAL;
712 }
713 if (app_cont_len < 0)
714 return -EINVAL;
715 buf_ptr = dub_tlvp_header(buf_ptr, BSSGP_IE_APP_ERROR_CONTAINER, app_cont_len);
716 } else {
717 switch (cont->app_id) {
718 case BSSGP_RAN_INF_APP_ID_NACC:
719 app_cont_len =
720 bssgp_enc_ran_inf_app_cont_nacc(buf_ptr + TVLV_HDR_LEN, remaining_buf_len - TVLV_HDR_MAXLEN,
721 &cont->u.app_cont_nacc);
722 break;
723 case BSSGP_RAN_INF_APP_ID_SI3:
724 case BSSGP_RAN_INF_APP_ID_MBMS:
725 case BSSGP_RAN_INF_APP_ID_SON:
726 case BSSGP_RAN_INF_APP_ID_UTRA_SI:
727 /* TODO: add encoders for Si3, MBMS, SON, UTRA-SI app containers */
Philipp Maier836c6da2021-01-19 20:03:50 +0100728 return -EOPNOTSUPP;
Philipp Maier9828d282021-01-06 20:40:23 +0100729 default:
730 return -EINVAL;
731 }
732 if (app_cont_len < 0)
733 return -EINVAL;
734 buf_ptr = dub_tlvp_header(buf_ptr, BSSGP_IE_RAN_INFO_APP_CONTAINER, app_cont_len);
735 }
736
737 remaining_buf_len = len - (int)(buf_ptr - buf);
738 if (remaining_buf_len < 0)
739 return -EINVAL;
740
741 if (cont->son_trans_app_id && cont->son_trans_app_id_len > 0) {
742 if (remaining_buf_len < cont->son_trans_app_id_len + TVLV_HDR_MAXLEN)
743 return -EINVAL;
744 buf_ptr =
745 tvlv_put(buf_ptr, BSSGP_IE_SON_TRANSFER_APP_ID, cont->son_trans_app_id_len, cont->son_trans_app_id);
746 }
747 return (int)(buf_ptr - buf);
748}
749
750/*! Decode a RAN Information ACK RIM Container (3GPP TS 48.018, table 11.3.62a.3.b).
751 * \param[out] user provided memory for decoded data struct.
752 * \param[in] buf user provided memory with the encoded value data of the IE.
753 * \returns 0 on success, -EINVAL on error. */
754int bssgp_dec_ran_inf_ack_rim_cont(struct bssgp_ran_inf_ack_rim_cont *cont, const uint8_t *buf, size_t len)
755{
756 int rc;
757 struct tlv_parsed tp;
758
759 memset(cont, 0, sizeof(*cont));
760
761 rc = tlv_parse(&tp, &tvlv_att_def, buf, len, 0, 0);
762 if (rc < 0)
763 return -EINVAL;
764
765 if (TLVP_PRES_LEN(&tp, BSSGP_IE_RIM_APP_IDENTITY, sizeof(uint8_t)))
766 cont->app_id = TLVP_VAL(&tp, BSSGP_IE_RIM_APP_IDENTITY)[0];
767 else
768 return -EINVAL;
769
770 if (TLVP_PRES_LEN(&tp, BSSGP_IE_RIM_SEQ_NR, sizeof(cont->seq_num)))
771 cont->seq_num = tlvp_val32be(&tp, BSSGP_IE_RIM_SEQ_NR);
772 else
773 return -EINVAL;
774
775 if (TLVP_PRES_LEN(&tp, BSSGP_IE_RIM_PROTOCOL_VERSION, sizeof(cont->prot_ver)))
776 cont->prot_ver = TLVP_VAL(&tp, BSSGP_IE_RIM_PROTOCOL_VERSION)[0];
777 else
778 cont->prot_ver = 1;
779
780 if (TLVP_PRES_LEN(&tp, BSSGP_IE_SON_TRANSFER_APP_ID, 1)) {
781 cont->son_trans_app_id = TLVP_VAL(&tp, BSSGP_IE_SON_TRANSFER_APP_ID);
782 cont->son_trans_app_id_len = TLVP_LEN(&tp, BSSGP_IE_SON_TRANSFER_APP_ID);
783 }
784
785 return 0;
786}
787
788/*! Encode a RAN Information ACK RIM Container (3GPP TS 48.018, table 11.3.62a.3.b).
789 * \param[out] buf user provided memory for the generated value part of the IE.
790 * \param[in] cont user provided input data struct.
791 * \returns length of encoded octets, -EINVAL on error. */
792int bssgp_enc_ran_inf_ack_rim_cont(uint8_t *buf, size_t len, const struct bssgp_ran_inf_ack_rim_cont *cont)
793{
794 uint8_t *buf_ptr = buf;
795 uint32_t seq_num = osmo_htonl(cont->seq_num);
796 uint8_t app_id_temp;
797
798 if (len <
799 4 * TVLV_HDR_MAXLEN + sizeof(app_id_temp) + sizeof(seq_num) + sizeof(cont->prot_ver) +
800 cont->son_trans_app_id_len)
801 return -EINVAL;
802
803 app_id_temp = cont->app_id;
804 buf_ptr = tvlv_put(buf_ptr, BSSGP_IE_RIM_APP_IDENTITY, sizeof(app_id_temp), &app_id_temp);
805 buf_ptr = tvlv_put(buf_ptr, BSSGP_IE_RIM_SEQ_NR, sizeof(seq_num), (uint8_t *) & seq_num);
806
807 if (cont->prot_ver > 0)
808 buf_ptr = tvlv_put(buf_ptr, BSSGP_IE_RIM_PROTOCOL_VERSION, sizeof(cont->prot_ver), &cont->prot_ver);
809
810 if (cont->son_trans_app_id && cont->son_trans_app_id_len > 0)
811 buf_ptr =
812 tvlv_put(buf_ptr, BSSGP_IE_SON_TRANSFER_APP_ID, cont->son_trans_app_id_len, cont->son_trans_app_id);
813
814 return (int)(buf_ptr - buf);
815}
816
817/*! Decode a RAN Information Error RIM Container (3GPP TS 48.018, table 11.3.62a.4.b).
818 * \param[out] user provided memory for decoded data struct.
819 * \param[in] buf user provided memory with the encoded value data of the IE.
820 * \returns 0 on success, -EINVAL on error. */
821int bssgp_dec_ran_inf_err_rim_cont(struct bssgp_ran_inf_err_rim_cont *cont, const uint8_t *buf, size_t len)
822{
823 int rc;
824 struct tlv_parsed tp;
825
826 memset(cont, 0, sizeof(*cont));
827
828 rc = tlv_parse(&tp, &tvlv_att_def, buf, len, 0, 0);
829 if (rc < 0)
830 return -EINVAL;
831
832 if (TLVP_PRES_LEN(&tp, BSSGP_IE_RIM_APP_IDENTITY, sizeof(uint8_t)))
833 cont->app_id = TLVP_VAL(&tp, BSSGP_IE_RIM_APP_IDENTITY)[0];
834 else
835 return -EINVAL;
836
837 if (TLVP_PRES_LEN(&tp, BSSGP_IE_CAUSE, sizeof(cont->cause)))
838 cont->cause = TLVP_VAL(&tp, BSSGP_IE_CAUSE)[0];
839 else
840 return -EINVAL;
841
842 if (TLVP_PRES_LEN(&tp, BSSGP_IE_RIM_PROTOCOL_VERSION, sizeof(cont->prot_ver)))
843 cont->prot_ver = TLVP_VAL(&tp, BSSGP_IE_RIM_PROTOCOL_VERSION)[0];
844 else
845 cont->prot_ver = 1;
846
847 if (TLVP_PRESENT(&tp, BSSGP_IE_PDU_IN_ERROR)) {
848 cont->err_pdu = TLVP_VAL(&tp, BSSGP_IE_PDU_IN_ERROR);
849 cont->err_pdu_len = TLVP_LEN(&tp, BSSGP_IE_PDU_IN_ERROR);
850 } else {
851 return -EINVAL;
852 }
853
854 if (TLVP_PRES_LEN(&tp, BSSGP_IE_SON_TRANSFER_APP_ID, 1)) {
855 cont->son_trans_app_id = TLVP_VAL(&tp, BSSGP_IE_SON_TRANSFER_APP_ID);
856 cont->son_trans_app_id_len = TLVP_LEN(&tp, BSSGP_IE_SON_TRANSFER_APP_ID);
857 }
858
859 return 0;
860}
861
862/*! Encode a RAN Information Error RIM Container (3GPP TS 48.018, table 11.3.62a.4.b).
863 * \param[out] buf user provided memory for the generated value part of the IE.
864 * \param[in] cont user provided input data struct.
865 * \returns length of encoded octets, -EINVAL on error. */
866int bssgp_enc_ran_inf_err_rim_cont(uint8_t *buf, size_t len, const struct bssgp_ran_inf_err_rim_cont *cont)
867{
868 uint8_t *buf_ptr = buf;
869 uint8_t app_id_temp;
870
871 if (len <
872 TVLV_HDR_MAXLEN * 5 + sizeof(app_id_temp) + sizeof(cont->cause) + sizeof(cont->prot_ver) +
873 cont->err_pdu_len + cont->son_trans_app_id_len)
874 return -EINVAL;
875
876 app_id_temp = cont->app_id;
877 buf_ptr = tvlv_put(buf_ptr, BSSGP_IE_RIM_APP_IDENTITY, sizeof(app_id_temp), &app_id_temp);
878 buf_ptr = tvlv_put(buf_ptr, BSSGP_IE_CAUSE, sizeof(cont->cause), &cont->cause);
879
880 if (cont->prot_ver > 0)
881 buf_ptr = tvlv_put(buf_ptr, BSSGP_IE_RIM_PROTOCOL_VERSION, sizeof(cont->prot_ver), &cont->prot_ver);
882
883 if (cont->err_pdu && cont->err_pdu_len > 0)
884 buf_ptr = tvlv_put(buf_ptr, BSSGP_IE_PDU_IN_ERROR, cont->err_pdu_len, cont->err_pdu);
885 else
886 return -EINVAL;
887
888 if (cont->son_trans_app_id && cont->son_trans_app_id_len > 0)
889 buf_ptr =
890 tvlv_put(buf_ptr, BSSGP_IE_SON_TRANSFER_APP_ID, cont->son_trans_app_id_len, cont->son_trans_app_id);
891
892 return (int)(buf_ptr - buf);
893}
894
895/*! Decode a RAN Information Application Error RIM Container (3GPP TS 48.018, table 11.3.62a.5.b).
896 * \param[out] user provided memory for decoded data struct.
897 * \param[in] buf user provided memory with the encoded value data of the IE.
898 * \returns 0 on success, -EINVAL on error. */
899int bssgp_dec_ran_inf_app_err_rim_cont(struct bssgp_ran_inf_app_err_rim_cont *cont, const uint8_t *buf, size_t len)
900{
901 int rc;
902 struct tlv_parsed tp;
903
904 memset(cont, 0, sizeof(*cont));
905
906 rc = tlv_parse(&tp, &tvlv_att_def, buf, len, 0, 0);
907 if (rc < 0)
908 return -EINVAL;
909
910 rc = dec_rim_cont_common((struct bssgp_ran_inf_x_cont *)cont, &tp);
911 if (rc < 0)
912 return -EINVAL;
913
914 switch (cont->app_id) {
915 case BSSGP_RAN_INF_APP_ID_NACC:
916 rc = bssgp_dec_app_err_cont_nacc(&cont->u.app_err_cont_nacc,
917 TLVP_VAL(&tp, BSSGP_IE_APP_ERROR_CONTAINER), TLVP_LEN(&tp,
918 BSSGP_IE_APP_ERROR_CONTAINER));
919 break;
920 case BSSGP_RAN_INF_APP_ID_SI3:
921 case BSSGP_RAN_INF_APP_ID_MBMS:
922 case BSSGP_RAN_INF_APP_ID_SON:
923 case BSSGP_RAN_INF_APP_ID_UTRA_SI:
924 /* TODO: add parsers for Si3, MBMS, SON, UTRA-SI app containers */
Philipp Maier836c6da2021-01-19 20:03:50 +0100925 return -EOPNOTSUPP;
Philipp Maier9828d282021-01-06 20:40:23 +0100926 default:
927 return -EINVAL;
928 }
929 if (rc < 0)
930 return rc;
931
932 return 0;
933}
934
935/*! Encode a RAN Information Application Error RIM Container (3GPP TS 48.018, table 11.3.62a.5.b).
936 * \param[out] buf user provided memory for the generated value part of the IE.
937 * \param[in] cont user provided input data struct.
938 * \returns length of encoded octets, -EINVAL on error. */
939int bssgp_enc_ran_inf_app_err_rim_cont(uint8_t *buf, size_t len, const struct bssgp_ran_inf_app_err_rim_cont *cont)
940{
941 uint8_t *buf_ptr = buf;
942 int app_cont_len = 0;
943 int remaining_buf_len;
944
945 buf_ptr = enc_rim_cont_common(buf_ptr, len, (struct bssgp_ran_inf_x_cont *)cont);
946 if (!buf_ptr)
947 return -EINVAL;
948
949 remaining_buf_len = len - (int)(buf_ptr - buf);
950 if (remaining_buf_len <= 0)
951 return -EINVAL;
952
953 switch (cont->app_id) {
954 case BSSGP_RAN_INF_APP_ID_NACC:
955 app_cont_len =
956 bssgp_enc_app_err_cont_nacc(buf_ptr + TVLV_HDR_LEN, remaining_buf_len - TVLV_HDR_MAXLEN,
957 &cont->u.app_err_cont_nacc);
958 break;
959 case BSSGP_RAN_INF_APP_ID_SI3:
960 case BSSGP_RAN_INF_APP_ID_MBMS:
961 case BSSGP_RAN_INF_APP_ID_SON:
962 case BSSGP_RAN_INF_APP_ID_UTRA_SI:
963 /* TODO: add encoders for Si3, MBMS, SON, UTRA-SI app containers */
Philipp Maier836c6da2021-01-19 20:03:50 +0100964 return -EOPNOTSUPP;
Philipp Maier9828d282021-01-06 20:40:23 +0100965 default:
966 return -EINVAL;
967 }
968 if (app_cont_len < 0)
969 return -EINVAL;
970 buf_ptr = dub_tlvp_header(buf_ptr, BSSGP_IE_APP_ERROR_CONTAINER, app_cont_len);
971
972 return (int)(buf_ptr - buf);
973}
Philipp Maier4d400472021-01-26 12:57:13 +0100974
975/*! Parse a given message buffer into a rim-pdu struct.
976 * \param[out] pdu user provided memory for the resulting RAN INFORMATION PDU.
977 * \param[in] msg BSSGP message buffer that contains the encoded RAN INFORMATION PDU.
978 * \returns 0 on sccess, -EINVAL on error. */
979int bssgp_parse_rim_pdu(struct bssgp_ran_information_pdu *pdu, const struct msgb *msg)
980{
981 struct tlv_parsed tp[2];
982 struct bssgp_normal_hdr *bgph = (struct bssgp_normal_hdr *)msgb_bssgph(msg);
983 int data_len;
984 int rc;
985 uint16_t nsei = msgb_nsei(msg);
986
987 memset(pdu, 0, sizeof(*pdu));
988
989 data_len = msgb_bssgp_len(msg) - sizeof(*bgph);
990 if (data_len < 0)
991 return -EINVAL;
992
993 rc = osmo_tlv_prot_parse(&osmo_pdef_bssgp, tp, ARRAY_SIZE(tp), bgph->pdu_type, bgph->data, data_len, 0, 0,
994 DLBSSGP, __func__);
995 if (rc < 0)
996 return -EINVAL;
997
998 if (TLVP_PRESENT(&tp[0], BSSGP_IE_RIM_ROUTING_INFO)) {
999 rc = bssgp_parse_rim_ri(&pdu->routing_info_dest, TLVP_VAL(&tp[0], BSSGP_IE_RIM_ROUTING_INFO),
1000 TLVP_LEN(&tp[0], BSSGP_IE_RIM_ROUTING_INFO));
1001 if (rc < 0) {
1002 LOGP(DLBSSGP, LOGL_ERROR, "BSSGP RIM (NSEI=%u) invalid Destination Cell Identifier IE\n", nsei);
1003 return -EINVAL;
1004 }
1005 } else {
1006 LOGP(DLBSSGP, LOGL_ERROR, "BSSGP RIM (NSEI=%u) missing Destination Cell Identifier IE\n", nsei);
1007 return -EINVAL;
1008 }
1009
1010 if (TLVP_PRESENT(&tp[1], BSSGP_IE_RIM_ROUTING_INFO)) {
1011 rc = bssgp_parse_rim_ri(&pdu->routing_info_src, TLVP_VAL(&tp[1], BSSGP_IE_RIM_ROUTING_INFO),
1012 TLVP_LEN(&tp[1], BSSGP_IE_RIM_ROUTING_INFO));
1013 if (rc < 0) {
1014 LOGP(DLBSSGP, LOGL_ERROR, "BSSGP RIM (NSEI=%u) invalid Destination Cell Identifier IE\n", nsei);
1015 return -EINVAL;
1016 }
1017 } else {
1018 LOGP(DLBSSGP, LOGL_ERROR, "BSSGP RIM (NSEI=%u) missing Source Cell Identifier IE\n", nsei);
1019 return -EINVAL;
1020 }
1021
1022 if (TLVP_PRESENT(&tp[0], BSSGP_IE_RI_REQ_RIM_CONTAINER))
1023 pdu->rim_cont_iei = BSSGP_IE_RI_REQ_RIM_CONTAINER;
1024 else if (TLVP_PRESENT(&tp[0], BSSGP_IE_RI_RIM_CONTAINER))
1025 pdu->rim_cont_iei = BSSGP_IE_RI_RIM_CONTAINER;
1026 else if (TLVP_PRESENT(&tp[0], BSSGP_IE_RI_APP_ERROR_RIM_CONT))
1027 pdu->rim_cont_iei = BSSGP_IE_RI_APP_ERROR_RIM_CONT;
1028 else if (TLVP_PRESENT(&tp[0], BSSGP_IE_RI_ACK_RIM_CONTAINER))
1029 pdu->rim_cont_iei = BSSGP_IE_RI_ACK_RIM_CONTAINER;
1030 else if (TLVP_PRESENT(&tp[0], BSSGP_IE_RI_ERROR_RIM_COINTAINER))
1031 pdu->rim_cont_iei = BSSGP_IE_RI_ERROR_RIM_COINTAINER;
1032 else {
1033 LOGP(DLBSSGP, LOGL_ERROR, "BSSGP RIM (NSEI=%u) missing or wrong RIM Container IE\n", nsei);
1034 return -EINVAL;
1035 }
1036
1037 pdu->rim_cont = TLVP_VAL(&tp[0], pdu->rim_cont_iei);
1038 pdu->rim_cont_len = TLVP_LEN(&tp[0], pdu->rim_cont_iei);
1039
1040 /* Make sure the rim container field is not empty */
1041 if (pdu->rim_cont_len < 1)
1042 return -EINVAL;
1043 if (!pdu->rim_cont)
1044 return -EINVAL;
1045
1046 /* Note: It is not an error if we fail to parse the RIM container,
1047 * since there are applications where parsing the RIM container
1048 * is not necessary (routing). It is up to the API user to check
1049 * the results. */
1050 switch (pdu->rim_cont_iei) {
1051 case BSSGP_IE_RI_REQ_RIM_CONTAINER:
1052 rc = bssgp_dec_ran_inf_req_rim_cont(&pdu->decoded.req_rim_cont, pdu->rim_cont, pdu->rim_cont_len);
1053 break;
1054 case BSSGP_IE_RI_RIM_CONTAINER:
1055 rc = bssgp_dec_ran_inf_rim_cont(&pdu->decoded.rim_cont, pdu->rim_cont, pdu->rim_cont_len);
1056 break;
1057 case BSSGP_IE_RI_APP_ERROR_RIM_CONT:
1058 rc = bssgp_dec_ran_inf_app_err_rim_cont(&pdu->decoded.app_err_rim_cont, pdu->rim_cont,
1059 pdu->rim_cont_len);
1060 break;
1061 case BSSGP_IE_RI_ACK_RIM_CONTAINER:
1062 rc = bssgp_dec_ran_inf_ack_rim_cont(&pdu->decoded.ack_rim_cont, pdu->rim_cont, pdu->rim_cont_len);
1063 break;
1064 case BSSGP_IE_RI_ERROR_RIM_COINTAINER:
1065 rc = bssgp_dec_ran_inf_err_rim_cont(&pdu->decoded.err_rim_cont, pdu->rim_cont, pdu->rim_cont_len);
1066 break;
1067 default:
1068 LOGP(DLBSSGP, LOGL_DEBUG, "BSSGP RIM (NSEI=%u) cannot parse unknown RIM container.\n", nsei);
1069 return 0;
1070 }
1071 if (rc < 0) {
1072 LOGP(DLBSSGP, LOGL_DEBUG, "BSSGP RIM (NSEI=%u) unable to parse RIM container.\n", nsei);
1073 return 0;
1074 }
1075 pdu->decoded_present = true;
1076
1077 return 0;
1078}
1079
1080/*! Encode a given rim-pdu struct into a message buffer.
1081 * \param[out] pdu user provided memory that contains the RAN INFORMATION PDU to encode.
1082 * \returns BSSGP message buffer on sccess, NULL on error. */
Pau Espin Pedroladef5462021-05-06 18:17:18 +02001083struct msgb *bssgp_encode_rim_pdu(const struct bssgp_ran_information_pdu *pdu)
Philipp Maier4d400472021-01-26 12:57:13 +01001084{
1085 struct msgb *msg = bssgp_msgb_alloc();
1086 struct bssgp_normal_hdr *bgph;
1087 uint8_t rim_ri_buf[BSSGP_RIM_ROUTING_INFO_MAXLEN];
Philipp Maier4d400472021-01-26 12:57:13 +01001088 int rc;
1089
1090 if (!msg)
1091 return NULL;
1092 bgph = (struct bssgp_normal_hdr *)msgb_put(msg, sizeof(*bgph));
1093
1094 /* Set PDU type based on RIM container type */
1095 switch (pdu->rim_cont_iei) {
1096 case BSSGP_IE_RI_REQ_RIM_CONTAINER:
1097 bgph->pdu_type = BSSGP_PDUT_RAN_INFO_REQ;
1098 break;
1099 case BSSGP_IE_RI_RIM_CONTAINER:
1100 bgph->pdu_type = BSSGP_PDUT_RAN_INFO;
1101 break;
1102 case BSSGP_IE_RI_APP_ERROR_RIM_CONT:
1103 bgph->pdu_type = BSSGP_PDUT_RAN_INFO_APP_ERROR;
1104 break;
1105 case BSSGP_IE_RI_ACK_RIM_CONTAINER:
1106 bgph->pdu_type = BSSGP_PDUT_RAN_INFO_ACK;
1107 break;
1108 case BSSGP_IE_RI_ERROR_RIM_COINTAINER:
1109 bgph->pdu_type = BSSGP_PDUT_RAN_INFO_ERROR;
1110 break;
1111 default:
1112 /* The caller must correctly specify the container type! */
1113 OSMO_ASSERT(false);
1114 }
1115
1116 /* Put RIM routing information */
1117 rc = bssgp_create_rim_ri(rim_ri_buf, &pdu->routing_info_dest);
1118 if (rc < 0 || rc > BSSGP_RIM_ROUTING_INFO_MAXLEN)
1119 goto error;
1120 msgb_tvlv_put(msg, BSSGP_IE_RIM_ROUTING_INFO, rc, rim_ri_buf);
1121 rc = bssgp_create_rim_ri(rim_ri_buf, &pdu->routing_info_src);
1122 if (rc < 0 || rc > BSSGP_RIM_ROUTING_INFO_MAXLEN)
1123 goto error;
1124 msgb_tvlv_put(msg, BSSGP_IE_RIM_ROUTING_INFO, rc, rim_ri_buf);
1125
1126 /* Put RIM container */
1127 if (pdu->decoded_present) {
Vadim Yanitskiy0578c282022-07-04 20:47:16 +07001128 uint8_t *rim_cont_buf = talloc_zero_size(msg, msg->data_len);
Philipp Maier4d400472021-01-26 12:57:13 +01001129 if (!rim_cont_buf)
1130 goto error;
1131
1132 switch (pdu->rim_cont_iei) {
1133 case BSSGP_IE_RI_REQ_RIM_CONTAINER:
1134 rc = bssgp_enc_ran_inf_req_rim_cont(rim_cont_buf, msg->data_len, &pdu->decoded.req_rim_cont);
1135 break;
1136 case BSSGP_IE_RI_RIM_CONTAINER:
1137 rc = bssgp_enc_ran_inf_rim_cont(rim_cont_buf, msg->data_len, &pdu->decoded.rim_cont);
1138 break;
1139 case BSSGP_IE_RI_APP_ERROR_RIM_CONT:
1140 rc = bssgp_enc_ran_inf_app_err_rim_cont(rim_cont_buf, msg->data_len,
1141 &pdu->decoded.app_err_rim_cont);
1142 break;
1143 case BSSGP_IE_RI_ACK_RIM_CONTAINER:
1144 rc = bssgp_enc_ran_inf_ack_rim_cont(rim_cont_buf, msg->data_len, &pdu->decoded.ack_rim_cont);
1145 break;
1146 case BSSGP_IE_RI_ERROR_RIM_COINTAINER:
1147 rc = bssgp_enc_ran_inf_err_rim_cont(rim_cont_buf, msg->data_len, &pdu->decoded.err_rim_cont);
1148 break;
1149 default:
1150 /* The API user must set the iei properly! */
1151 OSMO_ASSERT(false);
1152 }
Vadim Yanitskiy0578c282022-07-04 20:47:16 +07001153 if (rc < 0) {
1154 talloc_free(rim_cont_buf);
Philipp Maier4d400472021-01-26 12:57:13 +01001155 goto error;
Vadim Yanitskiy0578c282022-07-04 20:47:16 +07001156 }
Philipp Maier4d400472021-01-26 12:57:13 +01001157
1158 msgb_tvlv_put(msg, pdu->rim_cont_iei, rc, rim_cont_buf);
1159 talloc_free(rim_cont_buf);
1160 } else {
1161 /* Make sure the RIM container is actually present. */
1162 OSMO_ASSERT(pdu->rim_cont_iei != 0 && pdu->rim_cont_len > 0 && pdu->rim_cont);
1163 msgb_tvlv_put(msg, pdu->rim_cont_iei, pdu->rim_cont_len, pdu->rim_cont);
1164 }
1165
1166 return msg;
1167error:
Philipp Maier4d400472021-01-26 12:57:13 +01001168 msgb_free(msg);
1169 return 0;
1170}
1171
1172/*! Send RIM RAN INFORMATION REQUEST via BSSGP (3GPP TS 48.018, section 10.6.1).
1173 * \param[in] pdu user provided memory for the RAN INFORMATION PDU to be sent.
1174 * \param[in] nsei BSSGP network service entity identifier (NSEI).
1175 * \returns 0 on sccess, -EINVAL on error. */
1176int bssgp_tx_rim(const struct bssgp_ran_information_pdu *pdu, uint16_t nsei)
1177{
1178 struct msgb *msg;
1179 struct bssgp_normal_hdr *bgph;
1180 char ri_src_str[64];
1181 char ri_dest_str[64];
1182
1183 /* Encode RIM PDU into mesage buffer */
Pau Espin Pedroladef5462021-05-06 18:17:18 +02001184 msg = bssgp_encode_rim_pdu(pdu);
Philipp Maier4d400472021-01-26 12:57:13 +01001185 if (!msg) {
1186 LOGP(DLBSSGP, LOGL_ERROR,
1187 "BSSGP RIM (NSEI=%u) unable to encode BSSGP RIM PDU\n", nsei);
1188 return -EINVAL;
1189 }
1190
1191 msgb_nsei(msg) = nsei;
1192 msgb_bvci(msg) = 0; /* Signalling */
1193
1194 bgph = (struct bssgp_normal_hdr *)msgb_bssgph(msg);
Philipp Maiera0d84832023-08-09 16:35:44 +02001195 DEBUGP(DLBSSGP, "BSSGP BVCI=0 NSEI=%u Tx RIM-PDU:%s, src=%s, dest=%s\n",
1196 nsei, bssgp_pdu_str(bgph->pdu_type),
Philipp Maier4d400472021-01-26 12:57:13 +01001197 bssgp_rim_ri_name_buf(ri_src_str, sizeof(ri_src_str), &pdu->routing_info_src),
1198 bssgp_rim_ri_name_buf(ri_dest_str, sizeof(ri_dest_str), &pdu->routing_info_dest));
1199
1200 return bssgp_ns_send(bssgp_ns_send_data, msg);
1201}
1202
Philipp Maier9e755442023-08-09 16:39:06 +02001203/*! Send encoded RAN TRANSPARENT CONTAINER via BSSGP (3GPP TS 29.060, section 7.7.43).
1204 * \param[in] msg user provided memory for the encoded RAN TRANSPARENT CONTAINER to be sent.
1205 * (this function will take ownership of msg).
1206 * \param[in] nsei BSSGP network service entity identifier (NSEI).
1207 * \returns 0 on sccess, -EINVAL on error. */
1208int bssgp_tx_rim_encoded(struct msgb *msg, uint16_t nsei)
1209{
1210 struct bssgp_normal_hdr *bgph;
1211
1212 msgb_nsei(msg) = nsei;
1213 msgb_bvci(msg) = 0; /* Signalling */
1214
1215 bgph = (struct bssgp_normal_hdr *)msgb_bssgph(msg);
1216 DEBUGP(DLBSSGP, "BSSGP BVCI=0 NSEI=%u Tx RIM-PDU:%s\n",
1217 nsei, bssgp_pdu_str(bgph->pdu_type));
1218
1219 return bssgp_ns_send(bssgp_ns_send_data, msg);
1220}
1221
Philipp Maier4d400472021-01-26 12:57:13 +01001222/* For internal use only (called from gprs_bssgp.c) */
1223int bssgp_rx_rim(struct msgb *msg, struct tlv_parsed *tp, uint16_t bvci)
1224{
1225 struct osmo_bssgp_prim nmp;
1226 uint16_t nsei = msgb_nsei(msg);
1227 struct bssgp_normal_hdr *bgph = (struct bssgp_normal_hdr *)msgb_bssgph(msg);
1228 enum bssgp_prim prim;
1229 char ri_src_str[64];
1230 char ri_dest_str[64];
1231
1232 /* Specify PRIM type based on the RIM PDU */
1233 switch (bgph->pdu_type) {
1234 case BSSGP_PDUT_RAN_INFO:
1235 case BSSGP_PDUT_RAN_INFO_REQ:
1236 case BSSGP_PDUT_RAN_INFO_ACK:
1237 case BSSGP_PDUT_RAN_INFO_ERROR:
1238 case BSSGP_PDUT_RAN_INFO_APP_ERROR:
1239 prim = PRIM_BSSGP_RIM_PDU_TRANSFER;
1240 break;
1241 default:
1242 /* Caller already makes sure that this can't happen. */
1243 OSMO_ASSERT(false);
1244 }
1245
1246 /* Send BSSGP RIM indication to NM */
1247 memset(&nmp, 0, sizeof(nmp));
1248 nmp.nsei = nsei;
1249 nmp.bvci = bvci;
1250 nmp.tp = tp;
1251 if (bssgp_parse_rim_pdu(&nmp.u.rim_pdu, msg) < 0)
1252 return bssgp_tx_status(BSSGP_CAUSE_MISSING_MAND_IE, NULL, msg);
1253 DEBUGP(DLBSSGP, "BSSGP BVCI=%u Rx RIM-PDU:%s, src=%s, dest=%s\n",
1254 bvci, bssgp_pdu_str(bgph->pdu_type),
1255 bssgp_rim_ri_name_buf(ri_src_str, sizeof(ri_src_str), &nmp.u.rim_pdu.routing_info_src),
1256 bssgp_rim_ri_name_buf(ri_dest_str, sizeof(ri_dest_str), &nmp.u.rim_pdu.routing_info_dest));
1257 osmo_prim_init(&nmp.oph, SAP_BSSGP_RIM, prim, PRIM_OP_INDICATION, msg);
1258 bssgp_prim_cb(&nmp.oph, NULL);
1259
1260 return 0;
1261}