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