blob: 6dfc5a5a525421075a2cee596d135ca17f8f6667 [file] [log] [blame]
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001/* A Media Gateway Control Protocol Media Gateway: RFC 3435 */
2/* The protocol implementation */
3
4/*
5 * (C) 2009-2012 by Holger Hans Peter Freyther <zecke@selfish.org>
6 * (C) 2009-2012 by On-Waves
7 * All Rights Reserved
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU Affero General Public License as published by
11 * the Free Software Foundation; either version 3 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU Affero General Public License for more details.
18 *
19 * You should have received a copy of the GNU Affero General Public License
20 * along with this program. If not, see <http://www.gnu.org/licenses/>.
21 *
22 */
23
24#include <string.h>
25#include <stdlib.h>
26#include <unistd.h>
27#include <errno.h>
28#include <time.h>
29#include <limits.h>
Neels Hofmeyrf83ec562017-09-07 19:18:40 +020030#include <arpa/inet.h>
31
32#include <osmocom/core/msgb.h>
33#include <osmocom/core/select.h>
Philipp Maier1cb1e382017-11-02 17:16:04 +010034#include <osmocom/core/socket.h>
Neels Hofmeyrf83ec562017-09-07 19:18:40 +020035#include <osmocom/netif/rtp.h>
Philipp Maier87bd9be2017-08-22 16:35:41 +020036#include <osmocom/mgcp/mgcp.h>
Neels Hofmeyr67793542017-09-08 04:25:16 +020037#include <osmocom/mgcp/mgcp_common.h>
Philipp Maier87bd9be2017-08-22 16:35:41 +020038#include <osmocom/mgcp/mgcp_internal.h>
39#include <osmocom/mgcp/mgcp_stat.h>
40#include <osmocom/mgcp/osmux.h>
41#include <osmocom/mgcp/mgcp_conn.h>
Philipp Maier37d11c82018-02-01 14:38:12 +010042#include <osmocom/mgcp/mgcp_endp.h>
Philipp Maier6931f9a2018-07-26 09:29:31 +020043#include <osmocom/mgcp/mgcp_codec.h>
Philipp Maierc3413882017-10-27 12:26:54 +020044#include <osmocom/mgcp/debug.h>
Neels Hofmeyrf83ec562017-09-07 19:18:40 +020045
Philipp Maier6931f9a2018-07-26 09:29:31 +020046
Neels Hofmeyrf83ec562017-09-07 19:18:40 +020047#define RTP_SEQ_MOD (1 << 16)
48#define RTP_MAX_DROPOUT 3000
49#define RTP_MAX_MISORDER 100
50#define RTP_BUF_SIZE 4096
51
52enum {
53 MGCP_PROTO_RTP,
54 MGCP_PROTO_RTCP,
55};
56
Philipp Maier1cb1e382017-11-02 17:16:04 +010057/*! Determine the local rtp bind IP-address.
58 * \param[out] addr caller provided memory to store the resulting IP-Address
59 * \param[in] endp mgcp endpoint, that holds a copy of the VTY parameters
60 *
61 * The local bind IP-address is automatically selected by probing the
62 * IP-Address of the interface that is pointing towards the remote IP-Address,
63 * if no remote IP-Address is known yet, the statically configured
64 * IP-Addresses are used as fallback. */
65void mgcp_get_local_addr(char *addr, struct mgcp_conn_rtp *conn)
66{
67
68 struct mgcp_endpoint *endp;
69 int rc;
70 endp = conn->conn->endp;
71
72 /* Try probing the local IP-Address */
73 if (endp->cfg->net_ports.bind_addr_probe && conn->end.addr.s_addr != 0) {
74 rc = osmo_sock_local_ip(addr, inet_ntoa(conn->end.addr));
75 if (rc < 0)
76 LOGP(DRTP, LOGL_ERROR,
Philipp Maier230e4fc2017-11-28 09:38:45 +010077 "endpoint:0x%x CI:%s local interface auto detection failed, using configured addresses...\n",
Philipp Maier1cb1e382017-11-02 17:16:04 +010078 ENDPOINT_NUMBER(endp), conn->conn->id);
79 else {
80 LOGP(DRTP, LOGL_DEBUG,
Philipp Maier230e4fc2017-11-28 09:38:45 +010081 "endpoint:0x%x CI:%s selected local rtp bind ip %s by probing using remote ip %s\n",
Philipp Maier1cb1e382017-11-02 17:16:04 +010082 ENDPOINT_NUMBER(endp), conn->conn->id, addr,
83 inet_ntoa(conn->end.addr));
84 return;
85 }
86 }
87
88 /* Select from preconfigured IP-Addresses */
89 if (endp->cfg->net_ports.bind_addr) {
90 /* Check there is a bind IP for the RTP traffic configured,
91 * if so, use that IP-Address */
Philipp Maierf8bfbe82017-11-23 19:32:31 +010092 osmo_strlcpy(addr, endp->cfg->net_ports.bind_addr, INET_ADDRSTRLEN);
Philipp Maier1cb1e382017-11-02 17:16:04 +010093 LOGP(DRTP, LOGL_DEBUG,
Philipp Maier230e4fc2017-11-28 09:38:45 +010094 "endpoint:0x%x CI:%s using configured rtp bind ip as local bind ip %s\n",
Philipp Maier1cb1e382017-11-02 17:16:04 +010095 ENDPOINT_NUMBER(endp), conn->conn->id, addr);
96 } else {
97 /* No specific bind IP is configured for the RTP traffic, so
98 * assume the IP where we listen for incoming MGCP messages
99 * as bind IP */
Philipp Maierf8bfbe82017-11-23 19:32:31 +0100100 osmo_strlcpy(addr, endp->cfg->source_addr, INET_ADDRSTRLEN);
Philipp Maier1cb1e382017-11-02 17:16:04 +0100101 LOGP(DRTP, LOGL_DEBUG,
Philipp Maier230e4fc2017-11-28 09:38:45 +0100102 "endpoint:0x%x CI:%s using mgcp bind ip as local rtp bind ip: %s\n",
Philipp Maier1cb1e382017-11-02 17:16:04 +0100103 ENDPOINT_NUMBER(endp), conn->conn->id, addr);
104 }
105}
106
Philipp Maier87bd9be2017-08-22 16:35:41 +0200107/* This does not need to be a precision timestamp and
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200108 * is allowed to wrap quite fast. The returned value is
Philipp Maier87bd9be2017-08-22 16:35:41 +0200109 * 1/codec_rate seconds. */
110static uint32_t get_current_ts(unsigned codec_rate)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200111{
112 struct timespec tp;
113 uint64_t ret;
114
Philipp Maier87bd9be2017-08-22 16:35:41 +0200115 if (!codec_rate)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200116 return 0;
117
118 memset(&tp, 0, sizeof(tp));
119 if (clock_gettime(CLOCK_MONOTONIC, &tp) != 0)
Philipp Maierc3413882017-10-27 12:26:54 +0200120 LOGP(DRTP, LOGL_NOTICE, "Getting the clock failed.\n");
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200121
122 /* convert it to 1/unit seconds */
123 ret = tp.tv_sec;
Philipp Maier87bd9be2017-08-22 16:35:41 +0200124 ret *= codec_rate;
125 ret += (int64_t) tp.tv_nsec * codec_rate / 1000 / 1000 / 1000;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200126
127 return ret;
128}
129
Philipp Maier87bd9be2017-08-22 16:35:41 +0200130/*! send udp packet.
131 * \param[in] fd associated file descriptor
132 * \param[in] addr destination ip-address
133 * \param[in] port destination UDP port
134 * \param[in] buf buffer that holds the data to be send
135 * \param[in] len length of the data to be sent
136 * \returns bytes sent, -1 on error */
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200137int mgcp_udp_send(int fd, struct in_addr *addr, int port, char *buf, int len)
138{
139 struct sockaddr_in out;
Philipp Maier87bd9be2017-08-22 16:35:41 +0200140
Philipp Maierc3413882017-10-27 12:26:54 +0200141 LOGP(DRTP, LOGL_DEBUG,
Philipp Maier87bd9be2017-08-22 16:35:41 +0200142 "sending %i bytes length packet to %s:%u ...\n",
143 len, inet_ntoa(*addr), ntohs(port));
144
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200145 out.sin_family = AF_INET;
146 out.sin_port = port;
147 memcpy(&out.sin_addr, addr, sizeof(*addr));
148
149 return sendto(fd, buf, len, 0, (struct sockaddr *)&out, sizeof(out));
150}
151
Philipp Maier87bd9be2017-08-22 16:35:41 +0200152/*! send RTP dummy packet (to keep NAT connection open).
153 * \param[in] endp mcgp endpoint that holds the RTP connection
154 * \param[in] conn associated RTP connection
155 * \returns bytes sent, -1 on error */
156int mgcp_send_dummy(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200157{
158 static char buf[] = { MGCP_DUMMY_LOAD };
159 int rc;
160 int was_rtcp = 0;
161
Philipp Maier87bd9be2017-08-22 16:35:41 +0200162 OSMO_ASSERT(endp);
163 OSMO_ASSERT(conn);
164
Philipp Maierc3413882017-10-27 12:26:54 +0200165 LOGP(DRTP, LOGL_DEBUG,
Philipp Maier230e4fc2017-11-28 09:38:45 +0100166 "endpoint:0x%x sending dummy packet...\n", ENDPOINT_NUMBER(endp));
167 LOGP(DRTP, LOGL_DEBUG, "endpoint:0x%x conn:%s\n",
Philipp Maier87bd9be2017-08-22 16:35:41 +0200168 ENDPOINT_NUMBER(endp), mgcp_conn_dump(conn->conn));
169
170 rc = mgcp_udp_send(conn->end.rtp.fd, &conn->end.addr,
171 conn->end.rtp_port, buf, 1);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200172
173 if (rc == -1)
174 goto failed;
175
176 if (endp->tcfg->omit_rtcp)
177 return rc;
178
179 was_rtcp = 1;
Philipp Maier87bd9be2017-08-22 16:35:41 +0200180 rc = mgcp_udp_send(conn->end.rtcp.fd, &conn->end.addr,
181 conn->end.rtcp_port, buf, 1);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200182
183 if (rc >= 0)
184 return rc;
185
186failed:
Philipp Maierc3413882017-10-27 12:26:54 +0200187 LOGP(DRTP, LOGL_ERROR,
Philipp Maier230e4fc2017-11-28 09:38:45 +0100188 "endpoint:0x%x Failed to send dummy %s packet.\n",
Philipp Maier87bd9be2017-08-22 16:35:41 +0200189 ENDPOINT_NUMBER(endp), was_rtcp ? "RTCP" : "RTP");
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200190
191 return -1;
192}
193
Philipp Maier87bd9be2017-08-22 16:35:41 +0200194/* Compute timestamp alignment error */
195static int32_t ts_alignment_error(struct mgcp_rtp_stream_state *sstate,
196 int ptime, uint32_t timestamp)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200197{
198 int32_t timestamp_delta;
199
200 if (ptime == 0)
201 return 0;
202
203 /* Align according to: T - Tlast = k * Tptime */
204 timestamp_delta = timestamp - sstate->last_timestamp;
205
206 return timestamp_delta % ptime;
207}
208
Philipp Maier87bd9be2017-08-22 16:35:41 +0200209/* Check timestamp and sequence number for plausibility */
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200210static int check_rtp_timestamp(struct mgcp_endpoint *endp,
211 struct mgcp_rtp_state *state,
212 struct mgcp_rtp_stream_state *sstate,
213 struct mgcp_rtp_end *rtp_end,
214 struct sockaddr_in *addr,
215 uint16_t seq, uint32_t timestamp,
Philipp Maier87bd9be2017-08-22 16:35:41 +0200216 const char *text, int32_t * tsdelta_out)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200217{
218 int32_t tsdelta;
219 int32_t timestamp_error;
220
221 /* Not fully intialized, skip */
222 if (sstate->last_tsdelta == 0 && timestamp == sstate->last_timestamp)
223 return 0;
224
225 if (seq == sstate->last_seq) {
226 if (timestamp != sstate->last_timestamp) {
Philipp Maier9e1d1642018-05-09 16:26:34 +0200227 rate_ctr_inc(sstate->err_ts_ctr);
Philipp Maierc3413882017-10-27 12:26:54 +0200228 LOGP(DRTP, LOGL_ERROR,
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200229 "The %s timestamp delta is != 0 but the sequence "
230 "number %d is the same, "
231 "TS offset: %d, SeqNo offset: %d "
232 "on 0x%x SSRC: %u timestamp: %u "
Philipp Maier87bd9be2017-08-22 16:35:41 +0200233 "from %s:%d\n",
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200234 text, seq,
Harald Welte33381352017-12-25 09:44:26 +0100235 state->patch.timestamp_offset, state->patch.seq_offset,
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200236 ENDPOINT_NUMBER(endp), sstate->ssrc, timestamp,
Philipp Maier87bd9be2017-08-22 16:35:41 +0200237 inet_ntoa(addr->sin_addr), ntohs(addr->sin_port));
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200238 }
239 return 0;
240 }
241
242 tsdelta =
Philipp Maier87bd9be2017-08-22 16:35:41 +0200243 (int32_t)(timestamp - sstate->last_timestamp) /
244 (int16_t)(seq - sstate->last_seq);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200245
246 if (tsdelta == 0) {
247 /* Don't update *tsdelta_out */
Philipp Maierc3413882017-10-27 12:26:54 +0200248 LOGP(DRTP, LOGL_NOTICE,
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200249 "The %s timestamp delta is %d "
250 "on 0x%x SSRC: %u timestamp: %u "
Philipp Maier87bd9be2017-08-22 16:35:41 +0200251 "from %s:%d\n",
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200252 text, tsdelta,
253 ENDPOINT_NUMBER(endp), sstate->ssrc, timestamp,
Philipp Maier87bd9be2017-08-22 16:35:41 +0200254 inet_ntoa(addr->sin_addr), ntohs(addr->sin_port));
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200255
256 return 0;
257 }
258
259 if (sstate->last_tsdelta != tsdelta) {
260 if (sstate->last_tsdelta) {
Philipp Maierc3413882017-10-27 12:26:54 +0200261 LOGP(DRTP, LOGL_INFO,
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200262 "The %s timestamp delta changes from %d to %d "
Philipp Maier87bd9be2017-08-22 16:35:41 +0200263 "on 0x%x SSRC: %u timestamp: %u from %s:%d\n",
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200264 text, sstate->last_tsdelta, tsdelta,
265 ENDPOINT_NUMBER(endp), sstate->ssrc, timestamp,
Philipp Maier87bd9be2017-08-22 16:35:41 +0200266 inet_ntoa(addr->sin_addr), ntohs(addr->sin_port));
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200267 }
268 }
269
270 if (tsdelta_out)
271 *tsdelta_out = tsdelta;
272
273 timestamp_error =
Philipp Maier87bd9be2017-08-22 16:35:41 +0200274 ts_alignment_error(sstate, state->packet_duration, timestamp);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200275
276 if (timestamp_error) {
Philipp Maier9e1d1642018-05-09 16:26:34 +0200277 rate_ctr_inc(sstate->err_ts_ctr);
Philipp Maierc3413882017-10-27 12:26:54 +0200278 LOGP(DRTP, LOGL_NOTICE,
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200279 "The %s timestamp has an alignment error of %d "
280 "on 0x%x SSRC: %u "
281 "SeqNo delta: %d, TS delta: %d, dTS/dSeq: %d "
Philipp Maier87bd9be2017-08-22 16:35:41 +0200282 "from %s:%d. ptime: %d\n",
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200283 text, timestamp_error,
284 ENDPOINT_NUMBER(endp), sstate->ssrc,
285 (int16_t)(seq - sstate->last_seq),
286 (int32_t)(timestamp - sstate->last_timestamp),
287 tsdelta,
288 inet_ntoa(addr->sin_addr), ntohs(addr->sin_port),
Philipp Maier87bd9be2017-08-22 16:35:41 +0200289 state->packet_duration);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200290 }
291 return 1;
292}
293
294/* Set the timestamp offset according to the packet duration. */
295static int adjust_rtp_timestamp_offset(struct mgcp_endpoint *endp,
296 struct mgcp_rtp_state *state,
297 struct mgcp_rtp_end *rtp_end,
298 struct sockaddr_in *addr,
299 int16_t delta_seq, uint32_t in_timestamp)
300{
301 int32_t tsdelta = state->packet_duration;
302 int timestamp_offset;
303 uint32_t out_timestamp;
304
305 if (tsdelta == 0) {
306 tsdelta = state->out_stream.last_tsdelta;
307 if (tsdelta != 0) {
Philipp Maierc3413882017-10-27 12:26:54 +0200308 LOGP(DRTP, LOGL_NOTICE,
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200309 "A fixed packet duration is not available on 0x%x, "
310 "using last output timestamp delta instead: %d "
Philipp Maier87bd9be2017-08-22 16:35:41 +0200311 "from %s:%d\n",
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200312 ENDPOINT_NUMBER(endp), tsdelta,
Philipp Maier87bd9be2017-08-22 16:35:41 +0200313 inet_ntoa(addr->sin_addr), ntohs(addr->sin_port));
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200314 } else {
Philipp Maierbc0346e2018-06-07 09:52:16 +0200315 tsdelta = rtp_end->codec->rate * 20 / 1000;
Philipp Maierc3413882017-10-27 12:26:54 +0200316 LOGP(DRTP, LOGL_NOTICE,
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200317 "Fixed packet duration and last timestamp delta "
318 "are not available on 0x%x, "
319 "using fixed 20ms instead: %d "
Philipp Maier87bd9be2017-08-22 16:35:41 +0200320 "from %s:%d\n",
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200321 ENDPOINT_NUMBER(endp), tsdelta,
Philipp Maier87bd9be2017-08-22 16:35:41 +0200322 inet_ntoa(addr->sin_addr), ntohs(addr->sin_port));
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200323 }
324 }
325
326 out_timestamp = state->out_stream.last_timestamp + delta_seq * tsdelta;
327 timestamp_offset = out_timestamp - in_timestamp;
328
Harald Welte33381352017-12-25 09:44:26 +0100329 if (state->patch.timestamp_offset != timestamp_offset) {
330 state->patch.timestamp_offset = timestamp_offset;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200331
Philipp Maierc3413882017-10-27 12:26:54 +0200332 LOGP(DRTP, LOGL_NOTICE,
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200333 "Timestamp offset change on 0x%x SSRC: %u "
334 "SeqNo delta: %d, TS offset: %d, "
Philipp Maier87bd9be2017-08-22 16:35:41 +0200335 "from %s:%d\n",
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200336 ENDPOINT_NUMBER(endp), state->in_stream.ssrc,
Harald Welte33381352017-12-25 09:44:26 +0100337 delta_seq, state->patch.timestamp_offset,
Philipp Maier87bd9be2017-08-22 16:35:41 +0200338 inet_ntoa(addr->sin_addr), ntohs(addr->sin_port));
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200339 }
340
341 return timestamp_offset;
342}
343
344/* Set the timestamp offset according to the packet duration. */
345static int align_rtp_timestamp_offset(struct mgcp_endpoint *endp,
346 struct mgcp_rtp_state *state,
347 struct mgcp_rtp_end *rtp_end,
348 struct sockaddr_in *addr,
349 uint32_t timestamp)
350{
Philipp Maier87bd9be2017-08-22 16:35:41 +0200351 int ts_error = 0;
352 int ts_check = 0;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200353 int ptime = state->packet_duration;
354
355 /* Align according to: T + Toffs - Tlast = k * Tptime */
356
Philipp Maier87bd9be2017-08-22 16:35:41 +0200357 ts_error = ts_alignment_error(&state->out_stream, ptime,
Harald Welte33381352017-12-25 09:44:26 +0100358 timestamp + state->patch.timestamp_offset);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200359
Philipp Maier87bd9be2017-08-22 16:35:41 +0200360 /* If there is an alignment error, we have to compensate it */
361 if (ts_error) {
Harald Welte33381352017-12-25 09:44:26 +0100362 state->patch.timestamp_offset += ptime - ts_error;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200363
Philipp Maierc3413882017-10-27 12:26:54 +0200364 LOGP(DRTP, LOGL_NOTICE,
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200365 "Corrected timestamp alignment error of %d on 0x%x SSRC: %u "
366 "new TS offset: %d, "
Philipp Maier87bd9be2017-08-22 16:35:41 +0200367 "from %s:%d\n",
368 ts_error,
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200369 ENDPOINT_NUMBER(endp), state->in_stream.ssrc,
Harald Welte33381352017-12-25 09:44:26 +0100370 state->patch.timestamp_offset, inet_ntoa(addr->sin_addr),
Philipp Maier87bd9be2017-08-22 16:35:41 +0200371 ntohs(addr->sin_port));
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200372 }
373
Philipp Maier87bd9be2017-08-22 16:35:41 +0200374 /* Check we really managed to compensate the timestamp
375 * offset. There should not be any remaining error, failing
Harald Welte1d1b98f2017-12-25 10:03:40 +0100376 * here would point to a serous problem with the alignment
377 * error computation function */
Philipp Maier87bd9be2017-08-22 16:35:41 +0200378 ts_check = ts_alignment_error(&state->out_stream, ptime,
Harald Welte33381352017-12-25 09:44:26 +0100379 timestamp + state->patch.timestamp_offset);
Philipp Maier87bd9be2017-08-22 16:35:41 +0200380 OSMO_ASSERT(ts_check == 0);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200381
Philipp Maier87bd9be2017-08-22 16:35:41 +0200382 /* Return alignment error before compensation */
383 return ts_error;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200384}
385
Philipp Maier87bd9be2017-08-22 16:35:41 +0200386/*! dummy callback to disable transcoding (see also cfg->rtp_processing_cb).
387 * \param[in] associated endpoint
388 * \param[in] destination RTP end
389 * \param[in,out] pointer to buffer with voice data
390 * \param[in] voice data length
Harald Welte1d1b98f2017-12-25 10:03:40 +0100391 * \param[in] maximum size of caller provided voice data buffer
Philipp Maier87bd9be2017-08-22 16:35:41 +0200392 * \returns ignores input parameters, return always 0 */
393int mgcp_rtp_processing_default(struct mgcp_endpoint *endp,
394 struct mgcp_rtp_end *dst_end,
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200395 char *data, int *len, int buf_size)
396{
Philipp Maier230e4fc2017-11-28 09:38:45 +0100397 LOGP(DRTP, LOGL_DEBUG, "endpoint:0x%x transcoding disabled\n",
Philipp Maier87bd9be2017-08-22 16:35:41 +0200398 ENDPOINT_NUMBER(endp));
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200399 return 0;
400}
401
Philipp Maier87bd9be2017-08-22 16:35:41 +0200402/*! dummy callback to disable transcoding (see also cfg->setup_rtp_processing_cb).
403 * \param[in] associated endpoint
Philipp Maieracc10352018-07-19 18:07:57 +0200404 * \param[in] destination RTP connnection
405 * \param[in] source RTP connection
Philipp Maier87bd9be2017-08-22 16:35:41 +0200406 * \returns ignores input parameters, return always 0 */
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200407int mgcp_setup_rtp_processing_default(struct mgcp_endpoint *endp,
Philipp Maieracc10352018-07-19 18:07:57 +0200408 struct mgcp_conn_rtp *conn_dst,
409 struct mgcp_conn_rtp *conn_src)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200410{
Philipp Maier230e4fc2017-11-28 09:38:45 +0100411 LOGP(DRTP, LOGL_DEBUG, "endpoint:0x%x transcoding disabled\n",
Philipp Maier87bd9be2017-08-22 16:35:41 +0200412 ENDPOINT_NUMBER(endp));
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200413 return 0;
414}
415
416void mgcp_get_net_downlink_format_default(struct mgcp_endpoint *endp,
417 int *payload_type,
Philipp Maier87bd9be2017-08-22 16:35:41 +0200418 const char **audio_name,
419 const char **fmtp_extra,
420 struct mgcp_conn_rtp *conn)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200421{
Philipp Maierc3413882017-10-27 12:26:54 +0200422 LOGP(DRTP, LOGL_DEBUG,
Philipp Maier230e4fc2017-11-28 09:38:45 +0100423 "endpoint:0x%x conn:%s using format defaults\n",
Philipp Maier87bd9be2017-08-22 16:35:41 +0200424 ENDPOINT_NUMBER(endp), mgcp_conn_dump(conn->conn));
425
Philipp Maierbc0346e2018-06-07 09:52:16 +0200426 *payload_type = conn->end.codec->payload_type;
427 *audio_name = conn->end.codec->audio_name;
Philipp Maier87bd9be2017-08-22 16:35:41 +0200428 *fmtp_extra = conn->end.fmtp_extra;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200429}
430
Philipp Maier87bd9be2017-08-22 16:35:41 +0200431void mgcp_rtp_annex_count(struct mgcp_endpoint *endp,
432 struct mgcp_rtp_state *state, const uint16_t seq,
433 const int32_t transit, const uint32_t ssrc)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200434{
435 int32_t d;
436
437 /* initialize or re-initialize */
Harald Welte49e3d5a2017-12-25 09:47:57 +0100438 if (!state->stats.initialized || state->stats.ssrc != ssrc) {
439 state->stats.initialized = 1;
440 state->stats.base_seq = seq;
441 state->stats.max_seq = seq - 1;
442 state->stats.ssrc = ssrc;
443 state->stats.jitter = 0;
444 state->stats.transit = transit;
445 state->stats.cycles = 0;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200446 } else {
447 uint16_t udelta;
448
Philipp Maier87bd9be2017-08-22 16:35:41 +0200449 /* The below takes the shape of the validation of
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200450 * Appendix A. Check if there is something weird with
451 * the sequence number, otherwise check for a wrap
452 * around in the sequence number.
453 * It can't wrap during the initialization so let's
454 * skip it here. The Appendix A probably doesn't have
Philipp Maier87bd9be2017-08-22 16:35:41 +0200455 * this issue because of the probation. */
Harald Welte49e3d5a2017-12-25 09:47:57 +0100456 udelta = seq - state->stats.max_seq;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200457 if (udelta < RTP_MAX_DROPOUT) {
Harald Welte49e3d5a2017-12-25 09:47:57 +0100458 if (seq < state->stats.max_seq)
459 state->stats.cycles += RTP_SEQ_MOD;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200460 } else if (udelta <= RTP_SEQ_MOD - RTP_MAX_MISORDER) {
Philipp Maierc3413882017-10-27 12:26:54 +0200461 LOGP(DRTP, LOGL_NOTICE,
Philipp Maier87bd9be2017-08-22 16:35:41 +0200462 "RTP seqno made a very large jump on 0x%x delta: %u\n",
463 ENDPOINT_NUMBER(endp), udelta);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200464 }
465 }
466
Philipp Maier87bd9be2017-08-22 16:35:41 +0200467 /* Calculate the jitter between the two packages. The TS should be
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200468 * taken closer to the read function. This was taken from the
469 * Appendix A of RFC 3550. Timestamp and arrival_time have a 1/rate
Philipp Maier87bd9be2017-08-22 16:35:41 +0200470 * resolution. */
Harald Welte49e3d5a2017-12-25 09:47:57 +0100471 d = transit - state->stats.transit;
472 state->stats.transit = transit;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200473 if (d < 0)
474 d = -d;
Harald Welte49e3d5a2017-12-25 09:47:57 +0100475 state->stats.jitter += d - ((state->stats.jitter + 8) >> 4);
476 state->stats.max_seq = seq;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200477}
478
Philipp Maier6931f9a2018-07-26 09:29:31 +0200479/* There may be different payload type numbers negotiated for two connections.
480 * Patch the payload type of an RTP packet so that it uses the payload type
481 * that is valid for the destination connection (conn_dst) */
482static int mgcp_patch_pt(struct mgcp_conn_rtp *conn_src,
483 struct mgcp_conn_rtp *conn_dst, char *data, int len)
484{
485 struct rtp_hdr *rtp_hdr;
486 uint8_t pt_in;
487 int pt_out;
488
489 OSMO_ASSERT(len >= sizeof(struct rtp_hdr));
490 rtp_hdr = (struct rtp_hdr *)data;
491
492 pt_in = rtp_hdr->payload_type;
493 pt_out = mgcp_codec_pt_translate(conn_src, conn_dst, pt_in);
494 if (pt_out < 0)
495 return -EINVAL;
496
497 rtp_hdr->payload_type = (uint8_t) pt_out;
498 return 0;
499}
500
Philipp Maier87bd9be2017-08-22 16:35:41 +0200501/* The RFC 3550 Appendix A assumes there are multiple sources but
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200502 * some of the supported endpoints (e.g. the nanoBTS) can only handle
503 * one source and this code will patch RTP header to appear as if there
504 * is only one source.
505 * There is also no probation period for new sources. Every RTP header
Philipp Maier87bd9be2017-08-22 16:35:41 +0200506 * we receive will be seen as a switch in streams. */
507void mgcp_patch_and_count(struct mgcp_endpoint *endp,
508 struct mgcp_rtp_state *state,
509 struct mgcp_rtp_end *rtp_end,
510 struct sockaddr_in *addr, char *data, int len)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200511{
512 uint32_t arrival_time;
513 int32_t transit;
514 uint16_t seq;
515 uint32_t timestamp, ssrc;
516 struct rtp_hdr *rtp_hdr;
Philipp Maierbc0346e2018-06-07 09:52:16 +0200517 int payload = rtp_end->codec->payload_type;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200518
519 if (len < sizeof(*rtp_hdr))
520 return;
521
Philipp Maier87bd9be2017-08-22 16:35:41 +0200522 rtp_hdr = (struct rtp_hdr *)data;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200523 seq = ntohs(rtp_hdr->sequence);
524 timestamp = ntohl(rtp_hdr->timestamp);
Philipp Maierbc0346e2018-06-07 09:52:16 +0200525 arrival_time = get_current_ts(rtp_end->codec->rate);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200526 ssrc = ntohl(rtp_hdr->ssrc);
527 transit = arrival_time - timestamp;
528
529 mgcp_rtp_annex_count(endp, state, seq, transit, ssrc);
530
531 if (!state->initialized) {
532 state->initialized = 1;
533 state->in_stream.last_seq = seq - 1;
Harald Welte33381352017-12-25 09:44:26 +0100534 state->in_stream.ssrc = state->patch.orig_ssrc = ssrc;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200535 state->in_stream.last_tsdelta = 0;
Philipp Maier87bd9be2017-08-22 16:35:41 +0200536 state->packet_duration =
537 mgcp_rtp_packet_duration(endp, rtp_end);
Philipp Maier0ec1d4e2018-05-16 11:09:42 +0200538 state->out_stream.last_seq = seq - 1;
539 state->out_stream.ssrc = state->patch.orig_ssrc = ssrc;
540 state->out_stream.last_tsdelta = 0;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200541 state->out_stream.last_timestamp = timestamp;
Philipp Maier87bd9be2017-08-22 16:35:41 +0200542 state->out_stream.ssrc = ssrc - 1; /* force output SSRC change */
Philipp Maierc3413882017-10-27 12:26:54 +0200543 LOGP(DRTP, LOGL_INFO,
Philipp Maier230e4fc2017-11-28 09:38:45 +0100544 "endpoint:0x%x initializing stream, SSRC: %u timestamp: %u "
Philipp Maier87bd9be2017-08-22 16:35:41 +0200545 "pkt-duration: %d, from %s:%d\n",
546 ENDPOINT_NUMBER(endp), state->in_stream.ssrc,
Harald Welte33381352017-12-25 09:44:26 +0100547 state->patch.seq_offset, state->packet_duration,
Philipp Maier87bd9be2017-08-22 16:35:41 +0200548 inet_ntoa(addr->sin_addr), ntohs(addr->sin_port));
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200549 if (state->packet_duration == 0) {
Philipp Maier87bd9be2017-08-22 16:35:41 +0200550 state->packet_duration =
Philipp Maierbc0346e2018-06-07 09:52:16 +0200551 rtp_end->codec->rate * 20 / 1000;
Philipp Maierc3413882017-10-27 12:26:54 +0200552 LOGP(DRTP, LOGL_NOTICE,
Philipp Maier230e4fc2017-11-28 09:38:45 +0100553 "endpoint:0x%x fixed packet duration is not available, "
Philipp Maier87bd9be2017-08-22 16:35:41 +0200554 "using fixed 20ms instead: %d from %s:%d\n",
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200555 ENDPOINT_NUMBER(endp), state->packet_duration,
Philipp Maier87bd9be2017-08-22 16:35:41 +0200556 inet_ntoa(addr->sin_addr), ntohs(addr->sin_port));
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200557 }
558 } else if (state->in_stream.ssrc != ssrc) {
Philipp Maierc3413882017-10-27 12:26:54 +0200559 LOGP(DRTP, LOGL_NOTICE,
Philipp Maier230e4fc2017-11-28 09:38:45 +0100560 "endpoint:0x%x SSRC changed: %u -> %u "
Philipp Maier87bd9be2017-08-22 16:35:41 +0200561 "from %s:%d\n",
562 ENDPOINT_NUMBER(endp),
563 state->in_stream.ssrc, rtp_hdr->ssrc,
564 inet_ntoa(addr->sin_addr), ntohs(addr->sin_port));
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200565
566 state->in_stream.ssrc = ssrc;
567 if (rtp_end->force_constant_ssrc) {
568 int16_t delta_seq;
569
570 /* Always increment seqno by 1 */
Harald Welte33381352017-12-25 09:44:26 +0100571 state->patch.seq_offset =
Philipp Maier87bd9be2017-08-22 16:35:41 +0200572 (state->out_stream.last_seq + 1) - seq;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200573
574 /* Estimate number of packets that would have been sent */
575 delta_seq =
Philipp Maier87bd9be2017-08-22 16:35:41 +0200576 (arrival_time - state->in_stream.last_arrival_time
577 + state->packet_duration / 2) /
578 state->packet_duration;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200579
580 adjust_rtp_timestamp_offset(endp, state, rtp_end, addr,
581 delta_seq, timestamp);
582
Harald Welte33381352017-12-25 09:44:26 +0100583 state->patch.patch_ssrc = 1;
584 ssrc = state->patch.orig_ssrc;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200585 if (rtp_end->force_constant_ssrc != -1)
586 rtp_end->force_constant_ssrc -= 1;
587
Philipp Maierc3413882017-10-27 12:26:54 +0200588 LOGP(DRTP, LOGL_NOTICE,
Philipp Maier230e4fc2017-11-28 09:38:45 +0100589 "endpoint:0x%x SSRC patching enabled, SSRC: %u "
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200590 "SeqNo offset: %d, TS offset: %d "
Philipp Maier87bd9be2017-08-22 16:35:41 +0200591 "from %s:%d\n",
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200592 ENDPOINT_NUMBER(endp), state->in_stream.ssrc,
Harald Welte33381352017-12-25 09:44:26 +0100593 state->patch.seq_offset, state->patch.timestamp_offset,
Philipp Maier87bd9be2017-08-22 16:35:41 +0200594 inet_ntoa(addr->sin_addr), ntohs(addr->sin_port));
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200595 }
596
597 state->in_stream.last_tsdelta = 0;
598 } else {
599 /* Compute current per-packet timestamp delta */
Philipp Maier87bd9be2017-08-22 16:35:41 +0200600 check_rtp_timestamp(endp, state, &state->in_stream, rtp_end,
601 addr, seq, timestamp, "input",
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200602 &state->in_stream.last_tsdelta);
603
Harald Welte33381352017-12-25 09:44:26 +0100604 if (state->patch.patch_ssrc)
605 ssrc = state->patch.orig_ssrc;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200606 }
607
608 /* Save before patching */
609 state->in_stream.last_timestamp = timestamp;
610 state->in_stream.last_seq = seq;
611 state->in_stream.last_arrival_time = arrival_time;
612
613 if (rtp_end->force_aligned_timing &&
614 state->out_stream.ssrc == ssrc && state->packet_duration)
615 /* Align the timestamp offset */
Philipp Maier87bd9be2017-08-22 16:35:41 +0200616 align_rtp_timestamp_offset(endp, state, rtp_end, addr,
617 timestamp);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200618
619 /* Store the updated SSRC back to the packet */
Harald Welte33381352017-12-25 09:44:26 +0100620 if (state->patch.patch_ssrc)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200621 rtp_hdr->ssrc = htonl(ssrc);
622
623 /* Apply the offset and store it back to the packet.
624 * This won't change anything if the offset is 0, so the conditional is
625 * omitted. */
Harald Welte33381352017-12-25 09:44:26 +0100626 seq += state->patch.seq_offset;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200627 rtp_hdr->sequence = htons(seq);
Harald Welte33381352017-12-25 09:44:26 +0100628 timestamp += state->patch.timestamp_offset;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200629 rtp_hdr->timestamp = htonl(timestamp);
630
631 /* Check again, whether the timestamps are still valid */
632 if (state->out_stream.ssrc == ssrc)
633 check_rtp_timestamp(endp, state, &state->out_stream, rtp_end,
634 addr, seq, timestamp, "output",
635 &state->out_stream.last_tsdelta);
636
637 /* Save output values */
638 state->out_stream.last_seq = seq;
639 state->out_stream.last_timestamp = timestamp;
640 state->out_stream.ssrc = ssrc;
641
642 if (payload < 0)
643 return;
644
645#if 0
Philipp Maierc3413882017-10-27 12:26:54 +0200646 DEBUGP(DRTP,
Philipp Maier230e4fc2017-11-28 09:38:45 +0100647 "endpoint:0x%x payload hdr payload %u -> endp payload %u\n",
Philipp Maier87bd9be2017-08-22 16:35:41 +0200648 ENDPOINT_NUMBER(endp), rtp_hdr->payload_type, payload);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200649 rtp_hdr->payload_type = payload;
650#endif
651}
652
Philipp Maier87bd9be2017-08-22 16:35:41 +0200653/* Forward data to a debug tap. This is debug function that is intended for
654 * debugging the voice traffic with tools like gstreamer */
Philipp Maiere6f172d2017-11-07 12:00:01 +0100655static void forward_data(int fd, struct mgcp_rtp_tap *tap, const char *buf,
656 int len)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200657{
Philipp Maiere6f172d2017-11-07 12:00:01 +0100658 int rc;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200659
Philipp Maiere6f172d2017-11-07 12:00:01 +0100660 if (!tap->enabled)
661 return;
662
663 rc = sendto(fd, buf, len, 0, (struct sockaddr *)&tap->forward,
664 sizeof(tap->forward));
665
666 if (rc < 0)
667 LOGP(DRTP, LOGL_ERROR,
668 "Forwarding tapped (debug) voice data failed.\n");
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200669}
670
Philipp Maier87bd9be2017-08-22 16:35:41 +0200671/*! Send RTP/RTCP data to a specified destination connection.
672 * \param[in] endp associated endpoint (for configuration, logging)
673 * \param[in] is_rtp flag to specify if the packet is of type RTP or RTCP
674 * \param[in] spoofed source address (set to NULL to disable)
675 * \param[in] buf buffer that contains the RTP/RTCP data
676 * \param[in] len length of the buffer that contains the RTP/RTCP data
677 * \param[in] conn_src associated source connection
678 * \param[in] conn_dst associated destination connection
679 * \returns 0 on success, -1 on ERROR */
680int mgcp_send(struct mgcp_endpoint *endp, int is_rtp, struct sockaddr_in *addr,
681 char *buf, int len, struct mgcp_conn_rtp *conn_src,
682 struct mgcp_conn_rtp *conn_dst)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200683{
Philipp Maier87bd9be2017-08-22 16:35:41 +0200684 /*! When no destination connection is available (e.g. when only one
685 * connection in loopback mode exists), then the source connection
686 * shall be specified as destination connection */
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200687
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200688 struct mgcp_trunk_config *tcfg = endp->tcfg;
689 struct mgcp_rtp_end *rtp_end;
690 struct mgcp_rtp_state *rtp_state;
Philipp Maier87bd9be2017-08-22 16:35:41 +0200691 char *dest_name;
Philipp Maier6931f9a2018-07-26 09:29:31 +0200692 int rc;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200693
Philipp Maier87bd9be2017-08-22 16:35:41 +0200694 OSMO_ASSERT(conn_src);
695 OSMO_ASSERT(conn_dst);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200696
Philipp Maier87bd9be2017-08-22 16:35:41 +0200697 if (is_rtp) {
Philipp Maierc3413882017-10-27 12:26:54 +0200698 LOGP(DRTP, LOGL_DEBUG,
Philipp Maier230e4fc2017-11-28 09:38:45 +0100699 "endpoint:0x%x delivering RTP packet...\n",
Philipp Maier87bd9be2017-08-22 16:35:41 +0200700 ENDPOINT_NUMBER(endp));
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200701 } else {
Philipp Maierc3413882017-10-27 12:26:54 +0200702 LOGP(DRTP, LOGL_DEBUG,
Philipp Maier230e4fc2017-11-28 09:38:45 +0100703 "endpoint:0x%x delivering RTCP packet...\n",
Philipp Maier87bd9be2017-08-22 16:35:41 +0200704 ENDPOINT_NUMBER(endp));
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200705 }
Philipp Maier87bd9be2017-08-22 16:35:41 +0200706
Philipp Maierc3413882017-10-27 12:26:54 +0200707 LOGP(DRTP, LOGL_DEBUG,
Neels Hofmeyr7066af82018-07-23 18:28:36 +0200708 "endpoint:0x%x loop:%d, mode:%d%s\n",
709 ENDPOINT_NUMBER(endp), tcfg->audio_loop, conn_src->conn->mode,
710 conn_src->conn->mode == MGCP_CONN_LOOPBACK ? " (loopback)" : "");
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200711
Philipp Maier6931f9a2018-07-26 09:29:31 +0200712 /* FIXME: It is legal that the payload type on the egress connection is
713 * different from the payload type that has been negotiated on the
714 * ingress connection. Essentially the codecs are the same so we can
715 * match them and patch the payload type. However, if we can not find
716 * the codec pendant (everything ist equal except the PT), we are of
717 * course unable to patch the payload type. A situation like this
718 * should not occur if transcoding is consequently avoided. Until
719 * we have transcoding support in osmo-mgw we can not resolve this. */
Philipp Maierda895b12018-08-03 12:16:37 +0200720 if (is_rtp) {
721 rc = mgcp_patch_pt(conn_src, conn_dst, buf, len);
722 if (rc < 0) {
723 LOGP(DRTP, LOGL_ERROR,
724 "endpoint:0x%x can not patch PT because no suitable egress codec was found.\n",
725 ENDPOINT_NUMBER(endp));
726 }
Philipp Maier6931f9a2018-07-26 09:29:31 +0200727 }
728
Philipp Maier87bd9be2017-08-22 16:35:41 +0200729 /* Note: In case of loopback configuration, both, the source and the
730 * destination will point to the same connection. */
731 rtp_end = &conn_dst->end;
732 rtp_state = &conn_src->state;
733 dest_name = conn_dst->conn->name;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200734
735 if (!rtp_end->output_enabled) {
Philipp Maiercede2a42018-07-03 14:14:21 +0200736 rate_ctr_inc(&conn_dst->rate_ctr_group->ctr[RTP_DROPPED_PACKETS_CTR]);
Philipp Maierc3413882017-10-27 12:26:54 +0200737 LOGP(DRTP, LOGL_DEBUG,
Philipp Maier230e4fc2017-11-28 09:38:45 +0100738 "endpoint:0x%x output disabled, drop to %s %s "
Philipp Maier87bd9be2017-08-22 16:35:41 +0200739 "rtp_port:%u rtcp_port:%u\n",
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200740 ENDPOINT_NUMBER(endp),
Philipp Maier87bd9be2017-08-22 16:35:41 +0200741 dest_name,
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200742 inet_ntoa(rtp_end->addr),
Philipp Maier87bd9be2017-08-22 16:35:41 +0200743 ntohs(rtp_end->rtp_port), ntohs(rtp_end->rtcp_port)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200744 );
745 } else if (is_rtp) {
746 int cont;
747 int nbytes = 0;
Philipp Maier87bd9be2017-08-22 16:35:41 +0200748 int buflen = len;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200749 do {
Philipp Maier87bd9be2017-08-22 16:35:41 +0200750 /* Run transcoder */
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200751 cont = endp->cfg->rtp_processing_cb(endp, rtp_end,
Philipp Maier87bd9be2017-08-22 16:35:41 +0200752 buf, &buflen,
753 RTP_BUF_SIZE);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200754 if (cont < 0)
755 break;
756
Philipp Maier87bd9be2017-08-22 16:35:41 +0200757 if (addr)
758 mgcp_patch_and_count(endp, rtp_state, rtp_end,
759 addr, buf, buflen);
Philipp Maierc3413882017-10-27 12:26:54 +0200760 LOGP(DRTP, LOGL_DEBUG,
Philipp Maier230e4fc2017-11-28 09:38:45 +0100761 "endpoint:0x%x process/send to %s %s "
Philipp Maier87bd9be2017-08-22 16:35:41 +0200762 "rtp_port:%u rtcp_port:%u\n",
763 ENDPOINT_NUMBER(endp), dest_name,
764 inet_ntoa(rtp_end->addr), ntohs(rtp_end->rtp_port),
765 ntohs(rtp_end->rtcp_port)
766 );
767
768 /* Forward a copy of the RTP data to a debug ip/port */
769 forward_data(rtp_end->rtp.fd, &conn_src->tap_out,
770 buf, buflen);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200771
772 /* FIXME: HACK HACK HACK. See OS#2459.
773 * The ip.access nano3G needs the first RTP payload's first two bytes to read hex
774 * 'e400', or it will reject the RAB assignment. It seems to not harm other femto
775 * cells (as long as we patch only the first RTP payload in each stream).
776 */
Neels Hofmeyr35a38292018-07-23 18:29:04 +0200777 if (!rtp_state->patched_first_rtp_payload
778 && conn_src->conn->mode == MGCP_CONN_LOOPBACK) {
Philipp Maier87bd9be2017-08-22 16:35:41 +0200779 uint8_t *data = (uint8_t *) & buf[12];
Neels Hofmeyr35a38292018-07-23 18:29:04 +0200780 if (data[0] == 0xe0) {
781 data[0] = 0xe4;
782 data[1] = 0x00;
783 rtp_state->patched_first_rtp_payload = true;
784 LOGP(DRTP, LOGL_DEBUG,
785 "endpoint:0x%x Patching over first two bytes"
786 " to fake an IuUP Initialization Ack\n",
787 ENDPOINT_NUMBER(endp));
788 }
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200789 }
790
Philipp Maier87bd9be2017-08-22 16:35:41 +0200791 len = mgcp_udp_send(rtp_end->rtp.fd,
792 &rtp_end->addr,
793 rtp_end->rtp_port, buf, buflen);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200794
Philipp Maier87bd9be2017-08-22 16:35:41 +0200795 if (len <= 0)
796 return len;
797
Philipp Maiercede2a42018-07-03 14:14:21 +0200798 rate_ctr_inc(&conn_dst->rate_ctr_group->ctr[RTP_PACKETS_TX_CTR]);
799 rate_ctr_add(&conn_dst->rate_ctr_group->ctr[RTP_OCTETS_TX_CTR], len);
Philipp Maier87bd9be2017-08-22 16:35:41 +0200800
801 nbytes += len;
802 buflen = cont;
803 } while (buflen > 0);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200804 return nbytes;
805 } else if (!tcfg->omit_rtcp) {
Philipp Maierc3413882017-10-27 12:26:54 +0200806 LOGP(DRTP, LOGL_DEBUG,
Philipp Maier230e4fc2017-11-28 09:38:45 +0100807 "endpoint:0x%x send to %s %s rtp_port:%u rtcp_port:%u\n",
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200808 ENDPOINT_NUMBER(endp),
Philipp Maier87bd9be2017-08-22 16:35:41 +0200809 dest_name,
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200810 inet_ntoa(rtp_end->addr),
Philipp Maier87bd9be2017-08-22 16:35:41 +0200811 ntohs(rtp_end->rtp_port), ntohs(rtp_end->rtcp_port)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200812 );
813
Philipp Maier87bd9be2017-08-22 16:35:41 +0200814 len = mgcp_udp_send(rtp_end->rtcp.fd,
815 &rtp_end->addr,
816 rtp_end->rtcp_port, buf, len);
817
Philipp Maiercede2a42018-07-03 14:14:21 +0200818 rate_ctr_inc(&conn_dst->rate_ctr_group->ctr[RTP_PACKETS_TX_CTR]);
819 rate_ctr_add(&conn_dst->rate_ctr_group->ctr[RTP_OCTETS_TX_CTR], len);
Philipp Maier87bd9be2017-08-22 16:35:41 +0200820
821 return len;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200822 }
823
824 return 0;
825}
826
Philipp Maier87bd9be2017-08-22 16:35:41 +0200827/* Helper function for mgcp_recv(),
828 Receive one RTP Packet + Originating address from file descriptor */
829static int receive_from(struct mgcp_endpoint *endp, int fd,
830 struct sockaddr_in *addr, char *buf, int bufsize)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200831{
832 int rc;
833 socklen_t slen = sizeof(*addr);
Philipp Maier87bd9be2017-08-22 16:35:41 +0200834 struct sockaddr_in addr_sink;
835 char buf_sink[RTP_BUF_SIZE];
836 bool tossed = false;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200837
Philipp Maier87bd9be2017-08-22 16:35:41 +0200838 if (!addr)
839 addr = &addr_sink;
840 if (!buf) {
841 tossed = true;
842 buf = buf_sink;
843 bufsize = sizeof(buf_sink);
844 }
845
846 rc = recvfrom(fd, buf, bufsize, 0, (struct sockaddr *)addr, &slen);
847
Philipp Maierc3413882017-10-27 12:26:54 +0200848 LOGP(DRTP, LOGL_DEBUG,
Philipp Maier87bd9be2017-08-22 16:35:41 +0200849 "receiving %u bytes length packet from %s:%u ...\n",
850 rc, inet_ntoa(addr->sin_addr), ntohs(addr->sin_port));
851
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200852 if (rc < 0) {
Philipp Maierc3413882017-10-27 12:26:54 +0200853 LOGP(DRTP, LOGL_ERROR,
Philipp Maier230e4fc2017-11-28 09:38:45 +0100854 "endpoint:0x%x failed to receive packet, errno: %d/%s\n",
Philipp Maier87bd9be2017-08-22 16:35:41 +0200855 ENDPOINT_NUMBER(endp), errno, strerror(errno));
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200856 return -1;
857 }
858
Philipp Maier87bd9be2017-08-22 16:35:41 +0200859 if (tossed) {
Philipp Maier230e4fc2017-11-28 09:38:45 +0100860 LOGP(DRTP, LOGL_ERROR, "endpoint:0x%x packet tossed\n",
Philipp Maier87bd9be2017-08-22 16:35:41 +0200861 ENDPOINT_NUMBER(endp));
862 }
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200863
864 return rc;
865}
866
Philipp Maier87bd9be2017-08-22 16:35:41 +0200867/* Check if the origin (addr) matches the address/port data of the RTP
868 * connections. */
869static int check_rtp_origin(struct mgcp_conn_rtp *conn,
870 struct sockaddr_in *addr)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200871{
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200872 struct mgcp_endpoint *endp;
Philipp Maier87bd9be2017-08-22 16:35:41 +0200873 endp = conn->conn->endp;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200874
Philipp Maier87bd9be2017-08-22 16:35:41 +0200875 /* Note: Check if the inbound RTP data comes from the same host to
876 * which we send our outgoing RTP traffic. */
877 if (memcmp(&addr->sin_addr, &conn->end.addr, sizeof(addr->sin_addr))
878 != 0) {
Philipp Maierc3413882017-10-27 12:26:54 +0200879 LOGP(DRTP, LOGL_ERROR,
Philipp Maier230e4fc2017-11-28 09:38:45 +0100880 "endpoint:0x%x data from wrong address: %s, ",
Philipp Maier87bd9be2017-08-22 16:35:41 +0200881 ENDPOINT_NUMBER(endp), inet_ntoa(addr->sin_addr));
Philipp Maierc3413882017-10-27 12:26:54 +0200882 LOGPC(DRTP, LOGL_ERROR, "expected: %s\n",
Philipp Maier87bd9be2017-08-22 16:35:41 +0200883 inet_ntoa(conn->end.addr));
Philipp Maier230e4fc2017-11-28 09:38:45 +0100884 LOGP(DRTP, LOGL_ERROR, "endpoint:0x%x packet tossed\n",
Philipp Maier87bd9be2017-08-22 16:35:41 +0200885 ENDPOINT_NUMBER(endp));
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200886 return -1;
887 }
888
Philipp Maier87bd9be2017-08-22 16:35:41 +0200889 /* Note: Usually the remote remote port of the data we receive will be
890 * the same as the remote port where we transmit outgoing RTP traffic
891 * to (set by MDCX). We use this to check the origin of the data for
892 * plausibility. */
893 if (conn->end.rtp_port != addr->sin_port &&
894 conn->end.rtcp_port != addr->sin_port) {
Philipp Maierc3413882017-10-27 12:26:54 +0200895 LOGP(DRTP, LOGL_ERROR,
Philipp Maier230e4fc2017-11-28 09:38:45 +0100896 "endpoint:0x%x data from wrong source port: %d, ",
Philipp Maier87bd9be2017-08-22 16:35:41 +0200897 ENDPOINT_NUMBER(endp), ntohs(addr->sin_port));
Philipp Maierc3413882017-10-27 12:26:54 +0200898 LOGPC(DRTP, LOGL_ERROR,
Philipp Maier87bd9be2017-08-22 16:35:41 +0200899 "expected: %d for RTP or %d for RTCP\n",
900 ntohs(conn->end.rtp_port), ntohs(conn->end.rtcp_port));
Philipp Maier230e4fc2017-11-28 09:38:45 +0100901 LOGP(DRTP, LOGL_ERROR, "endpoint:0x%x packet tossed\n",
Philipp Maier87bd9be2017-08-22 16:35:41 +0200902 ENDPOINT_NUMBER(endp));
903 return -1;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200904 }
905
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200906 return 0;
907}
908
Philipp Maier87bd9be2017-08-22 16:35:41 +0200909/* Check the if the destination address configuration of an RTP connection
910 * makes sense */
911static int check_rtp_destin(struct mgcp_conn_rtp *conn)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200912{
Philipp Maier87bd9be2017-08-22 16:35:41 +0200913 struct mgcp_endpoint *endp;
914 endp = conn->conn->endp;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200915
Philipp Maiere6df0e42018-05-29 14:03:06 +0200916 /* Note: it is legal to create a connection but never setting a port
917 * and IP-address for outgoing data. */
918 if (strcmp(inet_ntoa(conn->end.addr), "0.0.0.0") == 0 && conn->end.rtp_port == 0) {
919 LOGP(DRTP, LOGL_DEBUG,
920 "endpoint:0x%x destination IP-address and rtp port is (not yet) known\n",
921 ENDPOINT_NUMBER(endp));
922 return -1;
923 }
924
Philipp Maier87bd9be2017-08-22 16:35:41 +0200925 if (strcmp(inet_ntoa(conn->end.addr), "0.0.0.0") == 0) {
Philipp Maierc3413882017-10-27 12:26:54 +0200926 LOGP(DRTP, LOGL_ERROR,
Philipp Maier230e4fc2017-11-28 09:38:45 +0100927 "endpoint:0x%x destination IP-address is invalid\n",
Philipp Maier87bd9be2017-08-22 16:35:41 +0200928 ENDPOINT_NUMBER(endp));
929 return -1;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200930 }
Philipp Maier87bd9be2017-08-22 16:35:41 +0200931
932 if (conn->end.rtp_port == 0) {
Philipp Maierc3413882017-10-27 12:26:54 +0200933 LOGP(DRTP, LOGL_ERROR,
Philipp Maier230e4fc2017-11-28 09:38:45 +0100934 "endpoint:0x%x destination rtp port is invalid\n",
Philipp Maier87bd9be2017-08-22 16:35:41 +0200935 ENDPOINT_NUMBER(endp));
936 return -1;
937 }
938
939 return 0;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200940}
941
Philipp Maier87bd9be2017-08-22 16:35:41 +0200942/* Receive RTP data from a specified source connection and dispatch it to a
943 * destination connection. */
944static int mgcp_recv(int *proto, struct sockaddr_in *addr, char *buf,
945 unsigned int buf_size, struct osmo_fd *fd)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200946{
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200947 struct mgcp_endpoint *endp;
Philipp Maier87bd9be2017-08-22 16:35:41 +0200948 struct mgcp_conn_rtp *conn;
949 struct mgcp_trunk_config *tcfg;
950 int rc;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200951
Philipp Maier87bd9be2017-08-22 16:35:41 +0200952 conn = (struct mgcp_conn_rtp*) fd->data;
953 endp = conn->conn->endp;
954 tcfg = endp->tcfg;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200955
Philipp Maier230e4fc2017-11-28 09:38:45 +0100956 LOGP(DRTP, LOGL_DEBUG, "endpoint:0x%x receiving RTP/RTCP packet...\n",
Philipp Maier87bd9be2017-08-22 16:35:41 +0200957 ENDPOINT_NUMBER(endp));
958
959 rc = receive_from(endp, fd->fd, addr, buf, buf_size);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200960 if (rc <= 0)
961 return -1;
Philipp Maier87bd9be2017-08-22 16:35:41 +0200962 *proto = fd == &conn->end.rtp ? MGCP_PROTO_RTP : MGCP_PROTO_RTCP;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200963
Philipp Maier230e4fc2017-11-28 09:38:45 +0100964 LOGP(DRTP, LOGL_DEBUG, "endpoint:0x%x ", ENDPOINT_NUMBER(endp));
Neels Hofmeyr56725632018-01-15 15:15:07 +0100965 LOGPC(DRTP, LOGL_DEBUG, "receiving from %s %s %d\n",
Philipp Maier87bd9be2017-08-22 16:35:41 +0200966 conn->conn->name, inet_ntoa(addr->sin_addr),
967 ntohs(addr->sin_port));
Philipp Maier230e4fc2017-11-28 09:38:45 +0100968 LOGP(DRTP, LOGL_DEBUG, "endpoint:0x%x conn:%s\n", ENDPOINT_NUMBER(endp),
Philipp Maier87bd9be2017-08-22 16:35:41 +0200969 mgcp_conn_dump(conn->conn));
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200970
Philipp Maier87bd9be2017-08-22 16:35:41 +0200971 /* Check if the origin of the RTP packet seems plausible */
972 if (tcfg->rtp_accept_all == 0) {
973 if (check_rtp_origin(conn, addr) != 0)
974 return -1;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200975 }
976
Philipp Maier87bd9be2017-08-22 16:35:41 +0200977 /* Filter out dummy message */
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200978 if (rc == 1 && buf[0] == MGCP_DUMMY_LOAD) {
Philipp Maierc3413882017-10-27 12:26:54 +0200979 LOGP(DRTP, LOGL_NOTICE,
Philipp Maier230e4fc2017-11-28 09:38:45 +0100980 "endpoint:0x%x dummy message received\n",
Philipp Maier87bd9be2017-08-22 16:35:41 +0200981 ENDPOINT_NUMBER(endp));
Philipp Maierc3413882017-10-27 12:26:54 +0200982 LOGP(DRTP, LOGL_ERROR,
Philipp Maier230e4fc2017-11-28 09:38:45 +0100983 "endpoint:0x%x packet tossed\n", ENDPOINT_NUMBER(endp));
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200984 return 0;
985 }
986
Philipp Maier87bd9be2017-08-22 16:35:41 +0200987 /* Increment RX statistics */
Philipp Maiercede2a42018-07-03 14:14:21 +0200988 rate_ctr_inc(&conn->rate_ctr_group->ctr[RTP_PACKETS_RX_CTR]);
989 rate_ctr_add(&conn->rate_ctr_group->ctr[RTP_OCTETS_RX_CTR], rc);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200990
Philipp Maier87bd9be2017-08-22 16:35:41 +0200991 /* Forward a copy of the RTP data to a debug ip/port */
992 forward_data(fd->fd, &conn->tap_in, buf, rc);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200993
Philipp Maier87bd9be2017-08-22 16:35:41 +0200994 return rc;
995}
996
997/* Send RTP data. Possible options are standard RTP packet
998 * transmission or trsmission via an osmux connection */
999static int mgcp_send_rtp(int proto, struct sockaddr_in *addr, char *buf,
1000 unsigned int buf_size,
1001 struct mgcp_conn_rtp *conn_src,
1002 struct mgcp_conn_rtp *conn_dst)
1003{
1004 struct mgcp_endpoint *endp;
1005 endp = conn_src->conn->endp;
1006
Philipp Maier230e4fc2017-11-28 09:38:45 +01001007 LOGP(DRTP, LOGL_DEBUG, "endpoint:0x%x destin conn:%s\n",
Philipp Maier87bd9be2017-08-22 16:35:41 +02001008 ENDPOINT_NUMBER(endp), mgcp_conn_dump(conn_dst->conn));
1009
1010 /* Before we try to deliver the packet, we check if the destination
1011 * port and IP-Address make sense at all. If not, we will be unable
1012 * to deliver the packet. */
1013 if (check_rtp_destin(conn_dst) != 0)
1014 return -1;
1015
1016 /* Depending on the RTP connection type, deliver the RTP packet to the
1017 * destination connection. */
1018 switch (conn_dst->type) {
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001019 case MGCP_RTP_DEFAULT:
Philipp Maierc3413882017-10-27 12:26:54 +02001020 LOGP(DRTP, LOGL_DEBUG,
Philipp Maier230e4fc2017-11-28 09:38:45 +01001021 "endpoint:0x%x endpoint type is MGCP_RTP_DEFAULT, "
Philipp Maier87bd9be2017-08-22 16:35:41 +02001022 "using mgcp_send() to forward data directly\n",
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001023 ENDPOINT_NUMBER(endp));
Philipp Maier87bd9be2017-08-22 16:35:41 +02001024 return mgcp_send(endp, proto == MGCP_PROTO_RTP,
1025 addr, buf, buf_size, conn_src, conn_dst);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001026 case MGCP_OSMUX_BSC_NAT:
Philipp Maier87bd9be2017-08-22 16:35:41 +02001027 case MGCP_OSMUX_BSC:
Philipp Maierc3413882017-10-27 12:26:54 +02001028 LOGP(DRTP, LOGL_DEBUG,
Philipp Maier230e4fc2017-11-28 09:38:45 +01001029 "endpoint:0x%x endpoint type is MGCP_OSMUX_BSC_NAT, "
Philipp Maier87bd9be2017-08-22 16:35:41 +02001030 "using osmux_xfrm_to_osmux() to forward data through OSMUX\n",
1031 ENDPOINT_NUMBER(endp));
1032 return osmux_xfrm_to_osmux(buf, buf_size, conn_dst);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001033 }
1034
Philipp Maier87bd9be2017-08-22 16:35:41 +02001035 /* If the data has not been handled/forwarded until here, it will
1036 * be discarded, this should not happen, normally the MGCP type
1037 * should be properly set */
Philipp Maierc3413882017-10-27 12:26:54 +02001038 LOGP(DRTP, LOGL_ERROR,
Philipp Maier230e4fc2017-11-28 09:38:45 +01001039 "endpoint:0x%x bad MGCP type -- data discarded!\n",
Philipp Maier87bd9be2017-08-22 16:35:41 +02001040 ENDPOINT_NUMBER(endp));
1041
1042 return -1;
1043}
1044
1045/*! dispatch incoming RTP packet to opposite RTP connection.
1046 * \param[in] proto protocol (MGCP_CONN_TYPE_RTP or MGCP_CONN_TYPE_RTCP)
1047 * \param[in] addr socket address where the RTP packet has been received from
1048 * \param[in] buf buffer that hold the RTP payload
1049 * \param[in] buf_size size data length of buf
1050 * \param[in] conn originating connection
1051 * \returns 0 on success, -1 on ERROR */
1052int mgcp_dispatch_rtp_bridge_cb(int proto, struct sockaddr_in *addr, char *buf,
1053 unsigned int buf_size, struct mgcp_conn *conn)
1054{
1055 struct mgcp_conn *conn_dst;
1056 struct mgcp_endpoint *endp;
1057 endp = conn->endp;
1058
1059 /*! NOTE: This callback function implements the endpoint specific
1060 * dispatch bahviour of an rtp bridge/proxy endpoint. It is assumed
1061 * that the endpoint will hold only two connections. This premise
1062 * is used to determine the opposite connection (it is always the
1063 * connection that is not the originating connection). Once the
1064 * destination connection is known the RTP packet is sent via
1065 * the destination connection. */
1066
1067 /* Find a destination connection. */
1068 /* NOTE: This code path runs every time an RTP packet is received. The
1069 * function mgcp_find_dst_conn() we use to determine the detination
1070 * connection will iterate the connection list inside the endpoint.
1071 * Since list iterations are quite costly, we will figure out the
1072 * destination only once and use the optional private data pointer of
1073 * the connection to cache the destination connection pointer. */
1074 if (!conn->priv) {
1075 conn_dst = mgcp_find_dst_conn(conn);
1076 conn->priv = conn_dst;
1077 } else {
1078 conn_dst = (struct mgcp_conn *)conn->priv;
1079 }
1080
1081 /* There is no destination conn, stop here */
1082 if (!conn_dst) {
Philipp Maierc3413882017-10-27 12:26:54 +02001083 LOGP(DRTP, LOGL_ERROR,
Philipp Maier230e4fc2017-11-28 09:38:45 +01001084 "endpoint:0x%x unable to find destination conn\n",
Philipp Maier87bd9be2017-08-22 16:35:41 +02001085 ENDPOINT_NUMBER(endp));
1086 return -1;
1087 }
1088
1089 /* The destination conn is not an RTP connection */
1090 if (conn_dst->type != MGCP_CONN_TYPE_RTP) {
Philipp Maierc3413882017-10-27 12:26:54 +02001091 LOGP(DRTP, LOGL_ERROR,
Philipp Maier230e4fc2017-11-28 09:38:45 +01001092 "endpoint:0x%x unable to find suitable destination conn\n",
Philipp Maier87bd9be2017-08-22 16:35:41 +02001093 ENDPOINT_NUMBER(endp));
1094 return -1;
1095 }
1096
1097 /* Dispatch RTP packet to destination RTP connection */
1098 return mgcp_send_rtp(proto, addr, buf,
1099 buf_size, &conn->u.rtp, &conn_dst->u.rtp);
1100
1101}
1102
Philipp Maierdf5d2192018-01-24 11:39:32 +01001103/*! cleanup an endpoint when a connection on an RTP bridge endpoint is removed.
1104 * \param[in] endp Endpoint on which the connection resides.
1105 * \param[in] conn Connection that is about to be removed (ignored).
1106 * \returns 0 on success, -1 on ERROR. */
1107void mgcp_cleanup_rtp_bridge_cb(struct mgcp_endpoint *endp, struct mgcp_conn *conn)
1108{
1109 struct mgcp_conn *conn_cleanup;
1110
1111 /* In mgcp_dispatch_rtp_bridge_cb() we use conn->priv to cache the
1112 * pointer to the destination connection, so that we do not have
1113 * to go through the list every time an RTP packet arrives. To prevent
1114 * a use-after-free situation we invalidate this information for all
1115 * connections present when one connection is removed from the
1116 * endpoint. */
1117 llist_for_each_entry(conn_cleanup, &endp->conns, entry) {
1118 conn_cleanup->priv = NULL;
1119 }
1120}
1121
Philipp Maier87bd9be2017-08-22 16:35:41 +02001122/* Handle incoming RTP data from NET */
1123static int rtp_data_net(struct osmo_fd *fd, unsigned int what)
1124{
1125 /* NOTE: This is a generic implementation. RTP data is received. In
1126 * case of loopback the data is just sent back to its origin. All
1127 * other cases implement endpoint specific behaviour (e.g. how is the
1128 * destination connection determined?). That specific behaviour is
1129 * implemented by the callback function that is called at the end of
1130 * the function */
1131
1132 struct mgcp_conn_rtp *conn_src;
1133 struct mgcp_endpoint *endp;
1134 struct sockaddr_in addr;
1135
1136 char buf[RTP_BUF_SIZE];
1137 int proto;
Philipp Maierb9694552017-11-08 16:53:57 +01001138 int len;
Philipp Maier87bd9be2017-08-22 16:35:41 +02001139
1140 conn_src = (struct mgcp_conn_rtp *)fd->data;
1141 OSMO_ASSERT(conn_src);
1142 endp = conn_src->conn->endp;
1143 OSMO_ASSERT(endp);
1144
Philipp Maier230e4fc2017-11-28 09:38:45 +01001145 LOGP(DRTP, LOGL_DEBUG, "endpoint:0x%x source conn:%s\n",
Philipp Maier87bd9be2017-08-22 16:35:41 +02001146 ENDPOINT_NUMBER(endp), mgcp_conn_dump(conn_src->conn));
1147
1148 /* Receive packet */
Philipp Maierb9694552017-11-08 16:53:57 +01001149 len = mgcp_recv(&proto, &addr, buf, sizeof(buf), fd);
1150 if (len < 0)
Philipp Maier87bd9be2017-08-22 16:35:41 +02001151 return -1;
1152
1153 /* Check if the connection is in loopback mode, if yes, just send the
1154 * incoming data back to the origin */
Philipp Maier5dbfc782017-12-12 16:20:25 +01001155
Philipp Maier87bd9be2017-08-22 16:35:41 +02001156 if (conn_src->conn->mode == MGCP_CONN_LOOPBACK) {
Philipp Maier5dbfc782017-12-12 16:20:25 +01001157 /* When we are in loopback mode, we loop back all incoming
1158 * packets back to their origin. We will use the originating
1159 * address data from the UDP packet header to patch the
1160 * outgoing address in connection on the fly */
1161 if (conn_src->end.rtp_port == 0) {
1162 conn_src->end.addr = addr.sin_addr;
1163 conn_src->end.rtp_port = addr.sin_port;
1164 }
Philipp Maier87bd9be2017-08-22 16:35:41 +02001165 return mgcp_send_rtp(proto, &addr, buf,
Philipp Maierb9694552017-11-08 16:53:57 +01001166 len, conn_src, conn_src);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001167 }
1168
1169 /* Execute endpoint specific implementation that handles the
1170 * dispatching of the RTP data */
Philipp Maierb9694552017-11-08 16:53:57 +01001171 return endp->type->dispatch_rtp_cb(proto, &addr, buf, len,
Philipp Maier87bd9be2017-08-22 16:35:41 +02001172 conn_src->conn);
1173}
1174
1175/*! set IP Type of Service parameter.
1176 * \param[in] fd associated file descriptor
1177 * \param[in] tos dscp value
1178 * \returns 0 on success, -1 on ERROR */
1179int mgcp_set_ip_tos(int fd, int tos)
1180{
1181 int ret;
1182 ret = setsockopt(fd, IPPROTO_IP, IP_TOS, &tos, sizeof(tos));
1183
1184 if (ret < 0)
1185 return -1;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001186 return 0;
1187}
1188
Philipp Maier87bd9be2017-08-22 16:35:41 +02001189/*! bind RTP port to osmo_fd.
1190 * \param[in] source_addr source (local) address to bind on
1191 * \param[in] fd associated file descriptor
1192 * \param[in] port to bind on
1193 * \returns 0 on success, -1 on ERROR */
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001194int mgcp_create_bind(const char *source_addr, struct osmo_fd *fd, int port)
1195{
Harald Welte8890dfa2017-11-17 15:09:30 +01001196 int rc;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001197
Harald Welte8890dfa2017-11-17 15:09:30 +01001198 rc = osmo_sock_init2(AF_INET, SOCK_DGRAM, IPPROTO_UDP, source_addr, port,
1199 NULL, 0, OSMO_SOCK_F_BIND);
1200 if (rc < 0) {
Philipp Maierc3413882017-10-27 12:26:54 +02001201 LOGP(DRTP, LOGL_ERROR, "failed to bind UDP port (%s:%i).\n",
Philipp Maier87bd9be2017-08-22 16:35:41 +02001202 source_addr, port);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001203 return -1;
1204 }
Harald Welte8890dfa2017-11-17 15:09:30 +01001205 fd->fd = rc;
1206 LOGP(DRTP, LOGL_DEBUG, "created socket + bound UDP port (%s:%i).\n", source_addr, port);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001207
1208 return 0;
1209}
1210
Philipp Maier87bd9be2017-08-22 16:35:41 +02001211/* Bind RTP and RTCP port (helper function for mgcp_bind_net_rtp_port()) */
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001212static int bind_rtp(struct mgcp_config *cfg, const char *source_addr,
Philipp Maier87bd9be2017-08-22 16:35:41 +02001213 struct mgcp_rtp_end *rtp_end, int endpno)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001214{
Philipp Maier87bd9be2017-08-22 16:35:41 +02001215 /* NOTE: The port that is used for RTCP is the RTP port incremented by one
1216 * (e.g. RTP-Port = 16000 ==> RTCP-Port = 16001) */
1217
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001218 if (mgcp_create_bind(source_addr, &rtp_end->rtp,
1219 rtp_end->local_port) != 0) {
Philipp Maierc3413882017-10-27 12:26:54 +02001220 LOGP(DRTP, LOGL_ERROR,
Philipp Maier230e4fc2017-11-28 09:38:45 +01001221 "endpoint:0x%x failed to create RTP port: %s:%d\n", endpno,
Philipp Maier87bd9be2017-08-22 16:35:41 +02001222 source_addr, rtp_end->local_port);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001223 goto cleanup0;
1224 }
1225
1226 if (mgcp_create_bind(source_addr, &rtp_end->rtcp,
1227 rtp_end->local_port + 1) != 0) {
Philipp Maierc3413882017-10-27 12:26:54 +02001228 LOGP(DRTP, LOGL_ERROR,
Philipp Maier230e4fc2017-11-28 09:38:45 +01001229 "endpoint:0x%x failed to create RTCP port: %s:%d\n", endpno,
Philipp Maier87bd9be2017-08-22 16:35:41 +02001230 source_addr, rtp_end->local_port + 1);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001231 goto cleanup1;
1232 }
1233
Philipp Maier87bd9be2017-08-22 16:35:41 +02001234 /* Set Type of Service (DSCP-Value) as configured via VTY */
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001235 mgcp_set_ip_tos(rtp_end->rtp.fd, cfg->endp_dscp);
1236 mgcp_set_ip_tos(rtp_end->rtcp.fd, cfg->endp_dscp);
1237
1238 rtp_end->rtp.when = BSC_FD_READ;
1239 if (osmo_fd_register(&rtp_end->rtp) != 0) {
Philipp Maierc3413882017-10-27 12:26:54 +02001240 LOGP(DRTP, LOGL_ERROR,
Philipp Maier230e4fc2017-11-28 09:38:45 +01001241 "endpoint:0x%x failed to register RTP port %d\n", endpno,
Philipp Maier87bd9be2017-08-22 16:35:41 +02001242 rtp_end->local_port);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001243 goto cleanup2;
1244 }
1245
1246 rtp_end->rtcp.when = BSC_FD_READ;
1247 if (osmo_fd_register(&rtp_end->rtcp) != 0) {
Philipp Maierc3413882017-10-27 12:26:54 +02001248 LOGP(DRTP, LOGL_ERROR,
Philipp Maier230e4fc2017-11-28 09:38:45 +01001249 "endpoint:0x%x failed to register RTCP port %d\n", endpno,
Philipp Maier87bd9be2017-08-22 16:35:41 +02001250 rtp_end->local_port + 1);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001251 goto cleanup3;
1252 }
1253
1254 return 0;
1255
1256cleanup3:
1257 osmo_fd_unregister(&rtp_end->rtp);
1258cleanup2:
1259 close(rtp_end->rtcp.fd);
1260 rtp_end->rtcp.fd = -1;
1261cleanup1:
1262 close(rtp_end->rtp.fd);
1263 rtp_end->rtp.fd = -1;
1264cleanup0:
1265 return -1;
1266}
1267
Philipp Maier87bd9be2017-08-22 16:35:41 +02001268/*! bind RTP port to endpoint/connection.
1269 * \param[in] endp endpoint that holds the RTP connection
1270 * \param[in] rtp_port port number to bind on
1271 * \param[in] conn associated RTP connection
1272 * \returns 0 on success, -1 on ERROR */
1273int mgcp_bind_net_rtp_port(struct mgcp_endpoint *endp, int rtp_port,
1274 struct mgcp_conn_rtp *conn)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001275{
Philipp Maier87bd9be2017-08-22 16:35:41 +02001276 char name[512];
1277 struct mgcp_rtp_end *end;
Philipp Maier1cb1e382017-11-02 17:16:04 +01001278 char local_ip_addr[INET_ADDRSTRLEN];
Philipp Maier87bd9be2017-08-22 16:35:41 +02001279
Philipp Maier01d24a32017-11-21 17:26:09 +01001280 snprintf(name, sizeof(name), "%s-%s", conn->conn->name, conn->conn->id);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001281 end = &conn->end;
1282
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001283 if (end->rtp.fd != -1 || end->rtcp.fd != -1) {
Philipp Maierc3413882017-10-27 12:26:54 +02001284 LOGP(DRTP, LOGL_ERROR,
Philipp Maier230e4fc2017-11-28 09:38:45 +01001285 "endpoint:0x%x %u was already bound on conn:%s\n",
Philipp Maier87bd9be2017-08-22 16:35:41 +02001286 ENDPOINT_NUMBER(endp), rtp_port,
1287 mgcp_conn_dump(conn->conn));
1288
1289 /* Double bindings should never occour! Since we always allocate
1290 * connections dynamically and free them when they are not
1291 * needed anymore, there must be no previous binding leftover.
1292 * Should there be a connection bound twice, we have a serious
1293 * problem and must exit immediately! */
1294 OSMO_ASSERT(false);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001295 }
1296
1297 end->local_port = rtp_port;
Philipp Maier87bd9be2017-08-22 16:35:41 +02001298 end->rtp.cb = rtp_data_net;
1299 end->rtp.data = conn;
1300 end->rtcp.data = conn;
1301 end->rtcp.cb = rtp_data_net;
1302
Philipp Maier1cb1e382017-11-02 17:16:04 +01001303 mgcp_get_local_addr(local_ip_addr, conn);
1304
1305 return bind_rtp(endp->cfg, local_ip_addr, end,
Philipp Maier87bd9be2017-08-22 16:35:41 +02001306 ENDPOINT_NUMBER(endp));
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001307}
1308
Philipp Maier87bd9be2017-08-22 16:35:41 +02001309/*! free allocated RTP and RTCP ports.
1310 * \param[in] end RTP end */
1311void mgcp_free_rtp_port(struct mgcp_rtp_end *end)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001312{
1313 if (end->rtp.fd != -1) {
1314 close(end->rtp.fd);
1315 end->rtp.fd = -1;
1316 osmo_fd_unregister(&end->rtp);
1317 }
1318
1319 if (end->rtcp.fd != -1) {
1320 close(end->rtcp.fd);
1321 end->rtcp.fd = -1;
1322 osmo_fd_unregister(&end->rtcp);
1323 }
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001324}