blob: 9251dec978b01632a7370a2276c63c3d3766476b [file] [log] [blame]
Harald Welte0b0bbce2009-07-28 00:01:58 +02001/* RTP proxy handling for ip.access nanoBTS */
2
Harald Welte9a696d72013-02-03 12:06:58 +01003/* (C) 2009-2013 by Harald Welte <laforge@gnumonks.org>
Harald Welte0b0bbce2009-07-28 00:01:58 +02004 * All Rights Reserved
5 *
6 * This program is free software; you can redistribute it and/or modify
Harald Welte0e3e88e2011-01-01 15:25:50 +01007 * 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
Harald Welte0b0bbce2009-07-28 00:01:58 +02009 * (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
Harald Welte0e3e88e2011-01-01 15:25:50 +010014 * GNU Affero General Public License for more details.
Harald Welte0b0bbce2009-07-28 00:01:58 +020015 *
Harald Welte0e3e88e2011-01-01 15:25:50 +010016 * 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/>.
Harald Welte0b0bbce2009-07-28 00:01:58 +020018 *
19 */
20
21#include <errno.h>
22#include <unistd.h>
23#include <sys/socket.h>
24#include <netinet/in.h>
Harald Welte3c062072009-07-28 18:25:29 +020025#include <arpa/inet.h>
Harald Welte3971ad52009-12-19 22:23:05 +010026#include <sys/time.h> /* gettimeofday() */
27#include <unistd.h> /* get..() */
28#include <time.h> /* clock() */
29#include <sys/utsname.h> /* uname() */
Harald Welte0b0bbce2009-07-28 00:01:58 +020030
Pablo Neira Ayusodd5fff42011-03-22 16:47:59 +010031#include <osmocom/core/talloc.h>
Harald Welte0b0bbce2009-07-28 00:01:58 +020032#include <openbsc/gsm_data.h>
Pablo Neira Ayusodd5fff42011-03-22 16:47:59 +010033#include <osmocom/core/msgb.h>
34#include <osmocom/core/select.h>
Harald Welte3c062072009-07-28 18:25:29 +020035#include <openbsc/debug.h>
Harald Welte0b0bbce2009-07-28 00:01:58 +020036#include <openbsc/rtp_proxy.h>
Harald Welte28dce912011-05-24 13:25:38 +020037#include <openbsc/mncc.h>
Alexander Huemer45a00142011-09-06 00:09:49 +020038#include <openbsc/trau_upqueue.h>
Harald Welte0b0bbce2009-07-28 00:01:58 +020039
Holger Hans Peter Freyther19f4aa52010-10-12 15:39:46 +020040/* attempt to determine byte order */
Holger Hans Peter Freyther19f4aa52010-10-12 15:39:46 +020041#include <sys/param.h>
42#include <limits.h>
43
44#ifndef __BYTE_ORDER
Tobias Engel82c64c92012-10-24 17:53:50 +020045# ifdef __APPLE__
46# define __BYTE_ORDER __DARWIN_BYTE_ORDER
47# define __LITTLE_ENDIAN __DARWIN_LITTLE_ENDIAN
48# define __BIG_ENDIAN __DARWIN_BIG_ENDIAN
49# else
50# error "__BYTE_ORDER should be defined by someone"
51# endif
Holger Hans Peter Freyther19f4aa52010-10-12 15:39:46 +020052#endif
53
Harald Welte0b0bbce2009-07-28 00:01:58 +020054static LLIST_HEAD(rtp_sockets);
55
Harald Welte3c062072009-07-28 18:25:29 +020056/* should we mangle the CNAME inside SDES of RTCP packets? We disable
57 * this by default, as it seems to be not needed */
58static int mangle_rtcp_cname = 0;
59
Harald Welte0b0bbce2009-07-28 00:01:58 +020060enum rtp_bfd_priv {
61 RTP_PRIV_NONE,
62 RTP_PRIV_RTP,
63 RTP_PRIV_RTCP
64};
65
66#define RTP_ALLOC_SIZE 1500
67
Harald Welte3c062072009-07-28 18:25:29 +020068/* according to RFC 1889 */
69struct rtcp_hdr {
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +020070 uint8_t byte0;
71 uint8_t type;
72 uint16_t length;
Harald Welte3c062072009-07-28 18:25:29 +020073} __attribute__((packed));
74
75#define RTCP_TYPE_SDES 202
76
77#define RTCP_IE_CNAME 1
78
Harald Welte3971ad52009-12-19 22:23:05 +010079/* according to RFC 3550 */
80struct rtp_hdr {
Holger Hans Peter Freyther6037ee92010-02-26 13:12:41 +010081#if __BYTE_ORDER == __LITTLE_ENDIAN
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +020082 uint8_t csrc_count:4,
Harald Welte3971ad52009-12-19 22:23:05 +010083 extension:1,
84 padding:1,
85 version:2;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +020086 uint8_t payload_type:7,
Harald Welte3971ad52009-12-19 22:23:05 +010087 marker:1;
Holger Hans Peter Freyther6037ee92010-02-26 13:12:41 +010088#elif __BYTE_ORDER == __BIG_ENDIAN
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +020089 uint8_t version:2,
Holger Hans Peter Freyther6037ee92010-02-26 13:12:41 +010090 padding:1,
91 extension:1,
92 csrc_count:4;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +020093 uint8_t marker:1,
Holger Hans Peter Freyther6037ee92010-02-26 13:12:41 +010094 payload_type:7;
95#endif
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +020096 uint16_t sequence;
97 uint32_t timestamp;
98 uint32_t ssrc;
Harald Welte3971ad52009-12-19 22:23:05 +010099} __attribute__((packed));
100
101struct rtp_x_hdr {
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200102 uint16_t by_profile;
103 uint16_t length;
Harald Welte3971ad52009-12-19 22:23:05 +0100104} __attribute__((packed));
105
106#define RTP_VERSION 2
107
Harald Welteadab89c2014-05-17 13:43:01 +0200108/* 33 for FR, all other codecs have smaller size */
109#define MAX_RTP_PAYLOAD_LEN 33
110
Harald Welte3971ad52009-12-19 22:23:05 +0100111/* decode an rtp frame and create a new buffer with payload */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200112static int rtp_decode(struct msgb *msg, uint32_t callref, struct msgb **data)
Harald Welte3971ad52009-12-19 22:23:05 +0100113{
114 struct msgb *new_msg;
115 struct gsm_data_frame *frame;
116 struct rtp_hdr *rtph = (struct rtp_hdr *)msg->data;
117 struct rtp_x_hdr *rtpxh;
Harald Welteadab89c2014-05-17 13:43:01 +0200118 uint8_t *payload, *payload_out;
Harald Welte3971ad52009-12-19 22:23:05 +0100119 int payload_len;
120 int msg_type;
121 int x_len;
122
123 if (msg->len < 12) {
Pablo Neira Ayuso42e41df2011-08-17 22:44:07 +0200124 DEBUGPC(DLMUX, "received RTP frame too short (len = %d)\n",
Harald Welte3971ad52009-12-19 22:23:05 +0100125 msg->len);
126 return -EINVAL;
127 }
128 if (rtph->version != RTP_VERSION) {
Pablo Neira Ayuso42e41df2011-08-17 22:44:07 +0200129 DEBUGPC(DLMUX, "received RTP version %d not supported.\n",
Harald Welte3971ad52009-12-19 22:23:05 +0100130 rtph->version);
131 return -EINVAL;
132 }
133 payload = msg->data + sizeof(struct rtp_hdr) + (rtph->csrc_count << 2);
134 payload_len = msg->len - sizeof(struct rtp_hdr) - (rtph->csrc_count << 2);
135 if (payload_len < 0) {
Pablo Neira Ayuso42e41df2011-08-17 22:44:07 +0200136 DEBUGPC(DLMUX, "received RTP frame too short (len = %d, "
Harald Welte3971ad52009-12-19 22:23:05 +0100137 "csrc count = %d)\n", msg->len, rtph->csrc_count);
138 return -EINVAL;
139 }
140 if (rtph->extension) {
141 if (payload_len < sizeof(struct rtp_x_hdr)) {
Pablo Neira Ayuso42e41df2011-08-17 22:44:07 +0200142 DEBUGPC(DLMUX, "received RTP frame too short for "
Harald Welte3971ad52009-12-19 22:23:05 +0100143 "extension header\n");
144 return -EINVAL;
145 }
146 rtpxh = (struct rtp_x_hdr *)payload;
147 x_len = ntohs(rtpxh->length) * 4 + sizeof(struct rtp_x_hdr);
148 payload += x_len;
149 payload_len -= x_len;
150 if (payload_len < 0) {
Pablo Neira Ayuso42e41df2011-08-17 22:44:07 +0200151 DEBUGPC(DLMUX, "received RTP frame too short, "
Harald Welte3971ad52009-12-19 22:23:05 +0100152 "extension header exceeds frame length\n");
153 return -EINVAL;
154 }
155 }
156 if (rtph->padding) {
Jacob Erlbeckb99fee12013-11-21 19:05:42 +0100157 if (payload_len < 1) {
Pablo Neira Ayuso42e41df2011-08-17 22:44:07 +0200158 DEBUGPC(DLMUX, "received RTP frame too short for "
Harald Welte3971ad52009-12-19 22:23:05 +0100159 "padding length\n");
160 return -EINVAL;
161 }
162 payload_len -= payload[payload_len - 1];
163 if (payload_len < 0) {
Pablo Neira Ayuso42e41df2011-08-17 22:44:07 +0200164 DEBUGPC(DLMUX, "received RTP frame with padding "
Harald Welte3971ad52009-12-19 22:23:05 +0100165 "greater than payload\n");
166 return -EINVAL;
167 }
168 }
169
170 switch (rtph->payload_type) {
171 case RTP_PT_GSM_FULL:
172 msg_type = GSM_TCHF_FRAME;
Andreas Eversberg4371c562014-01-22 10:05:51 +0100173 if (payload_len != RTP_LEN_GSM_FULL) {
Pablo Neira Ayuso42e41df2011-08-17 22:44:07 +0200174 DEBUGPC(DLMUX, "received RTP full rate frame with "
Andreas Eversberg4371c562014-01-22 10:05:51 +0100175 "payload length != %d (len = %d)\n",
176 RTP_LEN_GSM_FULL, payload_len);
Harald Welte3971ad52009-12-19 22:23:05 +0100177 return -EINVAL;
178 }
179 break;
Harald Welted3d68ad2009-12-19 23:06:41 +0100180 case RTP_PT_GSM_EFR:
181 msg_type = GSM_TCHF_FRAME_EFR;
Andreas Eversberg4371c562014-01-22 10:05:51 +0100182 if (payload_len != RTP_LEN_GSM_EFR) {
183 DEBUGPC(DLMUX, "received RTP extended full rate frame "
184 "with payload length != %d (len = %d)\n",
185 RTP_LEN_GSM_EFR, payload_len);
186 return -EINVAL;
187 }
Harald Welted3d68ad2009-12-19 23:06:41 +0100188 break;
Andreas Eversberg39ff0842014-01-17 19:06:38 +0100189 case RTP_PT_GSM_HALF:
190 msg_type = GSM_TCHH_FRAME;
191 if (payload_len != RTP_LEN_GSM_HALF) {
192 DEBUGPC(DLMUX, "received RTP half rate frame with "
193 "payload length != %d (len = %d)\n",
194 RTP_LEN_GSM_HALF, payload_len);
195 return -EINVAL;
196 }
197 break;
Andreas Eversberga3773f62012-03-08 14:39:19 +0100198 case RTP_PT_AMR:
199 break;
Harald Welte3971ad52009-12-19 22:23:05 +0100200 default:
Pablo Neira Ayuso42e41df2011-08-17 22:44:07 +0200201 DEBUGPC(DLMUX, "received RTP frame with unknown payload "
Harald Welte3971ad52009-12-19 22:23:05 +0100202 "type %d\n", rtph->payload_type);
203 return -EINVAL;
204 }
205
Harald Welteadab89c2014-05-17 13:43:01 +0200206 if (payload_len > MAX_RTP_PAYLOAD_LEN) {
Andreas Eversberga3773f62012-03-08 14:39:19 +0100207 DEBUGPC(DLMUX, "RTP payload too large (%d octets)\n",
208 payload_len);
209 return -EINVAL;
210 }
211
Harald Welteadab89c2014-05-17 13:43:01 +0200212 /* always allocate for the maximum possible size to avoid
213 * fragmentation */
214 new_msg = msgb_alloc(sizeof(struct gsm_data_frame) +
215 MAX_RTP_PAYLOAD_LEN, "GSM-DATA (TCH)");
216
Harald Welte3971ad52009-12-19 22:23:05 +0100217 if (!new_msg)
218 return -ENOMEM;
Harald Welteadab89c2014-05-17 13:43:01 +0200219 frame = msgb_put(new_msg, sizeof(struct gsm_data_frame));
Harald Welte3971ad52009-12-19 22:23:05 +0100220 frame->msg_type = msg_type;
221 frame->callref = callref;
Andreas Eversberga3773f62012-03-08 14:39:19 +0100222 if (rtph->payload_type == RTP_PT_AMR) {
Harald Welteadab89c2014-05-17 13:43:01 +0200223 /* for FR/HR/EFR the length is implicit. In AMR, we
224 * need to make it explicit by using the first byte of
225 * the data[] buffer as length byte */
226 uint8_t *data0 = msgb_put(new_msg, 1);
227 *data0 = payload_len;
Andreas Eversberga3773f62012-03-08 14:39:19 +0100228 }
Harald Welteadab89c2014-05-17 13:43:01 +0200229 payload_out = msgb_put(new_msg, payload_len);
230 memcpy(payload_out, payload, payload_len);
Harald Welte3971ad52009-12-19 22:23:05 +0100231
232 *data = new_msg;
233 return 0;
234}
235
Harald Welte51cc1bb2009-12-20 13:16:14 +0100236/* "to - from" */
237static void tv_difference(struct timeval *diff, const struct timeval *from,
238 const struct timeval *__to)
239{
240 struct timeval _to = *__to, *to = &_to;
241
242 if (to->tv_usec < from->tv_usec) {
243 to->tv_sec -= 1;
244 to->tv_usec += 1000000;
245 }
246
247 diff->tv_usec = to->tv_usec - from->tv_usec;
248 diff->tv_sec = to->tv_sec - from->tv_sec;
249}
250
Harald Welte9a696d72013-02-03 12:06:58 +0100251/*! \brief encode and send a rtp frame
252 * \param[in] rs RTP socket through which we shall send
253 * \param[in] frame GSM RTP frame to be sent
254 */
Harald Welte3971ad52009-12-19 22:23:05 +0100255int rtp_send_frame(struct rtp_socket *rs, struct gsm_data_frame *frame)
256{
257 struct rtp_sub_socket *rss = &rs->rtp;
258 struct msgb *msg;
259 struct rtp_hdr *rtph;
Harald Welteadab89c2014-05-17 13:43:01 +0200260 uint8_t *payload;
Harald Welte3971ad52009-12-19 22:23:05 +0100261 int payload_type;
262 int payload_len;
263 int duration; /* in samples */
264
265 if (rs->tx_action != RTP_SEND_DOWNSTREAM) {
266 /* initialize sequences */
267 rs->tx_action = RTP_SEND_DOWNSTREAM;
268 rs->transmit.ssrc = rand();
269 rs->transmit.sequence = random();
270 rs->transmit.timestamp = random();
271 }
272
273 switch (frame->msg_type) {
274 case GSM_TCHF_FRAME:
275 payload_type = RTP_PT_GSM_FULL;
Andreas Eversberg4371c562014-01-22 10:05:51 +0100276 payload_len = RTP_LEN_GSM_FULL;
277 duration = RTP_GSM_DURATION;
Harald Welte3971ad52009-12-19 22:23:05 +0100278 break;
Harald Welted3d68ad2009-12-19 23:06:41 +0100279 case GSM_TCHF_FRAME_EFR:
280 payload_type = RTP_PT_GSM_EFR;
Andreas Eversberg4371c562014-01-22 10:05:51 +0100281 payload_len = RTP_LEN_GSM_EFR;
282 duration = RTP_GSM_DURATION;
Harald Welted3d68ad2009-12-19 23:06:41 +0100283 break;
Andreas Eversberg39ff0842014-01-17 19:06:38 +0100284 case GSM_TCHH_FRAME:
285 payload_type = RTP_PT_GSM_HALF;
286 payload_len = RTP_LEN_GSM_HALF;
287 duration = RTP_GSM_DURATION;
288 break;
Andreas Eversberga3773f62012-03-08 14:39:19 +0100289 case GSM_TCH_FRAME_AMR:
290 payload_type = RTP_PT_AMR;
291 payload_len = frame->data[0];
292 duration = RTP_GSM_DURATION;
293 break;
Harald Welte3971ad52009-12-19 22:23:05 +0100294 default:
Pablo Neira Ayuso42e41df2011-08-17 22:44:07 +0200295 DEBUGPC(DLMUX, "unsupported message type %d\n",
Harald Welte3971ad52009-12-19 22:23:05 +0100296 frame->msg_type);
297 return -EINVAL;
298 }
299
Harald Welte51cc1bb2009-12-20 13:16:14 +0100300 {
301 struct timeval tv, tv_diff;
302 long int usec_diff, frame_diff;
303
304 gettimeofday(&tv, NULL);
305 tv_difference(&tv_diff, &rs->transmit.last_tv, &tv);
306 rs->transmit.last_tv = tv;
307
308 usec_diff = tv_diff.tv_sec * 1000000 + tv_diff.tv_usec;
309 frame_diff = (usec_diff / 20000);
310
311 if (abs(frame_diff) > 1) {
312 long int frame_diff_excess = frame_diff - 1;
313
Pablo Neira Ayuso42e41df2011-08-17 22:44:07 +0200314 LOGP(DLMUX, LOGL_NOTICE,
Harald Welte (local)3a212392009-12-27 17:01:40 +0100315 "Correcting frame difference of %ld frames\n", frame_diff_excess);
Harald Welte51cc1bb2009-12-20 13:16:14 +0100316 rs->transmit.sequence += frame_diff_excess;
317 rs->transmit.timestamp += frame_diff_excess * duration;
318 }
319 }
320
Harald Welteadab89c2014-05-17 13:43:01 +0200321 if (payload_len > MAX_RTP_PAYLOAD_LEN) {
Andreas Eversberga3773f62012-03-08 14:39:19 +0100322 DEBUGPC(DLMUX, "RTP payload too large (%d octets)\n",
323 payload_len);
324 return -EINVAL;
325 }
326
Harald Welteadab89c2014-05-17 13:43:01 +0200327 msg = msgb_alloc(sizeof(struct rtp_hdr) + payload_len, "RTP-GSM");
Harald Welte3971ad52009-12-19 22:23:05 +0100328 if (!msg)
329 return -ENOMEM;
Harald Welteadab89c2014-05-17 13:43:01 +0200330 rtph = (struct rtp_hdr *) msgb_put(msg, sizeof(struct rtp_hdr));
Harald Welte3971ad52009-12-19 22:23:05 +0100331 rtph->version = RTP_VERSION;
332 rtph->padding = 0;
333 rtph->extension = 0;
334 rtph->csrc_count = 0;
335 rtph->marker = 0;
336 rtph->payload_type = payload_type;
337 rtph->sequence = htons(rs->transmit.sequence++);
338 rtph->timestamp = htonl(rs->transmit.timestamp);
339 rs->transmit.timestamp += duration;
340 rtph->ssrc = htonl(rs->transmit.ssrc);
Harald Welteadab89c2014-05-17 13:43:01 +0200341
342 payload = msgb_put(msg, payload_len);
Andreas Eversberga3773f62012-03-08 14:39:19 +0100343 if (frame->msg_type == GSM_TCH_FRAME_AMR)
Harald Welteadab89c2014-05-17 13:43:01 +0200344 memcpy(payload, frame->data + 1, payload_len);
Andreas Eversberga3773f62012-03-08 14:39:19 +0100345 else
Harald Welteadab89c2014-05-17 13:43:01 +0200346 memcpy(payload, frame->data, payload_len);
Harald Welte3971ad52009-12-19 22:23:05 +0100347 msgb_enqueue(&rss->tx_queue, msg);
348 rss->bfd.when |= BSC_FD_WRITE;
349
350 return 0;
351}
352
Holger Hans Peter Freyther0168dc12009-07-29 06:46:26 +0200353/* iterate over all chunks in one RTCP message, look for CNAME IEs and
Harald Welte3c062072009-07-28 18:25:29 +0200354 * replace all of those with 'new_cname' */
355static int rtcp_sdes_cname_mangle(struct msgb *msg, struct rtcp_hdr *rh,
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200356 uint16_t *rtcp_len, const char *new_cname)
Harald Welte3c062072009-07-28 18:25:29 +0200357{
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200358 uint8_t *rtcp_end;
359 uint8_t *cur = (uint8_t *) rh;
360 uint8_t tag, len = 0;
Harald Welte3c062072009-07-28 18:25:29 +0200361
362 rtcp_end = cur + *rtcp_len;
363 /* move cur to end of RTP header */
Harald Welte6977a292009-07-29 10:46:41 +0200364 cur += sizeof(*rh);
Harald Welte3c062072009-07-28 18:25:29 +0200365
366 /* iterate over Chunks */
367 while (cur+4 < rtcp_end) {
368 /* skip four bytes SSRC/CSRC */
369 cur += 4;
370
371 /* iterate over IE's inside the chunk */
372 while (cur+1 < rtcp_end) {
373 tag = *cur++;
374 if (tag == 0) {
375 /* end of chunk, skip additional zero */
376 while (*cur++ == 0) { }
377 break;
378 }
379 len = *cur++;
380
381 if (tag == RTCP_IE_CNAME) {
382 /* we've found the CNAME, lets mangle it */
383 if (len < strlen(new_cname)) {
384 /* we need to make more space */
385 int increase = strlen(new_cname) - len;
386
387 msgb_push(msg, increase);
388 memmove(cur+len+increase, cur+len,
389 rtcp_end - (cur+len));
390 /* FIXME: we have to respect RTCP
391 * padding/alignment rules! */
392 len += increase;
393 *(cur-1) += increase;
394 rtcp_end += increase;
395 *rtcp_len += increase;
396 }
397 /* copy new CNAME into message */
398 memcpy(cur, new_cname, strlen(new_cname));
399 /* FIXME: zero the padding in case new CNAME
400 * is smaller than old one !!! */
401 }
402 cur += len;
403 }
404 }
405
406 return 0;
407}
408
409static int rtcp_mangle(struct msgb *msg, struct rtp_socket *rs)
410{
411 struct rtp_sub_socket *rss = &rs->rtcp;
412 struct rtcp_hdr *rtph;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200413 uint16_t old_len;
Harald Welte3c062072009-07-28 18:25:29 +0200414 int rc;
415
416 if (!mangle_rtcp_cname)
417 return 0;
418
Harald Welte3971ad52009-12-19 22:23:05 +0100419 printf("RTCP\n");
Harald Welte3c062072009-07-28 18:25:29 +0200420 /* iterate over list of RTCP messages */
421 rtph = (struct rtcp_hdr *)msg->data;
Harald Welte3971ad52009-12-19 22:23:05 +0100422 while ((void *)rtph + sizeof(*rtph) <= (void *)msg->data + msg->len) {
Harald Welte3c062072009-07-28 18:25:29 +0200423 old_len = (ntohs(rtph->length) + 1) * 4;
Harald Welte3971ad52009-12-19 22:23:05 +0100424 if ((void *)rtph + old_len > (void *)msg->data + msg->len) {
Pablo Neira Ayuso42e41df2011-08-17 22:44:07 +0200425 DEBUGPC(DLMUX, "received RTCP packet too short for "
Harald Welte3971ad52009-12-19 22:23:05 +0100426 "length element\n");
427 return -EINVAL;
428 }
Harald Welte3c062072009-07-28 18:25:29 +0200429 if (rtph->type == RTCP_TYPE_SDES) {
430 char new_cname[255];
431 strncpy(new_cname, inet_ntoa(rss->sin_local.sin_addr),
432 sizeof(new_cname));
433 new_cname[sizeof(new_cname)-1] = '\0';
434 rc = rtcp_sdes_cname_mangle(msg, rtph, &old_len,
435 new_cname);
436 if (rc < 0)
437 return rc;
438 }
439 rtph = (void *)rtph + old_len;
440 }
441
442 return 0;
443}
444
Harald Welte0b0bbce2009-07-28 00:01:58 +0200445/* read from incoming RTP/RTCP socket */
446static int rtp_socket_read(struct rtp_socket *rs, struct rtp_sub_socket *rss)
447{
448 int rc;
449 struct msgb *msg = msgb_alloc(RTP_ALLOC_SIZE, "RTP/RTCP");
Harald Welte3971ad52009-12-19 22:23:05 +0100450 struct msgb *new_msg;
Harald Welte0b0bbce2009-07-28 00:01:58 +0200451 struct rtp_sub_socket *other_rss;
452
453 if (!msg)
454 return -ENOMEM;
455
456 rc = read(rss->bfd.fd, msg->data, RTP_ALLOC_SIZE);
457 if (rc <= 0) {
458 rss->bfd.when &= ~BSC_FD_READ;
459 return rc;
460 }
461
462 msgb_put(msg, rc);
463
464 switch (rs->rx_action) {
465 case RTP_PROXY:
Harald Welte3c062072009-07-28 18:25:29 +0200466 if (!rs->proxy.other_sock) {
467 rc = -EIO;
468 goto out_free;
469 }
Harald Welte0b0bbce2009-07-28 00:01:58 +0200470 if (rss->bfd.priv_nr == RTP_PRIV_RTP)
471 other_rss = &rs->proxy.other_sock->rtp;
Harald Welte3c062072009-07-28 18:25:29 +0200472 else if (rss->bfd.priv_nr == RTP_PRIV_RTCP) {
Harald Welte0b0bbce2009-07-28 00:01:58 +0200473 other_rss = &rs->proxy.other_sock->rtcp;
Harald Welte3c062072009-07-28 18:25:29 +0200474 /* modify RTCP SDES CNAME */
475 rc = rtcp_mangle(msg, rs);
476 if (rc < 0)
477 goto out_free;
478 } else {
479 rc = -EINVAL;
480 goto out_free;
Harald Welte0b0bbce2009-07-28 00:01:58 +0200481 }
482 msgb_enqueue(&other_rss->tx_queue, msg);
483 other_rss->bfd.when |= BSC_FD_WRITE;
484 break;
Holger Hans Peter Freyther911b2012009-08-10 07:57:13 +0200485
486 case RTP_RECV_UPSTREAM:
Harald Welte3971ad52009-12-19 22:23:05 +0100487 if (!rs->receive.callref || !rs->receive.net) {
488 rc = -EIO;
489 goto out_free;
490 }
491 if (rss->bfd.priv_nr == RTP_PRIV_RTCP) {
492 if (!mangle_rtcp_cname) {
493 msgb_free(msg);
494 break;
495 }
496 /* modify RTCP SDES CNAME */
497 rc = rtcp_mangle(msg, rs);
498 if (rc < 0)
499 goto out_free;
500 msgb_enqueue(&rss->tx_queue, msg);
501 rss->bfd.when |= BSC_FD_WRITE;
502 break;
503 }
504 if (rss->bfd.priv_nr != RTP_PRIV_RTP) {
505 rc = -EINVAL;
506 goto out_free;
507 }
508 rc = rtp_decode(msg, rs->receive.callref, &new_msg);
509 if (rc < 0)
510 goto out_free;
511 msgb_free(msg);
Harald Welte4f272cc2011-03-03 23:29:05 +0100512 trau_tx_to_mncc(rs->receive.net, new_msg);
Harald Welte3971ad52009-12-19 22:23:05 +0100513 break;
514
515 case RTP_NONE: /* if socket exists, but disabled by app */
516 msgb_free(msg);
Holger Hans Peter Freyther911b2012009-08-10 07:57:13 +0200517 break;
Harald Welte0b0bbce2009-07-28 00:01:58 +0200518 }
519
Harald Welte3971ad52009-12-19 22:23:05 +0100520 return 0;
Harald Welte3c062072009-07-28 18:25:29 +0200521
522out_free:
523 msgb_free(msg);
524 return rc;
Harald Welte0b0bbce2009-07-28 00:01:58 +0200525}
526
Harald Welte9a696d72013-02-03 12:06:58 +0100527/* \brief write from tx_queue to RTP/RTCP socket */
Harald Welte0b0bbce2009-07-28 00:01:58 +0200528static int rtp_socket_write(struct rtp_socket *rs, struct rtp_sub_socket *rss)
529{
530 struct msgb *msg;
531 int written;
532
533 msg = msgb_dequeue(&rss->tx_queue);
534 if (!msg) {
535 rss->bfd.when &= ~BSC_FD_WRITE;
536 return 0;
537 }
538
539 written = write(rss->bfd.fd, msg->data, msg->len);
540 if (written < msg->len) {
Pablo Neira Ayuso42e41df2011-08-17 22:44:07 +0200541 LOGP(DLMIB, LOGL_ERROR, "short write");
Harald Welte0b0bbce2009-07-28 00:01:58 +0200542 msgb_free(msg);
543 return -EIO;
544 }
545
546 msgb_free(msg);
547
548 return 0;
549}
550
551
Harald Welte9a696d72013-02-03 12:06:58 +0100552/*! \brief callback for the select.c:bfd_* layer */
Pablo Neira Ayuso04d24cd2011-05-06 12:11:23 +0200553static int rtp_bfd_cb(struct osmo_fd *bfd, unsigned int flags)
Harald Welte0b0bbce2009-07-28 00:01:58 +0200554{
555 struct rtp_socket *rs = bfd->data;
556 struct rtp_sub_socket *rss;
557
558 switch (bfd->priv_nr) {
559 case RTP_PRIV_RTP:
560 rss = &rs->rtp;
561 break;
562 case RTP_PRIV_RTCP:
563 rss = &rs->rtcp;
564 break;
565 default:
566 return -EINVAL;
567 }
568
569 if (flags & BSC_FD_READ)
570 rtp_socket_read(rs, rss);
571
572 if (flags & BSC_FD_WRITE)
573 rtp_socket_write(rs, rss);
574
575 return 0;
576}
577
Harald Welte9a696d72013-02-03 12:06:58 +0100578/*! \brief initialize one rtp sub-socket */
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +0200579static void init_rss(struct rtp_sub_socket *rss,
Harald Welte0b0bbce2009-07-28 00:01:58 +0200580 struct rtp_socket *rs, int fd, int priv_nr)
581{
582 /* initialize bfd */
583 rss->bfd.fd = fd;
584 rss->bfd.data = rs;
585 rss->bfd.priv_nr = priv_nr;
586 rss->bfd.cb = rtp_bfd_cb;
587}
588
Harald Welte9a696d72013-02-03 12:06:58 +0100589/*! \brief create a new RTP/RTCP socket and bind it */
Harald Welte0b0bbce2009-07-28 00:01:58 +0200590struct rtp_socket *rtp_socket_create(void)
591{
592 int rc;
593 struct rtp_socket *rs;
594
Pablo Neira Ayuso42e41df2011-08-17 22:44:07 +0200595 DEBUGP(DLMUX, "rtp_socket_create(): ");
Harald Welte3c062072009-07-28 18:25:29 +0200596
Harald Welte0b0bbce2009-07-28 00:01:58 +0200597 rs = talloc_zero(tall_bsc_ctx, struct rtp_socket);
598 if (!rs)
599 return NULL;
600
601 INIT_LLIST_HEAD(&rs->rtp.tx_queue);
602 INIT_LLIST_HEAD(&rs->rtcp.tx_queue);
603
604 rc = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
605 if (rc < 0)
606 goto out_free;
607
608 init_rss(&rs->rtp, rs, rc, RTP_PRIV_RTP);
Pablo Neira Ayuso04d24cd2011-05-06 12:11:23 +0200609 rc = osmo_fd_register(&rs->rtp.bfd);
Harald Welte0b0bbce2009-07-28 00:01:58 +0200610 if (rc < 0)
611 goto out_rtp_socket;
612
613 rc = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
614 if (rc < 0)
615 goto out_rtp_bfd;
616
617 init_rss(&rs->rtcp, rs, rc, RTP_PRIV_RTCP);
Pablo Neira Ayuso04d24cd2011-05-06 12:11:23 +0200618 rc = osmo_fd_register(&rs->rtcp.bfd);
Harald Welte0b0bbce2009-07-28 00:01:58 +0200619 if (rc < 0)
620 goto out_rtcp_socket;
621
Pablo Neira Ayuso42e41df2011-08-17 22:44:07 +0200622 DEBUGPC(DLMUX, "success\n");
Harald Welte3c062072009-07-28 18:25:29 +0200623
624 rc = rtp_socket_bind(rs, INADDR_ANY);
625 if (rc < 0)
626 goto out_rtcp_bfd;
627
Harald Welte0b0bbce2009-07-28 00:01:58 +0200628 return rs;
629
Harald Welte3c062072009-07-28 18:25:29 +0200630out_rtcp_bfd:
Pablo Neira Ayuso04d24cd2011-05-06 12:11:23 +0200631 osmo_fd_unregister(&rs->rtcp.bfd);
Harald Welte0b0bbce2009-07-28 00:01:58 +0200632out_rtcp_socket:
633 close(rs->rtcp.bfd.fd);
634out_rtp_bfd:
Pablo Neira Ayuso04d24cd2011-05-06 12:11:23 +0200635 osmo_fd_unregister(&rs->rtp.bfd);
Harald Welte0b0bbce2009-07-28 00:01:58 +0200636out_rtp_socket:
637 close(rs->rtp.bfd.fd);
638out_free:
639 talloc_free(rs);
Pablo Neira Ayuso42e41df2011-08-17 22:44:07 +0200640 DEBUGPC(DLMUX, "failed\n");
Harald Welte0b0bbce2009-07-28 00:01:58 +0200641 return NULL;
642}
643
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200644static int rtp_sub_socket_bind(struct rtp_sub_socket *rss, uint32_t ip,
645 uint16_t port)
Harald Welte0b0bbce2009-07-28 00:01:58 +0200646{
Harald Welte3c062072009-07-28 18:25:29 +0200647 int rc;
648 socklen_t alen = sizeof(rss->sin_local);
649
Harald Welte0b0bbce2009-07-28 00:01:58 +0200650 rss->sin_local.sin_family = AF_INET;
651 rss->sin_local.sin_addr.s_addr = htonl(ip);
652 rss->sin_local.sin_port = htons(port);
653 rss->bfd.when |= BSC_FD_READ;
654
Harald Welte3c062072009-07-28 18:25:29 +0200655 rc = bind(rss->bfd.fd, (struct sockaddr *)&rss->sin_local,
656 sizeof(rss->sin_local));
657 if (rc < 0)
658 return rc;
659
660 /* retrieve the address we actually bound to, in case we
661 * passed INADDR_ANY as IP address */
662 return getsockname(rss->bfd.fd, (struct sockaddr *)&rss->sin_local,
663 &alen);
Harald Welte0b0bbce2009-07-28 00:01:58 +0200664}
665
666#define RTP_PORT_BASE 30000
Harald Welte3c062072009-07-28 18:25:29 +0200667static unsigned int next_udp_port = RTP_PORT_BASE;
Harald Welte0b0bbce2009-07-28 00:01:58 +0200668
Harald Welte9a696d72013-02-03 12:06:58 +0100669/*! \brief bind a RTP socket to a specific local address
670 * \param[in] rs RTP socket to be bound
671 * \param[in] ip local IP address to which socket is to be bound
672 */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200673int rtp_socket_bind(struct rtp_socket *rs, uint32_t ip)
Harald Welte0b0bbce2009-07-28 00:01:58 +0200674{
Harald Welte3c062072009-07-28 18:25:29 +0200675 int rc = -EIO;
676 struct in_addr ia;
677
678 ia.s_addr = htonl(ip);
Pablo Neira Ayuso42e41df2011-08-17 22:44:07 +0200679 DEBUGP(DLMUX, "rtp_socket_bind(rs=%p, IP=%s): ", rs,
Harald Welte3c062072009-07-28 18:25:29 +0200680 inet_ntoa(ia));
Harald Welte0b0bbce2009-07-28 00:01:58 +0200681
682 /* try to bind to a consecutive pair of ports */
Harald Welte3c062072009-07-28 18:25:29 +0200683 for (next_udp_port = next_udp_port % 0xffff;
684 next_udp_port < 0xffff; next_udp_port += 2) {
Harald Welte0b0bbce2009-07-28 00:01:58 +0200685 rc = rtp_sub_socket_bind(&rs->rtp, ip, next_udp_port);
686 if (rc != 0)
687 continue;
688
689 rc = rtp_sub_socket_bind(&rs->rtcp, ip, next_udp_port+1);
690 if (rc == 0)
691 break;
692 }
Harald Welte3c062072009-07-28 18:25:29 +0200693 if (rc < 0) {
Pablo Neira Ayuso42e41df2011-08-17 22:44:07 +0200694 DEBUGPC(DLMUX, "failed\n");
Harald Welte0b0bbce2009-07-28 00:01:58 +0200695 return rc;
Harald Welte3c062072009-07-28 18:25:29 +0200696 }
Harald Welte0b0bbce2009-07-28 00:01:58 +0200697
Harald Welte3c062072009-07-28 18:25:29 +0200698 ia.s_addr = rs->rtp.sin_local.sin_addr.s_addr;
Pablo Neira Ayuso42e41df2011-08-17 22:44:07 +0200699 DEBUGPC(DLMUX, "BOUND_IP=%s, BOUND_PORT=%u\n",
Harald Welte3c062072009-07-28 18:25:29 +0200700 inet_ntoa(ia), ntohs(rs->rtp.sin_local.sin_port));
Harald Welte0b0bbce2009-07-28 00:01:58 +0200701 return ntohs(rs->rtp.sin_local.sin_port);
702}
703
704static int rtp_sub_socket_connect(struct rtp_sub_socket *rss,
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200705 uint32_t ip, uint16_t port)
Harald Welte0b0bbce2009-07-28 00:01:58 +0200706{
Harald Welte3c062072009-07-28 18:25:29 +0200707 int rc;
708 socklen_t alen = sizeof(rss->sin_local);
709
Harald Welte0b0bbce2009-07-28 00:01:58 +0200710 rss->sin_remote.sin_family = AF_INET;
711 rss->sin_remote.sin_addr.s_addr = htonl(ip);
712 rss->sin_remote.sin_port = htons(port);
713
Harald Welte3c062072009-07-28 18:25:29 +0200714 rc = connect(rss->bfd.fd, (struct sockaddr *) &rss->sin_remote,
715 sizeof(rss->sin_remote));
716 if (rc < 0)
717 return rc;
718
719 return getsockname(rss->bfd.fd, (struct sockaddr *)&rss->sin_local,
720 &alen);
Harald Welte0b0bbce2009-07-28 00:01:58 +0200721}
722
Harald Welte9a696d72013-02-03 12:06:58 +0100723/*! \brief 'connect' a RTP socket to a remote peer
724 * \param[in] rs RTP socket to be connected
725 * \param[in] ip remote IP address to which to connect
726 * \param[in] port remote UDP port number to which to connect
727 */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200728int rtp_socket_connect(struct rtp_socket *rs, uint32_t ip, uint16_t port)
Harald Welte0b0bbce2009-07-28 00:01:58 +0200729{
730 int rc;
Harald Welte3c062072009-07-28 18:25:29 +0200731 struct in_addr ia;
732
733 ia.s_addr = htonl(ip);
Pablo Neira Ayuso42e41df2011-08-17 22:44:07 +0200734 DEBUGP(DLMUX, "rtp_socket_connect(rs=%p, ip=%s, port=%u)\n",
Harald Welte3c062072009-07-28 18:25:29 +0200735 rs, inet_ntoa(ia), port);
Harald Welte0b0bbce2009-07-28 00:01:58 +0200736
737 rc = rtp_sub_socket_connect(&rs->rtp, ip, port);
738 if (rc < 0)
739 return rc;
740
741 return rtp_sub_socket_connect(&rs->rtcp, ip, port+1);
742}
743
Harald Welte9a696d72013-02-03 12:06:58 +0100744/*! \brief bind two RTP/RTCP sockets together in the proxy
745 * \param[in] this First RTP socket
746 * \param[in] other Second RTP socket
747 */
Harald Welte0b0bbce2009-07-28 00:01:58 +0200748int rtp_socket_proxy(struct rtp_socket *this, struct rtp_socket *other)
749{
Pablo Neira Ayuso42e41df2011-08-17 22:44:07 +0200750 DEBUGP(DLMUX, "rtp_socket_proxy(this=%p, other=%p)\n",
Harald Welte3c062072009-07-28 18:25:29 +0200751 this, other);
752
Harald Welte0b0bbce2009-07-28 00:01:58 +0200753 this->rx_action = RTP_PROXY;
754 this->proxy.other_sock = other;
755
756 other->rx_action = RTP_PROXY;
757 other->proxy.other_sock = this;
758
759 return 0;
760}
761
Harald Welte9a696d72013-02-03 12:06:58 +0100762/*! \brief bind RTP/RTCP socket to application, disabling proxy
763 * \param[in] this RTP socket
764 * \param[in] net gsm_network argument to trau_tx_to_mncc()
765 * \param[in] callref callref argument to trau_tx_to_mncc()
766 */
Harald Welte08eaf752009-12-20 17:07:23 +0100767int rtp_socket_upstream(struct rtp_socket *this, struct gsm_network *net,
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200768 uint32_t callref)
Harald Welte3971ad52009-12-19 22:23:05 +0100769{
Pablo Neira Ayuso42e41df2011-08-17 22:44:07 +0200770 DEBUGP(DLMUX, "rtp_socket_proxy(this=%p, callref=%u)\n",
Harald Welte3971ad52009-12-19 22:23:05 +0100771 this, callref);
772
773 if (callref) {
774 this->rx_action = RTP_RECV_UPSTREAM;
775 this->receive.net = net;
776 this->receive.callref = callref;
777 } else
778 this->rx_action = RTP_NONE;
779
780 return 0;
781}
782
Harald Welte0b0bbce2009-07-28 00:01:58 +0200783static void free_tx_queue(struct rtp_sub_socket *rss)
784{
785 struct msgb *msg;
786
787 while ((msg = msgb_dequeue(&rss->tx_queue)))
788 msgb_free(msg);
789}
790
Harald Welte9a696d72013-02-03 12:06:58 +0100791/*! \brief Free/release a previously allocated RTP socket
792 * \param[in[] rs RTP/RTCP socket to be released
793 */
Harald Welte0b0bbce2009-07-28 00:01:58 +0200794int rtp_socket_free(struct rtp_socket *rs)
795{
Pablo Neira Ayuso42e41df2011-08-17 22:44:07 +0200796 DEBUGP(DLMUX, "rtp_socket_free(rs=%p)\n", rs);
Harald Welte0b0bbce2009-07-28 00:01:58 +0200797
798 /* make sure we don't leave references dangling to us */
799 if (rs->rx_action == RTP_PROXY &&
800 rs->proxy.other_sock)
801 rs->proxy.other_sock->proxy.other_sock = NULL;
802
Pablo Neira Ayuso04d24cd2011-05-06 12:11:23 +0200803 osmo_fd_unregister(&rs->rtp.bfd);
Harald Welte0b0bbce2009-07-28 00:01:58 +0200804 close(rs->rtp.bfd.fd);
805 free_tx_queue(&rs->rtp);
806
Pablo Neira Ayuso04d24cd2011-05-06 12:11:23 +0200807 osmo_fd_unregister(&rs->rtcp.bfd);
Harald Welte0b0bbce2009-07-28 00:01:58 +0200808 close(rs->rtcp.bfd.fd);
809 free_tx_queue(&rs->rtcp);
810
811 talloc_free(rs);
812
813 return 0;
814}