blob: 2d95ec6849debfa507e34e29f7148038bb73e29d [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
Stefan Sperlinge1a86742018-03-15 18:05:02 +0100692static 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 +0100693 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;
Stefan Sperlinge1a86742018-03-15 18:05:02 +0100705 id = &cil->id_list[i].global;
Stefan Sperling2873bf12018-03-14 18:38:41 +0100706 lai_offset = i * elemlen;
Stefan Sperling11a4d9d2018-02-15 18:28:04 +0100707 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
Stefan Sperlinge1a86742018-03-15 18:05:02 +0100719static 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 +0100720 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;
Stefan Sperlinge1a86742018-03-15 18:05:02 +0100737 id = &cil->id_list[i].lac_and_ci;
Stefan Sperling11a4d9d2018-02-15 18:28:04 +0100738 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
Stefan Sperlinge1a86742018-03-15 18:05:02 +0100749static int parse_cell_id_ci_list(struct gsm0808_cell_id_list2 *cil, const uint8_t *data, size_t remain,
750 size_t *consumed)
Stefan Sperling11a4d9d2018-02-15 18:28:04 +0100751{
752 const uint16_t *ci_be = (const uint16_t *)data;
753 int i = 0;
754 const size_t elemlen = sizeof(*ci_be);
755
756 *consumed = 0;
757 while (remain >= elemlen) {
758 if (i >= GSM0808_CELL_ID_LIST2_MAXLEN)
759 return -ENOSPC;
Stefan Sperlinge1a86742018-03-15 18:05:02 +0100760 cil->id_list[i++].ci = osmo_load16be(ci_be++);
Stefan Sperling11a4d9d2018-02-15 18:28:04 +0100761 consumed += elemlen;
762 remain -= elemlen;
763 }
764 return i;
765}
766
Stefan Sperlinge1a86742018-03-15 18:05:02 +0100767static 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 +0100768 size_t *consumed)
769{
770 struct osmo_location_area_id *id;
771 int i = 0;
772 const size_t elemlen = sizeof(struct gsm48_loc_area_id);
773
774 *consumed = 0;
775 while (remain >= elemlen) {
776 if (i >= GSM0808_CELL_ID_LIST2_MAXLEN)
777 return -ENOSPC;
Stefan Sperlinge1a86742018-03-15 18:05:02 +0100778 id = &cil->id_list[i].lai_and_lac;
Stefan Sperling2873bf12018-03-14 18:38:41 +0100779 if (decode_lai(&data[i * elemlen], &id->plmn.mcc, &id->plmn.mnc, &id->lac) != 0)
Stefan Sperling11a4d9d2018-02-15 18:28:04 +0100780 return -EINVAL;
781 *consumed += elemlen;
782 remain -= elemlen;
783 i++;
784 }
785
786 return i;
787}
788
Stefan Sperlinge1a86742018-03-15 18:05:02 +0100789static 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 +0100790{
791 const uint16_t *lac_be = (const uint16_t *)data;
792 int i = 0;
793 const size_t elemlen = sizeof(*lac_be);
794
795 *consumed = 0;
796 while (remain >= elemlen) {
797 if (i >= GSM0808_CELL_ID_LIST2_MAXLEN)
798 return -ENOSPC;
Stefan Sperlinge1a86742018-03-15 18:05:02 +0100799 cil->id_list[i++].lac = osmo_load16be(lac_be++);
Stefan Sperling11a4d9d2018-02-15 18:28:04 +0100800 *consumed += elemlen;
801 remain -= elemlen;
802 }
803 return i;
804}
805
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200806/*! Decode Cell Identifier List IE
Harald Welte96e2a002017-06-12 21:44:18 +0200807 * \param[out] cil Caller-provided memory to store Cell ID list
808 * \param[in] elem IE value to be decoded
809 * \param[in] len Length of \a elem in bytes
810 * \returns number of bytes parsed; negative on error */
Stefan Sperling11a4d9d2018-02-15 18:28:04 +0100811int gsm0808_dec_cell_id_list2(struct gsm0808_cell_id_list2 *cil,
812 const uint8_t *elem, uint8_t len)
813{
814 uint8_t id_discr;
815 size_t bytes_elem = 0;
816 int list_len = 0;
817
818 OSMO_ASSERT(cil);
819 if (!elem)
820 return -EINVAL;
821 if (len == 0)
822 return -EINVAL;
823
824 memset(cil, 0, sizeof(*cil));
825
826 id_discr = *elem & 0x0f;
827 elem++;
828 len--;
829
830 switch (id_discr) {
831 case CELL_IDENT_WHOLE_GLOBAL:
Stefan Sperlinge1a86742018-03-15 18:05:02 +0100832 list_len = parse_cell_id_global_list(cil, elem, len, &bytes_elem);
Stefan Sperling11a4d9d2018-02-15 18:28:04 +0100833 break;
834 case CELL_IDENT_LAC_AND_CI:
Stefan Sperlinge1a86742018-03-15 18:05:02 +0100835 list_len = parse_cell_id_lac_and_ci_list(cil, elem, len, &bytes_elem);
Stefan Sperling11a4d9d2018-02-15 18:28:04 +0100836 break;
837 case CELL_IDENT_CI:
Stefan Sperlinge1a86742018-03-15 18:05:02 +0100838 list_len = parse_cell_id_ci_list(cil, elem, len, &bytes_elem);
Stefan Sperling11a4d9d2018-02-15 18:28:04 +0100839 break;
840 case CELL_IDENT_LAI_AND_LAC:
Stefan Sperlinge1a86742018-03-15 18:05:02 +0100841 list_len = parse_cell_id_lai_and_lac(cil, elem, len, &bytes_elem);
Stefan Sperling11a4d9d2018-02-15 18:28:04 +0100842 break;
843 case CELL_IDENT_LAC:
Stefan Sperlinge1a86742018-03-15 18:05:02 +0100844 list_len = parse_cell_id_lac_list(cil, elem, len, &bytes_elem);
Stefan Sperling11a4d9d2018-02-15 18:28:04 +0100845 break;
846 case CELL_IDENT_BSS:
847 case CELL_IDENT_NO_CELL:
848 /* Does not have any list items */
849 break;
850 default:
851 /* Remaining cell identification types are not implemented. */
852 return -EINVAL;
853 }
854
855 if (list_len < 0) /* parsing error */
856 return list_len;
857
858 cil->id_discr = id_discr;
859 cil->id_list_len = list_len;
860
861 /* One byte for the cell ID discriminator + any remaining bytes in
862 * the IE which were consumed by the parser functions above. */
863 return 1 + (int)bytes_elem;
864}
865
866/*! DEPRECATED: Use gsm0808_dec_cell_id_list2 instead.
867 *
868 * Decode Cell Identifier List IE
869 * \param[out] cil Caller-provided memory to store Cell ID list
870 * \param[in] elem IE value to be decoded
871 * \param[in] len Length of \a elem in bytes
872 * \returns number of bytes parsed; negative on error */
Philipp Maier783047e2017-03-29 11:35:50 +0200873int gsm0808_dec_cell_id_list(struct gsm0808_cell_id_list *cil,
874 const uint8_t *elem, uint8_t len)
875{
876 uint8_t id_discr;
877 const uint8_t *old_elem = elem;
878 unsigned int item_count = 0;
879
880 OSMO_ASSERT(cil);
881 if (!elem)
882 return -EINVAL;
Philipp Maier17778bd2017-04-28 11:05:44 +0200883 if (len == 0)
Philipp Maier783047e2017-03-29 11:35:50 +0200884 return -EINVAL;
885
886 memset(cil, 0, sizeof(*cil));
887
888 id_discr = *elem & 0x0f;
889 elem++;
890 len--;
891
892 cil->id_discr = id_discr;
893
894 switch (id_discr) {
895 case CELL_IDENT_LAC:
896 while (len >= 2) {
897 cil->id_list_lac[item_count] = osmo_load16be(elem);
898 elem += 2;
899 item_count++;
900 len -= 2;
901 }
902 case CELL_IDENT_BSS:
903 /* Does not have any list items */
904 break;
905 default:
906 /* FIXME: Implement support for all identifier list elements */
907 return -EINVAL;
908 }
909
910 cil->id_list_len = item_count;
911 return (int)(elem - old_elem);
912}
Harald Welte96e2a002017-06-12 21:44:18 +0200913
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200914/*! Convert the representation of the permitted speech codec identifier
Philipp Maier3149b0d2017-06-02 13:22:34 +0200915 * that is used in struct gsm0808_channel_type to the speech codec
916 * representation we use in struct gsm0808_speech_codec.
917 * \param[in] perm_spch to be converted (see also gsm0808_permitted_speech)
918 * \returns GSM speech codec type; negative on error */
919int gsm0808_chan_type_to_speech_codec(uint8_t perm_spch)
920{
921 /*! The speech codec type, which is used in the channel type field to
922 * signal the permitted speech versions (codecs) has a different
923 * encoding than the type field in the speech codec type element
924 * (See also 3GPP TS 48.008, 3.2.2.11 and 3.2.2.103) */
925
926 switch (perm_spch) {
927 case GSM0808_PERM_FR1:
928 return GSM0808_SCT_FR1;
929 case GSM0808_PERM_FR2:
930 return GSM0808_SCT_FR2;
931 case GSM0808_PERM_FR3:
932 return GSM0808_SCT_FR3;
933 case GSM0808_PERM_FR4:
934 return GSM0808_SCT_FR4;
935 case GSM0808_PERM_FR5:
936 return GSM0808_SCT_FR5;
937 case GSM0808_PERM_HR1:
938 return GSM0808_SCT_HR1;
939 case GSM0808_PERM_HR3:
940 return GSM0808_SCT_HR3;
941 case GSM0808_PERM_HR4:
942 return GSM0808_SCT_HR4;
943 case GSM0808_PERM_HR6:
944 return GSM0808_SCT_HR6;
945 }
946
947 /* Invalid input */
948 return -EINVAL;
949}
950
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200951/*! Extrapolate a speech codec field from a given permitted speech
Philipp Maier884ba0f2017-06-02 13:49:16 +0200952 * parameter (channel type).
953 * \param[out] sc Caller provided memory to store the resulting speech codec
954 * \param[in] perm_spch value that is used to derive the speech codec info
955 * (see also: enum gsm0808_speech_codec_type in gsm0808_utils.h)
956 * \returns zero when successful; negative on error */
957int gsm0808_speech_codec_from_chan_type(struct gsm0808_speech_codec *sc,
958 uint8_t perm_spch)
959{
960 int rc;
961
962 memset(sc, 0, sizeof(*sc));
963
964 /* Determine codec type */
965 rc = gsm0808_chan_type_to_speech_codec(perm_spch);
966 if (rc < 0)
967 return -EINVAL;
968 sc->type = (uint8_t) rc;
969
970 /* Depending on the speech codec type, pick a default codec
971 * configuration that exactly matches the configuration on the
972 * air interface. */
973 switch (sc->type) {
974 case GSM0808_SCT_FR3:
975 sc->cfg = GSM0808_SC_CFG_DEFAULT_FR_AMR;
976 break;
977 case GSM0808_SCT_FR4:
978 sc->cfg = GSM0808_SC_CFG_DEFAULT_OFR_AMR_WB;
979 break;
980 case GSM0808_SCT_FR5:
981 sc->cfg = GSM0808_SC_CFG_DEFAULT_FR_AMR_WB;
982 break;
983 case GSM0808_SCT_HR3:
984 sc->cfg = GSM0808_SC_CFG_DEFAULT_HR_AMR;
985 break;
986 case GSM0808_SCT_HR4:
987 sc->cfg = GSM0808_SC_CFG_DEFAULT_OHR_AMR_WB;
988 break;
989 case GSM0808_SCT_HR6:
990 sc->cfg = GSM0808_SC_CFG_DEFAULT_OHR_AMR;
991 break;
992 default:
993 /* Note: Not all codec types specify a default setting,
994 * in this case, we just set the field to zero. */
995 sc->cfg = 0;
996 }
997
998 /* Tag all codecs as "Full IP"
999 * (see als 3GPP TS 48.008 3.2.2.103) */
1000 sc->fi = true;
1001
1002 return 0;
1003}
1004
Harald Welte96e2a002017-06-12 21:44:18 +02001005/*! @} */