blob: ef0f9431c02a36de21763071e40474f8225ab923 [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 Maier6f725d62017-03-24 18:03:17 +010036
Philipp Maier22401432017-03-24 17:59:26 +010037/* Encode AoIP transport address element */
38uint8_t gsm0808_enc_aoip_trasp_addr(struct msgb *msg,
39 const struct sockaddr_storage *ss)
40{
41 /* See also 3GPP TS 48.008 3.2.2.102 AoIP Transport Layer Address */
42 struct sockaddr_in *sin;
43 struct sockaddr_in6 *sin6;
44 uint16_t port = 0;
45 uint8_t *ptr;
46 uint8_t *old_tail;
47 uint8_t *tlv_len;
48
49 OSMO_ASSERT(msg);
50 OSMO_ASSERT(ss);
51 OSMO_ASSERT(ss->ss_family == AF_INET || ss->ss_family == AF_INET6);
52
53 msgb_put_u8(msg, GSM0808_IE_AOIP_TRASP_ADDR);
54 tlv_len = msgb_put(msg,1);
55 old_tail = msg->tail;
56
57 switch (ss->ss_family) {
58 case AF_INET:
59 sin = (struct sockaddr_in *)ss;
60 port = ntohs(sin->sin_port);
61 ptr = msgb_put(msg, IP_V4_ADDR_LEN);
62 memcpy(ptr, &sin->sin_addr.s_addr, IP_V4_ADDR_LEN);
63 break;
64 case AF_INET6:
65 sin6 = (struct sockaddr_in6 *)ss;
66 port = ntohs(sin6->sin6_port);
67 ptr = msgb_put(msg, IP_V6_ADDR_LEN);
68 memcpy(ptr, sin6->sin6_addr.s6_addr, IP_V6_ADDR_LEN);
69 break;
70 }
71
72 msgb_put_u16(msg, port);
73
74 *tlv_len = (uint8_t) (msg->tail - old_tail);
75 return *tlv_len + 2;
76}
77
78/* Decode AoIP transport address element */
79int gsm0808_dec_aoip_trasp_addr(struct sockaddr_storage *ss,
80 const uint8_t *elem, uint8_t len)
81{
82 /* See also 3GPP TS 48.008 3.2.2.102 AoIP Transport Layer Address */
83 struct sockaddr_in sin;
84 struct sockaddr_in6 sin6;
85 const uint8_t *old_elem = elem;
86
87 OSMO_ASSERT(ss);
88 if (!elem)
89 return -EINVAL;
90 if (len <= 0)
91 return -EINVAL;
92
93 memset(ss, 0, sizeof(*ss));
94
95 switch (len) {
96 case IP_V4_ADDR_LEN + IP_PORT_LEN:
97 memset(&sin, 0, sizeof(sin));
98 sin.sin_family = AF_INET;
99
100 memcpy(&sin.sin_addr.s_addr, elem, IP_V4_ADDR_LEN);
101 elem += IP_V4_ADDR_LEN;
102 sin.sin_port = osmo_load16le(elem);
103 elem += IP_PORT_LEN;
104
105 memcpy(ss, &sin, sizeof(sin));
106 break;
107 case IP_V6_ADDR_LEN + IP_PORT_LEN:
108 memset(&sin6, 0, sizeof(sin6));
109 sin6.sin6_family = AF_INET6;
110
111 memcpy(sin6.sin6_addr.s6_addr, elem, IP_V6_ADDR_LEN);
112 elem += IP_V6_ADDR_LEN;
113 sin6.sin6_port = osmo_load16le(elem);
114 elem += IP_PORT_LEN;
115
116 memcpy(ss, &sin6, sizeof(sin6));
117 break;
118 default:
119 /* Malformed element! */
120 return -EINVAL;
121 break;
122 }
123
124 return (int)(elem - old_elem);
125}
Philipp Maier6f725d62017-03-24 18:03:17 +0100126
127/* Helper function for gsm0808_enc_speech_codec()
128 * and gsm0808_enc_speech_codec_list() */
129static uint8_t enc_speech_codec(struct msgb *msg,
130 const struct gsm0808_speech_codec *sc)
131{
132 /* See also 3GPP TS 48.008 3.2.2.103 Speech Codec List */
133 uint8_t header = 0;
134 uint8_t *old_tail;
135
136 old_tail = msg->tail;
137
138 if (sc->fi)
139 header |= (1 << 7);
140 if (sc->pi)
141 header |= (1 << 6);
142 if (sc->pt)
143 header |= (1 << 5);
144 if (sc->tf)
145 header |= (1 << 4);
146 if (sc->type_extended) {
147 header |= 0x0f;
148 msgb_put_u8(msg, header);
149 } else {
150 OSMO_ASSERT(sc->type < 0x0f);
151 header |= sc->type;
152 msgb_put_u8(msg, header);
153 return (uint8_t) (msg->tail - old_tail);
154 }
155
156 msgb_put_u8(msg, sc->type);
157
158 if (sc->cfg_present)
159 msgb_put_u16(msg, sc->cfg);
160
161 return (uint8_t) (msg->tail - old_tail);
162}
163
164/* Encode Speech Codec element */
165uint8_t gsm0808_enc_speech_codec(struct msgb *msg,
166 const struct gsm0808_speech_codec *sc)
167{
168 uint8_t *old_tail;
169 uint8_t *tlv_len;
170
171 OSMO_ASSERT(msg);
172 OSMO_ASSERT(sc);
173
174 msgb_put_u8(msg, GSM0808_IE_SPEECH_CODEC);
175 tlv_len = msgb_put(msg, 1);
176 old_tail = msg->tail;
177
178 enc_speech_codec(msg, sc);
179
180 *tlv_len = (uint8_t) (msg->tail - old_tail);
181 return *tlv_len + 2;
182}
183
184/* Decode Speech Codec element */
185int gsm0808_dec_speech_codec(struct gsm0808_speech_codec *sc,
186 const uint8_t *elem, uint8_t len)
187{
188 /* See also 3GPP TS 48.008 3.2.2.103 Speech Codec List */
189 uint8_t header;
190 const uint8_t *old_elem = elem;
191
192 OSMO_ASSERT(sc);
193 if (!elem)
194 return -EINVAL;
195 if (len <= 0)
196 return -EINVAL;
197
198 memset(sc, 0, sizeof(*sc));
199
200 header = *elem;
201
202 /* Malformed elements */
203 if ((header & 0x0F) == 0x0F && len < 2)
204 return -EINVAL;
205 else if ((header & 0x0F) != 0x0F && len < 1)
206 return -EINVAL;
207
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}