blob: 96542c5a0fc887f7b68ca7a309efa35ec83a5fe2 [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
Holger Hans Peter Freyther1cc5ff82014-05-22 15:03:10 +020069static int mgcp_check_param(const struct mgcp_endpoint *endp, const char *line)
70{
71 const size_t line_len = strlen(line);
72 if (line[0] != '\0' && line_len < 2) {
73 LOGP(DMGCP, LOGL_ERROR,
74 "Wrong MGCP option format: '%s' on 0x%x\n",
75 line, ENDPOINT_NUMBER(endp));
76 return 0;
77 }
78
79 return 1;
80}
81
Holger Hans Peter Freyther46340132010-08-06 08:26:54 +080082static uint32_t generate_call_id(struct mgcp_config *cfg)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +010083{
84 int i;
85
86 /* use the call id */
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +010087 ++cfg->last_call_id;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +010088
89 /* handle wrap around */
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +010090 if (cfg->last_call_id == CI_UNUSED)
91 ++cfg->last_call_id;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +010092
93 /* callstack can only be of size number_of_endpoints */
94 /* verify that the call id is free, e.g. in case of overrun */
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +010095 for (i = 1; i < cfg->trunk.number_endpoints; ++i)
96 if (cfg->trunk.endpoints[i].ci == cfg->last_call_id)
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +010097 return generate_call_id(cfg);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +010098
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +010099 return cfg->last_call_id;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100100}
101
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100102/*
103 * array of function pointers for handling various
104 * messages. In the future this might be binary sorted
105 * for performance reasons.
106 */
107static const struct mgcp_request mgcp_requests [] = {
108 MGCP_REQUEST("AUEP", handle_audit_endpoint, "AuditEndpoint")
109 MGCP_REQUEST("CRCX", handle_create_con, "CreateConnection")
110 MGCP_REQUEST("DLCX", handle_delete_con, "DeleteConnection")
111 MGCP_REQUEST("MDCX", handle_modify_con, "ModifiyConnection")
Holger Hans Peter Freyther6e94d6d2011-01-25 23:33:54 +0100112 MGCP_REQUEST("RQNT", handle_noti_req, "NotificationRequest")
Holger Hans Peter Freyther9bdcc9c2010-03-31 06:39:35 +0200113
114 /* SPEC extension */
115 MGCP_REQUEST("RSIP", handle_rsip, "ReSetInProgress")
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100116};
117
Holger Hans Peter Freyther62e836c2010-02-03 11:03:45 +0100118static struct msgb *mgcp_msgb_alloc(void)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100119{
Holger Hans Peter Freyther62e836c2010-02-03 11:03:45 +0100120 struct msgb *msg;
121 msg = msgb_alloc_headroom(4096, 128, "MGCP msg");
122 if (!msg)
123 LOGP(DMGCP, LOGL_ERROR, "Failed to msgb for MGCP data.\n");
124
125 return msg;
126}
127
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100128static struct msgb *do_retransmission(const struct mgcp_endpoint *endp)
129{
130 struct msgb *msg = mgcp_msgb_alloc();
131 if (!msg)
132 return NULL;
133
134 msg->l2h = msgb_put(msg, strlen(endp->last_response));
135 memcpy(msg->l2h, endp->last_response, msgb_l2len(msg));
136 return msg;
137}
138
Holger Hans Peter Freythera769dcb2012-12-07 15:14:27 +0100139static struct msgb *create_resp(struct mgcp_endpoint *endp, int code,
140 const char *txt, const char *msg,
Holger Hans Peter Freyther0bf15a82012-09-14 17:18:12 +0200141 const char *trans, const char *param,
142 const char *sdp)
Holger Hans Peter Freyther62e836c2010-02-03 11:03:45 +0100143{
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100144 int len;
Holger Hans Peter Freyther62e836c2010-02-03 11:03:45 +0100145 struct msgb *res;
146
147 res = mgcp_msgb_alloc();
148 if (!res)
149 return NULL;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100150
Holger Hans Peter Freyther0bf15a82012-09-14 17:18:12 +0200151 len = snprintf((char *) res->data, 2048, "%d %s%s%s\r\n%s",
152 code, trans, txt, param ? param : "", sdp ? sdp : "");
153 if (len < 0) {
154 LOGP(DMGCP, LOGL_ERROR, "Failed to sprintf MGCP response.\n");
155 msgb_free(res);
156 return NULL;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100157 }
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100158
Holger Hans Peter Freyther62e836c2010-02-03 11:03:45 +0100159 res->l2h = msgb_put(res, len);
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100160 LOGP(DMGCP, LOGL_DEBUG, "Generated response: code: %d for '%s'\n", code, res->l2h);
161
162 /*
163 * Remember the last transmission per endpoint.
164 */
165 if (endp) {
166 struct mgcp_trunk_config *tcfg = endp->tcfg;
167 talloc_free(endp->last_response);
168 talloc_free(endp->last_trans);
169 endp->last_trans = talloc_strdup(tcfg->endpoints, trans);
170 endp->last_response = talloc_strndup(tcfg->endpoints,
171 (const char *) res->l2h,
172 msgb_l2len(res));
173 }
174
Holger Hans Peter Freyther62e836c2010-02-03 11:03:45 +0100175 return res;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100176}
177
Holger Hans Peter Freythera769dcb2012-12-07 15:14:27 +0100178static struct msgb *create_ok_resp_with_param(struct mgcp_endpoint *endp,
179 int code, const char *msg,
Holger Hans Peter Freyther0bf15a82012-09-14 17:18:12 +0200180 const char *trans, const char *param)
181{
Holger Hans Peter Freythera769dcb2012-12-07 15:14:27 +0100182 return create_resp(endp, code, " OK", msg, trans, param, NULL);
Holger Hans Peter Freyther0bf15a82012-09-14 17:18:12 +0200183}
184
Holger Hans Peter Freythera769dcb2012-12-07 15:14:27 +0100185static struct msgb *create_ok_response(struct mgcp_endpoint *endp,
186 int code, const char *msg, const char *trans)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100187{
Holger Hans Peter Freythera769dcb2012-12-07 15:14:27 +0100188 return create_ok_resp_with_param(endp, code, msg, trans, NULL);
Holger Hans Peter Freyther6adac172011-01-06 16:19:55 +0100189}
190
Holger Hans Peter Freythera769dcb2012-12-07 15:14:27 +0100191static struct msgb *create_err_response(struct mgcp_endpoint *endp,
192 int code, const char *msg, const char *trans)
Holger Hans Peter Freyther6adac172011-01-06 16:19:55 +0100193{
Holger Hans Peter Freythera769dcb2012-12-07 15:14:27 +0100194 return create_resp(endp, code, " FAIL", msg, trans, NULL, NULL);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100195}
196
Jacob Erlbeck997e1e82014-03-14 18:01:20 +0100197static int write_response_sdp(struct mgcp_endpoint *endp,
198 char *sdp_record, size_t size, const char *addr)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100199{
Jacob Erlbeck168ca002014-03-17 12:40:07 +0100200 const char *fmtp_extra;
201 const char *audio_name;
202 int payload_type;
Jacob Erlbeck0a1bc562013-12-10 13:09:37 +0100203 int len;
Jacob Erlbeck997e1e82014-03-14 18:01:20 +0100204 int nchars;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100205
Jacob Erlbeck168ca002014-03-17 12:40:07 +0100206 endp->cfg->get_net_downlink_format_cb(endp, &payload_type,
207 &audio_name, &fmtp_extra);
208
Jacob Erlbeck997e1e82014-03-14 18:01:20 +0100209 len = snprintf(sdp_record, size,
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100210 "v=0\r\n"
Holger Hans Peter Freytherc7e49d32011-07-20 20:43:15 +0200211 "o=- %u 23 IN IP4 %s\r\n"
Holger Hans Peter Freytherb1edf7b2014-11-20 23:17:32 +0100212 "s=-\r\n"
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100213 "c=IN IP4 %s\r\n"
Jacob Erlbeck997e1e82014-03-14 18:01:20 +0100214 "t=0 0\r\n",
215 endp->ci, addr, addr);
Jacob Erlbeck0a1bc562013-12-10 13:09:37 +0100216
Jacob Erlbeck997e1e82014-03-14 18:01:20 +0100217 if (len < 0 || len >= size)
Jacob Erlbeck0a1bc562013-12-10 13:09:37 +0100218 goto buffer_too_small;
219
Jacob Erlbeck997e1e82014-03-14 18:01:20 +0100220 if (payload_type >= 0) {
221 nchars = snprintf(sdp_record + len, size - len,
222 "m=audio %d RTP/AVP %d\r\n",
223 endp->net_end.local_port, payload_type);
224 if (nchars < 0 || nchars >= size - len)
225 goto buffer_too_small;
226
227 len += nchars;
228
Holger Hans Peter Freyther619b0142014-11-19 16:04:45 +0100229 if (audio_name && endp->tcfg->audio_send_name) {
Jacob Erlbeck997e1e82014-03-14 18:01:20 +0100230 nchars = snprintf(sdp_record + len, size - len,
231 "a=rtpmap:%d %s\r\n",
232 payload_type, audio_name);
233
234 if (nchars < 0 || nchars >= size - len)
235 goto buffer_too_small;
236
237 len += nchars;
238 }
239
240 if (fmtp_extra) {
241 nchars = snprintf(sdp_record + len, size - len,
Jacob Erlbeckcb04ca22014-06-12 12:42:38 +0200242 "%s\r\n", fmtp_extra);
Jacob Erlbeck997e1e82014-03-14 18:01:20 +0100243
244 if (nchars < 0 || nchars >= size - len)
245 goto buffer_too_small;
246
247 len += nchars;
248 }
249 }
Jacob Erlbeck0a1bc562013-12-10 13:09:37 +0100250 if (endp->bts_end.packet_duration_ms > 0 && endp->tcfg->audio_send_ptime) {
Jacob Erlbeck997e1e82014-03-14 18:01:20 +0100251 nchars = snprintf(sdp_record + len, size - len,
252 "a=ptime:%d\r\n",
253 endp->bts_end.packet_duration_ms);
254 if (nchars < 0 || nchars >= size - len)
Jacob Erlbeck0a1bc562013-12-10 13:09:37 +0100255 goto buffer_too_small;
256
257 len += nchars;
258 }
Jacob Erlbeck997e1e82014-03-14 18:01:20 +0100259
260 return len;
Jacob Erlbeck0a1bc562013-12-10 13:09:37 +0100261
262buffer_too_small:
Holger Hans Peter Freytherc6e32ad2015-01-02 11:25:54 +0100263 LOGP(DMGCP, LOGL_ERROR, "SDP buffer too small: %zu (needed %d)\n",
Jacob Erlbeck997e1e82014-03-14 18:01:20 +0100264 size, len);
265 return -1;
266}
267
268static struct msgb *create_response_with_sdp(struct mgcp_endpoint *endp,
269 const char *msg, const char *trans_id)
270{
271 const char *addr = endp->cfg->local_ip;
272 char sdp_record[4096];
273 int len;
274 int nchars;
Pablo Neira Ayusob769f3c2014-08-27 17:02:52 +0200275 char osmux_extension[strlen("\nX-Osmux: 255") + 1];
Jacob Erlbeck997e1e82014-03-14 18:01:20 +0100276
277 if (!addr)
Holger Hans Peter Freythere6ed0092015-08-20 14:58:19 +0200278 addr = mgcp_net_src_addr(endp);
Jacob Erlbeck997e1e82014-03-14 18:01:20 +0100279
Pau Espin Pedrolc5f60fb2017-08-11 18:32:22 +0200280 if (endp->osmux.state == OSMUX_STATE_NEGOTIATING) {
Pablo Neira Ayusob769f3c2014-08-27 17:02:52 +0200281 sprintf(osmux_extension, "\nX-Osmux: %u", endp->osmux.cid);
Pau Espin Pedrolc5f60fb2017-08-11 18:32:22 +0200282 endp->osmux.state = OSMUX_STATE_ACTIVATING;
283 } else {
Pablo Neira Ayusob769f3c2014-08-27 17:02:52 +0200284 osmux_extension[0] = '\0';
Pau Espin Pedrolc5f60fb2017-08-11 18:32:22 +0200285 }
Jacob Erlbeck997e1e82014-03-14 18:01:20 +0100286
Pablo Neira Ayusob769f3c2014-08-27 17:02:52 +0200287 len = snprintf(sdp_record, sizeof(sdp_record),
288 "I: %u%s\n\n", endp->ci, osmux_extension);
Jacob Erlbeck997e1e82014-03-14 18:01:20 +0100289 if (len < 0)
290 return NULL;
291
292 nchars = write_response_sdp(endp, sdp_record + len,
293 sizeof(sdp_record) - len - 1, addr);
294 if (nchars < 0)
295 return NULL;
296
297 len += nchars;
298
299 sdp_record[sizeof(sdp_record) - 1] = '\0';
300
301 return create_resp(endp, 200, " OK", msg, trans_id, NULL, sdp_record);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100302}
303
Holger Hans Peter Freyther6b0ba012014-07-08 13:01:56 +0200304static void send_dummy(struct mgcp_endpoint *endp)
305{
Pablo Neira Ayusob769f3c2014-08-27 17:02:52 +0200306 if (endp->osmux.state != OSMUX_STATE_DISABLED)
Holger Hans Peter Freyther6b0ba012014-07-08 13:01:56 +0200307 osmux_send_dummy(endp);
308 else
309 mgcp_send_dummy(endp);
310}
311
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100312/*
313 * handle incoming messages:
314 * - this can be a command (four letters, space, transaction id)
315 * - or a response (three numbers, space, transaction id)
316 */
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100317struct msgb *mgcp_handle_message(struct mgcp_config *cfg, struct msgb *msg)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100318{
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100319 struct mgcp_parse_data pdata;
320 int i, code, handled = 0;
Holger Hans Peter Freyther62e836c2010-02-03 11:03:45 +0100321 struct msgb *resp = NULL;
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100322 char *data;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100323
Holger Hans Peter Freytherf36a11a2010-03-31 13:26:46 +0200324 if (msgb_l2len(msg) < 4) {
Holger Hans Peter Freyther0d904e02012-12-07 16:46:19 +0100325 LOGP(DMGCP, LOGL_ERROR, "msg too short: %d\n", msg->len);
Holger Hans Peter Freyther62e836c2010-02-03 11:03:45 +0100326 return NULL;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100327 }
328
Neels Hofmeyra1756f32016-05-20 21:59:55 +0200329 if (mgcp_msg_terminate_nul(msg))
Jacob Erlbeck9107e2d2013-12-03 17:14:44 +0100330 return NULL;
Jacob Erlbeck9107e2d2013-12-03 17:14:44 +0100331
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100332 /* attempt to treat it as a response */
Holger Hans Peter Freytherf36a11a2010-03-31 13:26:46 +0200333 if (sscanf((const char *)&msg->l2h[0], "%3d %*s", &code) == 1) {
Holger Hans Peter Freyther63f2db22010-02-26 13:30:57 +0100334 LOGP(DMGCP, LOGL_DEBUG, "Response: Code: %d\n", code);
Holger Hans Peter Freyther29de3462012-12-07 16:07:46 +0100335 return NULL;
336 }
337
338 msg->l3h = &msg->l2h[4];
339
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100340
341 /*
342 * Check for a duplicate message and respond.
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100343 */
344 memset(&pdata, 0, sizeof(pdata));
345 pdata.cfg = cfg;
Jacob Erlbeck17711712013-11-29 13:43:46 +0100346 data = strline_r((char *) msg->l3h, &pdata.save);
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100347 pdata.found = mgcp_analyze_header(&pdata, data);
348 if (pdata.endp && pdata.trans
349 && pdata.endp->last_trans
350 && strcmp(pdata.endp->last_trans, pdata.trans) == 0) {
351 return do_retransmission(pdata.endp);
352 }
353
Holger Hans Peter Freyther29de3462012-12-07 16:07:46 +0100354 for (i = 0; i < ARRAY_SIZE(mgcp_requests); ++i) {
355 if (strncmp(mgcp_requests[i].name, (const char *) &msg->l2h[0], 4) == 0) {
356 handled = 1;
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100357 resp = mgcp_requests[i].handle_request(&pdata);
Holger Hans Peter Freyther29de3462012-12-07 16:07:46 +0100358 break;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100359 }
360 }
361
Holger Hans Peter Freyther29de3462012-12-07 16:07:46 +0100362 if (!handled)
363 LOGP(DMGCP, LOGL_NOTICE, "MSG with type: '%.4s' not handled\n", &msg->l2h[0]);
364
Holger Hans Peter Freyther62e836c2010-02-03 11:03:45 +0100365 return resp;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100366}
367
Holger Hans Peter Freyther9f239a22011-01-06 19:32:52 +0100368/**
369 * We have a null terminated string with the endpoint name here. We only
370 * support two kinds. Simple ones as seen on the BSC level and the ones
371 * seen on the trunk side.
372 */
373static struct mgcp_endpoint *find_e1_endpoint(struct mgcp_config *cfg,
374 const char *mgcp)
375{
376 char *rest = NULL;
Holger Hans Peter Freyther74e61112011-02-28 14:13:47 +0100377 struct mgcp_trunk_config *tcfg;
378 int trunk, endp;
Holger Hans Peter Freyther9f239a22011-01-06 19:32:52 +0100379
380 trunk = strtoul(mgcp + 6, &rest, 10);
Holger Hans Peter Freytherf43f2fc2011-01-07 11:30:21 +0100381 if (rest == NULL || rest[0] != '/' || trunk < 1) {
Holger Hans Peter Freyther9f239a22011-01-06 19:32:52 +0100382 LOGP(DMGCP, LOGL_ERROR, "Wrong trunk name '%s'\n", mgcp);
383 return NULL;
384 }
385
386 endp = strtoul(rest + 1, &rest, 10);
387 if (rest == NULL || rest[0] != '@') {
Holger Hans Peter Freytherf43f2fc2011-01-07 11:30:21 +0100388 LOGP(DMGCP, LOGL_ERROR, "Wrong endpoint name '%s'\n", mgcp);
Holger Hans Peter Freyther9f239a22011-01-06 19:32:52 +0100389 return NULL;
390 }
391
392 /* signalling is on timeslot 1 */
393 if (endp == 1)
394 return NULL;
395
Holger Hans Peter Freyther74e61112011-02-28 14:13:47 +0100396 tcfg = mgcp_trunk_num(cfg, trunk);
397 if (!tcfg) {
398 LOGP(DMGCP, LOGL_ERROR, "The trunk %d is not declared.\n", trunk);
399 return NULL;
400 }
401
402 if (!tcfg->endpoints) {
403 LOGP(DMGCP, LOGL_ERROR, "Endpoints of trunk %d not allocated.\n", trunk);
404 return NULL;
405 }
406
407 if (endp < 1 || endp >= tcfg->number_endpoints) {
Holger Hans Peter Freyther9f239a22011-01-06 19:32:52 +0100408 LOGP(DMGCP, LOGL_ERROR, "Failed to find endpoint '%s'\n", mgcp);
Holger Hans Peter Freyther45c21842011-01-07 11:36:54 +0100409 return NULL;
Holger Hans Peter Freyther9f239a22011-01-06 19:32:52 +0100410 }
411
Holger Hans Peter Freyther74e61112011-02-28 14:13:47 +0100412 return &tcfg->endpoints[endp];
Holger Hans Peter Freyther9f239a22011-01-06 19:32:52 +0100413}
414
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100415static struct mgcp_endpoint *find_endpoint(struct mgcp_config *cfg, const char *mgcp)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100416{
417 char *endptr = NULL;
418 unsigned int gw = INT_MAX;
419
Holger Hans Peter Freyther614aba32015-09-04 16:01:12 +0200420 if (strncmp(mgcp, "ds/e1", 5) == 0)
Holger Hans Peter Freyther9f239a22011-01-06 19:32:52 +0100421 return find_e1_endpoint(cfg, mgcp);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100422
Holger Hans Peter Freyther614aba32015-09-04 16:01:12 +0200423 gw = strtoul(mgcp, &endptr, 16);
424 if (gw > 0 && gw < cfg->trunk.number_endpoints && endptr[0] == '@')
425 return &cfg->trunk.endpoints[gw];
426
427 LOGP(DMGCP, LOGL_ERROR, "Not able to find the endpoint: '%s'\n", mgcp);
Holger Hans Peter Freyther9f239a22011-01-06 19:32:52 +0100428 return NULL;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100429}
430
Harald Welteae199722012-01-27 12:31:36 +0100431/**
432 * @returns 0 when the status line was complete and transaction_id and
433 * endp out parameters are set.
434 */
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100435static int mgcp_analyze_header(struct mgcp_parse_data *pdata, char *data)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100436{
Harald Welteae199722012-01-27 12:31:36 +0100437 int i = 0;
Holger Hans Peter Freyther1eba7de2013-07-03 10:23:35 +0200438 char *elem, *save = NULL;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100439
Harald Welte4a7d0e72016-11-26 15:03:02 +0100440 OSMO_ASSERT(data);
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100441 pdata->trans = "000000";
Holger Hans Peter Freythera820c5f2010-02-26 13:32:55 +0100442
Harald Welteae199722012-01-27 12:31:36 +0100443 for (elem = strtok_r(data, " ", &save); elem;
444 elem = strtok_r(NULL, " ", &save)) {
445 switch (i) {
446 case 0:
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100447 pdata->trans = elem;
Harald Welteae199722012-01-27 12:31:36 +0100448 break;
449 case 1:
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100450 pdata->endp = find_endpoint(pdata->cfg, elem);
451 if (!pdata->endp) {
452 LOGP(DMGCP, LOGL_ERROR,
453 "Unable to find Endpoint `%s'\n", elem);
454 return -1;
Harald Welteae199722012-01-27 12:31:36 +0100455 }
456 break;
457 case 2:
458 if (strcmp("MGCP", elem)) {
459 LOGP(DMGCP, LOGL_ERROR,
460 "MGCP header parsing error\n");
461 return -1;
462 }
463 break;
464 case 3:
465 if (strcmp("1.0", elem)) {
466 LOGP(DMGCP, LOGL_ERROR, "MGCP version `%s' "
467 "not supported\n", elem);
468 return -1;
469 }
470 break;
471 }
472 i++;
473 }
474
475 if (i != 4) {
476 LOGP(DMGCP, LOGL_ERROR, "MGCP status line too short.\n");
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100477 pdata->trans = "000000";
478 pdata->endp = NULL;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100479 return -1;
480 }
481
Holger Hans Peter Freytherf2f15912010-04-01 03:27:04 +0200482 return 0;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100483}
484
485static int verify_call_id(const struct mgcp_endpoint *endp,
486 const char *callid)
487{
488 if (strcmp(endp->callid, callid) != 0) {
Holger Hans Peter Freyther2ada71d2010-02-03 09:13:10 +0100489 LOGP(DMGCP, LOGL_ERROR, "CallIDs does not match on 0x%x. '%s' != '%s'\n",
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100490 ENDPOINT_NUMBER(endp), endp->callid, callid);
491 return -1;
492 }
493
494 return 0;
495}
496
497static int verify_ci(const struct mgcp_endpoint *endp,
Holger Hans Peter Freyther46340132010-08-06 08:26:54 +0800498 const char *_ci)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100499{
Holger Hans Peter Freyther46340132010-08-06 08:26:54 +0800500 uint32_t ci = strtoul(_ci, NULL, 10);
501
502 if (ci != endp->ci) {
503 LOGP(DMGCP, LOGL_ERROR, "ConnectionIdentifiers do not match on 0x%x. %u != %s\n",
504 ENDPOINT_NUMBER(endp), endp->ci, _ci);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100505 return -1;
506 }
507
508 return 0;
509}
510
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100511static struct msgb *handle_audit_endpoint(struct mgcp_parse_data *p)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100512{
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100513 if (p->found != 0)
514 return create_err_response(NULL, 500, "AUEP", p->trans);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100515 else
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100516 return create_ok_response(p->endp, 200, "AUEP", p->trans);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100517}
518
Jacob Erlbeck2645c9e2013-12-19 12:23:24 +0100519static int parse_conn_mode(const char *msg, struct mgcp_endpoint *endp)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100520{
521 int ret = 0;
522 if (strcmp(msg, "recvonly") == 0)
Jacob Erlbeck2645c9e2013-12-19 12:23:24 +0100523 endp->conn_mode = MGCP_CONN_RECV_ONLY;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100524 else if (strcmp(msg, "sendrecv") == 0)
Jacob Erlbeck2645c9e2013-12-19 12:23:24 +0100525 endp->conn_mode = MGCP_CONN_RECV_SEND;
Holger Hans Peter Freythere02860a2010-09-18 20:21:44 +0800526 else if (strcmp(msg, "sendonly") == 0)
Jacob Erlbeck2645c9e2013-12-19 12:23:24 +0100527 endp->conn_mode = MGCP_CONN_SEND_ONLY;
Holger Hans Peter Freyther98a38772010-08-03 02:27:21 +0800528 else if (strcmp(msg, "loopback") == 0)
Jacob Erlbeck2645c9e2013-12-19 12:23:24 +0100529 endp->conn_mode = MGCP_CONN_LOOPBACK;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100530 else {
Holger Hans Peter Freyther2ada71d2010-02-03 09:13:10 +0100531 LOGP(DMGCP, LOGL_ERROR, "Unknown connection mode: '%s'\n", msg);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100532 ret = -1;
533 }
534
Jacob Erlbecke35fd132014-01-16 16:50:40 +0100535 endp->net_end.output_enabled =
536 endp->conn_mode & MGCP_CONN_SEND_ONLY ? 1 : 0;
537 endp->bts_end.output_enabled =
538 endp->conn_mode & MGCP_CONN_RECV_ONLY ? 1 : 0;
Jacob Erlbeck2645c9e2013-12-19 12:23:24 +0100539
Neels Hofmeyra1756f32016-05-20 21:59:55 +0200540 LOGP(DMGCP, LOGL_DEBUG, "endpoint %x connection mode '%s' %d output_enabled net %d bts %d\n",
541 ENDPOINT_NUMBER(endp),
542 msg, endp->conn_mode, endp->net_end.output_enabled,
543 endp->bts_end.output_enabled);
544
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100545 return ret;
546}
547
Holger Hans Peter Freytherf138f912010-08-05 08:08:17 +0800548static int allocate_port(struct mgcp_endpoint *endp, struct mgcp_rtp_end *end,
Holger Hans Peter Freyther218f8562010-09-18 02:30:02 +0800549 struct mgcp_port_range *range,
550 int (*alloc)(struct mgcp_endpoint *endp, int port))
Holger Hans Peter Freytherf138f912010-08-05 08:08:17 +0800551{
552 int i;
553
554 if (range->mode == PORT_ALLOC_STATIC) {
Holger Hans Peter Freytherf138f912010-08-05 08:08:17 +0800555 end->local_alloc = PORT_ALLOC_STATIC;
556 return 0;
557 }
558
559 /* attempt to find a port */
560 for (i = 0; i < 200; ++i) {
561 int rc;
562
563 if (range->last_port >= range->range_end)
564 range->last_port = range->range_start;
565
Holger Hans Peter Freyther218f8562010-09-18 02:30:02 +0800566 rc = alloc(endp, range->last_port);
Holger Hans Peter Freytherf138f912010-08-05 08:08:17 +0800567
568 range->last_port += 2;
569 if (rc == 0) {
570 end->local_alloc = PORT_ALLOC_DYNAMIC;
571 return 0;
572 }
573
574 }
575
Holger Hans Peter Freyther218f8562010-09-18 02:30:02 +0800576 LOGP(DMGCP, LOGL_ERROR, "Allocating a RTP/RTCP port failed 200 times 0x%x.\n",
577 ENDPOINT_NUMBER(endp));
Holger Hans Peter Freytherf138f912010-08-05 08:08:17 +0800578 return -1;
579}
580
581static int allocate_ports(struct mgcp_endpoint *endp)
582{
Holger Hans Peter Freyther218f8562010-09-18 02:30:02 +0800583 if (allocate_port(endp, &endp->net_end, &endp->cfg->net_ports,
584 mgcp_bind_net_rtp_port) != 0)
Holger Hans Peter Freytherf138f912010-08-05 08:08:17 +0800585 return -1;
586
Holger Hans Peter Freyther218f8562010-09-18 02:30:02 +0800587 if (allocate_port(endp, &endp->bts_end, &endp->cfg->bts_ports,
588 mgcp_bind_bts_rtp_port) != 0) {
Holger Hans Peter Freytherf138f912010-08-05 08:08:17 +0800589 mgcp_rtp_end_reset(&endp->net_end);
590 return -1;
591 }
592
Holger Hans Peter Freyther69906872011-02-28 14:51:48 +0100593 if (endp->cfg->transcoder_ip && endp->tcfg->trunk_type == MGCP_TRUNK_VIRTUAL) {
Holger Hans Peter Freyther21262332010-11-01 20:53:31 +0100594 if (allocate_port(endp, &endp->trans_net,
Holger Hans Peter Freytherb54048f2010-11-01 19:57:50 +0100595 &endp->cfg->transcoder_ports,
Holger Hans Peter Freytherbd7b3c52010-11-01 21:04:54 +0100596 mgcp_bind_trans_net_rtp_port) != 0) {
Holger Hans Peter Freytherb54048f2010-11-01 19:57:50 +0100597 mgcp_rtp_end_reset(&endp->net_end);
598 mgcp_rtp_end_reset(&endp->bts_end);
599 return -1;
600 }
601
Holger Hans Peter Freytherbd7b3c52010-11-01 21:04:54 +0100602 if (allocate_port(endp, &endp->trans_bts,
603 &endp->cfg->transcoder_ports,
604 mgcp_bind_trans_bts_rtp_port) != 0) {
605 mgcp_rtp_end_reset(&endp->net_end);
606 mgcp_rtp_end_reset(&endp->bts_end);
607 mgcp_rtp_end_reset(&endp->trans_net);
608 return -1;
609 }
610
Holger Hans Peter Freytherb54048f2010-11-01 19:57:50 +0100611 /* remember that we have set up transcoding */
Pablo Neira Ayuso46bd4242013-07-08 05:09:46 +0200612 endp->type = MGCP_RTP_TRANSCODED;
Holger Hans Peter Freyther218f8562010-09-18 02:30:02 +0800613 }
614
Holger Hans Peter Freytherf138f912010-08-05 08:08:17 +0800615 return 0;
616}
617
Jacob Erlbeck2c2ca4d2013-12-09 14:32:03 +0100618/* Set the LCO from a string (see RFC 3435).
619 * The string is stored in the 'string' field. A NULL string is handled excatly
620 * like an empty string, the 'string' field is never NULL after this function
621 * has been called. */
622static void set_local_cx_options(void *ctx, struct mgcp_lco *lco,
623 const char *options)
624{
Jacob Erlbeck452c1832014-05-09 19:42:17 +0200625 char *p_opt, *a_opt;
626 char codec[9];
Jacob Erlbeck2c2ca4d2013-12-09 14:32:03 +0100627
628 talloc_free(lco->string);
Jacob Erlbeck452c1832014-05-09 19:42:17 +0200629 talloc_free(lco->codec);
630 lco->codec = NULL;
Jacob Erlbeck2c2ca4d2013-12-09 14:32:03 +0100631 lco->pkt_period_min = lco->pkt_period_max = 0;
632 lco->string = talloc_strdup(ctx, options ? options : "");
633
634 p_opt = strstr(lco->string, "p:");
635 if (p_opt && sscanf(p_opt, "p:%d-%d",
636 &lco->pkt_period_min, &lco->pkt_period_max) == 1)
637 lco->pkt_period_max = lco->pkt_period_min;
Jacob Erlbeck452c1832014-05-09 19:42:17 +0200638
639 a_opt = strstr(lco->string, "a:");
640 if (a_opt && sscanf(a_opt, "a:%8[^,]", codec) == 1)
641 lco->codec = talloc_strdup(ctx, codec);
Jacob Erlbeck2c2ca4d2013-12-09 14:32:03 +0100642}
643
Jacob Erlbeckdb2d4312013-12-03 14:43:34 +0100644void mgcp_rtp_end_config(struct mgcp_endpoint *endp, int expect_ssrc_change,
645 struct mgcp_rtp_end *rtp)
646{
647 struct mgcp_trunk_config *tcfg = endp->tcfg;
648
Jacob Erlbecke2292f32013-12-03 15:13:12 +0100649 int patch_ssrc = expect_ssrc_change && tcfg->force_constant_ssrc;
650
Jacob Erlbeck4bbddc62013-12-18 12:54:51 +0100651 rtp->force_aligned_timing = tcfg->force_aligned_timing;
Jacob Erlbecke2292f32013-12-03 15:13:12 +0100652 rtp->force_constant_ssrc = patch_ssrc ? 1 : 0;
Jacob Erlbeckdb2d4312013-12-03 14:43:34 +0100653
654 LOGP(DMGCP, LOGL_DEBUG,
655 "Configuring RTP endpoint: local port %d%s%s\n",
656 ntohs(rtp->rtp_port),
Jacob Erlbeck4bbddc62013-12-18 12:54:51 +0100657 rtp->force_aligned_timing ? ", force constant timing" : "",
Jacob Erlbeckdb2d4312013-12-03 14:43:34 +0100658 rtp->force_constant_ssrc ? ", force constant ssrc" : "");
659}
660
Jacob Erlbeckf6ec0e92013-12-04 10:30:11 +0100661uint32_t mgcp_rtp_packet_duration(struct mgcp_endpoint *endp,
662 struct mgcp_rtp_end *rtp)
663{
664 int f = 0;
665
666 /* Get the number of frames per channel and packet */
667 if (rtp->frames_per_packet)
668 f = rtp->frames_per_packet;
Holger Hans Peter Freythercac24382014-09-01 10:35:55 +0200669 else if (rtp->packet_duration_ms && rtp->codec.frame_duration_num) {
670 int den = 1000 * rtp->codec.frame_duration_num;
671 f = (rtp->packet_duration_ms * rtp->codec.frame_duration_den + den/2)
Jacob Erlbeckf6ec0e92013-12-04 10:30:11 +0100672 / den;
673 }
674
Holger Hans Peter Freythercac24382014-09-01 10:35:55 +0200675 return rtp->codec.rate * f * rtp->codec.frame_duration_num / rtp->codec.frame_duration_den;
Jacob Erlbeckf6ec0e92013-12-04 10:30:11 +0100676}
677
Pablo Neira Ayusob769f3c2014-08-27 17:02:52 +0200678static int mgcp_parse_osmux_cid(const char *line)
679{
Pablo Neira Ayuso3ba3cf82014-08-29 08:46:05 +0200680 int osmux_cid;
Pablo Neira Ayusob769f3c2014-08-27 17:02:52 +0200681
Pablo Neira Ayuso3ba3cf82014-08-29 08:46:05 +0200682 if (sscanf(line + 2, "Osmux: %u", &osmux_cid) != 1)
683 return -1;
684
Pablo Neira Ayusob769f3c2014-08-27 17:02:52 +0200685 if (osmux_cid > OSMUX_CID_MAX) {
686 LOGP(DMGCP, LOGL_ERROR, "Osmux ID too large: %u > %u\n",
687 osmux_cid, OSMUX_CID_MAX);
688 return -1;
689 }
690 LOGP(DMGCP, LOGL_DEBUG, "bsc-nat offered Osmux CID %u\n", osmux_cid);
691
692 return osmux_cid;
693}
694
695static int mgcp_osmux_setup(struct mgcp_endpoint *endp, const char *line)
Pablo Neira Ayuso8be171e2014-08-27 14:58:43 +0200696{
697 if (!endp->cfg->osmux_init) {
698 if (osmux_init(OSMUX_ROLE_BSC, endp->cfg) < 0) {
699 LOGP(DMGCP, LOGL_ERROR, "Cannot init OSMUX\n");
700 return -1;
701 }
702 LOGP(DMGCP, LOGL_NOTICE, "OSMUX socket has been set up\n");
703 }
704
Pablo Neira Ayusob769f3c2014-08-27 17:02:52 +0200705 return mgcp_parse_osmux_cid(line);
Pablo Neira Ayuso8be171e2014-08-27 14:58:43 +0200706}
707
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100708static struct msgb *handle_create_con(struct mgcp_parse_data *p)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100709{
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +0100710 struct mgcp_trunk_config *tcfg;
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100711 struct mgcp_endpoint *endp = p->endp;
Holger Hans Peter Freyther9e9392d2010-08-08 16:24:48 +0800712 int error_code = 400;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100713
Holger Hans Peter Freyther3488c3d2011-07-20 20:44:54 +0200714 const char *local_options = NULL;
715 const char *callid = NULL;
716 const char *mode = NULL;
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100717 char *line;
Pablo Neira Ayusob769f3c2014-08-27 17:02:52 +0200718 int have_sdp = 0, osmux_cid = -1;
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100719
720 if (p->found != 0)
721 return create_err_response(NULL, 510, "CRCX", p->trans);
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +0100722
Holger Hans Peter Freyther3488c3d2011-07-20 20:44:54 +0200723 /* parse CallID C: and LocalParameters L: */
Jacob Erlbeck17711712013-11-29 13:43:46 +0100724 for_each_line(line, p->save) {
Holger Hans Peter Freyther1cc5ff82014-05-22 15:03:10 +0200725 if (!mgcp_check_param(endp, line))
726 continue;
727
Harald Welteae199722012-01-27 12:31:36 +0100728 switch (line[0]) {
729 case 'L':
730 local_options = (const char *) line + 3;
731 break;
732 case 'C':
733 callid = (const char *) line + 3;
734 break;
735 case 'M':
736 mode = (const char *) line + 3;
737 break;
Pablo Neira Ayusocab6e752014-02-05 18:56:17 +0100738 case 'X':
Pablo Neira Ayusob769f3c2014-08-27 17:02:52 +0200739 /* Osmux is not enabled in this bsc, ignore it so the
740 * bsc-nat knows that we don't want to use Osmux.
741 */
742 if (!p->endp->cfg->osmux)
743 break;
744
745 if (strncmp("Osmux: ", line + 2, strlen("Osmux: ")) == 0)
746 osmux_cid = mgcp_osmux_setup(endp, line);
Pablo Neira Ayusocab6e752014-02-05 18:56:17 +0100747 break;
Jacob Erlbeck78a95012013-11-29 13:43:49 +0100748 case '\0':
749 have_sdp = 1;
750 goto mgcp_header_done;
Harald Welteae199722012-01-27 12:31:36 +0100751 default:
752 LOGP(DMGCP, LOGL_NOTICE, "Unhandled option: '%c'/%d on 0x%x\n",
753 *line, *line, ENDPOINT_NUMBER(endp));
754 break;
755 }
Holger Hans Peter Freyther3488c3d2011-07-20 20:44:54 +0200756 }
Harald Welteae199722012-01-27 12:31:36 +0100757
Jacob Erlbeck78a95012013-11-29 13:43:49 +0100758mgcp_header_done:
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100759 tcfg = p->endp->tcfg;
Holger Hans Peter Freyther3488c3d2011-07-20 20:44:54 +0200760
761 /* Check required data */
762 if (!callid || !mode) {
763 LOGP(DMGCP, LOGL_ERROR, "Missing callid and mode in CRCX on 0x%x\n",
764 ENDPOINT_NUMBER(endp));
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100765 return create_err_response(endp, 400, "CRCX", p->trans);
Holger Hans Peter Freyther3488c3d2011-07-20 20:44:54 +0200766 }
767
Holger Hans Peter Freyther39a97e22010-08-06 18:03:11 +0800768 if (endp->allocated) {
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +0100769 if (tcfg->force_realloc) {
Holger Hans Peter Freyther408cc4a2010-04-07 10:51:27 +0200770 LOGP(DMGCP, LOGL_NOTICE, "Endpoint 0x%x already allocated. Forcing realloc.\n",
771 ENDPOINT_NUMBER(endp));
Holger Hans Peter Freythercb6ad702014-07-22 15:00:52 +0200772 mgcp_release_endp(endp);
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100773 if (p->cfg->realloc_cb)
774 p->cfg->realloc_cb(tcfg, ENDPOINT_NUMBER(endp));
Holger Hans Peter Freyther408cc4a2010-04-07 10:51:27 +0200775 } else {
776 LOGP(DMGCP, LOGL_ERROR, "Endpoint is already used. 0x%x\n",
777 ENDPOINT_NUMBER(endp));
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100778 return create_err_response(endp, 400, "CRCX", p->trans);
Holger Hans Peter Freyther408cc4a2010-04-07 10:51:27 +0200779 }
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100780 }
781
Holger Hans Peter Freyther3488c3d2011-07-20 20:44:54 +0200782 /* copy some parameters */
783 endp->callid = talloc_strdup(tcfg->endpoints, callid);
784
Jacob Erlbeck2c2ca4d2013-12-09 14:32:03 +0100785 set_local_cx_options(endp->tcfg->endpoints, &endp->local_options,
786 local_options);
Holger Hans Peter Freyther3488c3d2011-07-20 20:44:54 +0200787
Jacob Erlbeck2645c9e2013-12-19 12:23:24 +0100788 if (parse_conn_mode(mode, endp) != 0) {
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100789 error_code = 517;
790 goto error2;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100791 }
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100792
793 /* initialize */
Holger Hans Peter Freythera17d7012010-08-05 01:34:51 +0800794 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 +0100795 mgcp_rtp_end_config(endp, 0, &endp->net_end);
796 mgcp_rtp_end_config(endp, 0, &endp->bts_end);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100797
798 /* set to zero until we get the info */
Holger Hans Peter Freythera17d7012010-08-05 01:34:51 +0800799 memset(&endp->net_end.addr, 0, sizeof(endp->net_end.addr));
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100800
801 /* bind to the port now */
Holger Hans Peter Freytherf138f912010-08-05 08:08:17 +0800802 if (allocate_ports(endp) != 0)
803 goto error2;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100804
805 /* assign a local call identifier or fail */
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100806 endp->ci = generate_call_id(p->cfg);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100807 if (endp->ci == CI_UNUSED)
808 goto error2;
809
Daniel Willmann57542062016-06-29 16:24:42 +0200810 /* Annotate Osmux circuit ID and set it to negotiating state until this
Pablo Neira Ayusob769f3c2014-08-27 17:02:52 +0200811 * is fully set up from the dummy load.
812 */
813 endp->osmux.state = OSMUX_STATE_DISABLED;
814 if (osmux_cid >= 0) {
815 endp->osmux.cid = osmux_cid;
Daniel Willmann57542062016-06-29 16:24:42 +0200816 endp->osmux.state = OSMUX_STATE_NEGOTIATING;
Harald Welte7e5bb622016-09-28 08:20:58 +0800817 } else if (endp->cfg->osmux == OSMUX_USAGE_ONLY) {
Holger Hans Peter Freyther6598ded2015-10-02 17:38:27 +0200818 LOGP(DMGCP, LOGL_ERROR,
819 "Osmux only and no osmux offered on 0x%x\n", ENDPOINT_NUMBER(endp));
820 goto error2;
Pablo Neira Ayusob769f3c2014-08-27 17:02:52 +0200821 }
822
Holger Hans Peter Freyther39a97e22010-08-06 18:03:11 +0800823 endp->allocated = 1;
Jacob Erlbeck78a95012013-11-29 13:43:49 +0100824
825 /* set up RTP media parameters */
Holger Hans Peter Freythera611da82015-08-14 09:24:11 +0200826 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 +0200827 endp->bts_end.fmtp_extra = talloc_strdup(tcfg->endpoints,
828 tcfg->audio_fmtp_extra);
Jacob Erlbeck42a833e2014-04-14 10:31:47 +0200829 if (have_sdp)
Holger Hans Peter Freytheraeadf262015-08-14 15:43:06 +0200830 mgcp_parse_sdp_data(endp, &endp->net_end, p);
Jacob Erlbeck452c1832014-05-09 19:42:17 +0200831 else if (endp->local_options.codec)
Holger Hans Peter Freythera611da82015-08-14 09:24:11 +0200832 mgcp_set_audio_info(p->cfg, &endp->net_end.codec,
Jacob Erlbeck452c1832014-05-09 19:42:17 +0200833 PTYPE_UNDEFINED, endp->local_options.codec);
Jacob Erlbeck42a833e2014-04-14 10:31:47 +0200834
835 if (p->cfg->bts_force_ptime) {
836 endp->bts_end.packet_duration_ms = p->cfg->bts_force_ptime;
837 endp->bts_end.force_output_ptime = 1;
Jacob Erlbecka0d64ce2014-03-13 14:24:52 +0100838 }
Holger Hans Peter Freytheref6bb252010-02-26 13:41:22 +0100839
Holger Hans Peter Freyther7cce1d32015-03-26 20:34:12 +0100840 if (setup_rtp_processing(endp) != 0)
841 goto error2;
Jacob Erlbeck42a833e2014-04-14 10:31:47 +0200842
Holger Hans Peter Freytherfe86d3c2010-02-26 13:37:05 +0100843 /* policy CB */
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100844 if (p->cfg->policy_cb) {
845 int rc;
846 rc = p->cfg->policy_cb(tcfg, ENDPOINT_NUMBER(endp),
847 MGCP_ENDP_CRCX, p->trans);
848 switch (rc) {
Holger Hans Peter Freytherfe86d3c2010-02-26 13:37:05 +0100849 case MGCP_POLICY_REJECT:
850 LOGP(DMGCP, LOGL_NOTICE, "CRCX rejected by policy on 0x%x\n",
851 ENDPOINT_NUMBER(endp));
Holger Hans Peter Freythercb6ad702014-07-22 15:00:52 +0200852 mgcp_release_endp(endp);
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100853 return create_err_response(endp, 400, "CRCX", p->trans);
Holger Hans Peter Freytherfe86d3c2010-02-26 13:37:05 +0100854 break;
855 case MGCP_POLICY_DEFER:
856 /* stop processing */
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +0800857 create_transcoder(endp);
Holger Hans Peter Freytherfe86d3c2010-02-26 13:37:05 +0100858 return NULL;
859 break;
860 case MGCP_POLICY_CONT:
861 /* just continue */
862 break;
863 }
864 }
865
Holger Hans Peter Freythere378cb12010-08-06 20:22:23 +0800866 LOGP(DMGCP, LOGL_DEBUG, "Creating endpoint on: 0x%x CI: %u port: %u/%u\n",
Holger Hans Peter Freyther58ff2192010-08-05 03:08:35 +0800867 ENDPOINT_NUMBER(endp), endp->ci,
868 endp->net_end.local_port, endp->bts_end.local_port);
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100869 if (p->cfg->change_cb)
870 p->cfg->change_cb(tcfg, ENDPOINT_NUMBER(endp), MGCP_ENDP_CRCX);
Holger Hans Peter Freyther77f7afe2010-02-03 09:54:43 +0100871
Pablo Neira Ayusocab6e752014-02-05 18:56:17 +0100872 if (endp->conn_mode & MGCP_CONN_RECV_ONLY && tcfg->keepalive_interval != 0) {
Holger Hans Peter Freyther6b0ba012014-07-08 13:01:56 +0200873 send_dummy(endp);
Pablo Neira Ayusocab6e752014-02-05 18:56:17 +0100874 }
Jacob Erlbeck075a9eb2013-12-19 18:53:07 +0100875
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +0800876 create_transcoder(endp);
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100877 return create_response_with_sdp(endp, "CRCX", p->trans);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100878error2:
Holger Hans Peter Freythercb6ad702014-07-22 15:00:52 +0200879 mgcp_release_endp(endp);
Holger Hans Peter Freyther2ada71d2010-02-03 09:13:10 +0100880 LOGP(DMGCP, LOGL_NOTICE, "Resource error on 0x%x\n", ENDPOINT_NUMBER(endp));
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100881 return create_err_response(endp, error_code, "CRCX", p->trans);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100882}
883
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100884static struct msgb *handle_modify_con(struct mgcp_parse_data *p)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100885{
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100886 struct mgcp_endpoint *endp = p->endp;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100887 int error_code = 500;
Pablo Neira Ayusob769f3c2014-08-27 17:02:52 +0200888 int silent = 0;
Jacob Erlbeck452c1832014-05-09 19:42:17 +0200889 int have_sdp = 0;
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100890 char *line;
Jacob Erlbeck2c2ca4d2013-12-09 14:32:03 +0100891 const char *local_options = NULL;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100892
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100893 if (p->found != 0)
894 return create_err_response(NULL, 510, "MDCX", p->trans);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100895
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100896 if (endp->ci == CI_UNUSED) {
897 LOGP(DMGCP, LOGL_ERROR, "Endpoint is not "
898 "holding a connection. 0x%x\n", ENDPOINT_NUMBER(endp));
899 return create_err_response(endp, 400, "MDCX", p->trans);
900 }
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100901
Jacob Erlbeck17711712013-11-29 13:43:46 +0100902 for_each_line(line, p->save) {
Holger Hans Peter Freyther1cc5ff82014-05-22 15:03:10 +0200903 if (!mgcp_check_param(endp, line))
904 continue;
905
Harald Welteae199722012-01-27 12:31:36 +0100906 switch (line[0]) {
907 case 'C': {
908 if (verify_call_id(endp, line + 3) != 0)
909 goto error3;
910 break;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100911 }
Harald Welteae199722012-01-27 12:31:36 +0100912 case 'I': {
913 if (verify_ci(endp, line + 3) != 0)
914 goto error3;
915 break;
916 }
917 case 'L':
Jacob Erlbeck2c2ca4d2013-12-09 14:32:03 +0100918 local_options = (const char *) line + 3;
Harald Welteae199722012-01-27 12:31:36 +0100919 break;
920 case 'M':
Jacob Erlbeck2645c9e2013-12-19 12:23:24 +0100921 if (parse_conn_mode(line + 3, endp) != 0) {
Harald Welteae199722012-01-27 12:31:36 +0100922 error_code = 517;
923 goto error3;
924 }
925 endp->orig_mode = endp->conn_mode;
926 break;
927 case 'Z':
928 silent = strcmp("noanswer", line + 3) == 0;
929 break;
930 case '\0':
931 /* SDP file begins */
Jacob Erlbeck452c1832014-05-09 19:42:17 +0200932 have_sdp = 1;
Holger Hans Peter Freytheraeadf262015-08-14 15:43:06 +0200933 mgcp_parse_sdp_data(endp, &endp->net_end, p);
Jacob Erlbeck17711712013-11-29 13:43:46 +0100934 /* This will exhaust p->save, so the loop will
935 * terminate next time.
936 */
Harald Welteae199722012-01-27 12:31:36 +0100937 break;
Harald Welteae199722012-01-27 12:31:36 +0100938 default:
Jacob Erlbeck17711712013-11-29 13:43:46 +0100939 LOGP(DMGCP, LOGL_NOTICE, "Unhandled MGCP option: '%c'/%d on 0x%x\n",
Harald Welteae199722012-01-27 12:31:36 +0100940 line[0], line[0], ENDPOINT_NUMBER(endp));
941 break;
942 }
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100943 }
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100944
Jacob Erlbeck2c2ca4d2013-12-09 14:32:03 +0100945 set_local_cx_options(endp->tcfg->endpoints, &endp->local_options,
946 local_options);
947
Jacob Erlbeck452c1832014-05-09 19:42:17 +0200948 if (!have_sdp && endp->local_options.codec)
Holger Hans Peter Freythera611da82015-08-14 09:24:11 +0200949 mgcp_set_audio_info(p->cfg, &endp->net_end.codec,
Jacob Erlbeck452c1832014-05-09 19:42:17 +0200950 PTYPE_UNDEFINED, endp->local_options.codec);
951
Holger Hans Peter Freyther7cce1d32015-03-26 20:34:12 +0100952 if (setup_rtp_processing(endp) != 0)
953 goto error3;
Jacob Erlbecka0d64ce2014-03-13 14:24:52 +0100954
Holger Hans Peter Freytherfe86d3c2010-02-26 13:37:05 +0100955 /* policy CB */
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100956 if (p->cfg->policy_cb) {
957 int rc;
958 rc = p->cfg->policy_cb(endp->tcfg, ENDPOINT_NUMBER(endp),
959 MGCP_ENDP_MDCX, p->trans);
960 switch (rc) {
Holger Hans Peter Freytherfe86d3c2010-02-26 13:37:05 +0100961 case MGCP_POLICY_REJECT:
962 LOGP(DMGCP, LOGL_NOTICE, "MDCX rejected by policy on 0x%x\n",
963 ENDPOINT_NUMBER(endp));
Holger Hans Peter Freythere3d16bb2010-04-22 11:58:13 +0800964 if (silent)
965 goto out_silent;
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100966 return create_err_response(endp, 400, "MDCX", p->trans);
Holger Hans Peter Freytherfe86d3c2010-02-26 13:37:05 +0100967 break;
968 case MGCP_POLICY_DEFER:
969 /* stop processing */
Neels Hofmeyra1756f32016-05-20 21:59:55 +0200970 LOGP(DMGCP, LOGL_DEBUG, "endp %x MDCX defer\n",
971 ENDPOINT_NUMBER(endp));
Holger Hans Peter Freytherfe86d3c2010-02-26 13:37:05 +0100972 return NULL;
973 break;
974 case MGCP_POLICY_CONT:
975 /* just continue */
976 break;
977 }
978 }
979
Jacob Erlbeckdb2d4312013-12-03 14:43:34 +0100980 mgcp_rtp_end_config(endp, 1, &endp->net_end);
981 mgcp_rtp_end_config(endp, 1, &endp->bts_end);
982
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100983 /* modify */
Holger Hans Peter Freythere378cb12010-08-06 20:22:23 +0800984 LOGP(DMGCP, LOGL_DEBUG, "Modified endpoint on: 0x%x Server: %s:%u\n",
Holger Hans Peter Freythera17d7012010-08-05 01:34:51 +0800985 ENDPOINT_NUMBER(endp), inet_ntoa(endp->net_end.addr), ntohs(endp->net_end.rtp_port));
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100986 if (p->cfg->change_cb)
987 p->cfg->change_cb(endp->tcfg, ENDPOINT_NUMBER(endp), MGCP_ENDP_MDCX);
Jacob Erlbeck075a9eb2013-12-19 18:53:07 +0100988
Jacob Erlbecke35fd132014-01-16 16:50:40 +0100989 if (endp->conn_mode & MGCP_CONN_RECV_ONLY &&
990 endp->tcfg->keepalive_interval != 0)
Holger Hans Peter Freyther6b0ba012014-07-08 13:01:56 +0200991 send_dummy(endp);
Jacob Erlbeck075a9eb2013-12-19 18:53:07 +0100992
Holger Hans Peter Freythere3d16bb2010-04-22 11:58:13 +0800993 if (silent)
994 goto out_silent;
995
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100996 return create_response_with_sdp(endp, "MDCX", p->trans);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100997
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100998error3:
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100999 return create_err_response(endp, error_code, "MDCX", p->trans);
Holger Hans Peter Freythere3d16bb2010-04-22 11:58:13 +08001000
1001
1002out_silent:
Neels Hofmeyra1756f32016-05-20 21:59:55 +02001003 LOGP(DMGCP, LOGL_DEBUG, "endp %x Modify endpoint: silent exit\n",
1004 ENDPOINT_NUMBER(endp));
Holger Hans Peter Freythere3d16bb2010-04-22 11:58:13 +08001005 return NULL;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +01001006}
1007
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +01001008static struct msgb *handle_delete_con(struct mgcp_parse_data *p)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +01001009{
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +01001010 struct mgcp_endpoint *endp = p->endp;
Holger Hans Peter Freyther9e9392d2010-08-08 16:24:48 +08001011 int error_code = 400;
Holger Hans Peter Freythere3d16bb2010-04-22 11:58:13 +08001012 int silent = 0;
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +01001013 char *line;
Holger Hans Peter Freyther0bf15a82012-09-14 17:18:12 +02001014 char stats[1048];
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +01001015
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +01001016 if (p->found != 0)
1017 return create_err_response(NULL, error_code, "DLCX", p->trans);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +01001018
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +01001019 if (!p->endp->allocated) {
1020 LOGP(DMGCP, LOGL_ERROR, "Endpoint is not used. 0x%x\n",
1021 ENDPOINT_NUMBER(endp));
1022 return create_err_response(endp, 400, "DLCX", p->trans);
1023 }
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +01001024
Jacob Erlbeck17711712013-11-29 13:43:46 +01001025 for_each_line(line, p->save) {
Holger Hans Peter Freyther1cc5ff82014-05-22 15:03:10 +02001026 if (!mgcp_check_param(endp, line))
1027 continue;
1028
Harald Welteae199722012-01-27 12:31:36 +01001029 switch (line[0]) {
1030 case 'C':
1031 if (verify_call_id(endp, line + 3) != 0)
1032 goto error3;
1033 break;
1034 case 'I':
1035 if (verify_ci(endp, line + 3) != 0)
1036 goto error3;
1037 break;
1038 case 'Z':
1039 silent = strcmp("noanswer", line + 3) == 0;
1040 break;
1041 default:
1042 LOGP(DMGCP, LOGL_NOTICE, "Unhandled option: '%c'/%d on 0x%x\n",
1043 line[0], line[0], ENDPOINT_NUMBER(endp));
1044 break;
1045 }
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +01001046 }
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +01001047
Holger Hans Peter Freytherfe86d3c2010-02-26 13:37:05 +01001048 /* policy CB */
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +01001049 if (p->cfg->policy_cb) {
1050 int rc;
1051 rc = p->cfg->policy_cb(endp->tcfg, ENDPOINT_NUMBER(endp),
1052 MGCP_ENDP_DLCX, p->trans);
1053 switch (rc) {
Holger Hans Peter Freytherfe86d3c2010-02-26 13:37:05 +01001054 case MGCP_POLICY_REJECT:
1055 LOGP(DMGCP, LOGL_NOTICE, "DLCX rejected by policy on 0x%x\n",
1056 ENDPOINT_NUMBER(endp));
Holger Hans Peter Freythere3d16bb2010-04-22 11:58:13 +08001057 if (silent)
1058 goto out_silent;
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +01001059 return create_err_response(endp, 400, "DLCX", p->trans);
Holger Hans Peter Freytherfe86d3c2010-02-26 13:37:05 +01001060 break;
1061 case MGCP_POLICY_DEFER:
1062 /* stop processing */
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +08001063 delete_transcoder(endp);
Holger Hans Peter Freytherfe86d3c2010-02-26 13:37:05 +01001064 return NULL;
1065 break;
1066 case MGCP_POLICY_CONT:
1067 /* just continue */
1068 break;
1069 }
1070 }
1071
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +01001072 /* free the connection */
Holger Hans Peter Freythere378cb12010-08-06 20:22:23 +08001073 LOGP(DMGCP, LOGL_DEBUG, "Deleted endpoint on: 0x%x Server: %s:%u\n",
Holger Hans Peter Freythera17d7012010-08-05 01:34:51 +08001074 ENDPOINT_NUMBER(endp), inet_ntoa(endp->net_end.addr), ntohs(endp->net_end.rtp_port));
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +08001075
Holger Hans Peter Freyther0bf15a82012-09-14 17:18:12 +02001076 /* save the statistics of the current call */
1077 mgcp_format_stats(endp, stats, sizeof(stats));
1078
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +08001079 delete_transcoder(endp);
Holger Hans Peter Freythercb6ad702014-07-22 15:00:52 +02001080 mgcp_release_endp(endp);
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +01001081 if (p->cfg->change_cb)
1082 p->cfg->change_cb(endp->tcfg, ENDPOINT_NUMBER(endp), MGCP_ENDP_DLCX);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +01001083
Holger Hans Peter Freythere3d16bb2010-04-22 11:58:13 +08001084 if (silent)
1085 goto out_silent;
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +01001086 return create_ok_resp_with_param(endp, 250, "DLCX", p->trans, stats);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +01001087
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +01001088error3:
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +01001089 return create_err_response(endp, error_code, "DLCX", p->trans);
Holger Hans Peter Freythere3d16bb2010-04-22 11:58:13 +08001090
1091out_silent:
1092 return NULL;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +01001093}
1094
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +01001095static struct msgb *handle_rsip(struct mgcp_parse_data *p)
Holger Hans Peter Freyther9bdcc9c2010-03-31 06:39:35 +02001096{
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +01001097 if (p->found != 0) {
Holger Hans Peter Freyther74db7742011-06-10 00:04:55 +02001098 LOGP(DMGCP, LOGL_ERROR, "Failed to find the endpoint.\n");
1099 return NULL;
1100 }
1101
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +01001102 if (p->cfg->reset_cb)
1103 p->cfg->reset_cb(p->endp->tcfg);
Holger Hans Peter Freyther9bdcc9c2010-03-31 06:39:35 +02001104 return NULL;
1105}
1106
Holger Hans Peter Freyther8d0be252012-11-29 12:54:22 +01001107static char extract_tone(const char *line)
1108{
1109 const char *str = strstr(line, "D/");
1110 if (!str)
1111 return CHAR_MAX;
1112
1113 return str[2];
1114}
1115
Holger Hans Peter Freyther6e94d6d2011-01-25 23:33:54 +01001116/*
1117 * This can request like DTMF detection and forward, fax detection... it
1118 * can also request when the notification should be send and such. We don't
1119 * do this right now.
1120 */
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +01001121static struct msgb *handle_noti_req(struct mgcp_parse_data *p)
Holger Hans Peter Freyther6e94d6d2011-01-25 23:33:54 +01001122{
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +01001123 int res = 0;
1124 char *line;
Holger Hans Peter Freyther9f3835b2013-05-21 17:04:35 +02001125 char tone = CHAR_MAX;
Holger Hans Peter Freyther6e94d6d2011-01-25 23:33:54 +01001126
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +01001127 if (p->found != 0)
1128 return create_err_response(NULL, 400, "RQNT", p->trans);
Holger Hans Peter Freyther6e94d6d2011-01-25 23:33:54 +01001129
Jacob Erlbeck17711712013-11-29 13:43:46 +01001130 for_each_line(line, p->save) {
Holger Hans Peter Freyther8d0be252012-11-29 12:54:22 +01001131 switch (line[0]) {
1132 case 'S':
1133 tone = extract_tone(line);
1134 break;
1135 }
Holger Hans Peter Freyther6e94d6d2011-01-25 23:33:54 +01001136 }
Holger Hans Peter Freyther8d0be252012-11-29 12:54:22 +01001137
1138 /* we didn't see a signal request with a tone */
1139 if (tone == CHAR_MAX)
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +01001140 return create_ok_response(p->endp, 200, "RQNT", p->trans);
Holger Hans Peter Freyther8d0be252012-11-29 12:54:22 +01001141
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +01001142 if (p->cfg->rqnt_cb)
1143 res = p->cfg->rqnt_cb(p->endp, tone);
Holger Hans Peter Freyther8d0be252012-11-29 12:54:22 +01001144
1145 return res == 0 ?
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +01001146 create_ok_response(p->endp, 200, "RQNT", p->trans) :
1147 create_err_response(p->endp, res, "RQNT", p->trans);
Holger Hans Peter Freyther6e94d6d2011-01-25 23:33:54 +01001148}
1149
Jacob Erlbeck075a9eb2013-12-19 18:53:07 +01001150static void mgcp_keepalive_timer_cb(void *_tcfg)
1151{
1152 struct mgcp_trunk_config *tcfg = _tcfg;
1153 int i;
1154 LOGP(DMGCP, LOGL_DEBUG, "Triggered trunk %d keepalive timer.\n",
1155 tcfg->trunk_nr);
1156
1157 if (tcfg->keepalive_interval <= 0)
1158 return;
1159
1160 for (i = 1; i < tcfg->number_endpoints; ++i) {
1161 struct mgcp_endpoint *endp = &tcfg->endpoints[i];
1162 if (endp->conn_mode == MGCP_CONN_RECV_ONLY)
Holger Hans Peter Freyther6b0ba012014-07-08 13:01:56 +02001163 send_dummy(endp);
Jacob Erlbeck075a9eb2013-12-19 18:53:07 +01001164 }
1165
1166 LOGP(DMGCP, LOGL_DEBUG, "Rescheduling trunk %d keepalive timer.\n",
1167 tcfg->trunk_nr);
1168 osmo_timer_schedule(&tcfg->keepalive_timer, tcfg->keepalive_interval, 0);
1169}
1170
1171void mgcp_trunk_set_keepalive(struct mgcp_trunk_config *tcfg, int interval)
1172{
1173 tcfg->keepalive_interval = interval;
Pablo Neira Ayuso51215762017-05-08 20:57:52 +02001174 osmo_timer_setup(&tcfg->keepalive_timer, mgcp_keepalive_timer_cb, tcfg);
Jacob Erlbeck075a9eb2013-12-19 18:53:07 +01001175
1176 if (interval <= 0)
1177 osmo_timer_del(&tcfg->keepalive_timer);
1178 else
1179 osmo_timer_schedule(&tcfg->keepalive_timer,
1180 tcfg->keepalive_interval, 0);
1181}
1182
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +01001183struct mgcp_config *mgcp_config_alloc(void)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +01001184{
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +01001185 struct mgcp_config *cfg;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +01001186
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +01001187 cfg = talloc_zero(NULL, struct mgcp_config);
1188 if (!cfg) {
1189 LOGP(DMGCP, LOGL_FATAL, "Failed to allocate config.\n");
1190 return NULL;
1191 }
1192
1193 cfg->source_port = 2427;
1194 cfg->source_addr = talloc_strdup(cfg, "0.0.0.0");
Holger Hans Peter Freythera777c9e2015-10-12 20:06:16 +02001195 cfg->osmux_addr = talloc_strdup(cfg, "0.0.0.0");
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +01001196
Holger Hans Peter Freytherb98ba722010-09-19 04:21:39 +08001197 cfg->transcoder_remote_base = 4000;
Holger Hans Peter Freyther15e73892010-08-05 07:10:56 +08001198
1199 cfg->bts_ports.base_port = RTP_PORT_DEFAULT;
1200 cfg->net_ports.base_port = RTP_PORT_NET_DEFAULT;
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +01001201
Jacob Erlbecka0d64ce2014-03-13 14:24:52 +01001202 cfg->rtp_processing_cb = &mgcp_rtp_processing_default;
1203 cfg->setup_rtp_processing_cb = &mgcp_setup_rtp_processing_default;
1204
Jacob Erlbeck168ca002014-03-17 12:40:07 +01001205 cfg->get_net_downlink_format_cb = &mgcp_get_net_downlink_format_default;
1206
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +01001207 /* default trunk handling */
1208 cfg->trunk.cfg = cfg;
1209 cfg->trunk.trunk_nr = 0;
1210 cfg->trunk.trunk_type = MGCP_TRUNK_VIRTUAL;
1211 cfg->trunk.audio_name = talloc_strdup(cfg, "AMR/8000");
1212 cfg->trunk.audio_payload = 126;
Jacob Erlbeck0a1bc562013-12-10 13:09:37 +01001213 cfg->trunk.audio_send_ptime = 1;
Holger Hans Peter Freyther619b0142014-11-19 16:04:45 +01001214 cfg->trunk.audio_send_name = 1;
Holger Hans Peter Freythera8090d52012-05-11 13:00:45 +02001215 cfg->trunk.omit_rtcp = 0;
Jacob Erlbeck075a9eb2013-12-19 18:53:07 +01001216 mgcp_trunk_set_keepalive(&cfg->trunk, MGCP_KEEPALIVE_ONCE);
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +01001217
Holger Hans Peter Freyther0e939fe2011-02-28 12:11:02 +01001218 INIT_LLIST_HEAD(&cfg->trunks);
1219
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +01001220 return cfg;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +01001221}
1222
Holger Hans Peter Freyther0e939fe2011-02-28 12:11:02 +01001223struct mgcp_trunk_config *mgcp_trunk_alloc(struct mgcp_config *cfg, int nr)
1224{
1225 struct mgcp_trunk_config *trunk;
1226
1227 trunk = talloc_zero(cfg, struct mgcp_trunk_config);
1228 if (!trunk) {
1229 LOGP(DMGCP, LOGL_ERROR, "Failed to allocate.\n");
1230 return NULL;
1231 }
1232
1233 trunk->cfg = cfg;
1234 trunk->trunk_type = MGCP_TRUNK_E1;
1235 trunk->trunk_nr = nr;
1236 trunk->audio_name = talloc_strdup(cfg, "AMR/8000");
1237 trunk->audio_payload = 126;
Jacob Erlbeck0a1bc562013-12-10 13:09:37 +01001238 trunk->audio_send_ptime = 1;
Holger Hans Peter Freyther619b0142014-11-19 16:04:45 +01001239 trunk->audio_send_name = 1;
Holger Hans Peter Freyther0e939fe2011-02-28 12:11:02 +01001240 trunk->number_endpoints = 33;
Holger Hans Peter Freythera8090d52012-05-11 13:00:45 +02001241 trunk->omit_rtcp = 0;
Jacob Erlbeck075a9eb2013-12-19 18:53:07 +01001242 mgcp_trunk_set_keepalive(trunk, MGCP_KEEPALIVE_ONCE);
Holger Hans Peter Freyther0e939fe2011-02-28 12:11:02 +01001243 llist_add_tail(&trunk->entry, &cfg->trunks);
1244 return trunk;
1245}
1246
1247struct mgcp_trunk_config *mgcp_trunk_num(struct mgcp_config *cfg, int index)
1248{
1249 struct mgcp_trunk_config *trunk;
1250
1251 llist_for_each_entry(trunk, &cfg->trunks, entry)
1252 if (trunk->trunk_nr == index)
1253 return trunk;
1254
1255 return NULL;
1256}
1257
Holger Hans Peter Freytherfa80d072014-09-01 10:40:19 +02001258static void mgcp_rtp_codec_reset(struct mgcp_rtp_codec *codec)
1259{
1260 codec->payload_type = -1;
1261 talloc_free(codec->subtype_name);
1262 codec->subtype_name = NULL;
1263 talloc_free(codec->audio_name);
1264 codec->audio_name = NULL;
1265 codec->frame_duration_num = DEFAULT_RTP_AUDIO_FRAME_DUR_NUM;
1266 codec->frame_duration_den = DEFAULT_RTP_AUDIO_FRAME_DUR_DEN;
1267 codec->rate = DEFAULT_RTP_AUDIO_DEFAULT_RATE;
1268 codec->channels = DEFAULT_RTP_AUDIO_DEFAULT_CHANNELS;
1269}
1270
Holger Hans Peter Freythera17d7012010-08-05 01:34:51 +08001271static void mgcp_rtp_end_reset(struct mgcp_rtp_end *end)
1272{
Holger Hans Peter Freythere97155a2010-11-02 19:06:13 +01001273 if (end->local_alloc == PORT_ALLOC_DYNAMIC) {
Holger Hans Peter Freytherf138f912010-08-05 08:08:17 +08001274 mgcp_free_rtp_port(end);
Holger Hans Peter Freythere97155a2010-11-02 19:06:13 +01001275 end->local_port = 0;
1276 }
Holger Hans Peter Freytherf138f912010-08-05 08:08:17 +08001277
Holger Hans Peter Freytherc4921272010-08-05 03:37:22 +08001278 end->packets = 0;
Holger Hans Peter Freyther952f7522012-09-12 11:38:37 +02001279 end->octets = 0;
Jacob Erlbeck0970bab2013-12-19 12:13:32 +01001280 end->dropped_packets = 0;
Holger Hans Peter Freytherc4921272010-08-05 03:37:22 +08001281 memset(&end->addr, 0, sizeof(end->addr));
Holger Hans Peter Freythere97155a2010-11-02 19:06:13 +01001282 end->rtp_port = end->rtcp_port = 0;
Holger Hans Peter Freytherf138f912010-08-05 08:08:17 +08001283 end->local_alloc = -1;
Holger Hans Peter Freyther5ea1bc72012-09-03 00:07:39 +02001284 talloc_free(end->fmtp_extra);
1285 end->fmtp_extra = NULL;
Jacob Erlbecka0d64ce2014-03-13 14:24:52 +01001286 talloc_free(end->rtp_process_data);
1287 end->rtp_process_data = NULL;
Jacob Erlbeck72c30902013-11-25 15:23:35 +01001288
1289 /* Set default values */
Jacob Erlbeckf6ec0e92013-12-04 10:30:11 +01001290 end->frames_per_packet = 0; /* unknown */
1291 end->packet_duration_ms = DEFAULT_RTP_AUDIO_PACKET_DURATION_MS;
Jacob Erlbeck8857c902014-01-16 16:50:39 +01001292 end->output_enabled = 0;
Holger Hans Peter Freytherfa80d072014-09-01 10:40:19 +02001293
1294 mgcp_rtp_codec_reset(&end->codec);
Holger Hans Peter Freythere46bc272014-09-01 10:50:22 +02001295 mgcp_rtp_codec_reset(&end->alt_codec);
Holger Hans Peter Freythera17d7012010-08-05 01:34:51 +08001296}
1297
Holger Hans Peter Freytherc4921272010-08-05 03:37:22 +08001298static void mgcp_rtp_end_init(struct mgcp_rtp_end *end)
1299{
1300 mgcp_rtp_end_reset(end);
1301 end->rtp.fd = -1;
1302 end->rtcp.fd = -1;
1303}
1304
Holger Hans Peter Freyther1f0c5b42011-02-28 14:37:03 +01001305int mgcp_endpoints_allocate(struct mgcp_trunk_config *tcfg)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +01001306{
1307 int i;
1308
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +01001309 /* Initialize all endpoints */
Holger Hans Peter Freyther1f0c5b42011-02-28 14:37:03 +01001310 tcfg->endpoints = _talloc_zero_array(tcfg->cfg,
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +01001311 sizeof(struct mgcp_endpoint),
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +01001312 tcfg->number_endpoints, "endpoints");
1313 if (!tcfg->endpoints)
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +01001314 return -1;
1315
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +01001316 for (i = 0; i < tcfg->number_endpoints; ++i) {
Holger Hans Peter Freyther1afe7c72015-10-04 11:11:11 +02001317 tcfg->endpoints[i].osmux.allocated_cid = -1;
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +01001318 tcfg->endpoints[i].ci = CI_UNUSED;
Holger Hans Peter Freyther1f0c5b42011-02-28 14:37:03 +01001319 tcfg->endpoints[i].cfg = tcfg->cfg;
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +01001320 tcfg->endpoints[i].tcfg = tcfg;
1321 mgcp_rtp_end_init(&tcfg->endpoints[i].net_end);
1322 mgcp_rtp_end_init(&tcfg->endpoints[i].bts_end);
1323 mgcp_rtp_end_init(&tcfg->endpoints[i].trans_net);
1324 mgcp_rtp_end_init(&tcfg->endpoints[i].trans_bts);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +01001325 }
1326
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +01001327 return 0;
1328}
Holger Hans Peter Freyther154b9552010-02-26 13:27:51 +01001329
Holger Hans Peter Freythercb6ad702014-07-22 15:00:52 +02001330void mgcp_release_endp(struct mgcp_endpoint *endp)
Holger Hans Peter Freyther154b9552010-02-26 13:27:51 +01001331{
Holger Hans Peter Freythercb6ad702014-07-22 15:00:52 +02001332 LOGP(DMGCP, LOGL_DEBUG, "Releasing endpoint on: 0x%x\n", ENDPOINT_NUMBER(endp));
Holger Hans Peter Freyther89976e82010-08-03 15:01:43 +00001333 endp->ci = CI_UNUSED;
Holger Hans Peter Freyther39a97e22010-08-06 18:03:11 +08001334 endp->allocated = 0;
Holger Hans Peter Freyther154b9552010-02-26 13:27:51 +01001335
Holger Hans Peter Freyther01d315f2012-12-07 11:52:16 +01001336 talloc_free(endp->callid);
1337 endp->callid = NULL;
Holger Hans Peter Freyther154b9552010-02-26 13:27:51 +01001338
Jacob Erlbeck2c2ca4d2013-12-09 14:32:03 +01001339 talloc_free(endp->local_options.string);
1340 endp->local_options.string = NULL;
Jacob Erlbeck452c1832014-05-09 19:42:17 +02001341 talloc_free(endp->local_options.codec);
1342 endp->local_options.codec = NULL;
Holger Hans Peter Freyther154b9552010-02-26 13:27:51 +01001343
Holger Hans Peter Freythera17d7012010-08-05 01:34:51 +08001344 mgcp_rtp_end_reset(&endp->bts_end);
1345 mgcp_rtp_end_reset(&endp->net_end);
Holger Hans Peter Freyther21262332010-11-01 20:53:31 +01001346 mgcp_rtp_end_reset(&endp->trans_net);
Holger Hans Peter Freytherbd7b3c52010-11-01 21:04:54 +01001347 mgcp_rtp_end_reset(&endp->trans_bts);
Pablo Neira Ayuso46bd4242013-07-08 05:09:46 +02001348 endp->type = MGCP_RTP_DEFAULT;
Holger Hans Peter Freyther380b8712010-07-29 02:38:39 +08001349
Holger Hans Peter Freyther31868922010-08-03 11:59:04 +00001350 memset(&endp->net_state, 0, sizeof(endp->net_state));
1351 memset(&endp->bts_state, 0, sizeof(endp->bts_state));
Holger Hans Peter Freytherc597a4e2010-08-03 02:57:02 +08001352
1353 endp->conn_mode = endp->orig_mode = MGCP_CONN_NONE;
Holger Hans Peter Freyther260d6ed2010-08-06 01:12:21 +08001354
Pablo Neira Ayusob769f3c2014-08-27 17:02:52 +02001355 if (endp->osmux.state == OSMUX_STATE_ENABLED)
1356 osmux_disable_endpoint(endp);
1357
Holger Hans Peter Freyther1afe7c72015-10-04 11:11:11 +02001358 /* release the circuit ID if it had been allocated */
1359 osmux_release_cid(endp);
1360
Holger Hans Peter Freyther260d6ed2010-08-06 01:12:21 +08001361 memset(&endp->taps, 0, sizeof(endp->taps));
Holger Hans Peter Freyther154b9552010-02-26 13:27:51 +01001362}
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +08001363
Holger Hans Peter Freythercb6ad702014-07-22 15:00:52 +02001364void mgcp_initialize_endp(struct mgcp_endpoint *endp)
1365{
1366 return mgcp_release_endp(endp);
1367}
1368
Holger Hans Peter Freyther557b1ab2010-09-19 04:39:55 +08001369static int send_trans(struct mgcp_config *cfg, const char *buf, int len)
1370{
1371 struct sockaddr_in addr;
1372
1373 memset(&addr, 0, sizeof(addr));
1374 addr.sin_family = AF_INET;
1375 addr.sin_addr = cfg->transcoder_in;
1376 addr.sin_port = htons(2427);
1377 return sendto(cfg->gw_fd.bfd.fd, buf, len, 0,
1378 (struct sockaddr *) &addr, sizeof(addr));
1379}
1380
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +08001381static void send_msg(struct mgcp_endpoint *endp, int endpoint, int port,
1382 const char *msg, const char *mode)
1383{
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +08001384 char buf[2096];
1385 int len;
Jacob Erlbeck997e1e82014-03-14 18:01:20 +01001386 int nchars;
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +08001387
1388 /* hardcoded to AMR right now, we do not know the real type at this point */
1389 len = snprintf(buf, sizeof(buf),
1390 "%s 42 %x@mgw MGCP 1.0\r\n"
1391 "C: 4256\r\n"
1392 "M: %s\r\n"
Jacob Erlbeck997e1e82014-03-14 18:01:20 +01001393 "\r\n",
1394 msg, endpoint, mode);
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +08001395
1396 if (len < 0)
1397 return;
1398
Holger Hans Peter Freythere6ed0092015-08-20 14:58:19 +02001399 nchars = write_response_sdp(endp, buf + len, sizeof(buf) + len - 1, NULL);
Jacob Erlbeck997e1e82014-03-14 18:01:20 +01001400 if (nchars < 0)
1401 return;
1402
1403 len += nchars;
1404
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +08001405 buf[sizeof(buf) - 1] = '\0';
1406
Holger Hans Peter Freyther557b1ab2010-09-19 04:39:55 +08001407 send_trans(endp->cfg, buf, len);
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +08001408}
1409
1410static void send_dlcx(struct mgcp_endpoint *endp, int endpoint)
1411{
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +08001412 char buf[2096];
1413 int len;
1414
1415 len = snprintf(buf, sizeof(buf),
1416 "DLCX 43 %x@mgw MGCP 1.0\r\n"
1417 "C: 4256\r\n"
1418 , endpoint);
1419
1420 if (len < 0)
1421 return;
1422
1423 buf[sizeof(buf) - 1] = '\0';
1424
Holger Hans Peter Freyther557b1ab2010-09-19 04:39:55 +08001425 send_trans(endp->cfg, buf, len);
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +08001426}
1427
Harald Welte6a857052012-01-27 00:41:39 +01001428static int send_agent(struct mgcp_config *cfg, const char *buf, int len)
1429{
1430 return write(cfg->gw_fd.bfd.fd, buf, len);
1431}
1432
1433int mgcp_send_reset_all(struct mgcp_config *cfg)
1434{
1435 static const char mgcp_reset[] = {
1436 "RSIP 1 *@mgw MGCP 1.0\r\n"
1437 };
1438
1439 return send_agent(cfg, mgcp_reset, sizeof mgcp_reset -1);
1440}
1441
1442int mgcp_send_reset_ep(struct mgcp_endpoint *endp, int endpoint)
1443{
1444 char buf[128];
1445 int len;
1446
1447 len = snprintf(buf, sizeof(buf),
1448 "RSIP 39 %x@mgw MGCP 1.0\r\n"
1449 , endpoint);
1450 if (len < 0)
1451 return len;
1452
1453 buf[sizeof(buf) - 1] = '\0';
1454
1455 return send_agent(endp->cfg, buf, len);
1456}
1457
Holger Hans Peter Freyther7cce1d32015-03-26 20:34:12 +01001458static int setup_rtp_processing(struct mgcp_endpoint *endp)
Jacob Erlbecka0d64ce2014-03-13 14:24:52 +01001459{
Holger Hans Peter Freyther7cce1d32015-03-26 20:34:12 +01001460 int rc = 0;
Jacob Erlbecka0d64ce2014-03-13 14:24:52 +01001461 struct mgcp_config *cfg = endp->cfg;
1462
1463 if (endp->type != MGCP_RTP_DEFAULT)
Holger Hans Peter Freyther7cce1d32015-03-26 20:34:12 +01001464 return 0;
Jacob Erlbecka0d64ce2014-03-13 14:24:52 +01001465
1466 if (endp->conn_mode == MGCP_CONN_LOOPBACK)
Holger Hans Peter Freyther7cce1d32015-03-26 20:34:12 +01001467 return 0;
Jacob Erlbecka0d64ce2014-03-13 14:24:52 +01001468
1469 if (endp->conn_mode & MGCP_CONN_SEND_ONLY)
Holger Hans Peter Freyther7cce1d32015-03-26 20:34:12 +01001470 rc |= cfg->setup_rtp_processing_cb(endp, &endp->net_end, &endp->bts_end);
Jacob Erlbecka0d64ce2014-03-13 14:24:52 +01001471 else
Holger Hans Peter Freyther7cce1d32015-03-26 20:34:12 +01001472 rc |= cfg->setup_rtp_processing_cb(endp, &endp->net_end, NULL);
Jacob Erlbecka0d64ce2014-03-13 14:24:52 +01001473
1474 if (endp->conn_mode & MGCP_CONN_RECV_ONLY)
Holger Hans Peter Freyther7cce1d32015-03-26 20:34:12 +01001475 rc |= cfg->setup_rtp_processing_cb(endp, &endp->bts_end, &endp->net_end);
Jacob Erlbecka0d64ce2014-03-13 14:24:52 +01001476 else
Holger Hans Peter Freyther7cce1d32015-03-26 20:34:12 +01001477 rc |= cfg->setup_rtp_processing_cb(endp, &endp->bts_end, NULL);
1478 return rc;
Jacob Erlbecka0d64ce2014-03-13 14:24:52 +01001479}
1480
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +08001481static void create_transcoder(struct mgcp_endpoint *endp)
1482{
1483 int port;
1484 int in_endp = ENDPOINT_NUMBER(endp);
Holger Hans Peter Freytherbd7b3c52010-11-01 21:04:54 +01001485 int out_endp = endp_back_channel(in_endp);
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +08001486
Pablo Neira Ayuso46bd4242013-07-08 05:09:46 +02001487 if (endp->type != MGCP_RTP_TRANSCODED)
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +08001488 return;
1489
Holger Hans Peter Freyther8b19dee2010-11-01 22:38:25 +01001490 send_msg(endp, in_endp, endp->trans_bts.local_port, "CRCX", "sendrecv");
1491 send_msg(endp, in_endp, endp->trans_bts.local_port, "MDCX", "sendrecv");
Holger Hans Peter Freyther21262332010-11-01 20:53:31 +01001492 send_msg(endp, out_endp, endp->trans_net.local_port, "CRCX", "sendrecv");
1493 send_msg(endp, out_endp, endp->trans_net.local_port, "MDCX", "sendrecv");
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +08001494
Holger Hans Peter Freytherbd7b3c52010-11-01 21:04:54 +01001495 port = rtp_calculate_port(in_endp, endp->cfg->transcoder_remote_base);
1496 endp->trans_bts.rtp_port = htons(port);
1497 endp->trans_bts.rtcp_port = htons(port + 1);
1498
Holger Hans Peter Freytherb98ba722010-09-19 04:21:39 +08001499 port = rtp_calculate_port(out_endp, endp->cfg->transcoder_remote_base);
Holger Hans Peter Freyther21262332010-11-01 20:53:31 +01001500 endp->trans_net.rtp_port = htons(port);
1501 endp->trans_net.rtcp_port = htons(port + 1);
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +08001502}
1503
1504static void delete_transcoder(struct mgcp_endpoint *endp)
1505{
1506 int in_endp = ENDPOINT_NUMBER(endp);
Holger Hans Peter Freytherbd7b3c52010-11-01 21:04:54 +01001507 int out_endp = endp_back_channel(in_endp);
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +08001508
Pablo Neira Ayuso46bd4242013-07-08 05:09:46 +02001509 if (endp->type != MGCP_RTP_TRANSCODED)
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +08001510 return;
1511
1512 send_dlcx(endp, in_endp);
1513 send_dlcx(endp, out_endp);
1514}
Holger Hans Peter Freytherf2eedff2010-09-19 04:36:07 +08001515
1516int mgcp_reset_transcoder(struct mgcp_config *cfg)
1517{
Holger Hans Peter Freytherf2eedff2010-09-19 04:36:07 +08001518 if (!cfg->transcoder_ip)
Holger Hans Peter Freythercf1c8772010-09-24 04:41:28 +08001519 return 0;
Holger Hans Peter Freytherf2eedff2010-09-19 04:36:07 +08001520
1521 static const char mgcp_reset[] = {
1522 "RSIP 1 13@mgw MGCP 1.0\r\n"
1523 };
1524
Holger Hans Peter Freyther557b1ab2010-09-19 04:39:55 +08001525 return send_trans(cfg, mgcp_reset, sizeof mgcp_reset -1);
Holger Hans Peter Freytherf2eedff2010-09-19 04:36:07 +08001526}
Holger Hans Peter Freyther0bf15a82012-09-14 17:18:12 +02001527
1528void mgcp_format_stats(struct mgcp_endpoint *endp, char *msg, size_t size)
1529{
Holger Hans Peter Freythercb306a62012-10-24 21:22:47 +02001530 uint32_t expected, jitter;
Holger Hans Peter Freyther38e02c52012-10-22 18:09:35 +02001531 int ploss;
Jacob Erlbeck50079a12013-11-25 12:53:28 +01001532 int nchars;
Holger Hans Peter Freyther38e02c52012-10-22 18:09:35 +02001533 mgcp_state_calc_loss(&endp->net_state, &endp->net_end,
1534 &expected, &ploss);
Holger Hans Peter Freythercb306a62012-10-24 21:22:47 +02001535 jitter = mgcp_state_calc_jitter(&endp->net_state);
Holger Hans Peter Freyther38e02c52012-10-22 18:09:35 +02001536
Jacob Erlbeck50079a12013-11-25 12:53:28 +01001537 nchars = snprintf(msg, size,
1538 "\r\nP: PS=%u, OS=%u, PR=%u, OR=%u, PL=%d, JI=%u",
1539 endp->bts_end.packets, endp->bts_end.octets,
1540 endp->net_end.packets, endp->net_end.octets,
1541 ploss, jitter);
1542 if (nchars < 0 || nchars >= size)
1543 goto truncate;
1544
1545 msg += nchars;
1546 size -= nchars;
1547
1548 /* Error Counter */
Pablo Neira Ayusoee11bc02014-09-17 12:33:09 +02001549 nchars = snprintf(msg, size,
1550 "\r\nX-Osmo-CP: EC TIS=%u, TOS=%u, TIR=%u, TOR=%u",
1551 endp->net_state.in_stream.err_ts_counter,
1552 endp->net_state.out_stream.err_ts_counter,
1553 endp->bts_state.in_stream.err_ts_counter,
1554 endp->bts_state.out_stream.err_ts_counter);
1555 if (nchars < 0 || nchars >= size)
1556 goto truncate;
1557
1558 msg += nchars;
1559 size -= nchars;
1560
1561 if (endp->osmux.state == OSMUX_STATE_ENABLED) {
1562 snprintf(msg, size,
1563 "\r\nX-Osmux-ST: CR=%u, BR=%u",
1564 endp->osmux.stats.chunks,
1565 endp->osmux.stats.octets);
1566 }
Jacob Erlbeck50079a12013-11-25 12:53:28 +01001567truncate:
Holger Hans Peter Freyther0bf15a82012-09-14 17:18:12 +02001568 msg[size - 1] = '\0';
1569}
Holger Hans Peter Freyther462b7d72012-10-24 21:53:40 +02001570
1571int mgcp_parse_stats(struct msgb *msg, uint32_t *ps, uint32_t *os,
1572 uint32_t *pr, uint32_t *_or, int *loss, uint32_t *jitter)
1573{
1574 char *line, *save;
1575 int rc;
1576
1577 /* initialize with bad values */
1578 *ps = *os = *pr = *_or = *jitter = UINT_MAX;
1579 *loss = INT_MAX;
1580
1581
1582 line = strtok_r((char *) msg->l2h, "\r\n", &save);
1583 if (!line)
1584 return -1;
1585
1586 /* this can only parse the message that is created above... */
Jacob Erlbecka01bd602013-11-29 13:43:43 +01001587 for_each_non_empty_line(line, save) {
Holger Hans Peter Freyther462b7d72012-10-24 21:53:40 +02001588 switch (line[0]) {
1589 case 'P':
1590 rc = sscanf(line, "P: PS=%u, OS=%u, PR=%u, OR=%u, PL=%d, JI=%u",
1591 ps, os, pr, _or, loss, jitter);
1592 return rc == 6 ? 0 : -1;
1593 }
1594 }
1595
1596 return -1;
1597}