blob: e2cd91b443903538d4ad3353b3239f4aa59cd10f [file] [log] [blame]
Neels Hofmeyr17518fe2017-06-20 04:35:06 +02001/*! \file gsm0808_utils.c */
2/*
3 * (C) 2016 by Sysmocom s.f.m.c. GmbH
Philipp Maier22401432017-03-24 17:59:26 +01004 * All Rights Reserved
5 *
6 * Author: Philipp Maier
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU Affero General Public License as published by
10 * the Free Software Foundation; either version 3 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU Affero General Public License for more details.
17 *
18 * You should have received a copy of the GNU Affero General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 *
21 */
22
Harald Welte20725b92017-05-15 12:50:04 +020023#include "config.h"
24
Philipp Maier22401432017-03-24 17:59:26 +010025#include <osmocom/core/utils.h>
26#include <osmocom/core/msgb.h>
Harald Welte95871da2017-05-15 12:11:36 +020027#include <osmocom/core/byteswap.h>
Philipp Maier22401432017-03-24 17:59:26 +010028#include <string.h>
Philipp Maier22401432017-03-24 17:59:26 +010029#include <errno.h>
30#include <osmocom/gsm/protocol/gsm_08_08.h>
31
32#define IP_V4_ADDR_LEN 4
33#define IP_V6_ADDR_LEN 16
34#define IP_PORT_LEN 2
35
Philipp Maiere0c65302017-03-28 17:05:40 +020036#define CHANNEL_TYPE_ELEMENT_MAXLEN 11
37#define CHANNEL_TYPE_ELEMENT_MINLEN 3
Philipp Maier14e76b92017-03-28 18:36:52 +020038#define ENCRYPT_INFO_ELEMENT_MINLEN 1
Philipp Maier6f725d62017-03-24 18:03:17 +010039
Harald Welte20725b92017-05-15 12:50:04 +020040#ifdef HAVE_SYS_SOCKET_H
41
42#include <sys/socket.h>
43#include <netinet/in.h>
Harald Welte96e2a002017-06-12 21:44:18 +020044
45/*! \addtogroup gsm0808
46 * @{
47 */
48
Neels Hofmeyr87e45502017-06-20 00:17:59 +020049/*! Encode TS 08.08 AoIP transport address IE
Harald Welte96e2a002017-06-12 21:44:18 +020050 * \param[out] msg Message Buffer to which to append IE
51 * \param[in] ss Socket Address to be used in IE
52 * \returns number of bytes added to \a msg */
Philipp Maier22401432017-03-24 17:59:26 +010053uint8_t gsm0808_enc_aoip_trasp_addr(struct msgb *msg,
54 const struct sockaddr_storage *ss)
55{
56 /* See also 3GPP TS 48.008 3.2.2.102 AoIP Transport Layer Address */
57 struct sockaddr_in *sin;
58 struct sockaddr_in6 *sin6;
59 uint16_t port = 0;
60 uint8_t *ptr;
61 uint8_t *old_tail;
62 uint8_t *tlv_len;
63
64 OSMO_ASSERT(msg);
65 OSMO_ASSERT(ss);
66 OSMO_ASSERT(ss->ss_family == AF_INET || ss->ss_family == AF_INET6);
67
68 msgb_put_u8(msg, GSM0808_IE_AOIP_TRASP_ADDR);
69 tlv_len = msgb_put(msg,1);
70 old_tail = msg->tail;
71
72 switch (ss->ss_family) {
73 case AF_INET:
74 sin = (struct sockaddr_in *)ss;
Harald Welte95871da2017-05-15 12:11:36 +020075 port = osmo_ntohs(sin->sin_port);
Philipp Maier22401432017-03-24 17:59:26 +010076 ptr = msgb_put(msg, IP_V4_ADDR_LEN);
77 memcpy(ptr, &sin->sin_addr.s_addr, IP_V4_ADDR_LEN);
78 break;
79 case AF_INET6:
80 sin6 = (struct sockaddr_in6 *)ss;
Harald Welte95871da2017-05-15 12:11:36 +020081 port = osmo_ntohs(sin6->sin6_port);
Philipp Maier22401432017-03-24 17:59:26 +010082 ptr = msgb_put(msg, IP_V6_ADDR_LEN);
83 memcpy(ptr, sin6->sin6_addr.s6_addr, IP_V6_ADDR_LEN);
84 break;
85 }
86
87 msgb_put_u16(msg, port);
88
89 *tlv_len = (uint8_t) (msg->tail - old_tail);
90 return *tlv_len + 2;
91}
92
Neels Hofmeyr87e45502017-06-20 00:17:59 +020093/*! Decode TS 08.08 AoIP transport address IE
Harald Welte96e2a002017-06-12 21:44:18 +020094 * \param[out] ss Caller-provided memory where decoded socket addr is stored
95 * \param[in] elem pointer to IE value
96 * \param[in] len length of \a elem in bytes
97 * \returns number of bytes parsed */
Philipp Maier22401432017-03-24 17:59:26 +010098int gsm0808_dec_aoip_trasp_addr(struct sockaddr_storage *ss,
99 const uint8_t *elem, uint8_t len)
100{
101 /* See also 3GPP TS 48.008 3.2.2.102 AoIP Transport Layer Address */
102 struct sockaddr_in sin;
103 struct sockaddr_in6 sin6;
104 const uint8_t *old_elem = elem;
105
106 OSMO_ASSERT(ss);
107 if (!elem)
108 return -EINVAL;
Philipp Maier17778bd2017-04-28 11:05:44 +0200109 if (len == 0)
Philipp Maier22401432017-03-24 17:59:26 +0100110 return -EINVAL;
111
112 memset(ss, 0, sizeof(*ss));
113
114 switch (len) {
115 case IP_V4_ADDR_LEN + IP_PORT_LEN:
116 memset(&sin, 0, sizeof(sin));
117 sin.sin_family = AF_INET;
118
119 memcpy(&sin.sin_addr.s_addr, elem, IP_V4_ADDR_LEN);
120 elem += IP_V4_ADDR_LEN;
121 sin.sin_port = osmo_load16le(elem);
122 elem += IP_PORT_LEN;
123
124 memcpy(ss, &sin, sizeof(sin));
125 break;
126 case IP_V6_ADDR_LEN + IP_PORT_LEN:
127 memset(&sin6, 0, sizeof(sin6));
128 sin6.sin6_family = AF_INET6;
129
130 memcpy(sin6.sin6_addr.s6_addr, elem, IP_V6_ADDR_LEN);
131 elem += IP_V6_ADDR_LEN;
132 sin6.sin6_port = osmo_load16le(elem);
133 elem += IP_PORT_LEN;
134
135 memcpy(ss, &sin6, sizeof(sin6));
136 break;
137 default:
138 /* Malformed element! */
139 return -EINVAL;
140 break;
141 }
142
143 return (int)(elem - old_elem);
144}
Philipp Maier6f725d62017-03-24 18:03:17 +0100145
Harald Welte20725b92017-05-15 12:50:04 +0200146#endif /* HAVE_SYS_SOCKET_H */
147
Philipp Maier6f725d62017-03-24 18:03:17 +0100148/* Helper function for gsm0808_enc_speech_codec()
149 * and gsm0808_enc_speech_codec_list() */
150static uint8_t enc_speech_codec(struct msgb *msg,
151 const struct gsm0808_speech_codec *sc)
152{
153 /* See also 3GPP TS 48.008 3.2.2.103 Speech Codec List */
154 uint8_t header = 0;
155 uint8_t *old_tail;
Philipp Maierbb839662017-06-01 17:11:19 +0200156 bool type_extended;
157
158 /* Note: Extended codec types are codec types that require 8 instead
159 * of 4 bit to fully specify the selected codec. In the following,
160 * we check if we work with an extended type or not. We also check
161 * if the codec type is valid at all. */
162 switch(sc->type) {
163 case GSM0808_SCT_FR1:
164 case GSM0808_SCT_FR2:
165 case GSM0808_SCT_FR3:
166 case GSM0808_SCT_FR4:
167 case GSM0808_SCT_FR5:
168 case GSM0808_SCT_HR1:
169 case GSM0808_SCT_HR3:
170 case GSM0808_SCT_HR4:
171 case GSM0808_SCT_HR6:
172 type_extended = false;
173 break;
174 case GSM0808_SCT_CSD:
175 type_extended = true;
176 break;
177 default:
178 /* Invalid codec type specified */
179 OSMO_ASSERT(false);
180 break;
181 }
Philipp Maier6f725d62017-03-24 18:03:17 +0100182
183 old_tail = msg->tail;
184
185 if (sc->fi)
186 header |= (1 << 7);
187 if (sc->pi)
188 header |= (1 << 6);
189 if (sc->pt)
190 header |= (1 << 5);
191 if (sc->tf)
192 header |= (1 << 4);
Philipp Maierbb839662017-06-01 17:11:19 +0200193
194 if (type_extended) {
Philipp Maier6f725d62017-03-24 18:03:17 +0100195 header |= 0x0f;
196 msgb_put_u8(msg, header);
Philipp Maierbb839662017-06-01 17:11:19 +0200197 msgb_put_u8(msg, sc->type);
Philipp Maier6f725d62017-03-24 18:03:17 +0100198 } else {
199 OSMO_ASSERT(sc->type < 0x0f);
200 header |= sc->type;
201 msgb_put_u8(msg, header);
Philipp Maier6f725d62017-03-24 18:03:17 +0100202 }
203
Philipp Maierbb839662017-06-01 17:11:19 +0200204 /* Note: Whether a configuration is present or not depends on the
205 * selected codec type. If present, it can either consist of one
206 * or two octets, depending on the codec type */
207 switch (sc->type) {
208 case GSM0808_SCT_FR3:
209 case GSM0808_SCT_HR3:
210 case GSM0808_SCT_HR6:
Philipp Maier6f725d62017-03-24 18:03:17 +0100211 msgb_put_u16(msg, sc->cfg);
Philipp Maierbb839662017-06-01 17:11:19 +0200212 break;
213 case GSM0808_SCT_FR4:
214 case GSM0808_SCT_FR5:
215 case GSM0808_SCT_HR4:
216 case GSM0808_SCT_CSD:
217 OSMO_ASSERT((sc->cfg & 0xff00) == 0)
218 msgb_put_u8(msg, (uint8_t) sc->cfg & 0xff);
219 break;
220 default:
221 OSMO_ASSERT(sc->cfg == 0);
222 break;
223 }
Philipp Maier6f725d62017-03-24 18:03:17 +0100224
225 return (uint8_t) (msg->tail - old_tail);
226}
227
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200228/*! Encode TS 08.08 Speech Codec IE
Harald Welte96e2a002017-06-12 21:44:18 +0200229 * \param[out] msg Message Buffer to which IE will be appended
230 * \param[in] sc Speech Codec to be encoded into IE
231 * \returns number of bytes appended to \a msg */
Philipp Maier6f725d62017-03-24 18:03:17 +0100232uint8_t gsm0808_enc_speech_codec(struct msgb *msg,
233 const struct gsm0808_speech_codec *sc)
234{
Philipp Maier452a6bb2017-06-23 00:29:34 +0200235 /*! See also 3GPP TS 48.008 3.2.2.103 Speech Codec List */
Philipp Maier6f725d62017-03-24 18:03:17 +0100236 uint8_t *old_tail;
237 uint8_t *tlv_len;
238
239 OSMO_ASSERT(msg);
240 OSMO_ASSERT(sc);
241
242 msgb_put_u8(msg, GSM0808_IE_SPEECH_CODEC);
243 tlv_len = msgb_put(msg, 1);
244 old_tail = msg->tail;
245
246 enc_speech_codec(msg, sc);
247
248 *tlv_len = (uint8_t) (msg->tail - old_tail);
249 return *tlv_len + 2;
250}
251
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200252/*! Decode TS 08.08 Speech Codec IE
Harald Welte96e2a002017-06-12 21:44:18 +0200253 * \param[out] sc Caller-allocated memory for Speech Codec
254 * \param[in] elem IE value to be decoded
255 * \param[in] len Length of \a elem in bytes
256 * \returns number of bytes parsed; negative on error */
Philipp Maier6f725d62017-03-24 18:03:17 +0100257int gsm0808_dec_speech_codec(struct gsm0808_speech_codec *sc,
258 const uint8_t *elem, uint8_t len)
259{
260 /* See also 3GPP TS 48.008 3.2.2.103 Speech Codec List */
261 uint8_t header;
262 const uint8_t *old_elem = elem;
263
264 OSMO_ASSERT(sc);
265 if (!elem)
266 return -EINVAL;
Philipp Maier17778bd2017-04-28 11:05:44 +0200267 if (len == 0)
Philipp Maier6f725d62017-03-24 18:03:17 +0100268 return -EINVAL;
269
270 memset(sc, 0, sizeof(*sc));
271
272 header = *elem;
273
Philipp Maier85a6af22017-04-28 10:55:05 +0200274 /* An extended codec type needs at least two fields,
275 * bail if the input data length is not sufficient. */
Philipp Maier6f725d62017-03-24 18:03:17 +0100276 if ((header & 0x0F) == 0x0F && len < 2)
277 return -EINVAL;
Philipp Maier6f725d62017-03-24 18:03:17 +0100278
279 elem++;
280 len--;
281
282 if (header & (1 << 7))
283 sc->fi = true;
284 if (header & (1 << 6))
285 sc->pi = true;
286 if (header & (1 << 5))
287 sc->pt = true;
288 if (header & (1 << 4))
289 sc->tf = true;
290
291 if ((header & 0x0F) != 0x0F) {
292 sc->type = (header & 0x0F);
Philipp Maierbb839662017-06-01 17:11:19 +0200293 } else {
294 sc->type = *elem;
295 elem++;
296 len--;
Philipp Maier6f725d62017-03-24 18:03:17 +0100297 }
298
Philipp Maierbb839662017-06-01 17:11:19 +0200299 /* Note: Whether a configuration is present or not depends on the
300 * selected codec type. If present, it can either consist of one or
301 * two octets depending on the codec type */
302 switch (sc->type) {
303 case GSM0808_SCT_FR1:
304 case GSM0808_SCT_FR2:
305 case GSM0808_SCT_HR1:
306 break;
307 case GSM0808_SCT_HR4:
308 case GSM0808_SCT_CSD:
309 case GSM0808_SCT_FR4:
310 case GSM0808_SCT_FR5:
311 if (len < 1)
312 return -EINVAL;
313 sc->cfg = *elem;
314 elem++;
315 break;
316 case GSM0808_SCT_FR3:
317 case GSM0808_SCT_HR3:
318 case GSM0808_SCT_HR6:
319 if (len < 2)
320 return -EINVAL;
321 sc->cfg = osmo_load16be(elem);
322 elem += 2;
323 break;
324 default:
325 /* Invalid codec type => malformed speech codec element! */
326 return -EINVAL;
327 break;
328 }
Philipp Maier6f725d62017-03-24 18:03:17 +0100329
330 return (int)(elem - old_elem);
331}
332
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200333/*! Encode TS 08.08 Speech Codec list
Harald Welte96e2a002017-06-12 21:44:18 +0200334 * \param[out] msg Message Buffer to which IE is to be appended
335 * \param[in] scl Speech Codec List to be encoded into IE
336 * \returns number of bytes added to \a msg */
Philipp Maier6f725d62017-03-24 18:03:17 +0100337uint8_t gsm0808_enc_speech_codec_list(struct msgb *msg,
338 const struct gsm0808_speech_codec_list *scl)
339{
Philipp Maier452a6bb2017-06-23 00:29:34 +0200340 /*! See also 3GPP TS 48.008 3.2.2.103 Speech Codec List */
Philipp Maier6f725d62017-03-24 18:03:17 +0100341 uint8_t *old_tail;
342 uint8_t *tlv_len;
343 unsigned int i;
344 uint8_t rc;
345 unsigned int bytes_used = 0;
346
347 OSMO_ASSERT(msg);
348 OSMO_ASSERT(scl);
349
350 /* Empty list */
351 OSMO_ASSERT(scl->len >= 1);
352
353 msgb_put_u8(msg, GSM0808_IE_SPEECH_CODEC_LIST);
354 tlv_len = msgb_put(msg, 1);
355 old_tail = msg->tail;
356
357 for (i = 0; i < scl->len; i++) {
358 rc = enc_speech_codec(msg, &scl->codec[i]);
359 OSMO_ASSERT(rc >= 1);
360 bytes_used += rc;
361 OSMO_ASSERT(bytes_used <= 255);
362 }
363
364 *tlv_len = (uint8_t) (msg->tail - old_tail);
365 return *tlv_len + 2;
366}
367
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200368/*! Decode TS 08.08 Speech Codec list IE
Harald Welte96e2a002017-06-12 21:44:18 +0200369 * \param[out] scl Caller-provided memory to store codec list
370 * \param[in] elem IE value to be decoded
371 * \param[in] len Length of \a elem in bytes
372 * \returns number of bytes parsed; negative on error */
Philipp Maier6f725d62017-03-24 18:03:17 +0100373int gsm0808_dec_speech_codec_list(struct gsm0808_speech_codec_list *scl,
374 const uint8_t *elem, uint8_t len)
375{
Philipp Maier452a6bb2017-06-23 00:29:34 +0200376 /*! See also 3GPP TS 48.008 3.2.2.103 Speech Codec List */
Philipp Maier6f725d62017-03-24 18:03:17 +0100377 const uint8_t *old_elem = elem;
378 unsigned int i;
379 int rc;
380 uint8_t decoded = 0;
381
382 OSMO_ASSERT(scl);
383 if (!elem)
384 return -EINVAL;
Philipp Maier17778bd2017-04-28 11:05:44 +0200385 if (len == 0)
Philipp Maier6f725d62017-03-24 18:03:17 +0100386 return -EINVAL;
387
388 memset(scl, 0, sizeof(*scl));
389
390 for (i = 0; i < ARRAY_SIZE(scl->codec); i++) {
391 if (len <= 0)
392 break;
393
394 rc = gsm0808_dec_speech_codec(&scl->codec[i], elem, len);
395 if (rc < 1)
396 return -EINVAL;
397
398 elem+=rc;
399 len -= rc;
400 decoded++;
401 }
402
403 scl->len = decoded;
404
405 /* Empty list */
406 if (decoded < 1) {
407 return -EINVAL;
408 }
409
410 return (int)(elem - old_elem);
411}
Philipp Maiere0c65302017-03-28 17:05:40 +0200412
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200413/*! Encode TS 08.08 Channel Type IE
Harald Welte96e2a002017-06-12 21:44:18 +0200414 * \param[out] msg Message Buffer to which IE is to be appended
415 * \param[in] ct Channel Type to be encoded
416 * \returns number of bytes added to \a msg */
Philipp Maiere0c65302017-03-28 17:05:40 +0200417uint8_t gsm0808_enc_channel_type(struct msgb *msg,
418 const struct gsm0808_channel_type *ct)
419{
Philipp Maier452a6bb2017-06-23 00:29:34 +0200420 /*! See also 3GPP TS 48.008 3.2.2.11 Channel Type */
Philipp Maiere0c65302017-03-28 17:05:40 +0200421 unsigned int i;
422 uint8_t byte;
423 uint8_t *old_tail;
424 uint8_t *tlv_len;
425
426 OSMO_ASSERT(msg);
427 OSMO_ASSERT(ct);
428 OSMO_ASSERT(ct->perm_spch_len <= CHANNEL_TYPE_ELEMENT_MAXLEN - 2);
429
430 /* FIXME: Implement encoding support for Data
431 * and Speech + CTM Text Telephony */
432 if ((ct->ch_indctr & 0x0f) != GSM0808_CHAN_SPEECH
433 && (ct->ch_indctr & 0x0f) != GSM0808_CHAN_SIGN)
434 OSMO_ASSERT(false);
435
436 msgb_put_u8(msg, GSM0808_IE_CHANNEL_TYPE);
437 tlv_len = msgb_put(msg, 1);
438 old_tail = msg->tail;
439
440 msgb_put_u8(msg, ct->ch_indctr & 0x0f);
441 msgb_put_u8(msg, ct->ch_rate_type);
442
443 for (i = 0; i < ct->perm_spch_len; i++) {
444 byte = ct->perm_spch[i];
445
446 if (i < ct->perm_spch_len - 1)
447 byte |= 0x80;
448 msgb_put_u8(msg, byte);
449 }
450
451 *tlv_len = (uint8_t) (msg->tail - old_tail);
452 return *tlv_len + 2;
453}
454
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200455/*! Decode TS 08.08 Channel Type IE
Harald Welte96e2a002017-06-12 21:44:18 +0200456 * \param[out] ct Caller-provided memory to store channel type
457 * \param[in] elem IE Value to be decoded
458 * \param[in] len Length of \a elem in bytes
459 * \returns number of bytes parsed; negative on error */
Philipp Maiere0c65302017-03-28 17:05:40 +0200460int gsm0808_dec_channel_type(struct gsm0808_channel_type *ct,
461 const uint8_t *elem, uint8_t len)
462{
Philipp Maier452a6bb2017-06-23 00:29:34 +0200463 /*! See also 3GPP TS 48.008 3.2.2.11 Channel Type */
Philipp Maiere0c65302017-03-28 17:05:40 +0200464 unsigned int i;
465 uint8_t byte;
466 const uint8_t *old_elem = elem;
467
468 OSMO_ASSERT(ct);
469 if (!elem)
470 return -EINVAL;
Philipp Maier17778bd2017-04-28 11:05:44 +0200471 if (len < 3 || len > 11)
Philipp Maiere0c65302017-03-28 17:05:40 +0200472 return -EINVAL;
473
474 memset(ct, 0, sizeof(*ct));
475
476 ct->ch_indctr = (*elem) & 0x0f;
477 elem++;
478 ct->ch_rate_type = (*elem) & 0x0f;
479 elem++;
480
481 for (i = 0; i < ARRAY_SIZE(ct->perm_spch); i++) {
482 byte = *elem;
483 elem++;
484 ct->perm_spch[i] = byte & 0x7f;
485 if ((byte & 0x80) == 0x00)
486 break;
487 }
488 ct->perm_spch_len = i + 1;
489
490 return (int)(elem - old_elem);
491}
Philipp Maier14e76b92017-03-28 18:36:52 +0200492
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200493/*! Encode TS 08.08 Encryption Information IE
Harald Welte96e2a002017-06-12 21:44:18 +0200494 * \param[out] msg Message Buffer to which IE is to be appended
495 * \param[in] ei Encryption Information to be encoded
496 * \returns number of bytes appended to \a msg */
Philipp Maier14e76b92017-03-28 18:36:52 +0200497uint8_t gsm0808_enc_encrypt_info(struct msgb *msg,
498 const struct gsm0808_encrypt_info *ei)
499{
500 unsigned int i;
501 uint8_t perm_algo = 0;
502 uint8_t *ptr;
503 uint8_t *old_tail;
504 uint8_t *tlv_len;
505
506 OSMO_ASSERT(msg);
507 OSMO_ASSERT(ei);
508 OSMO_ASSERT(ei->key_len <= ARRAY_SIZE(ei->key));
509 OSMO_ASSERT(ei->perm_algo_len <= ENCRY_INFO_PERM_ALGO_MAXLEN);
510
511 msgb_put_u8(msg, GSM0808_IE_ENCRYPTION_INFORMATION);
512 tlv_len = msgb_put(msg, 1);
513 old_tail = msg->tail;
514
515 for (i = 0; i < ei->perm_algo_len; i++) {
516 /* Note: gsm_08_08.h defines the permitted algorithms
517 * as an enum which ranges from 0x01 to 0x08 */
518 OSMO_ASSERT(ei->perm_algo[i] != 0);
519 OSMO_ASSERT(ei->perm_algo[i] <= ENCRY_INFO_PERM_ALGO_MAXLEN);
520 perm_algo |= (1 << (ei->perm_algo[i] - 1));
521 }
522
523 msgb_put_u8(msg, perm_algo);
524 ptr = msgb_put(msg, ei->key_len);
525 memcpy(ptr, ei->key, ei->key_len);
526
527 *tlv_len = (uint8_t) (msg->tail - old_tail);
528 return *tlv_len + 2;
529}
530
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200531/*! Decode TS 08.08 Encryption Information IE
Harald Welte96e2a002017-06-12 21:44:18 +0200532 * \param[out] ei Caller-provided memory to store encryption information
533 * \param[in] elem IE value to be decoded
534 * \param[in] len Length of \a elem in bytes
535 * \returns number of bytes parsed; negative on error */
Philipp Maier14e76b92017-03-28 18:36:52 +0200536int gsm0808_dec_encrypt_info(struct gsm0808_encrypt_info *ei,
537 const uint8_t *elem, uint8_t len)
538{
539 uint8_t perm_algo;
540 unsigned int i;
541 unsigned int perm_algo_len = 0;
542 const uint8_t *old_elem = elem;
543
544 OSMO_ASSERT(ei);
545 if (!elem)
546 return -EINVAL;
Philipp Maier17778bd2017-04-28 11:05:44 +0200547 if (len == 0)
Philipp Maier14e76b92017-03-28 18:36:52 +0200548 return -EINVAL;
549
550 memset(ei, 0, sizeof(*ei));
551
552 perm_algo = *elem;
553 elem++;
554
555 for (i = 0; i < ENCRY_INFO_PERM_ALGO_MAXLEN; i++) {
556 if (perm_algo & (1 << i)) {
557 ei->perm_algo[perm_algo_len] = i + 1;
558 perm_algo_len++;
559 }
560 }
561 ei->perm_algo_len = perm_algo_len;
562
563 ei->key_len = len - 1;
564 memcpy(ei->key, elem, ei->key_len);
565 elem+=ei->key_len;
566
567 return (int)(elem - old_elem);
568}
Philipp Maier783047e2017-03-29 11:35:50 +0200569
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200570/*! Encode TS 08.08 Cell Identifier List IE
Harald Welte96e2a002017-06-12 21:44:18 +0200571 * \param[out] msg Message Buffer to which IE is to be appended
572 * \param[in] cil Cell ID List to be encoded
573 * \returns number of bytes appended to \a msg */
Philipp Maier783047e2017-03-29 11:35:50 +0200574uint8_t gsm0808_enc_cell_id_list(struct msgb *msg,
575 const struct gsm0808_cell_id_list *cil)
576{
577 uint8_t *old_tail;
578 uint8_t *tlv_len;
579 unsigned int i;
580
581 OSMO_ASSERT(msg);
582 OSMO_ASSERT(cil);
583
584 msgb_put_u8(msg, GSM0808_IE_CELL_IDENTIFIER_LIST);
585 tlv_len = msgb_put(msg, 1);
586 old_tail = msg->tail;
587
588 msgb_put_u8(msg, cil->id_discr & 0x0f);
589
590 switch (cil->id_discr) {
591 case CELL_IDENT_LAC:
592 OSMO_ASSERT(cil->id_list_len <= CELL_ID_LIST_LAC_MAXLEN)
593 for (i=0;i<cil->id_list_len;i++) {
594 msgb_put_u16(msg, cil->id_list_lac[i]);
595 }
596 break;
597 case CELL_IDENT_BSS:
598 /* Does not have any list items */
599 break;
600 default:
601 /* FIXME: Implement support for all identifier list elements */
602 OSMO_ASSERT(false);
603 }
604
605 *tlv_len = (uint8_t) (msg->tail - old_tail);
606 return *tlv_len + 2;
607}
608
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200609/*! Decode Cell Identifier List IE
Harald Welte96e2a002017-06-12 21:44:18 +0200610 * \param[out] cil Caller-provided memory to store Cell ID list
611 * \param[in] elem IE value to be decoded
612 * \param[in] len Length of \a elem in bytes
613 * \returns number of bytes parsed; negative on error */
Philipp Maier783047e2017-03-29 11:35:50 +0200614int gsm0808_dec_cell_id_list(struct gsm0808_cell_id_list *cil,
615 const uint8_t *elem, uint8_t len)
616{
617 uint8_t id_discr;
618 const uint8_t *old_elem = elem;
619 unsigned int item_count = 0;
620
621 OSMO_ASSERT(cil);
622 if (!elem)
623 return -EINVAL;
Philipp Maier17778bd2017-04-28 11:05:44 +0200624 if (len == 0)
Philipp Maier783047e2017-03-29 11:35:50 +0200625 return -EINVAL;
626
627 memset(cil, 0, sizeof(*cil));
628
629 id_discr = *elem & 0x0f;
630 elem++;
631 len--;
632
633 cil->id_discr = id_discr;
634
635 switch (id_discr) {
636 case CELL_IDENT_LAC:
637 while (len >= 2) {
638 cil->id_list_lac[item_count] = osmo_load16be(elem);
639 elem += 2;
640 item_count++;
641 len -= 2;
642 }
643 case CELL_IDENT_BSS:
644 /* Does not have any list items */
645 break;
646 default:
647 /* FIXME: Implement support for all identifier list elements */
648 return -EINVAL;
649 }
650
651 cil->id_list_len = item_count;
652 return (int)(elem - old_elem);
653}
Harald Welte96e2a002017-06-12 21:44:18 +0200654
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200655/*! Convert the representation of the permitted speech codec identifier
Philipp Maier3149b0d2017-06-02 13:22:34 +0200656 * that is used in struct gsm0808_channel_type to the speech codec
657 * representation we use in struct gsm0808_speech_codec.
658 * \param[in] perm_spch to be converted (see also gsm0808_permitted_speech)
659 * \returns GSM speech codec type; negative on error */
660int gsm0808_chan_type_to_speech_codec(uint8_t perm_spch)
661{
662 /*! The speech codec type, which is used in the channel type field to
663 * signal the permitted speech versions (codecs) has a different
664 * encoding than the type field in the speech codec type element
665 * (See also 3GPP TS 48.008, 3.2.2.11 and 3.2.2.103) */
666
667 switch (perm_spch) {
668 case GSM0808_PERM_FR1:
669 return GSM0808_SCT_FR1;
670 case GSM0808_PERM_FR2:
671 return GSM0808_SCT_FR2;
672 case GSM0808_PERM_FR3:
673 return GSM0808_SCT_FR3;
674 case GSM0808_PERM_FR4:
675 return GSM0808_SCT_FR4;
676 case GSM0808_PERM_FR5:
677 return GSM0808_SCT_FR5;
678 case GSM0808_PERM_HR1:
679 return GSM0808_SCT_HR1;
680 case GSM0808_PERM_HR3:
681 return GSM0808_SCT_HR3;
682 case GSM0808_PERM_HR4:
683 return GSM0808_SCT_HR4;
684 case GSM0808_PERM_HR6:
685 return GSM0808_SCT_HR6;
686 }
687
688 /* Invalid input */
689 return -EINVAL;
690}
691
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200692/*! Extrapolate a speech codec field from a given permitted speech
Philipp Maier884ba0f2017-06-02 13:49:16 +0200693 * parameter (channel type).
694 * \param[out] sc Caller provided memory to store the resulting speech codec
695 * \param[in] perm_spch value that is used to derive the speech codec info
696 * (see also: enum gsm0808_speech_codec_type in gsm0808_utils.h)
697 * \returns zero when successful; negative on error */
698int gsm0808_speech_codec_from_chan_type(struct gsm0808_speech_codec *sc,
699 uint8_t perm_spch)
700{
701 int rc;
702
703 memset(sc, 0, sizeof(*sc));
704
705 /* Determine codec type */
706 rc = gsm0808_chan_type_to_speech_codec(perm_spch);
707 if (rc < 0)
708 return -EINVAL;
709 sc->type = (uint8_t) rc;
710
711 /* Depending on the speech codec type, pick a default codec
712 * configuration that exactly matches the configuration on the
713 * air interface. */
714 switch (sc->type) {
715 case GSM0808_SCT_FR3:
716 sc->cfg = GSM0808_SC_CFG_DEFAULT_FR_AMR;
717 break;
718 case GSM0808_SCT_FR4:
719 sc->cfg = GSM0808_SC_CFG_DEFAULT_OFR_AMR_WB;
720 break;
721 case GSM0808_SCT_FR5:
722 sc->cfg = GSM0808_SC_CFG_DEFAULT_FR_AMR_WB;
723 break;
724 case GSM0808_SCT_HR3:
725 sc->cfg = GSM0808_SC_CFG_DEFAULT_HR_AMR;
726 break;
727 case GSM0808_SCT_HR4:
728 sc->cfg = GSM0808_SC_CFG_DEFAULT_OHR_AMR_WB;
729 break;
730 case GSM0808_SCT_HR6:
731 sc->cfg = GSM0808_SC_CFG_DEFAULT_OHR_AMR;
732 break;
733 default:
734 /* Note: Not all codec types specify a default setting,
735 * in this case, we just set the field to zero. */
736 sc->cfg = 0;
737 }
738
739 /* Tag all codecs as "Full IP"
740 * (see als 3GPP TS 48.008 3.2.2.103) */
741 sc->fi = true;
742
743 return 0;
744}
745
Harald Welte96e2a002017-06-12 21:44:18 +0200746/*! @} */