blob: ff97b2d29c1918ac8efdea5e5c39c4008f78dc76 [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>
Philipp Maier22401432017-03-24 17:59:26 +010042/* Encode AoIP transport address element */
43uint8_t gsm0808_enc_aoip_trasp_addr(struct msgb *msg,
44 const struct sockaddr_storage *ss)
45{
46 /* See also 3GPP TS 48.008 3.2.2.102 AoIP Transport Layer Address */
47 struct sockaddr_in *sin;
48 struct sockaddr_in6 *sin6;
49 uint16_t port = 0;
50 uint8_t *ptr;
51 uint8_t *old_tail;
52 uint8_t *tlv_len;
53
54 OSMO_ASSERT(msg);
55 OSMO_ASSERT(ss);
56 OSMO_ASSERT(ss->ss_family == AF_INET || ss->ss_family == AF_INET6);
57
58 msgb_put_u8(msg, GSM0808_IE_AOIP_TRASP_ADDR);
59 tlv_len = msgb_put(msg,1);
60 old_tail = msg->tail;
61
62 switch (ss->ss_family) {
63 case AF_INET:
64 sin = (struct sockaddr_in *)ss;
Harald Welte95871da2017-05-15 12:11:36 +020065 port = osmo_ntohs(sin->sin_port);
Philipp Maier22401432017-03-24 17:59:26 +010066 ptr = msgb_put(msg, IP_V4_ADDR_LEN);
67 memcpy(ptr, &sin->sin_addr.s_addr, IP_V4_ADDR_LEN);
68 break;
69 case AF_INET6:
70 sin6 = (struct sockaddr_in6 *)ss;
Harald Welte95871da2017-05-15 12:11:36 +020071 port = osmo_ntohs(sin6->sin6_port);
Philipp Maier22401432017-03-24 17:59:26 +010072 ptr = msgb_put(msg, IP_V6_ADDR_LEN);
73 memcpy(ptr, sin6->sin6_addr.s6_addr, IP_V6_ADDR_LEN);
74 break;
75 }
76
77 msgb_put_u16(msg, port);
78
79 *tlv_len = (uint8_t) (msg->tail - old_tail);
80 return *tlv_len + 2;
81}
82
83/* Decode AoIP transport address element */
84int gsm0808_dec_aoip_trasp_addr(struct sockaddr_storage *ss,
85 const uint8_t *elem, uint8_t len)
86{
87 /* See also 3GPP TS 48.008 3.2.2.102 AoIP Transport Layer Address */
88 struct sockaddr_in sin;
89 struct sockaddr_in6 sin6;
90 const uint8_t *old_elem = elem;
91
92 OSMO_ASSERT(ss);
93 if (!elem)
94 return -EINVAL;
95 if (len <= 0)
96 return -EINVAL;
97
98 memset(ss, 0, sizeof(*ss));
99
100 switch (len) {
101 case IP_V4_ADDR_LEN + IP_PORT_LEN:
102 memset(&sin, 0, sizeof(sin));
103 sin.sin_family = AF_INET;
104
105 memcpy(&sin.sin_addr.s_addr, elem, IP_V4_ADDR_LEN);
106 elem += IP_V4_ADDR_LEN;
107 sin.sin_port = osmo_load16le(elem);
108 elem += IP_PORT_LEN;
109
110 memcpy(ss, &sin, sizeof(sin));
111 break;
112 case IP_V6_ADDR_LEN + IP_PORT_LEN:
113 memset(&sin6, 0, sizeof(sin6));
114 sin6.sin6_family = AF_INET6;
115
116 memcpy(sin6.sin6_addr.s6_addr, elem, IP_V6_ADDR_LEN);
117 elem += IP_V6_ADDR_LEN;
118 sin6.sin6_port = osmo_load16le(elem);
119 elem += IP_PORT_LEN;
120
121 memcpy(ss, &sin6, sizeof(sin6));
122 break;
123 default:
124 /* Malformed element! */
125 return -EINVAL;
126 break;
127 }
128
129 return (int)(elem - old_elem);
130}
Philipp Maier6f725d62017-03-24 18:03:17 +0100131
Harald Welte20725b92017-05-15 12:50:04 +0200132#endif /* HAVE_SYS_SOCKET_H */
133
Philipp Maier6f725d62017-03-24 18:03:17 +0100134/* Helper function for gsm0808_enc_speech_codec()
135 * and gsm0808_enc_speech_codec_list() */
136static uint8_t enc_speech_codec(struct msgb *msg,
137 const struct gsm0808_speech_codec *sc)
138{
139 /* See also 3GPP TS 48.008 3.2.2.103 Speech Codec List */
140 uint8_t header = 0;
141 uint8_t *old_tail;
142
143 old_tail = msg->tail;
144
145 if (sc->fi)
146 header |= (1 << 7);
147 if (sc->pi)
148 header |= (1 << 6);
149 if (sc->pt)
150 header |= (1 << 5);
151 if (sc->tf)
152 header |= (1 << 4);
153 if (sc->type_extended) {
154 header |= 0x0f;
155 msgb_put_u8(msg, header);
156 } else {
157 OSMO_ASSERT(sc->type < 0x0f);
158 header |= sc->type;
159 msgb_put_u8(msg, header);
160 return (uint8_t) (msg->tail - old_tail);
161 }
162
163 msgb_put_u8(msg, sc->type);
164
165 if (sc->cfg_present)
166 msgb_put_u16(msg, sc->cfg);
167
168 return (uint8_t) (msg->tail - old_tail);
169}
170
171/* Encode Speech Codec element */
172uint8_t gsm0808_enc_speech_codec(struct msgb *msg,
173 const struct gsm0808_speech_codec *sc)
174{
175 uint8_t *old_tail;
176 uint8_t *tlv_len;
177
178 OSMO_ASSERT(msg);
179 OSMO_ASSERT(sc);
180
181 msgb_put_u8(msg, GSM0808_IE_SPEECH_CODEC);
182 tlv_len = msgb_put(msg, 1);
183 old_tail = msg->tail;
184
185 enc_speech_codec(msg, sc);
186
187 *tlv_len = (uint8_t) (msg->tail - old_tail);
188 return *tlv_len + 2;
189}
190
191/* Decode Speech Codec element */
192int gsm0808_dec_speech_codec(struct gsm0808_speech_codec *sc,
193 const uint8_t *elem, uint8_t len)
194{
195 /* See also 3GPP TS 48.008 3.2.2.103 Speech Codec List */
196 uint8_t header;
197 const uint8_t *old_elem = elem;
198
199 OSMO_ASSERT(sc);
200 if (!elem)
201 return -EINVAL;
202 if (len <= 0)
203 return -EINVAL;
204
205 memset(sc, 0, sizeof(*sc));
206
207 header = *elem;
208
Philipp Maier85a6af22017-04-28 10:55:05 +0200209 /* An extended codec type needs at least two fields,
210 * bail if the input data length is not sufficient. */
Philipp Maier6f725d62017-03-24 18:03:17 +0100211 if ((header & 0x0F) == 0x0F && len < 2)
212 return -EINVAL;
Philipp Maier6f725d62017-03-24 18:03:17 +0100213
214 elem++;
215 len--;
216
217 if (header & (1 << 7))
218 sc->fi = true;
219 if (header & (1 << 6))
220 sc->pi = true;
221 if (header & (1 << 5))
222 sc->pt = true;
223 if (header & (1 << 4))
224 sc->tf = true;
225
226 if ((header & 0x0F) != 0x0F) {
227 sc->type = (header & 0x0F);
228 return (int)(elem - old_elem);
229 }
230
231 sc->type = *elem;
232 elem++;
233 len--;
234
235 sc->type_extended = true;
236
237 if (len < 2)
238 return (int)(elem - old_elem);
239
240 sc->cfg = osmo_load16be(elem);
241 elem += 2;
242 sc->cfg_present = true;
243
244 return (int)(elem - old_elem);
245}
246
247/* Encode Speech Codec list */
248uint8_t gsm0808_enc_speech_codec_list(struct msgb *msg,
249 const struct gsm0808_speech_codec_list *scl)
250{
251 uint8_t *old_tail;
252 uint8_t *tlv_len;
253 unsigned int i;
254 uint8_t rc;
255 unsigned int bytes_used = 0;
256
257 OSMO_ASSERT(msg);
258 OSMO_ASSERT(scl);
259
260 /* Empty list */
261 OSMO_ASSERT(scl->len >= 1);
262
263 msgb_put_u8(msg, GSM0808_IE_SPEECH_CODEC_LIST);
264 tlv_len = msgb_put(msg, 1);
265 old_tail = msg->tail;
266
267 for (i = 0; i < scl->len; i++) {
268 rc = enc_speech_codec(msg, &scl->codec[i]);
269 OSMO_ASSERT(rc >= 1);
270 bytes_used += rc;
271 OSMO_ASSERT(bytes_used <= 255);
272 }
273
274 *tlv_len = (uint8_t) (msg->tail - old_tail);
275 return *tlv_len + 2;
276}
277
278/* Decode Speech Codec list */
279int gsm0808_dec_speech_codec_list(struct gsm0808_speech_codec_list *scl,
280 const uint8_t *elem, uint8_t len)
281{
282 const uint8_t *old_elem = elem;
283 unsigned int i;
284 int rc;
285 uint8_t decoded = 0;
286
287 OSMO_ASSERT(scl);
288 if (!elem)
289 return -EINVAL;
290 if (len <= 0)
291 return -EINVAL;
292
293 memset(scl, 0, sizeof(*scl));
294
295 for (i = 0; i < ARRAY_SIZE(scl->codec); i++) {
296 if (len <= 0)
297 break;
298
299 rc = gsm0808_dec_speech_codec(&scl->codec[i], elem, len);
300 if (rc < 1)
301 return -EINVAL;
302
303 elem+=rc;
304 len -= rc;
305 decoded++;
306 }
307
308 scl->len = decoded;
309
310 /* Empty list */
311 if (decoded < 1) {
312 return -EINVAL;
313 }
314
315 return (int)(elem - old_elem);
316}
Philipp Maiere0c65302017-03-28 17:05:40 +0200317
318/* Encode Channel Type element */
319uint8_t gsm0808_enc_channel_type(struct msgb *msg,
320 const struct gsm0808_channel_type *ct)
321{
322 unsigned int i;
323 uint8_t byte;
324 uint8_t *old_tail;
325 uint8_t *tlv_len;
326
327 OSMO_ASSERT(msg);
328 OSMO_ASSERT(ct);
329 OSMO_ASSERT(ct->perm_spch_len <= CHANNEL_TYPE_ELEMENT_MAXLEN - 2);
330
331 /* FIXME: Implement encoding support for Data
332 * and Speech + CTM Text Telephony */
333 if ((ct->ch_indctr & 0x0f) != GSM0808_CHAN_SPEECH
334 && (ct->ch_indctr & 0x0f) != GSM0808_CHAN_SIGN)
335 OSMO_ASSERT(false);
336
337 msgb_put_u8(msg, GSM0808_IE_CHANNEL_TYPE);
338 tlv_len = msgb_put(msg, 1);
339 old_tail = msg->tail;
340
341 msgb_put_u8(msg, ct->ch_indctr & 0x0f);
342 msgb_put_u8(msg, ct->ch_rate_type);
343
344 for (i = 0; i < ct->perm_spch_len; i++) {
345 byte = ct->perm_spch[i];
346
347 if (i < ct->perm_spch_len - 1)
348 byte |= 0x80;
349 msgb_put_u8(msg, byte);
350 }
351
352 *tlv_len = (uint8_t) (msg->tail - old_tail);
353 return *tlv_len + 2;
354}
355
356/* Decode Channel Type element */
357int gsm0808_dec_channel_type(struct gsm0808_channel_type *ct,
358 const uint8_t *elem, uint8_t len)
359{
360 unsigned int i;
361 uint8_t byte;
362 const uint8_t *old_elem = elem;
363
364 OSMO_ASSERT(ct);
365 if (!elem)
366 return -EINVAL;
367 if (len <= 0)
368 return -EINVAL;
369
370 memset(ct, 0, sizeof(*ct));
371
372 ct->ch_indctr = (*elem) & 0x0f;
373 elem++;
374 ct->ch_rate_type = (*elem) & 0x0f;
375 elem++;
376
377 for (i = 0; i < ARRAY_SIZE(ct->perm_spch); i++) {
378 byte = *elem;
379 elem++;
380 ct->perm_spch[i] = byte & 0x7f;
381 if ((byte & 0x80) == 0x00)
382 break;
383 }
384 ct->perm_spch_len = i + 1;
385
386 return (int)(elem - old_elem);
387}
Philipp Maier14e76b92017-03-28 18:36:52 +0200388
389/* Encode Encryption Information element */
390uint8_t gsm0808_enc_encrypt_info(struct msgb *msg,
391 const struct gsm0808_encrypt_info *ei)
392{
393 unsigned int i;
394 uint8_t perm_algo = 0;
395 uint8_t *ptr;
396 uint8_t *old_tail;
397 uint8_t *tlv_len;
398
399 OSMO_ASSERT(msg);
400 OSMO_ASSERT(ei);
401 OSMO_ASSERT(ei->key_len <= ARRAY_SIZE(ei->key));
402 OSMO_ASSERT(ei->perm_algo_len <= ENCRY_INFO_PERM_ALGO_MAXLEN);
403
404 msgb_put_u8(msg, GSM0808_IE_ENCRYPTION_INFORMATION);
405 tlv_len = msgb_put(msg, 1);
406 old_tail = msg->tail;
407
408 for (i = 0; i < ei->perm_algo_len; i++) {
409 /* Note: gsm_08_08.h defines the permitted algorithms
410 * as an enum which ranges from 0x01 to 0x08 */
411 OSMO_ASSERT(ei->perm_algo[i] != 0);
412 OSMO_ASSERT(ei->perm_algo[i] <= ENCRY_INFO_PERM_ALGO_MAXLEN);
413 perm_algo |= (1 << (ei->perm_algo[i] - 1));
414 }
415
416 msgb_put_u8(msg, perm_algo);
417 ptr = msgb_put(msg, ei->key_len);
418 memcpy(ptr, ei->key, ei->key_len);
419
420 *tlv_len = (uint8_t) (msg->tail - old_tail);
421 return *tlv_len + 2;
422}
423
424/* Decode Encryption Information element */
425int gsm0808_dec_encrypt_info(struct gsm0808_encrypt_info *ei,
426 const uint8_t *elem, uint8_t len)
427{
428 uint8_t perm_algo;
429 unsigned int i;
430 unsigned int perm_algo_len = 0;
431 const uint8_t *old_elem = elem;
432
433 OSMO_ASSERT(ei);
434 if (!elem)
435 return -EINVAL;
436 if (len <= 0)
437 return -EINVAL;
438
439 memset(ei, 0, sizeof(*ei));
440
441 perm_algo = *elem;
442 elem++;
443
444 for (i = 0; i < ENCRY_INFO_PERM_ALGO_MAXLEN; i++) {
445 if (perm_algo & (1 << i)) {
446 ei->perm_algo[perm_algo_len] = i + 1;
447 perm_algo_len++;
448 }
449 }
450 ei->perm_algo_len = perm_algo_len;
451
452 ei->key_len = len - 1;
453 memcpy(ei->key, elem, ei->key_len);
454 elem+=ei->key_len;
455
456 return (int)(elem - old_elem);
457}
Philipp Maier783047e2017-03-29 11:35:50 +0200458
459/* Encode Cell Identifier List element */
460uint8_t gsm0808_enc_cell_id_list(struct msgb *msg,
461 const struct gsm0808_cell_id_list *cil)
462{
463 uint8_t *old_tail;
464 uint8_t *tlv_len;
465 unsigned int i;
466
467 OSMO_ASSERT(msg);
468 OSMO_ASSERT(cil);
469
470 msgb_put_u8(msg, GSM0808_IE_CELL_IDENTIFIER_LIST);
471 tlv_len = msgb_put(msg, 1);
472 old_tail = msg->tail;
473
474 msgb_put_u8(msg, cil->id_discr & 0x0f);
475
476 switch (cil->id_discr) {
477 case CELL_IDENT_LAC:
478 OSMO_ASSERT(cil->id_list_len <= CELL_ID_LIST_LAC_MAXLEN)
479 for (i=0;i<cil->id_list_len;i++) {
480 msgb_put_u16(msg, cil->id_list_lac[i]);
481 }
482 break;
483 case CELL_IDENT_BSS:
484 /* Does not have any list items */
485 break;
486 default:
487 /* FIXME: Implement support for all identifier list elements */
488 OSMO_ASSERT(false);
489 }
490
491 *tlv_len = (uint8_t) (msg->tail - old_tail);
492 return *tlv_len + 2;
493}
494
495/* Decode Cell Identifier List element */
496int gsm0808_dec_cell_id_list(struct gsm0808_cell_id_list *cil,
497 const uint8_t *elem, uint8_t len)
498{
499 uint8_t id_discr;
500 const uint8_t *old_elem = elem;
501 unsigned int item_count = 0;
502
503 OSMO_ASSERT(cil);
504 if (!elem)
505 return -EINVAL;
506 if (len <= 0)
507 return -EINVAL;
508
509 memset(cil, 0, sizeof(*cil));
510
511 id_discr = *elem & 0x0f;
512 elem++;
513 len--;
514
515 cil->id_discr = id_discr;
516
517 switch (id_discr) {
518 case CELL_IDENT_LAC:
519 while (len >= 2) {
520 cil->id_list_lac[item_count] = osmo_load16be(elem);
521 elem += 2;
522 item_count++;
523 len -= 2;
524 }
525 case CELL_IDENT_BSS:
526 /* Does not have any list items */
527 break;
528 default:
529 /* FIXME: Implement support for all identifier list elements */
530 return -EINVAL;
531 }
532
533 cil->id_list_len = item_count;
534 return (int)(elem - old_elem);
535}