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