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