blob: eef6146d93dada90cd021e194db7aea4d8815d3f [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 Maier6f725d62017-03-24 18:03:17 +010034
Philipp Maier22401432017-03-24 17:59:26 +010035/* Encode AoIP transport address element */
36uint8_t gsm0808_enc_aoip_trasp_addr(struct msgb *msg,
37 const struct sockaddr_storage *ss)
38{
39 /* See also 3GPP TS 48.008 3.2.2.102 AoIP Transport Layer Address */
40 struct sockaddr_in *sin;
41 struct sockaddr_in6 *sin6;
42 uint16_t port = 0;
43 uint8_t *ptr;
44 uint8_t *old_tail;
45 uint8_t *tlv_len;
46
47 OSMO_ASSERT(msg);
48 OSMO_ASSERT(ss);
49 OSMO_ASSERT(ss->ss_family == AF_INET || ss->ss_family == AF_INET6);
50
51 msgb_put_u8(msg, GSM0808_IE_AOIP_TRASP_ADDR);
52 tlv_len = msgb_put(msg,1);
53 old_tail = msg->tail;
54
55 switch (ss->ss_family) {
56 case AF_INET:
57 sin = (struct sockaddr_in *)ss;
58 port = ntohs(sin->sin_port);
59 ptr = msgb_put(msg, IP_V4_ADDR_LEN);
60 memcpy(ptr, &sin->sin_addr.s_addr, IP_V4_ADDR_LEN);
61 break;
62 case AF_INET6:
63 sin6 = (struct sockaddr_in6 *)ss;
64 port = ntohs(sin6->sin6_port);
65 ptr = msgb_put(msg, IP_V6_ADDR_LEN);
66 memcpy(ptr, sin6->sin6_addr.s6_addr, IP_V6_ADDR_LEN);
67 break;
68 }
69
70 msgb_put_u16(msg, port);
71
72 *tlv_len = (uint8_t) (msg->tail - old_tail);
73 return *tlv_len + 2;
74}
75
76/* Decode AoIP transport address element */
77int gsm0808_dec_aoip_trasp_addr(struct sockaddr_storage *ss,
78 const uint8_t *elem, uint8_t len)
79{
80 /* See also 3GPP TS 48.008 3.2.2.102 AoIP Transport Layer Address */
81 struct sockaddr_in sin;
82 struct sockaddr_in6 sin6;
83 const uint8_t *old_elem = elem;
84
85 OSMO_ASSERT(ss);
86 if (!elem)
87 return -EINVAL;
88 if (len <= 0)
89 return -EINVAL;
90
91 memset(ss, 0, sizeof(*ss));
92
93 switch (len) {
94 case IP_V4_ADDR_LEN + IP_PORT_LEN:
95 memset(&sin, 0, sizeof(sin));
96 sin.sin_family = AF_INET;
97
98 memcpy(&sin.sin_addr.s_addr, elem, IP_V4_ADDR_LEN);
99 elem += IP_V4_ADDR_LEN;
100 sin.sin_port = osmo_load16le(elem);
101 elem += IP_PORT_LEN;
102
103 memcpy(ss, &sin, sizeof(sin));
104 break;
105 case IP_V6_ADDR_LEN + IP_PORT_LEN:
106 memset(&sin6, 0, sizeof(sin6));
107 sin6.sin6_family = AF_INET6;
108
109 memcpy(sin6.sin6_addr.s6_addr, elem, IP_V6_ADDR_LEN);
110 elem += IP_V6_ADDR_LEN;
111 sin6.sin6_port = osmo_load16le(elem);
112 elem += IP_PORT_LEN;
113
114 memcpy(ss, &sin6, sizeof(sin6));
115 break;
116 default:
117 /* Malformed element! */
118 return -EINVAL;
119 break;
120 }
121
122 return (int)(elem - old_elem);
123}
Philipp Maier6f725d62017-03-24 18:03:17 +0100124
125/* Helper function for gsm0808_enc_speech_codec()
126 * and gsm0808_enc_speech_codec_list() */
127static uint8_t enc_speech_codec(struct msgb *msg,
128 const struct gsm0808_speech_codec *sc)
129{
130 /* See also 3GPP TS 48.008 3.2.2.103 Speech Codec List */
131 uint8_t header = 0;
132 uint8_t *old_tail;
133
134 old_tail = msg->tail;
135
136 if (sc->fi)
137 header |= (1 << 7);
138 if (sc->pi)
139 header |= (1 << 6);
140 if (sc->pt)
141 header |= (1 << 5);
142 if (sc->tf)
143 header |= (1 << 4);
144 if (sc->type_extended) {
145 header |= 0x0f;
146 msgb_put_u8(msg, header);
147 } else {
148 OSMO_ASSERT(sc->type < 0x0f);
149 header |= sc->type;
150 msgb_put_u8(msg, header);
151 return (uint8_t) (msg->tail - old_tail);
152 }
153
154 msgb_put_u8(msg, sc->type);
155
156 if (sc->cfg_present)
157 msgb_put_u16(msg, sc->cfg);
158
159 return (uint8_t) (msg->tail - old_tail);
160}
161
162/* Encode Speech Codec element */
163uint8_t gsm0808_enc_speech_codec(struct msgb *msg,
164 const struct gsm0808_speech_codec *sc)
165{
166 uint8_t *old_tail;
167 uint8_t *tlv_len;
168
169 OSMO_ASSERT(msg);
170 OSMO_ASSERT(sc);
171
172 msgb_put_u8(msg, GSM0808_IE_SPEECH_CODEC);
173 tlv_len = msgb_put(msg, 1);
174 old_tail = msg->tail;
175
176 enc_speech_codec(msg, sc);
177
178 *tlv_len = (uint8_t) (msg->tail - old_tail);
179 return *tlv_len + 2;
180}
181
182/* Decode Speech Codec element */
183int gsm0808_dec_speech_codec(struct gsm0808_speech_codec *sc,
184 const uint8_t *elem, uint8_t len)
185{
186 /* See also 3GPP TS 48.008 3.2.2.103 Speech Codec List */
187 uint8_t header;
188 const uint8_t *old_elem = elem;
189
190 OSMO_ASSERT(sc);
191 if (!elem)
192 return -EINVAL;
193 if (len <= 0)
194 return -EINVAL;
195
196 memset(sc, 0, sizeof(*sc));
197
198 header = *elem;
199
200 /* Malformed elements */
201 if ((header & 0x0F) == 0x0F && len < 2)
202 return -EINVAL;
203 else if ((header & 0x0F) != 0x0F && len < 1)
204 return -EINVAL;
205
206 elem++;
207 len--;
208
209 if (header & (1 << 7))
210 sc->fi = true;
211 if (header & (1 << 6))
212 sc->pi = true;
213 if (header & (1 << 5))
214 sc->pt = true;
215 if (header & (1 << 4))
216 sc->tf = true;
217
218 if ((header & 0x0F) != 0x0F) {
219 sc->type = (header & 0x0F);
220 return (int)(elem - old_elem);
221 }
222
223 sc->type = *elem;
224 elem++;
225 len--;
226
227 sc->type_extended = true;
228
229 if (len < 2)
230 return (int)(elem - old_elem);
231
232 sc->cfg = osmo_load16be(elem);
233 elem += 2;
234 sc->cfg_present = true;
235
236 return (int)(elem - old_elem);
237}
238
239/* Encode Speech Codec list */
240uint8_t gsm0808_enc_speech_codec_list(struct msgb *msg,
241 const struct gsm0808_speech_codec_list *scl)
242{
243 uint8_t *old_tail;
244 uint8_t *tlv_len;
245 unsigned int i;
246 uint8_t rc;
247 unsigned int bytes_used = 0;
248
249 OSMO_ASSERT(msg);
250 OSMO_ASSERT(scl);
251
252 /* Empty list */
253 OSMO_ASSERT(scl->len >= 1);
254
255 msgb_put_u8(msg, GSM0808_IE_SPEECH_CODEC_LIST);
256 tlv_len = msgb_put(msg, 1);
257 old_tail = msg->tail;
258
259 for (i = 0; i < scl->len; i++) {
260 rc = enc_speech_codec(msg, &scl->codec[i]);
261 OSMO_ASSERT(rc >= 1);
262 bytes_used += rc;
263 OSMO_ASSERT(bytes_used <= 255);
264 }
265
266 *tlv_len = (uint8_t) (msg->tail - old_tail);
267 return *tlv_len + 2;
268}
269
270/* Decode Speech Codec list */
271int gsm0808_dec_speech_codec_list(struct gsm0808_speech_codec_list *scl,
272 const uint8_t *elem, uint8_t len)
273{
274 const uint8_t *old_elem = elem;
275 unsigned int i;
276 int rc;
277 uint8_t decoded = 0;
278
279 OSMO_ASSERT(scl);
280 if (!elem)
281 return -EINVAL;
282 if (len <= 0)
283 return -EINVAL;
284
285 memset(scl, 0, sizeof(*scl));
286
287 for (i = 0; i < ARRAY_SIZE(scl->codec); i++) {
288 if (len <= 0)
289 break;
290
291 rc = gsm0808_dec_speech_codec(&scl->codec[i], elem, len);
292 if (rc < 1)
293 return -EINVAL;
294
295 elem+=rc;
296 len -= rc;
297 decoded++;
298 }
299
300 scl->len = decoded;
301
302 /* Empty list */
303 if (decoded < 1) {
304 return -EINVAL;
305 }
306
307 return (int)(elem - old_elem);
308}