blob: bdd02e56f5cbe35ca56ad1f48d905296e8204265 [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
47/*! \brief Encode TS 08.08 AoIP transport address IE
48 * \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
Harald Welte96e2a002017-06-12 21:44:18 +020091/*! \brief Decode TS 08.08 AoIP transport address IE
92 * \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;
107 if (len <= 0)
108 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;
154
155 old_tail = msg->tail;
156
157 if (sc->fi)
158 header |= (1 << 7);
159 if (sc->pi)
160 header |= (1 << 6);
161 if (sc->pt)
162 header |= (1 << 5);
163 if (sc->tf)
164 header |= (1 << 4);
165 if (sc->type_extended) {
166 header |= 0x0f;
167 msgb_put_u8(msg, header);
168 } else {
169 OSMO_ASSERT(sc->type < 0x0f);
170 header |= sc->type;
171 msgb_put_u8(msg, header);
172 return (uint8_t) (msg->tail - old_tail);
173 }
174
175 msgb_put_u8(msg, sc->type);
176
177 if (sc->cfg_present)
178 msgb_put_u16(msg, sc->cfg);
179
180 return (uint8_t) (msg->tail - old_tail);
181}
182
Harald Welte96e2a002017-06-12 21:44:18 +0200183/*! \brief Encode TS 08.08 Speech Codec IE
184 * \param[out] msg Message Buffer to which IE will be appended
185 * \param[in] sc Speech Codec to be encoded into IE
186 * \returns number of bytes appended to \a msg */
Philipp Maier6f725d62017-03-24 18:03:17 +0100187uint8_t gsm0808_enc_speech_codec(struct msgb *msg,
188 const struct gsm0808_speech_codec *sc)
189{
190 uint8_t *old_tail;
191 uint8_t *tlv_len;
192
193 OSMO_ASSERT(msg);
194 OSMO_ASSERT(sc);
195
196 msgb_put_u8(msg, GSM0808_IE_SPEECH_CODEC);
197 tlv_len = msgb_put(msg, 1);
198 old_tail = msg->tail;
199
200 enc_speech_codec(msg, sc);
201
202 *tlv_len = (uint8_t) (msg->tail - old_tail);
203 return *tlv_len + 2;
204}
205
Harald Welte96e2a002017-06-12 21:44:18 +0200206/*! \brief Decode TS 08.08 Speech Codec IE
207 * \param[out] sc Caller-allocated memory for Speech Codec
208 * \param[in] elem IE value to be decoded
209 * \param[in] len Length of \a elem in bytes
210 * \returns number of bytes parsed; negative on error */
Philipp Maier6f725d62017-03-24 18:03:17 +0100211int gsm0808_dec_speech_codec(struct gsm0808_speech_codec *sc,
212 const uint8_t *elem, uint8_t len)
213{
214 /* See also 3GPP TS 48.008 3.2.2.103 Speech Codec List */
215 uint8_t header;
216 const uint8_t *old_elem = elem;
217
218 OSMO_ASSERT(sc);
219 if (!elem)
220 return -EINVAL;
221 if (len <= 0)
222 return -EINVAL;
223
224 memset(sc, 0, sizeof(*sc));
225
226 header = *elem;
227
Philipp Maier85a6af22017-04-28 10:55:05 +0200228 /* An extended codec type needs at least two fields,
229 * bail if the input data length is not sufficient. */
Philipp Maier6f725d62017-03-24 18:03:17 +0100230 if ((header & 0x0F) == 0x0F && len < 2)
231 return -EINVAL;
Philipp Maier6f725d62017-03-24 18:03:17 +0100232
233 elem++;
234 len--;
235
236 if (header & (1 << 7))
237 sc->fi = true;
238 if (header & (1 << 6))
239 sc->pi = true;
240 if (header & (1 << 5))
241 sc->pt = true;
242 if (header & (1 << 4))
243 sc->tf = true;
244
245 if ((header & 0x0F) != 0x0F) {
246 sc->type = (header & 0x0F);
247 return (int)(elem - old_elem);
248 }
249
250 sc->type = *elem;
251 elem++;
252 len--;
253
254 sc->type_extended = true;
255
256 if (len < 2)
257 return (int)(elem - old_elem);
258
259 sc->cfg = osmo_load16be(elem);
260 elem += 2;
261 sc->cfg_present = true;
262
263 return (int)(elem - old_elem);
264}
265
Harald Welte96e2a002017-06-12 21:44:18 +0200266/*! \brief Encode TS 08.08 Speech Codec list
267 * \param[out] msg Message Buffer to which IE is to be appended
268 * \param[in] scl Speech Codec List to be encoded into IE
269 * \returns number of bytes added to \a msg */
Philipp Maier6f725d62017-03-24 18:03:17 +0100270uint8_t gsm0808_enc_speech_codec_list(struct msgb *msg,
271 const struct gsm0808_speech_codec_list *scl)
272{
273 uint8_t *old_tail;
274 uint8_t *tlv_len;
275 unsigned int i;
276 uint8_t rc;
277 unsigned int bytes_used = 0;
278
279 OSMO_ASSERT(msg);
280 OSMO_ASSERT(scl);
281
282 /* Empty list */
283 OSMO_ASSERT(scl->len >= 1);
284
285 msgb_put_u8(msg, GSM0808_IE_SPEECH_CODEC_LIST);
286 tlv_len = msgb_put(msg, 1);
287 old_tail = msg->tail;
288
289 for (i = 0; i < scl->len; i++) {
290 rc = enc_speech_codec(msg, &scl->codec[i]);
291 OSMO_ASSERT(rc >= 1);
292 bytes_used += rc;
293 OSMO_ASSERT(bytes_used <= 255);
294 }
295
296 *tlv_len = (uint8_t) (msg->tail - old_tail);
297 return *tlv_len + 2;
298}
299
Harald Welte96e2a002017-06-12 21:44:18 +0200300/*! \brief Decode TS 08.08 Speech Codec list IE
301 * \param[out] scl Caller-provided memory to store codec list
302 * \param[in] elem IE value to be decoded
303 * \param[in] len Length of \a elem in bytes
304 * \returns number of bytes parsed; negative on error */
Philipp Maier6f725d62017-03-24 18:03:17 +0100305int gsm0808_dec_speech_codec_list(struct gsm0808_speech_codec_list *scl,
306 const uint8_t *elem, uint8_t len)
307{
308 const uint8_t *old_elem = elem;
309 unsigned int i;
310 int rc;
311 uint8_t decoded = 0;
312
313 OSMO_ASSERT(scl);
314 if (!elem)
315 return -EINVAL;
316 if (len <= 0)
317 return -EINVAL;
318
319 memset(scl, 0, sizeof(*scl));
320
321 for (i = 0; i < ARRAY_SIZE(scl->codec); i++) {
322 if (len <= 0)
323 break;
324
325 rc = gsm0808_dec_speech_codec(&scl->codec[i], elem, len);
326 if (rc < 1)
327 return -EINVAL;
328
329 elem+=rc;
330 len -= rc;
331 decoded++;
332 }
333
334 scl->len = decoded;
335
336 /* Empty list */
337 if (decoded < 1) {
338 return -EINVAL;
339 }
340
341 return (int)(elem - old_elem);
342}
Philipp Maiere0c65302017-03-28 17:05:40 +0200343
Harald Welte96e2a002017-06-12 21:44:18 +0200344/*! \brief Encode TS 08.08 Channel Type IE
345 * \param[out] msg Message Buffer to which IE is to be appended
346 * \param[in] ct Channel Type to be encoded
347 * \returns number of bytes added to \a msg */
Philipp Maiere0c65302017-03-28 17:05:40 +0200348uint8_t gsm0808_enc_channel_type(struct msgb *msg,
349 const struct gsm0808_channel_type *ct)
350{
351 unsigned int i;
352 uint8_t byte;
353 uint8_t *old_tail;
354 uint8_t *tlv_len;
355
356 OSMO_ASSERT(msg);
357 OSMO_ASSERT(ct);
358 OSMO_ASSERT(ct->perm_spch_len <= CHANNEL_TYPE_ELEMENT_MAXLEN - 2);
359
360 /* FIXME: Implement encoding support for Data
361 * and Speech + CTM Text Telephony */
362 if ((ct->ch_indctr & 0x0f) != GSM0808_CHAN_SPEECH
363 && (ct->ch_indctr & 0x0f) != GSM0808_CHAN_SIGN)
364 OSMO_ASSERT(false);
365
366 msgb_put_u8(msg, GSM0808_IE_CHANNEL_TYPE);
367 tlv_len = msgb_put(msg, 1);
368 old_tail = msg->tail;
369
370 msgb_put_u8(msg, ct->ch_indctr & 0x0f);
371 msgb_put_u8(msg, ct->ch_rate_type);
372
373 for (i = 0; i < ct->perm_spch_len; i++) {
374 byte = ct->perm_spch[i];
375
376 if (i < ct->perm_spch_len - 1)
377 byte |= 0x80;
378 msgb_put_u8(msg, byte);
379 }
380
381 *tlv_len = (uint8_t) (msg->tail - old_tail);
382 return *tlv_len + 2;
383}
384
Harald Welte96e2a002017-06-12 21:44:18 +0200385/*! \brief Decode TS 08.08 Channel Type IE
386 * \param[out] ct Caller-provided memory to store channel type
387 * \param[in] elem IE Value to be decoded
388 * \param[in] len Length of \a elem in bytes
389 * \returns number of bytes parsed; negative on error */
Philipp Maiere0c65302017-03-28 17:05:40 +0200390int gsm0808_dec_channel_type(struct gsm0808_channel_type *ct,
391 const uint8_t *elem, uint8_t len)
392{
393 unsigned int i;
394 uint8_t byte;
395 const uint8_t *old_elem = elem;
396
397 OSMO_ASSERT(ct);
398 if (!elem)
399 return -EINVAL;
400 if (len <= 0)
401 return -EINVAL;
402
403 memset(ct, 0, sizeof(*ct));
404
405 ct->ch_indctr = (*elem) & 0x0f;
406 elem++;
407 ct->ch_rate_type = (*elem) & 0x0f;
408 elem++;
409
410 for (i = 0; i < ARRAY_SIZE(ct->perm_spch); i++) {
411 byte = *elem;
412 elem++;
413 ct->perm_spch[i] = byte & 0x7f;
414 if ((byte & 0x80) == 0x00)
415 break;
416 }
417 ct->perm_spch_len = i + 1;
418
419 return (int)(elem - old_elem);
420}
Philipp Maier14e76b92017-03-28 18:36:52 +0200421
Harald Welte96e2a002017-06-12 21:44:18 +0200422/*! \brief Encode TS 08.08 Encryption Information IE
423 * \param[out] msg Message Buffer to which IE is to be appended
424 * \param[in] ei Encryption Information to be encoded
425 * \returns number of bytes appended to \a msg */
Philipp Maier14e76b92017-03-28 18:36:52 +0200426uint8_t gsm0808_enc_encrypt_info(struct msgb *msg,
427 const struct gsm0808_encrypt_info *ei)
428{
429 unsigned int i;
430 uint8_t perm_algo = 0;
431 uint8_t *ptr;
432 uint8_t *old_tail;
433 uint8_t *tlv_len;
434
435 OSMO_ASSERT(msg);
436 OSMO_ASSERT(ei);
437 OSMO_ASSERT(ei->key_len <= ARRAY_SIZE(ei->key));
438 OSMO_ASSERT(ei->perm_algo_len <= ENCRY_INFO_PERM_ALGO_MAXLEN);
439
440 msgb_put_u8(msg, GSM0808_IE_ENCRYPTION_INFORMATION);
441 tlv_len = msgb_put(msg, 1);
442 old_tail = msg->tail;
443
444 for (i = 0; i < ei->perm_algo_len; i++) {
445 /* Note: gsm_08_08.h defines the permitted algorithms
446 * as an enum which ranges from 0x01 to 0x08 */
447 OSMO_ASSERT(ei->perm_algo[i] != 0);
448 OSMO_ASSERT(ei->perm_algo[i] <= ENCRY_INFO_PERM_ALGO_MAXLEN);
449 perm_algo |= (1 << (ei->perm_algo[i] - 1));
450 }
451
452 msgb_put_u8(msg, perm_algo);
453 ptr = msgb_put(msg, ei->key_len);
454 memcpy(ptr, ei->key, ei->key_len);
455
456 *tlv_len = (uint8_t) (msg->tail - old_tail);
457 return *tlv_len + 2;
458}
459
Harald Welte96e2a002017-06-12 21:44:18 +0200460/*! \brief Decode TS 08.08 Encryption Information IE
461 * \param[out] ei Caller-provided memory to store encryption information
462 * \param[in] elem IE value to be decoded
463 * \param[in] len Length of \a elem in bytes
464 * \returns number of bytes parsed; negative on error */
Philipp Maier14e76b92017-03-28 18:36:52 +0200465int gsm0808_dec_encrypt_info(struct gsm0808_encrypt_info *ei,
466 const uint8_t *elem, uint8_t len)
467{
468 uint8_t perm_algo;
469 unsigned int i;
470 unsigned int perm_algo_len = 0;
471 const uint8_t *old_elem = elem;
472
473 OSMO_ASSERT(ei);
474 if (!elem)
475 return -EINVAL;
476 if (len <= 0)
477 return -EINVAL;
478
479 memset(ei, 0, sizeof(*ei));
480
481 perm_algo = *elem;
482 elem++;
483
484 for (i = 0; i < ENCRY_INFO_PERM_ALGO_MAXLEN; i++) {
485 if (perm_algo & (1 << i)) {
486 ei->perm_algo[perm_algo_len] = i + 1;
487 perm_algo_len++;
488 }
489 }
490 ei->perm_algo_len = perm_algo_len;
491
492 ei->key_len = len - 1;
493 memcpy(ei->key, elem, ei->key_len);
494 elem+=ei->key_len;
495
496 return (int)(elem - old_elem);
497}
Philipp Maier783047e2017-03-29 11:35:50 +0200498
Harald Welte96e2a002017-06-12 21:44:18 +0200499/*! \brief Encode TS 08.08 Cell Identifier List IE
500 * \param[out] msg Message Buffer to which IE is to be appended
501 * \param[in] cil Cell ID List to be encoded
502 * \returns number of bytes appended to \a msg */
Philipp Maier783047e2017-03-29 11:35:50 +0200503uint8_t gsm0808_enc_cell_id_list(struct msgb *msg,
504 const struct gsm0808_cell_id_list *cil)
505{
506 uint8_t *old_tail;
507 uint8_t *tlv_len;
508 unsigned int i;
509
510 OSMO_ASSERT(msg);
511 OSMO_ASSERT(cil);
512
513 msgb_put_u8(msg, GSM0808_IE_CELL_IDENTIFIER_LIST);
514 tlv_len = msgb_put(msg, 1);
515 old_tail = msg->tail;
516
517 msgb_put_u8(msg, cil->id_discr & 0x0f);
518
519 switch (cil->id_discr) {
520 case CELL_IDENT_LAC:
521 OSMO_ASSERT(cil->id_list_len <= CELL_ID_LIST_LAC_MAXLEN)
522 for (i=0;i<cil->id_list_len;i++) {
523 msgb_put_u16(msg, cil->id_list_lac[i]);
524 }
525 break;
526 case CELL_IDENT_BSS:
527 /* Does not have any list items */
528 break;
529 default:
530 /* FIXME: Implement support for all identifier list elements */
531 OSMO_ASSERT(false);
532 }
533
534 *tlv_len = (uint8_t) (msg->tail - old_tail);
535 return *tlv_len + 2;
536}
537
Harald Welte96e2a002017-06-12 21:44:18 +0200538/*! \brief Decode Cell Identifier List IE
539 * \param[out] cil Caller-provided memory to store Cell ID list
540 * \param[in] elem IE value to be decoded
541 * \param[in] len Length of \a elem in bytes
542 * \returns number of bytes parsed; negative on error */
Philipp Maier783047e2017-03-29 11:35:50 +0200543int gsm0808_dec_cell_id_list(struct gsm0808_cell_id_list *cil,
544 const uint8_t *elem, uint8_t len)
545{
546 uint8_t id_discr;
547 const uint8_t *old_elem = elem;
548 unsigned int item_count = 0;
549
550 OSMO_ASSERT(cil);
551 if (!elem)
552 return -EINVAL;
553 if (len <= 0)
554 return -EINVAL;
555
556 memset(cil, 0, sizeof(*cil));
557
558 id_discr = *elem & 0x0f;
559 elem++;
560 len--;
561
562 cil->id_discr = id_discr;
563
564 switch (id_discr) {
565 case CELL_IDENT_LAC:
566 while (len >= 2) {
567 cil->id_list_lac[item_count] = osmo_load16be(elem);
568 elem += 2;
569 item_count++;
570 len -= 2;
571 }
572 case CELL_IDENT_BSS:
573 /* Does not have any list items */
574 break;
575 default:
576 /* FIXME: Implement support for all identifier list elements */
577 return -EINVAL;
578 }
579
580 cil->id_list_len = item_count;
581 return (int)(elem - old_elem);
582}
Harald Welte96e2a002017-06-12 21:44:18 +0200583
584/*! @} */