blob: 34e10bbcf3f982eefde04e47f8fc3e78fdb8c5ee [file] [log] [blame]
Philipp Maier22401432017-03-24 17:59:26 +01001/* (C) 2016 by Sysmocom s.f.m.c. GmbH
2 * All Rights Reserved
3 *
4 * Author: Philipp Maier
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU Affero General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Affero General Public License for more details.
15 *
16 * You should have received a copy of the GNU Affero General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 *
19 */
20
Harald Welte20725b92017-05-15 12:50:04 +020021#include "config.h"
22
Philipp Maier22401432017-03-24 17:59:26 +010023#include <osmocom/core/utils.h>
24#include <osmocom/core/msgb.h>
Harald Welte95871da2017-05-15 12:11:36 +020025#include <osmocom/core/byteswap.h>
Philipp Maier22401432017-03-24 17:59:26 +010026#include <string.h>
Philipp Maier22401432017-03-24 17:59:26 +010027#include <errno.h>
28#include <osmocom/gsm/protocol/gsm_08_08.h>
29
30#define IP_V4_ADDR_LEN 4
31#define IP_V6_ADDR_LEN 16
32#define IP_PORT_LEN 2
33
Philipp Maiere0c65302017-03-28 17:05:40 +020034#define CHANNEL_TYPE_ELEMENT_MAXLEN 11
35#define CHANNEL_TYPE_ELEMENT_MINLEN 3
Philipp Maier14e76b92017-03-28 18:36:52 +020036#define ENCRYPT_INFO_ELEMENT_MINLEN 1
Philipp Maier6f725d62017-03-24 18:03:17 +010037
Harald Welte20725b92017-05-15 12:50:04 +020038#ifdef HAVE_SYS_SOCKET_H
39
40#include <sys/socket.h>
41#include <netinet/in.h>
Harald Welte96e2a002017-06-12 21:44:18 +020042
43/*! \addtogroup gsm0808
44 * @{
45 */
46
Neels Hofmeyr87e45502017-06-20 00:17:59 +020047/*! Encode TS 08.08 AoIP transport address IE
Harald Welte96e2a002017-06-12 21:44:18 +020048 * \param[out] msg Message Buffer to which to append IE
49 * \param[in] ss Socket Address to be used in IE
50 * \returns number of bytes added to \a msg */
Philipp Maier22401432017-03-24 17:59:26 +010051uint8_t gsm0808_enc_aoip_trasp_addr(struct msgb *msg,
52 const struct sockaddr_storage *ss)
53{
54 /* See also 3GPP TS 48.008 3.2.2.102 AoIP Transport Layer Address */
55 struct sockaddr_in *sin;
56 struct sockaddr_in6 *sin6;
57 uint16_t port = 0;
58 uint8_t *ptr;
59 uint8_t *old_tail;
60 uint8_t *tlv_len;
61
62 OSMO_ASSERT(msg);
63 OSMO_ASSERT(ss);
64 OSMO_ASSERT(ss->ss_family == AF_INET || ss->ss_family == AF_INET6);
65
66 msgb_put_u8(msg, GSM0808_IE_AOIP_TRASP_ADDR);
67 tlv_len = msgb_put(msg,1);
68 old_tail = msg->tail;
69
70 switch (ss->ss_family) {
71 case AF_INET:
72 sin = (struct sockaddr_in *)ss;
Harald Welte95871da2017-05-15 12:11:36 +020073 port = osmo_ntohs(sin->sin_port);
Philipp Maier22401432017-03-24 17:59:26 +010074 ptr = msgb_put(msg, IP_V4_ADDR_LEN);
75 memcpy(ptr, &sin->sin_addr.s_addr, IP_V4_ADDR_LEN);
76 break;
77 case AF_INET6:
78 sin6 = (struct sockaddr_in6 *)ss;
Harald Welte95871da2017-05-15 12:11:36 +020079 port = osmo_ntohs(sin6->sin6_port);
Philipp Maier22401432017-03-24 17:59:26 +010080 ptr = msgb_put(msg, IP_V6_ADDR_LEN);
81 memcpy(ptr, sin6->sin6_addr.s6_addr, IP_V6_ADDR_LEN);
82 break;
83 }
84
85 msgb_put_u16(msg, port);
86
87 *tlv_len = (uint8_t) (msg->tail - old_tail);
88 return *tlv_len + 2;
89}
90
Neels Hofmeyr87e45502017-06-20 00:17:59 +020091/*! Decode TS 08.08 AoIP transport address IE
Harald Welte96e2a002017-06-12 21:44:18 +020092 * \param[out] ss Caller-provided memory where decoded socket addr is stored
93 * \param[in] elem pointer to IE value
94 * \param[in] len length of \a elem in bytes
95 * \returns number of bytes parsed */
Philipp Maier22401432017-03-24 17:59:26 +010096int gsm0808_dec_aoip_trasp_addr(struct sockaddr_storage *ss,
97 const uint8_t *elem, uint8_t len)
98{
99 /* See also 3GPP TS 48.008 3.2.2.102 AoIP Transport Layer Address */
100 struct sockaddr_in sin;
101 struct sockaddr_in6 sin6;
102 const uint8_t *old_elem = elem;
103
104 OSMO_ASSERT(ss);
105 if (!elem)
106 return -EINVAL;
Philipp Maier17778bd2017-04-28 11:05:44 +0200107 if (len == 0)
Philipp Maier22401432017-03-24 17:59:26 +0100108 return -EINVAL;
109
110 memset(ss, 0, sizeof(*ss));
111
112 switch (len) {
113 case IP_V4_ADDR_LEN + IP_PORT_LEN:
114 memset(&sin, 0, sizeof(sin));
115 sin.sin_family = AF_INET;
116
117 memcpy(&sin.sin_addr.s_addr, elem, IP_V4_ADDR_LEN);
118 elem += IP_V4_ADDR_LEN;
119 sin.sin_port = osmo_load16le(elem);
120 elem += IP_PORT_LEN;
121
122 memcpy(ss, &sin, sizeof(sin));
123 break;
124 case IP_V6_ADDR_LEN + IP_PORT_LEN:
125 memset(&sin6, 0, sizeof(sin6));
126 sin6.sin6_family = AF_INET6;
127
128 memcpy(sin6.sin6_addr.s6_addr, elem, IP_V6_ADDR_LEN);
129 elem += IP_V6_ADDR_LEN;
130 sin6.sin6_port = osmo_load16le(elem);
131 elem += IP_PORT_LEN;
132
133 memcpy(ss, &sin6, sizeof(sin6));
134 break;
135 default:
136 /* Malformed element! */
137 return -EINVAL;
138 break;
139 }
140
141 return (int)(elem - old_elem);
142}
Philipp Maier6f725d62017-03-24 18:03:17 +0100143
Harald Welte20725b92017-05-15 12:50:04 +0200144#endif /* HAVE_SYS_SOCKET_H */
145
Philipp Maier6f725d62017-03-24 18:03:17 +0100146/* Helper function for gsm0808_enc_speech_codec()
147 * and gsm0808_enc_speech_codec_list() */
148static uint8_t enc_speech_codec(struct msgb *msg,
149 const struct gsm0808_speech_codec *sc)
150{
151 /* See also 3GPP TS 48.008 3.2.2.103 Speech Codec List */
152 uint8_t header = 0;
153 uint8_t *old_tail;
Philipp Maierbb839662017-06-01 17:11:19 +0200154 bool type_extended;
155
156 /* Note: Extended codec types are codec types that require 8 instead
157 * of 4 bit to fully specify the selected codec. In the following,
158 * we check if we work with an extended type or not. We also check
159 * if the codec type is valid at all. */
160 switch(sc->type) {
161 case GSM0808_SCT_FR1:
162 case GSM0808_SCT_FR2:
163 case GSM0808_SCT_FR3:
164 case GSM0808_SCT_FR4:
165 case GSM0808_SCT_FR5:
166 case GSM0808_SCT_HR1:
167 case GSM0808_SCT_HR3:
168 case GSM0808_SCT_HR4:
169 case GSM0808_SCT_HR6:
170 type_extended = false;
171 break;
172 case GSM0808_SCT_CSD:
173 type_extended = true;
174 break;
175 default:
176 /* Invalid codec type specified */
177 OSMO_ASSERT(false);
178 break;
179 }
Philipp Maier6f725d62017-03-24 18:03:17 +0100180
181 old_tail = msg->tail;
182
183 if (sc->fi)
184 header |= (1 << 7);
185 if (sc->pi)
186 header |= (1 << 6);
187 if (sc->pt)
188 header |= (1 << 5);
189 if (sc->tf)
190 header |= (1 << 4);
Philipp Maierbb839662017-06-01 17:11:19 +0200191
192 if (type_extended) {
Philipp Maier6f725d62017-03-24 18:03:17 +0100193 header |= 0x0f;
194 msgb_put_u8(msg, header);
Philipp Maierbb839662017-06-01 17:11:19 +0200195 msgb_put_u8(msg, sc->type);
Philipp Maier6f725d62017-03-24 18:03:17 +0100196 } else {
197 OSMO_ASSERT(sc->type < 0x0f);
198 header |= sc->type;
199 msgb_put_u8(msg, header);
Philipp Maier6f725d62017-03-24 18:03:17 +0100200 }
201
Philipp Maierbb839662017-06-01 17:11:19 +0200202 /* Note: Whether a configuration is present or not depends on the
203 * selected codec type. If present, it can either consist of one
204 * or two octets, depending on the codec type */
205 switch (sc->type) {
206 case GSM0808_SCT_FR3:
207 case GSM0808_SCT_HR3:
208 case GSM0808_SCT_HR6:
Philipp Maier6f725d62017-03-24 18:03:17 +0100209 msgb_put_u16(msg, sc->cfg);
Philipp Maierbb839662017-06-01 17:11:19 +0200210 break;
211 case GSM0808_SCT_FR4:
212 case GSM0808_SCT_FR5:
213 case GSM0808_SCT_HR4:
214 case GSM0808_SCT_CSD:
215 OSMO_ASSERT((sc->cfg & 0xff00) == 0)
216 msgb_put_u8(msg, (uint8_t) sc->cfg & 0xff);
217 break;
218 default:
219 OSMO_ASSERT(sc->cfg == 0);
220 break;
221 }
Philipp Maier6f725d62017-03-24 18:03:17 +0100222
223 return (uint8_t) (msg->tail - old_tail);
224}
225
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200226/*! Encode TS 08.08 Speech Codec IE
Harald Welte96e2a002017-06-12 21:44:18 +0200227 * \param[out] msg Message Buffer to which IE will be appended
228 * \param[in] sc Speech Codec to be encoded into IE
229 * \returns number of bytes appended to \a msg */
Philipp Maier6f725d62017-03-24 18:03:17 +0100230uint8_t gsm0808_enc_speech_codec(struct msgb *msg,
231 const struct gsm0808_speech_codec *sc)
232{
Philipp Maier452a6bb2017-06-23 00:29:34 +0200233 /*! See also 3GPP TS 48.008 3.2.2.103 Speech Codec List */
Philipp Maier6f725d62017-03-24 18:03:17 +0100234 uint8_t *old_tail;
235 uint8_t *tlv_len;
236
237 OSMO_ASSERT(msg);
238 OSMO_ASSERT(sc);
239
240 msgb_put_u8(msg, GSM0808_IE_SPEECH_CODEC);
241 tlv_len = msgb_put(msg, 1);
242 old_tail = msg->tail;
243
244 enc_speech_codec(msg, sc);
245
246 *tlv_len = (uint8_t) (msg->tail - old_tail);
247 return *tlv_len + 2;
248}
249
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200250/*! Decode TS 08.08 Speech Codec IE
Harald Welte96e2a002017-06-12 21:44:18 +0200251 * \param[out] sc Caller-allocated memory for Speech Codec
252 * \param[in] elem IE value to be decoded
253 * \param[in] len Length of \a elem in bytes
254 * \returns number of bytes parsed; negative on error */
Philipp Maier6f725d62017-03-24 18:03:17 +0100255int gsm0808_dec_speech_codec(struct gsm0808_speech_codec *sc,
256 const uint8_t *elem, uint8_t len)
257{
258 /* See also 3GPP TS 48.008 3.2.2.103 Speech Codec List */
259 uint8_t header;
260 const uint8_t *old_elem = elem;
261
262 OSMO_ASSERT(sc);
263 if (!elem)
264 return -EINVAL;
Philipp Maier17778bd2017-04-28 11:05:44 +0200265 if (len == 0)
Philipp Maier6f725d62017-03-24 18:03:17 +0100266 return -EINVAL;
267
268 memset(sc, 0, sizeof(*sc));
269
270 header = *elem;
271
Philipp Maier85a6af22017-04-28 10:55:05 +0200272 /* An extended codec type needs at least two fields,
273 * bail if the input data length is not sufficient. */
Philipp Maier6f725d62017-03-24 18:03:17 +0100274 if ((header & 0x0F) == 0x0F && len < 2)
275 return -EINVAL;
Philipp Maier6f725d62017-03-24 18:03:17 +0100276
277 elem++;
278 len--;
279
280 if (header & (1 << 7))
281 sc->fi = true;
282 if (header & (1 << 6))
283 sc->pi = true;
284 if (header & (1 << 5))
285 sc->pt = true;
286 if (header & (1 << 4))
287 sc->tf = true;
288
289 if ((header & 0x0F) != 0x0F) {
290 sc->type = (header & 0x0F);
Philipp Maierbb839662017-06-01 17:11:19 +0200291 } else {
292 sc->type = *elem;
293 elem++;
294 len--;
Philipp Maier6f725d62017-03-24 18:03:17 +0100295 }
296
Philipp Maierbb839662017-06-01 17:11:19 +0200297 /* Note: Whether a configuration is present or not depends on the
298 * selected codec type. If present, it can either consist of one or
299 * two octets depending on the codec type */
300 switch (sc->type) {
301 case GSM0808_SCT_FR1:
302 case GSM0808_SCT_FR2:
303 case GSM0808_SCT_HR1:
304 break;
305 case GSM0808_SCT_HR4:
306 case GSM0808_SCT_CSD:
307 case GSM0808_SCT_FR4:
308 case GSM0808_SCT_FR5:
309 if (len < 1)
310 return -EINVAL;
311 sc->cfg = *elem;
312 elem++;
313 break;
314 case GSM0808_SCT_FR3:
315 case GSM0808_SCT_HR3:
316 case GSM0808_SCT_HR6:
317 if (len < 2)
318 return -EINVAL;
319 sc->cfg = osmo_load16be(elem);
320 elem += 2;
321 break;
322 default:
323 /* Invalid codec type => malformed speech codec element! */
324 return -EINVAL;
325 break;
326 }
Philipp Maier6f725d62017-03-24 18:03:17 +0100327
328 return (int)(elem - old_elem);
329}
330
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200331/*! Encode TS 08.08 Speech Codec list
Harald Welte96e2a002017-06-12 21:44:18 +0200332 * \param[out] msg Message Buffer to which IE is to be appended
333 * \param[in] scl Speech Codec List to be encoded into IE
334 * \returns number of bytes added to \a msg */
Philipp Maier6f725d62017-03-24 18:03:17 +0100335uint8_t gsm0808_enc_speech_codec_list(struct msgb *msg,
336 const struct gsm0808_speech_codec_list *scl)
337{
Philipp Maier452a6bb2017-06-23 00:29:34 +0200338 /*! See also 3GPP TS 48.008 3.2.2.103 Speech Codec List */
Philipp Maier6f725d62017-03-24 18:03:17 +0100339 uint8_t *old_tail;
340 uint8_t *tlv_len;
341 unsigned int i;
342 uint8_t rc;
343 unsigned int bytes_used = 0;
344
345 OSMO_ASSERT(msg);
346 OSMO_ASSERT(scl);
347
348 /* Empty list */
349 OSMO_ASSERT(scl->len >= 1);
350
351 msgb_put_u8(msg, GSM0808_IE_SPEECH_CODEC_LIST);
352 tlv_len = msgb_put(msg, 1);
353 old_tail = msg->tail;
354
355 for (i = 0; i < scl->len; i++) {
356 rc = enc_speech_codec(msg, &scl->codec[i]);
357 OSMO_ASSERT(rc >= 1);
358 bytes_used += rc;
359 OSMO_ASSERT(bytes_used <= 255);
360 }
361
362 *tlv_len = (uint8_t) (msg->tail - old_tail);
363 return *tlv_len + 2;
364}
365
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200366/*! Decode TS 08.08 Speech Codec list IE
Harald Welte96e2a002017-06-12 21:44:18 +0200367 * \param[out] scl Caller-provided memory to store codec list
368 * \param[in] elem IE value to be decoded
369 * \param[in] len Length of \a elem in bytes
370 * \returns number of bytes parsed; negative on error */
Philipp Maier6f725d62017-03-24 18:03:17 +0100371int gsm0808_dec_speech_codec_list(struct gsm0808_speech_codec_list *scl,
372 const uint8_t *elem, uint8_t len)
373{
Philipp Maier452a6bb2017-06-23 00:29:34 +0200374 /*! See also 3GPP TS 48.008 3.2.2.103 Speech Codec List */
Philipp Maier6f725d62017-03-24 18:03:17 +0100375 const uint8_t *old_elem = elem;
376 unsigned int i;
377 int rc;
378 uint8_t decoded = 0;
379
380 OSMO_ASSERT(scl);
381 if (!elem)
382 return -EINVAL;
Philipp Maier17778bd2017-04-28 11:05:44 +0200383 if (len == 0)
Philipp Maier6f725d62017-03-24 18:03:17 +0100384 return -EINVAL;
385
386 memset(scl, 0, sizeof(*scl));
387
388 for (i = 0; i < ARRAY_SIZE(scl->codec); i++) {
389 if (len <= 0)
390 break;
391
392 rc = gsm0808_dec_speech_codec(&scl->codec[i], elem, len);
393 if (rc < 1)
394 return -EINVAL;
395
396 elem+=rc;
397 len -= rc;
398 decoded++;
399 }
400
401 scl->len = decoded;
402
403 /* Empty list */
404 if (decoded < 1) {
405 return -EINVAL;
406 }
407
408 return (int)(elem - old_elem);
409}
Philipp Maiere0c65302017-03-28 17:05:40 +0200410
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200411/*! Encode TS 08.08 Channel Type IE
Harald Welte96e2a002017-06-12 21:44:18 +0200412 * \param[out] msg Message Buffer to which IE is to be appended
413 * \param[in] ct Channel Type to be encoded
414 * \returns number of bytes added to \a msg */
Philipp Maiere0c65302017-03-28 17:05:40 +0200415uint8_t gsm0808_enc_channel_type(struct msgb *msg,
416 const struct gsm0808_channel_type *ct)
417{
Philipp Maier452a6bb2017-06-23 00:29:34 +0200418 /*! See also 3GPP TS 48.008 3.2.2.11 Channel Type */
Philipp Maiere0c65302017-03-28 17:05:40 +0200419 unsigned int i;
420 uint8_t byte;
421 uint8_t *old_tail;
422 uint8_t *tlv_len;
423
424 OSMO_ASSERT(msg);
425 OSMO_ASSERT(ct);
426 OSMO_ASSERT(ct->perm_spch_len <= CHANNEL_TYPE_ELEMENT_MAXLEN - 2);
427
428 /* FIXME: Implement encoding support for Data
429 * and Speech + CTM Text Telephony */
430 if ((ct->ch_indctr & 0x0f) != GSM0808_CHAN_SPEECH
431 && (ct->ch_indctr & 0x0f) != GSM0808_CHAN_SIGN)
432 OSMO_ASSERT(false);
433
434 msgb_put_u8(msg, GSM0808_IE_CHANNEL_TYPE);
435 tlv_len = msgb_put(msg, 1);
436 old_tail = msg->tail;
437
438 msgb_put_u8(msg, ct->ch_indctr & 0x0f);
439 msgb_put_u8(msg, ct->ch_rate_type);
440
441 for (i = 0; i < ct->perm_spch_len; i++) {
442 byte = ct->perm_spch[i];
443
444 if (i < ct->perm_spch_len - 1)
445 byte |= 0x80;
446 msgb_put_u8(msg, byte);
447 }
448
449 *tlv_len = (uint8_t) (msg->tail - old_tail);
450 return *tlv_len + 2;
451}
452
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200453/*! Decode TS 08.08 Channel Type IE
Harald Welte96e2a002017-06-12 21:44:18 +0200454 * \param[out] ct Caller-provided memory to store channel type
455 * \param[in] elem IE Value to be decoded
456 * \param[in] len Length of \a elem in bytes
457 * \returns number of bytes parsed; negative on error */
Philipp Maiere0c65302017-03-28 17:05:40 +0200458int gsm0808_dec_channel_type(struct gsm0808_channel_type *ct,
459 const uint8_t *elem, uint8_t len)
460{
Philipp Maier452a6bb2017-06-23 00:29:34 +0200461 /*! See also 3GPP TS 48.008 3.2.2.11 Channel Type */
Philipp Maiere0c65302017-03-28 17:05:40 +0200462 unsigned int i;
463 uint8_t byte;
464 const uint8_t *old_elem = elem;
465
466 OSMO_ASSERT(ct);
467 if (!elem)
468 return -EINVAL;
Philipp Maier17778bd2017-04-28 11:05:44 +0200469 if (len < 3 || len > 11)
Philipp Maiere0c65302017-03-28 17:05:40 +0200470 return -EINVAL;
471
472 memset(ct, 0, sizeof(*ct));
473
474 ct->ch_indctr = (*elem) & 0x0f;
475 elem++;
476 ct->ch_rate_type = (*elem) & 0x0f;
477 elem++;
478
479 for (i = 0; i < ARRAY_SIZE(ct->perm_spch); i++) {
480 byte = *elem;
481 elem++;
482 ct->perm_spch[i] = byte & 0x7f;
483 if ((byte & 0x80) == 0x00)
484 break;
485 }
486 ct->perm_spch_len = i + 1;
487
488 return (int)(elem - old_elem);
489}
Philipp Maier14e76b92017-03-28 18:36:52 +0200490
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200491/*! Encode TS 08.08 Encryption Information IE
Harald Welte96e2a002017-06-12 21:44:18 +0200492 * \param[out] msg Message Buffer to which IE is to be appended
493 * \param[in] ei Encryption Information to be encoded
494 * \returns number of bytes appended to \a msg */
Philipp Maier14e76b92017-03-28 18:36:52 +0200495uint8_t gsm0808_enc_encrypt_info(struct msgb *msg,
496 const struct gsm0808_encrypt_info *ei)
497{
498 unsigned int i;
499 uint8_t perm_algo = 0;
500 uint8_t *ptr;
501 uint8_t *old_tail;
502 uint8_t *tlv_len;
503
504 OSMO_ASSERT(msg);
505 OSMO_ASSERT(ei);
506 OSMO_ASSERT(ei->key_len <= ARRAY_SIZE(ei->key));
507 OSMO_ASSERT(ei->perm_algo_len <= ENCRY_INFO_PERM_ALGO_MAXLEN);
508
509 msgb_put_u8(msg, GSM0808_IE_ENCRYPTION_INFORMATION);
510 tlv_len = msgb_put(msg, 1);
511 old_tail = msg->tail;
512
513 for (i = 0; i < ei->perm_algo_len; i++) {
514 /* Note: gsm_08_08.h defines the permitted algorithms
515 * as an enum which ranges from 0x01 to 0x08 */
516 OSMO_ASSERT(ei->perm_algo[i] != 0);
517 OSMO_ASSERT(ei->perm_algo[i] <= ENCRY_INFO_PERM_ALGO_MAXLEN);
518 perm_algo |= (1 << (ei->perm_algo[i] - 1));
519 }
520
521 msgb_put_u8(msg, perm_algo);
522 ptr = msgb_put(msg, ei->key_len);
523 memcpy(ptr, ei->key, ei->key_len);
524
525 *tlv_len = (uint8_t) (msg->tail - old_tail);
526 return *tlv_len + 2;
527}
528
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200529/*! Decode TS 08.08 Encryption Information IE
Harald Welte96e2a002017-06-12 21:44:18 +0200530 * \param[out] ei Caller-provided memory to store encryption information
531 * \param[in] elem IE value to be decoded
532 * \param[in] len Length of \a elem in bytes
533 * \returns number of bytes parsed; negative on error */
Philipp Maier14e76b92017-03-28 18:36:52 +0200534int gsm0808_dec_encrypt_info(struct gsm0808_encrypt_info *ei,
535 const uint8_t *elem, uint8_t len)
536{
537 uint8_t perm_algo;
538 unsigned int i;
539 unsigned int perm_algo_len = 0;
540 const uint8_t *old_elem = elem;
541
542 OSMO_ASSERT(ei);
543 if (!elem)
544 return -EINVAL;
Philipp Maier17778bd2017-04-28 11:05:44 +0200545 if (len == 0)
Philipp Maier14e76b92017-03-28 18:36:52 +0200546 return -EINVAL;
547
548 memset(ei, 0, sizeof(*ei));
549
550 perm_algo = *elem;
551 elem++;
552
553 for (i = 0; i < ENCRY_INFO_PERM_ALGO_MAXLEN; i++) {
554 if (perm_algo & (1 << i)) {
555 ei->perm_algo[perm_algo_len] = i + 1;
556 perm_algo_len++;
557 }
558 }
559 ei->perm_algo_len = perm_algo_len;
560
561 ei->key_len = len - 1;
562 memcpy(ei->key, elem, ei->key_len);
563 elem+=ei->key_len;
564
565 return (int)(elem - old_elem);
566}
Philipp Maier783047e2017-03-29 11:35:50 +0200567
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200568/*! Encode TS 08.08 Cell Identifier List IE
Harald Welte96e2a002017-06-12 21:44:18 +0200569 * \param[out] msg Message Buffer to which IE is to be appended
570 * \param[in] cil Cell ID List to be encoded
571 * \returns number of bytes appended to \a msg */
Philipp Maier783047e2017-03-29 11:35:50 +0200572uint8_t gsm0808_enc_cell_id_list(struct msgb *msg,
573 const struct gsm0808_cell_id_list *cil)
574{
575 uint8_t *old_tail;
576 uint8_t *tlv_len;
577 unsigned int i;
578
579 OSMO_ASSERT(msg);
580 OSMO_ASSERT(cil);
581
582 msgb_put_u8(msg, GSM0808_IE_CELL_IDENTIFIER_LIST);
583 tlv_len = msgb_put(msg, 1);
584 old_tail = msg->tail;
585
586 msgb_put_u8(msg, cil->id_discr & 0x0f);
587
588 switch (cil->id_discr) {
589 case CELL_IDENT_LAC:
590 OSMO_ASSERT(cil->id_list_len <= CELL_ID_LIST_LAC_MAXLEN)
591 for (i=0;i<cil->id_list_len;i++) {
592 msgb_put_u16(msg, cil->id_list_lac[i]);
593 }
594 break;
595 case CELL_IDENT_BSS:
596 /* Does not have any list items */
597 break;
598 default:
599 /* FIXME: Implement support for all identifier list elements */
600 OSMO_ASSERT(false);
601 }
602
603 *tlv_len = (uint8_t) (msg->tail - old_tail);
604 return *tlv_len + 2;
605}
606
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200607/*! Decode Cell Identifier List IE
Harald Welte96e2a002017-06-12 21:44:18 +0200608 * \param[out] cil Caller-provided memory to store Cell ID list
609 * \param[in] elem IE value to be decoded
610 * \param[in] len Length of \a elem in bytes
611 * \returns number of bytes parsed; negative on error */
Philipp Maier783047e2017-03-29 11:35:50 +0200612int gsm0808_dec_cell_id_list(struct gsm0808_cell_id_list *cil,
613 const uint8_t *elem, uint8_t len)
614{
615 uint8_t id_discr;
616 const uint8_t *old_elem = elem;
617 unsigned int item_count = 0;
618
619 OSMO_ASSERT(cil);
620 if (!elem)
621 return -EINVAL;
Philipp Maier17778bd2017-04-28 11:05:44 +0200622 if (len == 0)
Philipp Maier783047e2017-03-29 11:35:50 +0200623 return -EINVAL;
624
625 memset(cil, 0, sizeof(*cil));
626
627 id_discr = *elem & 0x0f;
628 elem++;
629 len--;
630
631 cil->id_discr = id_discr;
632
633 switch (id_discr) {
634 case CELL_IDENT_LAC:
635 while (len >= 2) {
636 cil->id_list_lac[item_count] = osmo_load16be(elem);
637 elem += 2;
638 item_count++;
639 len -= 2;
640 }
641 case CELL_IDENT_BSS:
642 /* Does not have any list items */
643 break;
644 default:
645 /* FIXME: Implement support for all identifier list elements */
646 return -EINVAL;
647 }
648
649 cil->id_list_len = item_count;
650 return (int)(elem - old_elem);
651}
Harald Welte96e2a002017-06-12 21:44:18 +0200652
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200653/*! Convert the representation of the permitted speech codec identifier
Philipp Maier3149b0d2017-06-02 13:22:34 +0200654 * that is used in struct gsm0808_channel_type to the speech codec
655 * representation we use in struct gsm0808_speech_codec.
656 * \param[in] perm_spch to be converted (see also gsm0808_permitted_speech)
657 * \returns GSM speech codec type; negative on error */
658int gsm0808_chan_type_to_speech_codec(uint8_t perm_spch)
659{
660 /*! The speech codec type, which is used in the channel type field to
661 * signal the permitted speech versions (codecs) has a different
662 * encoding than the type field in the speech codec type element
663 * (See also 3GPP TS 48.008, 3.2.2.11 and 3.2.2.103) */
664
665 switch (perm_spch) {
666 case GSM0808_PERM_FR1:
667 return GSM0808_SCT_FR1;
668 case GSM0808_PERM_FR2:
669 return GSM0808_SCT_FR2;
670 case GSM0808_PERM_FR3:
671 return GSM0808_SCT_FR3;
672 case GSM0808_PERM_FR4:
673 return GSM0808_SCT_FR4;
674 case GSM0808_PERM_FR5:
675 return GSM0808_SCT_FR5;
676 case GSM0808_PERM_HR1:
677 return GSM0808_SCT_HR1;
678 case GSM0808_PERM_HR3:
679 return GSM0808_SCT_HR3;
680 case GSM0808_PERM_HR4:
681 return GSM0808_SCT_HR4;
682 case GSM0808_PERM_HR6:
683 return GSM0808_SCT_HR6;
684 }
685
686 /* Invalid input */
687 return -EINVAL;
688}
689
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200690/*! Extrapolate a speech codec field from a given permitted speech
Philipp Maier884ba0f2017-06-02 13:49:16 +0200691 * parameter (channel type).
692 * \param[out] sc Caller provided memory to store the resulting speech codec
693 * \param[in] perm_spch value that is used to derive the speech codec info
694 * (see also: enum gsm0808_speech_codec_type in gsm0808_utils.h)
695 * \returns zero when successful; negative on error */
696int gsm0808_speech_codec_from_chan_type(struct gsm0808_speech_codec *sc,
697 uint8_t perm_spch)
698{
699 int rc;
700
701 memset(sc, 0, sizeof(*sc));
702
703 /* Determine codec type */
704 rc = gsm0808_chan_type_to_speech_codec(perm_spch);
705 if (rc < 0)
706 return -EINVAL;
707 sc->type = (uint8_t) rc;
708
709 /* Depending on the speech codec type, pick a default codec
710 * configuration that exactly matches the configuration on the
711 * air interface. */
712 switch (sc->type) {
713 case GSM0808_SCT_FR3:
714 sc->cfg = GSM0808_SC_CFG_DEFAULT_FR_AMR;
715 break;
716 case GSM0808_SCT_FR4:
717 sc->cfg = GSM0808_SC_CFG_DEFAULT_OFR_AMR_WB;
718 break;
719 case GSM0808_SCT_FR5:
720 sc->cfg = GSM0808_SC_CFG_DEFAULT_FR_AMR_WB;
721 break;
722 case GSM0808_SCT_HR3:
723 sc->cfg = GSM0808_SC_CFG_DEFAULT_HR_AMR;
724 break;
725 case GSM0808_SCT_HR4:
726 sc->cfg = GSM0808_SC_CFG_DEFAULT_OHR_AMR_WB;
727 break;
728 case GSM0808_SCT_HR6:
729 sc->cfg = GSM0808_SC_CFG_DEFAULT_OHR_AMR;
730 break;
731 default:
732 /* Note: Not all codec types specify a default setting,
733 * in this case, we just set the field to zero. */
734 sc->cfg = 0;
735 }
736
737 /* Tag all codecs as "Full IP"
738 * (see als 3GPP TS 48.008 3.2.2.103) */
739 sc->fi = true;
740
741 return 0;
742}
743
Harald Welte96e2a002017-06-12 21:44:18 +0200744/*! @} */