blob: 6ecb945b981d2e6e8da2132a49e9f9ffc3e4f709 [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 Maier993ea6b2020-08-04 18:26:50 +020040#include <osmocom/mgcp/mgcp_network.h>
41#include <osmocom/mgcp/mgcp_protocol.h>
Philipp Maier87bd9be2017-08-22 16:35:41 +020042#include <osmocom/mgcp/mgcp_stat.h>
43#include <osmocom/mgcp/osmux.h>
44#include <osmocom/mgcp/mgcp_conn.h>
Philipp Maier37d11c82018-02-01 14:38:12 +010045#include <osmocom/mgcp/mgcp_endp.h>
Philipp Maierc66ab2c2020-06-02 20:55:34 +020046#include <osmocom/mgcp/mgcp_trunk.h>
Philipp Maier6931f9a2018-07-26 09:29:31 +020047#include <osmocom/mgcp/mgcp_codec.h>
Philipp Maierc3413882017-10-27 12:26:54 +020048#include <osmocom/mgcp/debug.h>
Philipp Maier9fc8a022019-02-20 12:26:52 +010049#include <osmocom/codec/codec.h>
Philipp Maier889fe7f2020-07-06 17:44:12 +020050#include <osmocom/mgcp/mgcp_e1.h>
Philipp Maier6931f9a2018-07-26 09:29:31 +020051
Philipp Maier993ea6b2020-08-04 18:26:50 +020052
Neels Hofmeyrf83ec562017-09-07 19:18:40 +020053#define RTP_SEQ_MOD (1 << 16)
54#define RTP_MAX_DROPOUT 3000
55#define RTP_MAX_MISORDER 100
Neels Hofmeyrf83ec562017-09-07 19:18:40 +020056
Neels Hofmeyr51b42ff2020-06-19 01:34:42 +020057enum rtp_proto {
Neels Hofmeyrf83ec562017-09-07 19:18:40 +020058 MGCP_PROTO_RTP,
59 MGCP_PROTO_RTCP,
60};
61
Harald Weltea48ff4a2020-03-08 14:45:08 +010062static void rtpconn_rate_ctr_add(struct mgcp_conn_rtp *conn_rtp, struct mgcp_endpoint *endp,
63 int id, int inc)
64{
65 struct rate_ctr_group *conn_stats = conn_rtp->rate_ctr_group;
Philipp Maierc66ab2c2020-06-02 20:55:34 +020066 struct rate_ctr_group *mgw_stats = endp->trunk->ratectr.all_rtp_conn_stats;
Harald Weltea48ff4a2020-03-08 14:45:08 +010067
Philipp Maierc66ab2c2020-06-02 20:55:34 +020068 /* add to both the per-connection and the global stats */
Harald Weltea48ff4a2020-03-08 14:45:08 +010069 rate_ctr_add(&conn_stats->ctr[id], inc);
Philipp Maierc66ab2c2020-06-02 20:55:34 +020070 rate_ctr_add(&mgw_stats->ctr[id], inc);
Harald Weltea48ff4a2020-03-08 14:45:08 +010071}
72
73static void rtpconn_rate_ctr_inc(struct mgcp_conn_rtp *conn_rtp, struct mgcp_endpoint *endp, int id)
74{
75 rtpconn_rate_ctr_add(conn_rtp, endp, id, 1);
76}
77
Neels Hofmeyr51b42ff2020-06-19 01:34:42 +020078static int rx_rtp(struct msgb *msg);
79
Pau Espin Pedrola790f0c2020-08-31 13:29:11 +020080static bool addr_is_any(struct osmo_sockaddr *osa) {
81 if (osa->u.sa.sa_family == AF_INET6) {
82 struct in6_addr ip6_any = IN6ADDR_ANY_INIT;
83 return memcmp(&osa->u.sin6.sin6_addr,
84 &ip6_any, sizeof(ip6_any)) == 0;
85 } else {
86 return osa->u.sin.sin_addr.s_addr == 0;
87 }
88}
89
Philipp Maier1cb1e382017-11-02 17:16:04 +010090/*! Determine the local rtp bind IP-address.
Philipp Maier0b79d212020-06-18 12:02:49 +020091 * \param[out] addr caller provided memory to store the resulting IP-Address.
92 * \param[in] endp mgcp endpoint, that holds a copy of the VTY parameters.
Philipp Maier1cb1e382017-11-02 17:16:04 +010093 *
94 * The local bind IP-address is automatically selected by probing the
95 * IP-Address of the interface that is pointing towards the remote IP-Address,
96 * if no remote IP-Address is known yet, the statically configured
97 * IP-Addresses are used as fallback. */
98void mgcp_get_local_addr(char *addr, struct mgcp_conn_rtp *conn)
99{
100
101 struct mgcp_endpoint *endp;
Pau Espin Pedrola790f0c2020-08-31 13:29:11 +0200102 char ipbuf[INET6_ADDRSTRLEN];
Philipp Maier1cb1e382017-11-02 17:16:04 +0100103 int rc;
104 endp = conn->conn->endp;
105
106 /* Try probing the local IP-Address */
Pau Espin Pedrola790f0c2020-08-31 13:29:11 +0200107 if (endp->cfg->net_ports.bind_addr_probe && !addr_is_any(&conn->end.addr)) {
108 rc = osmo_sock_local_ip(addr, osmo_sockaddr_ntop(&conn->end.addr.u.sa, ipbuf));
Philipp Maier1cb1e382017-11-02 17:16:04 +0100109 if (rc < 0)
Pau Espin Pedrol3239f622019-04-24 18:47:46 +0200110 LOGPCONN(conn->conn, DRTP, LOGL_ERROR,
111 "local interface auto detection failed, using configured addresses...\n");
Philipp Maier1cb1e382017-11-02 17:16:04 +0100112 else {
Pau Espin Pedrol3239f622019-04-24 18:47:46 +0200113 LOGPCONN(conn->conn, DRTP, LOGL_DEBUG,
114 "selected local rtp bind ip %s by probing using remote ip %s\n",
Pau Espin Pedrola790f0c2020-08-31 13:29:11 +0200115 addr, osmo_sockaddr_ntop(&conn->end.addr.u.sa, ipbuf));
Philipp Maier1cb1e382017-11-02 17:16:04 +0100116 return;
117 }
118 }
119
Pau Espin Pedrola93c6e92019-05-06 15:23:57 +0200120 /* Select from preconfigured IP-Addresses. We don't have bind_addr for Osmux (yet?). */
Philipp Maier1cb1e382017-11-02 17:16:04 +0100121 if (endp->cfg->net_ports.bind_addr) {
122 /* Check there is a bind IP for the RTP traffic configured,
123 * if so, use that IP-Address */
Pau Espin Pedrola790f0c2020-08-31 13:29:11 +0200124 osmo_strlcpy(addr, endp->cfg->net_ports.bind_addr, INET6_ADDRSTRLEN);
Pau Espin Pedrol3239f622019-04-24 18:47:46 +0200125 LOGPCONN(conn->conn, DRTP, LOGL_DEBUG,
126 "using configured rtp bind ip as local bind ip %s\n",
127 addr);
Philipp Maier1cb1e382017-11-02 17:16:04 +0100128 } else {
129 /* No specific bind IP is configured for the RTP traffic, so
130 * assume the IP where we listen for incoming MGCP messages
131 * as bind IP */
Pau Espin Pedrola790f0c2020-08-31 13:29:11 +0200132 osmo_strlcpy(addr, endp->cfg->source_addr, INET6_ADDRSTRLEN);
Pau Espin Pedrol3239f622019-04-24 18:47:46 +0200133 LOGPCONN(conn->conn, DRTP, LOGL_DEBUG,
134 "using mgcp bind ip as local rtp bind ip: %s\n", addr);
Philipp Maier1cb1e382017-11-02 17:16:04 +0100135 }
136}
137
Philipp Maier87bd9be2017-08-22 16:35:41 +0200138/* This does not need to be a precision timestamp and
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200139 * is allowed to wrap quite fast. The returned value is
Philipp Maier87bd9be2017-08-22 16:35:41 +0200140 * 1/codec_rate seconds. */
141static uint32_t get_current_ts(unsigned codec_rate)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200142{
143 struct timespec tp;
144 uint64_t ret;
145
Philipp Maier87bd9be2017-08-22 16:35:41 +0200146 if (!codec_rate)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200147 return 0;
148
149 memset(&tp, 0, sizeof(tp));
150 if (clock_gettime(CLOCK_MONOTONIC, &tp) != 0)
Philipp Maierc3413882017-10-27 12:26:54 +0200151 LOGP(DRTP, LOGL_NOTICE, "Getting the clock failed.\n");
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200152
153 /* convert it to 1/unit seconds */
154 ret = tp.tv_sec;
Philipp Maier87bd9be2017-08-22 16:35:41 +0200155 ret *= codec_rate;
156 ret += (int64_t) tp.tv_nsec * codec_rate / 1000 / 1000 / 1000;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200157
158 return ret;
159}
160
Philipp Maier87bd9be2017-08-22 16:35:41 +0200161/*! send udp packet.
Philipp Maier0b79d212020-06-18 12:02:49 +0200162 * \param[in] fd associated file descriptor.
163 * \param[in] addr destination ip-address.
164 * \param[in] port destination UDP port (network byte order).
165 * \param[in] buf buffer that holds the data to be send.
166 * \param[in] len length of the data to be sent.
167 * \returns bytes sent, -1 on error. */
Pau Espin Pedrola790f0c2020-08-31 13:29:11 +0200168int mgcp_udp_send(int fd, struct osmo_sockaddr *addr, int port, char *buf, int len)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200169{
Pau Espin Pedrola790f0c2020-08-31 13:29:11 +0200170 char ipbuf[INET6_ADDRSTRLEN];
171 size_t addr_len;
172 bool is_ipv6 = addr->u.sa.sa_family == AF_INET6;
Philipp Maier87bd9be2017-08-22 16:35:41 +0200173
Philipp Maierc3413882017-10-27 12:26:54 +0200174 LOGP(DRTP, LOGL_DEBUG,
Pau Espin Pedrola790f0c2020-08-31 13:29:11 +0200175 "sending %i bytes length packet to %s:%u ...\n", len,
176 osmo_sockaddr_ntop(&addr->u.sa, ipbuf),
177 ntohs(port));
Philipp Maier87bd9be2017-08-22 16:35:41 +0200178
Pau Espin Pedrola790f0c2020-08-31 13:29:11 +0200179 if (is_ipv6) {
180 addr->u.sin6.sin6_port = port;
181 addr_len = sizeof(addr->u.sin6);
182 } else {
183 addr->u.sin.sin_port = port;
184 addr_len = sizeof(addr->u.sin);
185 }
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200186
Pau Espin Pedrola790f0c2020-08-31 13:29:11 +0200187 return sendto(fd, buf, len, 0, &addr->u.sa, addr_len);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200188}
189
Philipp Maier87bd9be2017-08-22 16:35:41 +0200190/*! send RTP dummy packet (to keep NAT connection open).
Philipp Maier0b79d212020-06-18 12:02:49 +0200191 * \param[in] endp mcgp endpoint that holds the RTP connection.
192 * \param[in] conn associated RTP connection.
193 * \returns bytes sent, -1 on error. */
Philipp Maier87bd9be2017-08-22 16:35:41 +0200194int mgcp_send_dummy(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200195{
196 static char buf[] = { MGCP_DUMMY_LOAD };
197 int rc;
198 int was_rtcp = 0;
199
Philipp Maier87bd9be2017-08-22 16:35:41 +0200200 OSMO_ASSERT(endp);
201 OSMO_ASSERT(conn);
202
Pau Espin Pedrol3239f622019-04-24 18:47:46 +0200203 LOGPCONN(conn->conn, DRTP, LOGL_DEBUG,"sending dummy packet... %s\n",
204 mgcp_conn_dump(conn->conn));
Philipp Maier87bd9be2017-08-22 16:35:41 +0200205
206 rc = mgcp_udp_send(conn->end.rtp.fd, &conn->end.addr,
207 conn->end.rtp_port, buf, 1);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200208
209 if (rc == -1)
210 goto failed;
211
Philipp Maier14b27a82020-06-02 20:15:30 +0200212 if (endp->trunk->omit_rtcp)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200213 return rc;
214
215 was_rtcp = 1;
Philipp Maier87bd9be2017-08-22 16:35:41 +0200216 rc = mgcp_udp_send(conn->end.rtcp.fd, &conn->end.addr,
217 conn->end.rtcp_port, buf, 1);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200218
219 if (rc >= 0)
220 return rc;
221
222failed:
Pau Espin Pedrol3239f622019-04-24 18:47:46 +0200223 LOGPCONN(conn->conn, DRTP, LOGL_ERROR,
224 "Failed to send dummy %s packet.\n",
225 was_rtcp ? "RTCP" : "RTP");
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200226
227 return -1;
228}
229
Philipp Maier87bd9be2017-08-22 16:35:41 +0200230/* Compute timestamp alignment error */
231static int32_t ts_alignment_error(struct mgcp_rtp_stream_state *sstate,
232 int ptime, uint32_t timestamp)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200233{
234 int32_t timestamp_delta;
235
236 if (ptime == 0)
237 return 0;
238
239 /* Align according to: T - Tlast = k * Tptime */
240 timestamp_delta = timestamp - sstate->last_timestamp;
241
242 return timestamp_delta % ptime;
243}
244
Philipp Maier87bd9be2017-08-22 16:35:41 +0200245/* Check timestamp and sequence number for plausibility */
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200246static int check_rtp_timestamp(struct mgcp_endpoint *endp,
247 struct mgcp_rtp_state *state,
248 struct mgcp_rtp_stream_state *sstate,
249 struct mgcp_rtp_end *rtp_end,
Pau Espin Pedrola790f0c2020-08-31 13:29:11 +0200250 struct osmo_sockaddr *addr,
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200251 uint16_t seq, uint32_t timestamp,
Philipp Maier87bd9be2017-08-22 16:35:41 +0200252 const char *text, int32_t * tsdelta_out)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200253{
254 int32_t tsdelta;
255 int32_t timestamp_error;
Pau Espin Pedrola790f0c2020-08-31 13:29:11 +0200256 char ipbuf[INET6_ADDRSTRLEN];
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200257
258 /* Not fully intialized, skip */
259 if (sstate->last_tsdelta == 0 && timestamp == sstate->last_timestamp)
260 return 0;
261
262 if (seq == sstate->last_seq) {
263 if (timestamp != sstate->last_timestamp) {
Philipp Maier9e1d1642018-05-09 16:26:34 +0200264 rate_ctr_inc(sstate->err_ts_ctr);
Pau Espin Pedrol3239f622019-04-24 18:47:46 +0200265 LOGPENDP(endp, DRTP, LOGL_ERROR,
266 "The %s timestamp delta is != 0 but the sequence "
267 "number %d is the same, "
268 "TS offset: %d, SeqNo offset: %d "
269 "on SSRC: %u timestamp: %u "
270 "from %s:%d\n",
271 text, seq,
272 state->patch.timestamp_offset, state->patch.seq_offset,
Pau Espin Pedrola790f0c2020-08-31 13:29:11 +0200273 sstate->ssrc, timestamp,
274 osmo_sockaddr_ntop(&addr->u.sa, ipbuf),
275 osmo_sockaddr_port(&addr->u.sa));
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200276 }
277 return 0;
278 }
279
280 tsdelta =
Philipp Maier87bd9be2017-08-22 16:35:41 +0200281 (int32_t)(timestamp - sstate->last_timestamp) /
282 (int16_t)(seq - sstate->last_seq);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200283
284 if (tsdelta == 0) {
285 /* Don't update *tsdelta_out */
Pau Espin Pedrol3239f622019-04-24 18:47:46 +0200286 LOGPENDP(endp, DRTP, LOGL_NOTICE,
287 "The %s timestamp delta is %d "
288 "on SSRC: %u timestamp: %u "
289 "from %s:%d\n",
Pau Espin Pedrola790f0c2020-08-31 13:29:11 +0200290 text, tsdelta, sstate->ssrc, timestamp,
291 osmo_sockaddr_ntop(&addr->u.sa, ipbuf),
292 osmo_sockaddr_port(&addr->u.sa));
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200293
294 return 0;
295 }
296
297 if (sstate->last_tsdelta != tsdelta) {
298 if (sstate->last_tsdelta) {
Pau Espin Pedrol3239f622019-04-24 18:47:46 +0200299 LOGPENDP(endp, DRTP, LOGL_INFO,
300 "The %s timestamp delta changes from %d to %d "
301 "on SSRC: %u timestamp: %u from %s:%d\n",
302 text, sstate->last_tsdelta, tsdelta,
303 sstate->ssrc, timestamp,
Pau Espin Pedrola790f0c2020-08-31 13:29:11 +0200304 osmo_sockaddr_ntop(&addr->u.sa, ipbuf),
305 osmo_sockaddr_port(&addr->u.sa));
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200306 }
307 }
308
309 if (tsdelta_out)
310 *tsdelta_out = tsdelta;
311
312 timestamp_error =
Philipp Maier87bd9be2017-08-22 16:35:41 +0200313 ts_alignment_error(sstate, state->packet_duration, timestamp);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200314
315 if (timestamp_error) {
Philipp Maier9e1d1642018-05-09 16:26:34 +0200316 rate_ctr_inc(sstate->err_ts_ctr);
Pau Espin Pedrol3239f622019-04-24 18:47:46 +0200317 LOGPENDP(endp, DRTP, LOGL_NOTICE,
318 "The %s timestamp has an alignment error of %d "
319 "on SSRC: %u "
320 "SeqNo delta: %d, TS delta: %d, dTS/dSeq: %d "
321 "from %s:%d. ptime: %d\n",
322 text, timestamp_error,
323 sstate->ssrc,
324 (int16_t)(seq - sstate->last_seq),
325 (int32_t)(timestamp - sstate->last_timestamp),
326 tsdelta,
Pau Espin Pedrola790f0c2020-08-31 13:29:11 +0200327 osmo_sockaddr_ntop(&addr->u.sa, ipbuf),
328 osmo_sockaddr_port(&addr->u.sa),
Pau Espin Pedrol3239f622019-04-24 18:47:46 +0200329 state->packet_duration);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200330 }
331 return 1;
332}
333
334/* Set the timestamp offset according to the packet duration. */
335static int adjust_rtp_timestamp_offset(struct mgcp_endpoint *endp,
336 struct mgcp_rtp_state *state,
337 struct mgcp_rtp_end *rtp_end,
Pau Espin Pedrola790f0c2020-08-31 13:29:11 +0200338 struct osmo_sockaddr *addr,
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200339 int16_t delta_seq, uint32_t in_timestamp)
340{
341 int32_t tsdelta = state->packet_duration;
342 int timestamp_offset;
343 uint32_t out_timestamp;
Pau Espin Pedrola790f0c2020-08-31 13:29:11 +0200344 char ipbuf[INET6_ADDRSTRLEN];
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200345
346 if (tsdelta == 0) {
347 tsdelta = state->out_stream.last_tsdelta;
348 if (tsdelta != 0) {
Pau Espin Pedrol3239f622019-04-24 18:47:46 +0200349 LOGPENDP(endp, DRTP, LOGL_NOTICE,
350 "A fixed packet duration is not available, "
351 "using last output timestamp delta instead: %d "
352 "from %s:%d\n", tsdelta,
Pau Espin Pedrola790f0c2020-08-31 13:29:11 +0200353 osmo_sockaddr_ntop(&addr->u.sa, ipbuf),
354 osmo_sockaddr_port(&addr->u.sa));
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200355 } else {
Philipp Maierbc0346e2018-06-07 09:52:16 +0200356 tsdelta = rtp_end->codec->rate * 20 / 1000;
Pau Espin Pedrol3239f622019-04-24 18:47:46 +0200357 LOGPENDP(endp, DRTP, LOGL_NOTICE,
358 "Fixed packet duration and last timestamp delta "
359 "are not available, "
360 "using fixed 20ms instead: %d "
361 "from %s:%d\n", tsdelta,
Pau Espin Pedrola790f0c2020-08-31 13:29:11 +0200362 osmo_sockaddr_ntop(&addr->u.sa, ipbuf),
363 osmo_sockaddr_port(&addr->u.sa));
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200364 }
365 }
366
367 out_timestamp = state->out_stream.last_timestamp + delta_seq * tsdelta;
368 timestamp_offset = out_timestamp - in_timestamp;
369
Harald Welte33381352017-12-25 09:44:26 +0100370 if (state->patch.timestamp_offset != timestamp_offset) {
371 state->patch.timestamp_offset = timestamp_offset;
Pau Espin Pedrol3239f622019-04-24 18:47:46 +0200372 LOGPENDP(endp, DRTP, LOGL_NOTICE,
373 "Timestamp offset change on SSRC: %u "
374 "SeqNo delta: %d, TS offset: %d, "
375 "from %s:%d\n", state->in_stream.ssrc,
376 delta_seq, state->patch.timestamp_offset,
Pau Espin Pedrola790f0c2020-08-31 13:29:11 +0200377 osmo_sockaddr_ntop(&addr->u.sa, ipbuf),
378 osmo_sockaddr_port(&addr->u.sa));
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200379 }
380
381 return timestamp_offset;
382}
383
384/* Set the timestamp offset according to the packet duration. */
385static int align_rtp_timestamp_offset(struct mgcp_endpoint *endp,
386 struct mgcp_rtp_state *state,
387 struct mgcp_rtp_end *rtp_end,
Pau Espin Pedrola790f0c2020-08-31 13:29:11 +0200388 struct osmo_sockaddr *addr,
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200389 uint32_t timestamp)
390{
Pau Espin Pedrola790f0c2020-08-31 13:29:11 +0200391 char ipbuf[INET6_ADDRSTRLEN];
Philipp Maier87bd9be2017-08-22 16:35:41 +0200392 int ts_error = 0;
393 int ts_check = 0;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200394 int ptime = state->packet_duration;
395
396 /* Align according to: T + Toffs - Tlast = k * Tptime */
397
Philipp Maier87bd9be2017-08-22 16:35:41 +0200398 ts_error = ts_alignment_error(&state->out_stream, ptime,
Harald Welte33381352017-12-25 09:44:26 +0100399 timestamp + state->patch.timestamp_offset);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200400
Philipp Maier87bd9be2017-08-22 16:35:41 +0200401 /* If there is an alignment error, we have to compensate it */
402 if (ts_error) {
Harald Welte33381352017-12-25 09:44:26 +0100403 state->patch.timestamp_offset += ptime - ts_error;
Pau Espin Pedrol3239f622019-04-24 18:47:46 +0200404 LOGPENDP(endp, DRTP, LOGL_NOTICE,
405 "Corrected timestamp alignment error of %d on SSRC: %u "
406 "new TS offset: %d, "
407 "from %s:%d\n",
408 ts_error, state->in_stream.ssrc,
Pau Espin Pedrola790f0c2020-08-31 13:29:11 +0200409 state->patch.timestamp_offset,
410 osmo_sockaddr_ntop(&addr->u.sa, ipbuf),
411 osmo_sockaddr_port(&addr->u.sa));
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200412 }
413
Philipp Maier87bd9be2017-08-22 16:35:41 +0200414 /* Check we really managed to compensate the timestamp
415 * offset. There should not be any remaining error, failing
Harald Welte1d1b98f2017-12-25 10:03:40 +0100416 * here would point to a serous problem with the alignment
417 * error computation function */
Philipp Maier87bd9be2017-08-22 16:35:41 +0200418 ts_check = ts_alignment_error(&state->out_stream, ptime,
Harald Welte33381352017-12-25 09:44:26 +0100419 timestamp + state->patch.timestamp_offset);
Philipp Maier87bd9be2017-08-22 16:35:41 +0200420 OSMO_ASSERT(ts_check == 0);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200421
Philipp Maier87bd9be2017-08-22 16:35:41 +0200422 /* Return alignment error before compensation */
423 return ts_error;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200424}
425
Philipp Maier87bd9be2017-08-22 16:35:41 +0200426/*! dummy callback to disable transcoding (see also cfg->rtp_processing_cb).
Philipp Maier0b79d212020-06-18 12:02:49 +0200427 * \param[in] associated endpoint.
428 * \param[in] destination RTP end.
429 * \param[in,out] pointer to buffer with voice data.
430 * \param[in] voice data length.
431 * \param[in] maximum size of caller provided voice data buffer.
432 * \returns ignores input parameters, return always 0. */
Philipp Maier87bd9be2017-08-22 16:35:41 +0200433int mgcp_rtp_processing_default(struct mgcp_endpoint *endp,
434 struct mgcp_rtp_end *dst_end,
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200435 char *data, int *len, int buf_size)
436{
Pau Espin Pedrol3239f622019-04-24 18:47:46 +0200437 LOGPENDP(endp, DRTP, LOGL_DEBUG, "transcoding disabled\n");
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200438 return 0;
439}
440
Philipp Maier87bd9be2017-08-22 16:35:41 +0200441/*! dummy callback to disable transcoding (see also cfg->setup_rtp_processing_cb).
Philipp Maier0b79d212020-06-18 12:02:49 +0200442 * \param[in] associated endpoint.
443 * \param[in] destination RTP connnection.
444 * \param[in] source RTP connection.
445 * \returns ignores input parameters, return always 0. */
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200446int mgcp_setup_rtp_processing_default(struct mgcp_endpoint *endp,
Philipp Maieracc10352018-07-19 18:07:57 +0200447 struct mgcp_conn_rtp *conn_dst,
448 struct mgcp_conn_rtp *conn_src)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200449{
Pau Espin Pedrol3239f622019-04-24 18:47:46 +0200450 LOGPENDP(endp, DRTP, LOGL_DEBUG, "transcoding disabled\n");
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200451 return 0;
452}
453
454void mgcp_get_net_downlink_format_default(struct mgcp_endpoint *endp,
Philipp Maier58128252019-03-06 11:28:18 +0100455 const struct mgcp_rtp_codec **codec,
Philipp Maier87bd9be2017-08-22 16:35:41 +0200456 const char **fmtp_extra,
457 struct mgcp_conn_rtp *conn)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200458{
Pau Espin Pedrol3239f622019-04-24 18:47:46 +0200459 LOGPENDP(endp, DRTP, LOGL_DEBUG, "conn:%s using format defaults\n",
460 mgcp_conn_dump(conn->conn));
Philipp Maier87bd9be2017-08-22 16:35:41 +0200461
Philipp Maier58128252019-03-06 11:28:18 +0100462 *codec = conn->end.codec;
Philipp Maier87bd9be2017-08-22 16:35:41 +0200463 *fmtp_extra = conn->end.fmtp_extra;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200464}
465
Philipp Maier87bd9be2017-08-22 16:35:41 +0200466void mgcp_rtp_annex_count(struct mgcp_endpoint *endp,
467 struct mgcp_rtp_state *state, const uint16_t seq,
468 const int32_t transit, const uint32_t ssrc)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200469{
470 int32_t d;
471
472 /* initialize or re-initialize */
Harald Welte49e3d5a2017-12-25 09:47:57 +0100473 if (!state->stats.initialized || state->stats.ssrc != ssrc) {
474 state->stats.initialized = 1;
475 state->stats.base_seq = seq;
476 state->stats.max_seq = seq - 1;
477 state->stats.ssrc = ssrc;
478 state->stats.jitter = 0;
479 state->stats.transit = transit;
480 state->stats.cycles = 0;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200481 } else {
482 uint16_t udelta;
483
Philipp Maier87bd9be2017-08-22 16:35:41 +0200484 /* The below takes the shape of the validation of
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200485 * Appendix A. Check if there is something weird with
486 * the sequence number, otherwise check for a wrap
487 * around in the sequence number.
488 * It can't wrap during the initialization so let's
489 * skip it here. The Appendix A probably doesn't have
Philipp Maier87bd9be2017-08-22 16:35:41 +0200490 * this issue because of the probation. */
Harald Welte49e3d5a2017-12-25 09:47:57 +0100491 udelta = seq - state->stats.max_seq;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200492 if (udelta < RTP_MAX_DROPOUT) {
Harald Welte49e3d5a2017-12-25 09:47:57 +0100493 if (seq < state->stats.max_seq)
494 state->stats.cycles += RTP_SEQ_MOD;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200495 } else if (udelta <= RTP_SEQ_MOD - RTP_MAX_MISORDER) {
Pau Espin Pedrol3239f622019-04-24 18:47:46 +0200496 LOGPENDP(endp, DRTP, LOGL_NOTICE,
497 "RTP seqno made a very large jump on delta: %u\n",
498 udelta);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200499 }
500 }
501
Philipp Maier87bd9be2017-08-22 16:35:41 +0200502 /* Calculate the jitter between the two packages. The TS should be
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200503 * taken closer to the read function. This was taken from the
504 * Appendix A of RFC 3550. Timestamp and arrival_time have a 1/rate
Philipp Maier87bd9be2017-08-22 16:35:41 +0200505 * resolution. */
Harald Welte49e3d5a2017-12-25 09:47:57 +0100506 d = transit - state->stats.transit;
507 state->stats.transit = transit;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200508 if (d < 0)
509 d = -d;
Harald Welte49e3d5a2017-12-25 09:47:57 +0100510 state->stats.jitter += d - ((state->stats.jitter + 8) >> 4);
511 state->stats.max_seq = seq;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200512}
513
Philipp Maier6931f9a2018-07-26 09:29:31 +0200514/* There may be different payload type numbers negotiated for two connections.
515 * Patch the payload type of an RTP packet so that it uses the payload type
516 * that is valid for the destination connection (conn_dst) */
517static int mgcp_patch_pt(struct mgcp_conn_rtp *conn_src,
Neels Hofmeyr51b42ff2020-06-19 01:34:42 +0200518 struct mgcp_conn_rtp *conn_dst, struct msgb *msg)
Philipp Maier6931f9a2018-07-26 09:29:31 +0200519{
520 struct rtp_hdr *rtp_hdr;
521 uint8_t pt_in;
522 int pt_out;
523
Neels Hofmeyr51b42ff2020-06-19 01:34:42 +0200524 if (msgb_length(msg) < sizeof(struct rtp_hdr)) {
525 LOG_CONN_RTP(conn_src, LOGL_ERROR, "RTP packet too short (%u < %zu)\n",
526 msgb_length(msg), sizeof(struct rtp_hdr));
Neels Hofmeyr7c6dd3c2019-08-20 03:06:17 +0200527 return -EINVAL;
Neels Hofmeyr51b42ff2020-06-19 01:34:42 +0200528 }
Neels Hofmeyr7c6dd3c2019-08-20 03:06:17 +0200529
Neels Hofmeyr51b42ff2020-06-19 01:34:42 +0200530 rtp_hdr = (struct rtp_hdr *)msgb_data(msg);
Philipp Maier6931f9a2018-07-26 09:29:31 +0200531
532 pt_in = rtp_hdr->payload_type;
533 pt_out = mgcp_codec_pt_translate(conn_src, conn_dst, pt_in);
534 if (pt_out < 0)
535 return -EINVAL;
536
537 rtp_hdr->payload_type = (uint8_t) pt_out;
538 return 0;
539}
540
Philipp Maier87bd9be2017-08-22 16:35:41 +0200541/* The RFC 3550 Appendix A assumes there are multiple sources but
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200542 * some of the supported endpoints (e.g. the nanoBTS) can only handle
543 * one source and this code will patch RTP header to appear as if there
544 * is only one source.
545 * There is also no probation period for new sources. Every RTP header
Philipp Maier87bd9be2017-08-22 16:35:41 +0200546 * we receive will be seen as a switch in streams. */
547void mgcp_patch_and_count(struct mgcp_endpoint *endp,
548 struct mgcp_rtp_state *state,
549 struct mgcp_rtp_end *rtp_end,
Pau Espin Pedrola790f0c2020-08-31 13:29:11 +0200550 struct osmo_sockaddr *addr, struct msgb *msg)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200551{
Pau Espin Pedrola790f0c2020-08-31 13:29:11 +0200552 char ipbuf[INET6_ADDRSTRLEN];
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200553 uint32_t arrival_time;
554 int32_t transit;
555 uint16_t seq;
556 uint32_t timestamp, ssrc;
557 struct rtp_hdr *rtp_hdr;
Philipp Maierbc0346e2018-06-07 09:52:16 +0200558 int payload = rtp_end->codec->payload_type;
Neels Hofmeyr51b42ff2020-06-19 01:34:42 +0200559 unsigned int len = msgb_length(msg);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200560
561 if (len < sizeof(*rtp_hdr))
562 return;
563
Neels Hofmeyr51b42ff2020-06-19 01:34:42 +0200564 rtp_hdr = (struct rtp_hdr *)msgb_data(msg);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200565 seq = ntohs(rtp_hdr->sequence);
566 timestamp = ntohl(rtp_hdr->timestamp);
Philipp Maierbc0346e2018-06-07 09:52:16 +0200567 arrival_time = get_current_ts(rtp_end->codec->rate);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200568 ssrc = ntohl(rtp_hdr->ssrc);
569 transit = arrival_time - timestamp;
570
571 mgcp_rtp_annex_count(endp, state, seq, transit, ssrc);
572
573 if (!state->initialized) {
574 state->initialized = 1;
575 state->in_stream.last_seq = seq - 1;
Harald Welte33381352017-12-25 09:44:26 +0100576 state->in_stream.ssrc = state->patch.orig_ssrc = ssrc;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200577 state->in_stream.last_tsdelta = 0;
Philipp Maier87bd9be2017-08-22 16:35:41 +0200578 state->packet_duration =
579 mgcp_rtp_packet_duration(endp, rtp_end);
Philipp Maier0ec1d4e2018-05-16 11:09:42 +0200580 state->out_stream.last_seq = seq - 1;
581 state->out_stream.ssrc = state->patch.orig_ssrc = ssrc;
582 state->out_stream.last_tsdelta = 0;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200583 state->out_stream.last_timestamp = timestamp;
Philipp Maier87bd9be2017-08-22 16:35:41 +0200584 state->out_stream.ssrc = ssrc - 1; /* force output SSRC change */
Pau Espin Pedrol3239f622019-04-24 18:47:46 +0200585 LOGPENDP(endp, DRTP, LOGL_INFO,
586 "initializing stream, SSRC: %u timestamp: %u "
587 "pkt-duration: %d, from %s:%d\n",
588 state->in_stream.ssrc,
589 state->patch.seq_offset, state->packet_duration,
Pau Espin Pedrola790f0c2020-08-31 13:29:11 +0200590 osmo_sockaddr_ntop(&addr->u.sa, ipbuf),
591 osmo_sockaddr_port(&addr->u.sa));
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200592 if (state->packet_duration == 0) {
Philipp Maier87bd9be2017-08-22 16:35:41 +0200593 state->packet_duration =
Philipp Maierbc0346e2018-06-07 09:52:16 +0200594 rtp_end->codec->rate * 20 / 1000;
Pau Espin Pedrol3239f622019-04-24 18:47:46 +0200595 LOGPENDP(endp, DRTP, LOGL_NOTICE,
596 "fixed packet duration is not available, "
597 "using fixed 20ms instead: %d from %s:%d\n",
598 state->packet_duration,
Pau Espin Pedrola790f0c2020-08-31 13:29:11 +0200599 osmo_sockaddr_ntop(&addr->u.sa, ipbuf),
600 osmo_sockaddr_port(&addr->u.sa));
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200601 }
602 } else if (state->in_stream.ssrc != ssrc) {
Pau Espin Pedrol3239f622019-04-24 18:47:46 +0200603 LOGPENDP(endp, DRTP, LOGL_NOTICE,
604 "SSRC changed: %u -> %u "
605 "from %s:%d\n",
606 state->in_stream.ssrc, rtp_hdr->ssrc,
Pau Espin Pedrola790f0c2020-08-31 13:29:11 +0200607 osmo_sockaddr_ntop(&addr->u.sa, ipbuf),
608 osmo_sockaddr_port(&addr->u.sa));
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200609
610 state->in_stream.ssrc = ssrc;
611 if (rtp_end->force_constant_ssrc) {
612 int16_t delta_seq;
613
614 /* Always increment seqno by 1 */
Harald Welte33381352017-12-25 09:44:26 +0100615 state->patch.seq_offset =
Philipp Maier87bd9be2017-08-22 16:35:41 +0200616 (state->out_stream.last_seq + 1) - seq;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200617
618 /* Estimate number of packets that would have been sent */
619 delta_seq =
Philipp Maier87bd9be2017-08-22 16:35:41 +0200620 (arrival_time - state->in_stream.last_arrival_time
621 + state->packet_duration / 2) /
622 state->packet_duration;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200623
624 adjust_rtp_timestamp_offset(endp, state, rtp_end, addr,
625 delta_seq, timestamp);
626
Harald Welte33381352017-12-25 09:44:26 +0100627 state->patch.patch_ssrc = 1;
628 ssrc = state->patch.orig_ssrc;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200629 if (rtp_end->force_constant_ssrc != -1)
630 rtp_end->force_constant_ssrc -= 1;
631
Pau Espin Pedrol3239f622019-04-24 18:47:46 +0200632 LOGPENDP(endp, DRTP, LOGL_NOTICE,
633 "SSRC patching enabled, SSRC: %u "
634 "SeqNo offset: %d, TS offset: %d "
635 "from %s:%d\n", state->in_stream.ssrc,
636 state->patch.seq_offset, state->patch.timestamp_offset,
Pau Espin Pedrola790f0c2020-08-31 13:29:11 +0200637 osmo_sockaddr_ntop(&addr->u.sa, ipbuf),
638 osmo_sockaddr_port(&addr->u.sa));
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200639 }
640
641 state->in_stream.last_tsdelta = 0;
642 } else {
643 /* Compute current per-packet timestamp delta */
Philipp Maier87bd9be2017-08-22 16:35:41 +0200644 check_rtp_timestamp(endp, state, &state->in_stream, rtp_end,
645 addr, seq, timestamp, "input",
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200646 &state->in_stream.last_tsdelta);
647
Harald Welte33381352017-12-25 09:44:26 +0100648 if (state->patch.patch_ssrc)
649 ssrc = state->patch.orig_ssrc;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200650 }
651
652 /* Save before patching */
653 state->in_stream.last_timestamp = timestamp;
654 state->in_stream.last_seq = seq;
655 state->in_stream.last_arrival_time = arrival_time;
656
657 if (rtp_end->force_aligned_timing &&
658 state->out_stream.ssrc == ssrc && state->packet_duration)
659 /* Align the timestamp offset */
Philipp Maier87bd9be2017-08-22 16:35:41 +0200660 align_rtp_timestamp_offset(endp, state, rtp_end, addr,
661 timestamp);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200662
663 /* Store the updated SSRC back to the packet */
Harald Welte33381352017-12-25 09:44:26 +0100664 if (state->patch.patch_ssrc)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200665 rtp_hdr->ssrc = htonl(ssrc);
666
667 /* Apply the offset and store it back to the packet.
668 * This won't change anything if the offset is 0, so the conditional is
669 * omitted. */
Harald Welte33381352017-12-25 09:44:26 +0100670 seq += state->patch.seq_offset;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200671 rtp_hdr->sequence = htons(seq);
Harald Welte33381352017-12-25 09:44:26 +0100672 timestamp += state->patch.timestamp_offset;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200673 rtp_hdr->timestamp = htonl(timestamp);
674
675 /* Check again, whether the timestamps are still valid */
676 if (state->out_stream.ssrc == ssrc)
677 check_rtp_timestamp(endp, state, &state->out_stream, rtp_end,
678 addr, seq, timestamp, "output",
679 &state->out_stream.last_tsdelta);
680
681 /* Save output values */
682 state->out_stream.last_seq = seq;
683 state->out_stream.last_timestamp = timestamp;
684 state->out_stream.ssrc = ssrc;
685
686 if (payload < 0)
687 return;
688
689#if 0
Philipp Maierc66ab2c2020-06-02 20:55:34 +0200690 LOGPENDP(endp, DRTP, LOGL_DEBUG, "payload hdr payload %u -> endp payload %u\n",
691 rtp_hdr->payload_type, payload);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200692 rtp_hdr->payload_type = payload;
693#endif
694}
695
Philipp Maier9fc8a022019-02-20 12:26:52 +0100696/* There are different dialects used to format and transfer voice data. When
697 * the receiving end expects GSM-HR data to be formated after RFC 5993, this
698 * function is used to convert between RFC 5993 and TS 101318, which we normally
Neels Hofmeyr7c6dd3c2019-08-20 03:06:17 +0200699 * use.
700 * Return 0 on sucess, negative on errors like invalid data length. */
Neels Hofmeyr51b42ff2020-06-19 01:34:42 +0200701static int rfc5993_hr_convert(struct mgcp_endpoint *endp, struct msgb *msg)
Philipp Maier9fc8a022019-02-20 12:26:52 +0100702{
Philipp Maier9fc8a022019-02-20 12:26:52 +0100703 struct rtp_hdr *rtp_hdr;
Neels Hofmeyr51b42ff2020-06-19 01:34:42 +0200704 if (msgb_length(msg) < sizeof(struct rtp_hdr)) {
Neels Hofmeyr7c6dd3c2019-08-20 03:06:17 +0200705 LOGPENDP(endp, DRTP, LOGL_ERROR, "AMR RTP packet too short (%d < %zu)\n",
Neels Hofmeyr51b42ff2020-06-19 01:34:42 +0200706 msgb_length(msg), sizeof(struct rtp_hdr));
Neels Hofmeyr7c6dd3c2019-08-20 03:06:17 +0200707 return -EINVAL;
708 }
709
Neels Hofmeyr51b42ff2020-06-19 01:34:42 +0200710 rtp_hdr = (struct rtp_hdr *)msgb_data(msg);
Philipp Maier9fc8a022019-02-20 12:26:52 +0100711
Neels Hofmeyr51b42ff2020-06-19 01:34:42 +0200712 if (msgb_length(msg) == GSM_HR_BYTES + sizeof(struct rtp_hdr)) {
Philipp Maier9fc8a022019-02-20 12:26:52 +0100713 /* TS 101318 encoding => RFC 5993 encoding */
Neels Hofmeyr51b42ff2020-06-19 01:34:42 +0200714 msgb_put(msg, 1);
Philipp Maier9fc8a022019-02-20 12:26:52 +0100715 memmove(rtp_hdr->data + 1, rtp_hdr->data, GSM_HR_BYTES);
716 rtp_hdr->data[0] = 0x00;
Neels Hofmeyr51b42ff2020-06-19 01:34:42 +0200717 } else if (msgb_length(msg) == GSM_HR_BYTES + sizeof(struct rtp_hdr) + 1) {
Philipp Maier9fc8a022019-02-20 12:26:52 +0100718 /* RFC 5993 encoding => TS 101318 encoding */
719 memmove(rtp_hdr->data, rtp_hdr->data + 1, GSM_HR_BYTES);
Neels Hofmeyr51b42ff2020-06-19 01:34:42 +0200720 msgb_trim(msg, msgb_length(msg) - 1);
Philipp Maier9fc8a022019-02-20 12:26:52 +0100721 } else {
722 /* It is possible that multiple payloads occur in one RTP
723 * packet. This is not supported yet. */
Pau Espin Pedrol3239f622019-04-24 18:47:46 +0200724 LOGPENDP(endp, DRTP, LOGL_ERROR,
725 "cannot figure out how to convert RTP packet\n");
Neels Hofmeyr7c6dd3c2019-08-20 03:06:17 +0200726 return -ENOTSUP;
Philipp Maier9fc8a022019-02-20 12:26:52 +0100727 }
Neels Hofmeyr7c6dd3c2019-08-20 03:06:17 +0200728 return 0;
Philipp Maier9fc8a022019-02-20 12:26:52 +0100729}
730
Philipp Maier228e5912019-03-05 13:56:59 +0100731/* For AMR RTP two framing modes are defined RFC3267. There is a bandwith
732 * efficient encoding scheme where all fields are packed together one after
733 * another and an octet aligned mode where all fields are aligned to octet
734 * boundaries. This function is used to convert between the two modes */
Neels Hofmeyr51b42ff2020-06-19 01:34:42 +0200735static int amr_oa_bwe_convert(struct mgcp_endpoint *endp, struct msgb *msg,
Philipp Maier228e5912019-03-05 13:56:59 +0100736 bool target_is_oa)
737{
Neels Hofmeyr51b42ff2020-06-19 01:34:42 +0200738 /* NOTE: the msgb has an allocated length of RTP_BUF_SIZE, so there is
Philipp Maier228e5912019-03-05 13:56:59 +0100739 * plenty of space available to store the slightly larger, converted
740 * data */
Philipp Maier228e5912019-03-05 13:56:59 +0100741 struct rtp_hdr *rtp_hdr;
742 unsigned int payload_len;
743 int rc;
744
Neels Hofmeyr51b42ff2020-06-19 01:34:42 +0200745 if (msgb_length(msg) < sizeof(struct rtp_hdr)) {
746 LOGPENDP(endp, DRTP, LOGL_ERROR, "AMR RTP packet too short (%d < %zu)\n", msgb_length(msg), sizeof(struct rtp_hdr));
Neels Hofmeyr7c6dd3c2019-08-20 03:06:17 +0200747 return -EINVAL;
748 }
749
Neels Hofmeyr51b42ff2020-06-19 01:34:42 +0200750 rtp_hdr = (struct rtp_hdr *)msgb_data(msg);
Philipp Maier228e5912019-03-05 13:56:59 +0100751
Neels Hofmeyr51b42ff2020-06-19 01:34:42 +0200752 payload_len = msgb_length(msg) - sizeof(struct rtp_hdr);
Philipp Maier228e5912019-03-05 13:56:59 +0100753
754 if (osmo_amr_is_oa(rtp_hdr->data, payload_len)) {
755 if (!target_is_oa)
756 /* Input data is oa an target format is bwe
757 * ==> convert */
758 rc = osmo_amr_oa_to_bwe(rtp_hdr->data, payload_len);
759 else
760 /* Input data is already bew, but we accept it anyway
761 * ==> no conversion needed */
762 rc = payload_len;
763 } else {
764 if (target_is_oa)
765 /* Input data is bwe an target format is oa
766 * ==> convert */
767 rc = osmo_amr_bwe_to_oa(rtp_hdr->data, payload_len,
768 RTP_BUF_SIZE);
769 else
770 /* Input data is already oa, but we accept it anyway
771 * ==> no conversion needed */
772 rc = payload_len;
773 }
774 if (rc < 0) {
Pau Espin Pedrol3239f622019-04-24 18:47:46 +0200775 LOGPENDP(endp, DRTP, LOGL_ERROR,
776 "AMR RTP packet conversion failed\n");
Philipp Maier228e5912019-03-05 13:56:59 +0100777 return -EINVAL;
778 }
779
Neels Hofmeyr51b42ff2020-06-19 01:34:42 +0200780 return msgb_trim(msg, rc + sizeof(struct rtp_hdr));
Philipp Maier228e5912019-03-05 13:56:59 +0100781}
782
783/* Check if a conversion between octet-aligned and bandwith-efficient mode is
784 * indicated. */
785static bool amr_oa_bwe_convert_indicated(struct mgcp_rtp_codec *codec)
786{
787 if (codec->param_present == false)
788 return false;
789 if (!codec->param.amr_octet_aligned_present)
790 return false;
791 if (strcmp(codec->subtype_name, "AMR") != 0)
792 return false;
793 return true;
794}
795
796
Neels Hofmeyr7c6dd3c2019-08-20 03:06:17 +0200797/* Return whether an RTP packet with AMR payload is in octet-aligned mode.
798 * Return 0 if in bandwidth-efficient mode, 1 for octet-aligned mode, and negative if the RTP data is invalid. */
799static int amr_oa_check(char *data, int len)
Philipp Maier228e5912019-03-05 13:56:59 +0100800{
801 struct rtp_hdr *rtp_hdr;
802 unsigned int payload_len;
803
Neels Hofmeyr7c6dd3c2019-08-20 03:06:17 +0200804 if (len < sizeof(struct rtp_hdr))
805 return -EINVAL;
806
Philipp Maier228e5912019-03-05 13:56:59 +0100807 rtp_hdr = (struct rtp_hdr *)data;
808
809 payload_len = len - sizeof(struct rtp_hdr);
Neels Hofmeyr7c6dd3c2019-08-20 03:06:17 +0200810 if (payload_len < sizeof(struct amr_hdr))
811 return -EINVAL;
Philipp Maier228e5912019-03-05 13:56:59 +0100812
Neels Hofmeyr7c6dd3c2019-08-20 03:06:17 +0200813 return osmo_amr_is_oa(rtp_hdr->data, payload_len) ? 1 : 0;
Philipp Maier228e5912019-03-05 13:56:59 +0100814}
815
Philipp Maier87bd9be2017-08-22 16:35:41 +0200816/* Forward data to a debug tap. This is debug function that is intended for
817 * debugging the voice traffic with tools like gstreamer */
Neels Hofmeyr51b42ff2020-06-19 01:34:42 +0200818static void forward_data(int fd, struct mgcp_rtp_tap *tap, struct msgb *msg)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200819{
Philipp Maiere6f172d2017-11-07 12:00:01 +0100820 int rc;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200821
Philipp Maiere6f172d2017-11-07 12:00:01 +0100822 if (!tap->enabled)
823 return;
824
Neels Hofmeyr51b42ff2020-06-19 01:34:42 +0200825 rc = sendto(fd, msgb_data(msg), msgb_length(msg), 0, (struct sockaddr *)&tap->forward,
Philipp Maiere6f172d2017-11-07 12:00:01 +0100826 sizeof(tap->forward));
827
828 if (rc < 0)
829 LOGP(DRTP, LOGL_ERROR,
830 "Forwarding tapped (debug) voice data failed.\n");
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200831}
832
Philipp Maier889fe7f2020-07-06 17:44:12 +0200833/* Generate an RTP header if it is missing */
834static void gen_rtp_header(struct msgb *msg, struct mgcp_rtp_end *rtp_end,
835 struct mgcp_rtp_state *state)
836{
837 struct rtp_hdr *hdr = (struct rtp_hdr *)msgb_data(msg);
838
839 if (hdr->version > 0)
840 return;
841
842 hdr->version = 2;
843 hdr->payload_type = rtp_end->codec->payload_type;
844 hdr->timestamp = osmo_htonl(get_current_ts(rtp_end->codec->rate));
845 hdr->sequence = osmo_htons(state->alt_rtp_tx_sequence);
846 hdr->ssrc = state->alt_rtp_tx_ssrc;
847}
848
849
Philipp Maier87bd9be2017-08-22 16:35:41 +0200850/*! Send RTP/RTCP data to a specified destination connection.
Philipp Maier0b79d212020-06-18 12:02:49 +0200851 * \param[in] endp associated endpoint (for configuration, logging).
852 * \param[in] is_rtp flag to specify if the packet is of type RTP or RTCP.
853 * \param[in] spoofed source address (set to NULL to disable).
854 * \param[in] buf buffer that contains the RTP/RTCP data.
855 * \param[in] len length of the buffer that contains the RTP/RTCP data.
856 * \param[in] conn_src associated source connection.
857 * \param[in] conn_dst associated destination connection.
858 * \returns 0 on success, -1 on ERROR. */
Pau Espin Pedrola790f0c2020-08-31 13:29:11 +0200859int mgcp_send(struct mgcp_endpoint *endp, int is_rtp, struct osmo_sockaddr *addr,
Neels Hofmeyr51b42ff2020-06-19 01:34:42 +0200860 struct msgb *msg, struct mgcp_conn_rtp *conn_src,
Philipp Maier87bd9be2017-08-22 16:35:41 +0200861 struct mgcp_conn_rtp *conn_dst)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200862{
Philipp Maier87bd9be2017-08-22 16:35:41 +0200863 /*! When no destination connection is available (e.g. when only one
864 * connection in loopback mode exists), then the source connection
865 * shall be specified as destination connection */
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200866
Philipp Maier14b27a82020-06-02 20:15:30 +0200867 struct mgcp_trunk *trunk = endp->trunk;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200868 struct mgcp_rtp_end *rtp_end;
869 struct mgcp_rtp_state *rtp_state;
Pau Espin Pedrola790f0c2020-08-31 13:29:11 +0200870 char ipbuf[INET6_ADDRSTRLEN];
Philipp Maier87bd9be2017-08-22 16:35:41 +0200871 char *dest_name;
Philipp Maier6931f9a2018-07-26 09:29:31 +0200872 int rc;
Neels Hofmeyr51b42ff2020-06-19 01:34:42 +0200873 int len;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200874
Philipp Maier87bd9be2017-08-22 16:35:41 +0200875 OSMO_ASSERT(conn_src);
876 OSMO_ASSERT(conn_dst);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200877
Philipp Maier87bd9be2017-08-22 16:35:41 +0200878 if (is_rtp) {
Pau Espin Pedrol3239f622019-04-24 18:47:46 +0200879 LOGPENDP(endp, DRTP, LOGL_DEBUG, "delivering RTP packet...\n");
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200880 } else {
Pau Espin Pedrol3239f622019-04-24 18:47:46 +0200881 LOGPENDP(endp, DRTP, LOGL_DEBUG, "delivering RTCP packet...\n");
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200882 }
Philipp Maier87bd9be2017-08-22 16:35:41 +0200883
Pau Espin Pedrol3239f622019-04-24 18:47:46 +0200884 LOGPENDP(endp, DRTP, LOGL_DEBUG, "loop:%d, mode:%d%s\n",
Philipp Maier14b27a82020-06-02 20:15:30 +0200885 trunk->audio_loop, conn_src->conn->mode,
Pau Espin Pedrol3239f622019-04-24 18:47:46 +0200886 conn_src->conn->mode == MGCP_CONN_LOOPBACK ? " (loopback)" : "");
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200887
Philipp Maier6931f9a2018-07-26 09:29:31 +0200888 /* FIXME: It is legal that the payload type on the egress connection is
889 * different from the payload type that has been negotiated on the
890 * ingress connection. Essentially the codecs are the same so we can
891 * match them and patch the payload type. However, if we can not find
892 * the codec pendant (everything ist equal except the PT), we are of
893 * course unable to patch the payload type. A situation like this
894 * should not occur if transcoding is consequently avoided. Until
895 * we have transcoding support in osmo-mgw we can not resolve this. */
Philipp Maierda895b12018-08-03 12:16:37 +0200896 if (is_rtp) {
Neels Hofmeyr51b42ff2020-06-19 01:34:42 +0200897 rc = mgcp_patch_pt(conn_src, conn_dst, msg);
Philipp Maierda895b12018-08-03 12:16:37 +0200898 if (rc < 0) {
Pau Espin Pedrol3239f622019-04-24 18:47:46 +0200899 LOGPENDP(endp, DRTP, LOGL_DEBUG,
900 "can not patch PT because no suitable egress codec was found.\n");
Philipp Maierda895b12018-08-03 12:16:37 +0200901 }
Philipp Maier6931f9a2018-07-26 09:29:31 +0200902 }
903
Philipp Maier87bd9be2017-08-22 16:35:41 +0200904 /* Note: In case of loopback configuration, both, the source and the
905 * destination will point to the same connection. */
906 rtp_end = &conn_dst->end;
907 rtp_state = &conn_src->state;
908 dest_name = conn_dst->conn->name;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200909
Philipp Maier889fe7f2020-07-06 17:44:12 +0200910 /* Ensure we have an alternative SSRC in case we need it, see also
911 * gen_rtp_header() */
912 if (rtp_state->alt_rtp_tx_ssrc == 0)
913 rtp_state->alt_rtp_tx_ssrc = rand();
914
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200915 if (!rtp_end->output_enabled) {
Harald Weltea48ff4a2020-03-08 14:45:08 +0100916 rtpconn_rate_ctr_inc(conn_dst, endp, RTP_DROPPED_PACKETS_CTR);
Pau Espin Pedrol3239f622019-04-24 18:47:46 +0200917 LOGPENDP(endp, DRTP, LOGL_DEBUG,
918 "output disabled, drop to %s %s "
919 "rtp_port:%u rtcp_port:%u\n",
920 dest_name,
Pau Espin Pedrola790f0c2020-08-31 13:29:11 +0200921 osmo_sockaddr_ntop(&rtp_end->addr.u.sa, ipbuf),
Pau Espin Pedrol3239f622019-04-24 18:47:46 +0200922 ntohs(rtp_end->rtp_port), ntohs(rtp_end->rtcp_port)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200923 );
924 } else if (is_rtp) {
925 int cont;
926 int nbytes = 0;
Neels Hofmeyr51b42ff2020-06-19 01:34:42 +0200927 int buflen = msgb_length(msg);
Philipp Maier889fe7f2020-07-06 17:44:12 +0200928
929 /* Make sure we have a valid RTP header, in cases where no RTP
930 * header is present, we will generate one. */
931 gen_rtp_header(msg, rtp_end, rtp_state);
932
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200933 do {
Philipp Maier87bd9be2017-08-22 16:35:41 +0200934 /* Run transcoder */
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200935 cont = endp->cfg->rtp_processing_cb(endp, rtp_end,
Neels Hofmeyr51b42ff2020-06-19 01:34:42 +0200936 (char*)msgb_data(msg), &buflen,
Philipp Maier87bd9be2017-08-22 16:35:41 +0200937 RTP_BUF_SIZE);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200938 if (cont < 0)
939 break;
940
Philipp Maier87bd9be2017-08-22 16:35:41 +0200941 if (addr)
942 mgcp_patch_and_count(endp, rtp_state, rtp_end,
Neels Hofmeyr51b42ff2020-06-19 01:34:42 +0200943 addr, msg);
Philipp Maier9fc8a022019-02-20 12:26:52 +0100944
Philipp Maier228e5912019-03-05 13:56:59 +0100945 if (amr_oa_bwe_convert_indicated(conn_dst->end.codec)) {
Neels Hofmeyr51b42ff2020-06-19 01:34:42 +0200946 rc = amr_oa_bwe_convert(endp, msg,
Neels Hofmeyr5a6220f2019-08-20 03:09:04 +0200947 conn_dst->end.codec->param.amr_octet_aligned);
948 if (rc < 0) {
949 LOGPENDP(endp, DRTP, LOGL_ERROR,
950 "Error in AMR octet-aligned <-> bandwidth-efficient mode conversion\n");
951 break;
952 }
Philipp Maier228e5912019-03-05 13:56:59 +0100953 }
954 else if (rtp_end->rfc5993_hr_convert
Philipp Maier9fc8a022019-02-20 12:26:52 +0100955 && strcmp(conn_src->end.codec->subtype_name,
Neels Hofmeyr5a6220f2019-08-20 03:09:04 +0200956 "GSM-HR-08") == 0) {
Neels Hofmeyr51b42ff2020-06-19 01:34:42 +0200957 rc = rfc5993_hr_convert(endp, msg);
Neels Hofmeyr5a6220f2019-08-20 03:09:04 +0200958 if (rc < 0) {
959 LOGPENDP(endp, DRTP, LOGL_ERROR, "Error while converting to GSM-HR-08\n");
960 break;
961 }
962 }
Philipp Maier9fc8a022019-02-20 12:26:52 +0100963
Pau Espin Pedrol3239f622019-04-24 18:47:46 +0200964 LOGPENDP(endp, DRTP, LOGL_DEBUG,
965 "process/send to %s %s "
966 "rtp_port:%u rtcp_port:%u\n",
Pau Espin Pedrola790f0c2020-08-31 13:29:11 +0200967 dest_name,
968 osmo_sockaddr_ntop(&rtp_end->addr.u.sa, ipbuf),
Pau Espin Pedrol3239f622019-04-24 18:47:46 +0200969 ntohs(rtp_end->rtp_port), ntohs(rtp_end->rtcp_port)
970 );
Philipp Maier87bd9be2017-08-22 16:35:41 +0200971
972 /* Forward a copy of the RTP data to a debug ip/port */
973 forward_data(rtp_end->rtp.fd, &conn_src->tap_out,
Neels Hofmeyr51b42ff2020-06-19 01:34:42 +0200974 msg);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200975
976 /* FIXME: HACK HACK HACK. See OS#2459.
977 * The ip.access nano3G needs the first RTP payload's first two bytes to read hex
978 * 'e400', or it will reject the RAB assignment. It seems to not harm other femto
979 * cells (as long as we patch only the first RTP payload in each stream).
980 */
Neels Hofmeyr35a38292018-07-23 18:29:04 +0200981 if (!rtp_state->patched_first_rtp_payload
982 && conn_src->conn->mode == MGCP_CONN_LOOPBACK) {
Neels Hofmeyr51b42ff2020-06-19 01:34:42 +0200983 uint8_t *data = msgb_data(msg) + 12;
Neels Hofmeyr35a38292018-07-23 18:29:04 +0200984 if (data[0] == 0xe0) {
985 data[0] = 0xe4;
986 data[1] = 0x00;
987 rtp_state->patched_first_rtp_payload = true;
Pau Espin Pedrol3239f622019-04-24 18:47:46 +0200988 LOGPENDP(endp, DRTP, LOGL_DEBUG,
989 "Patching over first two bytes"
990 " to fake an IuUP Initialization Ack\n");
Neels Hofmeyr35a38292018-07-23 18:29:04 +0200991 }
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200992 }
993
Neels Hofmeyr51b42ff2020-06-19 01:34:42 +0200994 len = mgcp_udp_send(rtp_end->rtp.fd, &rtp_end->addr, rtp_end->rtp_port,
995 (char*)msgb_data(msg), msgb_length(msg));
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200996
Philipp Maier87bd9be2017-08-22 16:35:41 +0200997 if (len <= 0)
998 return len;
999
Harald Weltea48ff4a2020-03-08 14:45:08 +01001000 rtpconn_rate_ctr_inc(conn_dst, endp, RTP_PACKETS_TX_CTR);
1001 rtpconn_rate_ctr_add(conn_dst, endp, RTP_OCTETS_TX_CTR, len);
Philipp Maier889fe7f2020-07-06 17:44:12 +02001002 rtp_state->alt_rtp_tx_sequence++;
Philipp Maier87bd9be2017-08-22 16:35:41 +02001003
1004 nbytes += len;
1005 buflen = cont;
1006 } while (buflen > 0);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001007 return nbytes;
Philipp Maier14b27a82020-06-02 20:15:30 +02001008 } else if (!trunk->omit_rtcp) {
Pau Espin Pedrol3239f622019-04-24 18:47:46 +02001009 LOGPENDP(endp, DRTP, LOGL_DEBUG,
1010 "send to %s %s rtp_port:%u rtcp_port:%u\n",
Pau Espin Pedrola790f0c2020-08-31 13:29:11 +02001011 dest_name, osmo_sockaddr_ntop(&rtp_end->addr.u.sa, ipbuf),
Pau Espin Pedrol3239f622019-04-24 18:47:46 +02001012 ntohs(rtp_end->rtp_port), ntohs(rtp_end->rtcp_port)
1013 );
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001014
Philipp Maier87bd9be2017-08-22 16:35:41 +02001015 len = mgcp_udp_send(rtp_end->rtcp.fd,
1016 &rtp_end->addr,
Neels Hofmeyr51b42ff2020-06-19 01:34:42 +02001017 rtp_end->rtcp_port, (char*)msgb_data(msg), msgb_length(msg));
Philipp Maier87bd9be2017-08-22 16:35:41 +02001018
Harald Weltea48ff4a2020-03-08 14:45:08 +01001019 rtpconn_rate_ctr_inc(conn_dst, endp, RTP_PACKETS_TX_CTR);
1020 rtpconn_rate_ctr_add(conn_dst, endp, RTP_OCTETS_TX_CTR, len);
Philipp Maier889fe7f2020-07-06 17:44:12 +02001021 rtp_state->alt_rtp_tx_sequence++;
Philipp Maier87bd9be2017-08-22 16:35:41 +02001022
1023 return len;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001024 }
1025
1026 return 0;
1027}
1028
Philipp Maier87bd9be2017-08-22 16:35:41 +02001029/* Check if the origin (addr) matches the address/port data of the RTP
1030 * connections. */
Pau Espin Pedrola790f0c2020-08-31 13:29:11 +02001031static int check_rtp_origin(struct mgcp_conn_rtp *conn, struct osmo_sockaddr *addr)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001032{
Pau Espin Pedrola790f0c2020-08-31 13:29:11 +02001033 char ipbuf[INET6_ADDRSTRLEN];
1034
1035 if (addr_is_any(&conn->end.addr)) {
Neels Hofmeyrefd645e2018-09-10 13:14:50 +02001036 switch (conn->conn->mode) {
1037 case MGCP_CONN_LOOPBACK:
1038 /* HACK: for IuUP, we want to reply with an IuUP Initialization ACK upon the first RTP
1039 * message received. We currently hackishly accomplish that by putting the endpoint in
1040 * loopback mode and patching over the looped back RTP message to make it look like an
1041 * ack. We don't know the femto cell's IP address and port until the RAB Assignment
1042 * Response is received, but the nano3G expects an IuUP Initialization Ack before it even
1043 * sends the RAB Assignment Response. Hence, if the remote address is 0.0.0.0 and the
1044 * MGCP port is in loopback mode, allow looping back the packet to any source. */
Pau Espin Pedrol3239f622019-04-24 18:47:46 +02001045 LOGPCONN(conn->conn, DRTP, LOGL_ERROR,
1046 "In loopback mode and remote address not set:"
Pau Espin Pedrola790f0c2020-08-31 13:29:11 +02001047 " allowing data from address: %s\n",
1048 osmo_sockaddr_ntop(&addr->u.sa, ipbuf));
Neels Hofmeyrefd645e2018-09-10 13:14:50 +02001049 return 0;
1050
1051 default:
1052 /* Receiving early media before the endpoint is configured. Instead of logging
1053 * this as an error that occurs on every call, keep it more low profile to not
1054 * confuse humans with expected errors. */
Pau Espin Pedrol3239f622019-04-24 18:47:46 +02001055 LOGPCONN(conn->conn, DRTP, LOGL_INFO,
1056 "Rx RTP from %s, but remote address not set:"
Pau Espin Pedrola790f0c2020-08-31 13:29:11 +02001057 " dropping early media\n",
1058 osmo_sockaddr_ntop(&addr->u.sa, ipbuf));
Neels Hofmeyrefd645e2018-09-10 13:14:50 +02001059 return -1;
1060 }
Neels Hofmeyr0063ca22018-07-23 18:12:16 +02001061 }
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001062
Philipp Maier87bd9be2017-08-22 16:35:41 +02001063 /* Note: Check if the inbound RTP data comes from the same host to
1064 * which we send our outgoing RTP traffic. */
Pau Espin Pedrola790f0c2020-08-31 13:29:11 +02001065 if (conn->end.addr.u.sa.sa_family != addr->u.sa.sa_family ||
1066 (conn->end.addr.u.sa.sa_family == AF_INET &&
1067 conn->end.addr.u.sin.sin_addr.s_addr != addr->u.sin.sin_addr.s_addr) ||
1068 (conn->end.addr.u.sa.sa_family == AF_INET6 &&
1069 memcmp(&conn->end.addr.u.sin6.sin6_addr, &addr->u.sin6.sin6_addr,
1070 sizeof(struct in6_addr)))) {
Pau Espin Pedrol3239f622019-04-24 18:47:46 +02001071 LOGPCONN(conn->conn, DRTP, LOGL_ERROR,
Pau Espin Pedrola790f0c2020-08-31 13:29:11 +02001072 "data from wrong address: %s, ",
1073 osmo_sockaddr_ntop(&addr->u.sa, ipbuf));
Philipp Maierc3413882017-10-27 12:26:54 +02001074 LOGPC(DRTP, LOGL_ERROR, "expected: %s\n",
Pau Espin Pedrola790f0c2020-08-31 13:29:11 +02001075 osmo_sockaddr_ntop(&conn->end.addr.u.sa, ipbuf));
Pau Espin Pedrol3239f622019-04-24 18:47:46 +02001076 LOGPCONN(conn->conn, DRTP, LOGL_ERROR, "packet tossed\n");
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001077 return -1;
1078 }
1079
Philipp Maier87bd9be2017-08-22 16:35:41 +02001080 /* Note: Usually the remote remote port of the data we receive will be
1081 * the same as the remote port where we transmit outgoing RTP traffic
1082 * to (set by MDCX). We use this to check the origin of the data for
1083 * plausibility. */
Pau Espin Pedrola790f0c2020-08-31 13:29:11 +02001084 if (ntohs(conn->end.rtp_port) != osmo_sockaddr_port(&addr->u.sa) &&
1085 ntohs(conn->end.rtcp_port) != osmo_sockaddr_port(&addr->u.sa)) {
Pau Espin Pedrol3239f622019-04-24 18:47:46 +02001086 LOGPCONN(conn->conn, DRTP, LOGL_ERROR,
Pau Espin Pedrola790f0c2020-08-31 13:29:11 +02001087 "data from wrong source port: %d, ",
1088 osmo_sockaddr_port(&addr->u.sa));
Philipp Maierc3413882017-10-27 12:26:54 +02001089 LOGPC(DRTP, LOGL_ERROR,
Philipp Maier87bd9be2017-08-22 16:35:41 +02001090 "expected: %d for RTP or %d for RTCP\n",
1091 ntohs(conn->end.rtp_port), ntohs(conn->end.rtcp_port));
Pau Espin Pedrol3239f622019-04-24 18:47:46 +02001092 LOGPCONN(conn->conn, DRTP, LOGL_ERROR, "packet tossed\n");
Philipp Maier87bd9be2017-08-22 16:35:41 +02001093 return -1;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001094 }
1095
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001096 return 0;
1097}
1098
Philipp Maier87bd9be2017-08-22 16:35:41 +02001099/* Check the if the destination address configuration of an RTP connection
1100 * makes sense */
1101static int check_rtp_destin(struct mgcp_conn_rtp *conn)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001102{
Pau Espin Pedrola790f0c2020-08-31 13:29:11 +02001103 char ipbuf[INET6_ADDRSTRLEN];
1104 bool ip_is_any = addr_is_any(&conn->end.addr);
1105
Philipp Maiere6df0e42018-05-29 14:03:06 +02001106 /* Note: it is legal to create a connection but never setting a port
1107 * and IP-address for outgoing data. */
Pau Espin Pedrola790f0c2020-08-31 13:29:11 +02001108 if (ip_is_any && conn->end.rtp_port == 0) {
Pau Espin Pedrol3239f622019-04-24 18:47:46 +02001109 LOGPCONN(conn->conn, DRTP, LOGL_DEBUG,
1110 "destination IP-address and rtp port is (not yet) known (%s:%u)\n",
Pau Espin Pedrola790f0c2020-08-31 13:29:11 +02001111 osmo_sockaddr_ntop(&conn->end.addr.u.sa, ipbuf), conn->end.rtp_port);
Philipp Maiere6df0e42018-05-29 14:03:06 +02001112 return -1;
1113 }
1114
Pau Espin Pedrola790f0c2020-08-31 13:29:11 +02001115 if (ip_is_any) {
Pau Espin Pedrol3239f622019-04-24 18:47:46 +02001116 LOGPCONN(conn->conn, DRTP, LOGL_ERROR,
1117 "destination IP-address is invalid (%s:%u)\n",
Pau Espin Pedrola790f0c2020-08-31 13:29:11 +02001118 osmo_sockaddr_ntop(&conn->end.addr.u.sa, ipbuf), conn->end.rtp_port);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001119 return -1;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001120 }
Philipp Maier87bd9be2017-08-22 16:35:41 +02001121
1122 if (conn->end.rtp_port == 0) {
Pau Espin Pedrol3239f622019-04-24 18:47:46 +02001123 LOGPCONN(conn->conn, DRTP, LOGL_ERROR,
1124 "destination rtp port is invalid (%s:%u)\n",
Pau Espin Pedrola790f0c2020-08-31 13:29:11 +02001125 osmo_sockaddr_ntop(&conn->end.addr.u.sa, ipbuf), conn->end.rtp_port);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001126 return -1;
1127 }
1128
1129 return 0;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001130}
1131
Philipp Maier4dba7692018-08-03 12:20:52 +02001132/* Do some basic checks to make sure that the RTCP packets we are going to
1133 * process are not complete garbage */
Neels Hofmeyr51b42ff2020-06-19 01:34:42 +02001134static int check_rtcp(struct mgcp_conn_rtp *conn_src, struct msgb *msg)
Philipp Maier4dba7692018-08-03 12:20:52 +02001135{
1136 struct rtcp_hdr *hdr;
1137 unsigned int len;
1138 uint8_t type;
1139
1140 /* RTPC packets that are just a header without data do not make
1141 * any sense. */
Neels Hofmeyr51b42ff2020-06-19 01:34:42 +02001142 if (msgb_length(msg) < sizeof(struct rtcp_hdr)) {
1143 LOG_CONN_RTP(conn_src, LOGL_ERROR, "RTCP packet too short (%u < %zu)\n",
1144 msgb_length(msg), sizeof(struct rtcp_hdr));
Philipp Maier4dba7692018-08-03 12:20:52 +02001145 return -EINVAL;
Neels Hofmeyr51b42ff2020-06-19 01:34:42 +02001146 }
Philipp Maier4dba7692018-08-03 12:20:52 +02001147
1148 /* Make sure that the length of the received packet does not exceed
1149 * the available buffer size */
Neels Hofmeyr51b42ff2020-06-19 01:34:42 +02001150 hdr = (struct rtcp_hdr *)msgb_data(msg);
Philipp Maier4dba7692018-08-03 12:20:52 +02001151 len = (osmo_ntohs(hdr->length) + 1) * 4;
Neels Hofmeyr51b42ff2020-06-19 01:34:42 +02001152 if (len > msgb_length(msg)) {
1153 LOG_CONN_RTP(conn_src, LOGL_ERROR, "RTCP header length exceeds packet size (%u > %u)\n",
1154 len, msgb_length(msg));
Philipp Maier4dba7692018-08-03 12:20:52 +02001155 return -EINVAL;
Neels Hofmeyr51b42ff2020-06-19 01:34:42 +02001156 }
Philipp Maier4dba7692018-08-03 12:20:52 +02001157
1158 /* Make sure we accept only packets that have a proper packet type set
1159 * See also: http://www.iana.org/assignments/rtp-parameters/rtp-parameters.xhtml */
1160 type = hdr->type;
Neels Hofmeyr51b42ff2020-06-19 01:34:42 +02001161 if ((type < 192 || type > 195) && (type < 200 || type > 213)) {
1162 LOG_CONN_RTP(conn_src, LOGL_ERROR, "RTCP header: invalid type: %u\n", type);
Philipp Maier4dba7692018-08-03 12:20:52 +02001163 return -EINVAL;
Neels Hofmeyr51b42ff2020-06-19 01:34:42 +02001164 }
Philipp Maier4dba7692018-08-03 12:20:52 +02001165
1166 return 0;
1167}
1168
1169/* Do some basic checks to make sure that the RTP packets we are going to
1170 * process are not complete garbage */
Neels Hofmeyr51b42ff2020-06-19 01:34:42 +02001171static int check_rtp(struct mgcp_conn_rtp *conn_src, struct msgb *msg)
Philipp Maier4dba7692018-08-03 12:20:52 +02001172{
Neels Hofmeyr51b42ff2020-06-19 01:34:42 +02001173 size_t min_size = sizeof(struct rtp_hdr);
1174 if (msgb_length(msg) < min_size) {
1175 LOG_CONN_RTP(conn_src, LOGL_ERROR, "RTP packet too short (%u < %zu)\n",
1176 msgb_length(msg), min_size);
1177 return -1;
1178 }
Philipp Maier4dba7692018-08-03 12:20:52 +02001179
1180 /* FIXME: Add more checks, the reason why we do not check more than
1181 * the length is because we currently handle IUUP packets as RTP
1182 * packets, so they must pass this check, if we weould be more
1183 * strict here, we would possibly break 3G. (see also FIXME note
1184 * below */
1185
1186 return 0;
1187}
1188
Philipp Maier87bd9be2017-08-22 16:35:41 +02001189/* Send RTP data. Possible options are standard RTP packet
1190 * transmission or trsmission via an osmux connection */
Neels Hofmeyr51b42ff2020-06-19 01:34:42 +02001191static int mgcp_send_rtp(struct mgcp_conn_rtp *conn_dst, struct msgb *msg)
Philipp Maier87bd9be2017-08-22 16:35:41 +02001192{
Neels Hofmeyr51b42ff2020-06-19 01:34:42 +02001193 struct osmo_rtp_msg_ctx *mc = OSMO_RTP_MSG_CTX(msg);
1194 enum rtp_proto proto = mc->proto;
1195 struct mgcp_conn_rtp *conn_src = mc->conn_src;
Neels Hofmeyr51b42ff2020-06-19 01:34:42 +02001196 struct mgcp_endpoint *endp = conn_src->conn->endp;
Philipp Maier87bd9be2017-08-22 16:35:41 +02001197
Pau Espin Pedrol3239f622019-04-24 18:47:46 +02001198 LOGPENDP(endp, DRTP, LOGL_DEBUG, "destin conn:%s\n",
1199 mgcp_conn_dump(conn_dst->conn));
Philipp Maier87bd9be2017-08-22 16:35:41 +02001200
1201 /* Before we try to deliver the packet, we check if the destination
1202 * port and IP-Address make sense at all. If not, we will be unable
1203 * to deliver the packet. */
1204 if (check_rtp_destin(conn_dst) != 0)
1205 return -1;
1206
1207 /* Depending on the RTP connection type, deliver the RTP packet to the
1208 * destination connection. */
1209 switch (conn_dst->type) {
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001210 case MGCP_RTP_DEFAULT:
Pau Espin Pedrol3239f622019-04-24 18:47:46 +02001211 LOGPENDP(endp, DRTP, LOGL_DEBUG,
1212 "endpoint type is MGCP_RTP_DEFAULT, "
1213 "using mgcp_send() to forward data directly\n");
Philipp Maier87bd9be2017-08-22 16:35:41 +02001214 return mgcp_send(endp, proto == MGCP_PROTO_RTP,
Pau Espin Pedrola790f0c2020-08-31 13:29:11 +02001215 mc->from_addr, msg, conn_src, conn_dst);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001216 case MGCP_OSMUX_BSC_NAT:
Philipp Maier87bd9be2017-08-22 16:35:41 +02001217 case MGCP_OSMUX_BSC:
Pau Espin Pedrol3239f622019-04-24 18:47:46 +02001218 LOGPENDP(endp, DRTP, LOGL_DEBUG,
1219 "endpoint type is MGCP_OSMUX_BSC_NAT, "
1220 "using osmux_xfrm_to_osmux() to forward data through OSMUX\n");
Neels Hofmeyr51b42ff2020-06-19 01:34:42 +02001221 return osmux_xfrm_to_osmux((char*)msgb_data(msg), msgb_length(msg), conn_dst);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001222 }
1223
Philipp Maier87bd9be2017-08-22 16:35:41 +02001224 /* If the data has not been handled/forwarded until here, it will
1225 * be discarded, this should not happen, normally the MGCP type
1226 * should be properly set */
Pau Espin Pedrol3239f622019-04-24 18:47:46 +02001227 LOGPENDP(endp, DRTP, LOGL_ERROR, "bad MGCP type -- data discarded!\n");
Philipp Maier87bd9be2017-08-22 16:35:41 +02001228
1229 return -1;
1230}
1231
1232/*! dispatch incoming RTP packet to opposite RTP connection.
Philipp Maier0b79d212020-06-18 12:02:49 +02001233 * \param[in] proto protocol (MGCP_CONN_TYPE_RTP or MGCP_CONN_TYPE_RTCP).
1234 * \param[in] addr socket address where the RTP packet has been received from.
1235 * \param[in] buf buffer that hold the RTP payload.
1236 * \param[in] buf_size size data length of buf.
1237 * \param[in] conn originating connection.
1238 * \returns 0 on success, -1 on ERROR. */
Neels Hofmeyr51b42ff2020-06-19 01:34:42 +02001239int mgcp_dispatch_rtp_bridge_cb(struct msgb *msg)
Philipp Maier87bd9be2017-08-22 16:35:41 +02001240{
Neels Hofmeyr51b42ff2020-06-19 01:34:42 +02001241 struct osmo_rtp_msg_ctx *mc = OSMO_RTP_MSG_CTX(msg);
1242 struct mgcp_conn_rtp *conn_src = mc->conn_src;
1243 struct mgcp_conn *conn = conn_src->conn;
Philipp Maier87bd9be2017-08-22 16:35:41 +02001244 struct mgcp_conn *conn_dst;
Pau Espin Pedrola790f0c2020-08-31 13:29:11 +02001245 struct osmo_sockaddr *from_addr = mc->from_addr;
Philipp Maier87bd9be2017-08-22 16:35:41 +02001246
1247 /*! NOTE: This callback function implements the endpoint specific
Alexander Chemeris61cf9bb2020-05-11 18:13:53 +03001248 * dispatch behaviour of an rtp bridge/proxy endpoint. It is assumed
Philipp Maier87bd9be2017-08-22 16:35:41 +02001249 * that the endpoint will hold only two connections. This premise
1250 * is used to determine the opposite connection (it is always the
1251 * connection that is not the originating connection). Once the
1252 * destination connection is known the RTP packet is sent via
1253 * the destination connection. */
1254
Pau Espin Pedrol9aaaab62019-05-15 23:23:27 +02001255
1256 /* Check if the connection is in loopback mode, if yes, just send the
1257 * incoming data back to the origin */
1258 if (conn->mode == MGCP_CONN_LOOPBACK) {
1259 /* When we are in loopback mode, we loop back all incoming
1260 * packets back to their origin. We will use the originating
1261 * address data from the UDP packet header to patch the
1262 * outgoing address in connection on the fly */
1263 if (conn->u.rtp.end.rtp_port == 0) {
Pau Espin Pedrola790f0c2020-08-31 13:29:11 +02001264 OSMO_ASSERT(conn->u.rtp.end.addr.u.sa.sa_family == from_addr->u.sa.sa_family);
1265 switch (from_addr->u.sa.sa_family) {
1266 case AF_INET:
1267 conn->u.rtp.end.addr.u.sin.sin_addr = from_addr->u.sin.sin_addr;
1268 conn->u.rtp.end.rtp_port = from_addr->u.sin.sin_port;
1269 break;
1270 case AF_INET6:
1271 conn->u.rtp.end.addr.u.sin6.sin6_addr = from_addr->u.sin6.sin6_addr;
1272 conn->u.rtp.end.rtp_port = from_addr->u.sin6.sin6_port;
1273 break;
1274 default:
1275 OSMO_ASSERT(false);
1276 }
Pau Espin Pedrol9aaaab62019-05-15 23:23:27 +02001277 }
Neels Hofmeyr51b42ff2020-06-19 01:34:42 +02001278 return mgcp_send_rtp(conn_src, msg);
Pau Espin Pedrol9aaaab62019-05-15 23:23:27 +02001279 }
1280
Philipp Maier87bd9be2017-08-22 16:35:41 +02001281 /* Find a destination connection. */
1282 /* NOTE: This code path runs every time an RTP packet is received. The
1283 * function mgcp_find_dst_conn() we use to determine the detination
1284 * connection will iterate the connection list inside the endpoint.
1285 * Since list iterations are quite costly, we will figure out the
1286 * destination only once and use the optional private data pointer of
1287 * the connection to cache the destination connection pointer. */
1288 if (!conn->priv) {
1289 conn_dst = mgcp_find_dst_conn(conn);
1290 conn->priv = conn_dst;
1291 } else {
1292 conn_dst = (struct mgcp_conn *)conn->priv;
1293 }
1294
1295 /* There is no destination conn, stop here */
1296 if (!conn_dst) {
Alexander Chemerisebb9bf32020-05-11 18:14:31 +03001297 LOGPCONN(conn, DRTP, LOGL_DEBUG,
1298 "no connection to forward an incoming RTP packet to\n");
Philipp Maier87bd9be2017-08-22 16:35:41 +02001299 return -1;
1300 }
1301
1302 /* The destination conn is not an RTP connection */
1303 if (conn_dst->type != MGCP_CONN_TYPE_RTP) {
Pau Espin Pedrol3239f622019-04-24 18:47:46 +02001304 LOGPCONN(conn, DRTP, LOGL_ERROR,
1305 "unable to find suitable destination conn\n");
Philipp Maier87bd9be2017-08-22 16:35:41 +02001306 return -1;
1307 }
1308
1309 /* Dispatch RTP packet to destination RTP connection */
Neels Hofmeyr51b42ff2020-06-19 01:34:42 +02001310 return mgcp_send_rtp(&conn_dst->u.rtp, msg);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001311}
1312
Philipp Maier0996a1e2020-06-10 15:27:14 +02001313/*! dispatch incoming RTP packet to E1 subslot, handle RTCP packets locally.
1314 * \param[in] proto protocol (MGCP_CONN_TYPE_RTP or MGCP_CONN_TYPE_RTCP).
1315 * \param[in] addr socket address where the RTP packet has been received from.
1316 * \param[in] buf buffer that hold the RTP payload.
1317 * \param[in] buf_size size data length of buf.
1318 * \param[in] conn originating connection.
1319 * \returns 0 on success, -1 on ERROR. */
Neels Hofmeyr51b42ff2020-06-19 01:34:42 +02001320int mgcp_dispatch_e1_bridge_cb(struct msgb *msg)
Philipp Maier0996a1e2020-06-10 15:27:14 +02001321{
Neels Hofmeyr51b42ff2020-06-19 01:34:42 +02001322 struct osmo_rtp_msg_ctx *mc = OSMO_RTP_MSG_CTX(msg);
1323 struct mgcp_conn_rtp *conn_src = mc->conn_src;
1324 struct mgcp_conn *conn = conn_src->conn;
Pau Espin Pedrola790f0c2020-08-31 13:29:11 +02001325 struct osmo_sockaddr *from_addr = mc->from_addr;
Neels Hofmeyr51b42ff2020-06-19 01:34:42 +02001326
Philipp Maier889fe7f2020-07-06 17:44:12 +02001327 /* Check if the connection is in loopback mode, if yes, just send the
1328 * incoming data back to the origin */
1329 if (conn->mode == MGCP_CONN_LOOPBACK) {
1330 /* When we are in loopback mode, we loop back all incoming
1331 * packets back to their origin. We will use the originating
1332 * address data from the UDP packet header to patch the
1333 * outgoing address in connection on the fly */
1334 if (conn->u.rtp.end.rtp_port == 0) {
Pau Espin Pedrola790f0c2020-08-31 13:29:11 +02001335 OSMO_ASSERT(conn->u.rtp.end.addr.u.sa.sa_family == from_addr->u.sa.sa_family);
1336 switch (from_addr->u.sa.sa_family) {
1337 case AF_INET:
1338 conn->u.rtp.end.addr.u.sin.sin_addr = from_addr->u.sin.sin_addr;
1339 conn->u.rtp.end.rtp_port = from_addr->u.sin.sin_port;
1340 break;
1341 case AF_INET6:
1342 conn->u.rtp.end.addr.u.sin6.sin6_addr = from_addr->u.sin6.sin6_addr;
1343 conn->u.rtp.end.rtp_port = from_addr->u.sin6.sin6_port;
1344 break;
1345 default:
1346 OSMO_ASSERT(false);
1347 }
Philipp Maier889fe7f2020-07-06 17:44:12 +02001348 }
1349 return mgcp_send_rtp(conn_src, msg);
1350 }
1351
1352 /* Forward to E1 */
1353 return mgcp_e1_send_rtp(conn->endp, conn->u.rtp.end.codec, msg);
Philipp Maier0996a1e2020-06-10 15:27:14 +02001354}
1355
Philipp Maierdf5d2192018-01-24 11:39:32 +01001356/*! cleanup an endpoint when a connection on an RTP bridge endpoint is removed.
1357 * \param[in] endp Endpoint on which the connection resides.
Philipp Maier08eb9352020-06-18 11:55:35 +02001358 * \param[in] conn Connection that is about to be removed (ignored). */
Philipp Maierdf5d2192018-01-24 11:39:32 +01001359void mgcp_cleanup_rtp_bridge_cb(struct mgcp_endpoint *endp, struct mgcp_conn *conn)
1360{
1361 struct mgcp_conn *conn_cleanup;
1362
1363 /* In mgcp_dispatch_rtp_bridge_cb() we use conn->priv to cache the
1364 * pointer to the destination connection, so that we do not have
1365 * to go through the list every time an RTP packet arrives. To prevent
1366 * a use-after-free situation we invalidate this information for all
1367 * connections present when one connection is removed from the
1368 * endpoint. */
1369 llist_for_each_entry(conn_cleanup, &endp->conns, entry) {
1370 conn_cleanup->priv = NULL;
1371 }
1372}
1373
Philipp Maier0996a1e2020-06-10 15:27:14 +02001374/*! cleanup an endpoint when a connection on an E1 endpoint is removed.
1375 * \param[in] endp Endpoint on which the connection resides.
1376 * \param[in] conn Connection that is about to be removed (ignored). */
1377void mgcp_cleanup_e1_bridge_cb(struct mgcp_endpoint *endp, struct mgcp_conn *conn)
1378{
Philipp Maier889fe7f2020-07-06 17:44:12 +02001379 /* Cleanup tasks for E1 are the same as for regular endpoint. The
1380 * shut down of the E1 part is handled separately. */
1381 mgcp_cleanup_rtp_bridge_cb(endp, conn);
Philipp Maier0996a1e2020-06-10 15:27:14 +02001382}
1383
Neels Hofmeyr51b42ff2020-06-19 01:34:42 +02001384static bool is_dummy_msg(enum rtp_proto proto, struct msgb *msg)
1385{
1386 return msgb_length(msg) == 1 && msgb_data(msg)[0] == MGCP_DUMMY_LOAD;
1387}
1388
Philipp Maier87bd9be2017-08-22 16:35:41 +02001389/* Handle incoming RTP data from NET */
1390static int rtp_data_net(struct osmo_fd *fd, unsigned int what)
1391{
1392 /* NOTE: This is a generic implementation. RTP data is received. In
1393 * case of loopback the data is just sent back to its origin. All
1394 * other cases implement endpoint specific behaviour (e.g. how is the
1395 * destination connection determined?). That specific behaviour is
1396 * implemented by the callback function that is called at the end of
1397 * the function */
1398
1399 struct mgcp_conn_rtp *conn_src;
1400 struct mgcp_endpoint *endp;
Pau Espin Pedrola790f0c2020-08-31 13:29:11 +02001401 struct osmo_sockaddr addr;
Neels Hofmeyr51b42ff2020-06-19 01:34:42 +02001402 socklen_t slen = sizeof(addr);
Pau Espin Pedrola790f0c2020-08-31 13:29:11 +02001403 char ipbuf[INET6_ADDRSTRLEN];
Neels Hofmeyr51b42ff2020-06-19 01:34:42 +02001404 int ret;
1405 enum rtp_proto proto;
1406 struct osmo_rtp_msg_ctx *mc;
1407 struct msgb *msg = msgb_alloc(RTP_BUF_SIZE, "RTP-rx");
1408 int rc;
Philipp Maier87bd9be2017-08-22 16:35:41 +02001409
1410 conn_src = (struct mgcp_conn_rtp *)fd->data;
1411 OSMO_ASSERT(conn_src);
1412 endp = conn_src->conn->endp;
1413 OSMO_ASSERT(endp);
1414
Neels Hofmeyr51b42ff2020-06-19 01:34:42 +02001415 proto = (fd == &conn_src->end.rtp)? MGCP_PROTO_RTP : MGCP_PROTO_RTCP;
Philipp Maier87bd9be2017-08-22 16:35:41 +02001416
Pau Espin Pedrola790f0c2020-08-31 13:29:11 +02001417 ret = recvfrom(fd->fd, msgb_data(msg), msg->data_len, 0, (struct sockaddr *)&addr.u.sa, &slen);
Neels Hofmeyr51b42ff2020-06-19 01:34:42 +02001418
1419 if (ret <= 0) {
1420 LOG_CONN_RTP(conn_src, LOGL_ERROR, "recvfrom error: %s\n", strerror(errno));
1421 rc = -1;
1422 goto out;
1423 }
1424
1425 msgb_put(msg, ret);
1426
1427 LOG_CONN_RTP(conn_src, LOGL_DEBUG, "%s: rx %u bytes from %s:%u\n",
1428 proto == MGCP_PROTO_RTP ? "RTP" : "RTPC",
Pau Espin Pedrola790f0c2020-08-31 13:29:11 +02001429 msgb_length(msg), osmo_sockaddr_ntop(&addr.u.sa, ipbuf),
1430 osmo_sockaddr_port(&addr.u.sa));
Neels Hofmeyr51b42ff2020-06-19 01:34:42 +02001431
1432 if ((proto == MGCP_PROTO_RTP && check_rtp(conn_src, msg))
1433 || (proto == MGCP_PROTO_RTCP && check_rtcp(conn_src, msg))) {
1434 /* Logging happened in the two check_ functions */
1435 rc = -1;
1436 goto out;
1437 }
1438
1439 if (is_dummy_msg(proto, msg)) {
1440 LOG_CONN_RTP(conn_src, LOGL_DEBUG, "rx dummy packet (dropped)\n");
1441 rc = 0;
1442 goto out;
1443 }
1444
1445 /* Since the msgb remains owned and freed by this function, the msg ctx data struct can just be on the stack and
1446 * needs not be allocated with the msgb. */
1447 mc = OSMO_RTP_MSG_CTX(msg);
1448 *mc = (struct osmo_rtp_msg_ctx){
1449 .proto = proto,
1450 .conn_src = conn_src,
1451 .from_addr = &addr,
1452 };
1453 LOG_CONN_RTP(conn_src, LOGL_DEBUG, "msg ctx: %d %p %s\n",
1454 mc->proto, mc->conn_src,
Pau Espin Pedrola790f0c2020-08-31 13:29:11 +02001455 osmo_hexdump((void*)mc->from_addr,
1456 mc->from_addr->u.sa.sa_family == AF_INET6 ?
1457 sizeof(struct sockaddr_in6) :
1458 sizeof(struct sockaddr_in)));
Neels Hofmeyr51b42ff2020-06-19 01:34:42 +02001459
1460 /* Increment RX statistics */
1461 rate_ctr_inc(&conn_src->rate_ctr_group->ctr[RTP_PACKETS_RX_CTR]);
1462 rate_ctr_add(&conn_src->rate_ctr_group->ctr[RTP_OCTETS_RX_CTR], msgb_length(msg));
1463 /* FIXME: count RTP and RTCP separately, also count IuUP payload-less separately */
1464
1465 /* Forward a copy of the RTP data to a debug ip/port */
1466 forward_data(fd->fd, &conn_src->tap_in, msg);
1467
1468 rc = rx_rtp(msg);
1469
1470out:
1471 msgb_free(msg);
1472 return rc;
1473}
1474
1475static int rx_rtp(struct msgb *msg)
1476{
1477 struct osmo_rtp_msg_ctx *mc = OSMO_RTP_MSG_CTX(msg);
1478 struct mgcp_conn_rtp *conn_src = mc->conn_src;
Pau Espin Pedrola790f0c2020-08-31 13:29:11 +02001479 struct osmo_sockaddr *from_addr = mc->from_addr;
Neels Hofmeyr51b42ff2020-06-19 01:34:42 +02001480 struct mgcp_conn *conn = conn_src->conn;
1481 struct mgcp_trunk *trunk = conn->endp->trunk;
1482
1483 LOG_CONN_RTP(conn_src, LOGL_DEBUG, "rx_rtp(%u bytes)\n", msgb_length(msg));
Philipp Maier87bd9be2017-08-22 16:35:41 +02001484
Oliver Smithe36b7752019-01-22 16:31:36 +01001485 mgcp_conn_watchdog_kick(conn_src->conn);
1486
Philipp Maier228e5912019-03-05 13:56:59 +01001487 /* If AMR is configured for the ingress connection a conversion of the
1488 * framing mode (octet-aligned vs. bandwith-efficient is explicitly
1489 * define, then we check if the incoming payload matches that
1490 * expectation. */
1491 if (amr_oa_bwe_convert_indicated(conn_src->end.codec)) {
Neels Hofmeyr51b42ff2020-06-19 01:34:42 +02001492 int oa = amr_oa_check((char*)msgb_data(msg), msgb_length(msg));
Neels Hofmeyr7c6dd3c2019-08-20 03:06:17 +02001493 if (oa < 0)
1494 return -1;
1495 if (((bool)oa) != conn_src->end.codec->param.amr_octet_aligned)
Philipp Maier228e5912019-03-05 13:56:59 +01001496 return -1;
1497 }
1498
Neels Hofmeyr51b42ff2020-06-19 01:34:42 +02001499 /* Check if the origin of the RTP packet seems plausible */
1500 if (!trunk->rtp_accept_all && check_rtp_origin(conn_src, from_addr))
1501 return -1;
1502
Philipp Maier87bd9be2017-08-22 16:35:41 +02001503 /* Execute endpoint specific implementation that handles the
1504 * dispatching of the RTP data */
Neels Hofmeyr51b42ff2020-06-19 01:34:42 +02001505 return conn->endp->type->dispatch_rtp_cb(msg);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001506}
1507
1508/*! set IP Type of Service parameter.
Philipp Maier0b79d212020-06-18 12:02:49 +02001509 * \param[in] fd associated file descriptor.
1510 * \param[in] tos dscp value.
1511 * \returns 0 on success, -1 on ERROR. */
Philipp Maier87bd9be2017-08-22 16:35:41 +02001512int mgcp_set_ip_tos(int fd, int tos)
1513{
1514 int ret;
1515 ret = setsockopt(fd, IPPROTO_IP, IP_TOS, &tos, sizeof(tos));
1516
1517 if (ret < 0)
1518 return -1;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001519 return 0;
1520}
1521
Philipp Maier87bd9be2017-08-22 16:35:41 +02001522/*! bind RTP port to osmo_fd.
Philipp Maier0b79d212020-06-18 12:02:49 +02001523 * \param[in] source_addr source (local) address to bind on.
1524 * \param[in] fd associated file descriptor.
1525 * \param[in] port to bind on.
1526 * \returns 0 on success, -1 on ERROR. */
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001527int mgcp_create_bind(const char *source_addr, struct osmo_fd *fd, int port)
1528{
Harald Welte8890dfa2017-11-17 15:09:30 +01001529 int rc;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001530
Pau Espin Pedrola790f0c2020-08-31 13:29:11 +02001531 rc = osmo_sock_init2(AF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP, source_addr, port,
Harald Welte8890dfa2017-11-17 15:09:30 +01001532 NULL, 0, OSMO_SOCK_F_BIND);
1533 if (rc < 0) {
Philipp Maierc3413882017-10-27 12:26:54 +02001534 LOGP(DRTP, LOGL_ERROR, "failed to bind UDP port (%s:%i).\n",
Philipp Maier87bd9be2017-08-22 16:35:41 +02001535 source_addr, port);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001536 return -1;
1537 }
Harald Welte8890dfa2017-11-17 15:09:30 +01001538 fd->fd = rc;
1539 LOGP(DRTP, LOGL_DEBUG, "created socket + bound UDP port (%s:%i).\n", source_addr, port);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001540
1541 return 0;
1542}
1543
Philipp Maier87bd9be2017-08-22 16:35:41 +02001544/* Bind RTP and RTCP port (helper function for mgcp_bind_net_rtp_port()) */
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001545static int bind_rtp(struct mgcp_config *cfg, const char *source_addr,
Philipp Maierc66ab2c2020-06-02 20:55:34 +02001546 struct mgcp_rtp_end *rtp_end, struct mgcp_endpoint *endp)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001547{
Philipp Maier87bd9be2017-08-22 16:35:41 +02001548 /* NOTE: The port that is used for RTCP is the RTP port incremented by one
1549 * (e.g. RTP-Port = 16000 ==> RTCP-Port = 16001) */
1550
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001551 if (mgcp_create_bind(source_addr, &rtp_end->rtp,
1552 rtp_end->local_port) != 0) {
Pau Espin Pedrol3239f622019-04-24 18:47:46 +02001553 LOGPENDP(endp, DRTP, LOGL_ERROR,
1554 "failed to create RTP port: %s:%d\n",
1555 source_addr, rtp_end->local_port);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001556 goto cleanup0;
1557 }
1558
1559 if (mgcp_create_bind(source_addr, &rtp_end->rtcp,
1560 rtp_end->local_port + 1) != 0) {
Pau Espin Pedrol3239f622019-04-24 18:47:46 +02001561 LOGPENDP(endp, DRTP, LOGL_ERROR,
1562 "failed to create RTCP port: %s:%d\n",
1563 source_addr, rtp_end->local_port + 1);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001564 goto cleanup1;
1565 }
1566
Philipp Maier87bd9be2017-08-22 16:35:41 +02001567 /* Set Type of Service (DSCP-Value) as configured via VTY */
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001568 mgcp_set_ip_tos(rtp_end->rtp.fd, cfg->endp_dscp);
1569 mgcp_set_ip_tos(rtp_end->rtcp.fd, cfg->endp_dscp);
1570
Pau Espin Pedrola7152e02020-05-09 19:15:50 +02001571 rtp_end->rtp.when = OSMO_FD_READ;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001572 if (osmo_fd_register(&rtp_end->rtp) != 0) {
Pau Espin Pedrol3239f622019-04-24 18:47:46 +02001573 LOGPENDP(endp, DRTP, LOGL_ERROR,
1574 "failed to register RTP port %d\n",
1575 rtp_end->local_port);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001576 goto cleanup2;
1577 }
1578
Pau Espin Pedrola7152e02020-05-09 19:15:50 +02001579 rtp_end->rtcp.when = OSMO_FD_READ;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001580 if (osmo_fd_register(&rtp_end->rtcp) != 0) {
Pau Espin Pedrol3239f622019-04-24 18:47:46 +02001581 LOGPENDP(endp, DRTP, LOGL_ERROR,
1582 "failed to register RTCP port %d\n",
1583 rtp_end->local_port + 1);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001584 goto cleanup3;
1585 }
1586
1587 return 0;
1588
1589cleanup3:
1590 osmo_fd_unregister(&rtp_end->rtp);
1591cleanup2:
1592 close(rtp_end->rtcp.fd);
1593 rtp_end->rtcp.fd = -1;
1594cleanup1:
1595 close(rtp_end->rtp.fd);
1596 rtp_end->rtp.fd = -1;
1597cleanup0:
1598 return -1;
1599}
1600
Philipp Maier87bd9be2017-08-22 16:35:41 +02001601/*! bind RTP port to endpoint/connection.
Philipp Maier0b79d212020-06-18 12:02:49 +02001602 * \param[in] endp endpoint that holds the RTP connection.
1603 * \param[in] rtp_port port number to bind on.
1604 * \param[in] conn associated RTP connection.
1605 * \returns 0 on success, -1 on ERROR. */
Philipp Maier87bd9be2017-08-22 16:35:41 +02001606int mgcp_bind_net_rtp_port(struct mgcp_endpoint *endp, int rtp_port,
1607 struct mgcp_conn_rtp *conn)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001608{
Philipp Maier87bd9be2017-08-22 16:35:41 +02001609 char name[512];
1610 struct mgcp_rtp_end *end;
Pau Espin Pedrola790f0c2020-08-31 13:29:11 +02001611 char local_ip_addr[INET6_ADDRSTRLEN];
Philipp Maier87bd9be2017-08-22 16:35:41 +02001612
Philipp Maier01d24a32017-11-21 17:26:09 +01001613 snprintf(name, sizeof(name), "%s-%s", conn->conn->name, conn->conn->id);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001614 end = &conn->end;
1615
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001616 if (end->rtp.fd != -1 || end->rtcp.fd != -1) {
Pau Espin Pedrol3239f622019-04-24 18:47:46 +02001617 LOGPENDP(endp, DRTP, LOGL_ERROR, "%u was already bound on conn:%s\n",
1618 rtp_port, mgcp_conn_dump(conn->conn));
Philipp Maier87bd9be2017-08-22 16:35:41 +02001619
1620 /* Double bindings should never occour! Since we always allocate
1621 * connections dynamically and free them when they are not
1622 * needed anymore, there must be no previous binding leftover.
1623 * Should there be a connection bound twice, we have a serious
1624 * problem and must exit immediately! */
1625 OSMO_ASSERT(false);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001626 }
1627
1628 end->local_port = rtp_port;
Philipp Maier87bd9be2017-08-22 16:35:41 +02001629 end->rtp.cb = rtp_data_net;
1630 end->rtp.data = conn;
1631 end->rtcp.data = conn;
1632 end->rtcp.cb = rtp_data_net;
1633
Philipp Maier1cb1e382017-11-02 17:16:04 +01001634 mgcp_get_local_addr(local_ip_addr, conn);
1635
Philipp Maierc66ab2c2020-06-02 20:55:34 +02001636 return bind_rtp(endp->cfg, local_ip_addr, end, endp);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001637}
1638
Philipp Maier87bd9be2017-08-22 16:35:41 +02001639/*! free allocated RTP and RTCP ports.
1640 * \param[in] end RTP end */
1641void mgcp_free_rtp_port(struct mgcp_rtp_end *end)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001642{
1643 if (end->rtp.fd != -1) {
1644 close(end->rtp.fd);
1645 end->rtp.fd = -1;
1646 osmo_fd_unregister(&end->rtp);
1647 }
1648
1649 if (end->rtcp.fd != -1) {
1650 close(end->rtcp.fd);
1651 end->rtcp.fd = -1;
1652 osmo_fd_unregister(&end->rtcp);
1653 }
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001654}