blob: 19156050f1a3b3ad38ea4798b3e46ca2918ee3d7 [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
203 /* Malformed elements */
204 if ((header & 0x0F) == 0x0F && len < 2)
205 return -EINVAL;
206 else if ((header & 0x0F) != 0x0F && len < 1)
207 return -EINVAL;
208
209 elem++;
210 len--;
211
212 if (header & (1 << 7))
213 sc->fi = true;
214 if (header & (1 << 6))
215 sc->pi = true;
216 if (header & (1 << 5))
217 sc->pt = true;
218 if (header & (1 << 4))
219 sc->tf = true;
220
221 if ((header & 0x0F) != 0x0F) {
222 sc->type = (header & 0x0F);
223 return (int)(elem - old_elem);
224 }
225
226 sc->type = *elem;
227 elem++;
228 len--;
229
230 sc->type_extended = true;
231
232 if (len < 2)
233 return (int)(elem - old_elem);
234
235 sc->cfg = osmo_load16be(elem);
236 elem += 2;
237 sc->cfg_present = true;
238
239 return (int)(elem - old_elem);
240}
241
242/* Encode Speech Codec list */
243uint8_t gsm0808_enc_speech_codec_list(struct msgb *msg,
244 const struct gsm0808_speech_codec_list *scl)
245{
246 uint8_t *old_tail;
247 uint8_t *tlv_len;
248 unsigned int i;
249 uint8_t rc;
250 unsigned int bytes_used = 0;
251
252 OSMO_ASSERT(msg);
253 OSMO_ASSERT(scl);
254
255 /* Empty list */
256 OSMO_ASSERT(scl->len >= 1);
257
258 msgb_put_u8(msg, GSM0808_IE_SPEECH_CODEC_LIST);
259 tlv_len = msgb_put(msg, 1);
260 old_tail = msg->tail;
261
262 for (i = 0; i < scl->len; i++) {
263 rc = enc_speech_codec(msg, &scl->codec[i]);
264 OSMO_ASSERT(rc >= 1);
265 bytes_used += rc;
266 OSMO_ASSERT(bytes_used <= 255);
267 }
268
269 *tlv_len = (uint8_t) (msg->tail - old_tail);
270 return *tlv_len + 2;
271}
272
273/* Decode Speech Codec list */
274int gsm0808_dec_speech_codec_list(struct gsm0808_speech_codec_list *scl,
275 const uint8_t *elem, uint8_t len)
276{
277 const uint8_t *old_elem = elem;
278 unsigned int i;
279 int rc;
280 uint8_t decoded = 0;
281
282 OSMO_ASSERT(scl);
283 if (!elem)
284 return -EINVAL;
285 if (len <= 0)
286 return -EINVAL;
287
288 memset(scl, 0, sizeof(*scl));
289
290 for (i = 0; i < ARRAY_SIZE(scl->codec); i++) {
291 if (len <= 0)
292 break;
293
294 rc = gsm0808_dec_speech_codec(&scl->codec[i], elem, len);
295 if (rc < 1)
296 return -EINVAL;
297
298 elem+=rc;
299 len -= rc;
300 decoded++;
301 }
302
303 scl->len = decoded;
304
305 /* Empty list */
306 if (decoded < 1) {
307 return -EINVAL;
308 }
309
310 return (int)(elem - old_elem);
311}
Philipp Maiere0c65302017-03-28 17:05:40 +0200312
313/* Encode Channel Type element */
314uint8_t gsm0808_enc_channel_type(struct msgb *msg,
315 const struct gsm0808_channel_type *ct)
316{
317 unsigned int i;
318 uint8_t byte;
319 uint8_t *old_tail;
320 uint8_t *tlv_len;
321
322 OSMO_ASSERT(msg);
323 OSMO_ASSERT(ct);
324 OSMO_ASSERT(ct->perm_spch_len <= CHANNEL_TYPE_ELEMENT_MAXLEN - 2);
325
326 /* FIXME: Implement encoding support for Data
327 * and Speech + CTM Text Telephony */
328 if ((ct->ch_indctr & 0x0f) != GSM0808_CHAN_SPEECH
329 && (ct->ch_indctr & 0x0f) != GSM0808_CHAN_SIGN)
330 OSMO_ASSERT(false);
331
332 msgb_put_u8(msg, GSM0808_IE_CHANNEL_TYPE);
333 tlv_len = msgb_put(msg, 1);
334 old_tail = msg->tail;
335
336 msgb_put_u8(msg, ct->ch_indctr & 0x0f);
337 msgb_put_u8(msg, ct->ch_rate_type);
338
339 for (i = 0; i < ct->perm_spch_len; i++) {
340 byte = ct->perm_spch[i];
341
342 if (i < ct->perm_spch_len - 1)
343 byte |= 0x80;
344 msgb_put_u8(msg, byte);
345 }
346
347 *tlv_len = (uint8_t) (msg->tail - old_tail);
348 return *tlv_len + 2;
349}
350
351/* Decode Channel Type element */
352int gsm0808_dec_channel_type(struct gsm0808_channel_type *ct,
353 const uint8_t *elem, uint8_t len)
354{
355 unsigned int i;
356 uint8_t byte;
357 const uint8_t *old_elem = elem;
358
359 OSMO_ASSERT(ct);
360 if (!elem)
361 return -EINVAL;
362 if (len <= 0)
363 return -EINVAL;
364
365 memset(ct, 0, sizeof(*ct));
366
367 ct->ch_indctr = (*elem) & 0x0f;
368 elem++;
369 ct->ch_rate_type = (*elem) & 0x0f;
370 elem++;
371
372 for (i = 0; i < ARRAY_SIZE(ct->perm_spch); i++) {
373 byte = *elem;
374 elem++;
375 ct->perm_spch[i] = byte & 0x7f;
376 if ((byte & 0x80) == 0x00)
377 break;
378 }
379 ct->perm_spch_len = i + 1;
380
381 return (int)(elem - old_elem);
382}
Philipp Maier14e76b92017-03-28 18:36:52 +0200383
384/* Encode Encryption Information element */
385uint8_t gsm0808_enc_encrypt_info(struct msgb *msg,
386 const struct gsm0808_encrypt_info *ei)
387{
388 unsigned int i;
389 uint8_t perm_algo = 0;
390 uint8_t *ptr;
391 uint8_t *old_tail;
392 uint8_t *tlv_len;
393
394 OSMO_ASSERT(msg);
395 OSMO_ASSERT(ei);
396 OSMO_ASSERT(ei->key_len <= ARRAY_SIZE(ei->key));
397 OSMO_ASSERT(ei->perm_algo_len <= ENCRY_INFO_PERM_ALGO_MAXLEN);
398
399 msgb_put_u8(msg, GSM0808_IE_ENCRYPTION_INFORMATION);
400 tlv_len = msgb_put(msg, 1);
401 old_tail = msg->tail;
402
403 for (i = 0; i < ei->perm_algo_len; i++) {
404 /* Note: gsm_08_08.h defines the permitted algorithms
405 * as an enum which ranges from 0x01 to 0x08 */
406 OSMO_ASSERT(ei->perm_algo[i] != 0);
407 OSMO_ASSERT(ei->perm_algo[i] <= ENCRY_INFO_PERM_ALGO_MAXLEN);
408 perm_algo |= (1 << (ei->perm_algo[i] - 1));
409 }
410
411 msgb_put_u8(msg, perm_algo);
412 ptr = msgb_put(msg, ei->key_len);
413 memcpy(ptr, ei->key, ei->key_len);
414
415 *tlv_len = (uint8_t) (msg->tail - old_tail);
416 return *tlv_len + 2;
417}
418
419/* Decode Encryption Information element */
420int gsm0808_dec_encrypt_info(struct gsm0808_encrypt_info *ei,
421 const uint8_t *elem, uint8_t len)
422{
423 uint8_t perm_algo;
424 unsigned int i;
425 unsigned int perm_algo_len = 0;
426 const uint8_t *old_elem = elem;
427
428 OSMO_ASSERT(ei);
429 if (!elem)
430 return -EINVAL;
431 if (len <= 0)
432 return -EINVAL;
433
434 memset(ei, 0, sizeof(*ei));
435
436 perm_algo = *elem;
437 elem++;
438
439 for (i = 0; i < ENCRY_INFO_PERM_ALGO_MAXLEN; i++) {
440 if (perm_algo & (1 << i)) {
441 ei->perm_algo[perm_algo_len] = i + 1;
442 perm_algo_len++;
443 }
444 }
445 ei->perm_algo_len = perm_algo_len;
446
447 ei->key_len = len - 1;
448 memcpy(ei->key, elem, ei->key_len);
449 elem+=ei->key_len;
450
451 return (int)(elem - old_elem);
452}