blob: 73a2aca0ba86b693a8a9903d48c66a75f710d4fa [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 Hofmeyr306dc092018-09-30 05:01:20 +020048#include <osmocom/mgcp/iuup_cn_node.h>
49#include <osmocom/mgcp/iuup_protocol.h>
Neels Hofmeyrf83ec562017-09-07 19:18:40 +020050
Philipp Maier6931f9a2018-07-26 09:29:31 +020051
Neels Hofmeyrf83ec562017-09-07 19:18:40 +020052#define RTP_SEQ_MOD (1 << 16)
53#define RTP_MAX_DROPOUT 3000
54#define RTP_MAX_MISORDER 100
55#define RTP_BUF_SIZE 4096
56
Neels Hofmeyr306dc092018-09-30 05:01:20 +020057enum rtp_proto {
Neels Hofmeyrf83ec562017-09-07 19:18:40 +020058 MGCP_PROTO_RTP,
59 MGCP_PROTO_RTCP,
60};
61
Neels Hofmeyr306dc092018-09-30 05:01:20 +020062static int rx_rtp(struct msgb *msg);
63
Philipp Maier1cb1e382017-11-02 17:16:04 +010064/*! Determine the local rtp bind IP-address.
65 * \param[out] addr caller provided memory to store the resulting IP-Address
66 * \param[in] endp mgcp endpoint, that holds a copy of the VTY parameters
67 *
68 * The local bind IP-address is automatically selected by probing the
69 * IP-Address of the interface that is pointing towards the remote IP-Address,
70 * if no remote IP-Address is known yet, the statically configured
71 * IP-Addresses are used as fallback. */
72void mgcp_get_local_addr(char *addr, struct mgcp_conn_rtp *conn)
73{
74
75 struct mgcp_endpoint *endp;
76 int rc;
77 endp = conn->conn->endp;
78
79 /* Try probing the local IP-Address */
80 if (endp->cfg->net_ports.bind_addr_probe && conn->end.addr.s_addr != 0) {
81 rc = osmo_sock_local_ip(addr, inet_ntoa(conn->end.addr));
82 if (rc < 0)
Pau Espin Pedrol3239f622019-04-24 18:47:46 +020083 LOGPCONN(conn->conn, DRTP, LOGL_ERROR,
84 "local interface auto detection failed, using configured addresses...\n");
Philipp Maier1cb1e382017-11-02 17:16:04 +010085 else {
Pau Espin Pedrol3239f622019-04-24 18:47:46 +020086 LOGPCONN(conn->conn, DRTP, LOGL_DEBUG,
87 "selected local rtp bind ip %s by probing using remote ip %s\n",
88 addr, inet_ntoa(conn->end.addr));
Philipp Maier1cb1e382017-11-02 17:16:04 +010089 return;
90 }
91 }
92
Pau Espin Pedrola93c6e92019-05-06 15:23:57 +020093 /* Select from preconfigured IP-Addresses. We don't have bind_addr for Osmux (yet?). */
Philipp Maier1cb1e382017-11-02 17:16:04 +010094 if (endp->cfg->net_ports.bind_addr) {
95 /* Check there is a bind IP for the RTP traffic configured,
96 * if so, use that IP-Address */
Philipp Maierf8bfbe82017-11-23 19:32:31 +010097 osmo_strlcpy(addr, endp->cfg->net_ports.bind_addr, INET_ADDRSTRLEN);
Pau Espin Pedrol3239f622019-04-24 18:47:46 +020098 LOGPCONN(conn->conn, DRTP, LOGL_DEBUG,
99 "using configured rtp bind ip as local bind ip %s\n",
100 addr);
Philipp Maier1cb1e382017-11-02 17:16:04 +0100101 } else {
102 /* No specific bind IP is configured for the RTP traffic, so
103 * assume the IP where we listen for incoming MGCP messages
104 * as bind IP */
Philipp Maierf8bfbe82017-11-23 19:32:31 +0100105 osmo_strlcpy(addr, endp->cfg->source_addr, INET_ADDRSTRLEN);
Pau Espin Pedrol3239f622019-04-24 18:47:46 +0200106 LOGPCONN(conn->conn, DRTP, LOGL_DEBUG,
107 "using mgcp bind ip as local rtp bind ip: %s\n", addr);
Philipp Maier1cb1e382017-11-02 17:16:04 +0100108 }
109}
110
Philipp Maier87bd9be2017-08-22 16:35:41 +0200111/* This does not need to be a precision timestamp and
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200112 * is allowed to wrap quite fast. The returned value is
Philipp Maier87bd9be2017-08-22 16:35:41 +0200113 * 1/codec_rate seconds. */
114static uint32_t get_current_ts(unsigned codec_rate)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200115{
116 struct timespec tp;
117 uint64_t ret;
118
Philipp Maier87bd9be2017-08-22 16:35:41 +0200119 if (!codec_rate)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200120 return 0;
121
122 memset(&tp, 0, sizeof(tp));
123 if (clock_gettime(CLOCK_MONOTONIC, &tp) != 0)
Philipp Maierc3413882017-10-27 12:26:54 +0200124 LOGP(DRTP, LOGL_NOTICE, "Getting the clock failed.\n");
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200125
126 /* convert it to 1/unit seconds */
127 ret = tp.tv_sec;
Philipp Maier87bd9be2017-08-22 16:35:41 +0200128 ret *= codec_rate;
129 ret += (int64_t) tp.tv_nsec * codec_rate / 1000 / 1000 / 1000;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200130
131 return ret;
132}
133
Philipp Maier87bd9be2017-08-22 16:35:41 +0200134/*! send udp packet.
135 * \param[in] fd associated file descriptor
136 * \param[in] addr destination ip-address
Pau Espin Pedrolf1d301a2019-05-13 16:35:53 +0200137 * \param[in] port destination UDP port (network byte order)
Philipp Maier87bd9be2017-08-22 16:35:41 +0200138 * \param[in] buf buffer that holds the data to be send
139 * \param[in] len length of the data to be sent
140 * \returns bytes sent, -1 on error */
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200141int mgcp_udp_send(int fd, struct in_addr *addr, int port, char *buf, int len)
142{
143 struct sockaddr_in out;
Philipp Maier87bd9be2017-08-22 16:35:41 +0200144
Philipp Maierc3413882017-10-27 12:26:54 +0200145 LOGP(DRTP, LOGL_DEBUG,
Philipp Maier87bd9be2017-08-22 16:35:41 +0200146 "sending %i bytes length packet to %s:%u ...\n",
147 len, inet_ntoa(*addr), ntohs(port));
148
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200149 out.sin_family = AF_INET;
150 out.sin_port = port;
151 memcpy(&out.sin_addr, addr, sizeof(*addr));
152
153 return sendto(fd, buf, len, 0, (struct sockaddr *)&out, sizeof(out));
154}
155
Philipp Maier87bd9be2017-08-22 16:35:41 +0200156/*! send RTP dummy packet (to keep NAT connection open).
157 * \param[in] endp mcgp endpoint that holds the RTP connection
158 * \param[in] conn associated RTP connection
159 * \returns bytes sent, -1 on error */
160int mgcp_send_dummy(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200161{
162 static char buf[] = { MGCP_DUMMY_LOAD };
163 int rc;
164 int was_rtcp = 0;
165
Philipp Maier87bd9be2017-08-22 16:35:41 +0200166 OSMO_ASSERT(endp);
167 OSMO_ASSERT(conn);
168
Pau Espin Pedrol3239f622019-04-24 18:47:46 +0200169 LOGPCONN(conn->conn, DRTP, LOGL_DEBUG,"sending dummy packet... %s\n",
170 mgcp_conn_dump(conn->conn));
Philipp Maier87bd9be2017-08-22 16:35:41 +0200171
172 rc = mgcp_udp_send(conn->end.rtp.fd, &conn->end.addr,
173 conn->end.rtp_port, buf, 1);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200174
175 if (rc == -1)
176 goto failed;
177
178 if (endp->tcfg->omit_rtcp)
179 return rc;
180
181 was_rtcp = 1;
Philipp Maier87bd9be2017-08-22 16:35:41 +0200182 rc = mgcp_udp_send(conn->end.rtcp.fd, &conn->end.addr,
183 conn->end.rtcp_port, buf, 1);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200184
185 if (rc >= 0)
186 return rc;
187
188failed:
Pau Espin Pedrol3239f622019-04-24 18:47:46 +0200189 LOGPCONN(conn->conn, DRTP, LOGL_ERROR,
190 "Failed to send dummy %s packet.\n",
191 was_rtcp ? "RTCP" : "RTP");
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200192
193 return -1;
194}
195
Philipp Maier87bd9be2017-08-22 16:35:41 +0200196/* Compute timestamp alignment error */
197static int32_t ts_alignment_error(struct mgcp_rtp_stream_state *sstate,
198 int ptime, uint32_t timestamp)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200199{
200 int32_t timestamp_delta;
201
202 if (ptime == 0)
203 return 0;
204
205 /* Align according to: T - Tlast = k * Tptime */
206 timestamp_delta = timestamp - sstate->last_timestamp;
207
208 return timestamp_delta % ptime;
209}
210
Philipp Maier87bd9be2017-08-22 16:35:41 +0200211/* Check timestamp and sequence number for plausibility */
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200212static int check_rtp_timestamp(struct mgcp_endpoint *endp,
213 struct mgcp_rtp_state *state,
214 struct mgcp_rtp_stream_state *sstate,
215 struct mgcp_rtp_end *rtp_end,
216 struct sockaddr_in *addr,
217 uint16_t seq, uint32_t timestamp,
Philipp Maier87bd9be2017-08-22 16:35:41 +0200218 const char *text, int32_t * tsdelta_out)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200219{
220 int32_t tsdelta;
221 int32_t timestamp_error;
222
223 /* Not fully intialized, skip */
224 if (sstate->last_tsdelta == 0 && timestamp == sstate->last_timestamp)
225 return 0;
226
227 if (seq == sstate->last_seq) {
228 if (timestamp != sstate->last_timestamp) {
Philipp Maier9e1d1642018-05-09 16:26:34 +0200229 rate_ctr_inc(sstate->err_ts_ctr);
Pau Espin Pedrol3239f622019-04-24 18:47:46 +0200230 LOGPENDP(endp, DRTP, LOGL_ERROR,
231 "The %s timestamp delta is != 0 but the sequence "
232 "number %d is the same, "
233 "TS offset: %d, SeqNo offset: %d "
234 "on SSRC: %u timestamp: %u "
235 "from %s:%d\n",
236 text, seq,
237 state->patch.timestamp_offset, state->patch.seq_offset,
238 sstate->ssrc, timestamp, inet_ntoa(addr->sin_addr),
239 ntohs(addr->sin_port));
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200240 }
241 return 0;
242 }
243
244 tsdelta =
Philipp Maier87bd9be2017-08-22 16:35:41 +0200245 (int32_t)(timestamp - sstate->last_timestamp) /
246 (int16_t)(seq - sstate->last_seq);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200247
248 if (tsdelta == 0) {
249 /* Don't update *tsdelta_out */
Pau Espin Pedrol3239f622019-04-24 18:47:46 +0200250 LOGPENDP(endp, DRTP, LOGL_NOTICE,
251 "The %s timestamp delta is %d "
252 "on SSRC: %u timestamp: %u "
253 "from %s:%d\n",
254 text, tsdelta,
255 sstate->ssrc, timestamp,
256 inet_ntoa(addr->sin_addr), ntohs(addr->sin_port));
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200257
258 return 0;
259 }
260
261 if (sstate->last_tsdelta != tsdelta) {
262 if (sstate->last_tsdelta) {
Pau Espin Pedrol3239f622019-04-24 18:47:46 +0200263 LOGPENDP(endp, DRTP, LOGL_INFO,
264 "The %s timestamp delta changes from %d to %d "
265 "on SSRC: %u timestamp: %u from %s:%d\n",
266 text, sstate->last_tsdelta, tsdelta,
267 sstate->ssrc, timestamp,
268 inet_ntoa(addr->sin_addr), ntohs(addr->sin_port));
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200269 }
270 }
271
272 if (tsdelta_out)
273 *tsdelta_out = tsdelta;
274
275 timestamp_error =
Philipp Maier87bd9be2017-08-22 16:35:41 +0200276 ts_alignment_error(sstate, state->packet_duration, timestamp);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200277
278 if (timestamp_error) {
Philipp Maier9e1d1642018-05-09 16:26:34 +0200279 rate_ctr_inc(sstate->err_ts_ctr);
Pau Espin Pedrol3239f622019-04-24 18:47:46 +0200280 LOGPENDP(endp, DRTP, LOGL_NOTICE,
281 "The %s timestamp has an alignment error of %d "
282 "on SSRC: %u "
283 "SeqNo delta: %d, TS delta: %d, dTS/dSeq: %d "
284 "from %s:%d. ptime: %d\n",
285 text, timestamp_error,
286 sstate->ssrc,
287 (int16_t)(seq - sstate->last_seq),
288 (int32_t)(timestamp - sstate->last_timestamp),
289 tsdelta,
290 inet_ntoa(addr->sin_addr), ntohs(addr->sin_port),
291 state->packet_duration);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200292 }
293 return 1;
294}
295
296/* Set the timestamp offset according to the packet duration. */
297static int adjust_rtp_timestamp_offset(struct mgcp_endpoint *endp,
298 struct mgcp_rtp_state *state,
299 struct mgcp_rtp_end *rtp_end,
300 struct sockaddr_in *addr,
301 int16_t delta_seq, uint32_t in_timestamp)
302{
303 int32_t tsdelta = state->packet_duration;
304 int timestamp_offset;
305 uint32_t out_timestamp;
306
307 if (tsdelta == 0) {
308 tsdelta = state->out_stream.last_tsdelta;
309 if (tsdelta != 0) {
Pau Espin Pedrol3239f622019-04-24 18:47:46 +0200310 LOGPENDP(endp, DRTP, LOGL_NOTICE,
311 "A fixed packet duration is not available, "
312 "using last output timestamp delta instead: %d "
313 "from %s:%d\n", tsdelta,
314 inet_ntoa(addr->sin_addr), ntohs(addr->sin_port));
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200315 } else {
Philipp Maierbc0346e2018-06-07 09:52:16 +0200316 tsdelta = rtp_end->codec->rate * 20 / 1000;
Pau Espin Pedrol3239f622019-04-24 18:47:46 +0200317 LOGPENDP(endp, DRTP, LOGL_NOTICE,
318 "Fixed packet duration and last timestamp delta "
319 "are not available, "
320 "using fixed 20ms instead: %d "
321 "from %s:%d\n", tsdelta,
322 inet_ntoa(addr->sin_addr), ntohs(addr->sin_port));
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200323 }
324 }
325
326 out_timestamp = state->out_stream.last_timestamp + delta_seq * tsdelta;
327 timestamp_offset = out_timestamp - in_timestamp;
328
Harald Welte33381352017-12-25 09:44:26 +0100329 if (state->patch.timestamp_offset != timestamp_offset) {
330 state->patch.timestamp_offset = timestamp_offset;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200331
Pau Espin Pedrol3239f622019-04-24 18:47:46 +0200332 LOGPENDP(endp, DRTP, LOGL_NOTICE,
333 "Timestamp offset change on SSRC: %u "
334 "SeqNo delta: %d, TS offset: %d, "
335 "from %s:%d\n", state->in_stream.ssrc,
336 delta_seq, state->patch.timestamp_offset,
337 inet_ntoa(addr->sin_addr), ntohs(addr->sin_port));
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200338 }
339
340 return timestamp_offset;
341}
342
343/* Set the timestamp offset according to the packet duration. */
344static int align_rtp_timestamp_offset(struct mgcp_endpoint *endp,
345 struct mgcp_rtp_state *state,
346 struct mgcp_rtp_end *rtp_end,
347 struct sockaddr_in *addr,
348 uint32_t timestamp)
349{
Philipp Maier87bd9be2017-08-22 16:35:41 +0200350 int ts_error = 0;
351 int ts_check = 0;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200352 int ptime = state->packet_duration;
353
354 /* Align according to: T + Toffs - Tlast = k * Tptime */
355
Philipp Maier87bd9be2017-08-22 16:35:41 +0200356 ts_error = ts_alignment_error(&state->out_stream, ptime,
Harald Welte33381352017-12-25 09:44:26 +0100357 timestamp + state->patch.timestamp_offset);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200358
Philipp Maier87bd9be2017-08-22 16:35:41 +0200359 /* If there is an alignment error, we have to compensate it */
360 if (ts_error) {
Harald Welte33381352017-12-25 09:44:26 +0100361 state->patch.timestamp_offset += ptime - ts_error;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200362
Pau Espin Pedrol3239f622019-04-24 18:47:46 +0200363 LOGPENDP(endp, DRTP, LOGL_NOTICE,
364 "Corrected timestamp alignment error of %d on SSRC: %u "
365 "new TS offset: %d, "
366 "from %s:%d\n",
367 ts_error, state->in_stream.ssrc,
368 state->patch.timestamp_offset, inet_ntoa(addr->sin_addr),
369 ntohs(addr->sin_port));
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200370 }
371
Philipp Maier87bd9be2017-08-22 16:35:41 +0200372 /* Check we really managed to compensate the timestamp
373 * offset. There should not be any remaining error, failing
Harald Welte1d1b98f2017-12-25 10:03:40 +0100374 * here would point to a serous problem with the alignment
375 * error computation function */
Philipp Maier87bd9be2017-08-22 16:35:41 +0200376 ts_check = ts_alignment_error(&state->out_stream, ptime,
Harald Welte33381352017-12-25 09:44:26 +0100377 timestamp + state->patch.timestamp_offset);
Philipp Maier87bd9be2017-08-22 16:35:41 +0200378 OSMO_ASSERT(ts_check == 0);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200379
Philipp Maier87bd9be2017-08-22 16:35:41 +0200380 /* Return alignment error before compensation */
381 return ts_error;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200382}
383
Philipp Maier87bd9be2017-08-22 16:35:41 +0200384/*! dummy callback to disable transcoding (see also cfg->rtp_processing_cb).
385 * \param[in] associated endpoint
386 * \param[in] destination RTP end
387 * \param[in,out] pointer to buffer with voice data
388 * \param[in] voice data length
Harald Welte1d1b98f2017-12-25 10:03:40 +0100389 * \param[in] maximum size of caller provided voice data buffer
Philipp Maier87bd9be2017-08-22 16:35:41 +0200390 * \returns ignores input parameters, return always 0 */
391int mgcp_rtp_processing_default(struct mgcp_endpoint *endp,
392 struct mgcp_rtp_end *dst_end,
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200393 char *data, int *len, int buf_size)
394{
Pau Espin Pedrol3239f622019-04-24 18:47:46 +0200395 LOGPENDP(endp, DRTP, LOGL_DEBUG, "transcoding disabled\n");
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200396 return 0;
397}
398
Philipp Maier87bd9be2017-08-22 16:35:41 +0200399/*! dummy callback to disable transcoding (see also cfg->setup_rtp_processing_cb).
400 * \param[in] associated endpoint
Philipp Maieracc10352018-07-19 18:07:57 +0200401 * \param[in] destination RTP connnection
402 * \param[in] source RTP connection
Philipp Maier87bd9be2017-08-22 16:35:41 +0200403 * \returns ignores input parameters, return always 0 */
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200404int mgcp_setup_rtp_processing_default(struct mgcp_endpoint *endp,
Philipp Maieracc10352018-07-19 18:07:57 +0200405 struct mgcp_conn_rtp *conn_dst,
406 struct mgcp_conn_rtp *conn_src)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200407{
Pau Espin Pedrol3239f622019-04-24 18:47:46 +0200408 LOGPENDP(endp, DRTP, LOGL_DEBUG, "transcoding disabled\n");
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200409 return 0;
410}
411
412void mgcp_get_net_downlink_format_default(struct mgcp_endpoint *endp,
Philipp Maier58128252019-03-06 11:28:18 +0100413 const struct mgcp_rtp_codec **codec,
Philipp Maier87bd9be2017-08-22 16:35:41 +0200414 const char **fmtp_extra,
415 struct mgcp_conn_rtp *conn)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200416{
Pau Espin Pedrol3239f622019-04-24 18:47:46 +0200417 LOGPENDP(endp, DRTP, LOGL_DEBUG, "conn:%s using format defaults\n",
418 mgcp_conn_dump(conn->conn));
Philipp Maier87bd9be2017-08-22 16:35:41 +0200419
Philipp Maier58128252019-03-06 11:28:18 +0100420 *codec = conn->end.codec;
Philipp Maier87bd9be2017-08-22 16:35:41 +0200421 *fmtp_extra = conn->end.fmtp_extra;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200422}
423
Philipp Maier87bd9be2017-08-22 16:35:41 +0200424void mgcp_rtp_annex_count(struct mgcp_endpoint *endp,
425 struct mgcp_rtp_state *state, const uint16_t seq,
426 const int32_t transit, const uint32_t ssrc)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200427{
428 int32_t d;
429
430 /* initialize or re-initialize */
Harald Welte49e3d5a2017-12-25 09:47:57 +0100431 if (!state->stats.initialized || state->stats.ssrc != ssrc) {
432 state->stats.initialized = 1;
433 state->stats.base_seq = seq;
434 state->stats.max_seq = seq - 1;
435 state->stats.ssrc = ssrc;
436 state->stats.jitter = 0;
437 state->stats.transit = transit;
438 state->stats.cycles = 0;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200439 } else {
440 uint16_t udelta;
441
Philipp Maier87bd9be2017-08-22 16:35:41 +0200442 /* The below takes the shape of the validation of
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200443 * Appendix A. Check if there is something weird with
444 * the sequence number, otherwise check for a wrap
445 * around in the sequence number.
446 * It can't wrap during the initialization so let's
447 * skip it here. The Appendix A probably doesn't have
Philipp Maier87bd9be2017-08-22 16:35:41 +0200448 * this issue because of the probation. */
Harald Welte49e3d5a2017-12-25 09:47:57 +0100449 udelta = seq - state->stats.max_seq;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200450 if (udelta < RTP_MAX_DROPOUT) {
Harald Welte49e3d5a2017-12-25 09:47:57 +0100451 if (seq < state->stats.max_seq)
452 state->stats.cycles += RTP_SEQ_MOD;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200453 } else if (udelta <= RTP_SEQ_MOD - RTP_MAX_MISORDER) {
Pau Espin Pedrol3239f622019-04-24 18:47:46 +0200454 LOGPENDP(endp, DRTP, LOGL_NOTICE,
455 "RTP seqno made a very large jump on delta: %u\n",
456 udelta);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200457 }
458 }
459
Philipp Maier87bd9be2017-08-22 16:35:41 +0200460 /* Calculate the jitter between the two packages. The TS should be
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200461 * taken closer to the read function. This was taken from the
462 * Appendix A of RFC 3550. Timestamp and arrival_time have a 1/rate
Philipp Maier87bd9be2017-08-22 16:35:41 +0200463 * resolution. */
Harald Welte49e3d5a2017-12-25 09:47:57 +0100464 d = transit - state->stats.transit;
465 state->stats.transit = transit;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200466 if (d < 0)
467 d = -d;
Harald Welte49e3d5a2017-12-25 09:47:57 +0100468 state->stats.jitter += d - ((state->stats.jitter + 8) >> 4);
469 state->stats.max_seq = seq;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200470}
471
Philipp Maier6931f9a2018-07-26 09:29:31 +0200472/* There may be different payload type numbers negotiated for two connections.
473 * Patch the payload type of an RTP packet so that it uses the payload type
474 * that is valid for the destination connection (conn_dst) */
475static int mgcp_patch_pt(struct mgcp_conn_rtp *conn_src,
Neels Hofmeyr306dc092018-09-30 05:01:20 +0200476 struct mgcp_conn_rtp *conn_dst, struct msgb *msg)
Philipp Maier6931f9a2018-07-26 09:29:31 +0200477{
478 struct rtp_hdr *rtp_hdr;
479 uint8_t pt_in;
480 int pt_out;
481
Neels Hofmeyr306dc092018-09-30 05:01:20 +0200482 if (msg->len < sizeof(struct rtp_hdr)) {
483 LOG_CONN_RTP(conn_src, LOGL_ERROR, "RTP packet too short (%u < %zu)\n",
484 msg->len, sizeof(struct rtp_hdr));
Neels Hofmeyree784f92019-08-20 03:06:17 +0200485 return -EINVAL;
Neels Hofmeyr306dc092018-09-30 05:01:20 +0200486 }
Neels Hofmeyree784f92019-08-20 03:06:17 +0200487
Neels Hofmeyr306dc092018-09-30 05:01:20 +0200488 rtp_hdr = (struct rtp_hdr *)msg->data;
Philipp Maier6931f9a2018-07-26 09:29:31 +0200489
Neels Hofmeyr306dc092018-09-30 05:01:20 +0200490 if (conn_src->iuup) {
491 /* The source is an IuUP payload. We have received a dynamic payload type number on the IuUP side, and
492 * towards the pure RTP side it should go out as "AMR/8000". Make sure that the payload type number in
493 * the RTP packet matches the a=rtpmap:N payload type number configured for AMR. */
494 const struct mgcp_rtp_codec *amr_codec = mgcp_codec_pt_find_by_subtype_name(conn_dst, "AMR", 0);
495
496 if (!amr_codec) {
497 /* There is no AMR codec configured on the outgoing conn. */
498 return -EINVAL;
499 }
500
501 pt_out = amr_codec->payload_type;
502 } else if (conn_dst->iuup) {
503 /* The destination is an IuUP payload. Use whatever payload number was negotiated during IuUP
504 * Initialization. */
505 pt_out = conn_dst->iuup->rtp_payload_type;
506 } else {
507 /* Both sides are normal RTP payloads. Consult the rtpmap settings received by SDP. */
508 pt_in = rtp_hdr->payload_type;
509 pt_out = mgcp_codec_pt_translate(conn_src, conn_dst, pt_in);
510 if (pt_out < 0)
511 return -EINVAL;
512 }
Philipp Maier6931f9a2018-07-26 09:29:31 +0200513
514 rtp_hdr->payload_type = (uint8_t) pt_out;
515 return 0;
516}
517
Philipp Maier87bd9be2017-08-22 16:35:41 +0200518/* The RFC 3550 Appendix A assumes there are multiple sources but
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200519 * some of the supported endpoints (e.g. the nanoBTS) can only handle
520 * one source and this code will patch RTP header to appear as if there
521 * is only one source.
522 * There is also no probation period for new sources. Every RTP header
Philipp Maier87bd9be2017-08-22 16:35:41 +0200523 * we receive will be seen as a switch in streams. */
524void mgcp_patch_and_count(struct mgcp_endpoint *endp,
525 struct mgcp_rtp_state *state,
526 struct mgcp_rtp_end *rtp_end,
Neels Hofmeyr306dc092018-09-30 05:01:20 +0200527 struct sockaddr_in *addr, struct msgb *msg)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200528{
529 uint32_t arrival_time;
530 int32_t transit;
531 uint16_t seq;
532 uint32_t timestamp, ssrc;
533 struct rtp_hdr *rtp_hdr;
Philipp Maierbc0346e2018-06-07 09:52:16 +0200534 int payload = rtp_end->codec->payload_type;
Neels Hofmeyr306dc092018-09-30 05:01:20 +0200535 unsigned int len = msg->len;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200536
537 if (len < sizeof(*rtp_hdr))
538 return;
539
Neels Hofmeyr306dc092018-09-30 05:01:20 +0200540 rtp_hdr = (struct rtp_hdr *)msg->data;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200541 seq = ntohs(rtp_hdr->sequence);
542 timestamp = ntohl(rtp_hdr->timestamp);
Philipp Maierbc0346e2018-06-07 09:52:16 +0200543 arrival_time = get_current_ts(rtp_end->codec->rate);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200544 ssrc = ntohl(rtp_hdr->ssrc);
545 transit = arrival_time - timestamp;
546
547 mgcp_rtp_annex_count(endp, state, seq, transit, ssrc);
548
549 if (!state->initialized) {
550 state->initialized = 1;
551 state->in_stream.last_seq = seq - 1;
Harald Welte33381352017-12-25 09:44:26 +0100552 state->in_stream.ssrc = state->patch.orig_ssrc = ssrc;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200553 state->in_stream.last_tsdelta = 0;
Philipp Maier87bd9be2017-08-22 16:35:41 +0200554 state->packet_duration =
555 mgcp_rtp_packet_duration(endp, rtp_end);
Philipp Maier0ec1d4e2018-05-16 11:09:42 +0200556 state->out_stream.last_seq = seq - 1;
557 state->out_stream.ssrc = state->patch.orig_ssrc = ssrc;
558 state->out_stream.last_tsdelta = 0;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200559 state->out_stream.last_timestamp = timestamp;
Philipp Maier87bd9be2017-08-22 16:35:41 +0200560 state->out_stream.ssrc = ssrc - 1; /* force output SSRC change */
Pau Espin Pedrol3239f622019-04-24 18:47:46 +0200561 LOGPENDP(endp, DRTP, LOGL_INFO,
562 "initializing stream, SSRC: %u timestamp: %u "
563 "pkt-duration: %d, from %s:%d\n",
564 state->in_stream.ssrc,
565 state->patch.seq_offset, state->packet_duration,
566 inet_ntoa(addr->sin_addr), ntohs(addr->sin_port));
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200567 if (state->packet_duration == 0) {
Philipp Maier87bd9be2017-08-22 16:35:41 +0200568 state->packet_duration =
Philipp Maierbc0346e2018-06-07 09:52:16 +0200569 rtp_end->codec->rate * 20 / 1000;
Pau Espin Pedrol3239f622019-04-24 18:47:46 +0200570 LOGPENDP(endp, DRTP, LOGL_NOTICE,
571 "fixed packet duration is not available, "
572 "using fixed 20ms instead: %d from %s:%d\n",
573 state->packet_duration,
574 inet_ntoa(addr->sin_addr), ntohs(addr->sin_port));
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200575 }
576 } else if (state->in_stream.ssrc != ssrc) {
Pau Espin Pedrol3239f622019-04-24 18:47:46 +0200577 LOGPENDP(endp, DRTP, LOGL_NOTICE,
578 "SSRC changed: %u -> %u "
579 "from %s:%d\n",
580 state->in_stream.ssrc, rtp_hdr->ssrc,
581 inet_ntoa(addr->sin_addr), ntohs(addr->sin_port));
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200582
583 state->in_stream.ssrc = ssrc;
584 if (rtp_end->force_constant_ssrc) {
585 int16_t delta_seq;
586
587 /* Always increment seqno by 1 */
Harald Welte33381352017-12-25 09:44:26 +0100588 state->patch.seq_offset =
Philipp Maier87bd9be2017-08-22 16:35:41 +0200589 (state->out_stream.last_seq + 1) - seq;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200590
591 /* Estimate number of packets that would have been sent */
592 delta_seq =
Philipp Maier87bd9be2017-08-22 16:35:41 +0200593 (arrival_time - state->in_stream.last_arrival_time
594 + state->packet_duration / 2) /
595 state->packet_duration;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200596
597 adjust_rtp_timestamp_offset(endp, state, rtp_end, addr,
598 delta_seq, timestamp);
599
Harald Welte33381352017-12-25 09:44:26 +0100600 state->patch.patch_ssrc = 1;
601 ssrc = state->patch.orig_ssrc;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200602 if (rtp_end->force_constant_ssrc != -1)
603 rtp_end->force_constant_ssrc -= 1;
604
Pau Espin Pedrol3239f622019-04-24 18:47:46 +0200605 LOGPENDP(endp, DRTP, LOGL_NOTICE,
606 "SSRC patching enabled, SSRC: %u "
607 "SeqNo offset: %d, TS offset: %d "
608 "from %s:%d\n", state->in_stream.ssrc,
609 state->patch.seq_offset, state->patch.timestamp_offset,
610 inet_ntoa(addr->sin_addr), ntohs(addr->sin_port));
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200611 }
612
613 state->in_stream.last_tsdelta = 0;
614 } else {
615 /* Compute current per-packet timestamp delta */
Philipp Maier87bd9be2017-08-22 16:35:41 +0200616 check_rtp_timestamp(endp, state, &state->in_stream, rtp_end,
617 addr, seq, timestamp, "input",
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200618 &state->in_stream.last_tsdelta);
619
Harald Welte33381352017-12-25 09:44:26 +0100620 if (state->patch.patch_ssrc)
621 ssrc = state->patch.orig_ssrc;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200622 }
623
624 /* Save before patching */
625 state->in_stream.last_timestamp = timestamp;
626 state->in_stream.last_seq = seq;
627 state->in_stream.last_arrival_time = arrival_time;
628
629 if (rtp_end->force_aligned_timing &&
630 state->out_stream.ssrc == ssrc && state->packet_duration)
631 /* Align the timestamp offset */
Philipp Maier87bd9be2017-08-22 16:35:41 +0200632 align_rtp_timestamp_offset(endp, state, rtp_end, addr,
633 timestamp);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200634
635 /* Store the updated SSRC back to the packet */
Harald Welte33381352017-12-25 09:44:26 +0100636 if (state->patch.patch_ssrc)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200637 rtp_hdr->ssrc = htonl(ssrc);
638
639 /* Apply the offset and store it back to the packet.
640 * This won't change anything if the offset is 0, so the conditional is
641 * omitted. */
Harald Welte33381352017-12-25 09:44:26 +0100642 seq += state->patch.seq_offset;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200643 rtp_hdr->sequence = htons(seq);
Harald Welte33381352017-12-25 09:44:26 +0100644 timestamp += state->patch.timestamp_offset;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200645 rtp_hdr->timestamp = htonl(timestamp);
646
647 /* Check again, whether the timestamps are still valid */
648 if (state->out_stream.ssrc == ssrc)
649 check_rtp_timestamp(endp, state, &state->out_stream, rtp_end,
650 addr, seq, timestamp, "output",
651 &state->out_stream.last_tsdelta);
652
653 /* Save output values */
654 state->out_stream.last_seq = seq;
655 state->out_stream.last_timestamp = timestamp;
656 state->out_stream.ssrc = ssrc;
657
658 if (payload < 0)
659 return;
660
661#if 0
Philipp Maierc3413882017-10-27 12:26:54 +0200662 DEBUGP(DRTP,
Philipp Maier230e4fc2017-11-28 09:38:45 +0100663 "endpoint:0x%x payload hdr payload %u -> endp payload %u\n",
Philipp Maier87bd9be2017-08-22 16:35:41 +0200664 ENDPOINT_NUMBER(endp), rtp_hdr->payload_type, payload);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200665 rtp_hdr->payload_type = payload;
666#endif
667}
668
Philipp Maier9fc8a022019-02-20 12:26:52 +0100669/* There are different dialects used to format and transfer voice data. When
670 * the receiving end expects GSM-HR data to be formated after RFC 5993, this
671 * function is used to convert between RFC 5993 and TS 101318, which we normally
672 * use. */
Neels Hofmeyree784f92019-08-20 03:06:17 +0200673static int rfc5993_hr_convert(struct mgcp_endpoint *endp, char *data, int *len)
Philipp Maier9fc8a022019-02-20 12:26:52 +0100674{
675 /* NOTE: *data has an overall length of RTP_BUF_SIZE, so there is
676 * plenty of space available to store the slightly larger, converted
677 * data */
678
679 struct rtp_hdr *rtp_hdr;
680
Neels Hofmeyree784f92019-08-20 03:06:17 +0200681 if (*len < sizeof(struct rtp_hdr)) {
682 LOGPENDP(endp, DRTP, LOGL_ERROR, "AMR RTP packet too short (%d < %zu)\n",
683 *len, sizeof(struct rtp_hdr));
684 return -EINVAL;
685 }
686
Philipp Maier9fc8a022019-02-20 12:26:52 +0100687 rtp_hdr = (struct rtp_hdr *)data;
688
689 if (*len == GSM_HR_BYTES + sizeof(struct rtp_hdr)) {
690 /* TS 101318 encoding => RFC 5993 encoding */
691 memmove(rtp_hdr->data + 1, rtp_hdr->data, GSM_HR_BYTES);
692 rtp_hdr->data[0] = 0x00;
693 (*len) += 1;
694
695 } else if (*len == GSM_HR_BYTES + sizeof(struct rtp_hdr) + 1) {
696 /* RFC 5993 encoding => TS 101318 encoding */
697 memmove(rtp_hdr->data, rtp_hdr->data + 1, GSM_HR_BYTES);
698 (*len) -= 1;
699 } else {
700 /* It is possible that multiple payloads occur in one RTP
701 * packet. This is not supported yet. */
Pau Espin Pedrol3239f622019-04-24 18:47:46 +0200702 LOGPENDP(endp, DRTP, LOGL_ERROR,
703 "cannot figure out how to convert RTP packet\n");
Neels Hofmeyree784f92019-08-20 03:06:17 +0200704 return -ENOTSUP;
Philipp Maier9fc8a022019-02-20 12:26:52 +0100705 }
Neels Hofmeyree784f92019-08-20 03:06:17 +0200706 return 0;
Philipp Maier9fc8a022019-02-20 12:26:52 +0100707}
708
Philipp Maier228e5912019-03-05 13:56:59 +0100709/* For AMR RTP two framing modes are defined RFC3267. There is a bandwith
710 * efficient encoding scheme where all fields are packed together one after
711 * another and an octet aligned mode where all fields are aligned to octet
712 * boundaries. This function is used to convert between the two modes */
713static int amr_oa_bwe_convert(struct mgcp_endpoint *endp, char *data, int *len,
714 bool target_is_oa)
715{
716 /* NOTE: *data has an overall length of RTP_BUF_SIZE, so there is
717 * plenty of space available to store the slightly larger, converted
718 * data */
719
720 struct rtp_hdr *rtp_hdr;
721 unsigned int payload_len;
722 int rc;
723
Neels Hofmeyree784f92019-08-20 03:06:17 +0200724 if (*len < sizeof(struct rtp_hdr)) {
725 LOGPENDP(endp, DRTP, LOGL_ERROR, "AMR RTP packet too short (%d < %zu)\n", *len, sizeof(struct rtp_hdr));
726 return -EINVAL;
727 }
728
Philipp Maier228e5912019-03-05 13:56:59 +0100729 rtp_hdr = (struct rtp_hdr *)data;
730
731 payload_len = *len - sizeof(struct rtp_hdr);
732
733 if (osmo_amr_is_oa(rtp_hdr->data, payload_len)) {
734 if (!target_is_oa)
735 /* Input data is oa an target format is bwe
736 * ==> convert */
737 rc = osmo_amr_oa_to_bwe(rtp_hdr->data, payload_len);
738 else
739 /* Input data is already bew, but we accept it anyway
740 * ==> no conversion needed */
741 rc = payload_len;
742 } else {
743 if (target_is_oa)
744 /* Input data is bwe an target format is oa
745 * ==> convert */
746 rc = osmo_amr_bwe_to_oa(rtp_hdr->data, payload_len,
747 RTP_BUF_SIZE);
748 else
749 /* Input data is already oa, but we accept it anyway
750 * ==> no conversion needed */
751 rc = payload_len;
752 }
753 if (rc < 0) {
Pau Espin Pedrol3239f622019-04-24 18:47:46 +0200754 LOGPENDP(endp, DRTP, LOGL_ERROR,
755 "AMR RTP packet conversion failed\n");
Philipp Maier228e5912019-03-05 13:56:59 +0100756 return -EINVAL;
757 }
758
759 *len = rc + sizeof(struct rtp_hdr);
760
761 return 0;
762}
763
764/* Check if a conversion between octet-aligned and bandwith-efficient mode is
765 * indicated. */
766static bool amr_oa_bwe_convert_indicated(struct mgcp_rtp_codec *codec)
767{
768 if (codec->param_present == false)
769 return false;
770 if (!codec->param.amr_octet_aligned_present)
771 return false;
772 if (strcmp(codec->subtype_name, "AMR") != 0)
773 return false;
774 return true;
775}
776
777
778/* Check if a given RTP with AMR payload for octet-aligned mode */
Neels Hofmeyree784f92019-08-20 03:06:17 +0200779static int amr_oa_check(char *data, int len)
Philipp Maier228e5912019-03-05 13:56:59 +0100780{
781 struct rtp_hdr *rtp_hdr;
782 unsigned int payload_len;
783
Neels Hofmeyree784f92019-08-20 03:06:17 +0200784 if (len < sizeof(struct rtp_hdr))
785 return -EINVAL;
786
Philipp Maier228e5912019-03-05 13:56:59 +0100787 rtp_hdr = (struct rtp_hdr *)data;
788
789 payload_len = len - sizeof(struct rtp_hdr);
Neels Hofmeyree784f92019-08-20 03:06:17 +0200790 if (payload_len < sizeof(struct amr_hdr))
791 return -EINVAL;
Philipp Maier228e5912019-03-05 13:56:59 +0100792
Neels Hofmeyree784f92019-08-20 03:06:17 +0200793 return osmo_amr_is_oa(rtp_hdr->data, payload_len) ? 1 : 0;
Philipp Maier228e5912019-03-05 13:56:59 +0100794}
795
Philipp Maier87bd9be2017-08-22 16:35:41 +0200796/* Forward data to a debug tap. This is debug function that is intended for
797 * debugging the voice traffic with tools like gstreamer */
Neels Hofmeyr306dc092018-09-30 05:01:20 +0200798static void forward_data(int fd, struct mgcp_rtp_tap *tap, struct msgb *msg)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200799{
Philipp Maiere6f172d2017-11-07 12:00:01 +0100800 int rc;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200801
Philipp Maiere6f172d2017-11-07 12:00:01 +0100802 if (!tap->enabled)
803 return;
804
Neels Hofmeyr306dc092018-09-30 05:01:20 +0200805 rc = sendto(fd, msg->data, msg->len, 0, (struct sockaddr *)&tap->forward,
Philipp Maiere6f172d2017-11-07 12:00:01 +0100806 sizeof(tap->forward));
807
808 if (rc < 0)
809 LOGP(DRTP, LOGL_ERROR,
810 "Forwarding tapped (debug) voice data failed.\n");
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200811}
812
Philipp Maier87bd9be2017-08-22 16:35:41 +0200813/*! Send RTP/RTCP data to a specified destination connection.
814 * \param[in] endp associated endpoint (for configuration, logging)
815 * \param[in] is_rtp flag to specify if the packet is of type RTP or RTCP
816 * \param[in] spoofed source address (set to NULL to disable)
817 * \param[in] buf buffer that contains the RTP/RTCP data
818 * \param[in] len length of the buffer that contains the RTP/RTCP data
819 * \param[in] conn_src associated source connection
820 * \param[in] conn_dst associated destination connection
821 * \returns 0 on success, -1 on ERROR */
822int mgcp_send(struct mgcp_endpoint *endp, int is_rtp, struct sockaddr_in *addr,
Neels Hofmeyr306dc092018-09-30 05:01:20 +0200823 struct msgb *msg, struct mgcp_conn_rtp *conn_src,
Philipp Maier87bd9be2017-08-22 16:35:41 +0200824 struct mgcp_conn_rtp *conn_dst)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200825{
Philipp Maier87bd9be2017-08-22 16:35:41 +0200826 /*! When no destination connection is available (e.g. when only one
827 * connection in loopback mode exists), then the source connection
828 * shall be specified as destination connection */
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200829
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200830 struct mgcp_trunk_config *tcfg = endp->tcfg;
831 struct mgcp_rtp_end *rtp_end;
832 struct mgcp_rtp_state *rtp_state;
Philipp Maier87bd9be2017-08-22 16:35:41 +0200833 char *dest_name;
Philipp Maier6931f9a2018-07-26 09:29:31 +0200834 int rc;
Neels Hofmeyr306dc092018-09-30 05:01:20 +0200835 int len;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200836
Philipp Maier87bd9be2017-08-22 16:35:41 +0200837 OSMO_ASSERT(conn_src);
838 OSMO_ASSERT(conn_dst);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200839
Philipp Maier87bd9be2017-08-22 16:35:41 +0200840 if (is_rtp) {
Pau Espin Pedrol3239f622019-04-24 18:47:46 +0200841 LOGPENDP(endp, DRTP, LOGL_DEBUG, "delivering RTP packet...\n");
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200842 } else {
Pau Espin Pedrol3239f622019-04-24 18:47:46 +0200843 LOGPENDP(endp, DRTP, LOGL_DEBUG, "delivering RTCP packet...\n");
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200844 }
Philipp Maier87bd9be2017-08-22 16:35:41 +0200845
Pau Espin Pedrol3239f622019-04-24 18:47:46 +0200846 LOGPENDP(endp, DRTP, LOGL_DEBUG, "loop:%d, mode:%d%s\n",
847 tcfg->audio_loop, conn_src->conn->mode,
848 conn_src->conn->mode == MGCP_CONN_LOOPBACK ? " (loopback)" : "");
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200849
Philipp Maier6931f9a2018-07-26 09:29:31 +0200850 /* FIXME: It is legal that the payload type on the egress connection is
851 * different from the payload type that has been negotiated on the
852 * ingress connection. Essentially the codecs are the same so we can
853 * match them and patch the payload type. However, if we can not find
854 * the codec pendant (everything ist equal except the PT), we are of
855 * course unable to patch the payload type. A situation like this
856 * should not occur if transcoding is consequently avoided. Until
857 * we have transcoding support in osmo-mgw we can not resolve this. */
Philipp Maierda895b12018-08-03 12:16:37 +0200858 if (is_rtp) {
Neels Hofmeyr306dc092018-09-30 05:01:20 +0200859 rc = mgcp_patch_pt(conn_src, conn_dst, msg);
Philipp Maierda895b12018-08-03 12:16:37 +0200860 if (rc < 0) {
Pau Espin Pedrol3239f622019-04-24 18:47:46 +0200861 LOGPENDP(endp, DRTP, LOGL_DEBUG,
862 "can not patch PT because no suitable egress codec was found.\n");
Philipp Maierda895b12018-08-03 12:16:37 +0200863 }
Philipp Maier6931f9a2018-07-26 09:29:31 +0200864 }
865
Philipp Maier87bd9be2017-08-22 16:35:41 +0200866 /* Note: In case of loopback configuration, both, the source and the
867 * destination will point to the same connection. */
868 rtp_end = &conn_dst->end;
869 rtp_state = &conn_src->state;
870 dest_name = conn_dst->conn->name;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200871
872 if (!rtp_end->output_enabled) {
Philipp Maiercede2a42018-07-03 14:14:21 +0200873 rate_ctr_inc(&conn_dst->rate_ctr_group->ctr[RTP_DROPPED_PACKETS_CTR]);
Pau Espin Pedrol3239f622019-04-24 18:47:46 +0200874 LOGPENDP(endp, DRTP, LOGL_DEBUG,
875 "output disabled, drop to %s %s "
876 "rtp_port:%u rtcp_port:%u\n",
877 dest_name,
878 inet_ntoa(rtp_end->addr),
879 ntohs(rtp_end->rtp_port), ntohs(rtp_end->rtcp_port)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200880 );
881 } else if (is_rtp) {
882 int cont;
883 int nbytes = 0;
Neels Hofmeyr306dc092018-09-30 05:01:20 +0200884 int buflen = msg->len;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200885 do {
Philipp Maier87bd9be2017-08-22 16:35:41 +0200886 /* Run transcoder */
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200887 cont = endp->cfg->rtp_processing_cb(endp, rtp_end,
Neels Hofmeyr306dc092018-09-30 05:01:20 +0200888 (char*)msg->data, &buflen,
Philipp Maier87bd9be2017-08-22 16:35:41 +0200889 RTP_BUF_SIZE);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200890 if (cont < 0)
891 break;
892
Philipp Maier87bd9be2017-08-22 16:35:41 +0200893 if (addr)
894 mgcp_patch_and_count(endp, rtp_state, rtp_end,
Neels Hofmeyr306dc092018-09-30 05:01:20 +0200895 addr, msg);
Philipp Maier9fc8a022019-02-20 12:26:52 +0100896
Philipp Maier228e5912019-03-05 13:56:59 +0100897 if (amr_oa_bwe_convert_indicated(conn_dst->end.codec)) {
Neels Hofmeyr306dc092018-09-30 05:01:20 +0200898 rc = amr_oa_bwe_convert(endp, (char*)msg->data, &buflen,
Neels Hofmeyr536dff12019-08-20 03:09:04 +0200899 conn_dst->end.codec->param.amr_octet_aligned);
900 if (rc < 0) {
901 LOGPENDP(endp, DRTP, LOGL_ERROR,
902 "Error in AMR octet-aligned <-> bandwidth-efficient mode conversion\n");
903 break;
904 }
Philipp Maier228e5912019-03-05 13:56:59 +0100905 }
906 else if (rtp_end->rfc5993_hr_convert
Philipp Maier9fc8a022019-02-20 12:26:52 +0100907 && strcmp(conn_src->end.codec->subtype_name,
Neels Hofmeyr536dff12019-08-20 03:09:04 +0200908 "GSM-HR-08") == 0) {
Neels Hofmeyr306dc092018-09-30 05:01:20 +0200909 rc = rfc5993_hr_convert(endp, (char*)msg->data, &buflen);
Neels Hofmeyr536dff12019-08-20 03:09:04 +0200910 if (rc < 0) {
911 LOGPENDP(endp, DRTP, LOGL_ERROR, "Error while converting to GSM-HR-08\n");
912 break;
913 }
914 }
Philipp Maier9fc8a022019-02-20 12:26:52 +0100915
Pau Espin Pedrol3239f622019-04-24 18:47:46 +0200916 LOGPENDP(endp, DRTP, LOGL_DEBUG,
917 "process/send to %s %s "
918 "rtp_port:%u rtcp_port:%u\n",
919 dest_name, inet_ntoa(rtp_end->addr),
920 ntohs(rtp_end->rtp_port), ntohs(rtp_end->rtcp_port)
921 );
Philipp Maier87bd9be2017-08-22 16:35:41 +0200922
923 /* Forward a copy of the RTP data to a debug ip/port */
924 forward_data(rtp_end->rtp.fd, &conn_src->tap_out,
Neels Hofmeyr306dc092018-09-30 05:01:20 +0200925 msg);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200926
Neels Hofmeyr306dc092018-09-30 05:01:20 +0200927#if 0
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200928 /* FIXME: HACK HACK HACK. See OS#2459.
929 * The ip.access nano3G needs the first RTP payload's first two bytes to read hex
930 * 'e400', or it will reject the RAB assignment. It seems to not harm other femto
931 * cells (as long as we patch only the first RTP payload in each stream).
932 */
Neels Hofmeyr35a38292018-07-23 18:29:04 +0200933 if (!rtp_state->patched_first_rtp_payload
934 && conn_src->conn->mode == MGCP_CONN_LOOPBACK) {
Neels Hofmeyr306dc092018-09-30 05:01:20 +0200935 uint8_t *data = msg->data + 12;
Neels Hofmeyr35a38292018-07-23 18:29:04 +0200936 if (data[0] == 0xe0) {
937 data[0] = 0xe4;
938 data[1] = 0x00;
939 rtp_state->patched_first_rtp_payload = true;
Pau Espin Pedrol3239f622019-04-24 18:47:46 +0200940 LOGPENDP(endp, DRTP, LOGL_DEBUG,
941 "Patching over first two bytes"
942 " to fake an IuUP Initialization Ack\n");
Neels Hofmeyr35a38292018-07-23 18:29:04 +0200943 }
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200944 }
Neels Hofmeyr306dc092018-09-30 05:01:20 +0200945#endif
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200946
Neels Hofmeyr306dc092018-09-30 05:01:20 +0200947 if (conn_dst->iuup)
948 len = osmo_iuup_cn_tx_payload(conn_dst->iuup, msg);
949 else
950 len = mgcp_udp_send(rtp_end->rtp.fd, &rtp_end->addr, rtp_end->rtp_port,
951 (char*)msg->data, msg->len);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200952
Philipp Maier87bd9be2017-08-22 16:35:41 +0200953 if (len <= 0)
954 return len;
955
Philipp Maiercede2a42018-07-03 14:14:21 +0200956 rate_ctr_inc(&conn_dst->rate_ctr_group->ctr[RTP_PACKETS_TX_CTR]);
957 rate_ctr_add(&conn_dst->rate_ctr_group->ctr[RTP_OCTETS_TX_CTR], len);
Philipp Maier87bd9be2017-08-22 16:35:41 +0200958
959 nbytes += len;
960 buflen = cont;
961 } while (buflen > 0);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200962 return nbytes;
963 } else if (!tcfg->omit_rtcp) {
Pau Espin Pedrol3239f622019-04-24 18:47:46 +0200964 LOGPENDP(endp, DRTP, LOGL_DEBUG,
965 "send to %s %s rtp_port:%u rtcp_port:%u\n",
966 dest_name, inet_ntoa(rtp_end->addr),
967 ntohs(rtp_end->rtp_port), ntohs(rtp_end->rtcp_port)
968 );
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200969
Philipp Maier87bd9be2017-08-22 16:35:41 +0200970 len = mgcp_udp_send(rtp_end->rtcp.fd,
971 &rtp_end->addr,
Neels Hofmeyr306dc092018-09-30 05:01:20 +0200972 rtp_end->rtcp_port, (char*)msg->data, msg->len);
Philipp Maier87bd9be2017-08-22 16:35:41 +0200973
Philipp Maiercede2a42018-07-03 14:14:21 +0200974 rate_ctr_inc(&conn_dst->rate_ctr_group->ctr[RTP_PACKETS_TX_CTR]);
975 rate_ctr_add(&conn_dst->rate_ctr_group->ctr[RTP_OCTETS_TX_CTR], len);
Philipp Maier87bd9be2017-08-22 16:35:41 +0200976
977 return len;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200978 }
979
980 return 0;
981}
982
Philipp Maier87bd9be2017-08-22 16:35:41 +0200983/* Check if the origin (addr) matches the address/port data of the RTP
984 * connections. */
985static int check_rtp_origin(struct mgcp_conn_rtp *conn,
986 struct sockaddr_in *addr)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200987{
Harald Weltec26b6652018-10-21 12:01:04 +0200988 if (conn->end.addr.s_addr == 0) {
Neels Hofmeyrefd645e2018-09-10 13:14:50 +0200989 switch (conn->conn->mode) {
990 case MGCP_CONN_LOOPBACK:
991 /* HACK: for IuUP, we want to reply with an IuUP Initialization ACK upon the first RTP
992 * message received. We currently hackishly accomplish that by putting the endpoint in
993 * loopback mode and patching over the looped back RTP message to make it look like an
994 * ack. We don't know the femto cell's IP address and port until the RAB Assignment
995 * Response is received, but the nano3G expects an IuUP Initialization Ack before it even
996 * sends the RAB Assignment Response. Hence, if the remote address is 0.0.0.0 and the
997 * MGCP port is in loopback mode, allow looping back the packet to any source. */
Pau Espin Pedrol3239f622019-04-24 18:47:46 +0200998 LOGPCONN(conn->conn, DRTP, LOGL_ERROR,
999 "In loopback mode and remote address not set:"
1000 " allowing data from address: %s\n", inet_ntoa(addr->sin_addr));
Neels Hofmeyrefd645e2018-09-10 13:14:50 +02001001 return 0;
1002
1003 default:
1004 /* Receiving early media before the endpoint is configured. Instead of logging
1005 * this as an error that occurs on every call, keep it more low profile to not
1006 * confuse humans with expected errors. */
Pau Espin Pedrol3239f622019-04-24 18:47:46 +02001007 LOGPCONN(conn->conn, DRTP, LOGL_INFO,
1008 "Rx RTP from %s, but remote address not set:"
1009 " dropping early media\n", inet_ntoa(addr->sin_addr));
Neels Hofmeyrefd645e2018-09-10 13:14:50 +02001010 return -1;
1011 }
Neels Hofmeyr0063ca22018-07-23 18:12:16 +02001012 }
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001013
Philipp Maier87bd9be2017-08-22 16:35:41 +02001014 /* Note: Check if the inbound RTP data comes from the same host to
1015 * which we send our outgoing RTP traffic. */
Harald Weltec26b6652018-10-21 12:01:04 +02001016 if (conn->end.addr.s_addr != addr->sin_addr.s_addr) {
Pau Espin Pedrol3239f622019-04-24 18:47:46 +02001017 LOGPCONN(conn->conn, DRTP, LOGL_ERROR,
1018 "data from wrong address: %s, ", inet_ntoa(addr->sin_addr));
Philipp Maierc3413882017-10-27 12:26:54 +02001019 LOGPC(DRTP, LOGL_ERROR, "expected: %s\n",
Philipp Maier87bd9be2017-08-22 16:35:41 +02001020 inet_ntoa(conn->end.addr));
Pau Espin Pedrol3239f622019-04-24 18:47:46 +02001021 LOGPCONN(conn->conn, DRTP, LOGL_ERROR, "packet tossed\n");
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001022 return -1;
1023 }
1024
Philipp Maier87bd9be2017-08-22 16:35:41 +02001025 /* Note: Usually the remote remote port of the data we receive will be
1026 * the same as the remote port where we transmit outgoing RTP traffic
1027 * to (set by MDCX). We use this to check the origin of the data for
1028 * plausibility. */
1029 if (conn->end.rtp_port != addr->sin_port &&
1030 conn->end.rtcp_port != addr->sin_port) {
Pau Espin Pedrol3239f622019-04-24 18:47:46 +02001031 LOGPCONN(conn->conn, DRTP, LOGL_ERROR,
1032 "data from wrong source port: %d, ", ntohs(addr->sin_port));
Philipp Maierc3413882017-10-27 12:26:54 +02001033 LOGPC(DRTP, LOGL_ERROR,
Philipp Maier87bd9be2017-08-22 16:35:41 +02001034 "expected: %d for RTP or %d for RTCP\n",
1035 ntohs(conn->end.rtp_port), ntohs(conn->end.rtcp_port));
Pau Espin Pedrol3239f622019-04-24 18:47:46 +02001036 LOGPCONN(conn->conn, DRTP, LOGL_ERROR, "packet tossed\n");
Philipp Maier87bd9be2017-08-22 16:35:41 +02001037 return -1;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001038 }
1039
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001040 return 0;
1041}
1042
Philipp Maier87bd9be2017-08-22 16:35:41 +02001043/* Check the if the destination address configuration of an RTP connection
1044 * makes sense */
1045static int check_rtp_destin(struct mgcp_conn_rtp *conn)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001046{
Philipp Maiere6df0e42018-05-29 14:03:06 +02001047 /* Note: it is legal to create a connection but never setting a port
1048 * and IP-address for outgoing data. */
1049 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 +02001050 LOGPCONN(conn->conn, DRTP, LOGL_DEBUG,
1051 "destination IP-address and rtp port is (not yet) known (%s:%u)\n",
1052 inet_ntoa(conn->end.addr), conn->end.rtp_port);
Philipp Maiere6df0e42018-05-29 14:03:06 +02001053 return -1;
1054 }
1055
Philipp Maier87bd9be2017-08-22 16:35:41 +02001056 if (strcmp(inet_ntoa(conn->end.addr), "0.0.0.0") == 0) {
Pau Espin Pedrol3239f622019-04-24 18:47:46 +02001057 LOGPCONN(conn->conn, DRTP, LOGL_ERROR,
1058 "destination IP-address is invalid (%s:%u)\n",
1059 inet_ntoa(conn->end.addr), conn->end.rtp_port);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001060 return -1;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001061 }
Philipp Maier87bd9be2017-08-22 16:35:41 +02001062
1063 if (conn->end.rtp_port == 0) {
Pau Espin Pedrol3239f622019-04-24 18:47:46 +02001064 LOGPCONN(conn->conn, DRTP, LOGL_ERROR,
1065 "destination rtp port is invalid (%s:%u)\n",
1066 inet_ntoa(conn->end.addr), conn->end.rtp_port);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001067 return -1;
1068 }
1069
1070 return 0;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001071}
1072
Philipp Maier4dba7692018-08-03 12:20:52 +02001073/* Do some basic checks to make sure that the RTCP packets we are going to
1074 * process are not complete garbage */
Neels Hofmeyr306dc092018-09-30 05:01:20 +02001075static int check_rtcp(struct mgcp_conn_rtp *conn_src, struct msgb *msg)
Philipp Maier4dba7692018-08-03 12:20:52 +02001076{
1077 struct rtcp_hdr *hdr;
1078 unsigned int len;
1079 uint8_t type;
1080
1081 /* RTPC packets that are just a header without data do not make
1082 * any sense. */
Neels Hofmeyr306dc092018-09-30 05:01:20 +02001083 if (msg->len < sizeof(struct rtcp_hdr)) {
1084 LOG_CONN_RTP(conn_src, LOGL_ERROR, "RTCP packet too short (%u < %zu)\n",
1085 msg->len, sizeof(struct rtcp_hdr));
Philipp Maier4dba7692018-08-03 12:20:52 +02001086 return -EINVAL;
Neels Hofmeyr306dc092018-09-30 05:01:20 +02001087 }
Philipp Maier4dba7692018-08-03 12:20:52 +02001088
1089 /* Make sure that the length of the received packet does not exceed
1090 * the available buffer size */
Neels Hofmeyr306dc092018-09-30 05:01:20 +02001091 hdr = (struct rtcp_hdr *)msg->data;
Philipp Maier4dba7692018-08-03 12:20:52 +02001092 len = (osmo_ntohs(hdr->length) + 1) * 4;
Neels Hofmeyr306dc092018-09-30 05:01:20 +02001093 if (len > msg->len) {
1094 LOG_CONN_RTP(conn_src, LOGL_ERROR, "RTCP header length exceeds packet size (%u > %u)\n",
1095 len, msg->len);
Philipp Maier4dba7692018-08-03 12:20:52 +02001096 return -EINVAL;
Neels Hofmeyr306dc092018-09-30 05:01:20 +02001097 }
Philipp Maier4dba7692018-08-03 12:20:52 +02001098
1099 /* Make sure we accept only packets that have a proper packet type set
1100 * See also: http://www.iana.org/assignments/rtp-parameters/rtp-parameters.xhtml */
1101 type = hdr->type;
Neels Hofmeyr306dc092018-09-30 05:01:20 +02001102 if ((type < 192 || type > 195) && (type < 200 || type > 213)) {
1103 LOG_CONN_RTP(conn_src, LOGL_ERROR, "RTCP header: invalid type: %u\n", type);
Philipp Maier4dba7692018-08-03 12:20:52 +02001104 return -EINVAL;
Neels Hofmeyr306dc092018-09-30 05:01:20 +02001105 }
Philipp Maier4dba7692018-08-03 12:20:52 +02001106
1107 return 0;
1108}
1109
1110/* Do some basic checks to make sure that the RTP packets we are going to
1111 * process are not complete garbage */
Neels Hofmeyr306dc092018-09-30 05:01:20 +02001112static int check_rtp(struct mgcp_conn_rtp *conn_src, struct msgb *msg)
Philipp Maier4dba7692018-08-03 12:20:52 +02001113{
Neels Hofmeyr306dc092018-09-30 05:01:20 +02001114 size_t min_size = sizeof(struct rtp_hdr);
1115 if (conn_src->iuup)
1116 min_size += sizeof(struct osmo_iuup_hdr_data);
1117 if (msg->len < min_size) {
1118 LOG_CONN_RTP(conn_src, LOGL_ERROR, "RTP packet too short (%u < %zu)\n",
1119 msg->len, min_size);
1120 return -1;
1121 }
Philipp Maier4dba7692018-08-03 12:20:52 +02001122
1123 /* FIXME: Add more checks, the reason why we do not check more than
1124 * the length is because we currently handle IUUP packets as RTP
1125 * packets, so they must pass this check, if we weould be more
1126 * strict here, we would possibly break 3G. (see also FIXME note
1127 * below */
1128
1129 return 0;
1130}
1131
Philipp Maier87bd9be2017-08-22 16:35:41 +02001132/* Send RTP data. Possible options are standard RTP packet
1133 * transmission or trsmission via an osmux connection */
Neels Hofmeyr306dc092018-09-30 05:01:20 +02001134static int mgcp_send_rtp(struct mgcp_conn_rtp *conn_dst, struct msgb *msg)
Philipp Maier87bd9be2017-08-22 16:35:41 +02001135{
Neels Hofmeyr306dc092018-09-30 05:01:20 +02001136 enum rtp_proto proto = OSMO_RTP_MSG_CTX(msg)->proto;
1137 struct mgcp_conn_rtp *conn_src = OSMO_RTP_MSG_CTX(msg)->conn_src;
1138 struct sockaddr_in *from_addr = OSMO_RTP_MSG_CTX(msg)->from_addr;
1139 struct mgcp_endpoint *endp = conn_src->conn->endp;
Philipp Maier87bd9be2017-08-22 16:35:41 +02001140
Pau Espin Pedrol3239f622019-04-24 18:47:46 +02001141 LOGPENDP(endp, DRTP, LOGL_DEBUG, "destin conn:%s\n",
1142 mgcp_conn_dump(conn_dst->conn));
Philipp Maier87bd9be2017-08-22 16:35:41 +02001143
1144 /* Before we try to deliver the packet, we check if the destination
1145 * port and IP-Address make sense at all. If not, we will be unable
1146 * to deliver the packet. */
1147 if (check_rtp_destin(conn_dst) != 0)
1148 return -1;
1149
1150 /* Depending on the RTP connection type, deliver the RTP packet to the
1151 * destination connection. */
1152 switch (conn_dst->type) {
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001153 case MGCP_RTP_DEFAULT:
Pau Espin Pedrol3239f622019-04-24 18:47:46 +02001154 LOGPENDP(endp, DRTP, LOGL_DEBUG,
1155 "endpoint type is MGCP_RTP_DEFAULT, "
1156 "using mgcp_send() to forward data directly\n");
Philipp Maier87bd9be2017-08-22 16:35:41 +02001157 return mgcp_send(endp, proto == MGCP_PROTO_RTP,
Neels Hofmeyr306dc092018-09-30 05:01:20 +02001158 from_addr, msg, conn_src, conn_dst);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001159 case MGCP_OSMUX_BSC_NAT:
Philipp Maier87bd9be2017-08-22 16:35:41 +02001160 case MGCP_OSMUX_BSC:
Pau Espin Pedrol3239f622019-04-24 18:47:46 +02001161 LOGPENDP(endp, DRTP, LOGL_DEBUG,
1162 "endpoint type is MGCP_OSMUX_BSC_NAT, "
1163 "using osmux_xfrm_to_osmux() to forward data through OSMUX\n");
Neels Hofmeyr306dc092018-09-30 05:01:20 +02001164 return osmux_xfrm_to_osmux((char*)msg->data, msg->len, conn_dst);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001165 }
1166
Philipp Maier87bd9be2017-08-22 16:35:41 +02001167 /* If the data has not been handled/forwarded until here, it will
1168 * be discarded, this should not happen, normally the MGCP type
1169 * should be properly set */
Pau Espin Pedrol3239f622019-04-24 18:47:46 +02001170 LOGPENDP(endp, DRTP, LOGL_ERROR, "bad MGCP type -- data discarded!\n");
Philipp Maier87bd9be2017-08-22 16:35:41 +02001171
1172 return -1;
1173}
1174
1175/*! dispatch incoming RTP packet to opposite RTP connection.
1176 * \param[in] proto protocol (MGCP_CONN_TYPE_RTP or MGCP_CONN_TYPE_RTCP)
1177 * \param[in] addr socket address where the RTP packet has been received from
1178 * \param[in] buf buffer that hold the RTP payload
1179 * \param[in] buf_size size data length of buf
1180 * \param[in] conn originating connection
1181 * \returns 0 on success, -1 on ERROR */
Neels Hofmeyr306dc092018-09-30 05:01:20 +02001182int mgcp_dispatch_rtp_bridge_cb(struct msgb *msg)
Philipp Maier87bd9be2017-08-22 16:35:41 +02001183{
Neels Hofmeyr306dc092018-09-30 05:01:20 +02001184 struct mgcp_conn_rtp *conn_src = OSMO_RTP_MSG_CTX(msg)->conn_src;
1185 struct mgcp_conn *conn = conn_src->conn;
Philipp Maier87bd9be2017-08-22 16:35:41 +02001186 struct mgcp_conn *conn_dst;
Neels Hofmeyr306dc092018-09-30 05:01:20 +02001187 struct sockaddr_in *from_addr = OSMO_RTP_MSG_CTX(msg)->from_addr;
Philipp Maier87bd9be2017-08-22 16:35:41 +02001188
1189 /*! NOTE: This callback function implements the endpoint specific
1190 * dispatch bahviour of an rtp bridge/proxy endpoint. It is assumed
1191 * that the endpoint will hold only two connections. This premise
1192 * is used to determine the opposite connection (it is always the
1193 * connection that is not the originating connection). Once the
1194 * destination connection is known the RTP packet is sent via
1195 * the destination connection. */
1196
Pau Espin Pedrol9aaaab62019-05-15 23:23:27 +02001197
1198 /* Check if the connection is in loopback mode, if yes, just send the
1199 * incoming data back to the origin */
1200 if (conn->mode == MGCP_CONN_LOOPBACK) {
1201 /* When we are in loopback mode, we loop back all incoming
1202 * packets back to their origin. We will use the originating
1203 * address data from the UDP packet header to patch the
1204 * outgoing address in connection on the fly */
1205 if (conn->u.rtp.end.rtp_port == 0) {
Neels Hofmeyr306dc092018-09-30 05:01:20 +02001206 conn->u.rtp.end.addr = from_addr->sin_addr;
1207 conn->u.rtp.end.rtp_port = from_addr->sin_port;
Pau Espin Pedrol9aaaab62019-05-15 23:23:27 +02001208 }
Neels Hofmeyr306dc092018-09-30 05:01:20 +02001209 return mgcp_send_rtp(conn_src, msg);
Pau Espin Pedrol9aaaab62019-05-15 23:23:27 +02001210 }
1211
Philipp Maier87bd9be2017-08-22 16:35:41 +02001212 /* Find a destination connection. */
1213 /* NOTE: This code path runs every time an RTP packet is received. The
1214 * function mgcp_find_dst_conn() we use to determine the detination
1215 * connection will iterate the connection list inside the endpoint.
1216 * Since list iterations are quite costly, we will figure out the
1217 * destination only once and use the optional private data pointer of
1218 * the connection to cache the destination connection pointer. */
1219 if (!conn->priv) {
1220 conn_dst = mgcp_find_dst_conn(conn);
1221 conn->priv = conn_dst;
1222 } else {
1223 conn_dst = (struct mgcp_conn *)conn->priv;
1224 }
1225
1226 /* There is no destination conn, stop here */
1227 if (!conn_dst) {
Pau Espin Pedrol3239f622019-04-24 18:47:46 +02001228 LOGPCONN(conn, DRTP, LOGL_ERROR,
1229 "unable to find destination conn\n");
Philipp Maier87bd9be2017-08-22 16:35:41 +02001230 return -1;
1231 }
1232
1233 /* The destination conn is not an RTP connection */
1234 if (conn_dst->type != MGCP_CONN_TYPE_RTP) {
Pau Espin Pedrol3239f622019-04-24 18:47:46 +02001235 LOGPCONN(conn, DRTP, LOGL_ERROR,
1236 "unable to find suitable destination conn\n");
Philipp Maier87bd9be2017-08-22 16:35:41 +02001237 return -1;
1238 }
1239
1240 /* Dispatch RTP packet to destination RTP connection */
Neels Hofmeyr306dc092018-09-30 05:01:20 +02001241 return mgcp_send_rtp(&conn_dst->u.rtp, msg);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001242}
1243
Philipp Maierdf5d2192018-01-24 11:39:32 +01001244/*! cleanup an endpoint when a connection on an RTP bridge endpoint is removed.
1245 * \param[in] endp Endpoint on which the connection resides.
1246 * \param[in] conn Connection that is about to be removed (ignored).
1247 * \returns 0 on success, -1 on ERROR. */
1248void mgcp_cleanup_rtp_bridge_cb(struct mgcp_endpoint *endp, struct mgcp_conn *conn)
1249{
1250 struct mgcp_conn *conn_cleanup;
1251
1252 /* In mgcp_dispatch_rtp_bridge_cb() we use conn->priv to cache the
1253 * pointer to the destination connection, so that we do not have
1254 * to go through the list every time an RTP packet arrives. To prevent
1255 * a use-after-free situation we invalidate this information for all
1256 * connections present when one connection is removed from the
1257 * endpoint. */
1258 llist_for_each_entry(conn_cleanup, &endp->conns, entry) {
1259 conn_cleanup->priv = NULL;
1260 }
1261}
1262
Neels Hofmeyr306dc092018-09-30 05:01:20 +02001263static bool is_dummy_msg(enum rtp_proto proto, struct msgb *msg)
1264{
1265 return msg->len == 1 && msg->data[0] == MGCP_DUMMY_LOAD;
1266}
1267
1268struct pdu_ctx {
1269 struct sockaddr_in *from_addr;
1270 struct mgcp_conn_rtp *conn_src;
1271};
1272
1273/* IuUP CN node has stripped an IuUP header and forwards RTP data to distribute to the peers. */
1274int iuup_rx_payload(struct msgb *msg, void *node_priv)
1275{
1276 struct mgcp_conn_rtp *conn_src = OSMO_RTP_MSG_CTX(msg)->conn_src;
1277 LOG_CONN_RTP(conn_src, LOGL_DEBUG, "iuup_rx_payload(%u bytes)\n", msg->len);
1278 return rx_rtp(msg);
1279}
1280
1281/* IuUP CN node has composed a message that contains an IuUP header and asks us to send to the IuUP peer.
1282 */
1283int iuup_tx_msg(struct msgb *msg, void *node_priv)
1284{
1285 const struct in_addr zero_addr = {};
1286 struct mgcp_conn_rtp *conn_src = OSMO_RTP_MSG_CTX(msg)->conn_src;
1287 struct mgcp_conn_rtp *conn_dst = node_priv;
1288 struct sockaddr_in *from_addr = OSMO_RTP_MSG_CTX(msg)->from_addr;
1289 struct mgcp_rtp_end *rtp_end = &conn_dst->end;
1290 struct in_addr to_addr = rtp_end->addr;
1291 uint16_t to_port = rtp_end->rtp_port;
1292
1293 if (conn_src == conn_dst
1294 && !memcmp(&zero_addr, &to_addr, sizeof(zero_addr)) && !to_port) {
1295 LOG_CONN_RTP(conn_dst, LOGL_DEBUG, "iuup_tx_msg(): direct IuUP reply\n");
1296 /* IuUP wants to send a message back to the same peer that sent an RTP package, but there
1297 * is no address configured for that peer yet. It is probably an IuUP Initialization ACK
1298 * reply. Use the sender address to send the reply.
1299 *
1300 * During 3G RAB Assignment, a 3G cell might first probe the MGW and expect an IuUP
1301 * Initialization ACK before it replies to the MSC with a successful RAB Assignment; only
1302 * after that reply does MSC officially know which RTP address+port the 3G cell wants to
1303 * use and can tell this MGW about it, so this "loopback" is, for some 3G cells, the only
1304 * chance we have to get a successful RAB Assignment done (particularly the nano3G does
1305 * this). */
1306 to_addr = from_addr->sin_addr;
1307 to_port = from_addr->sin_port;
1308 }
1309
1310 LOG_CONN_RTP(conn_dst, LOGL_DEBUG, "iuup_tx_msg(%u bytes) to %s:%u\n", msg->len,
1311 inet_ntoa(to_addr), ntohs(to_port));
1312
1313 return mgcp_udp_send(rtp_end->rtp.fd, &to_addr, to_port, (char*)msg->data, msg->len);
1314}
1315
1316static void iuup_init(struct mgcp_conn_rtp *conn_src)
1317{
1318 struct osmo_iuup_cn_cfg cfg = {
1319 .node_priv = conn_src,
1320 .rx_payload = iuup_rx_payload,
1321 .tx_msg = iuup_tx_msg,
1322 };
1323
1324 if (conn_src->iuup) {
1325 LOG_CONN_RTP(conn_src, LOGL_NOTICE, "Rx IuUP init, but already initialized. Ignoring.\n");
1326 return;
1327 }
1328
1329 conn_src->iuup = osmo_iuup_cn_init(conn_src->conn, &cfg, "endp_%d_conn_%s",
1330 ENDPOINT_NUMBER(conn_src->conn->endp), conn_src->conn->id);
1331}
1332
Philipp Maier87bd9be2017-08-22 16:35:41 +02001333/* Handle incoming RTP data from NET */
1334static int rtp_data_net(struct osmo_fd *fd, unsigned int what)
1335{
1336 /* NOTE: This is a generic implementation. RTP data is received. In
1337 * case of loopback the data is just sent back to its origin. All
1338 * other cases implement endpoint specific behaviour (e.g. how is the
1339 * destination connection determined?). That specific behaviour is
1340 * implemented by the callback function that is called at the end of
1341 * the function */
1342
1343 struct mgcp_conn_rtp *conn_src;
1344 struct mgcp_endpoint *endp;
1345 struct sockaddr_in addr;
Neels Hofmeyr306dc092018-09-30 05:01:20 +02001346 socklen_t slen = sizeof(addr);
1347 int ret;
1348 enum rtp_proto proto;
1349 struct osmo_rtp_msg_ctx mc;
1350 struct msgb *msg = msgb_alloc_headroom(RTP_BUF_SIZE + OSMO_IUUP_HEADROOM,
1351 OSMO_IUUP_HEADROOM, "RTP-rx");
1352 int rc;
Philipp Maier87bd9be2017-08-22 16:35:41 +02001353
1354 conn_src = (struct mgcp_conn_rtp *)fd->data;
1355 OSMO_ASSERT(conn_src);
1356 endp = conn_src->conn->endp;
1357 OSMO_ASSERT(endp);
1358
Neels Hofmeyr306dc092018-09-30 05:01:20 +02001359 proto = (fd == &conn_src->end.rtp)? MGCP_PROTO_RTP : MGCP_PROTO_RTCP;
Philipp Maier87bd9be2017-08-22 16:35:41 +02001360
Neels Hofmeyr306dc092018-09-30 05:01:20 +02001361 ret = recvfrom(fd->fd, msg->data, msg->data_len, 0, (struct sockaddr *)&addr, &slen);
1362
1363 if (ret <= 0) {
1364 LOG_CONN_RTP(conn_src, LOGL_ERROR, "recvfrom error: %s\n", strerror(errno));
1365 rc = -1;
1366 goto out;
1367 }
1368
1369 msgb_put(msg, ret);
1370
1371 LOG_CONN_RTP(conn_src, LOGL_DEBUG, "%s: rx %u bytes from %s:%u\n",
1372 proto == MGCP_PROTO_RTP ? "RTP" : "RTPC",
1373 msg->len, inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
1374
1375 if ((proto == MGCP_PROTO_RTP && check_rtp(conn_src, msg))
1376 || (proto == MGCP_PROTO_RTCP && check_rtcp(conn_src, msg))) {
1377 /* Logging happened in the two check_ functions */
1378 rc = -1;
1379 goto out;
1380 }
1381
1382 if (is_dummy_msg(proto, msg)) {
1383 LOG_CONN_RTP(conn_src, LOGL_DEBUG, "rx dummy packet (dropped)\n");
1384 rc = 0;
1385 goto out;
1386 }
1387
1388 mc = (struct osmo_rtp_msg_ctx){
1389 .proto = proto,
1390 .conn_src = conn_src,
1391 .from_addr = &addr,
1392 };
1393 OSMO_RTP_MSG_CTX(msg) = &mc;
1394 LOG_CONN_RTP(conn_src, LOGL_DEBUG, "msg ctx: %d %p %s\n",
1395 OSMO_RTP_MSG_CTX(msg)->proto,
1396 OSMO_RTP_MSG_CTX(msg)->conn_src,
1397 osmo_hexdump((void*)OSMO_RTP_MSG_CTX(msg)->from_addr, sizeof(struct sockaddr_in)));
1398
1399 /* Increment RX statistics */
1400 rate_ctr_inc(&conn_src->rate_ctr_group->ctr[RTP_PACKETS_RX_CTR]);
1401 rate_ctr_add(&conn_src->rate_ctr_group->ctr[RTP_OCTETS_RX_CTR], msg->len);
1402 /* FIXME: count RTP and RTCP separately, also count IuUP payload-less separately */
1403
1404 /* Forward a copy of the RTP data to a debug ip/port */
1405 forward_data(fd->fd, &conn_src->tap_in, msg);
1406
1407 if (proto == MGCP_PROTO_RTP && osmo_iuup_is_init(msg))
1408 iuup_init(conn_src);
1409
1410 if (conn_src->iuup && proto == MGCP_PROTO_RTP)
1411 rc = osmo_iuup_cn_rx_pdu(conn_src->iuup, msg);
1412 else
1413 rc = rx_rtp(msg);
1414
1415out:
1416 msgb_free(msg);
1417 return rc;
1418}
1419
1420static int rx_rtp(struct msgb *msg)
1421{
1422 struct mgcp_conn_rtp *conn_src = OSMO_RTP_MSG_CTX(msg)->conn_src;
1423 struct sockaddr_in *from_addr = OSMO_RTP_MSG_CTX(msg)->from_addr;
1424 struct mgcp_conn *conn = conn_src->conn;
1425 struct mgcp_trunk_config *tcfg = conn->endp->tcfg;
1426
1427 LOG_CONN_RTP(conn_src, LOGL_DEBUG, "rx_rtp(%u bytes)\n", msg->len);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001428
Oliver Smithe36b7752019-01-22 16:31:36 +01001429 mgcp_conn_watchdog_kick(conn_src->conn);
1430
Philipp Maier228e5912019-03-05 13:56:59 +01001431 /* If AMR is configured for the ingress connection a conversion of the
1432 * framing mode (octet-aligned vs. bandwith-efficient is explicitly
1433 * define, then we check if the incoming payload matches that
1434 * expectation. */
1435 if (amr_oa_bwe_convert_indicated(conn_src->end.codec)) {
Neels Hofmeyr306dc092018-09-30 05:01:20 +02001436 int oa = amr_oa_check((char*)msg->data, msg->len);
Neels Hofmeyree784f92019-08-20 03:06:17 +02001437 if (oa < 0)
1438 return -1;
1439 if (((bool)oa) != conn_src->end.codec->param.amr_octet_aligned)
Philipp Maier228e5912019-03-05 13:56:59 +01001440 return -1;
1441 }
1442
Neels Hofmeyr306dc092018-09-30 05:01:20 +02001443 /* Check if the origin of the RTP packet seems plausible */
1444 if (!tcfg->rtp_accept_all && check_rtp_origin(conn_src, from_addr))
1445 return -1;
1446
Philipp Maier87bd9be2017-08-22 16:35:41 +02001447 /* Execute endpoint specific implementation that handles the
1448 * dispatching of the RTP data */
Neels Hofmeyr306dc092018-09-30 05:01:20 +02001449 return conn->endp->type->dispatch_rtp_cb(msg);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001450}
1451
1452/*! set IP Type of Service parameter.
1453 * \param[in] fd associated file descriptor
1454 * \param[in] tos dscp value
1455 * \returns 0 on success, -1 on ERROR */
1456int mgcp_set_ip_tos(int fd, int tos)
1457{
1458 int ret;
1459 ret = setsockopt(fd, IPPROTO_IP, IP_TOS, &tos, sizeof(tos));
1460
1461 if (ret < 0)
1462 return -1;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001463 return 0;
1464}
1465
Philipp Maier87bd9be2017-08-22 16:35:41 +02001466/*! bind RTP port to osmo_fd.
1467 * \param[in] source_addr source (local) address to bind on
1468 * \param[in] fd associated file descriptor
1469 * \param[in] port to bind on
1470 * \returns 0 on success, -1 on ERROR */
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001471int mgcp_create_bind(const char *source_addr, struct osmo_fd *fd, int port)
1472{
Harald Welte8890dfa2017-11-17 15:09:30 +01001473 int rc;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001474
Harald Welte8890dfa2017-11-17 15:09:30 +01001475 rc = osmo_sock_init2(AF_INET, SOCK_DGRAM, IPPROTO_UDP, source_addr, port,
1476 NULL, 0, OSMO_SOCK_F_BIND);
1477 if (rc < 0) {
Philipp Maierc3413882017-10-27 12:26:54 +02001478 LOGP(DRTP, LOGL_ERROR, "failed to bind UDP port (%s:%i).\n",
Philipp Maier87bd9be2017-08-22 16:35:41 +02001479 source_addr, port);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001480 return -1;
1481 }
Harald Welte8890dfa2017-11-17 15:09:30 +01001482 fd->fd = rc;
1483 LOGP(DRTP, LOGL_DEBUG, "created socket + bound UDP port (%s:%i).\n", source_addr, port);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001484
1485 return 0;
1486}
1487
Philipp Maier87bd9be2017-08-22 16:35:41 +02001488/* Bind RTP and RTCP port (helper function for mgcp_bind_net_rtp_port()) */
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001489static int bind_rtp(struct mgcp_config *cfg, const char *source_addr,
Philipp Maier87bd9be2017-08-22 16:35:41 +02001490 struct mgcp_rtp_end *rtp_end, int endpno)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001491{
Philipp Maier87bd9be2017-08-22 16:35:41 +02001492 /* NOTE: The port that is used for RTCP is the RTP port incremented by one
1493 * (e.g. RTP-Port = 16000 ==> RTCP-Port = 16001) */
Pau Espin Pedrol3239f622019-04-24 18:47:46 +02001494 struct mgcp_endpoint *endp = &cfg->trunk.endpoints[endpno];
Philipp Maier87bd9be2017-08-22 16:35:41 +02001495
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001496 if (mgcp_create_bind(source_addr, &rtp_end->rtp,
1497 rtp_end->local_port) != 0) {
Pau Espin Pedrol3239f622019-04-24 18:47:46 +02001498 LOGPENDP(endp, DRTP, LOGL_ERROR,
1499 "failed to create RTP port: %s:%d\n",
1500 source_addr, rtp_end->local_port);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001501 goto cleanup0;
1502 }
1503
1504 if (mgcp_create_bind(source_addr, &rtp_end->rtcp,
1505 rtp_end->local_port + 1) != 0) {
Pau Espin Pedrol3239f622019-04-24 18:47:46 +02001506 LOGPENDP(endp, DRTP, LOGL_ERROR,
1507 "failed to create RTCP port: %s:%d\n",
1508 source_addr, rtp_end->local_port + 1);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001509 goto cleanup1;
1510 }
1511
Philipp Maier87bd9be2017-08-22 16:35:41 +02001512 /* Set Type of Service (DSCP-Value) as configured via VTY */
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001513 mgcp_set_ip_tos(rtp_end->rtp.fd, cfg->endp_dscp);
1514 mgcp_set_ip_tos(rtp_end->rtcp.fd, cfg->endp_dscp);
1515
1516 rtp_end->rtp.when = BSC_FD_READ;
1517 if (osmo_fd_register(&rtp_end->rtp) != 0) {
Pau Espin Pedrol3239f622019-04-24 18:47:46 +02001518 LOGPENDP(endp, DRTP, LOGL_ERROR,
1519 "failed to register RTP port %d\n",
1520 rtp_end->local_port);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001521 goto cleanup2;
1522 }
1523
1524 rtp_end->rtcp.when = BSC_FD_READ;
1525 if (osmo_fd_register(&rtp_end->rtcp) != 0) {
Pau Espin Pedrol3239f622019-04-24 18:47:46 +02001526 LOGPENDP(endp, DRTP, LOGL_ERROR,
1527 "failed to register RTCP port %d\n",
1528 rtp_end->local_port + 1);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001529 goto cleanup3;
1530 }
1531
1532 return 0;
1533
1534cleanup3:
1535 osmo_fd_unregister(&rtp_end->rtp);
1536cleanup2:
1537 close(rtp_end->rtcp.fd);
1538 rtp_end->rtcp.fd = -1;
1539cleanup1:
1540 close(rtp_end->rtp.fd);
1541 rtp_end->rtp.fd = -1;
1542cleanup0:
1543 return -1;
1544}
1545
Philipp Maier87bd9be2017-08-22 16:35:41 +02001546/*! bind RTP port to endpoint/connection.
1547 * \param[in] endp endpoint that holds the RTP connection
1548 * \param[in] rtp_port port number to bind on
1549 * \param[in] conn associated RTP connection
1550 * \returns 0 on success, -1 on ERROR */
1551int mgcp_bind_net_rtp_port(struct mgcp_endpoint *endp, int rtp_port,
1552 struct mgcp_conn_rtp *conn)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001553{
Philipp Maier87bd9be2017-08-22 16:35:41 +02001554 char name[512];
1555 struct mgcp_rtp_end *end;
Philipp Maier1cb1e382017-11-02 17:16:04 +01001556 char local_ip_addr[INET_ADDRSTRLEN];
Philipp Maier87bd9be2017-08-22 16:35:41 +02001557
Philipp Maier01d24a32017-11-21 17:26:09 +01001558 snprintf(name, sizeof(name), "%s-%s", conn->conn->name, conn->conn->id);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001559 end = &conn->end;
1560
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001561 if (end->rtp.fd != -1 || end->rtcp.fd != -1) {
Pau Espin Pedrol3239f622019-04-24 18:47:46 +02001562 LOGPENDP(endp, DRTP, LOGL_ERROR, "%u was already bound on conn:%s\n",
1563 rtp_port, mgcp_conn_dump(conn->conn));
Philipp Maier87bd9be2017-08-22 16:35:41 +02001564
1565 /* Double bindings should never occour! Since we always allocate
1566 * connections dynamically and free them when they are not
1567 * needed anymore, there must be no previous binding leftover.
1568 * Should there be a connection bound twice, we have a serious
1569 * problem and must exit immediately! */
1570 OSMO_ASSERT(false);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001571 }
1572
1573 end->local_port = rtp_port;
Philipp Maier87bd9be2017-08-22 16:35:41 +02001574 end->rtp.cb = rtp_data_net;
1575 end->rtp.data = conn;
1576 end->rtcp.data = conn;
1577 end->rtcp.cb = rtp_data_net;
1578
Philipp Maier1cb1e382017-11-02 17:16:04 +01001579 mgcp_get_local_addr(local_ip_addr, conn);
1580
1581 return bind_rtp(endp->cfg, local_ip_addr, end,
Philipp Maier87bd9be2017-08-22 16:35:41 +02001582 ENDPOINT_NUMBER(endp));
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001583}
1584
Philipp Maier87bd9be2017-08-22 16:35:41 +02001585/*! free allocated RTP and RTCP ports.
1586 * \param[in] end RTP end */
1587void mgcp_free_rtp_port(struct mgcp_rtp_end *end)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001588{
1589 if (end->rtp.fd != -1) {
1590 close(end->rtp.fd);
1591 end->rtp.fd = -1;
1592 osmo_fd_unregister(&end->rtp);
1593 }
1594
1595 if (end->rtcp.fd != -1) {
1596 close(end->rtcp.fd);
1597 end->rtcp.fd = -1;
1598 osmo_fd_unregister(&end->rtcp);
1599 }
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001600}