blob: c8b6e8660abd00a381666e16e136191bab6c13ac [file] [log] [blame]
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +01001/* A Media Gateway Control Protocol Media Gateway: RFC 3435 */
2/* The protocol implementation */
3
4/*
Holger Hans Peter Freyther8d0be252012-11-29 12:54:22 +01005 * (C) 2009-2012 by Holger Hans Peter Freyther <zecke@selfish.org>
6 * (C) 2009-2012 by On-Waves
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +01007 * All Rights Reserved
8 *
9 * This program is free software; you can redistribute it and/or modify
Harald Welte9af6ddf2011-01-01 15:25:50 +010010 * 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
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +010012 * (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
Harald Welte9af6ddf2011-01-01 15:25:50 +010017 * GNU Affero General Public License for more details.
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +010018 *
Harald Welte9af6ddf2011-01-01 15:25:50 +010019 * 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/>.
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +010021 *
22 */
23
24#include <ctype.h>
25#include <stdio.h>
26#include <stdlib.h>
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +010027#include <time.h>
28#include <limits.h>
29#include <unistd.h>
Jacob Erlbeck845d0052014-03-17 12:30:56 +010030#include <errno.h>
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +010031
Pablo Neira Ayuso136f4532011-03-22 16:47:59 +010032#include <osmocom/core/msgb.h>
33#include <osmocom/core/talloc.h>
34#include <osmocom/core/select.h>
Holger Hans Peter Freyther16b7f5c2011-02-28 22:06:47 +010035
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +010036#include <openbsc/mgcp.h>
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +010037#include <openbsc/mgcp_internal.h>
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +010038
Jacob Erlbecka01bd602013-11-29 13:43:43 +010039#define for_each_non_empty_line(line, save) \
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +010040 for (line = strtok_r(NULL, "\r\n", &save); line;\
Harald Welteae199722012-01-27 12:31:36 +010041 line = strtok_r(NULL, "\r\n", &save))
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +010042
Jacob Erlbeck452c1832014-05-09 19:42:17 +020043
Holger Hans Peter Freytherf138f912010-08-05 08:08:17 +080044static void mgcp_rtp_end_reset(struct mgcp_rtp_end *end);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +010045
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +010046struct mgcp_request {
47 char *name;
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +010048 struct msgb *(*handle_request) (struct mgcp_parse_data *data);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +010049 char *debug_name;
50};
51
52#define MGCP_REQUEST(NAME, REQ, DEBUG_NAME) \
53 { .name = NAME, .handle_request = REQ, .debug_name = DEBUG_NAME },
54
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +010055static struct msgb *handle_audit_endpoint(struct mgcp_parse_data *data);
56static struct msgb *handle_create_con(struct mgcp_parse_data *data);
57static struct msgb *handle_delete_con(struct mgcp_parse_data *data);
58static struct msgb *handle_modify_con(struct mgcp_parse_data *data);
59static struct msgb *handle_rsip(struct mgcp_parse_data *data);
60static struct msgb *handle_noti_req(struct mgcp_parse_data *data);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +010061
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +080062static void create_transcoder(struct mgcp_endpoint *endp);
63static void delete_transcoder(struct mgcp_endpoint *endp);
64
Holger Hans Peter Freyther7cce1d32015-03-26 20:34:12 +010065static int setup_rtp_processing(struct mgcp_endpoint *endp);
Jacob Erlbecka0d64ce2014-03-13 14:24:52 +010066
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +010067static int mgcp_analyze_header(struct mgcp_parse_data *parse, char *data);
68
Philipp Maier4b60d072017-04-09 12:32:51 +020069/* Display an mgcp message on the log output */
70void display_mgcp_message(unsigned char *message, unsigned int len,
71 char *preamble)
72{
73 unsigned char line[80];
74 unsigned char *ptr;
75 unsigned int consumed = 0;
76 unsigned int consumed_line = 0;
77 unsigned int line_count = 0;
78
79 if (!log_check_level(DMGCP, LOGL_DEBUG))
80 return;
81
82 while (1) {
83 memset(line, 0, sizeof(line));
84 ptr = line;
85 consumed_line = 0;
86 do {
87 if (*message != '\n' && *message != '\r') {
88 *ptr = *message;
89 ptr++;
90 }
91 message++;
92 consumed++;
93 consumed_line++;
94 } while (*message != '\n' && consumed < len
95 && consumed_line < sizeof(line));
96
97 if (strlen((const char *)line)) {
98 LOGP(DMGCP, LOGL_DEBUG, "%s: line #%02u: %s\n",
99 preamble, line_count, line);
100 line_count++;
101 }
102
103 if (consumed >= len)
104 return;
105 }
106}
107
Holger Hans Peter Freyther1cc5ff82014-05-22 15:03:10 +0200108static int mgcp_check_param(const struct mgcp_endpoint *endp, const char *line)
109{
110 const size_t line_len = strlen(line);
111 if (line[0] != '\0' && line_len < 2) {
112 LOGP(DMGCP, LOGL_ERROR,
113 "Wrong MGCP option format: '%s' on 0x%x\n",
114 line, ENDPOINT_NUMBER(endp));
115 return 0;
116 }
117
118 return 1;
119}
120
Holger Hans Peter Freyther46340132010-08-06 08:26:54 +0800121static uint32_t generate_call_id(struct mgcp_config *cfg)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100122{
123 int i;
124
125 /* use the call id */
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100126 ++cfg->last_call_id;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100127
128 /* handle wrap around */
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100129 if (cfg->last_call_id == CI_UNUSED)
130 ++cfg->last_call_id;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100131
132 /* callstack can only be of size number_of_endpoints */
133 /* verify that the call id is free, e.g. in case of overrun */
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +0100134 for (i = 1; i < cfg->trunk.number_endpoints; ++i)
135 if (cfg->trunk.endpoints[i].ci == cfg->last_call_id)
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100136 return generate_call_id(cfg);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100137
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100138 return cfg->last_call_id;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100139}
140
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100141/*
142 * array of function pointers for handling various
143 * messages. In the future this might be binary sorted
144 * for performance reasons.
145 */
146static const struct mgcp_request mgcp_requests [] = {
147 MGCP_REQUEST("AUEP", handle_audit_endpoint, "AuditEndpoint")
148 MGCP_REQUEST("CRCX", handle_create_con, "CreateConnection")
149 MGCP_REQUEST("DLCX", handle_delete_con, "DeleteConnection")
150 MGCP_REQUEST("MDCX", handle_modify_con, "ModifiyConnection")
Holger Hans Peter Freyther6e94d6d2011-01-25 23:33:54 +0100151 MGCP_REQUEST("RQNT", handle_noti_req, "NotificationRequest")
Holger Hans Peter Freyther9bdcc9c2010-03-31 06:39:35 +0200152
153 /* SPEC extension */
154 MGCP_REQUEST("RSIP", handle_rsip, "ReSetInProgress")
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100155};
156
Holger Hans Peter Freyther62e836c2010-02-03 11:03:45 +0100157static struct msgb *mgcp_msgb_alloc(void)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100158{
Holger Hans Peter Freyther62e836c2010-02-03 11:03:45 +0100159 struct msgb *msg;
160 msg = msgb_alloc_headroom(4096, 128, "MGCP msg");
161 if (!msg)
162 LOGP(DMGCP, LOGL_ERROR, "Failed to msgb for MGCP data.\n");
163
164 return msg;
165}
166
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100167static struct msgb *do_retransmission(const struct mgcp_endpoint *endp)
168{
169 struct msgb *msg = mgcp_msgb_alloc();
170 if (!msg)
171 return NULL;
172
173 msg->l2h = msgb_put(msg, strlen(endp->last_response));
174 memcpy(msg->l2h, endp->last_response, msgb_l2len(msg));
175 return msg;
176}
177
Holger Hans Peter Freythera769dcb2012-12-07 15:14:27 +0100178static struct msgb *create_resp(struct mgcp_endpoint *endp, int code,
179 const char *txt, const char *msg,
Holger Hans Peter Freyther0bf15a82012-09-14 17:18:12 +0200180 const char *trans, const char *param,
181 const char *sdp)
Holger Hans Peter Freyther62e836c2010-02-03 11:03:45 +0100182{
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100183 int len;
Holger Hans Peter Freyther62e836c2010-02-03 11:03:45 +0100184 struct msgb *res;
185
186 res = mgcp_msgb_alloc();
187 if (!res)
188 return NULL;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100189
Holger Hans Peter Freyther0bf15a82012-09-14 17:18:12 +0200190 len = snprintf((char *) res->data, 2048, "%d %s%s%s\r\n%s",
191 code, trans, txt, param ? param : "", sdp ? sdp : "");
192 if (len < 0) {
193 LOGP(DMGCP, LOGL_ERROR, "Failed to sprintf MGCP response.\n");
194 msgb_free(res);
195 return NULL;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100196 }
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100197
Holger Hans Peter Freyther62e836c2010-02-03 11:03:45 +0100198 res->l2h = msgb_put(res, len);
Philipp Maier4b60d072017-04-09 12:32:51 +0200199 LOGP(DMGCP, LOGL_DEBUG, "Generated response: code=%d\n", code);
200 display_mgcp_message(res->l2h, msgb_l2len(res), "Generated response");
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100201
202 /*
203 * Remember the last transmission per endpoint.
204 */
205 if (endp) {
206 struct mgcp_trunk_config *tcfg = endp->tcfg;
207 talloc_free(endp->last_response);
208 talloc_free(endp->last_trans);
209 endp->last_trans = talloc_strdup(tcfg->endpoints, trans);
210 endp->last_response = talloc_strndup(tcfg->endpoints,
211 (const char *) res->l2h,
212 msgb_l2len(res));
213 }
214
Holger Hans Peter Freyther62e836c2010-02-03 11:03:45 +0100215 return res;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100216}
217
Holger Hans Peter Freythera769dcb2012-12-07 15:14:27 +0100218static struct msgb *create_ok_resp_with_param(struct mgcp_endpoint *endp,
219 int code, const char *msg,
Holger Hans Peter Freyther0bf15a82012-09-14 17:18:12 +0200220 const char *trans, const char *param)
221{
Holger Hans Peter Freythera769dcb2012-12-07 15:14:27 +0100222 return create_resp(endp, code, " OK", msg, trans, param, NULL);
Holger Hans Peter Freyther0bf15a82012-09-14 17:18:12 +0200223}
224
Holger Hans Peter Freythera769dcb2012-12-07 15:14:27 +0100225static struct msgb *create_ok_response(struct mgcp_endpoint *endp,
226 int code, const char *msg, const char *trans)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100227{
Holger Hans Peter Freythera769dcb2012-12-07 15:14:27 +0100228 return create_ok_resp_with_param(endp, code, msg, trans, NULL);
Holger Hans Peter Freyther6adac172011-01-06 16:19:55 +0100229}
230
Holger Hans Peter Freythera769dcb2012-12-07 15:14:27 +0100231static struct msgb *create_err_response(struct mgcp_endpoint *endp,
232 int code, const char *msg, const char *trans)
Holger Hans Peter Freyther6adac172011-01-06 16:19:55 +0100233{
Holger Hans Peter Freythera769dcb2012-12-07 15:14:27 +0100234 return create_resp(endp, code, " FAIL", msg, trans, NULL, NULL);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100235}
236
Jacob Erlbeck997e1e82014-03-14 18:01:20 +0100237static int write_response_sdp(struct mgcp_endpoint *endp,
238 char *sdp_record, size_t size, const char *addr)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100239{
Jacob Erlbeck168ca002014-03-17 12:40:07 +0100240 const char *fmtp_extra;
241 const char *audio_name;
242 int payload_type;
Jacob Erlbeck0a1bc562013-12-10 13:09:37 +0100243 int len;
Jacob Erlbeck997e1e82014-03-14 18:01:20 +0100244 int nchars;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100245
Jacob Erlbeck168ca002014-03-17 12:40:07 +0100246 endp->cfg->get_net_downlink_format_cb(endp, &payload_type,
247 &audio_name, &fmtp_extra);
248
Jacob Erlbeck997e1e82014-03-14 18:01:20 +0100249 len = snprintf(sdp_record, size,
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100250 "v=0\r\n"
Holger Hans Peter Freytherc7e49d32011-07-20 20:43:15 +0200251 "o=- %u 23 IN IP4 %s\r\n"
Holger Hans Peter Freytherb1edf7b2014-11-20 23:17:32 +0100252 "s=-\r\n"
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100253 "c=IN IP4 %s\r\n"
Jacob Erlbeck997e1e82014-03-14 18:01:20 +0100254 "t=0 0\r\n",
255 endp->ci, addr, addr);
Jacob Erlbeck0a1bc562013-12-10 13:09:37 +0100256
Jacob Erlbeck997e1e82014-03-14 18:01:20 +0100257 if (len < 0 || len >= size)
Jacob Erlbeck0a1bc562013-12-10 13:09:37 +0100258 goto buffer_too_small;
259
Jacob Erlbeck997e1e82014-03-14 18:01:20 +0100260 if (payload_type >= 0) {
261 nchars = snprintf(sdp_record + len, size - len,
262 "m=audio %d RTP/AVP %d\r\n",
263 endp->net_end.local_port, payload_type);
264 if (nchars < 0 || nchars >= size - len)
265 goto buffer_too_small;
266
267 len += nchars;
268
Holger Hans Peter Freyther619b0142014-11-19 16:04:45 +0100269 if (audio_name && endp->tcfg->audio_send_name) {
Jacob Erlbeck997e1e82014-03-14 18:01:20 +0100270 nchars = snprintf(sdp_record + len, size - len,
271 "a=rtpmap:%d %s\r\n",
272 payload_type, audio_name);
273
274 if (nchars < 0 || nchars >= size - len)
275 goto buffer_too_small;
276
277 len += nchars;
278 }
279
280 if (fmtp_extra) {
281 nchars = snprintf(sdp_record + len, size - len,
Jacob Erlbeckcb04ca22014-06-12 12:42:38 +0200282 "%s\r\n", fmtp_extra);
Jacob Erlbeck997e1e82014-03-14 18:01:20 +0100283
284 if (nchars < 0 || nchars >= size - len)
285 goto buffer_too_small;
286
287 len += nchars;
288 }
289 }
Jacob Erlbeck0a1bc562013-12-10 13:09:37 +0100290 if (endp->bts_end.packet_duration_ms > 0 && endp->tcfg->audio_send_ptime) {
Jacob Erlbeck997e1e82014-03-14 18:01:20 +0100291 nchars = snprintf(sdp_record + len, size - len,
292 "a=ptime:%d\r\n",
293 endp->bts_end.packet_duration_ms);
294 if (nchars < 0 || nchars >= size - len)
Jacob Erlbeck0a1bc562013-12-10 13:09:37 +0100295 goto buffer_too_small;
296
297 len += nchars;
298 }
Jacob Erlbeck997e1e82014-03-14 18:01:20 +0100299
300 return len;
Jacob Erlbeck0a1bc562013-12-10 13:09:37 +0100301
302buffer_too_small:
Holger Hans Peter Freytherc6e32ad2015-01-02 11:25:54 +0100303 LOGP(DMGCP, LOGL_ERROR, "SDP buffer too small: %zu (needed %d)\n",
Jacob Erlbeck997e1e82014-03-14 18:01:20 +0100304 size, len);
305 return -1;
306}
307
308static struct msgb *create_response_with_sdp(struct mgcp_endpoint *endp,
309 const char *msg, const char *trans_id)
310{
311 const char *addr = endp->cfg->local_ip;
312 char sdp_record[4096];
313 int len;
314 int nchars;
Pablo Neira Ayusob769f3c2014-08-27 17:02:52 +0200315 char osmux_extension[strlen("\nX-Osmux: 255") + 1];
Jacob Erlbeck997e1e82014-03-14 18:01:20 +0100316
317 if (!addr)
Holger Hans Peter Freythere6ed0092015-08-20 14:58:19 +0200318 addr = mgcp_net_src_addr(endp);
Jacob Erlbeck997e1e82014-03-14 18:01:20 +0100319
Pau Espin Pedrolc5f60fb2017-08-11 18:32:22 +0200320 if (endp->osmux.state == OSMUX_STATE_NEGOTIATING) {
Pablo Neira Ayusob769f3c2014-08-27 17:02:52 +0200321 sprintf(osmux_extension, "\nX-Osmux: %u", endp->osmux.cid);
Pau Espin Pedrolc5f60fb2017-08-11 18:32:22 +0200322 endp->osmux.state = OSMUX_STATE_ACTIVATING;
323 } else {
Pablo Neira Ayusob769f3c2014-08-27 17:02:52 +0200324 osmux_extension[0] = '\0';
Pau Espin Pedrolc5f60fb2017-08-11 18:32:22 +0200325 }
Jacob Erlbeck997e1e82014-03-14 18:01:20 +0100326
Pablo Neira Ayusob769f3c2014-08-27 17:02:52 +0200327 len = snprintf(sdp_record, sizeof(sdp_record),
328 "I: %u%s\n\n", endp->ci, osmux_extension);
Jacob Erlbeck997e1e82014-03-14 18:01:20 +0100329 if (len < 0)
330 return NULL;
331
332 nchars = write_response_sdp(endp, sdp_record + len,
333 sizeof(sdp_record) - len - 1, addr);
334 if (nchars < 0)
335 return NULL;
336
337 len += nchars;
338
339 sdp_record[sizeof(sdp_record) - 1] = '\0';
340
341 return create_resp(endp, 200, " OK", msg, trans_id, NULL, sdp_record);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100342}
343
Holger Hans Peter Freyther6b0ba012014-07-08 13:01:56 +0200344static void send_dummy(struct mgcp_endpoint *endp)
345{
Pablo Neira Ayusob769f3c2014-08-27 17:02:52 +0200346 if (endp->osmux.state != OSMUX_STATE_DISABLED)
Holger Hans Peter Freyther6b0ba012014-07-08 13:01:56 +0200347 osmux_send_dummy(endp);
348 else
349 mgcp_send_dummy(endp);
350}
351
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100352/*
353 * handle incoming messages:
354 * - this can be a command (four letters, space, transaction id)
355 * - or a response (three numbers, space, transaction id)
356 */
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100357struct msgb *mgcp_handle_message(struct mgcp_config *cfg, struct msgb *msg)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100358{
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100359 struct mgcp_parse_data pdata;
360 int i, code, handled = 0;
Holger Hans Peter Freyther62e836c2010-02-03 11:03:45 +0100361 struct msgb *resp = NULL;
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100362 char *data;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100363
Holger Hans Peter Freytherf36a11a2010-03-31 13:26:46 +0200364 if (msgb_l2len(msg) < 4) {
Holger Hans Peter Freyther0d904e02012-12-07 16:46:19 +0100365 LOGP(DMGCP, LOGL_ERROR, "msg too short: %d\n", msg->len);
Holger Hans Peter Freyther62e836c2010-02-03 11:03:45 +0100366 return NULL;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100367 }
368
Neels Hofmeyra1756f32016-05-20 21:59:55 +0200369 if (mgcp_msg_terminate_nul(msg))
Jacob Erlbeck9107e2d2013-12-03 17:14:44 +0100370 return NULL;
Jacob Erlbeck9107e2d2013-12-03 17:14:44 +0100371
Philipp Maier4b60d072017-04-09 12:32:51 +0200372 display_mgcp_message(msg->l2h, msgb_l2len(msg), "Received message");
373
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100374 /* attempt to treat it as a response */
Holger Hans Peter Freytherf36a11a2010-03-31 13:26:46 +0200375 if (sscanf((const char *)&msg->l2h[0], "%3d %*s", &code) == 1) {
Holger Hans Peter Freyther63f2db22010-02-26 13:30:57 +0100376 LOGP(DMGCP, LOGL_DEBUG, "Response: Code: %d\n", code);
Holger Hans Peter Freyther29de3462012-12-07 16:07:46 +0100377 return NULL;
378 }
379
380 msg->l3h = &msg->l2h[4];
381
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100382
383 /*
384 * Check for a duplicate message and respond.
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100385 */
386 memset(&pdata, 0, sizeof(pdata));
387 pdata.cfg = cfg;
Jacob Erlbeck17711712013-11-29 13:43:46 +0100388 data = strline_r((char *) msg->l3h, &pdata.save);
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100389 pdata.found = mgcp_analyze_header(&pdata, data);
390 if (pdata.endp && pdata.trans
391 && pdata.endp->last_trans
392 && strcmp(pdata.endp->last_trans, pdata.trans) == 0) {
393 return do_retransmission(pdata.endp);
394 }
395
Holger Hans Peter Freyther29de3462012-12-07 16:07:46 +0100396 for (i = 0; i < ARRAY_SIZE(mgcp_requests); ++i) {
397 if (strncmp(mgcp_requests[i].name, (const char *) &msg->l2h[0], 4) == 0) {
398 handled = 1;
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100399 resp = mgcp_requests[i].handle_request(&pdata);
Holger Hans Peter Freyther29de3462012-12-07 16:07:46 +0100400 break;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100401 }
402 }
403
Holger Hans Peter Freyther29de3462012-12-07 16:07:46 +0100404 if (!handled)
405 LOGP(DMGCP, LOGL_NOTICE, "MSG with type: '%.4s' not handled\n", &msg->l2h[0]);
406
Holger Hans Peter Freyther62e836c2010-02-03 11:03:45 +0100407 return resp;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100408}
409
Holger Hans Peter Freyther9f239a22011-01-06 19:32:52 +0100410/**
411 * We have a null terminated string with the endpoint name here. We only
412 * support two kinds. Simple ones as seen on the BSC level and the ones
413 * seen on the trunk side.
414 */
415static struct mgcp_endpoint *find_e1_endpoint(struct mgcp_config *cfg,
416 const char *mgcp)
417{
418 char *rest = NULL;
Holger Hans Peter Freyther74e61112011-02-28 14:13:47 +0100419 struct mgcp_trunk_config *tcfg;
420 int trunk, endp;
Holger Hans Peter Freyther9f239a22011-01-06 19:32:52 +0100421
422 trunk = strtoul(mgcp + 6, &rest, 10);
Holger Hans Peter Freytherf43f2fc2011-01-07 11:30:21 +0100423 if (rest == NULL || rest[0] != '/' || trunk < 1) {
Holger Hans Peter Freyther9f239a22011-01-06 19:32:52 +0100424 LOGP(DMGCP, LOGL_ERROR, "Wrong trunk name '%s'\n", mgcp);
425 return NULL;
426 }
427
428 endp = strtoul(rest + 1, &rest, 10);
429 if (rest == NULL || rest[0] != '@') {
Holger Hans Peter Freytherf43f2fc2011-01-07 11:30:21 +0100430 LOGP(DMGCP, LOGL_ERROR, "Wrong endpoint name '%s'\n", mgcp);
Holger Hans Peter Freyther9f239a22011-01-06 19:32:52 +0100431 return NULL;
432 }
433
434 /* signalling is on timeslot 1 */
435 if (endp == 1)
436 return NULL;
437
Holger Hans Peter Freyther74e61112011-02-28 14:13:47 +0100438 tcfg = mgcp_trunk_num(cfg, trunk);
439 if (!tcfg) {
440 LOGP(DMGCP, LOGL_ERROR, "The trunk %d is not declared.\n", trunk);
441 return NULL;
442 }
443
444 if (!tcfg->endpoints) {
445 LOGP(DMGCP, LOGL_ERROR, "Endpoints of trunk %d not allocated.\n", trunk);
446 return NULL;
447 }
448
449 if (endp < 1 || endp >= tcfg->number_endpoints) {
Holger Hans Peter Freyther9f239a22011-01-06 19:32:52 +0100450 LOGP(DMGCP, LOGL_ERROR, "Failed to find endpoint '%s'\n", mgcp);
Holger Hans Peter Freyther45c21842011-01-07 11:36:54 +0100451 return NULL;
Holger Hans Peter Freyther9f239a22011-01-06 19:32:52 +0100452 }
453
Holger Hans Peter Freyther74e61112011-02-28 14:13:47 +0100454 return &tcfg->endpoints[endp];
Holger Hans Peter Freyther9f239a22011-01-06 19:32:52 +0100455}
456
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100457static struct mgcp_endpoint *find_endpoint(struct mgcp_config *cfg, const char *mgcp)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100458{
459 char *endptr = NULL;
460 unsigned int gw = INT_MAX;
461
Holger Hans Peter Freyther614aba32015-09-04 16:01:12 +0200462 if (strncmp(mgcp, "ds/e1", 5) == 0)
Holger Hans Peter Freyther9f239a22011-01-06 19:32:52 +0100463 return find_e1_endpoint(cfg, mgcp);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100464
Holger Hans Peter Freyther614aba32015-09-04 16:01:12 +0200465 gw = strtoul(mgcp, &endptr, 16);
466 if (gw > 0 && gw < cfg->trunk.number_endpoints && endptr[0] == '@')
467 return &cfg->trunk.endpoints[gw];
468
469 LOGP(DMGCP, LOGL_ERROR, "Not able to find the endpoint: '%s'\n", mgcp);
Holger Hans Peter Freyther9f239a22011-01-06 19:32:52 +0100470 return NULL;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100471}
472
Harald Welteae199722012-01-27 12:31:36 +0100473/**
474 * @returns 0 when the status line was complete and transaction_id and
475 * endp out parameters are set.
476 */
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100477static int mgcp_analyze_header(struct mgcp_parse_data *pdata, char *data)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100478{
Harald Welteae199722012-01-27 12:31:36 +0100479 int i = 0;
Holger Hans Peter Freyther1eba7de2013-07-03 10:23:35 +0200480 char *elem, *save = NULL;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100481
Harald Welte4a7d0e72016-11-26 15:03:02 +0100482 OSMO_ASSERT(data);
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100483 pdata->trans = "000000";
Holger Hans Peter Freythera820c5f2010-02-26 13:32:55 +0100484
Harald Welteae199722012-01-27 12:31:36 +0100485 for (elem = strtok_r(data, " ", &save); elem;
486 elem = strtok_r(NULL, " ", &save)) {
487 switch (i) {
488 case 0:
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100489 pdata->trans = elem;
Harald Welteae199722012-01-27 12:31:36 +0100490 break;
491 case 1:
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100492 pdata->endp = find_endpoint(pdata->cfg, elem);
493 if (!pdata->endp) {
494 LOGP(DMGCP, LOGL_ERROR,
495 "Unable to find Endpoint `%s'\n", elem);
496 return -1;
Harald Welteae199722012-01-27 12:31:36 +0100497 }
498 break;
499 case 2:
500 if (strcmp("MGCP", elem)) {
501 LOGP(DMGCP, LOGL_ERROR,
502 "MGCP header parsing error\n");
503 return -1;
504 }
505 break;
506 case 3:
507 if (strcmp("1.0", elem)) {
508 LOGP(DMGCP, LOGL_ERROR, "MGCP version `%s' "
509 "not supported\n", elem);
510 return -1;
511 }
512 break;
513 }
514 i++;
515 }
516
517 if (i != 4) {
518 LOGP(DMGCP, LOGL_ERROR, "MGCP status line too short.\n");
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100519 pdata->trans = "000000";
520 pdata->endp = NULL;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100521 return -1;
522 }
523
Holger Hans Peter Freytherf2f15912010-04-01 03:27:04 +0200524 return 0;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100525}
526
527static int verify_call_id(const struct mgcp_endpoint *endp,
528 const char *callid)
529{
530 if (strcmp(endp->callid, callid) != 0) {
Holger Hans Peter Freyther2ada71d2010-02-03 09:13:10 +0100531 LOGP(DMGCP, LOGL_ERROR, "CallIDs does not match on 0x%x. '%s' != '%s'\n",
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100532 ENDPOINT_NUMBER(endp), endp->callid, callid);
533 return -1;
534 }
535
536 return 0;
537}
538
539static int verify_ci(const struct mgcp_endpoint *endp,
Holger Hans Peter Freyther46340132010-08-06 08:26:54 +0800540 const char *_ci)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100541{
Holger Hans Peter Freyther46340132010-08-06 08:26:54 +0800542 uint32_t ci = strtoul(_ci, NULL, 10);
543
544 if (ci != endp->ci) {
545 LOGP(DMGCP, LOGL_ERROR, "ConnectionIdentifiers do not match on 0x%x. %u != %s\n",
546 ENDPOINT_NUMBER(endp), endp->ci, _ci);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100547 return -1;
548 }
549
550 return 0;
551}
552
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100553static struct msgb *handle_audit_endpoint(struct mgcp_parse_data *p)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100554{
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100555 if (p->found != 0)
556 return create_err_response(NULL, 500, "AUEP", p->trans);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100557 else
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100558 return create_ok_response(p->endp, 200, "AUEP", p->trans);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100559}
560
Jacob Erlbeck2645c9e2013-12-19 12:23:24 +0100561static int parse_conn_mode(const char *msg, struct mgcp_endpoint *endp)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100562{
563 int ret = 0;
564 if (strcmp(msg, "recvonly") == 0)
Jacob Erlbeck2645c9e2013-12-19 12:23:24 +0100565 endp->conn_mode = MGCP_CONN_RECV_ONLY;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100566 else if (strcmp(msg, "sendrecv") == 0)
Jacob Erlbeck2645c9e2013-12-19 12:23:24 +0100567 endp->conn_mode = MGCP_CONN_RECV_SEND;
Holger Hans Peter Freythere02860a2010-09-18 20:21:44 +0800568 else if (strcmp(msg, "sendonly") == 0)
Jacob Erlbeck2645c9e2013-12-19 12:23:24 +0100569 endp->conn_mode = MGCP_CONN_SEND_ONLY;
Holger Hans Peter Freyther98a38772010-08-03 02:27:21 +0800570 else if (strcmp(msg, "loopback") == 0)
Jacob Erlbeck2645c9e2013-12-19 12:23:24 +0100571 endp->conn_mode = MGCP_CONN_LOOPBACK;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100572 else {
Holger Hans Peter Freyther2ada71d2010-02-03 09:13:10 +0100573 LOGP(DMGCP, LOGL_ERROR, "Unknown connection mode: '%s'\n", msg);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100574 ret = -1;
575 }
576
Jacob Erlbecke35fd132014-01-16 16:50:40 +0100577 endp->net_end.output_enabled =
578 endp->conn_mode & MGCP_CONN_SEND_ONLY ? 1 : 0;
579 endp->bts_end.output_enabled =
580 endp->conn_mode & MGCP_CONN_RECV_ONLY ? 1 : 0;
Jacob Erlbeck2645c9e2013-12-19 12:23:24 +0100581
Neels Hofmeyra1756f32016-05-20 21:59:55 +0200582 LOGP(DMGCP, LOGL_DEBUG, "endpoint %x connection mode '%s' %d output_enabled net %d bts %d\n",
583 ENDPOINT_NUMBER(endp),
584 msg, endp->conn_mode, endp->net_end.output_enabled,
585 endp->bts_end.output_enabled);
586
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100587 return ret;
588}
589
Holger Hans Peter Freytherf138f912010-08-05 08:08:17 +0800590static int allocate_port(struct mgcp_endpoint *endp, struct mgcp_rtp_end *end,
Holger Hans Peter Freyther218f8562010-09-18 02:30:02 +0800591 struct mgcp_port_range *range,
592 int (*alloc)(struct mgcp_endpoint *endp, int port))
Holger Hans Peter Freytherf138f912010-08-05 08:08:17 +0800593{
594 int i;
595
596 if (range->mode == PORT_ALLOC_STATIC) {
Holger Hans Peter Freytherf138f912010-08-05 08:08:17 +0800597 end->local_alloc = PORT_ALLOC_STATIC;
598 return 0;
599 }
600
601 /* attempt to find a port */
602 for (i = 0; i < 200; ++i) {
603 int rc;
604
605 if (range->last_port >= range->range_end)
606 range->last_port = range->range_start;
607
Holger Hans Peter Freyther218f8562010-09-18 02:30:02 +0800608 rc = alloc(endp, range->last_port);
Holger Hans Peter Freytherf138f912010-08-05 08:08:17 +0800609
610 range->last_port += 2;
611 if (rc == 0) {
612 end->local_alloc = PORT_ALLOC_DYNAMIC;
613 return 0;
614 }
615
616 }
617
Holger Hans Peter Freyther218f8562010-09-18 02:30:02 +0800618 LOGP(DMGCP, LOGL_ERROR, "Allocating a RTP/RTCP port failed 200 times 0x%x.\n",
619 ENDPOINT_NUMBER(endp));
Holger Hans Peter Freytherf138f912010-08-05 08:08:17 +0800620 return -1;
621}
622
623static int allocate_ports(struct mgcp_endpoint *endp)
624{
Holger Hans Peter Freyther218f8562010-09-18 02:30:02 +0800625 if (allocate_port(endp, &endp->net_end, &endp->cfg->net_ports,
626 mgcp_bind_net_rtp_port) != 0)
Holger Hans Peter Freytherf138f912010-08-05 08:08:17 +0800627 return -1;
628
Holger Hans Peter Freyther218f8562010-09-18 02:30:02 +0800629 if (allocate_port(endp, &endp->bts_end, &endp->cfg->bts_ports,
630 mgcp_bind_bts_rtp_port) != 0) {
Holger Hans Peter Freytherf138f912010-08-05 08:08:17 +0800631 mgcp_rtp_end_reset(&endp->net_end);
632 return -1;
633 }
634
Holger Hans Peter Freyther69906872011-02-28 14:51:48 +0100635 if (endp->cfg->transcoder_ip && endp->tcfg->trunk_type == MGCP_TRUNK_VIRTUAL) {
Holger Hans Peter Freyther21262332010-11-01 20:53:31 +0100636 if (allocate_port(endp, &endp->trans_net,
Holger Hans Peter Freytherb54048f2010-11-01 19:57:50 +0100637 &endp->cfg->transcoder_ports,
Holger Hans Peter Freytherbd7b3c52010-11-01 21:04:54 +0100638 mgcp_bind_trans_net_rtp_port) != 0) {
Holger Hans Peter Freytherb54048f2010-11-01 19:57:50 +0100639 mgcp_rtp_end_reset(&endp->net_end);
640 mgcp_rtp_end_reset(&endp->bts_end);
641 return -1;
642 }
643
Holger Hans Peter Freytherbd7b3c52010-11-01 21:04:54 +0100644 if (allocate_port(endp, &endp->trans_bts,
645 &endp->cfg->transcoder_ports,
646 mgcp_bind_trans_bts_rtp_port) != 0) {
647 mgcp_rtp_end_reset(&endp->net_end);
648 mgcp_rtp_end_reset(&endp->bts_end);
649 mgcp_rtp_end_reset(&endp->trans_net);
650 return -1;
651 }
652
Holger Hans Peter Freytherb54048f2010-11-01 19:57:50 +0100653 /* remember that we have set up transcoding */
Pablo Neira Ayuso46bd4242013-07-08 05:09:46 +0200654 endp->type = MGCP_RTP_TRANSCODED;
Holger Hans Peter Freyther218f8562010-09-18 02:30:02 +0800655 }
656
Holger Hans Peter Freytherf138f912010-08-05 08:08:17 +0800657 return 0;
658}
659
Jacob Erlbeck2c2ca4d2013-12-09 14:32:03 +0100660/* Set the LCO from a string (see RFC 3435).
661 * The string is stored in the 'string' field. A NULL string is handled excatly
662 * like an empty string, the 'string' field is never NULL after this function
663 * has been called. */
664static void set_local_cx_options(void *ctx, struct mgcp_lco *lco,
665 const char *options)
666{
Jacob Erlbeck452c1832014-05-09 19:42:17 +0200667 char *p_opt, *a_opt;
668 char codec[9];
Jacob Erlbeck2c2ca4d2013-12-09 14:32:03 +0100669
670 talloc_free(lco->string);
Jacob Erlbeck452c1832014-05-09 19:42:17 +0200671 talloc_free(lco->codec);
672 lco->codec = NULL;
Jacob Erlbeck2c2ca4d2013-12-09 14:32:03 +0100673 lco->pkt_period_min = lco->pkt_period_max = 0;
674 lco->string = talloc_strdup(ctx, options ? options : "");
675
676 p_opt = strstr(lco->string, "p:");
677 if (p_opt && sscanf(p_opt, "p:%d-%d",
678 &lco->pkt_period_min, &lco->pkt_period_max) == 1)
679 lco->pkt_period_max = lco->pkt_period_min;
Jacob Erlbeck452c1832014-05-09 19:42:17 +0200680
681 a_opt = strstr(lco->string, "a:");
682 if (a_opt && sscanf(a_opt, "a:%8[^,]", codec) == 1)
683 lco->codec = talloc_strdup(ctx, codec);
Jacob Erlbeck2c2ca4d2013-12-09 14:32:03 +0100684}
685
Jacob Erlbeckdb2d4312013-12-03 14:43:34 +0100686void mgcp_rtp_end_config(struct mgcp_endpoint *endp, int expect_ssrc_change,
687 struct mgcp_rtp_end *rtp)
688{
689 struct mgcp_trunk_config *tcfg = endp->tcfg;
690
Jacob Erlbecke2292f32013-12-03 15:13:12 +0100691 int patch_ssrc = expect_ssrc_change && tcfg->force_constant_ssrc;
692
Jacob Erlbeck4bbddc62013-12-18 12:54:51 +0100693 rtp->force_aligned_timing = tcfg->force_aligned_timing;
Jacob Erlbecke2292f32013-12-03 15:13:12 +0100694 rtp->force_constant_ssrc = patch_ssrc ? 1 : 0;
Jacob Erlbeckdb2d4312013-12-03 14:43:34 +0100695
696 LOGP(DMGCP, LOGL_DEBUG,
697 "Configuring RTP endpoint: local port %d%s%s\n",
698 ntohs(rtp->rtp_port),
Jacob Erlbeck4bbddc62013-12-18 12:54:51 +0100699 rtp->force_aligned_timing ? ", force constant timing" : "",
Jacob Erlbeckdb2d4312013-12-03 14:43:34 +0100700 rtp->force_constant_ssrc ? ", force constant ssrc" : "");
701}
702
Jacob Erlbeckf6ec0e92013-12-04 10:30:11 +0100703uint32_t mgcp_rtp_packet_duration(struct mgcp_endpoint *endp,
704 struct mgcp_rtp_end *rtp)
705{
706 int f = 0;
707
708 /* Get the number of frames per channel and packet */
709 if (rtp->frames_per_packet)
710 f = rtp->frames_per_packet;
Holger Hans Peter Freythercac24382014-09-01 10:35:55 +0200711 else if (rtp->packet_duration_ms && rtp->codec.frame_duration_num) {
712 int den = 1000 * rtp->codec.frame_duration_num;
713 f = (rtp->packet_duration_ms * rtp->codec.frame_duration_den + den/2)
Jacob Erlbeckf6ec0e92013-12-04 10:30:11 +0100714 / den;
715 }
716
Holger Hans Peter Freythercac24382014-09-01 10:35:55 +0200717 return rtp->codec.rate * f * rtp->codec.frame_duration_num / rtp->codec.frame_duration_den;
Jacob Erlbeckf6ec0e92013-12-04 10:30:11 +0100718}
719
Pablo Neira Ayusob769f3c2014-08-27 17:02:52 +0200720static int mgcp_parse_osmux_cid(const char *line)
721{
Pablo Neira Ayuso3ba3cf82014-08-29 08:46:05 +0200722 int osmux_cid;
Pablo Neira Ayusob769f3c2014-08-27 17:02:52 +0200723
Pablo Neira Ayuso3ba3cf82014-08-29 08:46:05 +0200724 if (sscanf(line + 2, "Osmux: %u", &osmux_cid) != 1)
725 return -1;
726
Pablo Neira Ayusob769f3c2014-08-27 17:02:52 +0200727 if (osmux_cid > OSMUX_CID_MAX) {
728 LOGP(DMGCP, LOGL_ERROR, "Osmux ID too large: %u > %u\n",
729 osmux_cid, OSMUX_CID_MAX);
730 return -1;
731 }
732 LOGP(DMGCP, LOGL_DEBUG, "bsc-nat offered Osmux CID %u\n", osmux_cid);
733
734 return osmux_cid;
735}
736
737static int mgcp_osmux_setup(struct mgcp_endpoint *endp, const char *line)
Pablo Neira Ayuso8be171e2014-08-27 14:58:43 +0200738{
739 if (!endp->cfg->osmux_init) {
740 if (osmux_init(OSMUX_ROLE_BSC, endp->cfg) < 0) {
741 LOGP(DMGCP, LOGL_ERROR, "Cannot init OSMUX\n");
742 return -1;
743 }
744 LOGP(DMGCP, LOGL_NOTICE, "OSMUX socket has been set up\n");
745 }
746
Pablo Neira Ayusob769f3c2014-08-27 17:02:52 +0200747 return mgcp_parse_osmux_cid(line);
Pablo Neira Ayuso8be171e2014-08-27 14:58:43 +0200748}
749
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100750static struct msgb *handle_create_con(struct mgcp_parse_data *p)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100751{
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +0100752 struct mgcp_trunk_config *tcfg;
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100753 struct mgcp_endpoint *endp = p->endp;
Holger Hans Peter Freyther9e9392d2010-08-08 16:24:48 +0800754 int error_code = 400;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100755
Holger Hans Peter Freyther3488c3d2011-07-20 20:44:54 +0200756 const char *local_options = NULL;
757 const char *callid = NULL;
758 const char *mode = NULL;
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100759 char *line;
Pablo Neira Ayusob769f3c2014-08-27 17:02:52 +0200760 int have_sdp = 0, osmux_cid = -1;
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100761
762 if (p->found != 0)
763 return create_err_response(NULL, 510, "CRCX", p->trans);
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +0100764
Holger Hans Peter Freyther3488c3d2011-07-20 20:44:54 +0200765 /* parse CallID C: and LocalParameters L: */
Jacob Erlbeck17711712013-11-29 13:43:46 +0100766 for_each_line(line, p->save) {
Holger Hans Peter Freyther1cc5ff82014-05-22 15:03:10 +0200767 if (!mgcp_check_param(endp, line))
768 continue;
769
Harald Welteae199722012-01-27 12:31:36 +0100770 switch (line[0]) {
771 case 'L':
772 local_options = (const char *) line + 3;
773 break;
774 case 'C':
775 callid = (const char *) line + 3;
776 break;
777 case 'M':
778 mode = (const char *) line + 3;
779 break;
Pablo Neira Ayusocab6e752014-02-05 18:56:17 +0100780 case 'X':
Pablo Neira Ayusob769f3c2014-08-27 17:02:52 +0200781 /* Osmux is not enabled in this bsc, ignore it so the
782 * bsc-nat knows that we don't want to use Osmux.
783 */
784 if (!p->endp->cfg->osmux)
785 break;
786
787 if (strncmp("Osmux: ", line + 2, strlen("Osmux: ")) == 0)
788 osmux_cid = mgcp_osmux_setup(endp, line);
Pablo Neira Ayusocab6e752014-02-05 18:56:17 +0100789 break;
Jacob Erlbeck78a95012013-11-29 13:43:49 +0100790 case '\0':
791 have_sdp = 1;
792 goto mgcp_header_done;
Harald Welteae199722012-01-27 12:31:36 +0100793 default:
794 LOGP(DMGCP, LOGL_NOTICE, "Unhandled option: '%c'/%d on 0x%x\n",
795 *line, *line, ENDPOINT_NUMBER(endp));
796 break;
797 }
Holger Hans Peter Freyther3488c3d2011-07-20 20:44:54 +0200798 }
Harald Welteae199722012-01-27 12:31:36 +0100799
Jacob Erlbeck78a95012013-11-29 13:43:49 +0100800mgcp_header_done:
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100801 tcfg = p->endp->tcfg;
Holger Hans Peter Freyther3488c3d2011-07-20 20:44:54 +0200802
803 /* Check required data */
804 if (!callid || !mode) {
805 LOGP(DMGCP, LOGL_ERROR, "Missing callid and mode in CRCX on 0x%x\n",
806 ENDPOINT_NUMBER(endp));
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100807 return create_err_response(endp, 400, "CRCX", p->trans);
Holger Hans Peter Freyther3488c3d2011-07-20 20:44:54 +0200808 }
809
Holger Hans Peter Freyther39a97e22010-08-06 18:03:11 +0800810 if (endp->allocated) {
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +0100811 if (tcfg->force_realloc) {
Holger Hans Peter Freyther408cc4a2010-04-07 10:51:27 +0200812 LOGP(DMGCP, LOGL_NOTICE, "Endpoint 0x%x already allocated. Forcing realloc.\n",
813 ENDPOINT_NUMBER(endp));
Holger Hans Peter Freythercb6ad702014-07-22 15:00:52 +0200814 mgcp_release_endp(endp);
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100815 if (p->cfg->realloc_cb)
816 p->cfg->realloc_cb(tcfg, ENDPOINT_NUMBER(endp));
Holger Hans Peter Freyther408cc4a2010-04-07 10:51:27 +0200817 } else {
818 LOGP(DMGCP, LOGL_ERROR, "Endpoint is already used. 0x%x\n",
819 ENDPOINT_NUMBER(endp));
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100820 return create_err_response(endp, 400, "CRCX", p->trans);
Holger Hans Peter Freyther408cc4a2010-04-07 10:51:27 +0200821 }
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100822 }
823
Holger Hans Peter Freyther3488c3d2011-07-20 20:44:54 +0200824 /* copy some parameters */
825 endp->callid = talloc_strdup(tcfg->endpoints, callid);
826
Jacob Erlbeck2c2ca4d2013-12-09 14:32:03 +0100827 set_local_cx_options(endp->tcfg->endpoints, &endp->local_options,
828 local_options);
Holger Hans Peter Freyther3488c3d2011-07-20 20:44:54 +0200829
Jacob Erlbeck2645c9e2013-12-19 12:23:24 +0100830 if (parse_conn_mode(mode, endp) != 0) {
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100831 error_code = 517;
832 goto error2;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100833 }
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100834
835 /* initialize */
Holger Hans Peter Freythera17d7012010-08-05 01:34:51 +0800836 endp->net_end.rtp_port = endp->net_end.rtcp_port = endp->bts_end.rtp_port = endp->bts_end.rtcp_port = 0;
Jacob Erlbeckdb2d4312013-12-03 14:43:34 +0100837 mgcp_rtp_end_config(endp, 0, &endp->net_end);
838 mgcp_rtp_end_config(endp, 0, &endp->bts_end);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100839
840 /* set to zero until we get the info */
Holger Hans Peter Freythera17d7012010-08-05 01:34:51 +0800841 memset(&endp->net_end.addr, 0, sizeof(endp->net_end.addr));
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100842
843 /* bind to the port now */
Holger Hans Peter Freytherf138f912010-08-05 08:08:17 +0800844 if (allocate_ports(endp) != 0)
845 goto error2;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100846
847 /* assign a local call identifier or fail */
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100848 endp->ci = generate_call_id(p->cfg);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100849 if (endp->ci == CI_UNUSED)
850 goto error2;
851
Daniel Willmann57542062016-06-29 16:24:42 +0200852 /* Annotate Osmux circuit ID and set it to negotiating state until this
Pablo Neira Ayusob769f3c2014-08-27 17:02:52 +0200853 * is fully set up from the dummy load.
854 */
855 endp->osmux.state = OSMUX_STATE_DISABLED;
856 if (osmux_cid >= 0) {
857 endp->osmux.cid = osmux_cid;
Daniel Willmann57542062016-06-29 16:24:42 +0200858 endp->osmux.state = OSMUX_STATE_NEGOTIATING;
Harald Welte7e5bb622016-09-28 08:20:58 +0800859 } else if (endp->cfg->osmux == OSMUX_USAGE_ONLY) {
Holger Hans Peter Freyther6598ded2015-10-02 17:38:27 +0200860 LOGP(DMGCP, LOGL_ERROR,
861 "Osmux only and no osmux offered on 0x%x\n", ENDPOINT_NUMBER(endp));
862 goto error2;
Pablo Neira Ayusob769f3c2014-08-27 17:02:52 +0200863 }
864
Holger Hans Peter Freyther39a97e22010-08-06 18:03:11 +0800865 endp->allocated = 1;
Jacob Erlbeck78a95012013-11-29 13:43:49 +0100866
867 /* set up RTP media parameters */
Holger Hans Peter Freythera611da82015-08-14 09:24:11 +0200868 mgcp_set_audio_info(p->cfg, &endp->bts_end.codec, tcfg->audio_payload, tcfg->audio_name);
Holger Hans Peter Freyther5ea1bc72012-09-03 00:07:39 +0200869 endp->bts_end.fmtp_extra = talloc_strdup(tcfg->endpoints,
870 tcfg->audio_fmtp_extra);
Jacob Erlbeck42a833e2014-04-14 10:31:47 +0200871 if (have_sdp)
Holger Hans Peter Freytheraeadf262015-08-14 15:43:06 +0200872 mgcp_parse_sdp_data(endp, &endp->net_end, p);
Jacob Erlbeck452c1832014-05-09 19:42:17 +0200873 else if (endp->local_options.codec)
Holger Hans Peter Freythera611da82015-08-14 09:24:11 +0200874 mgcp_set_audio_info(p->cfg, &endp->net_end.codec,
Jacob Erlbeck452c1832014-05-09 19:42:17 +0200875 PTYPE_UNDEFINED, endp->local_options.codec);
Jacob Erlbeck42a833e2014-04-14 10:31:47 +0200876
877 if (p->cfg->bts_force_ptime) {
878 endp->bts_end.packet_duration_ms = p->cfg->bts_force_ptime;
879 endp->bts_end.force_output_ptime = 1;
Jacob Erlbecka0d64ce2014-03-13 14:24:52 +0100880 }
Holger Hans Peter Freytheref6bb252010-02-26 13:41:22 +0100881
Holger Hans Peter Freyther7cce1d32015-03-26 20:34:12 +0100882 if (setup_rtp_processing(endp) != 0)
883 goto error2;
Jacob Erlbeck42a833e2014-04-14 10:31:47 +0200884
Holger Hans Peter Freytherfe86d3c2010-02-26 13:37:05 +0100885 /* policy CB */
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100886 if (p->cfg->policy_cb) {
887 int rc;
888 rc = p->cfg->policy_cb(tcfg, ENDPOINT_NUMBER(endp),
889 MGCP_ENDP_CRCX, p->trans);
890 switch (rc) {
Holger Hans Peter Freytherfe86d3c2010-02-26 13:37:05 +0100891 case MGCP_POLICY_REJECT:
892 LOGP(DMGCP, LOGL_NOTICE, "CRCX rejected by policy on 0x%x\n",
893 ENDPOINT_NUMBER(endp));
Holger Hans Peter Freythercb6ad702014-07-22 15:00:52 +0200894 mgcp_release_endp(endp);
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100895 return create_err_response(endp, 400, "CRCX", p->trans);
Holger Hans Peter Freytherfe86d3c2010-02-26 13:37:05 +0100896 break;
897 case MGCP_POLICY_DEFER:
898 /* stop processing */
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +0800899 create_transcoder(endp);
Holger Hans Peter Freytherfe86d3c2010-02-26 13:37:05 +0100900 return NULL;
901 break;
902 case MGCP_POLICY_CONT:
903 /* just continue */
904 break;
905 }
906 }
907
Holger Hans Peter Freythere378cb12010-08-06 20:22:23 +0800908 LOGP(DMGCP, LOGL_DEBUG, "Creating endpoint on: 0x%x CI: %u port: %u/%u\n",
Holger Hans Peter Freyther58ff2192010-08-05 03:08:35 +0800909 ENDPOINT_NUMBER(endp), endp->ci,
910 endp->net_end.local_port, endp->bts_end.local_port);
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100911 if (p->cfg->change_cb)
912 p->cfg->change_cb(tcfg, ENDPOINT_NUMBER(endp), MGCP_ENDP_CRCX);
Holger Hans Peter Freyther77f7afe2010-02-03 09:54:43 +0100913
Pablo Neira Ayusocab6e752014-02-05 18:56:17 +0100914 if (endp->conn_mode & MGCP_CONN_RECV_ONLY && tcfg->keepalive_interval != 0) {
Holger Hans Peter Freyther6b0ba012014-07-08 13:01:56 +0200915 send_dummy(endp);
Pablo Neira Ayusocab6e752014-02-05 18:56:17 +0100916 }
Jacob Erlbeck075a9eb2013-12-19 18:53:07 +0100917
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +0800918 create_transcoder(endp);
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100919 return create_response_with_sdp(endp, "CRCX", p->trans);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100920error2:
Holger Hans Peter Freythercb6ad702014-07-22 15:00:52 +0200921 mgcp_release_endp(endp);
Holger Hans Peter Freyther2ada71d2010-02-03 09:13:10 +0100922 LOGP(DMGCP, LOGL_NOTICE, "Resource error on 0x%x\n", ENDPOINT_NUMBER(endp));
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100923 return create_err_response(endp, error_code, "CRCX", p->trans);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100924}
925
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100926static struct msgb *handle_modify_con(struct mgcp_parse_data *p)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100927{
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100928 struct mgcp_endpoint *endp = p->endp;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100929 int error_code = 500;
Pablo Neira Ayusob769f3c2014-08-27 17:02:52 +0200930 int silent = 0;
Jacob Erlbeck452c1832014-05-09 19:42:17 +0200931 int have_sdp = 0;
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100932 char *line;
Jacob Erlbeck2c2ca4d2013-12-09 14:32:03 +0100933 const char *local_options = NULL;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100934
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100935 if (p->found != 0)
936 return create_err_response(NULL, 510, "MDCX", p->trans);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100937
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100938 if (endp->ci == CI_UNUSED) {
939 LOGP(DMGCP, LOGL_ERROR, "Endpoint is not "
940 "holding a connection. 0x%x\n", ENDPOINT_NUMBER(endp));
941 return create_err_response(endp, 400, "MDCX", p->trans);
942 }
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100943
Jacob Erlbeck17711712013-11-29 13:43:46 +0100944 for_each_line(line, p->save) {
Holger Hans Peter Freyther1cc5ff82014-05-22 15:03:10 +0200945 if (!mgcp_check_param(endp, line))
946 continue;
947
Harald Welteae199722012-01-27 12:31:36 +0100948 switch (line[0]) {
949 case 'C': {
950 if (verify_call_id(endp, line + 3) != 0)
951 goto error3;
952 break;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100953 }
Harald Welteae199722012-01-27 12:31:36 +0100954 case 'I': {
955 if (verify_ci(endp, line + 3) != 0)
956 goto error3;
957 break;
958 }
959 case 'L':
Jacob Erlbeck2c2ca4d2013-12-09 14:32:03 +0100960 local_options = (const char *) line + 3;
Harald Welteae199722012-01-27 12:31:36 +0100961 break;
962 case 'M':
Jacob Erlbeck2645c9e2013-12-19 12:23:24 +0100963 if (parse_conn_mode(line + 3, endp) != 0) {
Harald Welteae199722012-01-27 12:31:36 +0100964 error_code = 517;
965 goto error3;
966 }
967 endp->orig_mode = endp->conn_mode;
968 break;
969 case 'Z':
970 silent = strcmp("noanswer", line + 3) == 0;
971 break;
972 case '\0':
973 /* SDP file begins */
Jacob Erlbeck452c1832014-05-09 19:42:17 +0200974 have_sdp = 1;
Holger Hans Peter Freytheraeadf262015-08-14 15:43:06 +0200975 mgcp_parse_sdp_data(endp, &endp->net_end, p);
Jacob Erlbeck17711712013-11-29 13:43:46 +0100976 /* This will exhaust p->save, so the loop will
977 * terminate next time.
978 */
Harald Welteae199722012-01-27 12:31:36 +0100979 break;
Harald Welteae199722012-01-27 12:31:36 +0100980 default:
Jacob Erlbeck17711712013-11-29 13:43:46 +0100981 LOGP(DMGCP, LOGL_NOTICE, "Unhandled MGCP option: '%c'/%d on 0x%x\n",
Harald Welteae199722012-01-27 12:31:36 +0100982 line[0], line[0], ENDPOINT_NUMBER(endp));
983 break;
984 }
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100985 }
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100986
Jacob Erlbeck2c2ca4d2013-12-09 14:32:03 +0100987 set_local_cx_options(endp->tcfg->endpoints, &endp->local_options,
988 local_options);
989
Jacob Erlbeck452c1832014-05-09 19:42:17 +0200990 if (!have_sdp && endp->local_options.codec)
Holger Hans Peter Freythera611da82015-08-14 09:24:11 +0200991 mgcp_set_audio_info(p->cfg, &endp->net_end.codec,
Jacob Erlbeck452c1832014-05-09 19:42:17 +0200992 PTYPE_UNDEFINED, endp->local_options.codec);
993
Holger Hans Peter Freyther7cce1d32015-03-26 20:34:12 +0100994 if (setup_rtp_processing(endp) != 0)
995 goto error3;
Jacob Erlbecka0d64ce2014-03-13 14:24:52 +0100996
Holger Hans Peter Freytherfe86d3c2010-02-26 13:37:05 +0100997 /* policy CB */
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100998 if (p->cfg->policy_cb) {
999 int rc;
1000 rc = p->cfg->policy_cb(endp->tcfg, ENDPOINT_NUMBER(endp),
1001 MGCP_ENDP_MDCX, p->trans);
1002 switch (rc) {
Holger Hans Peter Freytherfe86d3c2010-02-26 13:37:05 +01001003 case MGCP_POLICY_REJECT:
1004 LOGP(DMGCP, LOGL_NOTICE, "MDCX rejected by policy on 0x%x\n",
1005 ENDPOINT_NUMBER(endp));
Holger Hans Peter Freythere3d16bb2010-04-22 11:58:13 +08001006 if (silent)
1007 goto out_silent;
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +01001008 return create_err_response(endp, 400, "MDCX", p->trans);
Holger Hans Peter Freytherfe86d3c2010-02-26 13:37:05 +01001009 break;
1010 case MGCP_POLICY_DEFER:
1011 /* stop processing */
Neels Hofmeyra1756f32016-05-20 21:59:55 +02001012 LOGP(DMGCP, LOGL_DEBUG, "endp %x MDCX defer\n",
1013 ENDPOINT_NUMBER(endp));
Holger Hans Peter Freytherfe86d3c2010-02-26 13:37:05 +01001014 return NULL;
1015 break;
1016 case MGCP_POLICY_CONT:
1017 /* just continue */
1018 break;
1019 }
1020 }
1021
Jacob Erlbeckdb2d4312013-12-03 14:43:34 +01001022 mgcp_rtp_end_config(endp, 1, &endp->net_end);
1023 mgcp_rtp_end_config(endp, 1, &endp->bts_end);
1024
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +01001025 /* modify */
Holger Hans Peter Freythere378cb12010-08-06 20:22:23 +08001026 LOGP(DMGCP, LOGL_DEBUG, "Modified endpoint on: 0x%x Server: %s:%u\n",
Holger Hans Peter Freythera17d7012010-08-05 01:34:51 +08001027 ENDPOINT_NUMBER(endp), inet_ntoa(endp->net_end.addr), ntohs(endp->net_end.rtp_port));
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +01001028 if (p->cfg->change_cb)
1029 p->cfg->change_cb(endp->tcfg, ENDPOINT_NUMBER(endp), MGCP_ENDP_MDCX);
Jacob Erlbeck075a9eb2013-12-19 18:53:07 +01001030
Jacob Erlbecke35fd132014-01-16 16:50:40 +01001031 if (endp->conn_mode & MGCP_CONN_RECV_ONLY &&
1032 endp->tcfg->keepalive_interval != 0)
Holger Hans Peter Freyther6b0ba012014-07-08 13:01:56 +02001033 send_dummy(endp);
Jacob Erlbeck075a9eb2013-12-19 18:53:07 +01001034
Holger Hans Peter Freythere3d16bb2010-04-22 11:58:13 +08001035 if (silent)
1036 goto out_silent;
1037
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +01001038 return create_response_with_sdp(endp, "MDCX", p->trans);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +01001039
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +01001040error3:
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +01001041 return create_err_response(endp, error_code, "MDCX", p->trans);
Holger Hans Peter Freythere3d16bb2010-04-22 11:58:13 +08001042
1043
1044out_silent:
Neels Hofmeyra1756f32016-05-20 21:59:55 +02001045 LOGP(DMGCP, LOGL_DEBUG, "endp %x Modify endpoint: silent exit\n",
1046 ENDPOINT_NUMBER(endp));
Holger Hans Peter Freythere3d16bb2010-04-22 11:58:13 +08001047 return NULL;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +01001048}
1049
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +01001050static struct msgb *handle_delete_con(struct mgcp_parse_data *p)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +01001051{
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +01001052 struct mgcp_endpoint *endp = p->endp;
Holger Hans Peter Freyther9e9392d2010-08-08 16:24:48 +08001053 int error_code = 400;
Holger Hans Peter Freythere3d16bb2010-04-22 11:58:13 +08001054 int silent = 0;
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +01001055 char *line;
Holger Hans Peter Freyther0bf15a82012-09-14 17:18:12 +02001056 char stats[1048];
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +01001057
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +01001058 if (p->found != 0)
1059 return create_err_response(NULL, error_code, "DLCX", p->trans);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +01001060
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +01001061 if (!p->endp->allocated) {
1062 LOGP(DMGCP, LOGL_ERROR, "Endpoint is not used. 0x%x\n",
1063 ENDPOINT_NUMBER(endp));
1064 return create_err_response(endp, 400, "DLCX", p->trans);
1065 }
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +01001066
Jacob Erlbeck17711712013-11-29 13:43:46 +01001067 for_each_line(line, p->save) {
Holger Hans Peter Freyther1cc5ff82014-05-22 15:03:10 +02001068 if (!mgcp_check_param(endp, line))
1069 continue;
1070
Harald Welteae199722012-01-27 12:31:36 +01001071 switch (line[0]) {
1072 case 'C':
1073 if (verify_call_id(endp, line + 3) != 0)
1074 goto error3;
1075 break;
1076 case 'I':
1077 if (verify_ci(endp, line + 3) != 0)
1078 goto error3;
1079 break;
1080 case 'Z':
1081 silent = strcmp("noanswer", line + 3) == 0;
1082 break;
1083 default:
1084 LOGP(DMGCP, LOGL_NOTICE, "Unhandled option: '%c'/%d on 0x%x\n",
1085 line[0], line[0], ENDPOINT_NUMBER(endp));
1086 break;
1087 }
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +01001088 }
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +01001089
Holger Hans Peter Freytherfe86d3c2010-02-26 13:37:05 +01001090 /* policy CB */
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +01001091 if (p->cfg->policy_cb) {
1092 int rc;
1093 rc = p->cfg->policy_cb(endp->tcfg, ENDPOINT_NUMBER(endp),
1094 MGCP_ENDP_DLCX, p->trans);
1095 switch (rc) {
Holger Hans Peter Freytherfe86d3c2010-02-26 13:37:05 +01001096 case MGCP_POLICY_REJECT:
1097 LOGP(DMGCP, LOGL_NOTICE, "DLCX rejected by policy on 0x%x\n",
1098 ENDPOINT_NUMBER(endp));
Holger Hans Peter Freythere3d16bb2010-04-22 11:58:13 +08001099 if (silent)
1100 goto out_silent;
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +01001101 return create_err_response(endp, 400, "DLCX", p->trans);
Holger Hans Peter Freytherfe86d3c2010-02-26 13:37:05 +01001102 break;
1103 case MGCP_POLICY_DEFER:
1104 /* stop processing */
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +08001105 delete_transcoder(endp);
Holger Hans Peter Freytherfe86d3c2010-02-26 13:37:05 +01001106 return NULL;
1107 break;
1108 case MGCP_POLICY_CONT:
1109 /* just continue */
1110 break;
1111 }
1112 }
1113
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +01001114 /* free the connection */
Holger Hans Peter Freythere378cb12010-08-06 20:22:23 +08001115 LOGP(DMGCP, LOGL_DEBUG, "Deleted endpoint on: 0x%x Server: %s:%u\n",
Holger Hans Peter Freythera17d7012010-08-05 01:34:51 +08001116 ENDPOINT_NUMBER(endp), inet_ntoa(endp->net_end.addr), ntohs(endp->net_end.rtp_port));
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +08001117
Holger Hans Peter Freyther0bf15a82012-09-14 17:18:12 +02001118 /* save the statistics of the current call */
1119 mgcp_format_stats(endp, stats, sizeof(stats));
1120
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +08001121 delete_transcoder(endp);
Holger Hans Peter Freythercb6ad702014-07-22 15:00:52 +02001122 mgcp_release_endp(endp);
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +01001123 if (p->cfg->change_cb)
1124 p->cfg->change_cb(endp->tcfg, ENDPOINT_NUMBER(endp), MGCP_ENDP_DLCX);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +01001125
Holger Hans Peter Freythere3d16bb2010-04-22 11:58:13 +08001126 if (silent)
1127 goto out_silent;
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +01001128 return create_ok_resp_with_param(endp, 250, "DLCX", p->trans, stats);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +01001129
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +01001130error3:
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +01001131 return create_err_response(endp, error_code, "DLCX", p->trans);
Holger Hans Peter Freythere3d16bb2010-04-22 11:58:13 +08001132
1133out_silent:
1134 return NULL;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +01001135}
1136
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +01001137static struct msgb *handle_rsip(struct mgcp_parse_data *p)
Holger Hans Peter Freyther9bdcc9c2010-03-31 06:39:35 +02001138{
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +01001139 if (p->found != 0) {
Holger Hans Peter Freyther74db7742011-06-10 00:04:55 +02001140 LOGP(DMGCP, LOGL_ERROR, "Failed to find the endpoint.\n");
1141 return NULL;
1142 }
1143
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +01001144 if (p->cfg->reset_cb)
1145 p->cfg->reset_cb(p->endp->tcfg);
Holger Hans Peter Freyther9bdcc9c2010-03-31 06:39:35 +02001146 return NULL;
1147}
1148
Holger Hans Peter Freyther8d0be252012-11-29 12:54:22 +01001149static char extract_tone(const char *line)
1150{
1151 const char *str = strstr(line, "D/");
1152 if (!str)
1153 return CHAR_MAX;
1154
1155 return str[2];
1156}
1157
Holger Hans Peter Freyther6e94d6d2011-01-25 23:33:54 +01001158/*
1159 * This can request like DTMF detection and forward, fax detection... it
1160 * can also request when the notification should be send and such. We don't
1161 * do this right now.
1162 */
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +01001163static struct msgb *handle_noti_req(struct mgcp_parse_data *p)
Holger Hans Peter Freyther6e94d6d2011-01-25 23:33:54 +01001164{
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +01001165 int res = 0;
1166 char *line;
Holger Hans Peter Freyther9f3835b2013-05-21 17:04:35 +02001167 char tone = CHAR_MAX;
Holger Hans Peter Freyther6e94d6d2011-01-25 23:33:54 +01001168
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +01001169 if (p->found != 0)
1170 return create_err_response(NULL, 400, "RQNT", p->trans);
Holger Hans Peter Freyther6e94d6d2011-01-25 23:33:54 +01001171
Jacob Erlbeck17711712013-11-29 13:43:46 +01001172 for_each_line(line, p->save) {
Holger Hans Peter Freyther8d0be252012-11-29 12:54:22 +01001173 switch (line[0]) {
1174 case 'S':
1175 tone = extract_tone(line);
1176 break;
1177 }
Holger Hans Peter Freyther6e94d6d2011-01-25 23:33:54 +01001178 }
Holger Hans Peter Freyther8d0be252012-11-29 12:54:22 +01001179
1180 /* we didn't see a signal request with a tone */
1181 if (tone == CHAR_MAX)
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +01001182 return create_ok_response(p->endp, 200, "RQNT", p->trans);
Holger Hans Peter Freyther8d0be252012-11-29 12:54:22 +01001183
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +01001184 if (p->cfg->rqnt_cb)
1185 res = p->cfg->rqnt_cb(p->endp, tone);
Holger Hans Peter Freyther8d0be252012-11-29 12:54:22 +01001186
1187 return res == 0 ?
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +01001188 create_ok_response(p->endp, 200, "RQNT", p->trans) :
1189 create_err_response(p->endp, res, "RQNT", p->trans);
Holger Hans Peter Freyther6e94d6d2011-01-25 23:33:54 +01001190}
1191
Jacob Erlbeck075a9eb2013-12-19 18:53:07 +01001192static void mgcp_keepalive_timer_cb(void *_tcfg)
1193{
1194 struct mgcp_trunk_config *tcfg = _tcfg;
1195 int i;
1196 LOGP(DMGCP, LOGL_DEBUG, "Triggered trunk %d keepalive timer.\n",
1197 tcfg->trunk_nr);
1198
1199 if (tcfg->keepalive_interval <= 0)
1200 return;
1201
1202 for (i = 1; i < tcfg->number_endpoints; ++i) {
1203 struct mgcp_endpoint *endp = &tcfg->endpoints[i];
1204 if (endp->conn_mode == MGCP_CONN_RECV_ONLY)
Holger Hans Peter Freyther6b0ba012014-07-08 13:01:56 +02001205 send_dummy(endp);
Jacob Erlbeck075a9eb2013-12-19 18:53:07 +01001206 }
1207
1208 LOGP(DMGCP, LOGL_DEBUG, "Rescheduling trunk %d keepalive timer.\n",
1209 tcfg->trunk_nr);
1210 osmo_timer_schedule(&tcfg->keepalive_timer, tcfg->keepalive_interval, 0);
1211}
1212
1213void mgcp_trunk_set_keepalive(struct mgcp_trunk_config *tcfg, int interval)
1214{
1215 tcfg->keepalive_interval = interval;
Pablo Neira Ayuso51215762017-05-08 20:57:52 +02001216 osmo_timer_setup(&tcfg->keepalive_timer, mgcp_keepalive_timer_cb, tcfg);
Jacob Erlbeck075a9eb2013-12-19 18:53:07 +01001217
1218 if (interval <= 0)
1219 osmo_timer_del(&tcfg->keepalive_timer);
1220 else
1221 osmo_timer_schedule(&tcfg->keepalive_timer,
1222 tcfg->keepalive_interval, 0);
1223}
1224
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +01001225struct mgcp_config *mgcp_config_alloc(void)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +01001226{
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +01001227 struct mgcp_config *cfg;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +01001228
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +01001229 cfg = talloc_zero(NULL, struct mgcp_config);
1230 if (!cfg) {
1231 LOGP(DMGCP, LOGL_FATAL, "Failed to allocate config.\n");
1232 return NULL;
1233 }
1234
1235 cfg->source_port = 2427;
1236 cfg->source_addr = talloc_strdup(cfg, "0.0.0.0");
Holger Hans Peter Freythera777c9e2015-10-12 20:06:16 +02001237 cfg->osmux_addr = talloc_strdup(cfg, "0.0.0.0");
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +01001238
Holger Hans Peter Freytherb98ba722010-09-19 04:21:39 +08001239 cfg->transcoder_remote_base = 4000;
Holger Hans Peter Freyther15e73892010-08-05 07:10:56 +08001240
1241 cfg->bts_ports.base_port = RTP_PORT_DEFAULT;
1242 cfg->net_ports.base_port = RTP_PORT_NET_DEFAULT;
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +01001243
Jacob Erlbecka0d64ce2014-03-13 14:24:52 +01001244 cfg->rtp_processing_cb = &mgcp_rtp_processing_default;
1245 cfg->setup_rtp_processing_cb = &mgcp_setup_rtp_processing_default;
1246
Jacob Erlbeck168ca002014-03-17 12:40:07 +01001247 cfg->get_net_downlink_format_cb = &mgcp_get_net_downlink_format_default;
1248
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +01001249 /* default trunk handling */
1250 cfg->trunk.cfg = cfg;
1251 cfg->trunk.trunk_nr = 0;
1252 cfg->trunk.trunk_type = MGCP_TRUNK_VIRTUAL;
1253 cfg->trunk.audio_name = talloc_strdup(cfg, "AMR/8000");
1254 cfg->trunk.audio_payload = 126;
Jacob Erlbeck0a1bc562013-12-10 13:09:37 +01001255 cfg->trunk.audio_send_ptime = 1;
Holger Hans Peter Freyther619b0142014-11-19 16:04:45 +01001256 cfg->trunk.audio_send_name = 1;
Holger Hans Peter Freythera8090d52012-05-11 13:00:45 +02001257 cfg->trunk.omit_rtcp = 0;
Jacob Erlbeck075a9eb2013-12-19 18:53:07 +01001258 mgcp_trunk_set_keepalive(&cfg->trunk, MGCP_KEEPALIVE_ONCE);
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +01001259
Holger Hans Peter Freyther0e939fe2011-02-28 12:11:02 +01001260 INIT_LLIST_HEAD(&cfg->trunks);
1261
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +01001262 return cfg;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +01001263}
1264
Holger Hans Peter Freyther0e939fe2011-02-28 12:11:02 +01001265struct mgcp_trunk_config *mgcp_trunk_alloc(struct mgcp_config *cfg, int nr)
1266{
1267 struct mgcp_trunk_config *trunk;
1268
1269 trunk = talloc_zero(cfg, struct mgcp_trunk_config);
1270 if (!trunk) {
1271 LOGP(DMGCP, LOGL_ERROR, "Failed to allocate.\n");
1272 return NULL;
1273 }
1274
1275 trunk->cfg = cfg;
1276 trunk->trunk_type = MGCP_TRUNK_E1;
1277 trunk->trunk_nr = nr;
1278 trunk->audio_name = talloc_strdup(cfg, "AMR/8000");
1279 trunk->audio_payload = 126;
Jacob Erlbeck0a1bc562013-12-10 13:09:37 +01001280 trunk->audio_send_ptime = 1;
Holger Hans Peter Freyther619b0142014-11-19 16:04:45 +01001281 trunk->audio_send_name = 1;
Holger Hans Peter Freyther0e939fe2011-02-28 12:11:02 +01001282 trunk->number_endpoints = 33;
Holger Hans Peter Freythera8090d52012-05-11 13:00:45 +02001283 trunk->omit_rtcp = 0;
Jacob Erlbeck075a9eb2013-12-19 18:53:07 +01001284 mgcp_trunk_set_keepalive(trunk, MGCP_KEEPALIVE_ONCE);
Holger Hans Peter Freyther0e939fe2011-02-28 12:11:02 +01001285 llist_add_tail(&trunk->entry, &cfg->trunks);
1286 return trunk;
1287}
1288
1289struct mgcp_trunk_config *mgcp_trunk_num(struct mgcp_config *cfg, int index)
1290{
1291 struct mgcp_trunk_config *trunk;
1292
1293 llist_for_each_entry(trunk, &cfg->trunks, entry)
1294 if (trunk->trunk_nr == index)
1295 return trunk;
1296
1297 return NULL;
1298}
1299
Holger Hans Peter Freytherfa80d072014-09-01 10:40:19 +02001300static void mgcp_rtp_codec_reset(struct mgcp_rtp_codec *codec)
1301{
1302 codec->payload_type = -1;
1303 talloc_free(codec->subtype_name);
1304 codec->subtype_name = NULL;
1305 talloc_free(codec->audio_name);
1306 codec->audio_name = NULL;
1307 codec->frame_duration_num = DEFAULT_RTP_AUDIO_FRAME_DUR_NUM;
1308 codec->frame_duration_den = DEFAULT_RTP_AUDIO_FRAME_DUR_DEN;
1309 codec->rate = DEFAULT_RTP_AUDIO_DEFAULT_RATE;
1310 codec->channels = DEFAULT_RTP_AUDIO_DEFAULT_CHANNELS;
1311}
1312
Holger Hans Peter Freythera17d7012010-08-05 01:34:51 +08001313static void mgcp_rtp_end_reset(struct mgcp_rtp_end *end)
1314{
Holger Hans Peter Freythere97155a2010-11-02 19:06:13 +01001315 if (end->local_alloc == PORT_ALLOC_DYNAMIC) {
Holger Hans Peter Freytherf138f912010-08-05 08:08:17 +08001316 mgcp_free_rtp_port(end);
Holger Hans Peter Freythere97155a2010-11-02 19:06:13 +01001317 end->local_port = 0;
1318 }
Holger Hans Peter Freytherf138f912010-08-05 08:08:17 +08001319
Holger Hans Peter Freytherc4921272010-08-05 03:37:22 +08001320 end->packets = 0;
Holger Hans Peter Freyther952f7522012-09-12 11:38:37 +02001321 end->octets = 0;
Jacob Erlbeck0970bab2013-12-19 12:13:32 +01001322 end->dropped_packets = 0;
Holger Hans Peter Freytherc4921272010-08-05 03:37:22 +08001323 memset(&end->addr, 0, sizeof(end->addr));
Holger Hans Peter Freythere97155a2010-11-02 19:06:13 +01001324 end->rtp_port = end->rtcp_port = 0;
Holger Hans Peter Freytherf138f912010-08-05 08:08:17 +08001325 end->local_alloc = -1;
Holger Hans Peter Freyther5ea1bc72012-09-03 00:07:39 +02001326 talloc_free(end->fmtp_extra);
1327 end->fmtp_extra = NULL;
Jacob Erlbecka0d64ce2014-03-13 14:24:52 +01001328 talloc_free(end->rtp_process_data);
1329 end->rtp_process_data = NULL;
Jacob Erlbeck72c30902013-11-25 15:23:35 +01001330
1331 /* Set default values */
Jacob Erlbeckf6ec0e92013-12-04 10:30:11 +01001332 end->frames_per_packet = 0; /* unknown */
1333 end->packet_duration_ms = DEFAULT_RTP_AUDIO_PACKET_DURATION_MS;
Jacob Erlbeck8857c902014-01-16 16:50:39 +01001334 end->output_enabled = 0;
Holger Hans Peter Freytherfa80d072014-09-01 10:40:19 +02001335
1336 mgcp_rtp_codec_reset(&end->codec);
Holger Hans Peter Freythere46bc272014-09-01 10:50:22 +02001337 mgcp_rtp_codec_reset(&end->alt_codec);
Holger Hans Peter Freythera17d7012010-08-05 01:34:51 +08001338}
1339
Holger Hans Peter Freytherc4921272010-08-05 03:37:22 +08001340static void mgcp_rtp_end_init(struct mgcp_rtp_end *end)
1341{
1342 mgcp_rtp_end_reset(end);
1343 end->rtp.fd = -1;
1344 end->rtcp.fd = -1;
1345}
1346
Holger Hans Peter Freyther1f0c5b42011-02-28 14:37:03 +01001347int mgcp_endpoints_allocate(struct mgcp_trunk_config *tcfg)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +01001348{
1349 int i;
1350
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +01001351 /* Initialize all endpoints */
Holger Hans Peter Freyther1f0c5b42011-02-28 14:37:03 +01001352 tcfg->endpoints = _talloc_zero_array(tcfg->cfg,
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +01001353 sizeof(struct mgcp_endpoint),
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +01001354 tcfg->number_endpoints, "endpoints");
1355 if (!tcfg->endpoints)
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +01001356 return -1;
1357
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +01001358 for (i = 0; i < tcfg->number_endpoints; ++i) {
Holger Hans Peter Freyther1afe7c72015-10-04 11:11:11 +02001359 tcfg->endpoints[i].osmux.allocated_cid = -1;
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +01001360 tcfg->endpoints[i].ci = CI_UNUSED;
Holger Hans Peter Freyther1f0c5b42011-02-28 14:37:03 +01001361 tcfg->endpoints[i].cfg = tcfg->cfg;
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +01001362 tcfg->endpoints[i].tcfg = tcfg;
1363 mgcp_rtp_end_init(&tcfg->endpoints[i].net_end);
1364 mgcp_rtp_end_init(&tcfg->endpoints[i].bts_end);
1365 mgcp_rtp_end_init(&tcfg->endpoints[i].trans_net);
1366 mgcp_rtp_end_init(&tcfg->endpoints[i].trans_bts);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +01001367 }
1368
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +01001369 return 0;
1370}
Holger Hans Peter Freyther154b9552010-02-26 13:27:51 +01001371
Holger Hans Peter Freythercb6ad702014-07-22 15:00:52 +02001372void mgcp_release_endp(struct mgcp_endpoint *endp)
Holger Hans Peter Freyther154b9552010-02-26 13:27:51 +01001373{
Holger Hans Peter Freythercb6ad702014-07-22 15:00:52 +02001374 LOGP(DMGCP, LOGL_DEBUG, "Releasing endpoint on: 0x%x\n", ENDPOINT_NUMBER(endp));
Holger Hans Peter Freyther89976e82010-08-03 15:01:43 +00001375 endp->ci = CI_UNUSED;
Holger Hans Peter Freyther39a97e22010-08-06 18:03:11 +08001376 endp->allocated = 0;
Holger Hans Peter Freyther154b9552010-02-26 13:27:51 +01001377
Holger Hans Peter Freyther01d315f2012-12-07 11:52:16 +01001378 talloc_free(endp->callid);
1379 endp->callid = NULL;
Holger Hans Peter Freyther154b9552010-02-26 13:27:51 +01001380
Jacob Erlbeck2c2ca4d2013-12-09 14:32:03 +01001381 talloc_free(endp->local_options.string);
1382 endp->local_options.string = NULL;
Jacob Erlbeck452c1832014-05-09 19:42:17 +02001383 talloc_free(endp->local_options.codec);
1384 endp->local_options.codec = NULL;
Holger Hans Peter Freyther154b9552010-02-26 13:27:51 +01001385
Holger Hans Peter Freythera17d7012010-08-05 01:34:51 +08001386 mgcp_rtp_end_reset(&endp->bts_end);
1387 mgcp_rtp_end_reset(&endp->net_end);
Holger Hans Peter Freyther21262332010-11-01 20:53:31 +01001388 mgcp_rtp_end_reset(&endp->trans_net);
Holger Hans Peter Freytherbd7b3c52010-11-01 21:04:54 +01001389 mgcp_rtp_end_reset(&endp->trans_bts);
Pablo Neira Ayuso46bd4242013-07-08 05:09:46 +02001390 endp->type = MGCP_RTP_DEFAULT;
Holger Hans Peter Freyther380b8712010-07-29 02:38:39 +08001391
Holger Hans Peter Freyther31868922010-08-03 11:59:04 +00001392 memset(&endp->net_state, 0, sizeof(endp->net_state));
1393 memset(&endp->bts_state, 0, sizeof(endp->bts_state));
Holger Hans Peter Freytherc597a4e2010-08-03 02:57:02 +08001394
1395 endp->conn_mode = endp->orig_mode = MGCP_CONN_NONE;
Holger Hans Peter Freyther260d6ed2010-08-06 01:12:21 +08001396
Pablo Neira Ayusob769f3c2014-08-27 17:02:52 +02001397 if (endp->osmux.state == OSMUX_STATE_ENABLED)
1398 osmux_disable_endpoint(endp);
1399
Holger Hans Peter Freyther1afe7c72015-10-04 11:11:11 +02001400 /* release the circuit ID if it had been allocated */
1401 osmux_release_cid(endp);
1402
Holger Hans Peter Freyther260d6ed2010-08-06 01:12:21 +08001403 memset(&endp->taps, 0, sizeof(endp->taps));
Holger Hans Peter Freyther154b9552010-02-26 13:27:51 +01001404}
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +08001405
Holger Hans Peter Freythercb6ad702014-07-22 15:00:52 +02001406void mgcp_initialize_endp(struct mgcp_endpoint *endp)
1407{
1408 return mgcp_release_endp(endp);
1409}
1410
Holger Hans Peter Freyther557b1ab2010-09-19 04:39:55 +08001411static int send_trans(struct mgcp_config *cfg, const char *buf, int len)
1412{
1413 struct sockaddr_in addr;
1414
1415 memset(&addr, 0, sizeof(addr));
1416 addr.sin_family = AF_INET;
1417 addr.sin_addr = cfg->transcoder_in;
1418 addr.sin_port = htons(2427);
1419 return sendto(cfg->gw_fd.bfd.fd, buf, len, 0,
1420 (struct sockaddr *) &addr, sizeof(addr));
1421}
1422
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +08001423static void send_msg(struct mgcp_endpoint *endp, int endpoint, int port,
1424 const char *msg, const char *mode)
1425{
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +08001426 char buf[2096];
1427 int len;
Jacob Erlbeck997e1e82014-03-14 18:01:20 +01001428 int nchars;
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +08001429
1430 /* hardcoded to AMR right now, we do not know the real type at this point */
1431 len = snprintf(buf, sizeof(buf),
1432 "%s 42 %x@mgw MGCP 1.0\r\n"
1433 "C: 4256\r\n"
1434 "M: %s\r\n"
Jacob Erlbeck997e1e82014-03-14 18:01:20 +01001435 "\r\n",
1436 msg, endpoint, mode);
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +08001437
1438 if (len < 0)
1439 return;
1440
Holger Hans Peter Freythere6ed0092015-08-20 14:58:19 +02001441 nchars = write_response_sdp(endp, buf + len, sizeof(buf) + len - 1, NULL);
Jacob Erlbeck997e1e82014-03-14 18:01:20 +01001442 if (nchars < 0)
1443 return;
1444
1445 len += nchars;
1446
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +08001447 buf[sizeof(buf) - 1] = '\0';
1448
Holger Hans Peter Freyther557b1ab2010-09-19 04:39:55 +08001449 send_trans(endp->cfg, buf, len);
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +08001450}
1451
1452static void send_dlcx(struct mgcp_endpoint *endp, int endpoint)
1453{
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +08001454 char buf[2096];
1455 int len;
1456
1457 len = snprintf(buf, sizeof(buf),
1458 "DLCX 43 %x@mgw MGCP 1.0\r\n"
1459 "C: 4256\r\n"
1460 , endpoint);
1461
1462 if (len < 0)
1463 return;
1464
1465 buf[sizeof(buf) - 1] = '\0';
1466
Holger Hans Peter Freyther557b1ab2010-09-19 04:39:55 +08001467 send_trans(endp->cfg, buf, len);
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +08001468}
1469
Harald Welte6a857052012-01-27 00:41:39 +01001470static int send_agent(struct mgcp_config *cfg, const char *buf, int len)
1471{
1472 return write(cfg->gw_fd.bfd.fd, buf, len);
1473}
1474
1475int mgcp_send_reset_all(struct mgcp_config *cfg)
1476{
1477 static const char mgcp_reset[] = {
1478 "RSIP 1 *@mgw MGCP 1.0\r\n"
1479 };
1480
1481 return send_agent(cfg, mgcp_reset, sizeof mgcp_reset -1);
1482}
1483
1484int mgcp_send_reset_ep(struct mgcp_endpoint *endp, int endpoint)
1485{
1486 char buf[128];
1487 int len;
1488
1489 len = snprintf(buf, sizeof(buf),
1490 "RSIP 39 %x@mgw MGCP 1.0\r\n"
1491 , endpoint);
1492 if (len < 0)
1493 return len;
1494
1495 buf[sizeof(buf) - 1] = '\0';
1496
1497 return send_agent(endp->cfg, buf, len);
1498}
1499
Holger Hans Peter Freyther7cce1d32015-03-26 20:34:12 +01001500static int setup_rtp_processing(struct mgcp_endpoint *endp)
Jacob Erlbecka0d64ce2014-03-13 14:24:52 +01001501{
Holger Hans Peter Freyther7cce1d32015-03-26 20:34:12 +01001502 int rc = 0;
Jacob Erlbecka0d64ce2014-03-13 14:24:52 +01001503 struct mgcp_config *cfg = endp->cfg;
1504
1505 if (endp->type != MGCP_RTP_DEFAULT)
Holger Hans Peter Freyther7cce1d32015-03-26 20:34:12 +01001506 return 0;
Jacob Erlbecka0d64ce2014-03-13 14:24:52 +01001507
1508 if (endp->conn_mode == MGCP_CONN_LOOPBACK)
Holger Hans Peter Freyther7cce1d32015-03-26 20:34:12 +01001509 return 0;
Jacob Erlbecka0d64ce2014-03-13 14:24:52 +01001510
1511 if (endp->conn_mode & MGCP_CONN_SEND_ONLY)
Holger Hans Peter Freyther7cce1d32015-03-26 20:34:12 +01001512 rc |= cfg->setup_rtp_processing_cb(endp, &endp->net_end, &endp->bts_end);
Jacob Erlbecka0d64ce2014-03-13 14:24:52 +01001513 else
Holger Hans Peter Freyther7cce1d32015-03-26 20:34:12 +01001514 rc |= cfg->setup_rtp_processing_cb(endp, &endp->net_end, NULL);
Jacob Erlbecka0d64ce2014-03-13 14:24:52 +01001515
1516 if (endp->conn_mode & MGCP_CONN_RECV_ONLY)
Holger Hans Peter Freyther7cce1d32015-03-26 20:34:12 +01001517 rc |= cfg->setup_rtp_processing_cb(endp, &endp->bts_end, &endp->net_end);
Jacob Erlbecka0d64ce2014-03-13 14:24:52 +01001518 else
Holger Hans Peter Freyther7cce1d32015-03-26 20:34:12 +01001519 rc |= cfg->setup_rtp_processing_cb(endp, &endp->bts_end, NULL);
1520 return rc;
Jacob Erlbecka0d64ce2014-03-13 14:24:52 +01001521}
1522
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +08001523static void create_transcoder(struct mgcp_endpoint *endp)
1524{
1525 int port;
1526 int in_endp = ENDPOINT_NUMBER(endp);
Holger Hans Peter Freytherbd7b3c52010-11-01 21:04:54 +01001527 int out_endp = endp_back_channel(in_endp);
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +08001528
Pablo Neira Ayuso46bd4242013-07-08 05:09:46 +02001529 if (endp->type != MGCP_RTP_TRANSCODED)
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +08001530 return;
1531
Holger Hans Peter Freyther8b19dee2010-11-01 22:38:25 +01001532 send_msg(endp, in_endp, endp->trans_bts.local_port, "CRCX", "sendrecv");
1533 send_msg(endp, in_endp, endp->trans_bts.local_port, "MDCX", "sendrecv");
Holger Hans Peter Freyther21262332010-11-01 20:53:31 +01001534 send_msg(endp, out_endp, endp->trans_net.local_port, "CRCX", "sendrecv");
1535 send_msg(endp, out_endp, endp->trans_net.local_port, "MDCX", "sendrecv");
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +08001536
Holger Hans Peter Freytherbd7b3c52010-11-01 21:04:54 +01001537 port = rtp_calculate_port(in_endp, endp->cfg->transcoder_remote_base);
1538 endp->trans_bts.rtp_port = htons(port);
1539 endp->trans_bts.rtcp_port = htons(port + 1);
1540
Holger Hans Peter Freytherb98ba722010-09-19 04:21:39 +08001541 port = rtp_calculate_port(out_endp, endp->cfg->transcoder_remote_base);
Holger Hans Peter Freyther21262332010-11-01 20:53:31 +01001542 endp->trans_net.rtp_port = htons(port);
1543 endp->trans_net.rtcp_port = htons(port + 1);
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +08001544}
1545
1546static void delete_transcoder(struct mgcp_endpoint *endp)
1547{
1548 int in_endp = ENDPOINT_NUMBER(endp);
Holger Hans Peter Freytherbd7b3c52010-11-01 21:04:54 +01001549 int out_endp = endp_back_channel(in_endp);
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +08001550
Pablo Neira Ayuso46bd4242013-07-08 05:09:46 +02001551 if (endp->type != MGCP_RTP_TRANSCODED)
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +08001552 return;
1553
1554 send_dlcx(endp, in_endp);
1555 send_dlcx(endp, out_endp);
1556}
Holger Hans Peter Freytherf2eedff2010-09-19 04:36:07 +08001557
1558int mgcp_reset_transcoder(struct mgcp_config *cfg)
1559{
Holger Hans Peter Freytherf2eedff2010-09-19 04:36:07 +08001560 if (!cfg->transcoder_ip)
Holger Hans Peter Freythercf1c8772010-09-24 04:41:28 +08001561 return 0;
Holger Hans Peter Freytherf2eedff2010-09-19 04:36:07 +08001562
1563 static const char mgcp_reset[] = {
1564 "RSIP 1 13@mgw MGCP 1.0\r\n"
1565 };
1566
Holger Hans Peter Freyther557b1ab2010-09-19 04:39:55 +08001567 return send_trans(cfg, mgcp_reset, sizeof mgcp_reset -1);
Holger Hans Peter Freytherf2eedff2010-09-19 04:36:07 +08001568}
Holger Hans Peter Freyther0bf15a82012-09-14 17:18:12 +02001569
1570void mgcp_format_stats(struct mgcp_endpoint *endp, char *msg, size_t size)
1571{
Holger Hans Peter Freythercb306a62012-10-24 21:22:47 +02001572 uint32_t expected, jitter;
Holger Hans Peter Freyther38e02c52012-10-22 18:09:35 +02001573 int ploss;
Jacob Erlbeck50079a12013-11-25 12:53:28 +01001574 int nchars;
Holger Hans Peter Freyther38e02c52012-10-22 18:09:35 +02001575 mgcp_state_calc_loss(&endp->net_state, &endp->net_end,
1576 &expected, &ploss);
Holger Hans Peter Freythercb306a62012-10-24 21:22:47 +02001577 jitter = mgcp_state_calc_jitter(&endp->net_state);
Holger Hans Peter Freyther38e02c52012-10-22 18:09:35 +02001578
Jacob Erlbeck50079a12013-11-25 12:53:28 +01001579 nchars = snprintf(msg, size,
1580 "\r\nP: PS=%u, OS=%u, PR=%u, OR=%u, PL=%d, JI=%u",
1581 endp->bts_end.packets, endp->bts_end.octets,
1582 endp->net_end.packets, endp->net_end.octets,
1583 ploss, jitter);
1584 if (nchars < 0 || nchars >= size)
1585 goto truncate;
1586
1587 msg += nchars;
1588 size -= nchars;
1589
1590 /* Error Counter */
Pablo Neira Ayusoee11bc02014-09-17 12:33:09 +02001591 nchars = snprintf(msg, size,
1592 "\r\nX-Osmo-CP: EC TIS=%u, TOS=%u, TIR=%u, TOR=%u",
1593 endp->net_state.in_stream.err_ts_counter,
1594 endp->net_state.out_stream.err_ts_counter,
1595 endp->bts_state.in_stream.err_ts_counter,
1596 endp->bts_state.out_stream.err_ts_counter);
1597 if (nchars < 0 || nchars >= size)
1598 goto truncate;
1599
1600 msg += nchars;
1601 size -= nchars;
1602
1603 if (endp->osmux.state == OSMUX_STATE_ENABLED) {
1604 snprintf(msg, size,
1605 "\r\nX-Osmux-ST: CR=%u, BR=%u",
1606 endp->osmux.stats.chunks,
1607 endp->osmux.stats.octets);
1608 }
Jacob Erlbeck50079a12013-11-25 12:53:28 +01001609truncate:
Holger Hans Peter Freyther0bf15a82012-09-14 17:18:12 +02001610 msg[size - 1] = '\0';
1611}
Holger Hans Peter Freyther462b7d72012-10-24 21:53:40 +02001612
1613int mgcp_parse_stats(struct msgb *msg, uint32_t *ps, uint32_t *os,
1614 uint32_t *pr, uint32_t *_or, int *loss, uint32_t *jitter)
1615{
1616 char *line, *save;
1617 int rc;
1618
1619 /* initialize with bad values */
1620 *ps = *os = *pr = *_or = *jitter = UINT_MAX;
1621 *loss = INT_MAX;
1622
1623
1624 line = strtok_r((char *) msg->l2h, "\r\n", &save);
1625 if (!line)
1626 return -1;
1627
1628 /* this can only parse the message that is created above... */
Jacob Erlbecka01bd602013-11-29 13:43:43 +01001629 for_each_non_empty_line(line, save) {
Holger Hans Peter Freyther462b7d72012-10-24 21:53:40 +02001630 switch (line[0]) {
1631 case 'P':
1632 rc = sscanf(line, "P: PS=%u, OS=%u, PR=%u, OR=%u, PL=%d, JI=%u",
1633 ps, os, pr, _or, loss, jitter);
1634 return rc == 6 ? 0 : -1;
1635 }
1636 }
1637
1638 return -1;
1639}