blob: 1cca60a86d6f7b1d983abdd2f00e81faf4f03869 [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>
Philipp Maier4dba7692018-08-03 12:20:52 +020035#include <osmocom/core/byteswap.h>
Neels Hofmeyrf83ec562017-09-07 19:18:40 +020036#include <osmocom/netif/rtp.h>
Philipp Maier228e5912019-03-05 13:56:59 +010037#include <osmocom/netif/amr.h>
Philipp Maier87bd9be2017-08-22 16:35:41 +020038#include <osmocom/mgcp/mgcp.h>
Neels Hofmeyr67793542017-09-08 04:25:16 +020039#include <osmocom/mgcp/mgcp_common.h>
Philipp Maier87bd9be2017-08-22 16:35:41 +020040#include <osmocom/mgcp/mgcp_internal.h>
41#include <osmocom/mgcp/mgcp_stat.h>
42#include <osmocom/mgcp/osmux.h>
43#include <osmocom/mgcp/mgcp_conn.h>
Philipp Maier37d11c82018-02-01 14:38:12 +010044#include <osmocom/mgcp/mgcp_endp.h>
Philipp Maier6931f9a2018-07-26 09:29:31 +020045#include <osmocom/mgcp/mgcp_codec.h>
Philipp Maierc3413882017-10-27 12:26:54 +020046#include <osmocom/mgcp/debug.h>
Philipp Maier9fc8a022019-02-20 12:26:52 +010047#include <osmocom/codec/codec.h>
Neels Hofmeyrf83ec562017-09-07 19:18:40 +020048
Philipp Maier6931f9a2018-07-26 09:29:31 +020049
Neels Hofmeyrf83ec562017-09-07 19:18:40 +020050#define RTP_SEQ_MOD (1 << 16)
51#define RTP_MAX_DROPOUT 3000
52#define RTP_MAX_MISORDER 100
53#define RTP_BUF_SIZE 4096
54
55enum {
56 MGCP_PROTO_RTP,
57 MGCP_PROTO_RTCP,
58};
59
Harald Weltea48ff4a2020-03-08 14:45:08 +010060static void rtpconn_rate_ctr_add(struct mgcp_conn_rtp *conn_rtp, struct mgcp_endpoint *endp,
61 int id, int inc)
62{
63 struct rate_ctr_group *conn_stats = conn_rtp->rate_ctr_group;
64 struct rate_ctr_group *trunk_stats = endp->tcfg->all_rtp_conn_stats;
65
66 /* add to both the per-connection and the per-trunk global stats */
67 rate_ctr_add(&conn_stats->ctr[id], inc);
68 rate_ctr_add(&trunk_stats->ctr[id], inc);
69}
70
71static void rtpconn_rate_ctr_inc(struct mgcp_conn_rtp *conn_rtp, struct mgcp_endpoint *endp, int id)
72{
73 rtpconn_rate_ctr_add(conn_rtp, endp, id, 1);
74}
75
Philipp Maier1cb1e382017-11-02 17:16:04 +010076/*! Determine the local rtp bind IP-address.
77 * \param[out] addr caller provided memory to store the resulting IP-Address
78 * \param[in] endp mgcp endpoint, that holds a copy of the VTY parameters
79 *
80 * The local bind IP-address is automatically selected by probing the
81 * IP-Address of the interface that is pointing towards the remote IP-Address,
82 * if no remote IP-Address is known yet, the statically configured
83 * IP-Addresses are used as fallback. */
84void mgcp_get_local_addr(char *addr, struct mgcp_conn_rtp *conn)
85{
86
87 struct mgcp_endpoint *endp;
88 int rc;
89 endp = conn->conn->endp;
90
91 /* Try probing the local IP-Address */
92 if (endp->cfg->net_ports.bind_addr_probe && conn->end.addr.s_addr != 0) {
93 rc = osmo_sock_local_ip(addr, inet_ntoa(conn->end.addr));
94 if (rc < 0)
Pau Espin Pedrol3239f622019-04-24 18:47:46 +020095 LOGPCONN(conn->conn, DRTP, LOGL_ERROR,
96 "local interface auto detection failed, using configured addresses...\n");
Philipp Maier1cb1e382017-11-02 17:16:04 +010097 else {
Pau Espin Pedrol3239f622019-04-24 18:47:46 +020098 LOGPCONN(conn->conn, DRTP, LOGL_DEBUG,
99 "selected local rtp bind ip %s by probing using remote ip %s\n",
100 addr, inet_ntoa(conn->end.addr));
Philipp Maier1cb1e382017-11-02 17:16:04 +0100101 return;
102 }
103 }
104
Pau Espin Pedrola93c6e92019-05-06 15:23:57 +0200105 /* Select from preconfigured IP-Addresses. We don't have bind_addr for Osmux (yet?). */
Philipp Maier1cb1e382017-11-02 17:16:04 +0100106 if (endp->cfg->net_ports.bind_addr) {
107 /* Check there is a bind IP for the RTP traffic configured,
108 * if so, use that IP-Address */
Philipp Maierf8bfbe82017-11-23 19:32:31 +0100109 osmo_strlcpy(addr, endp->cfg->net_ports.bind_addr, INET_ADDRSTRLEN);
Pau Espin Pedrol3239f622019-04-24 18:47:46 +0200110 LOGPCONN(conn->conn, DRTP, LOGL_DEBUG,
111 "using configured rtp bind ip as local bind ip %s\n",
112 addr);
Philipp Maier1cb1e382017-11-02 17:16:04 +0100113 } else {
114 /* No specific bind IP is configured for the RTP traffic, so
115 * assume the IP where we listen for incoming MGCP messages
116 * as bind IP */
Philipp Maierf8bfbe82017-11-23 19:32:31 +0100117 osmo_strlcpy(addr, endp->cfg->source_addr, INET_ADDRSTRLEN);
Pau Espin Pedrol3239f622019-04-24 18:47:46 +0200118 LOGPCONN(conn->conn, DRTP, LOGL_DEBUG,
119 "using mgcp bind ip as local rtp bind ip: %s\n", addr);
Philipp Maier1cb1e382017-11-02 17:16:04 +0100120 }
121}
122
Philipp Maier87bd9be2017-08-22 16:35:41 +0200123/* This does not need to be a precision timestamp and
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200124 * is allowed to wrap quite fast. The returned value is
Philipp Maier87bd9be2017-08-22 16:35:41 +0200125 * 1/codec_rate seconds. */
126static uint32_t get_current_ts(unsigned codec_rate)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200127{
128 struct timespec tp;
129 uint64_t ret;
130
Philipp Maier87bd9be2017-08-22 16:35:41 +0200131 if (!codec_rate)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200132 return 0;
133
134 memset(&tp, 0, sizeof(tp));
135 if (clock_gettime(CLOCK_MONOTONIC, &tp) != 0)
Philipp Maierc3413882017-10-27 12:26:54 +0200136 LOGP(DRTP, LOGL_NOTICE, "Getting the clock failed.\n");
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200137
138 /* convert it to 1/unit seconds */
139 ret = tp.tv_sec;
Philipp Maier87bd9be2017-08-22 16:35:41 +0200140 ret *= codec_rate;
141 ret += (int64_t) tp.tv_nsec * codec_rate / 1000 / 1000 / 1000;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200142
143 return ret;
144}
145
Philipp Maier87bd9be2017-08-22 16:35:41 +0200146/*! send udp packet.
147 * \param[in] fd associated file descriptor
148 * \param[in] addr destination ip-address
Pau Espin Pedrolf1d301a2019-05-13 16:35:53 +0200149 * \param[in] port destination UDP port (network byte order)
Philipp Maier87bd9be2017-08-22 16:35:41 +0200150 * \param[in] buf buffer that holds the data to be send
151 * \param[in] len length of the data to be sent
152 * \returns bytes sent, -1 on error */
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200153int mgcp_udp_send(int fd, struct in_addr *addr, int port, char *buf, int len)
154{
155 struct sockaddr_in out;
Philipp Maier87bd9be2017-08-22 16:35:41 +0200156
Philipp Maierc3413882017-10-27 12:26:54 +0200157 LOGP(DRTP, LOGL_DEBUG,
Philipp Maier87bd9be2017-08-22 16:35:41 +0200158 "sending %i bytes length packet to %s:%u ...\n",
159 len, inet_ntoa(*addr), ntohs(port));
160
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200161 out.sin_family = AF_INET;
162 out.sin_port = port;
163 memcpy(&out.sin_addr, addr, sizeof(*addr));
164
165 return sendto(fd, buf, len, 0, (struct sockaddr *)&out, sizeof(out));
166}
167
Philipp Maier87bd9be2017-08-22 16:35:41 +0200168/*! send RTP dummy packet (to keep NAT connection open).
169 * \param[in] endp mcgp endpoint that holds the RTP connection
170 * \param[in] conn associated RTP connection
171 * \returns bytes sent, -1 on error */
172int mgcp_send_dummy(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200173{
174 static char buf[] = { MGCP_DUMMY_LOAD };
175 int rc;
176 int was_rtcp = 0;
177
Philipp Maier87bd9be2017-08-22 16:35:41 +0200178 OSMO_ASSERT(endp);
179 OSMO_ASSERT(conn);
180
Pau Espin Pedrol3239f622019-04-24 18:47:46 +0200181 LOGPCONN(conn->conn, DRTP, LOGL_DEBUG,"sending dummy packet... %s\n",
182 mgcp_conn_dump(conn->conn));
Philipp Maier87bd9be2017-08-22 16:35:41 +0200183
184 rc = mgcp_udp_send(conn->end.rtp.fd, &conn->end.addr,
185 conn->end.rtp_port, buf, 1);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200186
187 if (rc == -1)
188 goto failed;
189
190 if (endp->tcfg->omit_rtcp)
191 return rc;
192
193 was_rtcp = 1;
Philipp Maier87bd9be2017-08-22 16:35:41 +0200194 rc = mgcp_udp_send(conn->end.rtcp.fd, &conn->end.addr,
195 conn->end.rtcp_port, buf, 1);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200196
197 if (rc >= 0)
198 return rc;
199
200failed:
Pau Espin Pedrol3239f622019-04-24 18:47:46 +0200201 LOGPCONN(conn->conn, DRTP, LOGL_ERROR,
202 "Failed to send dummy %s packet.\n",
203 was_rtcp ? "RTCP" : "RTP");
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200204
205 return -1;
206}
207
Philipp Maier87bd9be2017-08-22 16:35:41 +0200208/* Compute timestamp alignment error */
209static int32_t ts_alignment_error(struct mgcp_rtp_stream_state *sstate,
210 int ptime, uint32_t timestamp)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200211{
212 int32_t timestamp_delta;
213
214 if (ptime == 0)
215 return 0;
216
217 /* Align according to: T - Tlast = k * Tptime */
218 timestamp_delta = timestamp - sstate->last_timestamp;
219
220 return timestamp_delta % ptime;
221}
222
Philipp Maier87bd9be2017-08-22 16:35:41 +0200223/* Check timestamp and sequence number for plausibility */
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200224static int check_rtp_timestamp(struct mgcp_endpoint *endp,
225 struct mgcp_rtp_state *state,
226 struct mgcp_rtp_stream_state *sstate,
227 struct mgcp_rtp_end *rtp_end,
228 struct sockaddr_in *addr,
229 uint16_t seq, uint32_t timestamp,
Philipp Maier87bd9be2017-08-22 16:35:41 +0200230 const char *text, int32_t * tsdelta_out)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200231{
232 int32_t tsdelta;
233 int32_t timestamp_error;
234
235 /* Not fully intialized, skip */
236 if (sstate->last_tsdelta == 0 && timestamp == sstate->last_timestamp)
237 return 0;
238
239 if (seq == sstate->last_seq) {
240 if (timestamp != sstate->last_timestamp) {
Philipp Maier9e1d1642018-05-09 16:26:34 +0200241 rate_ctr_inc(sstate->err_ts_ctr);
Pau Espin Pedrol3239f622019-04-24 18:47:46 +0200242 LOGPENDP(endp, DRTP, LOGL_ERROR,
243 "The %s timestamp delta is != 0 but the sequence "
244 "number %d is the same, "
245 "TS offset: %d, SeqNo offset: %d "
246 "on SSRC: %u timestamp: %u "
247 "from %s:%d\n",
248 text, seq,
249 state->patch.timestamp_offset, state->patch.seq_offset,
250 sstate->ssrc, timestamp, inet_ntoa(addr->sin_addr),
251 ntohs(addr->sin_port));
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200252 }
253 return 0;
254 }
255
256 tsdelta =
Philipp Maier87bd9be2017-08-22 16:35:41 +0200257 (int32_t)(timestamp - sstate->last_timestamp) /
258 (int16_t)(seq - sstate->last_seq);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200259
260 if (tsdelta == 0) {
261 /* Don't update *tsdelta_out */
Pau Espin Pedrol3239f622019-04-24 18:47:46 +0200262 LOGPENDP(endp, DRTP, LOGL_NOTICE,
263 "The %s timestamp delta is %d "
264 "on SSRC: %u timestamp: %u "
265 "from %s:%d\n",
266 text, tsdelta,
267 sstate->ssrc, timestamp,
268 inet_ntoa(addr->sin_addr), ntohs(addr->sin_port));
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200269
270 return 0;
271 }
272
273 if (sstate->last_tsdelta != tsdelta) {
274 if (sstate->last_tsdelta) {
Pau Espin Pedrol3239f622019-04-24 18:47:46 +0200275 LOGPENDP(endp, DRTP, LOGL_INFO,
276 "The %s timestamp delta changes from %d to %d "
277 "on SSRC: %u timestamp: %u from %s:%d\n",
278 text, sstate->last_tsdelta, tsdelta,
279 sstate->ssrc, timestamp,
280 inet_ntoa(addr->sin_addr), ntohs(addr->sin_port));
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200281 }
282 }
283
284 if (tsdelta_out)
285 *tsdelta_out = tsdelta;
286
287 timestamp_error =
Philipp Maier87bd9be2017-08-22 16:35:41 +0200288 ts_alignment_error(sstate, state->packet_duration, timestamp);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200289
290 if (timestamp_error) {
Philipp Maier9e1d1642018-05-09 16:26:34 +0200291 rate_ctr_inc(sstate->err_ts_ctr);
Pau Espin Pedrol3239f622019-04-24 18:47:46 +0200292 LOGPENDP(endp, DRTP, LOGL_NOTICE,
293 "The %s timestamp has an alignment error of %d "
294 "on SSRC: %u "
295 "SeqNo delta: %d, TS delta: %d, dTS/dSeq: %d "
296 "from %s:%d. ptime: %d\n",
297 text, timestamp_error,
298 sstate->ssrc,
299 (int16_t)(seq - sstate->last_seq),
300 (int32_t)(timestamp - sstate->last_timestamp),
301 tsdelta,
302 inet_ntoa(addr->sin_addr), ntohs(addr->sin_port),
303 state->packet_duration);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200304 }
305 return 1;
306}
307
308/* Set the timestamp offset according to the packet duration. */
309static int adjust_rtp_timestamp_offset(struct mgcp_endpoint *endp,
310 struct mgcp_rtp_state *state,
311 struct mgcp_rtp_end *rtp_end,
312 struct sockaddr_in *addr,
313 int16_t delta_seq, uint32_t in_timestamp)
314{
315 int32_t tsdelta = state->packet_duration;
316 int timestamp_offset;
317 uint32_t out_timestamp;
318
319 if (tsdelta == 0) {
320 tsdelta = state->out_stream.last_tsdelta;
321 if (tsdelta != 0) {
Pau Espin Pedrol3239f622019-04-24 18:47:46 +0200322 LOGPENDP(endp, DRTP, LOGL_NOTICE,
323 "A fixed packet duration is not available, "
324 "using last output timestamp delta instead: %d "
325 "from %s:%d\n", tsdelta,
326 inet_ntoa(addr->sin_addr), ntohs(addr->sin_port));
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200327 } else {
Philipp Maierbc0346e2018-06-07 09:52:16 +0200328 tsdelta = rtp_end->codec->rate * 20 / 1000;
Pau Espin Pedrol3239f622019-04-24 18:47:46 +0200329 LOGPENDP(endp, DRTP, LOGL_NOTICE,
330 "Fixed packet duration and last timestamp delta "
331 "are not available, "
332 "using fixed 20ms instead: %d "
333 "from %s:%d\n", tsdelta,
334 inet_ntoa(addr->sin_addr), ntohs(addr->sin_port));
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200335 }
336 }
337
338 out_timestamp = state->out_stream.last_timestamp + delta_seq * tsdelta;
339 timestamp_offset = out_timestamp - in_timestamp;
340
Harald Welte33381352017-12-25 09:44:26 +0100341 if (state->patch.timestamp_offset != timestamp_offset) {
342 state->patch.timestamp_offset = timestamp_offset;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200343
Pau Espin Pedrol3239f622019-04-24 18:47:46 +0200344 LOGPENDP(endp, DRTP, LOGL_NOTICE,
345 "Timestamp offset change on SSRC: %u "
346 "SeqNo delta: %d, TS offset: %d, "
347 "from %s:%d\n", state->in_stream.ssrc,
348 delta_seq, state->patch.timestamp_offset,
349 inet_ntoa(addr->sin_addr), ntohs(addr->sin_port));
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200350 }
351
352 return timestamp_offset;
353}
354
355/* Set the timestamp offset according to the packet duration. */
356static int align_rtp_timestamp_offset(struct mgcp_endpoint *endp,
357 struct mgcp_rtp_state *state,
358 struct mgcp_rtp_end *rtp_end,
359 struct sockaddr_in *addr,
360 uint32_t timestamp)
361{
Philipp Maier87bd9be2017-08-22 16:35:41 +0200362 int ts_error = 0;
363 int ts_check = 0;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200364 int ptime = state->packet_duration;
365
366 /* Align according to: T + Toffs - Tlast = k * Tptime */
367
Philipp Maier87bd9be2017-08-22 16:35:41 +0200368 ts_error = ts_alignment_error(&state->out_stream, ptime,
Harald Welte33381352017-12-25 09:44:26 +0100369 timestamp + state->patch.timestamp_offset);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200370
Philipp Maier87bd9be2017-08-22 16:35:41 +0200371 /* If there is an alignment error, we have to compensate it */
372 if (ts_error) {
Harald Welte33381352017-12-25 09:44:26 +0100373 state->patch.timestamp_offset += ptime - ts_error;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200374
Pau Espin Pedrol3239f622019-04-24 18:47:46 +0200375 LOGPENDP(endp, DRTP, LOGL_NOTICE,
376 "Corrected timestamp alignment error of %d on SSRC: %u "
377 "new TS offset: %d, "
378 "from %s:%d\n",
379 ts_error, state->in_stream.ssrc,
380 state->patch.timestamp_offset, inet_ntoa(addr->sin_addr),
381 ntohs(addr->sin_port));
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200382 }
383
Philipp Maier87bd9be2017-08-22 16:35:41 +0200384 /* Check we really managed to compensate the timestamp
385 * offset. There should not be any remaining error, failing
Harald Welte1d1b98f2017-12-25 10:03:40 +0100386 * here would point to a serous problem with the alignment
387 * error computation function */
Philipp Maier87bd9be2017-08-22 16:35:41 +0200388 ts_check = ts_alignment_error(&state->out_stream, ptime,
Harald Welte33381352017-12-25 09:44:26 +0100389 timestamp + state->patch.timestamp_offset);
Philipp Maier87bd9be2017-08-22 16:35:41 +0200390 OSMO_ASSERT(ts_check == 0);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200391
Philipp Maier87bd9be2017-08-22 16:35:41 +0200392 /* Return alignment error before compensation */
393 return ts_error;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200394}
395
Philipp Maier87bd9be2017-08-22 16:35:41 +0200396/*! dummy callback to disable transcoding (see also cfg->rtp_processing_cb).
397 * \param[in] associated endpoint
398 * \param[in] destination RTP end
399 * \param[in,out] pointer to buffer with voice data
400 * \param[in] voice data length
Harald Welte1d1b98f2017-12-25 10:03:40 +0100401 * \param[in] maximum size of caller provided voice data buffer
Philipp Maier87bd9be2017-08-22 16:35:41 +0200402 * \returns ignores input parameters, return always 0 */
403int mgcp_rtp_processing_default(struct mgcp_endpoint *endp,
404 struct mgcp_rtp_end *dst_end,
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200405 char *data, int *len, int buf_size)
406{
Pau Espin Pedrol3239f622019-04-24 18:47:46 +0200407 LOGPENDP(endp, DRTP, LOGL_DEBUG, "transcoding disabled\n");
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200408 return 0;
409}
410
Philipp Maier87bd9be2017-08-22 16:35:41 +0200411/*! dummy callback to disable transcoding (see also cfg->setup_rtp_processing_cb).
412 * \param[in] associated endpoint
Philipp Maieracc10352018-07-19 18:07:57 +0200413 * \param[in] destination RTP connnection
414 * \param[in] source RTP connection
Philipp Maier87bd9be2017-08-22 16:35:41 +0200415 * \returns ignores input parameters, return always 0 */
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200416int mgcp_setup_rtp_processing_default(struct mgcp_endpoint *endp,
Philipp Maieracc10352018-07-19 18:07:57 +0200417 struct mgcp_conn_rtp *conn_dst,
418 struct mgcp_conn_rtp *conn_src)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200419{
Pau Espin Pedrol3239f622019-04-24 18:47:46 +0200420 LOGPENDP(endp, DRTP, LOGL_DEBUG, "transcoding disabled\n");
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200421 return 0;
422}
423
424void mgcp_get_net_downlink_format_default(struct mgcp_endpoint *endp,
Philipp Maier58128252019-03-06 11:28:18 +0100425 const struct mgcp_rtp_codec **codec,
Philipp Maier87bd9be2017-08-22 16:35:41 +0200426 const char **fmtp_extra,
427 struct mgcp_conn_rtp *conn)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200428{
Pau Espin Pedrol3239f622019-04-24 18:47:46 +0200429 LOGPENDP(endp, DRTP, LOGL_DEBUG, "conn:%s using format defaults\n",
430 mgcp_conn_dump(conn->conn));
Philipp Maier87bd9be2017-08-22 16:35:41 +0200431
Philipp Maier58128252019-03-06 11:28:18 +0100432 *codec = conn->end.codec;
Philipp Maier87bd9be2017-08-22 16:35:41 +0200433 *fmtp_extra = conn->end.fmtp_extra;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200434}
435
Philipp Maier87bd9be2017-08-22 16:35:41 +0200436void mgcp_rtp_annex_count(struct mgcp_endpoint *endp,
437 struct mgcp_rtp_state *state, const uint16_t seq,
438 const int32_t transit, const uint32_t ssrc)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200439{
440 int32_t d;
441
442 /* initialize or re-initialize */
Harald Welte49e3d5a2017-12-25 09:47:57 +0100443 if (!state->stats.initialized || state->stats.ssrc != ssrc) {
444 state->stats.initialized = 1;
445 state->stats.base_seq = seq;
446 state->stats.max_seq = seq - 1;
447 state->stats.ssrc = ssrc;
448 state->stats.jitter = 0;
449 state->stats.transit = transit;
450 state->stats.cycles = 0;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200451 } else {
452 uint16_t udelta;
453
Philipp Maier87bd9be2017-08-22 16:35:41 +0200454 /* The below takes the shape of the validation of
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200455 * Appendix A. Check if there is something weird with
456 * the sequence number, otherwise check for a wrap
457 * around in the sequence number.
458 * It can't wrap during the initialization so let's
459 * skip it here. The Appendix A probably doesn't have
Philipp Maier87bd9be2017-08-22 16:35:41 +0200460 * this issue because of the probation. */
Harald Welte49e3d5a2017-12-25 09:47:57 +0100461 udelta = seq - state->stats.max_seq;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200462 if (udelta < RTP_MAX_DROPOUT) {
Harald Welte49e3d5a2017-12-25 09:47:57 +0100463 if (seq < state->stats.max_seq)
464 state->stats.cycles += RTP_SEQ_MOD;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200465 } else if (udelta <= RTP_SEQ_MOD - RTP_MAX_MISORDER) {
Pau Espin Pedrol3239f622019-04-24 18:47:46 +0200466 LOGPENDP(endp, DRTP, LOGL_NOTICE,
467 "RTP seqno made a very large jump on delta: %u\n",
468 udelta);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200469 }
470 }
471
Philipp Maier87bd9be2017-08-22 16:35:41 +0200472 /* Calculate the jitter between the two packages. The TS should be
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200473 * taken closer to the read function. This was taken from the
474 * Appendix A of RFC 3550. Timestamp and arrival_time have a 1/rate
Philipp Maier87bd9be2017-08-22 16:35:41 +0200475 * resolution. */
Harald Welte49e3d5a2017-12-25 09:47:57 +0100476 d = transit - state->stats.transit;
477 state->stats.transit = transit;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200478 if (d < 0)
479 d = -d;
Harald Welte49e3d5a2017-12-25 09:47:57 +0100480 state->stats.jitter += d - ((state->stats.jitter + 8) >> 4);
481 state->stats.max_seq = seq;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200482}
483
Philipp Maier6931f9a2018-07-26 09:29:31 +0200484/* There may be different payload type numbers negotiated for two connections.
485 * Patch the payload type of an RTP packet so that it uses the payload type
486 * that is valid for the destination connection (conn_dst) */
487static int mgcp_patch_pt(struct mgcp_conn_rtp *conn_src,
488 struct mgcp_conn_rtp *conn_dst, char *data, int len)
489{
490 struct rtp_hdr *rtp_hdr;
491 uint8_t pt_in;
492 int pt_out;
493
Neels Hofmeyr7c6dd3c2019-08-20 03:06:17 +0200494 if (len < sizeof(struct rtp_hdr))
495 return -EINVAL;
496
Philipp Maier6931f9a2018-07-26 09:29:31 +0200497 rtp_hdr = (struct rtp_hdr *)data;
498
499 pt_in = rtp_hdr->payload_type;
500 pt_out = mgcp_codec_pt_translate(conn_src, conn_dst, pt_in);
501 if (pt_out < 0)
502 return -EINVAL;
503
504 rtp_hdr->payload_type = (uint8_t) pt_out;
505 return 0;
506}
507
Philipp Maier87bd9be2017-08-22 16:35:41 +0200508/* The RFC 3550 Appendix A assumes there are multiple sources but
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200509 * some of the supported endpoints (e.g. the nanoBTS) can only handle
510 * one source and this code will patch RTP header to appear as if there
511 * is only one source.
512 * There is also no probation period for new sources. Every RTP header
Philipp Maier87bd9be2017-08-22 16:35:41 +0200513 * we receive will be seen as a switch in streams. */
514void mgcp_patch_and_count(struct mgcp_endpoint *endp,
515 struct mgcp_rtp_state *state,
516 struct mgcp_rtp_end *rtp_end,
517 struct sockaddr_in *addr, char *data, int len)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200518{
519 uint32_t arrival_time;
520 int32_t transit;
521 uint16_t seq;
522 uint32_t timestamp, ssrc;
523 struct rtp_hdr *rtp_hdr;
Philipp Maierbc0346e2018-06-07 09:52:16 +0200524 int payload = rtp_end->codec->payload_type;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200525
526 if (len < sizeof(*rtp_hdr))
527 return;
528
Philipp Maier87bd9be2017-08-22 16:35:41 +0200529 rtp_hdr = (struct rtp_hdr *)data;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200530 seq = ntohs(rtp_hdr->sequence);
531 timestamp = ntohl(rtp_hdr->timestamp);
Philipp Maierbc0346e2018-06-07 09:52:16 +0200532 arrival_time = get_current_ts(rtp_end->codec->rate);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200533 ssrc = ntohl(rtp_hdr->ssrc);
534 transit = arrival_time - timestamp;
535
536 mgcp_rtp_annex_count(endp, state, seq, transit, ssrc);
537
538 if (!state->initialized) {
539 state->initialized = 1;
540 state->in_stream.last_seq = seq - 1;
Harald Welte33381352017-12-25 09:44:26 +0100541 state->in_stream.ssrc = state->patch.orig_ssrc = ssrc;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200542 state->in_stream.last_tsdelta = 0;
Philipp Maier87bd9be2017-08-22 16:35:41 +0200543 state->packet_duration =
544 mgcp_rtp_packet_duration(endp, rtp_end);
Philipp Maier0ec1d4e2018-05-16 11:09:42 +0200545 state->out_stream.last_seq = seq - 1;
546 state->out_stream.ssrc = state->patch.orig_ssrc = ssrc;
547 state->out_stream.last_tsdelta = 0;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200548 state->out_stream.last_timestamp = timestamp;
Philipp Maier87bd9be2017-08-22 16:35:41 +0200549 state->out_stream.ssrc = ssrc - 1; /* force output SSRC change */
Pau Espin Pedrol3239f622019-04-24 18:47:46 +0200550 LOGPENDP(endp, DRTP, LOGL_INFO,
551 "initializing stream, SSRC: %u timestamp: %u "
552 "pkt-duration: %d, from %s:%d\n",
553 state->in_stream.ssrc,
554 state->patch.seq_offset, state->packet_duration,
555 inet_ntoa(addr->sin_addr), ntohs(addr->sin_port));
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200556 if (state->packet_duration == 0) {
Philipp Maier87bd9be2017-08-22 16:35:41 +0200557 state->packet_duration =
Philipp Maierbc0346e2018-06-07 09:52:16 +0200558 rtp_end->codec->rate * 20 / 1000;
Pau Espin Pedrol3239f622019-04-24 18:47:46 +0200559 LOGPENDP(endp, DRTP, LOGL_NOTICE,
560 "fixed packet duration is not available, "
561 "using fixed 20ms instead: %d from %s:%d\n",
562 state->packet_duration,
563 inet_ntoa(addr->sin_addr), ntohs(addr->sin_port));
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200564 }
565 } else if (state->in_stream.ssrc != ssrc) {
Pau Espin Pedrol3239f622019-04-24 18:47:46 +0200566 LOGPENDP(endp, DRTP, LOGL_NOTICE,
567 "SSRC changed: %u -> %u "
568 "from %s:%d\n",
569 state->in_stream.ssrc, rtp_hdr->ssrc,
570 inet_ntoa(addr->sin_addr), ntohs(addr->sin_port));
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200571
572 state->in_stream.ssrc = ssrc;
573 if (rtp_end->force_constant_ssrc) {
574 int16_t delta_seq;
575
576 /* Always increment seqno by 1 */
Harald Welte33381352017-12-25 09:44:26 +0100577 state->patch.seq_offset =
Philipp Maier87bd9be2017-08-22 16:35:41 +0200578 (state->out_stream.last_seq + 1) - seq;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200579
580 /* Estimate number of packets that would have been sent */
581 delta_seq =
Philipp Maier87bd9be2017-08-22 16:35:41 +0200582 (arrival_time - state->in_stream.last_arrival_time
583 + state->packet_duration / 2) /
584 state->packet_duration;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200585
586 adjust_rtp_timestamp_offset(endp, state, rtp_end, addr,
587 delta_seq, timestamp);
588
Harald Welte33381352017-12-25 09:44:26 +0100589 state->patch.patch_ssrc = 1;
590 ssrc = state->patch.orig_ssrc;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200591 if (rtp_end->force_constant_ssrc != -1)
592 rtp_end->force_constant_ssrc -= 1;
593
Pau Espin Pedrol3239f622019-04-24 18:47:46 +0200594 LOGPENDP(endp, DRTP, LOGL_NOTICE,
595 "SSRC patching enabled, SSRC: %u "
596 "SeqNo offset: %d, TS offset: %d "
597 "from %s:%d\n", state->in_stream.ssrc,
598 state->patch.seq_offset, state->patch.timestamp_offset,
599 inet_ntoa(addr->sin_addr), ntohs(addr->sin_port));
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200600 }
601
602 state->in_stream.last_tsdelta = 0;
603 } else {
604 /* Compute current per-packet timestamp delta */
Philipp Maier87bd9be2017-08-22 16:35:41 +0200605 check_rtp_timestamp(endp, state, &state->in_stream, rtp_end,
606 addr, seq, timestamp, "input",
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200607 &state->in_stream.last_tsdelta);
608
Harald Welte33381352017-12-25 09:44:26 +0100609 if (state->patch.patch_ssrc)
610 ssrc = state->patch.orig_ssrc;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200611 }
612
613 /* Save before patching */
614 state->in_stream.last_timestamp = timestamp;
615 state->in_stream.last_seq = seq;
616 state->in_stream.last_arrival_time = arrival_time;
617
618 if (rtp_end->force_aligned_timing &&
619 state->out_stream.ssrc == ssrc && state->packet_duration)
620 /* Align the timestamp offset */
Philipp Maier87bd9be2017-08-22 16:35:41 +0200621 align_rtp_timestamp_offset(endp, state, rtp_end, addr,
622 timestamp);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200623
624 /* Store the updated SSRC back to the packet */
Harald Welte33381352017-12-25 09:44:26 +0100625 if (state->patch.patch_ssrc)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200626 rtp_hdr->ssrc = htonl(ssrc);
627
628 /* Apply the offset and store it back to the packet.
629 * This won't change anything if the offset is 0, so the conditional is
630 * omitted. */
Harald Welte33381352017-12-25 09:44:26 +0100631 seq += state->patch.seq_offset;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200632 rtp_hdr->sequence = htons(seq);
Harald Welte33381352017-12-25 09:44:26 +0100633 timestamp += state->patch.timestamp_offset;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200634 rtp_hdr->timestamp = htonl(timestamp);
635
636 /* Check again, whether the timestamps are still valid */
637 if (state->out_stream.ssrc == ssrc)
638 check_rtp_timestamp(endp, state, &state->out_stream, rtp_end,
639 addr, seq, timestamp, "output",
640 &state->out_stream.last_tsdelta);
641
642 /* Save output values */
643 state->out_stream.last_seq = seq;
644 state->out_stream.last_timestamp = timestamp;
645 state->out_stream.ssrc = ssrc;
646
647 if (payload < 0)
648 return;
649
650#if 0
Philipp Maierc3413882017-10-27 12:26:54 +0200651 DEBUGP(DRTP,
Philipp Maier230e4fc2017-11-28 09:38:45 +0100652 "endpoint:0x%x payload hdr payload %u -> endp payload %u\n",
Philipp Maier87bd9be2017-08-22 16:35:41 +0200653 ENDPOINT_NUMBER(endp), rtp_hdr->payload_type, payload);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200654 rtp_hdr->payload_type = payload;
655#endif
656}
657
Philipp Maier9fc8a022019-02-20 12:26:52 +0100658/* There are different dialects used to format and transfer voice data. When
659 * the receiving end expects GSM-HR data to be formated after RFC 5993, this
660 * function is used to convert between RFC 5993 and TS 101318, which we normally
Neels Hofmeyr7c6dd3c2019-08-20 03:06:17 +0200661 * use.
662 * Return 0 on sucess, negative on errors like invalid data length. */
663static int rfc5993_hr_convert(struct mgcp_endpoint *endp, char *data, int *len)
Philipp Maier9fc8a022019-02-20 12:26:52 +0100664{
665 /* NOTE: *data has an overall length of RTP_BUF_SIZE, so there is
666 * plenty of space available to store the slightly larger, converted
667 * data */
668
669 struct rtp_hdr *rtp_hdr;
670
Neels Hofmeyr7c6dd3c2019-08-20 03:06:17 +0200671 if (*len < sizeof(struct rtp_hdr)) {
672 LOGPENDP(endp, DRTP, LOGL_ERROR, "AMR RTP packet too short (%d < %zu)\n",
673 *len, sizeof(struct rtp_hdr));
674 return -EINVAL;
675 }
676
Philipp Maier9fc8a022019-02-20 12:26:52 +0100677 rtp_hdr = (struct rtp_hdr *)data;
678
679 if (*len == GSM_HR_BYTES + sizeof(struct rtp_hdr)) {
680 /* TS 101318 encoding => RFC 5993 encoding */
681 memmove(rtp_hdr->data + 1, rtp_hdr->data, GSM_HR_BYTES);
682 rtp_hdr->data[0] = 0x00;
683 (*len) += 1;
684
685 } else if (*len == GSM_HR_BYTES + sizeof(struct rtp_hdr) + 1) {
686 /* RFC 5993 encoding => TS 101318 encoding */
687 memmove(rtp_hdr->data, rtp_hdr->data + 1, GSM_HR_BYTES);
688 (*len) -= 1;
689 } else {
690 /* It is possible that multiple payloads occur in one RTP
691 * packet. This is not supported yet. */
Pau Espin Pedrol3239f622019-04-24 18:47:46 +0200692 LOGPENDP(endp, DRTP, LOGL_ERROR,
693 "cannot figure out how to convert RTP packet\n");
Neels Hofmeyr7c6dd3c2019-08-20 03:06:17 +0200694 return -ENOTSUP;
Philipp Maier9fc8a022019-02-20 12:26:52 +0100695 }
Neels Hofmeyr7c6dd3c2019-08-20 03:06:17 +0200696 return 0;
Philipp Maier9fc8a022019-02-20 12:26:52 +0100697}
698
Philipp Maier228e5912019-03-05 13:56:59 +0100699/* For AMR RTP two framing modes are defined RFC3267. There is a bandwith
700 * efficient encoding scheme where all fields are packed together one after
701 * another and an octet aligned mode where all fields are aligned to octet
702 * boundaries. This function is used to convert between the two modes */
703static int amr_oa_bwe_convert(struct mgcp_endpoint *endp, char *data, int *len,
704 bool target_is_oa)
705{
706 /* NOTE: *data has an overall length of RTP_BUF_SIZE, so there is
707 * plenty of space available to store the slightly larger, converted
708 * data */
709
710 struct rtp_hdr *rtp_hdr;
711 unsigned int payload_len;
712 int rc;
713
Neels Hofmeyr7c6dd3c2019-08-20 03:06:17 +0200714 if (*len < sizeof(struct rtp_hdr)) {
715 LOGPENDP(endp, DRTP, LOGL_ERROR, "AMR RTP packet too short (%d < %zu)\n", *len, sizeof(struct rtp_hdr));
716 return -EINVAL;
717 }
718
Philipp Maier228e5912019-03-05 13:56:59 +0100719 rtp_hdr = (struct rtp_hdr *)data;
720
721 payload_len = *len - sizeof(struct rtp_hdr);
722
723 if (osmo_amr_is_oa(rtp_hdr->data, payload_len)) {
724 if (!target_is_oa)
725 /* Input data is oa an target format is bwe
726 * ==> convert */
727 rc = osmo_amr_oa_to_bwe(rtp_hdr->data, payload_len);
728 else
729 /* Input data is already bew, but we accept it anyway
730 * ==> no conversion needed */
731 rc = payload_len;
732 } else {
733 if (target_is_oa)
734 /* Input data is bwe an target format is oa
735 * ==> convert */
736 rc = osmo_amr_bwe_to_oa(rtp_hdr->data, payload_len,
737 RTP_BUF_SIZE);
738 else
739 /* Input data is already oa, but we accept it anyway
740 * ==> no conversion needed */
741 rc = payload_len;
742 }
743 if (rc < 0) {
Pau Espin Pedrol3239f622019-04-24 18:47:46 +0200744 LOGPENDP(endp, DRTP, LOGL_ERROR,
745 "AMR RTP packet conversion failed\n");
Philipp Maier228e5912019-03-05 13:56:59 +0100746 return -EINVAL;
747 }
748
749 *len = rc + sizeof(struct rtp_hdr);
750
751 return 0;
752}
753
754/* Check if a conversion between octet-aligned and bandwith-efficient mode is
755 * indicated. */
756static bool amr_oa_bwe_convert_indicated(struct mgcp_rtp_codec *codec)
757{
758 if (codec->param_present == false)
759 return false;
760 if (!codec->param.amr_octet_aligned_present)
761 return false;
762 if (strcmp(codec->subtype_name, "AMR") != 0)
763 return false;
764 return true;
765}
766
767
Neels Hofmeyr7c6dd3c2019-08-20 03:06:17 +0200768/* Return whether an RTP packet with AMR payload is in octet-aligned mode.
769 * Return 0 if in bandwidth-efficient mode, 1 for octet-aligned mode, and negative if the RTP data is invalid. */
770static int amr_oa_check(char *data, int len)
Philipp Maier228e5912019-03-05 13:56:59 +0100771{
772 struct rtp_hdr *rtp_hdr;
773 unsigned int payload_len;
774
Neels Hofmeyr7c6dd3c2019-08-20 03:06:17 +0200775 if (len < sizeof(struct rtp_hdr))
776 return -EINVAL;
777
Philipp Maier228e5912019-03-05 13:56:59 +0100778 rtp_hdr = (struct rtp_hdr *)data;
779
780 payload_len = len - sizeof(struct rtp_hdr);
Neels Hofmeyr7c6dd3c2019-08-20 03:06:17 +0200781 if (payload_len < sizeof(struct amr_hdr))
782 return -EINVAL;
Philipp Maier228e5912019-03-05 13:56:59 +0100783
Neels Hofmeyr7c6dd3c2019-08-20 03:06:17 +0200784 return osmo_amr_is_oa(rtp_hdr->data, payload_len) ? 1 : 0;
Philipp Maier228e5912019-03-05 13:56:59 +0100785}
786
Philipp Maier87bd9be2017-08-22 16:35:41 +0200787/* Forward data to a debug tap. This is debug function that is intended for
788 * debugging the voice traffic with tools like gstreamer */
Philipp Maiere6f172d2017-11-07 12:00:01 +0100789static void forward_data(int fd, struct mgcp_rtp_tap *tap, const char *buf,
790 int len)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200791{
Philipp Maiere6f172d2017-11-07 12:00:01 +0100792 int rc;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200793
Philipp Maiere6f172d2017-11-07 12:00:01 +0100794 if (!tap->enabled)
795 return;
796
797 rc = sendto(fd, buf, len, 0, (struct sockaddr *)&tap->forward,
798 sizeof(tap->forward));
799
800 if (rc < 0)
801 LOGP(DRTP, LOGL_ERROR,
802 "Forwarding tapped (debug) voice data failed.\n");
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200803}
804
Philipp Maier87bd9be2017-08-22 16:35:41 +0200805/*! Send RTP/RTCP data to a specified destination connection.
806 * \param[in] endp associated endpoint (for configuration, logging)
807 * \param[in] is_rtp flag to specify if the packet is of type RTP or RTCP
808 * \param[in] spoofed source address (set to NULL to disable)
809 * \param[in] buf buffer that contains the RTP/RTCP data
810 * \param[in] len length of the buffer that contains the RTP/RTCP data
811 * \param[in] conn_src associated source connection
812 * \param[in] conn_dst associated destination connection
813 * \returns 0 on success, -1 on ERROR */
814int mgcp_send(struct mgcp_endpoint *endp, int is_rtp, struct sockaddr_in *addr,
815 char *buf, int len, struct mgcp_conn_rtp *conn_src,
816 struct mgcp_conn_rtp *conn_dst)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200817{
Philipp Maier87bd9be2017-08-22 16:35:41 +0200818 /*! When no destination connection is available (e.g. when only one
819 * connection in loopback mode exists), then the source connection
820 * shall be specified as destination connection */
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200821
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200822 struct mgcp_trunk_config *tcfg = endp->tcfg;
823 struct mgcp_rtp_end *rtp_end;
824 struct mgcp_rtp_state *rtp_state;
Philipp Maier87bd9be2017-08-22 16:35:41 +0200825 char *dest_name;
Philipp Maier6931f9a2018-07-26 09:29:31 +0200826 int rc;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200827
Philipp Maier87bd9be2017-08-22 16:35:41 +0200828 OSMO_ASSERT(conn_src);
829 OSMO_ASSERT(conn_dst);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200830
Philipp Maier87bd9be2017-08-22 16:35:41 +0200831 if (is_rtp) {
Pau Espin Pedrol3239f622019-04-24 18:47:46 +0200832 LOGPENDP(endp, DRTP, LOGL_DEBUG, "delivering RTP packet...\n");
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200833 } else {
Pau Espin Pedrol3239f622019-04-24 18:47:46 +0200834 LOGPENDP(endp, DRTP, LOGL_DEBUG, "delivering RTCP packet...\n");
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200835 }
Philipp Maier87bd9be2017-08-22 16:35:41 +0200836
Pau Espin Pedrol3239f622019-04-24 18:47:46 +0200837 LOGPENDP(endp, DRTP, LOGL_DEBUG, "loop:%d, mode:%d%s\n",
838 tcfg->audio_loop, conn_src->conn->mode,
839 conn_src->conn->mode == MGCP_CONN_LOOPBACK ? " (loopback)" : "");
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200840
Philipp Maier6931f9a2018-07-26 09:29:31 +0200841 /* FIXME: It is legal that the payload type on the egress connection is
842 * different from the payload type that has been negotiated on the
843 * ingress connection. Essentially the codecs are the same so we can
844 * match them and patch the payload type. However, if we can not find
845 * the codec pendant (everything ist equal except the PT), we are of
846 * course unable to patch the payload type. A situation like this
847 * should not occur if transcoding is consequently avoided. Until
848 * we have transcoding support in osmo-mgw we can not resolve this. */
Philipp Maierda895b12018-08-03 12:16:37 +0200849 if (is_rtp) {
850 rc = mgcp_patch_pt(conn_src, conn_dst, buf, len);
851 if (rc < 0) {
Pau Espin Pedrol3239f622019-04-24 18:47:46 +0200852 LOGPENDP(endp, DRTP, LOGL_DEBUG,
853 "can not patch PT because no suitable egress codec was found.\n");
Philipp Maierda895b12018-08-03 12:16:37 +0200854 }
Philipp Maier6931f9a2018-07-26 09:29:31 +0200855 }
856
Philipp Maier87bd9be2017-08-22 16:35:41 +0200857 /* Note: In case of loopback configuration, both, the source and the
858 * destination will point to the same connection. */
859 rtp_end = &conn_dst->end;
860 rtp_state = &conn_src->state;
861 dest_name = conn_dst->conn->name;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200862
863 if (!rtp_end->output_enabled) {
Harald Weltea48ff4a2020-03-08 14:45:08 +0100864 rtpconn_rate_ctr_inc(conn_dst, endp, RTP_DROPPED_PACKETS_CTR);
Pau Espin Pedrol3239f622019-04-24 18:47:46 +0200865 LOGPENDP(endp, DRTP, LOGL_DEBUG,
866 "output disabled, drop to %s %s "
867 "rtp_port:%u rtcp_port:%u\n",
868 dest_name,
869 inet_ntoa(rtp_end->addr),
870 ntohs(rtp_end->rtp_port), ntohs(rtp_end->rtcp_port)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200871 );
872 } else if (is_rtp) {
873 int cont;
874 int nbytes = 0;
Philipp Maier87bd9be2017-08-22 16:35:41 +0200875 int buflen = len;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200876 do {
Philipp Maier87bd9be2017-08-22 16:35:41 +0200877 /* Run transcoder */
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200878 cont = endp->cfg->rtp_processing_cb(endp, rtp_end,
Philipp Maier87bd9be2017-08-22 16:35:41 +0200879 buf, &buflen,
880 RTP_BUF_SIZE);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200881 if (cont < 0)
882 break;
883
Philipp Maier87bd9be2017-08-22 16:35:41 +0200884 if (addr)
885 mgcp_patch_and_count(endp, rtp_state, rtp_end,
886 addr, buf, buflen);
Philipp Maier9fc8a022019-02-20 12:26:52 +0100887
Philipp Maier228e5912019-03-05 13:56:59 +0100888 if (amr_oa_bwe_convert_indicated(conn_dst->end.codec)) {
Neels Hofmeyr5a6220f2019-08-20 03:09:04 +0200889 rc = amr_oa_bwe_convert(endp, buf, &buflen,
890 conn_dst->end.codec->param.amr_octet_aligned);
891 if (rc < 0) {
892 LOGPENDP(endp, DRTP, LOGL_ERROR,
893 "Error in AMR octet-aligned <-> bandwidth-efficient mode conversion\n");
894 break;
895 }
Philipp Maier228e5912019-03-05 13:56:59 +0100896 }
897 else if (rtp_end->rfc5993_hr_convert
Philipp Maier9fc8a022019-02-20 12:26:52 +0100898 && strcmp(conn_src->end.codec->subtype_name,
Neels Hofmeyr5a6220f2019-08-20 03:09:04 +0200899 "GSM-HR-08") == 0) {
900 rc = rfc5993_hr_convert(endp, buf, &buflen);
901 if (rc < 0) {
902 LOGPENDP(endp, DRTP, LOGL_ERROR, "Error while converting to GSM-HR-08\n");
903 break;
904 }
905 }
Philipp Maier9fc8a022019-02-20 12:26:52 +0100906
Pau Espin Pedrol3239f622019-04-24 18:47:46 +0200907 LOGPENDP(endp, DRTP, LOGL_DEBUG,
908 "process/send to %s %s "
909 "rtp_port:%u rtcp_port:%u\n",
910 dest_name, inet_ntoa(rtp_end->addr),
911 ntohs(rtp_end->rtp_port), ntohs(rtp_end->rtcp_port)
912 );
Philipp Maier87bd9be2017-08-22 16:35:41 +0200913
914 /* Forward a copy of the RTP data to a debug ip/port */
915 forward_data(rtp_end->rtp.fd, &conn_src->tap_out,
916 buf, buflen);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200917
918 /* FIXME: HACK HACK HACK. See OS#2459.
919 * The ip.access nano3G needs the first RTP payload's first two bytes to read hex
920 * 'e400', or it will reject the RAB assignment. It seems to not harm other femto
921 * cells (as long as we patch only the first RTP payload in each stream).
922 */
Neels Hofmeyr35a38292018-07-23 18:29:04 +0200923 if (!rtp_state->patched_first_rtp_payload
924 && conn_src->conn->mode == MGCP_CONN_LOOPBACK) {
Philipp Maier87bd9be2017-08-22 16:35:41 +0200925 uint8_t *data = (uint8_t *) & buf[12];
Neels Hofmeyr35a38292018-07-23 18:29:04 +0200926 if (data[0] == 0xe0) {
927 data[0] = 0xe4;
928 data[1] = 0x00;
929 rtp_state->patched_first_rtp_payload = true;
Pau Espin Pedrol3239f622019-04-24 18:47:46 +0200930 LOGPENDP(endp, DRTP, LOGL_DEBUG,
931 "Patching over first two bytes"
932 " to fake an IuUP Initialization Ack\n");
Neels Hofmeyr35a38292018-07-23 18:29:04 +0200933 }
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200934 }
935
Philipp Maier87bd9be2017-08-22 16:35:41 +0200936 len = mgcp_udp_send(rtp_end->rtp.fd,
937 &rtp_end->addr,
938 rtp_end->rtp_port, buf, buflen);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200939
Philipp Maier87bd9be2017-08-22 16:35:41 +0200940 if (len <= 0)
941 return len;
942
Harald Weltea48ff4a2020-03-08 14:45:08 +0100943 rtpconn_rate_ctr_inc(conn_dst, endp, RTP_PACKETS_TX_CTR);
944 rtpconn_rate_ctr_add(conn_dst, endp, RTP_OCTETS_TX_CTR, len);
Philipp Maier87bd9be2017-08-22 16:35:41 +0200945
946 nbytes += len;
947 buflen = cont;
948 } while (buflen > 0);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200949 return nbytes;
950 } else if (!tcfg->omit_rtcp) {
Pau Espin Pedrol3239f622019-04-24 18:47:46 +0200951 LOGPENDP(endp, DRTP, LOGL_DEBUG,
952 "send to %s %s rtp_port:%u rtcp_port:%u\n",
953 dest_name, inet_ntoa(rtp_end->addr),
954 ntohs(rtp_end->rtp_port), ntohs(rtp_end->rtcp_port)
955 );
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200956
Philipp Maier87bd9be2017-08-22 16:35:41 +0200957 len = mgcp_udp_send(rtp_end->rtcp.fd,
958 &rtp_end->addr,
959 rtp_end->rtcp_port, buf, len);
960
Harald Weltea48ff4a2020-03-08 14:45:08 +0100961 rtpconn_rate_ctr_inc(conn_dst, endp, RTP_PACKETS_TX_CTR);
962 rtpconn_rate_ctr_add(conn_dst, endp, RTP_OCTETS_TX_CTR, len);
Philipp Maier87bd9be2017-08-22 16:35:41 +0200963
964 return len;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200965 }
966
967 return 0;
968}
969
Philipp Maier87bd9be2017-08-22 16:35:41 +0200970/* Helper function for mgcp_recv(),
971 Receive one RTP Packet + Originating address from file descriptor */
972static int receive_from(struct mgcp_endpoint *endp, int fd,
973 struct sockaddr_in *addr, char *buf, int bufsize)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200974{
975 int rc;
976 socklen_t slen = sizeof(*addr);
Philipp Maier87bd9be2017-08-22 16:35:41 +0200977 struct sockaddr_in addr_sink;
978 char buf_sink[RTP_BUF_SIZE];
979 bool tossed = false;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200980
Philipp Maier87bd9be2017-08-22 16:35:41 +0200981 if (!addr)
982 addr = &addr_sink;
983 if (!buf) {
984 tossed = true;
985 buf = buf_sink;
986 bufsize = sizeof(buf_sink);
987 }
988
989 rc = recvfrom(fd, buf, bufsize, 0, (struct sockaddr *)addr, &slen);
990
Pau Espin Pedrol3239f622019-04-24 18:47:46 +0200991 LOGPENDP(endp, DRTP, LOGL_DEBUG,
Philipp Maier87bd9be2017-08-22 16:35:41 +0200992 "receiving %u bytes length packet from %s:%u ...\n",
993 rc, inet_ntoa(addr->sin_addr), ntohs(addr->sin_port));
994
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200995 if (rc < 0) {
Pau Espin Pedrol3239f622019-04-24 18:47:46 +0200996 LOGPENDP(endp, DRTP, LOGL_ERROR,
997 "failed to receive packet, errno: %d/%s\n",
998 errno, strerror(errno));
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200999 return -1;
1000 }
1001
Philipp Maier87bd9be2017-08-22 16:35:41 +02001002 if (tossed) {
Pau Espin Pedrol3239f622019-04-24 18:47:46 +02001003 LOGPENDP(endp, DRTP, LOGL_ERROR, "packet tossed\n");
Philipp Maier87bd9be2017-08-22 16:35:41 +02001004 }
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001005
1006 return rc;
1007}
1008
Philipp Maier87bd9be2017-08-22 16:35:41 +02001009/* Check if the origin (addr) matches the address/port data of the RTP
1010 * connections. */
1011static int check_rtp_origin(struct mgcp_conn_rtp *conn,
1012 struct sockaddr_in *addr)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001013{
Harald Weltec26b6652018-10-21 12:01:04 +02001014 if (conn->end.addr.s_addr == 0) {
Neels Hofmeyrefd645e2018-09-10 13:14:50 +02001015 switch (conn->conn->mode) {
1016 case MGCP_CONN_LOOPBACK:
1017 /* HACK: for IuUP, we want to reply with an IuUP Initialization ACK upon the first RTP
1018 * message received. We currently hackishly accomplish that by putting the endpoint in
1019 * loopback mode and patching over the looped back RTP message to make it look like an
1020 * ack. We don't know the femto cell's IP address and port until the RAB Assignment
1021 * Response is received, but the nano3G expects an IuUP Initialization Ack before it even
1022 * sends the RAB Assignment Response. Hence, if the remote address is 0.0.0.0 and the
1023 * MGCP port is in loopback mode, allow looping back the packet to any source. */
Pau Espin Pedrol3239f622019-04-24 18:47:46 +02001024 LOGPCONN(conn->conn, DRTP, LOGL_ERROR,
1025 "In loopback mode and remote address not set:"
1026 " allowing data from address: %s\n", inet_ntoa(addr->sin_addr));
Neels Hofmeyrefd645e2018-09-10 13:14:50 +02001027 return 0;
1028
1029 default:
1030 /* Receiving early media before the endpoint is configured. Instead of logging
1031 * this as an error that occurs on every call, keep it more low profile to not
1032 * confuse humans with expected errors. */
Pau Espin Pedrol3239f622019-04-24 18:47:46 +02001033 LOGPCONN(conn->conn, DRTP, LOGL_INFO,
1034 "Rx RTP from %s, but remote address not set:"
1035 " dropping early media\n", inet_ntoa(addr->sin_addr));
Neels Hofmeyrefd645e2018-09-10 13:14:50 +02001036 return -1;
1037 }
Neels Hofmeyr0063ca22018-07-23 18:12:16 +02001038 }
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001039
Philipp Maier87bd9be2017-08-22 16:35:41 +02001040 /* Note: Check if the inbound RTP data comes from the same host to
1041 * which we send our outgoing RTP traffic. */
Harald Weltec26b6652018-10-21 12:01:04 +02001042 if (conn->end.addr.s_addr != addr->sin_addr.s_addr) {
Pau Espin Pedrol3239f622019-04-24 18:47:46 +02001043 LOGPCONN(conn->conn, DRTP, LOGL_ERROR,
1044 "data from wrong address: %s, ", inet_ntoa(addr->sin_addr));
Philipp Maierc3413882017-10-27 12:26:54 +02001045 LOGPC(DRTP, LOGL_ERROR, "expected: %s\n",
Philipp Maier87bd9be2017-08-22 16:35:41 +02001046 inet_ntoa(conn->end.addr));
Pau Espin Pedrol3239f622019-04-24 18:47:46 +02001047 LOGPCONN(conn->conn, DRTP, LOGL_ERROR, "packet tossed\n");
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001048 return -1;
1049 }
1050
Philipp Maier87bd9be2017-08-22 16:35:41 +02001051 /* Note: Usually the remote remote port of the data we receive will be
1052 * the same as the remote port where we transmit outgoing RTP traffic
1053 * to (set by MDCX). We use this to check the origin of the data for
1054 * plausibility. */
1055 if (conn->end.rtp_port != addr->sin_port &&
1056 conn->end.rtcp_port != addr->sin_port) {
Pau Espin Pedrol3239f622019-04-24 18:47:46 +02001057 LOGPCONN(conn->conn, DRTP, LOGL_ERROR,
1058 "data from wrong source port: %d, ", ntohs(addr->sin_port));
Philipp Maierc3413882017-10-27 12:26:54 +02001059 LOGPC(DRTP, LOGL_ERROR,
Philipp Maier87bd9be2017-08-22 16:35:41 +02001060 "expected: %d for RTP or %d for RTCP\n",
1061 ntohs(conn->end.rtp_port), ntohs(conn->end.rtcp_port));
Pau Espin Pedrol3239f622019-04-24 18:47:46 +02001062 LOGPCONN(conn->conn, DRTP, LOGL_ERROR, "packet tossed\n");
Philipp Maier87bd9be2017-08-22 16:35:41 +02001063 return -1;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001064 }
1065
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001066 return 0;
1067}
1068
Philipp Maier87bd9be2017-08-22 16:35:41 +02001069/* Check the if the destination address configuration of an RTP connection
1070 * makes sense */
1071static int check_rtp_destin(struct mgcp_conn_rtp *conn)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001072{
Philipp Maiere6df0e42018-05-29 14:03:06 +02001073 /* Note: it is legal to create a connection but never setting a port
1074 * and IP-address for outgoing data. */
1075 if (strcmp(inet_ntoa(conn->end.addr), "0.0.0.0") == 0 && conn->end.rtp_port == 0) {
Pau Espin Pedrol3239f622019-04-24 18:47:46 +02001076 LOGPCONN(conn->conn, DRTP, LOGL_DEBUG,
1077 "destination IP-address and rtp port is (not yet) known (%s:%u)\n",
1078 inet_ntoa(conn->end.addr), conn->end.rtp_port);
Philipp Maiere6df0e42018-05-29 14:03:06 +02001079 return -1;
1080 }
1081
Philipp Maier87bd9be2017-08-22 16:35:41 +02001082 if (strcmp(inet_ntoa(conn->end.addr), "0.0.0.0") == 0) {
Pau Espin Pedrol3239f622019-04-24 18:47:46 +02001083 LOGPCONN(conn->conn, DRTP, LOGL_ERROR,
1084 "destination IP-address is invalid (%s:%u)\n",
1085 inet_ntoa(conn->end.addr), conn->end.rtp_port);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001086 return -1;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001087 }
Philipp Maier87bd9be2017-08-22 16:35:41 +02001088
1089 if (conn->end.rtp_port == 0) {
Pau Espin Pedrol3239f622019-04-24 18:47:46 +02001090 LOGPCONN(conn->conn, DRTP, LOGL_ERROR,
1091 "destination rtp port is invalid (%s:%u)\n",
1092 inet_ntoa(conn->end.addr), conn->end.rtp_port);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001093 return -1;
1094 }
1095
1096 return 0;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001097}
1098
Philipp Maier4dba7692018-08-03 12:20:52 +02001099/* Do some basic checks to make sure that the RTCP packets we are going to
1100 * process are not complete garbage */
1101static int check_rtcp(char *buf, unsigned int buf_size)
1102{
1103 struct rtcp_hdr *hdr;
1104 unsigned int len;
1105 uint8_t type;
1106
1107 /* RTPC packets that are just a header without data do not make
1108 * any sense. */
1109 if (buf_size < sizeof(struct rtcp_hdr))
1110 return -EINVAL;
1111
1112 /* Make sure that the length of the received packet does not exceed
1113 * the available buffer size */
1114 hdr = (struct rtcp_hdr *)buf;
1115 len = (osmo_ntohs(hdr->length) + 1) * 4;
1116 if (len > buf_size)
1117 return -EINVAL;
1118
1119 /* Make sure we accept only packets that have a proper packet type set
1120 * See also: http://www.iana.org/assignments/rtp-parameters/rtp-parameters.xhtml */
1121 type = hdr->type;
1122 if ((type < 192 || type > 195) && (type < 200 || type > 213))
1123 return -EINVAL;
1124
1125 return 0;
1126}
1127
1128/* Do some basic checks to make sure that the RTP packets we are going to
1129 * process are not complete garbage */
1130static int check_rtp(char *buf, unsigned int buf_size)
1131{
1132 /* RTP packets that are just a header without data do not make
1133 * any sense. */
1134 if (buf_size < sizeof(struct rtp_hdr))
1135 return -EINVAL;
1136
1137 /* FIXME: Add more checks, the reason why we do not check more than
1138 * the length is because we currently handle IUUP packets as RTP
1139 * packets, so they must pass this check, if we weould be more
1140 * strict here, we would possibly break 3G. (see also FIXME note
1141 * below */
1142
1143 return 0;
1144}
1145
Philipp Maier87bd9be2017-08-22 16:35:41 +02001146/* Receive RTP data from a specified source connection and dispatch it to a
1147 * destination connection. */
1148static int mgcp_recv(int *proto, struct sockaddr_in *addr, char *buf,
1149 unsigned int buf_size, struct osmo_fd *fd)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001150{
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001151 struct mgcp_endpoint *endp;
Philipp Maier87bd9be2017-08-22 16:35:41 +02001152 struct mgcp_conn_rtp *conn;
1153 struct mgcp_trunk_config *tcfg;
1154 int rc;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001155
Philipp Maier87bd9be2017-08-22 16:35:41 +02001156 conn = (struct mgcp_conn_rtp*) fd->data;
1157 endp = conn->conn->endp;
1158 tcfg = endp->tcfg;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001159
Pau Espin Pedrol3239f622019-04-24 18:47:46 +02001160 LOGPCONN(conn->conn, DRTP, LOGL_DEBUG, "receiving RTP/RTCP packet...\n");
Philipp Maier87bd9be2017-08-22 16:35:41 +02001161
1162 rc = receive_from(endp, fd->fd, addr, buf, buf_size);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001163 if (rc <= 0)
1164 return -1;
Philipp Maier4dba7692018-08-03 12:20:52 +02001165
1166 /* FIXME: The way how we detect the protocol looks odd. We should look
1167 * into the packet header. Also we should introduce a packet type
1168 * MGCP_PROTO_IUUP because currently we handle IUUP packets like RTP
1169 * packets which is problematic. */
Philipp Maier87bd9be2017-08-22 16:35:41 +02001170 *proto = fd == &conn->end.rtp ? MGCP_PROTO_RTP : MGCP_PROTO_RTCP;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001171
Philipp Maier4dba7692018-08-03 12:20:52 +02001172 if (*proto == MGCP_PROTO_RTP) {
1173 if (check_rtp(buf, rc) < 0) {
Pau Espin Pedrol3239f622019-04-24 18:47:46 +02001174 LOGPCONN(conn->conn, DRTP, LOGL_ERROR,
1175 "invalid RTP packet received -- packet tossed\n");
Philipp Maier4dba7692018-08-03 12:20:52 +02001176 return -1;
1177 }
1178 } else if (*proto == MGCP_PROTO_RTCP) {
1179 if (check_rtcp(buf, rc) < 0) {
Pau Espin Pedrol3239f622019-04-24 18:47:46 +02001180 LOGPCONN(conn->conn, DRTP, LOGL_ERROR,
1181 "invalid RTCP packet received -- packet tossed\n");
Philipp Maier4dba7692018-08-03 12:20:52 +02001182 return -1;
1183 }
1184 }
1185
Pau Espin Pedrol3239f622019-04-24 18:47:46 +02001186 LOGPCONN(conn->conn, DRTP, LOGL_DEBUG, "");
Neels Hofmeyr56725632018-01-15 15:15:07 +01001187 LOGPC(DRTP, LOGL_DEBUG, "receiving from %s %s %d\n",
Philipp Maier87bd9be2017-08-22 16:35:41 +02001188 conn->conn->name, inet_ntoa(addr->sin_addr),
1189 ntohs(addr->sin_port));
Pau Espin Pedrol3239f622019-04-24 18:47:46 +02001190 LOGPENDP(endp, DRTP, LOGL_DEBUG, "conn:%s\n", mgcp_conn_dump(conn->conn));
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001191
Philipp Maier87bd9be2017-08-22 16:35:41 +02001192 /* Check if the origin of the RTP packet seems plausible */
1193 if (tcfg->rtp_accept_all == 0) {
1194 if (check_rtp_origin(conn, addr) != 0)
1195 return -1;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001196 }
1197
Philipp Maier87bd9be2017-08-22 16:35:41 +02001198 /* Filter out dummy message */
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001199 if (rc == 1 && buf[0] == MGCP_DUMMY_LOAD) {
Pau Espin Pedrol3239f622019-04-24 18:47:46 +02001200 LOGPCONN(conn->conn, DRTP, LOGL_NOTICE,
1201 "dummy message received\n");
1202 LOGPCONN(conn->conn, DRTP, LOGL_ERROR,
1203 "packet tossed\n");
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001204 return 0;
1205 }
1206
Philipp Maier87bd9be2017-08-22 16:35:41 +02001207 /* Increment RX statistics */
Harald Weltea48ff4a2020-03-08 14:45:08 +01001208 rtpconn_rate_ctr_inc(conn, endp, RTP_PACKETS_RX_CTR);
1209 rtpconn_rate_ctr_add(conn, endp, RTP_OCTETS_RX_CTR, rc);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001210
Philipp Maier87bd9be2017-08-22 16:35:41 +02001211 /* Forward a copy of the RTP data to a debug ip/port */
1212 forward_data(fd->fd, &conn->tap_in, buf, rc);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001213
Philipp Maier87bd9be2017-08-22 16:35:41 +02001214 return rc;
1215}
1216
1217/* Send RTP data. Possible options are standard RTP packet
1218 * transmission or trsmission via an osmux connection */
1219static int mgcp_send_rtp(int proto, struct sockaddr_in *addr, char *buf,
1220 unsigned int buf_size,
1221 struct mgcp_conn_rtp *conn_src,
1222 struct mgcp_conn_rtp *conn_dst)
1223{
1224 struct mgcp_endpoint *endp;
1225 endp = conn_src->conn->endp;
1226
Pau Espin Pedrol3239f622019-04-24 18:47:46 +02001227 LOGPENDP(endp, DRTP, LOGL_DEBUG, "destin conn:%s\n",
1228 mgcp_conn_dump(conn_dst->conn));
Philipp Maier87bd9be2017-08-22 16:35:41 +02001229
1230 /* Before we try to deliver the packet, we check if the destination
1231 * port and IP-Address make sense at all. If not, we will be unable
1232 * to deliver the packet. */
1233 if (check_rtp_destin(conn_dst) != 0)
1234 return -1;
1235
1236 /* Depending on the RTP connection type, deliver the RTP packet to the
1237 * destination connection. */
1238 switch (conn_dst->type) {
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001239 case MGCP_RTP_DEFAULT:
Pau Espin Pedrol3239f622019-04-24 18:47:46 +02001240 LOGPENDP(endp, DRTP, LOGL_DEBUG,
1241 "endpoint type is MGCP_RTP_DEFAULT, "
1242 "using mgcp_send() to forward data directly\n");
Philipp Maier87bd9be2017-08-22 16:35:41 +02001243 return mgcp_send(endp, proto == MGCP_PROTO_RTP,
1244 addr, buf, buf_size, conn_src, conn_dst);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001245 case MGCP_OSMUX_BSC_NAT:
Philipp Maier87bd9be2017-08-22 16:35:41 +02001246 case MGCP_OSMUX_BSC:
Pau Espin Pedrol3239f622019-04-24 18:47:46 +02001247 LOGPENDP(endp, DRTP, LOGL_DEBUG,
1248 "endpoint type is MGCP_OSMUX_BSC_NAT, "
1249 "using osmux_xfrm_to_osmux() to forward data through OSMUX\n");
Philipp Maier87bd9be2017-08-22 16:35:41 +02001250 return osmux_xfrm_to_osmux(buf, buf_size, conn_dst);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001251 }
1252
Philipp Maier87bd9be2017-08-22 16:35:41 +02001253 /* If the data has not been handled/forwarded until here, it will
1254 * be discarded, this should not happen, normally the MGCP type
1255 * should be properly set */
Pau Espin Pedrol3239f622019-04-24 18:47:46 +02001256 LOGPENDP(endp, DRTP, LOGL_ERROR, "bad MGCP type -- data discarded!\n");
Philipp Maier87bd9be2017-08-22 16:35:41 +02001257
1258 return -1;
1259}
1260
1261/*! dispatch incoming RTP packet to opposite RTP connection.
1262 * \param[in] proto protocol (MGCP_CONN_TYPE_RTP or MGCP_CONN_TYPE_RTCP)
1263 * \param[in] addr socket address where the RTP packet has been received from
1264 * \param[in] buf buffer that hold the RTP payload
1265 * \param[in] buf_size size data length of buf
1266 * \param[in] conn originating connection
1267 * \returns 0 on success, -1 on ERROR */
1268int mgcp_dispatch_rtp_bridge_cb(int proto, struct sockaddr_in *addr, char *buf,
1269 unsigned int buf_size, struct mgcp_conn *conn)
1270{
1271 struct mgcp_conn *conn_dst;
Philipp Maier87bd9be2017-08-22 16:35:41 +02001272
1273 /*! NOTE: This callback function implements the endpoint specific
Alexander Chemeris61cf9bb2020-05-11 18:13:53 +03001274 * dispatch behaviour of an rtp bridge/proxy endpoint. It is assumed
Philipp Maier87bd9be2017-08-22 16:35:41 +02001275 * that the endpoint will hold only two connections. This premise
1276 * is used to determine the opposite connection (it is always the
1277 * connection that is not the originating connection). Once the
1278 * destination connection is known the RTP packet is sent via
1279 * the destination connection. */
1280
Pau Espin Pedrol9aaaab62019-05-15 23:23:27 +02001281
1282 /* Check if the connection is in loopback mode, if yes, just send the
1283 * incoming data back to the origin */
1284 if (conn->mode == MGCP_CONN_LOOPBACK) {
1285 /* When we are in loopback mode, we loop back all incoming
1286 * packets back to their origin. We will use the originating
1287 * address data from the UDP packet header to patch the
1288 * outgoing address in connection on the fly */
1289 if (conn->u.rtp.end.rtp_port == 0) {
1290 conn->u.rtp.end.addr = addr->sin_addr;
1291 conn->u.rtp.end.rtp_port = addr->sin_port;
1292 }
1293 return mgcp_send_rtp(proto, addr, buf,
1294 buf_size, &conn->u.rtp, &conn->u.rtp);
1295 }
1296
Philipp Maier87bd9be2017-08-22 16:35:41 +02001297 /* Find a destination connection. */
1298 /* NOTE: This code path runs every time an RTP packet is received. The
1299 * function mgcp_find_dst_conn() we use to determine the detination
1300 * connection will iterate the connection list inside the endpoint.
1301 * Since list iterations are quite costly, we will figure out the
1302 * destination only once and use the optional private data pointer of
1303 * the connection to cache the destination connection pointer. */
1304 if (!conn->priv) {
1305 conn_dst = mgcp_find_dst_conn(conn);
1306 conn->priv = conn_dst;
1307 } else {
1308 conn_dst = (struct mgcp_conn *)conn->priv;
1309 }
1310
1311 /* There is no destination conn, stop here */
1312 if (!conn_dst) {
Pau Espin Pedrol3239f622019-04-24 18:47:46 +02001313 LOGPCONN(conn, DRTP, LOGL_ERROR,
1314 "unable to find destination conn\n");
Philipp Maier87bd9be2017-08-22 16:35:41 +02001315 return -1;
1316 }
1317
1318 /* The destination conn is not an RTP connection */
1319 if (conn_dst->type != MGCP_CONN_TYPE_RTP) {
Pau Espin Pedrol3239f622019-04-24 18:47:46 +02001320 LOGPCONN(conn, DRTP, LOGL_ERROR,
1321 "unable to find suitable destination conn\n");
Philipp Maier87bd9be2017-08-22 16:35:41 +02001322 return -1;
1323 }
1324
1325 /* Dispatch RTP packet to destination RTP connection */
1326 return mgcp_send_rtp(proto, addr, buf,
1327 buf_size, &conn->u.rtp, &conn_dst->u.rtp);
1328
1329}
1330
Philipp Maierdf5d2192018-01-24 11:39:32 +01001331/*! cleanup an endpoint when a connection on an RTP bridge endpoint is removed.
1332 * \param[in] endp Endpoint on which the connection resides.
1333 * \param[in] conn Connection that is about to be removed (ignored).
1334 * \returns 0 on success, -1 on ERROR. */
1335void mgcp_cleanup_rtp_bridge_cb(struct mgcp_endpoint *endp, struct mgcp_conn *conn)
1336{
1337 struct mgcp_conn *conn_cleanup;
1338
1339 /* In mgcp_dispatch_rtp_bridge_cb() we use conn->priv to cache the
1340 * pointer to the destination connection, so that we do not have
1341 * to go through the list every time an RTP packet arrives. To prevent
1342 * a use-after-free situation we invalidate this information for all
1343 * connections present when one connection is removed from the
1344 * endpoint. */
1345 llist_for_each_entry(conn_cleanup, &endp->conns, entry) {
1346 conn_cleanup->priv = NULL;
1347 }
1348}
1349
Philipp Maier87bd9be2017-08-22 16:35:41 +02001350/* Handle incoming RTP data from NET */
1351static int rtp_data_net(struct osmo_fd *fd, unsigned int what)
1352{
1353 /* NOTE: This is a generic implementation. RTP data is received. In
1354 * case of loopback the data is just sent back to its origin. All
1355 * other cases implement endpoint specific behaviour (e.g. how is the
1356 * destination connection determined?). That specific behaviour is
1357 * implemented by the callback function that is called at the end of
1358 * the function */
1359
1360 struct mgcp_conn_rtp *conn_src;
1361 struct mgcp_endpoint *endp;
1362 struct sockaddr_in addr;
1363
1364 char buf[RTP_BUF_SIZE];
1365 int proto;
Philipp Maierb9694552017-11-08 16:53:57 +01001366 int len;
Philipp Maier87bd9be2017-08-22 16:35:41 +02001367
1368 conn_src = (struct mgcp_conn_rtp *)fd->data;
1369 OSMO_ASSERT(conn_src);
1370 endp = conn_src->conn->endp;
1371 OSMO_ASSERT(endp);
1372
Pau Espin Pedrol3239f622019-04-24 18:47:46 +02001373 LOGPENDP(endp, DRTP, LOGL_DEBUG, "source conn:%s\n",
1374 mgcp_conn_dump(conn_src->conn));
Philipp Maier87bd9be2017-08-22 16:35:41 +02001375
1376 /* Receive packet */
Philipp Maierb9694552017-11-08 16:53:57 +01001377 len = mgcp_recv(&proto, &addr, buf, sizeof(buf), fd);
1378 if (len < 0)
Philipp Maier87bd9be2017-08-22 16:35:41 +02001379 return -1;
1380
Oliver Smithe36b7752019-01-22 16:31:36 +01001381 mgcp_conn_watchdog_kick(conn_src->conn);
1382
Philipp Maier228e5912019-03-05 13:56:59 +01001383 /* If AMR is configured for the ingress connection a conversion of the
1384 * framing mode (octet-aligned vs. bandwith-efficient is explicitly
1385 * define, then we check if the incoming payload matches that
1386 * expectation. */
1387 if (amr_oa_bwe_convert_indicated(conn_src->end.codec)) {
Neels Hofmeyr7c6dd3c2019-08-20 03:06:17 +02001388 int oa = amr_oa_check(buf, len);
1389 if (oa < 0)
1390 return -1;
1391 if (((bool)oa) != conn_src->end.codec->param.amr_octet_aligned)
Philipp Maier228e5912019-03-05 13:56:59 +01001392 return -1;
1393 }
1394
Philipp Maier87bd9be2017-08-22 16:35:41 +02001395 /* Execute endpoint specific implementation that handles the
1396 * dispatching of the RTP data */
Philipp Maierb9694552017-11-08 16:53:57 +01001397 return endp->type->dispatch_rtp_cb(proto, &addr, buf, len,
Philipp Maier87bd9be2017-08-22 16:35:41 +02001398 conn_src->conn);
1399}
1400
1401/*! set IP Type of Service parameter.
1402 * \param[in] fd associated file descriptor
1403 * \param[in] tos dscp value
1404 * \returns 0 on success, -1 on ERROR */
1405int mgcp_set_ip_tos(int fd, int tos)
1406{
1407 int ret;
1408 ret = setsockopt(fd, IPPROTO_IP, IP_TOS, &tos, sizeof(tos));
1409
1410 if (ret < 0)
1411 return -1;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001412 return 0;
1413}
1414
Philipp Maier87bd9be2017-08-22 16:35:41 +02001415/*! bind RTP port to osmo_fd.
1416 * \param[in] source_addr source (local) address to bind on
1417 * \param[in] fd associated file descriptor
1418 * \param[in] port to bind on
1419 * \returns 0 on success, -1 on ERROR */
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001420int mgcp_create_bind(const char *source_addr, struct osmo_fd *fd, int port)
1421{
Harald Welte8890dfa2017-11-17 15:09:30 +01001422 int rc;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001423
Harald Welte8890dfa2017-11-17 15:09:30 +01001424 rc = osmo_sock_init2(AF_INET, SOCK_DGRAM, IPPROTO_UDP, source_addr, port,
1425 NULL, 0, OSMO_SOCK_F_BIND);
1426 if (rc < 0) {
Philipp Maierc3413882017-10-27 12:26:54 +02001427 LOGP(DRTP, LOGL_ERROR, "failed to bind UDP port (%s:%i).\n",
Philipp Maier87bd9be2017-08-22 16:35:41 +02001428 source_addr, port);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001429 return -1;
1430 }
Harald Welte8890dfa2017-11-17 15:09:30 +01001431 fd->fd = rc;
1432 LOGP(DRTP, LOGL_DEBUG, "created socket + bound UDP port (%s:%i).\n", source_addr, port);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001433
1434 return 0;
1435}
1436
Philipp Maier87bd9be2017-08-22 16:35:41 +02001437/* Bind RTP and RTCP port (helper function for mgcp_bind_net_rtp_port()) */
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001438static int bind_rtp(struct mgcp_config *cfg, const char *source_addr,
Philipp Maier87bd9be2017-08-22 16:35:41 +02001439 struct mgcp_rtp_end *rtp_end, int endpno)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001440{
Philipp Maier87bd9be2017-08-22 16:35:41 +02001441 /* NOTE: The port that is used for RTCP is the RTP port incremented by one
1442 * (e.g. RTP-Port = 16000 ==> RTCP-Port = 16001) */
Pau Espin Pedrol3239f622019-04-24 18:47:46 +02001443 struct mgcp_endpoint *endp = &cfg->trunk.endpoints[endpno];
Philipp Maier87bd9be2017-08-22 16:35:41 +02001444
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001445 if (mgcp_create_bind(source_addr, &rtp_end->rtp,
1446 rtp_end->local_port) != 0) {
Pau Espin Pedrol3239f622019-04-24 18:47:46 +02001447 LOGPENDP(endp, DRTP, LOGL_ERROR,
1448 "failed to create RTP port: %s:%d\n",
1449 source_addr, rtp_end->local_port);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001450 goto cleanup0;
1451 }
1452
1453 if (mgcp_create_bind(source_addr, &rtp_end->rtcp,
1454 rtp_end->local_port + 1) != 0) {
Pau Espin Pedrol3239f622019-04-24 18:47:46 +02001455 LOGPENDP(endp, DRTP, LOGL_ERROR,
1456 "failed to create RTCP port: %s:%d\n",
1457 source_addr, rtp_end->local_port + 1);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001458 goto cleanup1;
1459 }
1460
Philipp Maier87bd9be2017-08-22 16:35:41 +02001461 /* Set Type of Service (DSCP-Value) as configured via VTY */
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001462 mgcp_set_ip_tos(rtp_end->rtp.fd, cfg->endp_dscp);
1463 mgcp_set_ip_tos(rtp_end->rtcp.fd, cfg->endp_dscp);
1464
Pau Espin Pedrola7152e02020-05-09 19:15:50 +02001465 rtp_end->rtp.when = OSMO_FD_READ;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001466 if (osmo_fd_register(&rtp_end->rtp) != 0) {
Pau Espin Pedrol3239f622019-04-24 18:47:46 +02001467 LOGPENDP(endp, DRTP, LOGL_ERROR,
1468 "failed to register RTP port %d\n",
1469 rtp_end->local_port);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001470 goto cleanup2;
1471 }
1472
Pau Espin Pedrola7152e02020-05-09 19:15:50 +02001473 rtp_end->rtcp.when = OSMO_FD_READ;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001474 if (osmo_fd_register(&rtp_end->rtcp) != 0) {
Pau Espin Pedrol3239f622019-04-24 18:47:46 +02001475 LOGPENDP(endp, DRTP, LOGL_ERROR,
1476 "failed to register RTCP port %d\n",
1477 rtp_end->local_port + 1);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001478 goto cleanup3;
1479 }
1480
1481 return 0;
1482
1483cleanup3:
1484 osmo_fd_unregister(&rtp_end->rtp);
1485cleanup2:
1486 close(rtp_end->rtcp.fd);
1487 rtp_end->rtcp.fd = -1;
1488cleanup1:
1489 close(rtp_end->rtp.fd);
1490 rtp_end->rtp.fd = -1;
1491cleanup0:
1492 return -1;
1493}
1494
Philipp Maier87bd9be2017-08-22 16:35:41 +02001495/*! bind RTP port to endpoint/connection.
1496 * \param[in] endp endpoint that holds the RTP connection
1497 * \param[in] rtp_port port number to bind on
1498 * \param[in] conn associated RTP connection
1499 * \returns 0 on success, -1 on ERROR */
1500int mgcp_bind_net_rtp_port(struct mgcp_endpoint *endp, int rtp_port,
1501 struct mgcp_conn_rtp *conn)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001502{
Philipp Maier87bd9be2017-08-22 16:35:41 +02001503 char name[512];
1504 struct mgcp_rtp_end *end;
Philipp Maier1cb1e382017-11-02 17:16:04 +01001505 char local_ip_addr[INET_ADDRSTRLEN];
Philipp Maier87bd9be2017-08-22 16:35:41 +02001506
Philipp Maier01d24a32017-11-21 17:26:09 +01001507 snprintf(name, sizeof(name), "%s-%s", conn->conn->name, conn->conn->id);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001508 end = &conn->end;
1509
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001510 if (end->rtp.fd != -1 || end->rtcp.fd != -1) {
Pau Espin Pedrol3239f622019-04-24 18:47:46 +02001511 LOGPENDP(endp, DRTP, LOGL_ERROR, "%u was already bound on conn:%s\n",
1512 rtp_port, mgcp_conn_dump(conn->conn));
Philipp Maier87bd9be2017-08-22 16:35:41 +02001513
1514 /* Double bindings should never occour! Since we always allocate
1515 * connections dynamically and free them when they are not
1516 * needed anymore, there must be no previous binding leftover.
1517 * Should there be a connection bound twice, we have a serious
1518 * problem and must exit immediately! */
1519 OSMO_ASSERT(false);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001520 }
1521
1522 end->local_port = rtp_port;
Philipp Maier87bd9be2017-08-22 16:35:41 +02001523 end->rtp.cb = rtp_data_net;
1524 end->rtp.data = conn;
1525 end->rtcp.data = conn;
1526 end->rtcp.cb = rtp_data_net;
1527
Philipp Maier1cb1e382017-11-02 17:16:04 +01001528 mgcp_get_local_addr(local_ip_addr, conn);
1529
1530 return bind_rtp(endp->cfg, local_ip_addr, end,
Philipp Maier87bd9be2017-08-22 16:35:41 +02001531 ENDPOINT_NUMBER(endp));
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001532}
1533
Philipp Maier87bd9be2017-08-22 16:35:41 +02001534/*! free allocated RTP and RTCP ports.
1535 * \param[in] end RTP end */
1536void mgcp_free_rtp_port(struct mgcp_rtp_end *end)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001537{
1538 if (end->rtp.fd != -1) {
1539 close(end->rtp.fd);
1540 end->rtp.fd = -1;
1541 osmo_fd_unregister(&end->rtp);
1542 }
1543
1544 if (end->rtcp.fd != -1) {
1545 close(end->rtcp.fd);
1546 end->rtcp.fd = -1;
1547 osmo_fd_unregister(&end->rtcp);
1548 }
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001549}