blob: a07ef0ec5f6dd92a4682655b3870d5010014e405 [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 Sperling11a4d9d2018-02-15 18:28:04 +0100680/* Decode 5-byte LAI list element data (see TS 08.08 3.2.2.27) into MCC/MNC/LAC.
681 * Return 0 if successful, negative on error. */
682static int decode_lai(const uint8_t *data, uint16_t *mcc, uint16_t *mnc, uint16_t *lac)
683{
684 struct gsm48_loc_area_id lai;
685
686 /* Copy data to stack to prevent unaligned access in gsm48_decode_lai(). */
687 memcpy(&lai, data, sizeof(lai)); /* don't byte swap yet */
688
689 return gsm48_decode_lai(&lai, mcc, mnc, lac) ? -1 : 0;
690}
691
692static int parse_cell_id_global_list(struct osmo_cell_global_id *id_list, const uint8_t *data, size_t remain,
693 size_t *consumed)
694{
695 struct osmo_cell_global_id *id;
696 uint16_t *ci_be;
697 size_t lai_offset;
698 int i = 0;
699 const size_t elemlen = sizeof(struct gsm48_loc_area_id) + sizeof(*ci_be);
700
701 *consumed = 0;
702 while (remain >= elemlen) {
703 if (i >= GSM0808_CELL_ID_LIST2_MAXLEN)
704 return -ENOSPC;
705 id = &id_list[i];
706 lai_offset = 1 + i * elemlen;
707 if (decode_lai(&data[lai_offset], &id->lai.plmn.mcc, &id->lai.plmn.mnc, &id->lai.lac) != 0)
708 return -EINVAL;
709 ci_be = (uint16_t *)(&data[lai_offset + sizeof(struct gsm48_loc_area_id)]);
710 id->cell_identity = osmo_load16be(ci_be);
711 *consumed += elemlen;
712 remain -= elemlen;
713 i++;
714 }
715
716 return i;
717}
718
719static int parse_cell_id_lac_and_ci_list(struct osmo_lac_and_ci_id *id_list, const uint8_t *data, size_t remain,
720 size_t *consumed)
721{
722 uint16_t *lacp_be, *ci_be;
723 struct osmo_lac_and_ci_id *id;
724 int i = 0;
725 const size_t elemlen = sizeof(*lacp_be) + sizeof(*ci_be);
726
727 *consumed = 0;
728
729 if (remain < elemlen)
730 return -EINVAL;
731
732 lacp_be = (uint16_t *)(&data[0]);
733 ci_be = (uint16_t *)(&data[2]);
734 while (remain >= elemlen) {
735 if (i >= GSM0808_CELL_ID_LIST2_MAXLEN)
736 return -ENOSPC;
737 id = &id_list[i];
738 id->lac = osmo_load16be(lacp_be);
739 id->ci = osmo_load16be(ci_be);
740 *consumed += elemlen;
741 remain -= elemlen;
742 lacp_be++;
743 ci_be++;
744 }
745
746 return i;
747}
748
749static int parse_cell_id_ci_list(uint16_t *id_list, const uint8_t *data, size_t remain, size_t *consumed)
750{
751 const uint16_t *ci_be = (const uint16_t *)data;
752 int i = 0;
753 const size_t elemlen = sizeof(*ci_be);
754
755 *consumed = 0;
756 while (remain >= elemlen) {
757 if (i >= GSM0808_CELL_ID_LIST2_MAXLEN)
758 return -ENOSPC;
759 id_list[i++] = osmo_load16be(ci_be++);
760 consumed += elemlen;
761 remain -= elemlen;
762 }
763 return i;
764}
765
766static int parse_cell_id_lai_and_lac(struct osmo_location_area_id *id_list, const uint8_t *data, size_t remain,
767 size_t *consumed)
768{
769 struct osmo_location_area_id *id;
770 int i = 0;
771 const size_t elemlen = sizeof(struct gsm48_loc_area_id);
772
773 *consumed = 0;
774 while (remain >= elemlen) {
775 if (i >= GSM0808_CELL_ID_LIST2_MAXLEN)
776 return -ENOSPC;
777 id = &id_list[i];
778 if (decode_lai(&data[1 + i * elemlen], &id->plmn.mcc, &id->plmn.mnc, &id->lac) != 0)
779 return -EINVAL;
780 *consumed += elemlen;
781 remain -= elemlen;
782 i++;
783 }
784
785 return i;
786}
787
788static int parse_cell_id_lac_list(uint16_t *id_list, const uint8_t *data, size_t remain, size_t *consumed)
789{
790 const uint16_t *lac_be = (const uint16_t *)data;
791 int i = 0;
792 const size_t elemlen = sizeof(*lac_be);
793
794 *consumed = 0;
795 while (remain >= elemlen) {
796 if (i >= GSM0808_CELL_ID_LIST2_MAXLEN)
797 return -ENOSPC;
798 id_list[i++] = osmo_load16be(lac_be++);
799 *consumed += elemlen;
800 remain -= elemlen;
801 }
802 return i;
803}
804
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200805/*! Decode Cell Identifier List IE
Harald Welte96e2a002017-06-12 21:44:18 +0200806 * \param[out] cil Caller-provided memory to store Cell ID list
807 * \param[in] elem IE value to be decoded
808 * \param[in] len Length of \a elem in bytes
809 * \returns number of bytes parsed; negative on error */
Stefan Sperling11a4d9d2018-02-15 18:28:04 +0100810int gsm0808_dec_cell_id_list2(struct gsm0808_cell_id_list2 *cil,
811 const uint8_t *elem, uint8_t len)
812{
813 uint8_t id_discr;
814 size_t bytes_elem = 0;
815 int list_len = 0;
816
817 OSMO_ASSERT(cil);
818 if (!elem)
819 return -EINVAL;
820 if (len == 0)
821 return -EINVAL;
822
823 memset(cil, 0, sizeof(*cil));
824
825 id_discr = *elem & 0x0f;
826 elem++;
827 len--;
828
829 switch (id_discr) {
830 case CELL_IDENT_WHOLE_GLOBAL:
831 list_len = parse_cell_id_global_list(&cil->id_list[0].global, elem, len, &bytes_elem);
832 break;
833 case CELL_IDENT_LAC_AND_CI:
834 list_len = parse_cell_id_lac_and_ci_list(&cil->id_list[0].lac_and_ci, elem, len, &bytes_elem);
835 break;
836 case CELL_IDENT_CI:
837 list_len = parse_cell_id_ci_list(&cil->id_list[0].ci, elem, len, &bytes_elem);
838 break;
839 case CELL_IDENT_LAI_AND_LAC:
840 list_len = parse_cell_id_lai_and_lac(&cil->id_list[0].lai_and_lac, elem, len, &bytes_elem);
841 break;
842 case CELL_IDENT_LAC:
843 list_len = parse_cell_id_lac_list(&cil->id_list[0].lac, elem, len, &bytes_elem);
844 break;
845 case CELL_IDENT_BSS:
846 case CELL_IDENT_NO_CELL:
847 /* Does not have any list items */
848 break;
849 default:
850 /* Remaining cell identification types are not implemented. */
851 return -EINVAL;
852 }
853
854 if (list_len < 0) /* parsing error */
855 return list_len;
856
857 cil->id_discr = id_discr;
858 cil->id_list_len = list_len;
859
860 /* One byte for the cell ID discriminator + any remaining bytes in
861 * the IE which were consumed by the parser functions above. */
862 return 1 + (int)bytes_elem;
863}
864
865/*! DEPRECATED: Use gsm0808_dec_cell_id_list2 instead.
866 *
867 * Decode Cell Identifier List IE
868 * \param[out] cil Caller-provided memory to store Cell ID list
869 * \param[in] elem IE value to be decoded
870 * \param[in] len Length of \a elem in bytes
871 * \returns number of bytes parsed; negative on error */
Philipp Maier783047e2017-03-29 11:35:50 +0200872int gsm0808_dec_cell_id_list(struct gsm0808_cell_id_list *cil,
873 const uint8_t *elem, uint8_t len)
874{
875 uint8_t id_discr;
876 const uint8_t *old_elem = elem;
877 unsigned int item_count = 0;
878
879 OSMO_ASSERT(cil);
880 if (!elem)
881 return -EINVAL;
Philipp Maier17778bd2017-04-28 11:05:44 +0200882 if (len == 0)
Philipp Maier783047e2017-03-29 11:35:50 +0200883 return -EINVAL;
884
885 memset(cil, 0, sizeof(*cil));
886
887 id_discr = *elem & 0x0f;
888 elem++;
889 len--;
890
891 cil->id_discr = id_discr;
892
893 switch (id_discr) {
894 case CELL_IDENT_LAC:
895 while (len >= 2) {
896 cil->id_list_lac[item_count] = osmo_load16be(elem);
897 elem += 2;
898 item_count++;
899 len -= 2;
900 }
901 case CELL_IDENT_BSS:
902 /* Does not have any list items */
903 break;
904 default:
905 /* FIXME: Implement support for all identifier list elements */
906 return -EINVAL;
907 }
908
909 cil->id_list_len = item_count;
910 return (int)(elem - old_elem);
911}
Harald Welte96e2a002017-06-12 21:44:18 +0200912
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200913/*! Convert the representation of the permitted speech codec identifier
Philipp Maier3149b0d2017-06-02 13:22:34 +0200914 * that is used in struct gsm0808_channel_type to the speech codec
915 * representation we use in struct gsm0808_speech_codec.
916 * \param[in] perm_spch to be converted (see also gsm0808_permitted_speech)
917 * \returns GSM speech codec type; negative on error */
918int gsm0808_chan_type_to_speech_codec(uint8_t perm_spch)
919{
920 /*! The speech codec type, which is used in the channel type field to
921 * signal the permitted speech versions (codecs) has a different
922 * encoding than the type field in the speech codec type element
923 * (See also 3GPP TS 48.008, 3.2.2.11 and 3.2.2.103) */
924
925 switch (perm_spch) {
926 case GSM0808_PERM_FR1:
927 return GSM0808_SCT_FR1;
928 case GSM0808_PERM_FR2:
929 return GSM0808_SCT_FR2;
930 case GSM0808_PERM_FR3:
931 return GSM0808_SCT_FR3;
932 case GSM0808_PERM_FR4:
933 return GSM0808_SCT_FR4;
934 case GSM0808_PERM_FR5:
935 return GSM0808_SCT_FR5;
936 case GSM0808_PERM_HR1:
937 return GSM0808_SCT_HR1;
938 case GSM0808_PERM_HR3:
939 return GSM0808_SCT_HR3;
940 case GSM0808_PERM_HR4:
941 return GSM0808_SCT_HR4;
942 case GSM0808_PERM_HR6:
943 return GSM0808_SCT_HR6;
944 }
945
946 /* Invalid input */
947 return -EINVAL;
948}
949
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200950/*! Extrapolate a speech codec field from a given permitted speech
Philipp Maier884ba0f2017-06-02 13:49:16 +0200951 * parameter (channel type).
952 * \param[out] sc Caller provided memory to store the resulting speech codec
953 * \param[in] perm_spch value that is used to derive the speech codec info
954 * (see also: enum gsm0808_speech_codec_type in gsm0808_utils.h)
955 * \returns zero when successful; negative on error */
956int gsm0808_speech_codec_from_chan_type(struct gsm0808_speech_codec *sc,
957 uint8_t perm_spch)
958{
959 int rc;
960
961 memset(sc, 0, sizeof(*sc));
962
963 /* Determine codec type */
964 rc = gsm0808_chan_type_to_speech_codec(perm_spch);
965 if (rc < 0)
966 return -EINVAL;
967 sc->type = (uint8_t) rc;
968
969 /* Depending on the speech codec type, pick a default codec
970 * configuration that exactly matches the configuration on the
971 * air interface. */
972 switch (sc->type) {
973 case GSM0808_SCT_FR3:
974 sc->cfg = GSM0808_SC_CFG_DEFAULT_FR_AMR;
975 break;
976 case GSM0808_SCT_FR4:
977 sc->cfg = GSM0808_SC_CFG_DEFAULT_OFR_AMR_WB;
978 break;
979 case GSM0808_SCT_FR5:
980 sc->cfg = GSM0808_SC_CFG_DEFAULT_FR_AMR_WB;
981 break;
982 case GSM0808_SCT_HR3:
983 sc->cfg = GSM0808_SC_CFG_DEFAULT_HR_AMR;
984 break;
985 case GSM0808_SCT_HR4:
986 sc->cfg = GSM0808_SC_CFG_DEFAULT_OHR_AMR_WB;
987 break;
988 case GSM0808_SCT_HR6:
989 sc->cfg = GSM0808_SC_CFG_DEFAULT_OHR_AMR;
990 break;
991 default:
992 /* Note: Not all codec types specify a default setting,
993 * in this case, we just set the field to zero. */
994 sc->cfg = 0;
995 }
996
997 /* Tag all codecs as "Full IP"
998 * (see als 3GPP TS 48.008 3.2.2.103) */
999 sc->fi = true;
1000
1001 return 0;
1002}
1003
Harald Welte96e2a002017-06-12 21:44:18 +02001004/*! @} */