blob: 0dc6d21568c484ab89b0ad74ba3cb5aea97398a1 [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>
30
31/* TVLV IEs use a variable length field. To be sure we will do all buffer
32 * length checks with the maximum possible header length, which is
33 * 1 octet tag + 2 octets length = 3 */
34#define TVLV_HDR_MAXLEN 3
35
36/* Usually RIM application containers and their surrounding RIM containers
37 * are not likely to exceed 128 octets, so the usual header length will be 2 */
38#define TVLV_HDR_LEN 2
39
40/* The reporting cell identifier is encoded as a cell identifier IE
41 * (3GPP TS 48.018, sub-clause 11.3.9) but without IE and length octets. */
42#define REP_CELL_ID_LEN 8
43
Philipp Maier7450f772021-01-06 20:56:43 +010044/*! Parse a RIM Routing information IE (3GPP TS 48.018, chapter 11.3.70).
45 * \param[out] ri user provided memory to store the parsed results.
46 * \param[in] buf input buffer of the value part of the IE.
47 * \returns length of parsed octets, -EINVAL on error. */
48int bssgp_parse_rim_ri(struct bssgp_rim_routing_info *ri, const uint8_t *buf,
49 unsigned int len)
50{
51 struct gprs_ra_id raid_temp;
52
53 memset(ri, 0, sizeof(*ri));
54 if (len < 2)
55 return -EINVAL;
56
57 ri->discr = buf[0] & 0x0f;
58 buf++;
59
60 switch (ri->discr) {
61 case BSSGP_RIM_ROUTING_INFO_GERAN:
62 if (len < 9)
63 return -EINVAL;
64 ri->geran.cid = bssgp_parse_cell_id(&ri->geran.raid, buf);
65 return 9;
66 case BSSGP_RIM_ROUTING_INFO_UTRAN:
67 if (len < 9)
68 return -EINVAL;
69 gsm48_parse_ra(&ri->utran.raid, buf);
70 ri->utran.rncid = osmo_load16be(buf + 6);
71 return 9;
72 case BSSGP_RIM_ROUTING_INFO_EUTRAN:
73 if (len < 7 || len > 14)
74 return -EINVAL;
75 /* Note: 3GPP TS 24.301 Figure 9.9.3.32.1 and 3GPP TS 24.008
76 * Figure 10.5.130 specify MCC/MNC encoding in the same way,
77 * so we can re-use gsm48_parse_ra() for that. */
78 gsm48_parse_ra(&raid_temp, buf);
79 ri->eutran.tai.mcc = raid_temp.mcc;
80 ri->eutran.tai.mnc = raid_temp.mnc;
81 ri->eutran.tai.mnc_3_digits = raid_temp.mnc_3_digits;
82 ri->eutran.tai.tac = osmo_load16be(buf + 3);
83 memcpy(ri->eutran.global_enb_id, buf + 5, len - 6);
84 ri->eutran.global_enb_id_len = len - 6;
85 return len;
86 default:
87 return -EINVAL;
88 }
89}
90
91/*! Encode a RIM Routing information IE (3GPP TS 48.018, chapter 11.3.70).
92 * \param[out] buf user provided memory (at least 14 byte) for the generated value part of the IE.
93 * \param[in] ri user provided input data struct.
94 * \returns length of encoded octets, -EINVAL on error. */
95int bssgp_create_rim_ri(uint8_t *buf, const struct bssgp_rim_routing_info *ri)
96{
97 int rc;
98 struct gprs_ra_id raid_temp;
99
100 buf[0] = ri->discr & 0x0f;
101 buf++;
102
103 switch (ri->discr) {
104 case BSSGP_RIM_ROUTING_INFO_GERAN:
105 rc = bssgp_create_cell_id(buf, &ri->geran.raid, ri->geran.cid);
106 if (rc < 0)
107 return -EINVAL;
108 return rc + 1;
109 case BSSGP_RIM_ROUTING_INFO_UTRAN:
110 gsm48_encode_ra((struct gsm48_ra_id *)buf, &ri->utran.raid);
111 osmo_store16be(ri->utran.rncid, buf + 6);
112 return 9;
113 case BSSGP_RIM_ROUTING_INFO_EUTRAN:
114 /* Note: 3GPP TS 24.301 Figure 9.9.3.32.1 and 3GPP TS 24.008
115 * Figure 10.5.130 specify MCC/MNC encoding in the same way,
116 * so we can re-use gsm48_encode_ra() for that. */
117 raid_temp = (struct gprs_ra_id) {
118 .mcc = ri->eutran.tai.mcc,
119 .mnc = ri->eutran.tai.mnc,
120 .mnc_3_digits = ri->eutran.tai.mnc_3_digits,
121 };
122
123 gsm48_encode_ra((struct gsm48_ra_id *)buf, &raid_temp);
124 osmo_store16be(ri->eutran.tai.tac, buf + 3);
125 OSMO_ASSERT(ri->eutran.global_enb_id_len <=
126 sizeof(ri->eutran.global_enb_id));
127 memcpy(buf + 5, ri->eutran.global_enb_id,
128 ri->eutran.global_enb_id_len);
129 return ri->eutran.global_enb_id_len + 6;
130 default:
131 return -EINVAL;
132 }
133}
134
Philipp Maier9828d282021-01-06 20:40:23 +0100135/*! Decode a RAN Information Request Application Container for NACC (3GPP TS 48.018, section 11.3.63.1.1).
136 * \param[out] user provided memory for decoded data struct.
137 * \param[in] buf user provided memory with the encoded value data of the IE.
138 * \returns 0 on success, -EINVAL on error. */
139int bssgp_dec_ran_inf_req_app_cont_nacc(struct bssgp_ran_inf_req_app_cont_nacc *cont, const uint8_t *buf, size_t len)
140{
141 int rc;
142
143 if (len < REP_CELL_ID_LEN)
144 return -EINVAL;
145
146 rc = gsm0808_decode_cell_id_u((union gsm0808_cell_id_u*)&cont->reprt_cell,
147 CELL_IDENT_WHOLE_GLOBAL_PS, buf, len);
148 if (rc < 0)
149 return -EINVAL;
150
151 return 0;
152}
153
154/*! Encode a RAN Information Request Application Container for NACC (3GPP TS 48.018, section 11.3.63.1.1).
155 * \param[out] buf user provided memory for the generated value part of the IE.
156 * \param[in] cont user provided input data struct.
157 * \returns length of encoded octets, -EINVAL on error. */
158int bssgp_enc_ran_inf_req_app_cont_nacc(uint8_t *buf, size_t len, const struct bssgp_ran_inf_req_app_cont_nacc *cont)
159{
160 int rc;
161 struct gprs_ra_id *raid;
162
163 if (len < REP_CELL_ID_LEN)
164 return -EINVAL;
165
166 raid = (struct gprs_ra_id *)&cont->reprt_cell.rai;
167 rc = bssgp_create_cell_id(buf, raid, cont->reprt_cell.cell_identity);
168 if (rc < 0)
169 return -EINVAL;
170 return rc;
171}
172
173/*! Decode a RAN Information Application Container (3GPP TS 48.018, section 11.3.63.2.1).
174 * \param[out] user provided memory for decoded data struct.
175 * \param[in] buf user provided memory with the encoded value data of the IE.
176 * \returns 0 on success, -EINVAL on error. */
177int bssgp_dec_ran_inf_app_cont_nacc(struct bssgp_ran_inf_app_cont_nacc *cont, const uint8_t *buf, size_t len)
178{
179 unsigned int i;
180 int remaining_buf_len;
181 int rc;
182
183 /* The given buffer must at least contain a reporting cell identifer
184 * plus one octet that defines number/type of attached sysinfo messages. */
185 if (len < REP_CELL_ID_LEN + 1)
186 return -EINVAL;
187
188 rc = gsm0808_decode_cell_id_u((union gsm0808_cell_id_u*)&cont->reprt_cell,
189 CELL_IDENT_WHOLE_GLOBAL_PS, buf, len);
190 if (rc < 0)
191 return -EINVAL;
192
193 buf += REP_CELL_ID_LEN;
194
195 cont->type_psi = buf[0] & 1;
196 cont->num_si = buf[0] >> 1;
197 buf++;
198
199 /* The number of sysinfo messages may be zero */
200 if (cont->num_si == 0)
201 return 0;
202
203 /* Check if the prospected system information messages fit in the
204 * remaining buffer space */
205 remaining_buf_len = len - REP_CELL_ID_LEN - 1;
206 if (remaining_buf_len <= 0)
207 return -EINVAL;
208 if (cont->type_psi && remaining_buf_len / BSSGP_RIM_PSI_LEN < cont->num_si)
209 return -EINVAL;
210 else if (remaining_buf_len / BSSGP_RIM_SI_LEN < cont->num_si)
211 return -EINVAL;
212
213 for (i = 0; i < cont->num_si; i++) {
214 cont->si[i] = buf;
215 if (cont->type_psi)
216 buf += BSSGP_RIM_PSI_LEN;
217 else
218 buf += BSSGP_RIM_SI_LEN;
219 }
220
221 return 0;
222}
223
224/*! Encode a RAN Information Application Container (3GPP TS 48.018, section 11.3.63.2.1).
225 * \param[out] buf user provided memory for the generated value part of the IE.
226 * \param[in] cont user provided input data struct.
227 * \returns length of encoded octets, -EINVAL on error. */
228int bssgp_enc_ran_inf_app_cont_nacc(uint8_t *buf, size_t len, const struct bssgp_ran_inf_app_cont_nacc *cont)
229{
230 uint8_t *buf_ptr = buf;
231 int rc;
232 unsigned int silen;
233 unsigned int i;
234 struct gprs_ra_id *raid;
235
236 if (cont->type_psi)
237 silen = BSSGP_RIM_PSI_LEN;
238 else
239 silen = BSSGP_RIM_SI_LEN;
240
241 /* The buffer must accept the reporting cell id, plus 1 byte to define
242 * the type and number of sysinfo messages. */
243 if (len < REP_CELL_ID_LEN + 1 + silen * cont->num_si)
244 return -EINVAL;
245
246 raid = (struct gprs_ra_id *)&cont->reprt_cell.rai;
247 rc = bssgp_create_cell_id(buf_ptr, raid, cont->reprt_cell.cell_identity);
248 if (rc < 0)
249 return -EINVAL;
250 buf_ptr += rc;
251
252 buf_ptr[0] = 0x00;
253 if (cont->type_psi)
254 buf_ptr[0] |= 0x01;
255 buf_ptr[0] |= (cont->num_si << 1);
256 buf_ptr++;
257
258 for (i = 0; i < cont->num_si; i++) {
259 memcpy(buf_ptr, cont->si[i], silen);
260 buf_ptr += silen;
261 }
262
263 return (int)(buf_ptr - buf);
264}
265
266/*! Decode a Application Error Container for NACC (3GPP TS 48.018, section 11.3.64.1).
267 * \param[out] user provided memory for decoded data struct.
268 * \param[in] buf user provided memory with the encoded value data of the IE.
269 * \returns 0 on success, -EINVAL on error. */
270int bssgp_dec_app_err_cont_nacc(struct bssgp_app_err_cont_nacc *cont, const uint8_t *buf, size_t len)
271{
272 /* The buffer must at least contain the NACC cause code, it should also
273 * contain the application container, but we won't error if it is missing. */
274 if (len < 1)
275 return -EINVAL;
276
277 cont->nacc_cause = buf[0];
278
279 if (len > 1) {
280 cont->err_app_cont = buf + 1;
281 cont->err_app_cont_len = len - 1;
282 } else {
283 cont->err_app_cont = NULL;
284 cont->err_app_cont_len = 0;
285 }
286
287 return 0;
288}
289
290/*! Encode Application Error Container for NACC (3GPP TS 48.018, section 11.3.64.1).
291 * \param[out] buf user provided memory for the generated value part of the IE.
292 * \param[in] cont user provided input data struct.
293 * \returns length of encoded octets, -EINVAL on error. */
294int bssgp_enc_app_err_cont_nacc(uint8_t *buf, size_t len, const struct bssgp_app_err_cont_nacc *cont)
295{
296 uint8_t *buf_ptr = buf;
297
298 /* The buffer must accept the length of the application container and the NACC
299 * cause code, which is one octet in length. */
300 if (len < cont->err_app_cont_len + 1)
301 return -EINVAL;
302
303 buf_ptr[0] = cont->nacc_cause;
304 buf_ptr++;
305
306 memcpy(buf_ptr, cont->err_app_cont, cont->err_app_cont_len);
307 buf_ptr += cont->err_app_cont_len;
308
309 return (int)(buf_ptr - buf);
310}
311
312/* The structs bssgp_ran_inf_req_rim_cont, bssgp_ran_inf_rim_cont and bssgp_ran_inf_app_err_rim_cont *cont
313 * share four common fields at the beginning, we use the following struct as parameter type for the common
314 * encoder/decoder functions. (See also 3GPP TS 48.018 table 11.3.62a.1.b, table 11.3.62a.2.b, and
315 * table 11.3.62a.5.b) */
316struct bssgp_ran_inf_x_cont {
317 enum bssgp_ran_inf_app_id app_id;
318 uint32_t seq_num;
319 struct bssgp_rim_pdu_ind pdu_ind;
320 uint8_t prot_ver;
321};
322
323static int dec_rim_cont_common(struct bssgp_ran_inf_x_cont *cont, struct tlv_parsed *tp)
324{
325 if (TLVP_PRES_LEN(tp, BSSGP_IE_RIM_APP_IDENTITY, sizeof(uint8_t)))
326 cont->app_id = TLVP_VAL(tp, BSSGP_IE_RIM_APP_IDENTITY)[0];
327 else
328 return -EINVAL;
329
330 if (TLVP_PRES_LEN(tp, BSSGP_IE_RIM_SEQ_NR, sizeof(cont->seq_num)))
331 cont->seq_num = tlvp_val32be(tp, BSSGP_IE_RIM_SEQ_NR);
332 else
333 return -EINVAL;
334
335 if (TLVP_PRES_LEN(tp, BSSGP_IE_RIM_PDU_INDICATIONS, sizeof(cont->pdu_ind)))
336 memcpy(&cont->pdu_ind, TLVP_VAL(tp, BSSGP_IE_RIM_PDU_INDICATIONS), sizeof(cont->pdu_ind));
337 else
338 return -EINVAL;
339
340 if (TLVP_PRES_LEN(tp, BSSGP_IE_RIM_PROTOCOL_VERSION, sizeof(cont->prot_ver)))
341 cont->prot_ver = TLVP_VAL(tp, BSSGP_IE_RIM_PROTOCOL_VERSION)[0];
342 else
343 cont->prot_ver = 1;
344
345 return 0;
346}
347
348static uint8_t *enc_rim_cont_common(uint8_t *buf, size_t len, const struct bssgp_ran_inf_x_cont *cont)
349{
350
351 uint32_t seq_num = osmo_htonl(cont->seq_num);
352 uint8_t app_id_temp;
353 uint8_t *buf_ptr = buf;
354
355 if (len <
356 TVLV_HDR_MAXLEN * 4 + sizeof(app_id_temp) + sizeof(seq_num) + sizeof(cont->pdu_ind) +
357 sizeof(cont->prot_ver))
358 return NULL;
359
360 app_id_temp = cont->app_id;
361 buf_ptr = tvlv_put(buf_ptr, BSSGP_IE_RIM_APP_IDENTITY, sizeof(app_id_temp), &app_id_temp);
362 buf_ptr = tvlv_put(buf_ptr, BSSGP_IE_RIM_SEQ_NR, sizeof(seq_num), (uint8_t *) & seq_num);
363 buf_ptr = tvlv_put(buf_ptr, BSSGP_IE_RIM_PDU_INDICATIONS, sizeof(cont->pdu_ind), (uint8_t *) & cont->pdu_ind);
364 if (cont->prot_ver > 0)
365 buf_ptr = tvlv_put(buf_ptr, BSSGP_IE_RIM_PROTOCOL_VERSION, sizeof(cont->prot_ver), &cont->prot_ver);
366
367 return buf_ptr;
368}
369
370/*! Decode a RAN Information Request RIM Container (3GPP TS 48.018, table 11.3.62a.1.b).
371 * \param[out] user provided memory for decoded data struct.
372 * \param[in] buf user provided memory with the encoded value data of the IE.
373 * \returns 0 on success, -EINVAL on error. */
374int bssgp_dec_ran_inf_req_rim_cont(struct bssgp_ran_inf_req_rim_cont *cont, const uint8_t *buf, size_t len)
375{
376 int rc;
377 struct tlv_parsed tp;
378
379 memset(cont, 0, sizeof(*cont));
380
381 rc = tlv_parse(&tp, &tvlv_att_def, buf, len, 0, 0);
382 if (rc < 0)
383 return -EINVAL;
384
385 rc = dec_rim_cont_common((struct bssgp_ran_inf_x_cont *)cont, &tp);
386 if (rc < 0)
387 return -EINVAL;
388
389 if (TLVP_PRESENT(&tp, BSSGP_IE_RIM_REQ_APP_CONTAINER)) {
390 switch (cont->app_id) {
391 case BSSGP_RAN_INF_APP_ID_NACC:
392 rc = bssgp_dec_ran_inf_req_app_cont_nacc(&cont->u.app_cont_nacc,
393 TLVP_VAL(&tp, BSSGP_IE_RIM_REQ_APP_CONTAINER),
394 TLVP_LEN(&tp, BSSGP_IE_RIM_REQ_APP_CONTAINER));
395 break;
396 case BSSGP_RAN_INF_APP_ID_SI3:
397 case BSSGP_RAN_INF_APP_ID_MBMS:
398 case BSSGP_RAN_INF_APP_ID_SON:
399 case BSSGP_RAN_INF_APP_ID_UTRA_SI:
400 /* TODO: add parsers for Si3, MBMS, SON, UTRA-SI app containers */
401 return -EINVAL;
402 default:
403 return -EINVAL;
404 }
405
406 if (rc < 0)
407 return rc;
408 }
409
410 if (TLVP_PRES_LEN(&tp, BSSGP_IE_SON_TRANSFER_APP_ID, 1)) {
411 cont->son_trans_app_id = TLVP_VAL(&tp, BSSGP_IE_SON_TRANSFER_APP_ID);
412 cont->son_trans_app_id_len = TLVP_LEN(&tp, BSSGP_IE_SON_TRANSFER_APP_ID);
413 }
414
415 return 0;
416}
417
418/* Dub a TLVP header into a given buffer. The value part of the IE must start
419 * at the 2nd octet. Should the length field make a 3 octet TLVP header
420 * necessary (unlikely, but possible) the value part is moved ahead by one
421 * octet. The function returns a pointer to the end of value part. */
422static uint8_t *dub_tlvp_header(uint8_t *buf, uint8_t iei, uint16_t len)
423{
424 uint8_t *buf_ptr = buf;
425
426 buf_ptr[0] = iei;
427 if (len <= TVLV_MAX_ONEBYTE) {
428 buf_ptr[1] = (uint8_t) len;
429 buf_ptr[1] |= 0x80;
430 buf_ptr += TVLV_HDR_LEN;
431 } else {
432 memmove(buf_ptr + 1, buf_ptr, len);
433 buf_ptr[1] = len >> 8;
434 buf_ptr[1] = len & 0xff;
435 buf_ptr += TVLV_HDR_MAXLEN;
436 }
437 buf_ptr += len;
438
439 return buf_ptr;
440}
441
442/*! Encode a RAN Information Request RIM Container (3GPP TS 48.018, table 11.3.62a.1.b).
443 * \param[out] buf user provided memory for the generated value part of the IE.
444 * \param[in] cont user provided input data struct.
445 * \returns length of encoded octets, -EINVAL on error. */
446int bssgp_enc_ran_inf_req_rim_cont(uint8_t *buf, size_t len, const struct bssgp_ran_inf_req_rim_cont *cont)
447{
448 uint8_t *buf_ptr = buf;
449 int app_cont_len = 0;
450 int remaining_buf_len;
451
452 buf_ptr = enc_rim_cont_common(buf_ptr, len, (struct bssgp_ran_inf_x_cont *)cont);
453 if (!buf_ptr)
454 return -EINVAL;
455
456 remaining_buf_len = len - (int)(buf_ptr - buf);
457 if (remaining_buf_len <= 0)
458 return -EINVAL;
459
460 switch (cont->app_id) {
461 case BSSGP_RAN_INF_APP_ID_NACC:
462 app_cont_len =
463 bssgp_enc_ran_inf_req_app_cont_nacc(buf_ptr + TVLV_HDR_LEN, remaining_buf_len - TVLV_HDR_MAXLEN,
464 &cont->u.app_cont_nacc);
465 break;
466 case BSSGP_RAN_INF_APP_ID_SI3:
467 case BSSGP_RAN_INF_APP_ID_MBMS:
468 case BSSGP_RAN_INF_APP_ID_SON:
469 case BSSGP_RAN_INF_APP_ID_UTRA_SI:
470 /* TODO: add encoders for Si3, MBMS, SON, UTRA-SI app containers */
471 return -EINVAL;
472 default:
473 return -EINVAL;
474 }
475
476 if (app_cont_len < 0)
477 return -EINVAL;
478 buf_ptr = dub_tlvp_header(buf_ptr, BSSGP_IE_RIM_REQ_APP_CONTAINER, app_cont_len);
479
480 remaining_buf_len = len - (int)(buf_ptr - buf);
481 if (remaining_buf_len < 0)
482 return -EINVAL;
483
484 if (cont->son_trans_app_id && cont->son_trans_app_id_len > 0) {
485 if (remaining_buf_len < cont->son_trans_app_id_len + TVLV_HDR_MAXLEN)
486 return -EINVAL;
487 buf_ptr =
488 tvlv_put(buf_ptr, BSSGP_IE_SON_TRANSFER_APP_ID, cont->son_trans_app_id_len, cont->son_trans_app_id);
489 }
490 return (int)(buf_ptr - buf);
491}
492
493/*! Decode a RAN Information RIM Container (3GPP TS 48.018, table 11.3.62a.2.b).
494 * \param[out] user provided memory for decoded data struct.
495 * \param[in] buf user provided memory with the encoded value data of the IE.
496 * \returns 0 on success, -EINVAL on error. */
497int bssgp_dec_ran_inf_rim_cont(struct bssgp_ran_inf_rim_cont *cont, const uint8_t *buf, size_t len)
498{
499 int rc;
500 struct tlv_parsed tp;
501
502 memset(cont, 0, sizeof(*cont));
503
504 rc = tlv_parse(&tp, &tvlv_att_def, buf, len, 0, 0);
505 if (rc < 0)
506 return -EINVAL;
507
508 rc = dec_rim_cont_common((struct bssgp_ran_inf_x_cont *)cont, &tp);
509 if (rc < 0)
510 return -EINVAL;
511
512 if (TLVP_PRESENT(&tp, BSSGP_IE_RAN_INFO_APP_CONTAINER)) {
513 switch (cont->app_id) {
514 case BSSGP_RAN_INF_APP_ID_NACC:
515 rc = bssgp_dec_ran_inf_app_cont_nacc(&cont->u.app_cont_nacc,
516 TLVP_VAL(&tp, BSSGP_IE_RAN_INFO_APP_CONTAINER),
517 TLVP_LEN(&tp, BSSGP_IE_RAN_INFO_APP_CONTAINER));
518 break;
519 case BSSGP_RAN_INF_APP_ID_SI3:
520 case BSSGP_RAN_INF_APP_ID_MBMS:
521 case BSSGP_RAN_INF_APP_ID_SON:
522 case BSSGP_RAN_INF_APP_ID_UTRA_SI:
523 /* TODO: add parsers for Si3, MBMS, SON, UTRA-SI app containers */
524 return -EINVAL;
525 default:
526 return -EINVAL;
527 }
528
529 if (rc < 0)
530 return rc;
531 } else if (TLVP_PRESENT(&tp, BSSGP_IE_APP_ERROR_CONTAINER)) {
532 switch (cont->app_id) {
533 case BSSGP_RAN_INF_APP_ID_NACC:
534 rc = bssgp_dec_app_err_cont_nacc(&cont->u.app_err_cont_nacc,
535 TLVP_VAL(&tp, BSSGP_IE_APP_ERROR_CONTAINER), TLVP_LEN(&tp,
536 BSSGP_IE_APP_ERROR_CONTAINER));
537 break;
538 case BSSGP_RAN_INF_APP_ID_SI3:
539 case BSSGP_RAN_INF_APP_ID_MBMS:
540 case BSSGP_RAN_INF_APP_ID_SON:
541 case BSSGP_RAN_INF_APP_ID_UTRA_SI:
542 /* TODO: add parsers for Si3, MBMS, SON, UTRA-SI app containers */
543 return -EINVAL;
544 default:
545 return -EINVAL;
546 }
547 if (rc < 0)
548 return rc;
549 cont->app_err = true;
550 }
551
552 if (TLVP_PRES_LEN(&tp, BSSGP_IE_SON_TRANSFER_APP_ID, 1)) {
553 cont->son_trans_app_id = TLVP_VAL(&tp, BSSGP_IE_SON_TRANSFER_APP_ID);
554 cont->son_trans_app_id_len = TLVP_LEN(&tp, BSSGP_IE_SON_TRANSFER_APP_ID);
555 }
556
557 return 0;
558}
559
560/*! Encode a RAN Information RIM Container (3GPP TS 48.018, table 11.3.62a.2.b).
561 * \param[out] buf user provided memory for the generated value part of the IE.
562 * \param[in] cont user provided input data struct.
563 * \returns length of encoded octets, -EINVAL on error. */
564int bssgp_enc_ran_inf_rim_cont(uint8_t *buf, size_t len, const struct bssgp_ran_inf_rim_cont *cont)
565{
566 uint8_t *buf_ptr = buf;
567 int app_cont_len = 0;
568 int remaining_buf_len;
569
570 buf_ptr = enc_rim_cont_common(buf_ptr, len, (struct bssgp_ran_inf_x_cont *)cont);
571 if (!buf_ptr)
572 return -EINVAL;
573
574 remaining_buf_len = len - (int)(buf_ptr - buf);
575 if (remaining_buf_len <= 0)
576 return -EINVAL;
577
578 if (cont->app_err) {
579 switch (cont->app_id) {
580 case BSSGP_RAN_INF_APP_ID_NACC:
581 app_cont_len =
582 bssgp_enc_app_err_cont_nacc(buf_ptr + TVLV_HDR_LEN, remaining_buf_len - TVLV_HDR_MAXLEN,
583 &cont->u.app_err_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 */
590 return -EINVAL;
591 default:
592 return -EINVAL;
593 }
594 if (app_cont_len < 0)
595 return -EINVAL;
596 buf_ptr = dub_tlvp_header(buf_ptr, BSSGP_IE_APP_ERROR_CONTAINER, app_cont_len);
597 } else {
598 switch (cont->app_id) {
599 case BSSGP_RAN_INF_APP_ID_NACC:
600 app_cont_len =
601 bssgp_enc_ran_inf_app_cont_nacc(buf_ptr + TVLV_HDR_LEN, remaining_buf_len - TVLV_HDR_MAXLEN,
602 &cont->u.app_cont_nacc);
603 break;
604 case BSSGP_RAN_INF_APP_ID_SI3:
605 case BSSGP_RAN_INF_APP_ID_MBMS:
606 case BSSGP_RAN_INF_APP_ID_SON:
607 case BSSGP_RAN_INF_APP_ID_UTRA_SI:
608 /* TODO: add encoders for Si3, MBMS, SON, UTRA-SI app containers */
609 return -EINVAL;
610 default:
611 return -EINVAL;
612 }
613 if (app_cont_len < 0)
614 return -EINVAL;
615 buf_ptr = dub_tlvp_header(buf_ptr, BSSGP_IE_RAN_INFO_APP_CONTAINER, app_cont_len);
616 }
617
618 remaining_buf_len = len - (int)(buf_ptr - buf);
619 if (remaining_buf_len < 0)
620 return -EINVAL;
621
622 if (cont->son_trans_app_id && cont->son_trans_app_id_len > 0) {
623 if (remaining_buf_len < cont->son_trans_app_id_len + TVLV_HDR_MAXLEN)
624 return -EINVAL;
625 buf_ptr =
626 tvlv_put(buf_ptr, BSSGP_IE_SON_TRANSFER_APP_ID, cont->son_trans_app_id_len, cont->son_trans_app_id);
627 }
628 return (int)(buf_ptr - buf);
629}
630
631/*! Decode a RAN Information ACK RIM Container (3GPP TS 48.018, table 11.3.62a.3.b).
632 * \param[out] user provided memory for decoded data struct.
633 * \param[in] buf user provided memory with the encoded value data of the IE.
634 * \returns 0 on success, -EINVAL on error. */
635int bssgp_dec_ran_inf_ack_rim_cont(struct bssgp_ran_inf_ack_rim_cont *cont, const uint8_t *buf, size_t len)
636{
637 int rc;
638 struct tlv_parsed tp;
639
640 memset(cont, 0, sizeof(*cont));
641
642 rc = tlv_parse(&tp, &tvlv_att_def, buf, len, 0, 0);
643 if (rc < 0)
644 return -EINVAL;
645
646 if (TLVP_PRES_LEN(&tp, BSSGP_IE_RIM_APP_IDENTITY, sizeof(uint8_t)))
647 cont->app_id = TLVP_VAL(&tp, BSSGP_IE_RIM_APP_IDENTITY)[0];
648 else
649 return -EINVAL;
650
651 if (TLVP_PRES_LEN(&tp, BSSGP_IE_RIM_SEQ_NR, sizeof(cont->seq_num)))
652 cont->seq_num = tlvp_val32be(&tp, BSSGP_IE_RIM_SEQ_NR);
653 else
654 return -EINVAL;
655
656 if (TLVP_PRES_LEN(&tp, BSSGP_IE_RIM_PROTOCOL_VERSION, sizeof(cont->prot_ver)))
657 cont->prot_ver = TLVP_VAL(&tp, BSSGP_IE_RIM_PROTOCOL_VERSION)[0];
658 else
659 cont->prot_ver = 1;
660
661 if (TLVP_PRES_LEN(&tp, BSSGP_IE_SON_TRANSFER_APP_ID, 1)) {
662 cont->son_trans_app_id = TLVP_VAL(&tp, BSSGP_IE_SON_TRANSFER_APP_ID);
663 cont->son_trans_app_id_len = TLVP_LEN(&tp, BSSGP_IE_SON_TRANSFER_APP_ID);
664 }
665
666 return 0;
667}
668
669/*! Encode a RAN Information ACK RIM Container (3GPP TS 48.018, table 11.3.62a.3.b).
670 * \param[out] buf user provided memory for the generated value part of the IE.
671 * \param[in] cont user provided input data struct.
672 * \returns length of encoded octets, -EINVAL on error. */
673int bssgp_enc_ran_inf_ack_rim_cont(uint8_t *buf, size_t len, const struct bssgp_ran_inf_ack_rim_cont *cont)
674{
675 uint8_t *buf_ptr = buf;
676 uint32_t seq_num = osmo_htonl(cont->seq_num);
677 uint8_t app_id_temp;
678
679 if (len <
680 4 * TVLV_HDR_MAXLEN + sizeof(app_id_temp) + sizeof(seq_num) + sizeof(cont->prot_ver) +
681 cont->son_trans_app_id_len)
682 return -EINVAL;
683
684 app_id_temp = cont->app_id;
685 buf_ptr = tvlv_put(buf_ptr, BSSGP_IE_RIM_APP_IDENTITY, sizeof(app_id_temp), &app_id_temp);
686 buf_ptr = tvlv_put(buf_ptr, BSSGP_IE_RIM_SEQ_NR, sizeof(seq_num), (uint8_t *) & seq_num);
687
688 if (cont->prot_ver > 0)
689 buf_ptr = tvlv_put(buf_ptr, BSSGP_IE_RIM_PROTOCOL_VERSION, sizeof(cont->prot_ver), &cont->prot_ver);
690
691 if (cont->son_trans_app_id && cont->son_trans_app_id_len > 0)
692 buf_ptr =
693 tvlv_put(buf_ptr, BSSGP_IE_SON_TRANSFER_APP_ID, cont->son_trans_app_id_len, cont->son_trans_app_id);
694
695 return (int)(buf_ptr - buf);
696}
697
698/*! Decode a RAN Information Error RIM Container (3GPP TS 48.018, table 11.3.62a.4.b).
699 * \param[out] user provided memory for decoded data struct.
700 * \param[in] buf user provided memory with the encoded value data of the IE.
701 * \returns 0 on success, -EINVAL on error. */
702int bssgp_dec_ran_inf_err_rim_cont(struct bssgp_ran_inf_err_rim_cont *cont, const uint8_t *buf, size_t len)
703{
704 int rc;
705 struct tlv_parsed tp;
706
707 memset(cont, 0, sizeof(*cont));
708
709 rc = tlv_parse(&tp, &tvlv_att_def, buf, len, 0, 0);
710 if (rc < 0)
711 return -EINVAL;
712
713 if (TLVP_PRES_LEN(&tp, BSSGP_IE_RIM_APP_IDENTITY, sizeof(uint8_t)))
714 cont->app_id = TLVP_VAL(&tp, BSSGP_IE_RIM_APP_IDENTITY)[0];
715 else
716 return -EINVAL;
717
718 if (TLVP_PRES_LEN(&tp, BSSGP_IE_CAUSE, sizeof(cont->cause)))
719 cont->cause = TLVP_VAL(&tp, BSSGP_IE_CAUSE)[0];
720 else
721 return -EINVAL;
722
723 if (TLVP_PRES_LEN(&tp, BSSGP_IE_RIM_PROTOCOL_VERSION, sizeof(cont->prot_ver)))
724 cont->prot_ver = TLVP_VAL(&tp, BSSGP_IE_RIM_PROTOCOL_VERSION)[0];
725 else
726 cont->prot_ver = 1;
727
728 if (TLVP_PRESENT(&tp, BSSGP_IE_PDU_IN_ERROR)) {
729 cont->err_pdu = TLVP_VAL(&tp, BSSGP_IE_PDU_IN_ERROR);
730 cont->err_pdu_len = TLVP_LEN(&tp, BSSGP_IE_PDU_IN_ERROR);
731 } else {
732 return -EINVAL;
733 }
734
735 if (TLVP_PRES_LEN(&tp, BSSGP_IE_SON_TRANSFER_APP_ID, 1)) {
736 cont->son_trans_app_id = TLVP_VAL(&tp, BSSGP_IE_SON_TRANSFER_APP_ID);
737 cont->son_trans_app_id_len = TLVP_LEN(&tp, BSSGP_IE_SON_TRANSFER_APP_ID);
738 }
739
740 return 0;
741}
742
743/*! Encode a RAN Information Error RIM Container (3GPP TS 48.018, table 11.3.62a.4.b).
744 * \param[out] buf user provided memory for the generated value part of the IE.
745 * \param[in] cont user provided input data struct.
746 * \returns length of encoded octets, -EINVAL on error. */
747int bssgp_enc_ran_inf_err_rim_cont(uint8_t *buf, size_t len, const struct bssgp_ran_inf_err_rim_cont *cont)
748{
749 uint8_t *buf_ptr = buf;
750 uint8_t app_id_temp;
751
752 if (len <
753 TVLV_HDR_MAXLEN * 5 + sizeof(app_id_temp) + sizeof(cont->cause) + sizeof(cont->prot_ver) +
754 cont->err_pdu_len + cont->son_trans_app_id_len)
755 return -EINVAL;
756
757 app_id_temp = cont->app_id;
758 buf_ptr = tvlv_put(buf_ptr, BSSGP_IE_RIM_APP_IDENTITY, sizeof(app_id_temp), &app_id_temp);
759 buf_ptr = tvlv_put(buf_ptr, BSSGP_IE_CAUSE, sizeof(cont->cause), &cont->cause);
760
761 if (cont->prot_ver > 0)
762 buf_ptr = tvlv_put(buf_ptr, BSSGP_IE_RIM_PROTOCOL_VERSION, sizeof(cont->prot_ver), &cont->prot_ver);
763
764 if (cont->err_pdu && cont->err_pdu_len > 0)
765 buf_ptr = tvlv_put(buf_ptr, BSSGP_IE_PDU_IN_ERROR, cont->err_pdu_len, cont->err_pdu);
766 else
767 return -EINVAL;
768
769 if (cont->son_trans_app_id && cont->son_trans_app_id_len > 0)
770 buf_ptr =
771 tvlv_put(buf_ptr, BSSGP_IE_SON_TRANSFER_APP_ID, cont->son_trans_app_id_len, cont->son_trans_app_id);
772
773 return (int)(buf_ptr - buf);
774}
775
776/*! Decode a RAN Information Application Error RIM Container (3GPP TS 48.018, table 11.3.62a.5.b).
777 * \param[out] user provided memory for decoded data struct.
778 * \param[in] buf user provided memory with the encoded value data of the IE.
779 * \returns 0 on success, -EINVAL on error. */
780int bssgp_dec_ran_inf_app_err_rim_cont(struct bssgp_ran_inf_app_err_rim_cont *cont, const uint8_t *buf, size_t len)
781{
782 int rc;
783 struct tlv_parsed tp;
784
785 memset(cont, 0, sizeof(*cont));
786
787 rc = tlv_parse(&tp, &tvlv_att_def, buf, len, 0, 0);
788 if (rc < 0)
789 return -EINVAL;
790
791 rc = dec_rim_cont_common((struct bssgp_ran_inf_x_cont *)cont, &tp);
792 if (rc < 0)
793 return -EINVAL;
794
795 switch (cont->app_id) {
796 case BSSGP_RAN_INF_APP_ID_NACC:
797 rc = bssgp_dec_app_err_cont_nacc(&cont->u.app_err_cont_nacc,
798 TLVP_VAL(&tp, BSSGP_IE_APP_ERROR_CONTAINER), TLVP_LEN(&tp,
799 BSSGP_IE_APP_ERROR_CONTAINER));
800 break;
801 case BSSGP_RAN_INF_APP_ID_SI3:
802 case BSSGP_RAN_INF_APP_ID_MBMS:
803 case BSSGP_RAN_INF_APP_ID_SON:
804 case BSSGP_RAN_INF_APP_ID_UTRA_SI:
805 /* TODO: add parsers for Si3, MBMS, SON, UTRA-SI app containers */
806 return -EINVAL;
807 default:
808 return -EINVAL;
809 }
810 if (rc < 0)
811 return rc;
812
813 return 0;
814}
815
816/*! Encode a RAN Information Application Error RIM Container (3GPP TS 48.018, table 11.3.62a.5.b).
817 * \param[out] buf user provided memory for the generated value part of the IE.
818 * \param[in] cont user provided input data struct.
819 * \returns length of encoded octets, -EINVAL on error. */
820int bssgp_enc_ran_inf_app_err_rim_cont(uint8_t *buf, size_t len, const struct bssgp_ran_inf_app_err_rim_cont *cont)
821{
822 uint8_t *buf_ptr = buf;
823 int app_cont_len = 0;
824 int remaining_buf_len;
825
826 buf_ptr = enc_rim_cont_common(buf_ptr, len, (struct bssgp_ran_inf_x_cont *)cont);
827 if (!buf_ptr)
828 return -EINVAL;
829
830 remaining_buf_len = len - (int)(buf_ptr - buf);
831 if (remaining_buf_len <= 0)
832 return -EINVAL;
833
834 switch (cont->app_id) {
835 case BSSGP_RAN_INF_APP_ID_NACC:
836 app_cont_len =
837 bssgp_enc_app_err_cont_nacc(buf_ptr + TVLV_HDR_LEN, remaining_buf_len - TVLV_HDR_MAXLEN,
838 &cont->u.app_err_cont_nacc);
839 break;
840 case BSSGP_RAN_INF_APP_ID_SI3:
841 case BSSGP_RAN_INF_APP_ID_MBMS:
842 case BSSGP_RAN_INF_APP_ID_SON:
843 case BSSGP_RAN_INF_APP_ID_UTRA_SI:
844 /* TODO: add encoders for Si3, MBMS, SON, UTRA-SI app containers */
845 return -EINVAL;
846 default:
847 return -EINVAL;
848 }
849 if (app_cont_len < 0)
850 return -EINVAL;
851 buf_ptr = dub_tlvp_header(buf_ptr, BSSGP_IE_APP_ERROR_CONTAINER, app_cont_len);
852
853 return (int)(buf_ptr - buf);
854}