blob: ac1e8520d38e5f8174a05549e5385dc28ddaf224 [file] [log] [blame]
Neels Hofmeyr17518fe2017-06-20 04:35:06 +02001/*
Harald Weltee08da972017-11-13 01:00:26 +09002 * (C) 2016 by sysmocom - s.f.m.c. GmbH, Author: Philipp Maier
Philipp Maier22401432017-03-24 17:59:26 +01003 * All Rights Reserved
4 *
Harald Weltee08da972017-11-13 01:00:26 +09005 * SPDX-License-Identifier: GPL-2.0+
Philipp Maier22401432017-03-24 17:59:26 +01006 *
7 * This program is free software; you can redistribute it and/or modify
Harald Weltee08da972017-11-13 01:00:26 +09008 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
Philipp Maier22401432017-03-24 17:59:26 +010010 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
Harald Weltee08da972017-11-13 01:00:26 +090015 * GNU General Public License for more details.
Philipp Maier22401432017-03-24 17:59:26 +010016 *
Harald Weltee08da972017-11-13 01:00:26 +090017 * You should have received a copy of the GNU General Public License
Philipp Maier22401432017-03-24 17:59:26 +010018 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 *
20 */
21
Harald Welte20725b92017-05-15 12:50:04 +020022#include "config.h"
23
Philipp Maier22401432017-03-24 17:59:26 +010024#include <osmocom/core/utils.h>
25#include <osmocom/core/msgb.h>
Harald Welte95871da2017-05-15 12:11:36 +020026#include <osmocom/core/byteswap.h>
Philipp Maier22401432017-03-24 17:59:26 +010027#include <string.h>
Philipp Maier22401432017-03-24 17:59:26 +010028#include <errno.h>
29#include <osmocom/gsm/protocol/gsm_08_08.h>
Stefan Sperling11a4d9d2018-02-15 18:28:04 +010030#include <osmocom/gsm/gsm48.h>
31#include <osmocom/gsm/gsm0808_utils.h>
Philipp Maier22401432017-03-24 17:59:26 +010032
33#define IP_V4_ADDR_LEN 4
34#define IP_V6_ADDR_LEN 16
35#define IP_PORT_LEN 2
36
Philipp Maiere0c65302017-03-28 17:05:40 +020037#define CHANNEL_TYPE_ELEMENT_MAXLEN 11
38#define CHANNEL_TYPE_ELEMENT_MINLEN 3
Philipp Maier14e76b92017-03-28 18:36:52 +020039#define ENCRYPT_INFO_ELEMENT_MINLEN 1
Philipp Maier6f725d62017-03-24 18:03:17 +010040
Harald Welte20725b92017-05-15 12:50:04 +020041#ifdef HAVE_SYS_SOCKET_H
42
43#include <sys/socket.h>
44#include <netinet/in.h>
Harald Welte96e2a002017-06-12 21:44:18 +020045
46/*! \addtogroup gsm0808
47 * @{
Harald Welte37b61652017-10-16 18:46:03 +020048 * \file gsm0808_utils.c
Harald Welte96e2a002017-06-12 21:44:18 +020049 */
50
Neels Hofmeyr87e45502017-06-20 00:17:59 +020051/*! Encode TS 08.08 AoIP transport address IE
Harald Welte96e2a002017-06-12 21:44:18 +020052 * \param[out] msg Message Buffer to which to append IE
53 * \param[in] ss Socket Address to be used in IE
54 * \returns number of bytes added to \a msg */
Philipp Maier22401432017-03-24 17:59:26 +010055uint8_t gsm0808_enc_aoip_trasp_addr(struct msgb *msg,
56 const struct sockaddr_storage *ss)
57{
58 /* See also 3GPP TS 48.008 3.2.2.102 AoIP Transport Layer Address */
59 struct sockaddr_in *sin;
60 struct sockaddr_in6 *sin6;
61 uint16_t port = 0;
62 uint8_t *ptr;
63 uint8_t *old_tail;
64 uint8_t *tlv_len;
65
66 OSMO_ASSERT(msg);
67 OSMO_ASSERT(ss);
68 OSMO_ASSERT(ss->ss_family == AF_INET || ss->ss_family == AF_INET6);
69
70 msgb_put_u8(msg, GSM0808_IE_AOIP_TRASP_ADDR);
71 tlv_len = msgb_put(msg,1);
72 old_tail = msg->tail;
73
74 switch (ss->ss_family) {
75 case AF_INET:
76 sin = (struct sockaddr_in *)ss;
Harald Welte95871da2017-05-15 12:11:36 +020077 port = osmo_ntohs(sin->sin_port);
Philipp Maier22401432017-03-24 17:59:26 +010078 ptr = msgb_put(msg, IP_V4_ADDR_LEN);
79 memcpy(ptr, &sin->sin_addr.s_addr, IP_V4_ADDR_LEN);
80 break;
81 case AF_INET6:
82 sin6 = (struct sockaddr_in6 *)ss;
Harald Welte95871da2017-05-15 12:11:36 +020083 port = osmo_ntohs(sin6->sin6_port);
Philipp Maier22401432017-03-24 17:59:26 +010084 ptr = msgb_put(msg, IP_V6_ADDR_LEN);
85 memcpy(ptr, sin6->sin6_addr.s6_addr, IP_V6_ADDR_LEN);
86 break;
87 }
88
89 msgb_put_u16(msg, port);
90
91 *tlv_len = (uint8_t) (msg->tail - old_tail);
92 return *tlv_len + 2;
93}
94
Neels Hofmeyr87e45502017-06-20 00:17:59 +020095/*! Decode TS 08.08 AoIP transport address IE
Harald Welte96e2a002017-06-12 21:44:18 +020096 * \param[out] ss Caller-provided memory where decoded socket addr is stored
97 * \param[in] elem pointer to IE value
98 * \param[in] len length of \a elem in bytes
99 * \returns number of bytes parsed */
Philipp Maier22401432017-03-24 17:59:26 +0100100int gsm0808_dec_aoip_trasp_addr(struct sockaddr_storage *ss,
101 const uint8_t *elem, uint8_t len)
102{
103 /* See also 3GPP TS 48.008 3.2.2.102 AoIP Transport Layer Address */
104 struct sockaddr_in sin;
105 struct sockaddr_in6 sin6;
106 const uint8_t *old_elem = elem;
107
108 OSMO_ASSERT(ss);
109 if (!elem)
110 return -EINVAL;
Philipp Maier17778bd2017-04-28 11:05:44 +0200111 if (len == 0)
Philipp Maier22401432017-03-24 17:59:26 +0100112 return -EINVAL;
113
114 memset(ss, 0, sizeof(*ss));
115
116 switch (len) {
117 case IP_V4_ADDR_LEN + IP_PORT_LEN:
118 memset(&sin, 0, sizeof(sin));
119 sin.sin_family = AF_INET;
120
121 memcpy(&sin.sin_addr.s_addr, elem, IP_V4_ADDR_LEN);
122 elem += IP_V4_ADDR_LEN;
123 sin.sin_port = osmo_load16le(elem);
124 elem += IP_PORT_LEN;
125
126 memcpy(ss, &sin, sizeof(sin));
127 break;
128 case IP_V6_ADDR_LEN + IP_PORT_LEN:
129 memset(&sin6, 0, sizeof(sin6));
130 sin6.sin6_family = AF_INET6;
131
132 memcpy(sin6.sin6_addr.s6_addr, elem, IP_V6_ADDR_LEN);
133 elem += IP_V6_ADDR_LEN;
134 sin6.sin6_port = osmo_load16le(elem);
135 elem += IP_PORT_LEN;
136
137 memcpy(ss, &sin6, sizeof(sin6));
138 break;
139 default:
140 /* Malformed element! */
141 return -EINVAL;
142 break;
143 }
144
145 return (int)(elem - old_elem);
146}
Philipp Maier6f725d62017-03-24 18:03:17 +0100147
Harald Welte20725b92017-05-15 12:50:04 +0200148#endif /* HAVE_SYS_SOCKET_H */
149
Philipp Maier6f725d62017-03-24 18:03:17 +0100150/* Helper function for gsm0808_enc_speech_codec()
151 * and gsm0808_enc_speech_codec_list() */
152static uint8_t enc_speech_codec(struct msgb *msg,
153 const struct gsm0808_speech_codec *sc)
154{
155 /* See also 3GPP TS 48.008 3.2.2.103 Speech Codec List */
156 uint8_t header = 0;
157 uint8_t *old_tail;
Philipp Maierbb839662017-06-01 17:11:19 +0200158 bool type_extended;
159
160 /* Note: Extended codec types are codec types that require 8 instead
161 * of 4 bit to fully specify the selected codec. In the following,
162 * we check if we work with an extended type or not. We also check
163 * if the codec type is valid at all. */
164 switch(sc->type) {
165 case GSM0808_SCT_FR1:
166 case GSM0808_SCT_FR2:
167 case GSM0808_SCT_FR3:
168 case GSM0808_SCT_FR4:
169 case GSM0808_SCT_FR5:
170 case GSM0808_SCT_HR1:
171 case GSM0808_SCT_HR3:
172 case GSM0808_SCT_HR4:
173 case GSM0808_SCT_HR6:
174 type_extended = false;
175 break;
176 case GSM0808_SCT_CSD:
177 type_extended = true;
178 break;
179 default:
180 /* Invalid codec type specified */
181 OSMO_ASSERT(false);
182 break;
183 }
Philipp Maier6f725d62017-03-24 18:03:17 +0100184
185 old_tail = msg->tail;
186
187 if (sc->fi)
188 header |= (1 << 7);
189 if (sc->pi)
190 header |= (1 << 6);
191 if (sc->pt)
192 header |= (1 << 5);
193 if (sc->tf)
194 header |= (1 << 4);
Philipp Maierbb839662017-06-01 17:11:19 +0200195
196 if (type_extended) {
Philipp Maier6f725d62017-03-24 18:03:17 +0100197 header |= 0x0f;
198 msgb_put_u8(msg, header);
Philipp Maierbb839662017-06-01 17:11:19 +0200199 msgb_put_u8(msg, sc->type);
Philipp Maier6f725d62017-03-24 18:03:17 +0100200 } else {
201 OSMO_ASSERT(sc->type < 0x0f);
202 header |= sc->type;
203 msgb_put_u8(msg, header);
Philipp Maier6f725d62017-03-24 18:03:17 +0100204 }
205
Philipp Maierbb839662017-06-01 17:11:19 +0200206 /* Note: Whether a configuration is present or not depends on the
207 * selected codec type. If present, it can either consist of one
208 * or two octets, depending on the codec type */
209 switch (sc->type) {
210 case GSM0808_SCT_FR3:
211 case GSM0808_SCT_HR3:
212 case GSM0808_SCT_HR6:
Philipp Maier6f725d62017-03-24 18:03:17 +0100213 msgb_put_u16(msg, sc->cfg);
Philipp Maierbb839662017-06-01 17:11:19 +0200214 break;
215 case GSM0808_SCT_FR4:
216 case GSM0808_SCT_FR5:
217 case GSM0808_SCT_HR4:
218 case GSM0808_SCT_CSD:
219 OSMO_ASSERT((sc->cfg & 0xff00) == 0)
220 msgb_put_u8(msg, (uint8_t) sc->cfg & 0xff);
221 break;
222 default:
223 OSMO_ASSERT(sc->cfg == 0);
224 break;
225 }
Philipp Maier6f725d62017-03-24 18:03:17 +0100226
227 return (uint8_t) (msg->tail - old_tail);
228}
229
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200230/*! Encode TS 08.08 Speech Codec IE
Harald Welte96e2a002017-06-12 21:44:18 +0200231 * \param[out] msg Message Buffer to which IE will be appended
232 * \param[in] sc Speech Codec to be encoded into IE
233 * \returns number of bytes appended to \a msg */
Philipp Maier6f725d62017-03-24 18:03:17 +0100234uint8_t gsm0808_enc_speech_codec(struct msgb *msg,
235 const struct gsm0808_speech_codec *sc)
236{
Philipp Maier452a6bb2017-06-23 00:29:34 +0200237 /*! See also 3GPP TS 48.008 3.2.2.103 Speech Codec List */
Philipp Maier6f725d62017-03-24 18:03:17 +0100238 uint8_t *old_tail;
239 uint8_t *tlv_len;
240
241 OSMO_ASSERT(msg);
242 OSMO_ASSERT(sc);
243
244 msgb_put_u8(msg, GSM0808_IE_SPEECH_CODEC);
245 tlv_len = msgb_put(msg, 1);
246 old_tail = msg->tail;
247
248 enc_speech_codec(msg, sc);
249
250 *tlv_len = (uint8_t) (msg->tail - old_tail);
251 return *tlv_len + 2;
252}
253
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200254/*! Decode TS 08.08 Speech Codec IE
Harald Welte96e2a002017-06-12 21:44:18 +0200255 * \param[out] sc Caller-allocated memory for Speech Codec
256 * \param[in] elem IE value to be decoded
257 * \param[in] len Length of \a elem in bytes
258 * \returns number of bytes parsed; negative on error */
Philipp Maier6f725d62017-03-24 18:03:17 +0100259int gsm0808_dec_speech_codec(struct gsm0808_speech_codec *sc,
260 const uint8_t *elem, uint8_t len)
261{
262 /* See also 3GPP TS 48.008 3.2.2.103 Speech Codec List */
263 uint8_t header;
264 const uint8_t *old_elem = elem;
265
266 OSMO_ASSERT(sc);
267 if (!elem)
268 return -EINVAL;
Philipp Maier17778bd2017-04-28 11:05:44 +0200269 if (len == 0)
Philipp Maier6f725d62017-03-24 18:03:17 +0100270 return -EINVAL;
271
272 memset(sc, 0, sizeof(*sc));
273
274 header = *elem;
275
Philipp Maier85a6af22017-04-28 10:55:05 +0200276 /* An extended codec type needs at least two fields,
277 * bail if the input data length is not sufficient. */
Philipp Maier6f725d62017-03-24 18:03:17 +0100278 if ((header & 0x0F) == 0x0F && len < 2)
279 return -EINVAL;
Philipp Maier6f725d62017-03-24 18:03:17 +0100280
281 elem++;
282 len--;
283
284 if (header & (1 << 7))
285 sc->fi = true;
286 if (header & (1 << 6))
287 sc->pi = true;
288 if (header & (1 << 5))
289 sc->pt = true;
290 if (header & (1 << 4))
291 sc->tf = true;
292
293 if ((header & 0x0F) != 0x0F) {
294 sc->type = (header & 0x0F);
Philipp Maierbb839662017-06-01 17:11:19 +0200295 } else {
296 sc->type = *elem;
297 elem++;
298 len--;
Philipp Maier6f725d62017-03-24 18:03:17 +0100299 }
300
Philipp Maierbb839662017-06-01 17:11:19 +0200301 /* Note: Whether a configuration is present or not depends on the
302 * selected codec type. If present, it can either consist of one or
303 * two octets depending on the codec type */
304 switch (sc->type) {
305 case GSM0808_SCT_FR1:
306 case GSM0808_SCT_FR2:
307 case GSM0808_SCT_HR1:
308 break;
309 case GSM0808_SCT_HR4:
310 case GSM0808_SCT_CSD:
311 case GSM0808_SCT_FR4:
312 case GSM0808_SCT_FR5:
313 if (len < 1)
314 return -EINVAL;
315 sc->cfg = *elem;
316 elem++;
317 break;
318 case GSM0808_SCT_FR3:
319 case GSM0808_SCT_HR3:
320 case GSM0808_SCT_HR6:
321 if (len < 2)
322 return -EINVAL;
323 sc->cfg = osmo_load16be(elem);
324 elem += 2;
325 break;
326 default:
327 /* Invalid codec type => malformed speech codec element! */
328 return -EINVAL;
329 break;
330 }
Philipp Maier6f725d62017-03-24 18:03:17 +0100331
332 return (int)(elem - old_elem);
333}
334
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200335/*! Encode TS 08.08 Speech Codec list
Harald Welte96e2a002017-06-12 21:44:18 +0200336 * \param[out] msg Message Buffer to which IE is to be appended
337 * \param[in] scl Speech Codec List to be encoded into IE
338 * \returns number of bytes added to \a msg */
Philipp Maier6f725d62017-03-24 18:03:17 +0100339uint8_t gsm0808_enc_speech_codec_list(struct msgb *msg,
340 const struct gsm0808_speech_codec_list *scl)
341{
Philipp Maier452a6bb2017-06-23 00:29:34 +0200342 /*! See also 3GPP TS 48.008 3.2.2.103 Speech Codec List */
Philipp Maier6f725d62017-03-24 18:03:17 +0100343 uint8_t *old_tail;
344 uint8_t *tlv_len;
345 unsigned int i;
346 uint8_t rc;
347 unsigned int bytes_used = 0;
348
349 OSMO_ASSERT(msg);
350 OSMO_ASSERT(scl);
351
352 /* Empty list */
353 OSMO_ASSERT(scl->len >= 1);
354
355 msgb_put_u8(msg, GSM0808_IE_SPEECH_CODEC_LIST);
356 tlv_len = msgb_put(msg, 1);
357 old_tail = msg->tail;
358
359 for (i = 0; i < scl->len; i++) {
360 rc = enc_speech_codec(msg, &scl->codec[i]);
361 OSMO_ASSERT(rc >= 1);
362 bytes_used += rc;
363 OSMO_ASSERT(bytes_used <= 255);
364 }
365
366 *tlv_len = (uint8_t) (msg->tail - old_tail);
367 return *tlv_len + 2;
368}
369
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200370/*! Decode TS 08.08 Speech Codec list IE
Harald Welte96e2a002017-06-12 21:44:18 +0200371 * \param[out] scl Caller-provided memory to store codec list
372 * \param[in] elem IE value to be decoded
373 * \param[in] len Length of \a elem in bytes
374 * \returns number of bytes parsed; negative on error */
Philipp Maier6f725d62017-03-24 18:03:17 +0100375int gsm0808_dec_speech_codec_list(struct gsm0808_speech_codec_list *scl,
376 const uint8_t *elem, uint8_t len)
377{
Philipp Maier452a6bb2017-06-23 00:29:34 +0200378 /*! See also 3GPP TS 48.008 3.2.2.103 Speech Codec List */
Philipp Maier6f725d62017-03-24 18:03:17 +0100379 const uint8_t *old_elem = elem;
380 unsigned int i;
381 int rc;
382 uint8_t decoded = 0;
383
384 OSMO_ASSERT(scl);
385 if (!elem)
386 return -EINVAL;
Philipp Maier17778bd2017-04-28 11:05:44 +0200387 if (len == 0)
Philipp Maier6f725d62017-03-24 18:03:17 +0100388 return -EINVAL;
389
390 memset(scl, 0, sizeof(*scl));
391
392 for (i = 0; i < ARRAY_SIZE(scl->codec); i++) {
393 if (len <= 0)
394 break;
395
396 rc = gsm0808_dec_speech_codec(&scl->codec[i], elem, len);
397 if (rc < 1)
398 return -EINVAL;
399
400 elem+=rc;
401 len -= rc;
402 decoded++;
403 }
404
405 scl->len = decoded;
406
407 /* Empty list */
408 if (decoded < 1) {
409 return -EINVAL;
410 }
411
412 return (int)(elem - old_elem);
413}
Philipp Maiere0c65302017-03-28 17:05:40 +0200414
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200415/*! Encode TS 08.08 Channel Type IE
Harald Welte96e2a002017-06-12 21:44:18 +0200416 * \param[out] msg Message Buffer to which IE is to be appended
417 * \param[in] ct Channel Type to be encoded
418 * \returns number of bytes added to \a msg */
Philipp Maiere0c65302017-03-28 17:05:40 +0200419uint8_t gsm0808_enc_channel_type(struct msgb *msg,
420 const struct gsm0808_channel_type *ct)
421{
Philipp Maier452a6bb2017-06-23 00:29:34 +0200422 /*! See also 3GPP TS 48.008 3.2.2.11 Channel Type */
Philipp Maiere0c65302017-03-28 17:05:40 +0200423 unsigned int i;
424 uint8_t byte;
425 uint8_t *old_tail;
426 uint8_t *tlv_len;
427
428 OSMO_ASSERT(msg);
429 OSMO_ASSERT(ct);
430 OSMO_ASSERT(ct->perm_spch_len <= CHANNEL_TYPE_ELEMENT_MAXLEN - 2);
431
432 /* FIXME: Implement encoding support for Data
433 * and Speech + CTM Text Telephony */
434 if ((ct->ch_indctr & 0x0f) != GSM0808_CHAN_SPEECH
435 && (ct->ch_indctr & 0x0f) != GSM0808_CHAN_SIGN)
436 OSMO_ASSERT(false);
437
438 msgb_put_u8(msg, GSM0808_IE_CHANNEL_TYPE);
439 tlv_len = msgb_put(msg, 1);
440 old_tail = msg->tail;
441
442 msgb_put_u8(msg, ct->ch_indctr & 0x0f);
443 msgb_put_u8(msg, ct->ch_rate_type);
444
445 for (i = 0; i < ct->perm_spch_len; i++) {
446 byte = ct->perm_spch[i];
447
448 if (i < ct->perm_spch_len - 1)
449 byte |= 0x80;
450 msgb_put_u8(msg, byte);
451 }
452
453 *tlv_len = (uint8_t) (msg->tail - old_tail);
454 return *tlv_len + 2;
455}
456
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200457/*! Decode TS 08.08 Channel Type IE
Harald Welte96e2a002017-06-12 21:44:18 +0200458 * \param[out] ct Caller-provided memory to store channel type
459 * \param[in] elem IE Value to be decoded
460 * \param[in] len Length of \a elem in bytes
461 * \returns number of bytes parsed; negative on error */
Philipp Maiere0c65302017-03-28 17:05:40 +0200462int gsm0808_dec_channel_type(struct gsm0808_channel_type *ct,
463 const uint8_t *elem, uint8_t len)
464{
Philipp Maier452a6bb2017-06-23 00:29:34 +0200465 /*! See also 3GPP TS 48.008 3.2.2.11 Channel Type */
Philipp Maiere0c65302017-03-28 17:05:40 +0200466 unsigned int i;
467 uint8_t byte;
468 const uint8_t *old_elem = elem;
469
470 OSMO_ASSERT(ct);
471 if (!elem)
472 return -EINVAL;
Philipp Maier17778bd2017-04-28 11:05:44 +0200473 if (len < 3 || len > 11)
Philipp Maiere0c65302017-03-28 17:05:40 +0200474 return -EINVAL;
475
476 memset(ct, 0, sizeof(*ct));
477
478 ct->ch_indctr = (*elem) & 0x0f;
479 elem++;
480 ct->ch_rate_type = (*elem) & 0x0f;
481 elem++;
482
483 for (i = 0; i < ARRAY_SIZE(ct->perm_spch); i++) {
484 byte = *elem;
485 elem++;
486 ct->perm_spch[i] = byte & 0x7f;
487 if ((byte & 0x80) == 0x00)
488 break;
489 }
490 ct->perm_spch_len = i + 1;
491
492 return (int)(elem - old_elem);
493}
Philipp Maier14e76b92017-03-28 18:36:52 +0200494
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200495/*! Encode TS 08.08 Encryption Information IE
Harald Welte96e2a002017-06-12 21:44:18 +0200496 * \param[out] msg Message Buffer to which IE is to be appended
497 * \param[in] ei Encryption Information to be encoded
498 * \returns number of bytes appended to \a msg */
Philipp Maier14e76b92017-03-28 18:36:52 +0200499uint8_t gsm0808_enc_encrypt_info(struct msgb *msg,
500 const struct gsm0808_encrypt_info *ei)
501{
502 unsigned int i;
503 uint8_t perm_algo = 0;
504 uint8_t *ptr;
505 uint8_t *old_tail;
506 uint8_t *tlv_len;
507
508 OSMO_ASSERT(msg);
509 OSMO_ASSERT(ei);
510 OSMO_ASSERT(ei->key_len <= ARRAY_SIZE(ei->key));
511 OSMO_ASSERT(ei->perm_algo_len <= ENCRY_INFO_PERM_ALGO_MAXLEN);
512
513 msgb_put_u8(msg, GSM0808_IE_ENCRYPTION_INFORMATION);
514 tlv_len = msgb_put(msg, 1);
515 old_tail = msg->tail;
516
517 for (i = 0; i < ei->perm_algo_len; i++) {
518 /* Note: gsm_08_08.h defines the permitted algorithms
519 * as an enum which ranges from 0x01 to 0x08 */
520 OSMO_ASSERT(ei->perm_algo[i] != 0);
521 OSMO_ASSERT(ei->perm_algo[i] <= ENCRY_INFO_PERM_ALGO_MAXLEN);
522 perm_algo |= (1 << (ei->perm_algo[i] - 1));
523 }
524
525 msgb_put_u8(msg, perm_algo);
526 ptr = msgb_put(msg, ei->key_len);
527 memcpy(ptr, ei->key, ei->key_len);
528
529 *tlv_len = (uint8_t) (msg->tail - old_tail);
530 return *tlv_len + 2;
531}
532
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200533/*! Decode TS 08.08 Encryption Information IE
Harald Welte96e2a002017-06-12 21:44:18 +0200534 * \param[out] ei Caller-provided memory to store encryption information
535 * \param[in] elem IE value to be decoded
536 * \param[in] len Length of \a elem in bytes
537 * \returns number of bytes parsed; negative on error */
Philipp Maier14e76b92017-03-28 18:36:52 +0200538int gsm0808_dec_encrypt_info(struct gsm0808_encrypt_info *ei,
539 const uint8_t *elem, uint8_t len)
540{
541 uint8_t perm_algo;
542 unsigned int i;
543 unsigned int perm_algo_len = 0;
544 const uint8_t *old_elem = elem;
545
546 OSMO_ASSERT(ei);
547 if (!elem)
548 return -EINVAL;
Philipp Maier17778bd2017-04-28 11:05:44 +0200549 if (len == 0)
Philipp Maier14e76b92017-03-28 18:36:52 +0200550 return -EINVAL;
551
552 memset(ei, 0, sizeof(*ei));
553
554 perm_algo = *elem;
555 elem++;
556
557 for (i = 0; i < ENCRY_INFO_PERM_ALGO_MAXLEN; i++) {
558 if (perm_algo & (1 << i)) {
559 ei->perm_algo[perm_algo_len] = i + 1;
560 perm_algo_len++;
561 }
562 }
563 ei->perm_algo_len = perm_algo_len;
564
565 ei->key_len = len - 1;
566 memcpy(ei->key, elem, ei->key_len);
567 elem+=ei->key_len;
568
569 return (int)(elem - old_elem);
570}
Philipp Maier783047e2017-03-29 11:35:50 +0200571
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200572/*! Encode TS 08.08 Cell Identifier List IE
Harald Welte96e2a002017-06-12 21:44:18 +0200573 * \param[out] msg Message Buffer to which IE is to be appended
574 * \param[in] cil Cell ID List to be encoded
575 * \returns number of bytes appended to \a msg */
Stefan Sperling11a4d9d2018-02-15 18:28:04 +0100576uint8_t gsm0808_enc_cell_id_list2(struct msgb *msg,
577 const struct gsm0808_cell_id_list2 *cil)
578{
579 uint8_t *old_tail;
580 uint8_t *tlv_len;
581 unsigned int i;
582
583 OSMO_ASSERT(msg);
584 OSMO_ASSERT(cil);
585
586 msgb_put_u8(msg, GSM0808_IE_CELL_IDENTIFIER_LIST);
587 tlv_len = msgb_put(msg, 1);
588 old_tail = msg->tail;
589
590 msgb_put_u8(msg, cil->id_discr & 0x0f);
591
592 OSMO_ASSERT(cil->id_list_len <= GSM0808_CELL_ID_LIST2_MAXLEN)
593 switch (cil->id_discr) {
594 case CELL_IDENT_WHOLE_GLOBAL:
595 for (i = 0; i < cil->id_list_len; i++) {
596 const struct osmo_cell_global_id *id = &cil->id_list[i].global;
597 struct gsm48_loc_area_id lai;
598 gsm48_generate_lai(&lai, id->lai.plmn.mcc, id->lai.plmn.mnc, id->lai.lac);
599 memcpy(msgb_put(msg, sizeof(lai)), &lai, sizeof(lai));
600 msgb_put_u16(msg, id->cell_identity);
601 }
602 break;
603 case CELL_IDENT_LAC_AND_CI:
604 for (i = 0; i < cil->id_list_len; i++) {
605 const struct osmo_lac_and_ci_id *id = &cil->id_list[i].lac_and_ci;
606 msgb_put_u16(msg, id->lac);
607 msgb_put_u16(msg, id->ci);
608 }
609 break;
610 case CELL_IDENT_CI:
611 for (i = 0; i < cil->id_list_len; i++)
612 msgb_put_u16(msg, cil->id_list[i].ci);
613 break;
614 case CELL_IDENT_LAI_AND_LAC:
615 for (i = 0; i < cil->id_list_len; i++) {
616 const struct osmo_location_area_id *id = &cil->id_list[i].lai_and_lac;
617 struct gsm48_loc_area_id lai;
618 gsm48_generate_lai(&lai, id->plmn.mcc, id->plmn.mnc, id->lac);
619 memcpy(msgb_put(msg, sizeof(lai)), &lai, sizeof(lai));
620 }
621 break;
622 case CELL_IDENT_LAC:
623 for (i = 0; i < cil->id_list_len; i++)
624 msgb_put_u16(msg, cil->id_list[i].lac);
625 break;
626 case CELL_IDENT_BSS:
627 case CELL_IDENT_NO_CELL:
628 /* Does not have any list items */
629 break;
630 default:
631 /* Support for other identifier list types is not implemented. */
632 OSMO_ASSERT(false);
633 }
634
635 *tlv_len = (uint8_t) (msg->tail - old_tail);
636 return *tlv_len + 2;
637}
638
639/*! DEPRECATED: Use gsm0808_enc_cell_id_list2 instead.
640 *
641 * Encode TS 08.08 Cell Identifier List IE
642 * \param[out] msg Message Buffer to which IE is to be appended
643 * \param[in] cil Cell ID List to be encoded
644 * \returns number of bytes appended to \a msg */
Philipp Maier783047e2017-03-29 11:35:50 +0200645uint8_t gsm0808_enc_cell_id_list(struct msgb *msg,
646 const struct gsm0808_cell_id_list *cil)
647{
648 uint8_t *old_tail;
649 uint8_t *tlv_len;
650 unsigned int i;
651
652 OSMO_ASSERT(msg);
653 OSMO_ASSERT(cil);
654
655 msgb_put_u8(msg, GSM0808_IE_CELL_IDENTIFIER_LIST);
656 tlv_len = msgb_put(msg, 1);
657 old_tail = msg->tail;
658
659 msgb_put_u8(msg, cil->id_discr & 0x0f);
660
661 switch (cil->id_discr) {
662 case CELL_IDENT_LAC:
663 OSMO_ASSERT(cil->id_list_len <= CELL_ID_LIST_LAC_MAXLEN)
664 for (i=0;i<cil->id_list_len;i++) {
665 msgb_put_u16(msg, cil->id_list_lac[i]);
666 }
667 break;
668 case CELL_IDENT_BSS:
669 /* Does not have any list items */
670 break;
671 default:
672 /* FIXME: Implement support for all identifier list elements */
673 OSMO_ASSERT(false);
674 }
675
676 *tlv_len = (uint8_t) (msg->tail - old_tail);
677 return *tlv_len + 2;
678}
679
Stefan Sperling23381452018-03-15 19:38:15 +0100680/* Decode 5-byte LAI list element data (see TS 08.08 3.2.2.27) into MCC/MNC/LAC. */
681static void decode_lai(const uint8_t *data, struct osmo_location_area_id *decoded)
Stefan Sperling11a4d9d2018-02-15 18:28:04 +0100682{
683 struct gsm48_loc_area_id lai;
684
Stefan Sperling23381452018-03-15 19:38:15 +0100685 /* Copy data to stack to prevent unaligned access in gsm48_decode_lai2(). */
Stefan Sperling11a4d9d2018-02-15 18:28:04 +0100686 memcpy(&lai, data, sizeof(lai)); /* don't byte swap yet */
687
Stefan Sperling23381452018-03-15 19:38:15 +0100688 gsm48_decode_lai2(&lai, decoded);
Stefan Sperling11a4d9d2018-02-15 18:28:04 +0100689}
690
Stefan Sperlinge1a86742018-03-15 18:05:02 +0100691static int parse_cell_id_global_list(struct gsm0808_cell_id_list2 *cil, const uint8_t *data, size_t remain,
Stefan Sperling11a4d9d2018-02-15 18:28:04 +0100692 size_t *consumed)
693{
694 struct osmo_cell_global_id *id;
695 uint16_t *ci_be;
696 size_t lai_offset;
697 int i = 0;
698 const size_t elemlen = sizeof(struct gsm48_loc_area_id) + sizeof(*ci_be);
699
700 *consumed = 0;
701 while (remain >= elemlen) {
702 if (i >= GSM0808_CELL_ID_LIST2_MAXLEN)
703 return -ENOSPC;
Stefan Sperlinge1a86742018-03-15 18:05:02 +0100704 id = &cil->id_list[i].global;
Stefan Sperling2873bf12018-03-14 18:38:41 +0100705 lai_offset = i * elemlen;
Stefan Sperling23381452018-03-15 19:38:15 +0100706 decode_lai(&data[lai_offset], &id->lai);
Stefan Sperling11a4d9d2018-02-15 18:28:04 +0100707 ci_be = (uint16_t *)(&data[lai_offset + sizeof(struct gsm48_loc_area_id)]);
708 id->cell_identity = osmo_load16be(ci_be);
709 *consumed += elemlen;
710 remain -= elemlen;
711 i++;
712 }
713
714 return i;
715}
716
Stefan Sperlinge1a86742018-03-15 18:05:02 +0100717static int parse_cell_id_lac_and_ci_list(struct gsm0808_cell_id_list2 *cil, const uint8_t *data, size_t remain,
Stefan Sperling11a4d9d2018-02-15 18:28:04 +0100718 size_t *consumed)
719{
720 uint16_t *lacp_be, *ci_be;
721 struct osmo_lac_and_ci_id *id;
722 int i = 0;
723 const size_t elemlen = sizeof(*lacp_be) + sizeof(*ci_be);
724
725 *consumed = 0;
726
727 if (remain < elemlen)
728 return -EINVAL;
729
730 lacp_be = (uint16_t *)(&data[0]);
731 ci_be = (uint16_t *)(&data[2]);
732 while (remain >= elemlen) {
733 if (i >= GSM0808_CELL_ID_LIST2_MAXLEN)
734 return -ENOSPC;
Stefan Sperlinge1a86742018-03-15 18:05:02 +0100735 id = &cil->id_list[i].lac_and_ci;
Stefan Sperling11a4d9d2018-02-15 18:28:04 +0100736 id->lac = osmo_load16be(lacp_be);
737 id->ci = osmo_load16be(ci_be);
738 *consumed += elemlen;
739 remain -= elemlen;
740 lacp_be++;
741 ci_be++;
742 }
743
744 return i;
745}
746
Stefan Sperlinge1a86742018-03-15 18:05:02 +0100747static int parse_cell_id_ci_list(struct gsm0808_cell_id_list2 *cil, const uint8_t *data, size_t remain,
748 size_t *consumed)
Stefan Sperling11a4d9d2018-02-15 18:28:04 +0100749{
750 const uint16_t *ci_be = (const uint16_t *)data;
751 int i = 0;
752 const size_t elemlen = sizeof(*ci_be);
753
754 *consumed = 0;
755 while (remain >= elemlen) {
756 if (i >= GSM0808_CELL_ID_LIST2_MAXLEN)
757 return -ENOSPC;
Stefan Sperlinge1a86742018-03-15 18:05:02 +0100758 cil->id_list[i++].ci = osmo_load16be(ci_be++);
Stefan Sperling11a4d9d2018-02-15 18:28:04 +0100759 consumed += elemlen;
760 remain -= elemlen;
761 }
762 return i;
763}
764
Stefan Sperlinge1a86742018-03-15 18:05:02 +0100765static int parse_cell_id_lai_and_lac(struct gsm0808_cell_id_list2 *cil, const uint8_t *data, size_t remain,
Stefan Sperling11a4d9d2018-02-15 18:28:04 +0100766 size_t *consumed)
767{
768 struct osmo_location_area_id *id;
769 int i = 0;
770 const size_t elemlen = sizeof(struct gsm48_loc_area_id);
771
772 *consumed = 0;
773 while (remain >= elemlen) {
774 if (i >= GSM0808_CELL_ID_LIST2_MAXLEN)
775 return -ENOSPC;
Stefan Sperlinge1a86742018-03-15 18:05:02 +0100776 id = &cil->id_list[i].lai_and_lac;
Stefan Sperling23381452018-03-15 19:38:15 +0100777 decode_lai(&data[i * elemlen], id);
Stefan Sperling11a4d9d2018-02-15 18:28:04 +0100778 *consumed += elemlen;
779 remain -= elemlen;
780 i++;
781 }
782
783 return i;
784}
785
Stefan Sperlinge1a86742018-03-15 18:05:02 +0100786static int parse_cell_id_lac_list(struct gsm0808_cell_id_list2 *cil, const uint8_t *data, size_t remain, size_t *consumed)
Stefan Sperling11a4d9d2018-02-15 18:28:04 +0100787{
788 const uint16_t *lac_be = (const uint16_t *)data;
789 int i = 0;
790 const size_t elemlen = sizeof(*lac_be);
791
792 *consumed = 0;
793 while (remain >= elemlen) {
794 if (i >= GSM0808_CELL_ID_LIST2_MAXLEN)
795 return -ENOSPC;
Stefan Sperlinge1a86742018-03-15 18:05:02 +0100796 cil->id_list[i++].lac = osmo_load16be(lac_be++);
Stefan Sperling11a4d9d2018-02-15 18:28:04 +0100797 *consumed += elemlen;
798 remain -= elemlen;
799 }
800 return i;
801}
802
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200803/*! Decode Cell Identifier List IE
Harald Welte96e2a002017-06-12 21:44:18 +0200804 * \param[out] cil Caller-provided memory to store Cell ID list
805 * \param[in] elem IE value to be decoded
806 * \param[in] len Length of \a elem in bytes
807 * \returns number of bytes parsed; negative on error */
Stefan Sperling11a4d9d2018-02-15 18:28:04 +0100808int gsm0808_dec_cell_id_list2(struct gsm0808_cell_id_list2 *cil,
809 const uint8_t *elem, uint8_t len)
810{
811 uint8_t id_discr;
812 size_t bytes_elem = 0;
813 int list_len = 0;
814
815 OSMO_ASSERT(cil);
816 if (!elem)
817 return -EINVAL;
818 if (len == 0)
819 return -EINVAL;
820
821 memset(cil, 0, sizeof(*cil));
822
823 id_discr = *elem & 0x0f;
824 elem++;
825 len--;
826
827 switch (id_discr) {
828 case CELL_IDENT_WHOLE_GLOBAL:
Stefan Sperlinge1a86742018-03-15 18:05:02 +0100829 list_len = parse_cell_id_global_list(cil, elem, len, &bytes_elem);
Stefan Sperling11a4d9d2018-02-15 18:28:04 +0100830 break;
831 case CELL_IDENT_LAC_AND_CI:
Stefan Sperlinge1a86742018-03-15 18:05:02 +0100832 list_len = parse_cell_id_lac_and_ci_list(cil, elem, len, &bytes_elem);
Stefan Sperling11a4d9d2018-02-15 18:28:04 +0100833 break;
834 case CELL_IDENT_CI:
Stefan Sperlinge1a86742018-03-15 18:05:02 +0100835 list_len = parse_cell_id_ci_list(cil, elem, len, &bytes_elem);
Stefan Sperling11a4d9d2018-02-15 18:28:04 +0100836 break;
837 case CELL_IDENT_LAI_AND_LAC:
Stefan Sperlinge1a86742018-03-15 18:05:02 +0100838 list_len = parse_cell_id_lai_and_lac(cil, elem, len, &bytes_elem);
Stefan Sperling11a4d9d2018-02-15 18:28:04 +0100839 break;
840 case CELL_IDENT_LAC:
Stefan Sperlinge1a86742018-03-15 18:05:02 +0100841 list_len = parse_cell_id_lac_list(cil, elem, len, &bytes_elem);
Stefan Sperling11a4d9d2018-02-15 18:28:04 +0100842 break;
843 case CELL_IDENT_BSS:
844 case CELL_IDENT_NO_CELL:
845 /* Does not have any list items */
846 break;
847 default:
848 /* Remaining cell identification types are not implemented. */
849 return -EINVAL;
850 }
851
852 if (list_len < 0) /* parsing error */
853 return list_len;
854
855 cil->id_discr = id_discr;
856 cil->id_list_len = list_len;
857
858 /* One byte for the cell ID discriminator + any remaining bytes in
859 * the IE which were consumed by the parser functions above. */
860 return 1 + (int)bytes_elem;
861}
862
863/*! DEPRECATED: Use gsm0808_dec_cell_id_list2 instead.
864 *
865 * Decode Cell Identifier List IE
866 * \param[out] cil Caller-provided memory to store Cell ID list
867 * \param[in] elem IE value to be decoded
868 * \param[in] len Length of \a elem in bytes
869 * \returns number of bytes parsed; negative on error */
Philipp Maier783047e2017-03-29 11:35:50 +0200870int gsm0808_dec_cell_id_list(struct gsm0808_cell_id_list *cil,
871 const uint8_t *elem, uint8_t len)
872{
873 uint8_t id_discr;
874 const uint8_t *old_elem = elem;
875 unsigned int item_count = 0;
876
877 OSMO_ASSERT(cil);
878 if (!elem)
879 return -EINVAL;
Philipp Maier17778bd2017-04-28 11:05:44 +0200880 if (len == 0)
Philipp Maier783047e2017-03-29 11:35:50 +0200881 return -EINVAL;
882
883 memset(cil, 0, sizeof(*cil));
884
885 id_discr = *elem & 0x0f;
886 elem++;
887 len--;
888
889 cil->id_discr = id_discr;
890
891 switch (id_discr) {
892 case CELL_IDENT_LAC:
893 while (len >= 2) {
894 cil->id_list_lac[item_count] = osmo_load16be(elem);
895 elem += 2;
896 item_count++;
897 len -= 2;
898 }
899 case CELL_IDENT_BSS:
900 /* Does not have any list items */
901 break;
902 default:
903 /* FIXME: Implement support for all identifier list elements */
904 return -EINVAL;
905 }
906
907 cil->id_list_len = item_count;
908 return (int)(elem - old_elem);
909}
Harald Welte96e2a002017-06-12 21:44:18 +0200910
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200911/*! Convert the representation of the permitted speech codec identifier
Philipp Maier3149b0d2017-06-02 13:22:34 +0200912 * that is used in struct gsm0808_channel_type to the speech codec
913 * representation we use in struct gsm0808_speech_codec.
914 * \param[in] perm_spch to be converted (see also gsm0808_permitted_speech)
915 * \returns GSM speech codec type; negative on error */
916int gsm0808_chan_type_to_speech_codec(uint8_t perm_spch)
917{
918 /*! The speech codec type, which is used in the channel type field to
919 * signal the permitted speech versions (codecs) has a different
920 * encoding than the type field in the speech codec type element
921 * (See also 3GPP TS 48.008, 3.2.2.11 and 3.2.2.103) */
922
923 switch (perm_spch) {
924 case GSM0808_PERM_FR1:
925 return GSM0808_SCT_FR1;
926 case GSM0808_PERM_FR2:
927 return GSM0808_SCT_FR2;
928 case GSM0808_PERM_FR3:
929 return GSM0808_SCT_FR3;
930 case GSM0808_PERM_FR4:
931 return GSM0808_SCT_FR4;
932 case GSM0808_PERM_FR5:
933 return GSM0808_SCT_FR5;
934 case GSM0808_PERM_HR1:
935 return GSM0808_SCT_HR1;
936 case GSM0808_PERM_HR3:
937 return GSM0808_SCT_HR3;
938 case GSM0808_PERM_HR4:
939 return GSM0808_SCT_HR4;
940 case GSM0808_PERM_HR6:
941 return GSM0808_SCT_HR6;
942 }
943
944 /* Invalid input */
945 return -EINVAL;
946}
947
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200948/*! Extrapolate a speech codec field from a given permitted speech
Philipp Maier884ba0f2017-06-02 13:49:16 +0200949 * parameter (channel type).
950 * \param[out] sc Caller provided memory to store the resulting speech codec
951 * \param[in] perm_spch value that is used to derive the speech codec info
952 * (see also: enum gsm0808_speech_codec_type in gsm0808_utils.h)
953 * \returns zero when successful; negative on error */
954int gsm0808_speech_codec_from_chan_type(struct gsm0808_speech_codec *sc,
955 uint8_t perm_spch)
956{
957 int rc;
958
959 memset(sc, 0, sizeof(*sc));
960
961 /* Determine codec type */
962 rc = gsm0808_chan_type_to_speech_codec(perm_spch);
963 if (rc < 0)
964 return -EINVAL;
965 sc->type = (uint8_t) rc;
966
967 /* Depending on the speech codec type, pick a default codec
968 * configuration that exactly matches the configuration on the
969 * air interface. */
970 switch (sc->type) {
971 case GSM0808_SCT_FR3:
972 sc->cfg = GSM0808_SC_CFG_DEFAULT_FR_AMR;
973 break;
974 case GSM0808_SCT_FR4:
975 sc->cfg = GSM0808_SC_CFG_DEFAULT_OFR_AMR_WB;
976 break;
977 case GSM0808_SCT_FR5:
978 sc->cfg = GSM0808_SC_CFG_DEFAULT_FR_AMR_WB;
979 break;
980 case GSM0808_SCT_HR3:
981 sc->cfg = GSM0808_SC_CFG_DEFAULT_HR_AMR;
982 break;
983 case GSM0808_SCT_HR4:
984 sc->cfg = GSM0808_SC_CFG_DEFAULT_OHR_AMR_WB;
985 break;
986 case GSM0808_SCT_HR6:
987 sc->cfg = GSM0808_SC_CFG_DEFAULT_OHR_AMR;
988 break;
989 default:
990 /* Note: Not all codec types specify a default setting,
991 * in this case, we just set the field to zero. */
992 sc->cfg = 0;
993 }
994
995 /* Tag all codecs as "Full IP"
996 * (see als 3GPP TS 48.008 3.2.2.103) */
997 sc->fi = true;
998
999 return 0;
1000}
1001
Harald Welte96e2a002017-06-12 21:44:18 +02001002/*! @} */