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