blob: 55609edba3cdf3738ab8f8a9b641d21971546fdc [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 Maier7450f772021-01-06 20:56:43 +010052/*! Parse a RIM Routing information IE (3GPP TS 48.018, chapter 11.3.70).
53 * \param[out] ri user provided memory to store the parsed results.
54 * \param[in] buf input buffer of the value part of the IE.
55 * \returns length of parsed octets, -EINVAL on error. */
56int bssgp_parse_rim_ri(struct bssgp_rim_routing_info *ri, const uint8_t *buf,
57 unsigned int len)
58{
59 struct gprs_ra_id raid_temp;
60
61 memset(ri, 0, sizeof(*ri));
62 if (len < 2)
63 return -EINVAL;
64
65 ri->discr = buf[0] & 0x0f;
66 buf++;
67
68 switch (ri->discr) {
69 case BSSGP_RIM_ROUTING_INFO_GERAN:
70 if (len < 9)
71 return -EINVAL;
72 ri->geran.cid = bssgp_parse_cell_id(&ri->geran.raid, buf);
73 return 9;
74 case BSSGP_RIM_ROUTING_INFO_UTRAN:
75 if (len < 9)
76 return -EINVAL;
77 gsm48_parse_ra(&ri->utran.raid, buf);
78 ri->utran.rncid = osmo_load16be(buf + 6);
79 return 9;
80 case BSSGP_RIM_ROUTING_INFO_EUTRAN:
81 if (len < 7 || len > 14)
82 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);
91 memcpy(ri->eutran.global_enb_id, buf + 5, len - 6);
92 ri->eutran.global_enb_id_len = len - 6;
93 return len;
94 default:
95 return -EINVAL;
96 }
97}
98
99/*! Encode a RIM Routing information IE (3GPP TS 48.018, chapter 11.3.70).
100 * \param[out] buf user provided memory (at least 14 byte) for the generated value part of the IE.
101 * \param[in] ri user provided input data struct.
102 * \returns length of encoded octets, -EINVAL on error. */
103int bssgp_create_rim_ri(uint8_t *buf, const struct bssgp_rim_routing_info *ri)
104{
105 int rc;
106 struct gprs_ra_id raid_temp;
Philipp Maier7741bc32021-01-07 21:55:48 +0100107 int len;
Philipp Maier7450f772021-01-06 20:56:43 +0100108
109 buf[0] = ri->discr & 0x0f;
110 buf++;
111
112 switch (ri->discr) {
113 case BSSGP_RIM_ROUTING_INFO_GERAN:
114 rc = bssgp_create_cell_id(buf, &ri->geran.raid, ri->geran.cid);
115 if (rc < 0)
116 return -EINVAL;
Philipp Maier7741bc32021-01-07 21:55:48 +0100117 len = rc + 1;
118 break;
Philipp Maier7450f772021-01-06 20:56:43 +0100119 case BSSGP_RIM_ROUTING_INFO_UTRAN:
120 gsm48_encode_ra((struct gsm48_ra_id *)buf, &ri->utran.raid);
121 osmo_store16be(ri->utran.rncid, buf + 6);
Philipp Maier7741bc32021-01-07 21:55:48 +0100122 len = 9;
123 break;
Philipp Maier7450f772021-01-06 20:56:43 +0100124 case BSSGP_RIM_ROUTING_INFO_EUTRAN:
125 /* Note: 3GPP TS 24.301 Figure 9.9.3.32.1 and 3GPP TS 24.008
126 * Figure 10.5.130 specify MCC/MNC encoding in the same way,
127 * so we can re-use gsm48_encode_ra() for that. */
128 raid_temp = (struct gprs_ra_id) {
129 .mcc = ri->eutran.tai.mcc,
130 .mnc = ri->eutran.tai.mnc,
131 .mnc_3_digits = ri->eutran.tai.mnc_3_digits,
132 };
133
134 gsm48_encode_ra((struct gsm48_ra_id *)buf, &raid_temp);
135 osmo_store16be(ri->eutran.tai.tac, buf + 3);
136 OSMO_ASSERT(ri->eutran.global_enb_id_len <=
137 sizeof(ri->eutran.global_enb_id));
138 memcpy(buf + 5, ri->eutran.global_enb_id,
139 ri->eutran.global_enb_id_len);
Philipp Maier7741bc32021-01-07 21:55:48 +0100140 len = ri->eutran.global_enb_id_len + 6;
141 break;
Philipp Maier7450f772021-01-06 20:56:43 +0100142 default:
143 return -EINVAL;
144 }
Philipp Maier7741bc32021-01-07 21:55:48 +0100145
146 OSMO_ASSERT(len <= BSSGP_RIM_ROUTING_INFO_MAXLEN);
147 return len;
Philipp Maier7450f772021-01-06 20:56:43 +0100148}
149
Philipp Maierc08a3fd2021-01-25 22:00:01 +0100150/*! Encode a RIM Routing information into a human readable string.
151 * \param[buf] user provided string buffer to store the resulting string.
152 * \param[buf_len] maximum length of string buffer.
153 * \param[in] ri user provided input data struct.
154 * \returns pointer to the beginning of the resulting string stored in string buffer. */
155char *bssgp_rim_ri_name_buf(char *buf, size_t buf_len, const struct bssgp_rim_routing_info *ri)
156{
157 char plmn_str[16];
158 char enb_id_str[16];
159 char g_id_ps_str[32];
160 struct osmo_plmn_id plmn;
161 struct osmo_cell_global_id_ps g_id_ps;
162
163 if (!ri)
164 return NULL;
165
166 switch (ri->discr) {
167 case BSSGP_RIM_ROUTING_INFO_GERAN:
168 g_id_ps.rai.rac = ri->geran.raid.rac;
169 g_id_ps.rai.lac.lac = ri->geran.raid.lac;
170 g_id_ps.rai.lac.plmn.mcc = ri->geran.raid.mcc;
171 g_id_ps.rai.lac.plmn.mnc_3_digits = ri->geran.raid.mnc_3_digits;
172 g_id_ps.rai.lac.plmn.mnc = ri->geran.raid.mnc;
173 g_id_ps.cell_identity = ri->geran.cid;
174 snprintf(buf, buf_len, "%s-%s", bssgp_rim_routing_info_discr_str(ri->discr),
175 osmo_cgi_ps_name_buf(g_id_ps_str, sizeof(g_id_ps_str), &g_id_ps));
176 break;
177 case BSSGP_RIM_ROUTING_INFO_UTRAN:
178 g_id_ps.rai.rac = ri->utran.raid.rac;
179 g_id_ps.rai.lac.lac = ri->utran.raid.lac;
180 g_id_ps.rai.lac.plmn.mcc = ri->utran.raid.mcc;
181 g_id_ps.rai.lac.plmn.mnc_3_digits = ri->utran.raid.mnc_3_digits;
182 g_id_ps.rai.lac.plmn.mnc = ri->utran.raid.mnc;
183 g_id_ps.cell_identity = ri->utran.rncid;
184 snprintf(buf, buf_len, "%s-%s", bssgp_rim_routing_info_discr_str(ri->discr),
185 osmo_cgi_ps_name_buf(g_id_ps_str, sizeof(g_id_ps_str), &g_id_ps));
186 break;
187 case BSSGP_RIM_ROUTING_INFO_EUTRAN:
188 plmn.mcc = ri->eutran.tai.mcc;
189 plmn.mnc = ri->eutran.tai.mnc;
190 plmn.mnc_3_digits = ri->eutran.tai.mnc_3_digits;
191 snprintf(buf, buf_len, "%s-%s-%u-%s", bssgp_rim_routing_info_discr_str(ri->discr),
192 osmo_plmn_name_buf(plmn_str, sizeof(plmn_str), &plmn), ri->eutran.tai.tac,
193 osmo_hexdump_buf(enb_id_str, sizeof(enb_id_str), ri->eutran.global_enb_id,
194 ri->eutran.global_enb_id_len, "", false));
195 break;
196 default:
197 snprintf(buf, buf_len, "invalid");
198 }
199
200 return buf;
201}
202
203/*! Encode a RIM Routing information into a human readable string.
204 * \param[in] ri user provided input data struct.
205 * \returns pointer to the resulting string. */
206const char *bssgp_rim_ri_name(const struct bssgp_rim_routing_info *ri)
207{
208 static __thread char rim_ri_buf[64];
209 return bssgp_rim_ri_name_buf(rim_ri_buf, sizeof(rim_ri_buf), ri);
210}
211
Philipp Maier9828d282021-01-06 20:40:23 +0100212/*! Decode a RAN Information Request Application Container for NACC (3GPP TS 48.018, section 11.3.63.1.1).
213 * \param[out] user provided memory for decoded data struct.
214 * \param[in] buf user provided memory with the encoded value data of the IE.
215 * \returns 0 on success, -EINVAL on error. */
216int bssgp_dec_ran_inf_req_app_cont_nacc(struct bssgp_ran_inf_req_app_cont_nacc *cont, const uint8_t *buf, size_t len)
217{
218 int rc;
219
220 if (len < REP_CELL_ID_LEN)
221 return -EINVAL;
222
223 rc = gsm0808_decode_cell_id_u((union gsm0808_cell_id_u*)&cont->reprt_cell,
224 CELL_IDENT_WHOLE_GLOBAL_PS, buf, len);
225 if (rc < 0)
226 return -EINVAL;
227
228 return 0;
229}
230
231/*! Encode a RAN Information Request Application Container for NACC (3GPP TS 48.018, section 11.3.63.1.1).
232 * \param[out] buf user provided memory for the generated value part of the IE.
233 * \param[in] cont user provided input data struct.
234 * \returns length of encoded octets, -EINVAL on error. */
235int bssgp_enc_ran_inf_req_app_cont_nacc(uint8_t *buf, size_t len, const struct bssgp_ran_inf_req_app_cont_nacc *cont)
236{
237 int rc;
238 struct gprs_ra_id *raid;
239
240 if (len < REP_CELL_ID_LEN)
241 return -EINVAL;
242
243 raid = (struct gprs_ra_id *)&cont->reprt_cell.rai;
244 rc = bssgp_create_cell_id(buf, raid, cont->reprt_cell.cell_identity);
245 if (rc < 0)
246 return -EINVAL;
247 return rc;
248}
249
250/*! Decode a RAN Information Application Container (3GPP TS 48.018, section 11.3.63.2.1).
251 * \param[out] user provided memory for decoded data struct.
252 * \param[in] buf user provided memory with the encoded value data of the IE.
253 * \returns 0 on success, -EINVAL on error. */
254int bssgp_dec_ran_inf_app_cont_nacc(struct bssgp_ran_inf_app_cont_nacc *cont, const uint8_t *buf, size_t len)
255{
256 unsigned int i;
257 int remaining_buf_len;
258 int rc;
259
260 /* The given buffer must at least contain a reporting cell identifer
261 * plus one octet that defines number/type of attached sysinfo messages. */
262 if (len < REP_CELL_ID_LEN + 1)
263 return -EINVAL;
264
265 rc = gsm0808_decode_cell_id_u((union gsm0808_cell_id_u*)&cont->reprt_cell,
266 CELL_IDENT_WHOLE_GLOBAL_PS, buf, len);
267 if (rc < 0)
268 return -EINVAL;
269
270 buf += REP_CELL_ID_LEN;
271
272 cont->type_psi = buf[0] & 1;
273 cont->num_si = buf[0] >> 1;
274 buf++;
275
276 /* The number of sysinfo messages may be zero */
277 if (cont->num_si == 0)
278 return 0;
279
280 /* Check if the prospected system information messages fit in the
281 * remaining buffer space */
282 remaining_buf_len = len - REP_CELL_ID_LEN - 1;
283 if (remaining_buf_len <= 0)
284 return -EINVAL;
285 if (cont->type_psi && remaining_buf_len / BSSGP_RIM_PSI_LEN < cont->num_si)
286 return -EINVAL;
287 else if (remaining_buf_len / BSSGP_RIM_SI_LEN < cont->num_si)
288 return -EINVAL;
289
290 for (i = 0; i < cont->num_si; i++) {
291 cont->si[i] = buf;
292 if (cont->type_psi)
293 buf += BSSGP_RIM_PSI_LEN;
294 else
295 buf += BSSGP_RIM_SI_LEN;
296 }
297
298 return 0;
299}
300
301/*! Encode a RAN Information Application Container (3GPP TS 48.018, section 11.3.63.2.1).
302 * \param[out] buf user provided memory for the generated value part of the IE.
303 * \param[in] cont user provided input data struct.
304 * \returns length of encoded octets, -EINVAL on error. */
305int bssgp_enc_ran_inf_app_cont_nacc(uint8_t *buf, size_t len, const struct bssgp_ran_inf_app_cont_nacc *cont)
306{
307 uint8_t *buf_ptr = buf;
308 int rc;
309 unsigned int silen;
310 unsigned int i;
311 struct gprs_ra_id *raid;
312
313 if (cont->type_psi)
314 silen = BSSGP_RIM_PSI_LEN;
315 else
316 silen = BSSGP_RIM_SI_LEN;
317
318 /* The buffer must accept the reporting cell id, plus 1 byte to define
319 * the type and number of sysinfo messages. */
320 if (len < REP_CELL_ID_LEN + 1 + silen * cont->num_si)
321 return -EINVAL;
322
323 raid = (struct gprs_ra_id *)&cont->reprt_cell.rai;
324 rc = bssgp_create_cell_id(buf_ptr, raid, cont->reprt_cell.cell_identity);
325 if (rc < 0)
326 return -EINVAL;
327 buf_ptr += rc;
328
329 buf_ptr[0] = 0x00;
330 if (cont->type_psi)
331 buf_ptr[0] |= 0x01;
332 buf_ptr[0] |= (cont->num_si << 1);
333 buf_ptr++;
334
335 for (i = 0; i < cont->num_si; i++) {
336 memcpy(buf_ptr, cont->si[i], silen);
337 buf_ptr += silen;
338 }
339
340 return (int)(buf_ptr - buf);
341}
342
Philipp Maier139c4ae2021-01-22 17:19:05 +0100343/* 3GPP TS 48.018, table 11.3.64.1.b, NACC Cause coding */
344const struct value_string bssgp_nacc_cause_strs[] = {
345 { BSSGP_NACC_CAUSE_UNSPEC, "unspecified error" },
346 { BSSGP_NACC_CAUSE_SYNTAX_ERR, "syntax error in app container" },
347 { BSSGP_NACC_CAUSE_RPRT_CELL_MISSMTCH, "reporting cell id mismatch" },
348 { BSSGP_NACC_CAUSE_SIPSI_TYPE_ERR, "SI/PSI type error" },
349 { BSSGP_NACC_CAUSE_SIPSI_LEN_ERR, "SI/PSI inconsistent length" },
350 { BSSGP_NACC_CAUSE_SIPSI_SET_ERR, "inconsistent set of msg" },
351 { 0, NULL }
352};
353
Philipp Maier9828d282021-01-06 20:40:23 +0100354/*! Decode a Application Error Container for NACC (3GPP TS 48.018, section 11.3.64.1).
355 * \param[out] user provided memory for decoded data struct.
356 * \param[in] buf user provided memory with the encoded value data of the IE.
357 * \returns 0 on success, -EINVAL on error. */
358int bssgp_dec_app_err_cont_nacc(struct bssgp_app_err_cont_nacc *cont, const uint8_t *buf, size_t len)
359{
360 /* The buffer must at least contain the NACC cause code, it should also
361 * contain the application container, but we won't error if it is missing. */
362 if (len < 1)
363 return -EINVAL;
364
365 cont->nacc_cause = buf[0];
366
367 if (len > 1) {
368 cont->err_app_cont = buf + 1;
369 cont->err_app_cont_len = len - 1;
370 } else {
371 cont->err_app_cont = NULL;
372 cont->err_app_cont_len = 0;
373 }
374
375 return 0;
376}
377
378/*! Encode Application Error Container for NACC (3GPP TS 48.018, section 11.3.64.1).
379 * \param[out] buf user provided memory for the generated value part of the IE.
380 * \param[in] cont user provided input data struct.
381 * \returns length of encoded octets, -EINVAL on error. */
382int bssgp_enc_app_err_cont_nacc(uint8_t *buf, size_t len, const struct bssgp_app_err_cont_nacc *cont)
383{
384 uint8_t *buf_ptr = buf;
385
386 /* The buffer must accept the length of the application container and the NACC
387 * cause code, which is one octet in length. */
388 if (len < cont->err_app_cont_len + 1)
389 return -EINVAL;
390
391 buf_ptr[0] = cont->nacc_cause;
392 buf_ptr++;
393
394 memcpy(buf_ptr, cont->err_app_cont, cont->err_app_cont_len);
395 buf_ptr += cont->err_app_cont_len;
396
397 return (int)(buf_ptr - buf);
398}
399
400/* The structs bssgp_ran_inf_req_rim_cont, bssgp_ran_inf_rim_cont and bssgp_ran_inf_app_err_rim_cont *cont
401 * share four common fields at the beginning, we use the following struct as parameter type for the common
402 * encoder/decoder functions. (See also 3GPP TS 48.018 table 11.3.62a.1.b, table 11.3.62a.2.b, and
403 * table 11.3.62a.5.b) */
404struct bssgp_ran_inf_x_cont {
405 enum bssgp_ran_inf_app_id app_id;
406 uint32_t seq_num;
407 struct bssgp_rim_pdu_ind pdu_ind;
408 uint8_t prot_ver;
409};
410
411static int dec_rim_cont_common(struct bssgp_ran_inf_x_cont *cont, struct tlv_parsed *tp)
412{
413 if (TLVP_PRES_LEN(tp, BSSGP_IE_RIM_APP_IDENTITY, sizeof(uint8_t)))
414 cont->app_id = TLVP_VAL(tp, BSSGP_IE_RIM_APP_IDENTITY)[0];
415 else
416 return -EINVAL;
417
418 if (TLVP_PRES_LEN(tp, BSSGP_IE_RIM_SEQ_NR, sizeof(cont->seq_num)))
419 cont->seq_num = tlvp_val32be(tp, BSSGP_IE_RIM_SEQ_NR);
420 else
421 return -EINVAL;
422
423 if (TLVP_PRES_LEN(tp, BSSGP_IE_RIM_PDU_INDICATIONS, sizeof(cont->pdu_ind)))
424 memcpy(&cont->pdu_ind, TLVP_VAL(tp, BSSGP_IE_RIM_PDU_INDICATIONS), sizeof(cont->pdu_ind));
425 else
426 return -EINVAL;
427
428 if (TLVP_PRES_LEN(tp, BSSGP_IE_RIM_PROTOCOL_VERSION, sizeof(cont->prot_ver)))
429 cont->prot_ver = TLVP_VAL(tp, BSSGP_IE_RIM_PROTOCOL_VERSION)[0];
430 else
431 cont->prot_ver = 1;
432
433 return 0;
434}
435
436static uint8_t *enc_rim_cont_common(uint8_t *buf, size_t len, const struct bssgp_ran_inf_x_cont *cont)
437{
438
439 uint32_t seq_num = osmo_htonl(cont->seq_num);
440 uint8_t app_id_temp;
441 uint8_t *buf_ptr = buf;
442
443 if (len <
444 TVLV_HDR_MAXLEN * 4 + sizeof(app_id_temp) + sizeof(seq_num) + sizeof(cont->pdu_ind) +
445 sizeof(cont->prot_ver))
446 return NULL;
447
448 app_id_temp = cont->app_id;
449 buf_ptr = tvlv_put(buf_ptr, BSSGP_IE_RIM_APP_IDENTITY, sizeof(app_id_temp), &app_id_temp);
450 buf_ptr = tvlv_put(buf_ptr, BSSGP_IE_RIM_SEQ_NR, sizeof(seq_num), (uint8_t *) & seq_num);
451 buf_ptr = tvlv_put(buf_ptr, BSSGP_IE_RIM_PDU_INDICATIONS, sizeof(cont->pdu_ind), (uint8_t *) & cont->pdu_ind);
452 if (cont->prot_ver > 0)
453 buf_ptr = tvlv_put(buf_ptr, BSSGP_IE_RIM_PROTOCOL_VERSION, sizeof(cont->prot_ver), &cont->prot_ver);
454
455 return buf_ptr;
456}
457
Philipp Maier8b19d062021-01-22 18:05:35 +0100458/* 3GPP TS 48.018, table 11.3.61.b: RIM Application Identity coding */
459const struct value_string bssgp_ran_inf_app_id_strs[] = {
460 { BSSGP_RAN_INF_APP_ID_NACC, "Network Assisted Cell Change (NACC)" },
461 { BSSGP_RAN_INF_APP_ID_SI3, "System Information 3 (SI3)" },
462 { BSSGP_RAN_INF_APP_ID_MBMS, "MBMS data channel" },
463 { BSSGP_RAN_INF_APP_ID_SON, "SON Transfer" },
464 { BSSGP_RAN_INF_APP_ID_UTRA_SI, "UTRA System Information (UTRA SI)" },
465 { 0, NULL }
466};
467
Philipp Maier9828d282021-01-06 20:40:23 +0100468/*! Decode a RAN Information Request RIM Container (3GPP TS 48.018, table 11.3.62a.1.b).
469 * \param[out] user provided memory for decoded data struct.
470 * \param[in] buf user provided memory with the encoded value data of the IE.
471 * \returns 0 on success, -EINVAL on error. */
472int bssgp_dec_ran_inf_req_rim_cont(struct bssgp_ran_inf_req_rim_cont *cont, const uint8_t *buf, size_t len)
473{
474 int rc;
475 struct tlv_parsed tp;
476
477 memset(cont, 0, sizeof(*cont));
478
479 rc = tlv_parse(&tp, &tvlv_att_def, buf, len, 0, 0);
480 if (rc < 0)
481 return -EINVAL;
482
483 rc = dec_rim_cont_common((struct bssgp_ran_inf_x_cont *)cont, &tp);
484 if (rc < 0)
485 return -EINVAL;
486
487 if (TLVP_PRESENT(&tp, BSSGP_IE_RIM_REQ_APP_CONTAINER)) {
488 switch (cont->app_id) {
489 case BSSGP_RAN_INF_APP_ID_NACC:
490 rc = bssgp_dec_ran_inf_req_app_cont_nacc(&cont->u.app_cont_nacc,
491 TLVP_VAL(&tp, BSSGP_IE_RIM_REQ_APP_CONTAINER),
492 TLVP_LEN(&tp, BSSGP_IE_RIM_REQ_APP_CONTAINER));
493 break;
494 case BSSGP_RAN_INF_APP_ID_SI3:
495 case BSSGP_RAN_INF_APP_ID_MBMS:
496 case BSSGP_RAN_INF_APP_ID_SON:
497 case BSSGP_RAN_INF_APP_ID_UTRA_SI:
498 /* TODO: add parsers for Si3, MBMS, SON, UTRA-SI app containers */
Philipp Maier836c6da2021-01-19 20:03:50 +0100499 return -EOPNOTSUPP;
Philipp Maier9828d282021-01-06 20:40:23 +0100500 default:
501 return -EINVAL;
502 }
503
504 if (rc < 0)
505 return rc;
506 }
507
508 if (TLVP_PRES_LEN(&tp, BSSGP_IE_SON_TRANSFER_APP_ID, 1)) {
509 cont->son_trans_app_id = TLVP_VAL(&tp, BSSGP_IE_SON_TRANSFER_APP_ID);
510 cont->son_trans_app_id_len = TLVP_LEN(&tp, BSSGP_IE_SON_TRANSFER_APP_ID);
511 }
512
513 return 0;
514}
515
516/* Dub a TLVP header into a given buffer. The value part of the IE must start
517 * at the 2nd octet. Should the length field make a 3 octet TLVP header
518 * necessary (unlikely, but possible) the value part is moved ahead by one
519 * octet. The function returns a pointer to the end of value part. */
520static uint8_t *dub_tlvp_header(uint8_t *buf, uint8_t iei, uint16_t len)
521{
522 uint8_t *buf_ptr = buf;
523
524 buf_ptr[0] = iei;
525 if (len <= TVLV_MAX_ONEBYTE) {
526 buf_ptr[1] = (uint8_t) len;
527 buf_ptr[1] |= 0x80;
528 buf_ptr += TVLV_HDR_LEN;
529 } else {
530 memmove(buf_ptr + 1, buf_ptr, len);
531 buf_ptr[1] = len >> 8;
Philipp Maier2b11fa92021-01-20 15:55:40 +0100532 buf_ptr[2] = len & 0xff;
Philipp Maier9828d282021-01-06 20:40:23 +0100533 buf_ptr += TVLV_HDR_MAXLEN;
534 }
535 buf_ptr += len;
536
537 return buf_ptr;
538}
539
540/*! Encode a RAN Information Request RIM Container (3GPP TS 48.018, table 11.3.62a.1.b).
541 * \param[out] buf user provided memory for the generated value part of the IE.
542 * \param[in] cont user provided input data struct.
543 * \returns length of encoded octets, -EINVAL on error. */
544int bssgp_enc_ran_inf_req_rim_cont(uint8_t *buf, size_t len, const struct bssgp_ran_inf_req_rim_cont *cont)
545{
546 uint8_t *buf_ptr = buf;
547 int app_cont_len = 0;
548 int remaining_buf_len;
549
550 buf_ptr = enc_rim_cont_common(buf_ptr, len, (struct bssgp_ran_inf_x_cont *)cont);
551 if (!buf_ptr)
552 return -EINVAL;
553
554 remaining_buf_len = len - (int)(buf_ptr - buf);
555 if (remaining_buf_len <= 0)
556 return -EINVAL;
557
558 switch (cont->app_id) {
559 case BSSGP_RAN_INF_APP_ID_NACC:
560 app_cont_len =
561 bssgp_enc_ran_inf_req_app_cont_nacc(buf_ptr + TVLV_HDR_LEN, remaining_buf_len - TVLV_HDR_MAXLEN,
562 &cont->u.app_cont_nacc);
563 break;
564 case BSSGP_RAN_INF_APP_ID_SI3:
565 case BSSGP_RAN_INF_APP_ID_MBMS:
566 case BSSGP_RAN_INF_APP_ID_SON:
567 case BSSGP_RAN_INF_APP_ID_UTRA_SI:
568 /* TODO: add encoders for Si3, MBMS, SON, UTRA-SI app containers */
Philipp Maier836c6da2021-01-19 20:03:50 +0100569 return -EOPNOTSUPP;
Philipp Maier9828d282021-01-06 20:40:23 +0100570 default:
571 return -EINVAL;
572 }
573
574 if (app_cont_len < 0)
575 return -EINVAL;
576 buf_ptr = dub_tlvp_header(buf_ptr, BSSGP_IE_RIM_REQ_APP_CONTAINER, app_cont_len);
577
578 remaining_buf_len = len - (int)(buf_ptr - buf);
579 if (remaining_buf_len < 0)
580 return -EINVAL;
581
582 if (cont->son_trans_app_id && cont->son_trans_app_id_len > 0) {
583 if (remaining_buf_len < cont->son_trans_app_id_len + TVLV_HDR_MAXLEN)
584 return -EINVAL;
585 buf_ptr =
586 tvlv_put(buf_ptr, BSSGP_IE_SON_TRANSFER_APP_ID, cont->son_trans_app_id_len, cont->son_trans_app_id);
587 }
588 return (int)(buf_ptr - buf);
589}
590
591/*! Decode a RAN Information RIM Container (3GPP TS 48.018, table 11.3.62a.2.b).
592 * \param[out] user provided memory for decoded data struct.
593 * \param[in] buf user provided memory with the encoded value data of the IE.
594 * \returns 0 on success, -EINVAL on error. */
595int bssgp_dec_ran_inf_rim_cont(struct bssgp_ran_inf_rim_cont *cont, const uint8_t *buf, size_t len)
596{
597 int rc;
598 struct tlv_parsed tp;
599
600 memset(cont, 0, sizeof(*cont));
601
602 rc = tlv_parse(&tp, &tvlv_att_def, buf, len, 0, 0);
603 if (rc < 0)
604 return -EINVAL;
605
606 rc = dec_rim_cont_common((struct bssgp_ran_inf_x_cont *)cont, &tp);
607 if (rc < 0)
608 return -EINVAL;
609
610 if (TLVP_PRESENT(&tp, BSSGP_IE_RAN_INFO_APP_CONTAINER)) {
611 switch (cont->app_id) {
612 case BSSGP_RAN_INF_APP_ID_NACC:
613 rc = bssgp_dec_ran_inf_app_cont_nacc(&cont->u.app_cont_nacc,
614 TLVP_VAL(&tp, BSSGP_IE_RAN_INFO_APP_CONTAINER),
615 TLVP_LEN(&tp, BSSGP_IE_RAN_INFO_APP_CONTAINER));
616 break;
617 case BSSGP_RAN_INF_APP_ID_SI3:
618 case BSSGP_RAN_INF_APP_ID_MBMS:
619 case BSSGP_RAN_INF_APP_ID_SON:
620 case BSSGP_RAN_INF_APP_ID_UTRA_SI:
621 /* TODO: add parsers for Si3, MBMS, SON, UTRA-SI app containers */
Philipp Maier836c6da2021-01-19 20:03:50 +0100622 return -EOPNOTSUPP;
Philipp Maier9828d282021-01-06 20:40:23 +0100623 default:
624 return -EINVAL;
625 }
626
627 if (rc < 0)
628 return rc;
629 } else if (TLVP_PRESENT(&tp, BSSGP_IE_APP_ERROR_CONTAINER)) {
630 switch (cont->app_id) {
631 case BSSGP_RAN_INF_APP_ID_NACC:
632 rc = bssgp_dec_app_err_cont_nacc(&cont->u.app_err_cont_nacc,
633 TLVP_VAL(&tp, BSSGP_IE_APP_ERROR_CONTAINER), TLVP_LEN(&tp,
634 BSSGP_IE_APP_ERROR_CONTAINER));
635 break;
636 case BSSGP_RAN_INF_APP_ID_SI3:
637 case BSSGP_RAN_INF_APP_ID_MBMS:
638 case BSSGP_RAN_INF_APP_ID_SON:
639 case BSSGP_RAN_INF_APP_ID_UTRA_SI:
640 /* TODO: add parsers for Si3, MBMS, SON, UTRA-SI app containers */
Philipp Maier836c6da2021-01-19 20:03:50 +0100641 return -EOPNOTSUPP;
Philipp Maier9828d282021-01-06 20:40:23 +0100642 default:
643 return -EINVAL;
644 }
645 if (rc < 0)
646 return rc;
647 cont->app_err = true;
648 }
649
650 if (TLVP_PRES_LEN(&tp, BSSGP_IE_SON_TRANSFER_APP_ID, 1)) {
651 cont->son_trans_app_id = TLVP_VAL(&tp, BSSGP_IE_SON_TRANSFER_APP_ID);
652 cont->son_trans_app_id_len = TLVP_LEN(&tp, BSSGP_IE_SON_TRANSFER_APP_ID);
653 }
654
655 return 0;
656}
657
658/*! Encode a RAN Information RIM Container (3GPP TS 48.018, table 11.3.62a.2.b).
659 * \param[out] buf user provided memory for the generated value part of the IE.
660 * \param[in] cont user provided input data struct.
661 * \returns length of encoded octets, -EINVAL on error. */
662int bssgp_enc_ran_inf_rim_cont(uint8_t *buf, size_t len, const struct bssgp_ran_inf_rim_cont *cont)
663{
664 uint8_t *buf_ptr = buf;
665 int app_cont_len = 0;
666 int remaining_buf_len;
667
668 buf_ptr = enc_rim_cont_common(buf_ptr, len, (struct bssgp_ran_inf_x_cont *)cont);
669 if (!buf_ptr)
670 return -EINVAL;
671
672 remaining_buf_len = len - (int)(buf_ptr - buf);
673 if (remaining_buf_len <= 0)
674 return -EINVAL;
675
676 if (cont->app_err) {
677 switch (cont->app_id) {
678 case BSSGP_RAN_INF_APP_ID_NACC:
679 app_cont_len =
680 bssgp_enc_app_err_cont_nacc(buf_ptr + TVLV_HDR_LEN, remaining_buf_len - TVLV_HDR_MAXLEN,
681 &cont->u.app_err_cont_nacc);
682 break;
683 case BSSGP_RAN_INF_APP_ID_SI3:
684 case BSSGP_RAN_INF_APP_ID_MBMS:
685 case BSSGP_RAN_INF_APP_ID_SON:
686 case BSSGP_RAN_INF_APP_ID_UTRA_SI:
687 /* TODO: add encoders for Si3, MBMS, SON, UTRA-SI app containers */
Philipp Maier836c6da2021-01-19 20:03:50 +0100688 return -EOPNOTSUPP;
Philipp Maier9828d282021-01-06 20:40:23 +0100689 default:
690 return -EINVAL;
691 }
692 if (app_cont_len < 0)
693 return -EINVAL;
694 buf_ptr = dub_tlvp_header(buf_ptr, BSSGP_IE_APP_ERROR_CONTAINER, app_cont_len);
695 } else {
696 switch (cont->app_id) {
697 case BSSGP_RAN_INF_APP_ID_NACC:
698 app_cont_len =
699 bssgp_enc_ran_inf_app_cont_nacc(buf_ptr + TVLV_HDR_LEN, remaining_buf_len - TVLV_HDR_MAXLEN,
700 &cont->u.app_cont_nacc);
701 break;
702 case BSSGP_RAN_INF_APP_ID_SI3:
703 case BSSGP_RAN_INF_APP_ID_MBMS:
704 case BSSGP_RAN_INF_APP_ID_SON:
705 case BSSGP_RAN_INF_APP_ID_UTRA_SI:
706 /* TODO: add encoders for Si3, MBMS, SON, UTRA-SI app containers */
Philipp Maier836c6da2021-01-19 20:03:50 +0100707 return -EOPNOTSUPP;
Philipp Maier9828d282021-01-06 20:40:23 +0100708 default:
709 return -EINVAL;
710 }
711 if (app_cont_len < 0)
712 return -EINVAL;
713 buf_ptr = dub_tlvp_header(buf_ptr, BSSGP_IE_RAN_INFO_APP_CONTAINER, app_cont_len);
714 }
715
716 remaining_buf_len = len - (int)(buf_ptr - buf);
717 if (remaining_buf_len < 0)
718 return -EINVAL;
719
720 if (cont->son_trans_app_id && cont->son_trans_app_id_len > 0) {
721 if (remaining_buf_len < cont->son_trans_app_id_len + TVLV_HDR_MAXLEN)
722 return -EINVAL;
723 buf_ptr =
724 tvlv_put(buf_ptr, BSSGP_IE_SON_TRANSFER_APP_ID, cont->son_trans_app_id_len, cont->son_trans_app_id);
725 }
726 return (int)(buf_ptr - buf);
727}
728
729/*! Decode a RAN Information ACK RIM Container (3GPP TS 48.018, table 11.3.62a.3.b).
730 * \param[out] user provided memory for decoded data struct.
731 * \param[in] buf user provided memory with the encoded value data of the IE.
732 * \returns 0 on success, -EINVAL on error. */
733int bssgp_dec_ran_inf_ack_rim_cont(struct bssgp_ran_inf_ack_rim_cont *cont, const uint8_t *buf, size_t len)
734{
735 int rc;
736 struct tlv_parsed tp;
737
738 memset(cont, 0, sizeof(*cont));
739
740 rc = tlv_parse(&tp, &tvlv_att_def, buf, len, 0, 0);
741 if (rc < 0)
742 return -EINVAL;
743
744 if (TLVP_PRES_LEN(&tp, BSSGP_IE_RIM_APP_IDENTITY, sizeof(uint8_t)))
745 cont->app_id = TLVP_VAL(&tp, BSSGP_IE_RIM_APP_IDENTITY)[0];
746 else
747 return -EINVAL;
748
749 if (TLVP_PRES_LEN(&tp, BSSGP_IE_RIM_SEQ_NR, sizeof(cont->seq_num)))
750 cont->seq_num = tlvp_val32be(&tp, BSSGP_IE_RIM_SEQ_NR);
751 else
752 return -EINVAL;
753
754 if (TLVP_PRES_LEN(&tp, BSSGP_IE_RIM_PROTOCOL_VERSION, sizeof(cont->prot_ver)))
755 cont->prot_ver = TLVP_VAL(&tp, BSSGP_IE_RIM_PROTOCOL_VERSION)[0];
756 else
757 cont->prot_ver = 1;
758
759 if (TLVP_PRES_LEN(&tp, BSSGP_IE_SON_TRANSFER_APP_ID, 1)) {
760 cont->son_trans_app_id = TLVP_VAL(&tp, BSSGP_IE_SON_TRANSFER_APP_ID);
761 cont->son_trans_app_id_len = TLVP_LEN(&tp, BSSGP_IE_SON_TRANSFER_APP_ID);
762 }
763
764 return 0;
765}
766
767/*! Encode a RAN Information ACK RIM Container (3GPP TS 48.018, table 11.3.62a.3.b).
768 * \param[out] buf user provided memory for the generated value part of the IE.
769 * \param[in] cont user provided input data struct.
770 * \returns length of encoded octets, -EINVAL on error. */
771int bssgp_enc_ran_inf_ack_rim_cont(uint8_t *buf, size_t len, const struct bssgp_ran_inf_ack_rim_cont *cont)
772{
773 uint8_t *buf_ptr = buf;
774 uint32_t seq_num = osmo_htonl(cont->seq_num);
775 uint8_t app_id_temp;
776
777 if (len <
778 4 * TVLV_HDR_MAXLEN + sizeof(app_id_temp) + sizeof(seq_num) + sizeof(cont->prot_ver) +
779 cont->son_trans_app_id_len)
780 return -EINVAL;
781
782 app_id_temp = cont->app_id;
783 buf_ptr = tvlv_put(buf_ptr, BSSGP_IE_RIM_APP_IDENTITY, sizeof(app_id_temp), &app_id_temp);
784 buf_ptr = tvlv_put(buf_ptr, BSSGP_IE_RIM_SEQ_NR, sizeof(seq_num), (uint8_t *) & seq_num);
785
786 if (cont->prot_ver > 0)
787 buf_ptr = tvlv_put(buf_ptr, BSSGP_IE_RIM_PROTOCOL_VERSION, sizeof(cont->prot_ver), &cont->prot_ver);
788
789 if (cont->son_trans_app_id && cont->son_trans_app_id_len > 0)
790 buf_ptr =
791 tvlv_put(buf_ptr, BSSGP_IE_SON_TRANSFER_APP_ID, cont->son_trans_app_id_len, cont->son_trans_app_id);
792
793 return (int)(buf_ptr - buf);
794}
795
796/*! Decode a RAN Information Error RIM Container (3GPP TS 48.018, table 11.3.62a.4.b).
797 * \param[out] user provided memory for decoded data struct.
798 * \param[in] buf user provided memory with the encoded value data of the IE.
799 * \returns 0 on success, -EINVAL on error. */
800int bssgp_dec_ran_inf_err_rim_cont(struct bssgp_ran_inf_err_rim_cont *cont, const uint8_t *buf, size_t len)
801{
802 int rc;
803 struct tlv_parsed tp;
804
805 memset(cont, 0, sizeof(*cont));
806
807 rc = tlv_parse(&tp, &tvlv_att_def, buf, len, 0, 0);
808 if (rc < 0)
809 return -EINVAL;
810
811 if (TLVP_PRES_LEN(&tp, BSSGP_IE_RIM_APP_IDENTITY, sizeof(uint8_t)))
812 cont->app_id = TLVP_VAL(&tp, BSSGP_IE_RIM_APP_IDENTITY)[0];
813 else
814 return -EINVAL;
815
816 if (TLVP_PRES_LEN(&tp, BSSGP_IE_CAUSE, sizeof(cont->cause)))
817 cont->cause = TLVP_VAL(&tp, BSSGP_IE_CAUSE)[0];
818 else
819 return -EINVAL;
820
821 if (TLVP_PRES_LEN(&tp, BSSGP_IE_RIM_PROTOCOL_VERSION, sizeof(cont->prot_ver)))
822 cont->prot_ver = TLVP_VAL(&tp, BSSGP_IE_RIM_PROTOCOL_VERSION)[0];
823 else
824 cont->prot_ver = 1;
825
826 if (TLVP_PRESENT(&tp, BSSGP_IE_PDU_IN_ERROR)) {
827 cont->err_pdu = TLVP_VAL(&tp, BSSGP_IE_PDU_IN_ERROR);
828 cont->err_pdu_len = TLVP_LEN(&tp, BSSGP_IE_PDU_IN_ERROR);
829 } else {
830 return -EINVAL;
831 }
832
833 if (TLVP_PRES_LEN(&tp, BSSGP_IE_SON_TRANSFER_APP_ID, 1)) {
834 cont->son_trans_app_id = TLVP_VAL(&tp, BSSGP_IE_SON_TRANSFER_APP_ID);
835 cont->son_trans_app_id_len = TLVP_LEN(&tp, BSSGP_IE_SON_TRANSFER_APP_ID);
836 }
837
838 return 0;
839}
840
841/*! Encode a RAN Information Error RIM Container (3GPP TS 48.018, table 11.3.62a.4.b).
842 * \param[out] buf user provided memory for the generated value part of the IE.
843 * \param[in] cont user provided input data struct.
844 * \returns length of encoded octets, -EINVAL on error. */
845int bssgp_enc_ran_inf_err_rim_cont(uint8_t *buf, size_t len, const struct bssgp_ran_inf_err_rim_cont *cont)
846{
847 uint8_t *buf_ptr = buf;
848 uint8_t app_id_temp;
849
850 if (len <
851 TVLV_HDR_MAXLEN * 5 + sizeof(app_id_temp) + sizeof(cont->cause) + sizeof(cont->prot_ver) +
852 cont->err_pdu_len + cont->son_trans_app_id_len)
853 return -EINVAL;
854
855 app_id_temp = cont->app_id;
856 buf_ptr = tvlv_put(buf_ptr, BSSGP_IE_RIM_APP_IDENTITY, sizeof(app_id_temp), &app_id_temp);
857 buf_ptr = tvlv_put(buf_ptr, BSSGP_IE_CAUSE, sizeof(cont->cause), &cont->cause);
858
859 if (cont->prot_ver > 0)
860 buf_ptr = tvlv_put(buf_ptr, BSSGP_IE_RIM_PROTOCOL_VERSION, sizeof(cont->prot_ver), &cont->prot_ver);
861
862 if (cont->err_pdu && cont->err_pdu_len > 0)
863 buf_ptr = tvlv_put(buf_ptr, BSSGP_IE_PDU_IN_ERROR, cont->err_pdu_len, cont->err_pdu);
864 else
865 return -EINVAL;
866
867 if (cont->son_trans_app_id && cont->son_trans_app_id_len > 0)
868 buf_ptr =
869 tvlv_put(buf_ptr, BSSGP_IE_SON_TRANSFER_APP_ID, cont->son_trans_app_id_len, cont->son_trans_app_id);
870
871 return (int)(buf_ptr - buf);
872}
873
874/*! Decode a RAN Information Application Error RIM Container (3GPP TS 48.018, table 11.3.62a.5.b).
875 * \param[out] user provided memory for decoded data struct.
876 * \param[in] buf user provided memory with the encoded value data of the IE.
877 * \returns 0 on success, -EINVAL on error. */
878int bssgp_dec_ran_inf_app_err_rim_cont(struct bssgp_ran_inf_app_err_rim_cont *cont, const uint8_t *buf, size_t len)
879{
880 int rc;
881 struct tlv_parsed tp;
882
883 memset(cont, 0, sizeof(*cont));
884
885 rc = tlv_parse(&tp, &tvlv_att_def, buf, len, 0, 0);
886 if (rc < 0)
887 return -EINVAL;
888
889 rc = dec_rim_cont_common((struct bssgp_ran_inf_x_cont *)cont, &tp);
890 if (rc < 0)
891 return -EINVAL;
892
893 switch (cont->app_id) {
894 case BSSGP_RAN_INF_APP_ID_NACC:
895 rc = bssgp_dec_app_err_cont_nacc(&cont->u.app_err_cont_nacc,
896 TLVP_VAL(&tp, BSSGP_IE_APP_ERROR_CONTAINER), TLVP_LEN(&tp,
897 BSSGP_IE_APP_ERROR_CONTAINER));
898 break;
899 case BSSGP_RAN_INF_APP_ID_SI3:
900 case BSSGP_RAN_INF_APP_ID_MBMS:
901 case BSSGP_RAN_INF_APP_ID_SON:
902 case BSSGP_RAN_INF_APP_ID_UTRA_SI:
903 /* TODO: add parsers for Si3, MBMS, SON, UTRA-SI app containers */
Philipp Maier836c6da2021-01-19 20:03:50 +0100904 return -EOPNOTSUPP;
Philipp Maier9828d282021-01-06 20:40:23 +0100905 default:
906 return -EINVAL;
907 }
908 if (rc < 0)
909 return rc;
910
911 return 0;
912}
913
914/*! Encode a RAN Information Application Error RIM Container (3GPP TS 48.018, table 11.3.62a.5.b).
915 * \param[out] buf user provided memory for the generated value part of the IE.
916 * \param[in] cont user provided input data struct.
917 * \returns length of encoded octets, -EINVAL on error. */
918int bssgp_enc_ran_inf_app_err_rim_cont(uint8_t *buf, size_t len, const struct bssgp_ran_inf_app_err_rim_cont *cont)
919{
920 uint8_t *buf_ptr = buf;
921 int app_cont_len = 0;
922 int remaining_buf_len;
923
924 buf_ptr = enc_rim_cont_common(buf_ptr, len, (struct bssgp_ran_inf_x_cont *)cont);
925 if (!buf_ptr)
926 return -EINVAL;
927
928 remaining_buf_len = len - (int)(buf_ptr - buf);
929 if (remaining_buf_len <= 0)
930 return -EINVAL;
931
932 switch (cont->app_id) {
933 case BSSGP_RAN_INF_APP_ID_NACC:
934 app_cont_len =
935 bssgp_enc_app_err_cont_nacc(buf_ptr + TVLV_HDR_LEN, remaining_buf_len - TVLV_HDR_MAXLEN,
936 &cont->u.app_err_cont_nacc);
937 break;
938 case BSSGP_RAN_INF_APP_ID_SI3:
939 case BSSGP_RAN_INF_APP_ID_MBMS:
940 case BSSGP_RAN_INF_APP_ID_SON:
941 case BSSGP_RAN_INF_APP_ID_UTRA_SI:
942 /* TODO: add encoders for Si3, MBMS, SON, UTRA-SI app containers */
Philipp Maier836c6da2021-01-19 20:03:50 +0100943 return -EOPNOTSUPP;
Philipp Maier9828d282021-01-06 20:40:23 +0100944 default:
945 return -EINVAL;
946 }
947 if (app_cont_len < 0)
948 return -EINVAL;
949 buf_ptr = dub_tlvp_header(buf_ptr, BSSGP_IE_APP_ERROR_CONTAINER, app_cont_len);
950
951 return (int)(buf_ptr - buf);
952}
Philipp Maier4d400472021-01-26 12:57:13 +0100953
954/*! Parse a given message buffer into a rim-pdu struct.
955 * \param[out] pdu user provided memory for the resulting RAN INFORMATION PDU.
956 * \param[in] msg BSSGP message buffer that contains the encoded RAN INFORMATION PDU.
957 * \returns 0 on sccess, -EINVAL on error. */
958int bssgp_parse_rim_pdu(struct bssgp_ran_information_pdu *pdu, const struct msgb *msg)
959{
960 struct tlv_parsed tp[2];
961 struct bssgp_normal_hdr *bgph = (struct bssgp_normal_hdr *)msgb_bssgph(msg);
962 int data_len;
963 int rc;
964 uint16_t nsei = msgb_nsei(msg);
965
966 memset(pdu, 0, sizeof(*pdu));
967
968 data_len = msgb_bssgp_len(msg) - sizeof(*bgph);
969 if (data_len < 0)
970 return -EINVAL;
971
972 rc = osmo_tlv_prot_parse(&osmo_pdef_bssgp, tp, ARRAY_SIZE(tp), bgph->pdu_type, bgph->data, data_len, 0, 0,
973 DLBSSGP, __func__);
974 if (rc < 0)
975 return -EINVAL;
976
977 if (TLVP_PRESENT(&tp[0], BSSGP_IE_RIM_ROUTING_INFO)) {
978 rc = bssgp_parse_rim_ri(&pdu->routing_info_dest, TLVP_VAL(&tp[0], BSSGP_IE_RIM_ROUTING_INFO),
979 TLVP_LEN(&tp[0], BSSGP_IE_RIM_ROUTING_INFO));
980 if (rc < 0) {
981 LOGP(DLBSSGP, LOGL_ERROR, "BSSGP RIM (NSEI=%u) invalid Destination Cell Identifier IE\n", nsei);
982 return -EINVAL;
983 }
984 } else {
985 LOGP(DLBSSGP, LOGL_ERROR, "BSSGP RIM (NSEI=%u) missing Destination Cell Identifier IE\n", nsei);
986 return -EINVAL;
987 }
988
989 if (TLVP_PRESENT(&tp[1], BSSGP_IE_RIM_ROUTING_INFO)) {
990 rc = bssgp_parse_rim_ri(&pdu->routing_info_src, TLVP_VAL(&tp[1], BSSGP_IE_RIM_ROUTING_INFO),
991 TLVP_LEN(&tp[1], BSSGP_IE_RIM_ROUTING_INFO));
992 if (rc < 0) {
993 LOGP(DLBSSGP, LOGL_ERROR, "BSSGP RIM (NSEI=%u) invalid Destination Cell Identifier IE\n", nsei);
994 return -EINVAL;
995 }
996 } else {
997 LOGP(DLBSSGP, LOGL_ERROR, "BSSGP RIM (NSEI=%u) missing Source Cell Identifier IE\n", nsei);
998 return -EINVAL;
999 }
1000
1001 if (TLVP_PRESENT(&tp[0], BSSGP_IE_RI_REQ_RIM_CONTAINER))
1002 pdu->rim_cont_iei = BSSGP_IE_RI_REQ_RIM_CONTAINER;
1003 else if (TLVP_PRESENT(&tp[0], BSSGP_IE_RI_RIM_CONTAINER))
1004 pdu->rim_cont_iei = BSSGP_IE_RI_RIM_CONTAINER;
1005 else if (TLVP_PRESENT(&tp[0], BSSGP_IE_RI_APP_ERROR_RIM_CONT))
1006 pdu->rim_cont_iei = BSSGP_IE_RI_APP_ERROR_RIM_CONT;
1007 else if (TLVP_PRESENT(&tp[0], BSSGP_IE_RI_ACK_RIM_CONTAINER))
1008 pdu->rim_cont_iei = BSSGP_IE_RI_ACK_RIM_CONTAINER;
1009 else if (TLVP_PRESENT(&tp[0], BSSGP_IE_RI_ERROR_RIM_COINTAINER))
1010 pdu->rim_cont_iei = BSSGP_IE_RI_ERROR_RIM_COINTAINER;
1011 else {
1012 LOGP(DLBSSGP, LOGL_ERROR, "BSSGP RIM (NSEI=%u) missing or wrong RIM Container IE\n", nsei);
1013 return -EINVAL;
1014 }
1015
1016 pdu->rim_cont = TLVP_VAL(&tp[0], pdu->rim_cont_iei);
1017 pdu->rim_cont_len = TLVP_LEN(&tp[0], pdu->rim_cont_iei);
1018
1019 /* Make sure the rim container field is not empty */
1020 if (pdu->rim_cont_len < 1)
1021 return -EINVAL;
1022 if (!pdu->rim_cont)
1023 return -EINVAL;
1024
1025 /* Note: It is not an error if we fail to parse the RIM container,
1026 * since there are applications where parsing the RIM container
1027 * is not necessary (routing). It is up to the API user to check
1028 * the results. */
1029 switch (pdu->rim_cont_iei) {
1030 case BSSGP_IE_RI_REQ_RIM_CONTAINER:
1031 rc = bssgp_dec_ran_inf_req_rim_cont(&pdu->decoded.req_rim_cont, pdu->rim_cont, pdu->rim_cont_len);
1032 break;
1033 case BSSGP_IE_RI_RIM_CONTAINER:
1034 rc = bssgp_dec_ran_inf_rim_cont(&pdu->decoded.rim_cont, pdu->rim_cont, pdu->rim_cont_len);
1035 break;
1036 case BSSGP_IE_RI_APP_ERROR_RIM_CONT:
1037 rc = bssgp_dec_ran_inf_app_err_rim_cont(&pdu->decoded.app_err_rim_cont, pdu->rim_cont,
1038 pdu->rim_cont_len);
1039 break;
1040 case BSSGP_IE_RI_ACK_RIM_CONTAINER:
1041 rc = bssgp_dec_ran_inf_ack_rim_cont(&pdu->decoded.ack_rim_cont, pdu->rim_cont, pdu->rim_cont_len);
1042 break;
1043 case BSSGP_IE_RI_ERROR_RIM_COINTAINER:
1044 rc = bssgp_dec_ran_inf_err_rim_cont(&pdu->decoded.err_rim_cont, pdu->rim_cont, pdu->rim_cont_len);
1045 break;
1046 default:
1047 LOGP(DLBSSGP, LOGL_DEBUG, "BSSGP RIM (NSEI=%u) cannot parse unknown RIM container.\n", nsei);
1048 return 0;
1049 }
1050 if (rc < 0) {
1051 LOGP(DLBSSGP, LOGL_DEBUG, "BSSGP RIM (NSEI=%u) unable to parse RIM container.\n", nsei);
1052 return 0;
1053 }
1054 pdu->decoded_present = true;
1055
1056 return 0;
1057}
1058
1059/*! Encode a given rim-pdu struct into a message buffer.
1060 * \param[out] pdu user provided memory that contains the RAN INFORMATION PDU to encode.
1061 * \returns BSSGP message buffer on sccess, NULL on error. */
Pau Espin Pedroladef5462021-05-06 18:17:18 +02001062struct msgb *bssgp_encode_rim_pdu(const struct bssgp_ran_information_pdu *pdu)
Philipp Maier4d400472021-01-26 12:57:13 +01001063{
1064 struct msgb *msg = bssgp_msgb_alloc();
1065 struct bssgp_normal_hdr *bgph;
1066 uint8_t rim_ri_buf[BSSGP_RIM_ROUTING_INFO_MAXLEN];
Philipp Maier4d400472021-01-26 12:57:13 +01001067 int rc;
1068
1069 if (!msg)
1070 return NULL;
1071 bgph = (struct bssgp_normal_hdr *)msgb_put(msg, sizeof(*bgph));
1072
1073 /* Set PDU type based on RIM container type */
1074 switch (pdu->rim_cont_iei) {
1075 case BSSGP_IE_RI_REQ_RIM_CONTAINER:
1076 bgph->pdu_type = BSSGP_PDUT_RAN_INFO_REQ;
1077 break;
1078 case BSSGP_IE_RI_RIM_CONTAINER:
1079 bgph->pdu_type = BSSGP_PDUT_RAN_INFO;
1080 break;
1081 case BSSGP_IE_RI_APP_ERROR_RIM_CONT:
1082 bgph->pdu_type = BSSGP_PDUT_RAN_INFO_APP_ERROR;
1083 break;
1084 case BSSGP_IE_RI_ACK_RIM_CONTAINER:
1085 bgph->pdu_type = BSSGP_PDUT_RAN_INFO_ACK;
1086 break;
1087 case BSSGP_IE_RI_ERROR_RIM_COINTAINER:
1088 bgph->pdu_type = BSSGP_PDUT_RAN_INFO_ERROR;
1089 break;
1090 default:
1091 /* The caller must correctly specify the container type! */
1092 OSMO_ASSERT(false);
1093 }
1094
1095 /* Put RIM routing information */
1096 rc = bssgp_create_rim_ri(rim_ri_buf, &pdu->routing_info_dest);
1097 if (rc < 0 || rc > BSSGP_RIM_ROUTING_INFO_MAXLEN)
1098 goto error;
1099 msgb_tvlv_put(msg, BSSGP_IE_RIM_ROUTING_INFO, rc, rim_ri_buf);
1100 rc = bssgp_create_rim_ri(rim_ri_buf, &pdu->routing_info_src);
1101 if (rc < 0 || rc > BSSGP_RIM_ROUTING_INFO_MAXLEN)
1102 goto error;
1103 msgb_tvlv_put(msg, BSSGP_IE_RIM_ROUTING_INFO, rc, rim_ri_buf);
1104
1105 /* Put RIM container */
1106 if (pdu->decoded_present) {
Vadim Yanitskiy0578c282022-07-04 20:47:16 +07001107 uint8_t *rim_cont_buf = talloc_zero_size(msg, msg->data_len);
Philipp Maier4d400472021-01-26 12:57:13 +01001108 if (!rim_cont_buf)
1109 goto error;
1110
1111 switch (pdu->rim_cont_iei) {
1112 case BSSGP_IE_RI_REQ_RIM_CONTAINER:
1113 rc = bssgp_enc_ran_inf_req_rim_cont(rim_cont_buf, msg->data_len, &pdu->decoded.req_rim_cont);
1114 break;
1115 case BSSGP_IE_RI_RIM_CONTAINER:
1116 rc = bssgp_enc_ran_inf_rim_cont(rim_cont_buf, msg->data_len, &pdu->decoded.rim_cont);
1117 break;
1118 case BSSGP_IE_RI_APP_ERROR_RIM_CONT:
1119 rc = bssgp_enc_ran_inf_app_err_rim_cont(rim_cont_buf, msg->data_len,
1120 &pdu->decoded.app_err_rim_cont);
1121 break;
1122 case BSSGP_IE_RI_ACK_RIM_CONTAINER:
1123 rc = bssgp_enc_ran_inf_ack_rim_cont(rim_cont_buf, msg->data_len, &pdu->decoded.ack_rim_cont);
1124 break;
1125 case BSSGP_IE_RI_ERROR_RIM_COINTAINER:
1126 rc = bssgp_enc_ran_inf_err_rim_cont(rim_cont_buf, msg->data_len, &pdu->decoded.err_rim_cont);
1127 break;
1128 default:
1129 /* The API user must set the iei properly! */
1130 OSMO_ASSERT(false);
1131 }
Vadim Yanitskiy0578c282022-07-04 20:47:16 +07001132 if (rc < 0) {
1133 talloc_free(rim_cont_buf);
Philipp Maier4d400472021-01-26 12:57:13 +01001134 goto error;
Vadim Yanitskiy0578c282022-07-04 20:47:16 +07001135 }
Philipp Maier4d400472021-01-26 12:57:13 +01001136
1137 msgb_tvlv_put(msg, pdu->rim_cont_iei, rc, rim_cont_buf);
1138 talloc_free(rim_cont_buf);
1139 } else {
1140 /* Make sure the RIM container is actually present. */
1141 OSMO_ASSERT(pdu->rim_cont_iei != 0 && pdu->rim_cont_len > 0 && pdu->rim_cont);
1142 msgb_tvlv_put(msg, pdu->rim_cont_iei, pdu->rim_cont_len, pdu->rim_cont);
1143 }
1144
1145 return msg;
1146error:
Philipp Maier4d400472021-01-26 12:57:13 +01001147 msgb_free(msg);
1148 return 0;
1149}
1150
1151/*! Send RIM RAN INFORMATION REQUEST via BSSGP (3GPP TS 48.018, section 10.6.1).
1152 * \param[in] pdu user provided memory for the RAN INFORMATION PDU to be sent.
1153 * \param[in] nsei BSSGP network service entity identifier (NSEI).
1154 * \returns 0 on sccess, -EINVAL on error. */
1155int bssgp_tx_rim(const struct bssgp_ran_information_pdu *pdu, uint16_t nsei)
1156{
1157 struct msgb *msg;
1158 struct bssgp_normal_hdr *bgph;
1159 char ri_src_str[64];
1160 char ri_dest_str[64];
1161
1162 /* Encode RIM PDU into mesage buffer */
Pau Espin Pedroladef5462021-05-06 18:17:18 +02001163 msg = bssgp_encode_rim_pdu(pdu);
Philipp Maier4d400472021-01-26 12:57:13 +01001164 if (!msg) {
1165 LOGP(DLBSSGP, LOGL_ERROR,
1166 "BSSGP RIM (NSEI=%u) unable to encode BSSGP RIM PDU\n", nsei);
1167 return -EINVAL;
1168 }
1169
1170 msgb_nsei(msg) = nsei;
1171 msgb_bvci(msg) = 0; /* Signalling */
1172
1173 bgph = (struct bssgp_normal_hdr *)msgb_bssgph(msg);
Philipp Maiera0d84832023-08-09 16:35:44 +02001174 DEBUGP(DLBSSGP, "BSSGP BVCI=0 NSEI=%u Tx RIM-PDU:%s, src=%s, dest=%s\n",
1175 nsei, bssgp_pdu_str(bgph->pdu_type),
Philipp Maier4d400472021-01-26 12:57:13 +01001176 bssgp_rim_ri_name_buf(ri_src_str, sizeof(ri_src_str), &pdu->routing_info_src),
1177 bssgp_rim_ri_name_buf(ri_dest_str, sizeof(ri_dest_str), &pdu->routing_info_dest));
1178
1179 return bssgp_ns_send(bssgp_ns_send_data, msg);
1180}
1181
1182/* For internal use only (called from gprs_bssgp.c) */
1183int bssgp_rx_rim(struct msgb *msg, struct tlv_parsed *tp, uint16_t bvci)
1184{
1185 struct osmo_bssgp_prim nmp;
1186 uint16_t nsei = msgb_nsei(msg);
1187 struct bssgp_normal_hdr *bgph = (struct bssgp_normal_hdr *)msgb_bssgph(msg);
1188 enum bssgp_prim prim;
1189 char ri_src_str[64];
1190 char ri_dest_str[64];
1191
1192 /* Specify PRIM type based on the RIM PDU */
1193 switch (bgph->pdu_type) {
1194 case BSSGP_PDUT_RAN_INFO:
1195 case BSSGP_PDUT_RAN_INFO_REQ:
1196 case BSSGP_PDUT_RAN_INFO_ACK:
1197 case BSSGP_PDUT_RAN_INFO_ERROR:
1198 case BSSGP_PDUT_RAN_INFO_APP_ERROR:
1199 prim = PRIM_BSSGP_RIM_PDU_TRANSFER;
1200 break;
1201 default:
1202 /* Caller already makes sure that this can't happen. */
1203 OSMO_ASSERT(false);
1204 }
1205
1206 /* Send BSSGP RIM indication to NM */
1207 memset(&nmp, 0, sizeof(nmp));
1208 nmp.nsei = nsei;
1209 nmp.bvci = bvci;
1210 nmp.tp = tp;
1211 if (bssgp_parse_rim_pdu(&nmp.u.rim_pdu, msg) < 0)
1212 return bssgp_tx_status(BSSGP_CAUSE_MISSING_MAND_IE, NULL, msg);
1213 DEBUGP(DLBSSGP, "BSSGP BVCI=%u Rx RIM-PDU:%s, src=%s, dest=%s\n",
1214 bvci, bssgp_pdu_str(bgph->pdu_type),
1215 bssgp_rim_ri_name_buf(ri_src_str, sizeof(ri_src_str), &nmp.u.rim_pdu.routing_info_src),
1216 bssgp_rim_ri_name_buf(ri_dest_str, sizeof(ri_dest_str), &nmp.u.rim_pdu.routing_info_dest));
1217 osmo_prim_init(&nmp.oph, SAP_BSSGP_RIM, prim, PRIM_OP_INDICATION, msg);
1218 bssgp_prim_cb(&nmp.oph, NULL);
1219
1220 return 0;
1221}