blob: c040ab1b4a89ace3440d28cf769899844e410089 [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>
27#include <string.h>
28#include <time.h>
29#include <limits.h>
30#include <unistd.h>
31
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 Erlbeck72c30902013-11-25 15:23:35 +010043/* Assume audio frame length of 20ms */
44#define DEFAULT_RTP_AUDIO_FRAME_DUR_NUM 20
45#define DEFAULT_RTP_AUDIO_FRAME_DUR_DEN 1000
46#define DEFAULT_RTP_AUDIO_FRAMES_PER_PACKET 1
47#define DEFAULT_RTP_AUDIO_DEFAULT_RATE 8000
48
Holger Hans Peter Freytherf138f912010-08-05 08:08:17 +080049static void mgcp_rtp_end_reset(struct mgcp_rtp_end *end);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +010050
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +010051struct mgcp_parse_data {
52 struct mgcp_config *cfg;
53 struct mgcp_endpoint *endp;
54 char *trans;
55 char *save;
56 int found;
57};
58
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +010059struct mgcp_request {
60 char *name;
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +010061 struct msgb *(*handle_request) (struct mgcp_parse_data *data);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +010062 char *debug_name;
63};
64
65#define MGCP_REQUEST(NAME, REQ, DEBUG_NAME) \
66 { .name = NAME, .handle_request = REQ, .debug_name = DEBUG_NAME },
67
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +010068static struct msgb *handle_audit_endpoint(struct mgcp_parse_data *data);
69static struct msgb *handle_create_con(struct mgcp_parse_data *data);
70static struct msgb *handle_delete_con(struct mgcp_parse_data *data);
71static struct msgb *handle_modify_con(struct mgcp_parse_data *data);
72static struct msgb *handle_rsip(struct mgcp_parse_data *data);
73static struct msgb *handle_noti_req(struct mgcp_parse_data *data);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +010074
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +080075static void create_transcoder(struct mgcp_endpoint *endp);
76static void delete_transcoder(struct mgcp_endpoint *endp);
77
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +010078static int mgcp_analyze_header(struct mgcp_parse_data *parse, char *data);
79
Holger Hans Peter Freyther46340132010-08-06 08:26:54 +080080static uint32_t generate_call_id(struct mgcp_config *cfg)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +010081{
82 int i;
83
84 /* use the call id */
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +010085 ++cfg->last_call_id;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +010086
87 /* handle wrap around */
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +010088 if (cfg->last_call_id == CI_UNUSED)
89 ++cfg->last_call_id;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +010090
91 /* callstack can only be of size number_of_endpoints */
92 /* verify that the call id is free, e.g. in case of overrun */
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +010093 for (i = 1; i < cfg->trunk.number_endpoints; ++i)
94 if (cfg->trunk.endpoints[i].ci == cfg->last_call_id)
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +010095 return generate_call_id(cfg);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +010096
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +010097 return cfg->last_call_id;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +010098}
99
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100100/*
101 * array of function pointers for handling various
102 * messages. In the future this might be binary sorted
103 * for performance reasons.
104 */
105static const struct mgcp_request mgcp_requests [] = {
106 MGCP_REQUEST("AUEP", handle_audit_endpoint, "AuditEndpoint")
107 MGCP_REQUEST("CRCX", handle_create_con, "CreateConnection")
108 MGCP_REQUEST("DLCX", handle_delete_con, "DeleteConnection")
109 MGCP_REQUEST("MDCX", handle_modify_con, "ModifiyConnection")
Holger Hans Peter Freyther6e94d6d2011-01-25 23:33:54 +0100110 MGCP_REQUEST("RQNT", handle_noti_req, "NotificationRequest")
Holger Hans Peter Freyther9bdcc9c2010-03-31 06:39:35 +0200111
112 /* SPEC extension */
113 MGCP_REQUEST("RSIP", handle_rsip, "ReSetInProgress")
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100114};
115
Holger Hans Peter Freyther62e836c2010-02-03 11:03:45 +0100116static struct msgb *mgcp_msgb_alloc(void)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100117{
Holger Hans Peter Freyther62e836c2010-02-03 11:03:45 +0100118 struct msgb *msg;
119 msg = msgb_alloc_headroom(4096, 128, "MGCP msg");
120 if (!msg)
121 LOGP(DMGCP, LOGL_ERROR, "Failed to msgb for MGCP data.\n");
122
123 return msg;
124}
125
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100126static struct msgb *do_retransmission(const struct mgcp_endpoint *endp)
127{
128 struct msgb *msg = mgcp_msgb_alloc();
129 if (!msg)
130 return NULL;
131
132 msg->l2h = msgb_put(msg, strlen(endp->last_response));
133 memcpy(msg->l2h, endp->last_response, msgb_l2len(msg));
134 return msg;
135}
136
Holger Hans Peter Freythera769dcb2012-12-07 15:14:27 +0100137static struct msgb *create_resp(struct mgcp_endpoint *endp, int code,
138 const char *txt, const char *msg,
Holger Hans Peter Freyther0bf15a82012-09-14 17:18:12 +0200139 const char *trans, const char *param,
140 const char *sdp)
Holger Hans Peter Freyther62e836c2010-02-03 11:03:45 +0100141{
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100142 int len;
Holger Hans Peter Freyther62e836c2010-02-03 11:03:45 +0100143 struct msgb *res;
144
145 res = mgcp_msgb_alloc();
146 if (!res)
147 return NULL;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100148
Holger Hans Peter Freyther0bf15a82012-09-14 17:18:12 +0200149 len = snprintf((char *) res->data, 2048, "%d %s%s%s\r\n%s",
150 code, trans, txt, param ? param : "", sdp ? sdp : "");
151 if (len < 0) {
152 LOGP(DMGCP, LOGL_ERROR, "Failed to sprintf MGCP response.\n");
153 msgb_free(res);
154 return NULL;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100155 }
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100156
Holger Hans Peter Freyther62e836c2010-02-03 11:03:45 +0100157 res->l2h = msgb_put(res, len);
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100158 LOGP(DMGCP, LOGL_DEBUG, "Generated response: code: %d for '%s'\n", code, res->l2h);
159
160 /*
161 * Remember the last transmission per endpoint.
162 */
163 if (endp) {
164 struct mgcp_trunk_config *tcfg = endp->tcfg;
165 talloc_free(endp->last_response);
166 talloc_free(endp->last_trans);
167 endp->last_trans = talloc_strdup(tcfg->endpoints, trans);
168 endp->last_response = talloc_strndup(tcfg->endpoints,
169 (const char *) res->l2h,
170 msgb_l2len(res));
171 }
172
Holger Hans Peter Freyther62e836c2010-02-03 11:03:45 +0100173 return res;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100174}
175
Holger Hans Peter Freythera769dcb2012-12-07 15:14:27 +0100176static struct msgb *create_ok_resp_with_param(struct mgcp_endpoint *endp,
177 int code, const char *msg,
Holger Hans Peter Freyther0bf15a82012-09-14 17:18:12 +0200178 const char *trans, const char *param)
179{
Holger Hans Peter Freythera769dcb2012-12-07 15:14:27 +0100180 return create_resp(endp, code, " OK", msg, trans, param, NULL);
Holger Hans Peter Freyther0bf15a82012-09-14 17:18:12 +0200181}
182
Holger Hans Peter Freythera769dcb2012-12-07 15:14:27 +0100183static struct msgb *create_ok_response(struct mgcp_endpoint *endp,
184 int code, const char *msg, const char *trans)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100185{
Holger Hans Peter Freythera769dcb2012-12-07 15:14:27 +0100186 return create_ok_resp_with_param(endp, code, msg, trans, NULL);
Holger Hans Peter Freyther6adac172011-01-06 16:19:55 +0100187}
188
Holger Hans Peter Freythera769dcb2012-12-07 15:14:27 +0100189static struct msgb *create_err_response(struct mgcp_endpoint *endp,
190 int code, const char *msg, const char *trans)
Holger Hans Peter Freyther6adac172011-01-06 16:19:55 +0100191{
Holger Hans Peter Freythera769dcb2012-12-07 15:14:27 +0100192 return create_resp(endp, code, " FAIL", msg, trans, NULL, NULL);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100193}
194
Holger Hans Peter Freyther8d188ed2010-02-21 01:44:08 +0100195static struct msgb *create_response_with_sdp(struct mgcp_endpoint *endp,
196 const char *msg, const char *trans_id)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100197{
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100198 const char *addr = endp->cfg->local_ip;
Holger Hans Peter Freyther5ea1bc72012-09-03 00:07:39 +0200199 const char *fmtp_extra = endp->bts_end.fmtp_extra;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100200 char sdp_record[4096];
201
202 if (!addr)
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100203 addr = endp->cfg->source_addr;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100204
205 snprintf(sdp_record, sizeof(sdp_record) - 1,
Holger Hans Peter Freyther46340132010-08-06 08:26:54 +0800206 "I: %u\n\n"
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100207 "v=0\r\n"
Holger Hans Peter Freytherc7e49d32011-07-20 20:43:15 +0200208 "o=- %u 23 IN IP4 %s\r\n"
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100209 "c=IN IP4 %s\r\n"
Holger Hans Peter Freytherc7e49d32011-07-20 20:43:15 +0200210 "t=0 0\r\n"
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100211 "m=audio %d RTP/AVP %d\r\n"
Holger Hans Peter Freyther5ea1bc72012-09-03 00:07:39 +0200212 "a=rtpmap:%d %s\r\n"
213 "%s%s",
Holger Hans Peter Freytherc7e49d32011-07-20 20:43:15 +0200214 endp->ci, endp->ci, addr, addr,
215 endp->net_end.local_port, endp->bts_end.payload_type,
Holger Hans Peter Freyther5ea1bc72012-09-03 00:07:39 +0200216 endp->bts_end.payload_type, endp->tcfg->audio_name,
217 fmtp_extra ? fmtp_extra : "", fmtp_extra ? "\r\n" : "");
Holger Hans Peter Freythera769dcb2012-12-07 15:14:27 +0100218 return create_resp(endp, 200, " OK", msg, trans_id, NULL, sdp_record);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100219}
220
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100221/*
222 * handle incoming messages:
223 * - this can be a command (four letters, space, transaction id)
224 * - or a response (three numbers, space, transaction id)
225 */
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100226struct msgb *mgcp_handle_message(struct mgcp_config *cfg, struct msgb *msg)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100227{
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100228 struct mgcp_parse_data pdata;
229 int i, code, handled = 0;
Holger Hans Peter Freyther62e836c2010-02-03 11:03:45 +0100230 struct msgb *resp = NULL;
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100231 char *data;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100232
Holger Hans Peter Freytherf36a11a2010-03-31 13:26:46 +0200233 if (msgb_l2len(msg) < 4) {
Holger Hans Peter Freyther0d904e02012-12-07 16:46:19 +0100234 LOGP(DMGCP, LOGL_ERROR, "msg too short: %d\n", msg->len);
Holger Hans Peter Freyther62e836c2010-02-03 11:03:45 +0100235 return NULL;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100236 }
237
238 /* attempt to treat it as a response */
Holger Hans Peter Freytherf36a11a2010-03-31 13:26:46 +0200239 if (sscanf((const char *)&msg->l2h[0], "%3d %*s", &code) == 1) {
Holger Hans Peter Freyther63f2db22010-02-26 13:30:57 +0100240 LOGP(DMGCP, LOGL_DEBUG, "Response: Code: %d\n", code);
Holger Hans Peter Freyther29de3462012-12-07 16:07:46 +0100241 return NULL;
242 }
243
244 msg->l3h = &msg->l2h[4];
245
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100246
247 /*
248 * Check for a duplicate message and respond.
249 * FIXME: Verify that the msg->l3h is NULL terminated.
250 */
251 memset(&pdata, 0, sizeof(pdata));
252 pdata.cfg = cfg;
253 data = strtok_r((char *) msg->l3h, "\r\n", &pdata.save);
254 pdata.found = mgcp_analyze_header(&pdata, data);
255 if (pdata.endp && pdata.trans
256 && pdata.endp->last_trans
257 && strcmp(pdata.endp->last_trans, pdata.trans) == 0) {
258 return do_retransmission(pdata.endp);
259 }
260
Holger Hans Peter Freyther29de3462012-12-07 16:07:46 +0100261 for (i = 0; i < ARRAY_SIZE(mgcp_requests); ++i) {
262 if (strncmp(mgcp_requests[i].name, (const char *) &msg->l2h[0], 4) == 0) {
263 handled = 1;
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100264 resp = mgcp_requests[i].handle_request(&pdata);
Holger Hans Peter Freyther29de3462012-12-07 16:07:46 +0100265 break;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100266 }
267 }
268
Holger Hans Peter Freyther29de3462012-12-07 16:07:46 +0100269 if (!handled)
270 LOGP(DMGCP, LOGL_NOTICE, "MSG with type: '%.4s' not handled\n", &msg->l2h[0]);
271
Holger Hans Peter Freyther62e836c2010-02-03 11:03:45 +0100272 return resp;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100273}
274
Holger Hans Peter Freyther9f239a22011-01-06 19:32:52 +0100275/**
276 * We have a null terminated string with the endpoint name here. We only
277 * support two kinds. Simple ones as seen on the BSC level and the ones
278 * seen on the trunk side.
279 */
280static struct mgcp_endpoint *find_e1_endpoint(struct mgcp_config *cfg,
281 const char *mgcp)
282{
283 char *rest = NULL;
Holger Hans Peter Freyther74e61112011-02-28 14:13:47 +0100284 struct mgcp_trunk_config *tcfg;
285 int trunk, endp;
Holger Hans Peter Freyther9f239a22011-01-06 19:32:52 +0100286
287 trunk = strtoul(mgcp + 6, &rest, 10);
Holger Hans Peter Freytherf43f2fc2011-01-07 11:30:21 +0100288 if (rest == NULL || rest[0] != '/' || trunk < 1) {
Holger Hans Peter Freyther9f239a22011-01-06 19:32:52 +0100289 LOGP(DMGCP, LOGL_ERROR, "Wrong trunk name '%s'\n", mgcp);
290 return NULL;
291 }
292
293 endp = strtoul(rest + 1, &rest, 10);
294 if (rest == NULL || rest[0] != '@') {
Holger Hans Peter Freytherf43f2fc2011-01-07 11:30:21 +0100295 LOGP(DMGCP, LOGL_ERROR, "Wrong endpoint name '%s'\n", mgcp);
Holger Hans Peter Freyther9f239a22011-01-06 19:32:52 +0100296 return NULL;
297 }
298
299 /* signalling is on timeslot 1 */
300 if (endp == 1)
301 return NULL;
302
Holger Hans Peter Freyther74e61112011-02-28 14:13:47 +0100303 tcfg = mgcp_trunk_num(cfg, trunk);
304 if (!tcfg) {
305 LOGP(DMGCP, LOGL_ERROR, "The trunk %d is not declared.\n", trunk);
306 return NULL;
307 }
308
309 if (!tcfg->endpoints) {
310 LOGP(DMGCP, LOGL_ERROR, "Endpoints of trunk %d not allocated.\n", trunk);
311 return NULL;
312 }
313
314 if (endp < 1 || endp >= tcfg->number_endpoints) {
Holger Hans Peter Freyther9f239a22011-01-06 19:32:52 +0100315 LOGP(DMGCP, LOGL_ERROR, "Failed to find endpoint '%s'\n", mgcp);
Holger Hans Peter Freyther45c21842011-01-07 11:36:54 +0100316 return NULL;
Holger Hans Peter Freyther9f239a22011-01-06 19:32:52 +0100317 }
318
Holger Hans Peter Freyther74e61112011-02-28 14:13:47 +0100319 return &tcfg->endpoints[endp];
Holger Hans Peter Freyther9f239a22011-01-06 19:32:52 +0100320}
321
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100322static struct mgcp_endpoint *find_endpoint(struct mgcp_config *cfg, const char *mgcp)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100323{
324 char *endptr = NULL;
325 unsigned int gw = INT_MAX;
326
Holger Hans Peter Freyther9f239a22011-01-06 19:32:52 +0100327 if (strncmp(mgcp, "ds/e1", 5) == 0) {
328 return find_e1_endpoint(cfg, mgcp);
329 } else {
330 gw = strtoul(mgcp, &endptr, 16);
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +0100331 if (gw > 0 && gw < cfg->trunk.number_endpoints && strcmp(endptr, "@mgw") == 0)
332 return &cfg->trunk.endpoints[gw];
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100333 }
334
Holger Hans Peter Freyther9f239a22011-01-06 19:32:52 +0100335 LOGP(DMGCP, LOGL_ERROR, "Not able to find endpoint: '%s'\n", mgcp);
336 return NULL;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100337}
338
Harald Welteae199722012-01-27 12:31:36 +0100339/**
340 * @returns 0 when the status line was complete and transaction_id and
341 * endp out parameters are set.
342 */
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100343static int mgcp_analyze_header(struct mgcp_parse_data *pdata, char *data)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100344{
Harald Welteae199722012-01-27 12:31:36 +0100345 int i = 0;
Holger Hans Peter Freyther1eba7de2013-07-03 10:23:35 +0200346 char *elem, *save = NULL;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100347
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100348 pdata->trans = "000000";
Holger Hans Peter Freythera820c5f2010-02-26 13:32:55 +0100349
Harald Welteae199722012-01-27 12:31:36 +0100350 for (elem = strtok_r(data, " ", &save); elem;
351 elem = strtok_r(NULL, " ", &save)) {
352 switch (i) {
353 case 0:
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100354 pdata->trans = elem;
Harald Welteae199722012-01-27 12:31:36 +0100355 break;
356 case 1:
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100357 pdata->endp = find_endpoint(pdata->cfg, elem);
358 if (!pdata->endp) {
359 LOGP(DMGCP, LOGL_ERROR,
360 "Unable to find Endpoint `%s'\n", elem);
361 return -1;
Harald Welteae199722012-01-27 12:31:36 +0100362 }
363 break;
364 case 2:
365 if (strcmp("MGCP", elem)) {
366 LOGP(DMGCP, LOGL_ERROR,
367 "MGCP header parsing error\n");
368 return -1;
369 }
370 break;
371 case 3:
372 if (strcmp("1.0", elem)) {
373 LOGP(DMGCP, LOGL_ERROR, "MGCP version `%s' "
374 "not supported\n", elem);
375 return -1;
376 }
377 break;
378 }
379 i++;
380 }
381
382 if (i != 4) {
383 LOGP(DMGCP, LOGL_ERROR, "MGCP status line too short.\n");
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100384 pdata->trans = "000000";
385 pdata->endp = NULL;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100386 return -1;
387 }
388
Holger Hans Peter Freytherf2f15912010-04-01 03:27:04 +0200389 return 0;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100390}
391
392static int verify_call_id(const struct mgcp_endpoint *endp,
393 const char *callid)
394{
395 if (strcmp(endp->callid, callid) != 0) {
Holger Hans Peter Freyther2ada71d2010-02-03 09:13:10 +0100396 LOGP(DMGCP, LOGL_ERROR, "CallIDs does not match on 0x%x. '%s' != '%s'\n",
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100397 ENDPOINT_NUMBER(endp), endp->callid, callid);
398 return -1;
399 }
400
401 return 0;
402}
403
404static int verify_ci(const struct mgcp_endpoint *endp,
Holger Hans Peter Freyther46340132010-08-06 08:26:54 +0800405 const char *_ci)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100406{
Holger Hans Peter Freyther46340132010-08-06 08:26:54 +0800407 uint32_t ci = strtoul(_ci, NULL, 10);
408
409 if (ci != endp->ci) {
410 LOGP(DMGCP, LOGL_ERROR, "ConnectionIdentifiers do not match on 0x%x. %u != %s\n",
411 ENDPOINT_NUMBER(endp), endp->ci, _ci);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100412 return -1;
413 }
414
415 return 0;
416}
417
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100418static struct msgb *handle_audit_endpoint(struct mgcp_parse_data *p)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100419{
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100420 if (p->found != 0)
421 return create_err_response(NULL, 500, "AUEP", p->trans);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100422 else
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100423 return create_ok_response(p->endp, 200, "AUEP", p->trans);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100424}
425
Holger Hans Peter Freytheradb6e1c2010-09-18 06:44:24 +0800426static int parse_conn_mode(const char *msg, int *conn_mode)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100427{
428 int ret = 0;
429 if (strcmp(msg, "recvonly") == 0)
430 *conn_mode = MGCP_CONN_RECV_ONLY;
431 else if (strcmp(msg, "sendrecv") == 0)
432 *conn_mode = MGCP_CONN_RECV_SEND;
Holger Hans Peter Freythere02860a2010-09-18 20:21:44 +0800433 else if (strcmp(msg, "sendonly") == 0)
434 *conn_mode = MGCP_CONN_SEND_ONLY;
Holger Hans Peter Freyther98a38772010-08-03 02:27:21 +0800435 else if (strcmp(msg, "loopback") == 0)
436 *conn_mode = MGCP_CONN_LOOPBACK;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100437 else {
Holger Hans Peter Freyther2ada71d2010-02-03 09:13:10 +0100438 LOGP(DMGCP, LOGL_ERROR, "Unknown connection mode: '%s'\n", msg);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100439 ret = -1;
440 }
441
442 return ret;
443}
444
Holger Hans Peter Freytherf138f912010-08-05 08:08:17 +0800445static int allocate_port(struct mgcp_endpoint *endp, struct mgcp_rtp_end *end,
Holger Hans Peter Freyther218f8562010-09-18 02:30:02 +0800446 struct mgcp_port_range *range,
447 int (*alloc)(struct mgcp_endpoint *endp, int port))
Holger Hans Peter Freytherf138f912010-08-05 08:08:17 +0800448{
449 int i;
450
451 if (range->mode == PORT_ALLOC_STATIC) {
Holger Hans Peter Freytherf138f912010-08-05 08:08:17 +0800452 end->local_alloc = PORT_ALLOC_STATIC;
453 return 0;
454 }
455
456 /* attempt to find a port */
457 for (i = 0; i < 200; ++i) {
458 int rc;
459
460 if (range->last_port >= range->range_end)
461 range->last_port = range->range_start;
462
Holger Hans Peter Freyther218f8562010-09-18 02:30:02 +0800463 rc = alloc(endp, range->last_port);
Holger Hans Peter Freytherf138f912010-08-05 08:08:17 +0800464
465 range->last_port += 2;
466 if (rc == 0) {
467 end->local_alloc = PORT_ALLOC_DYNAMIC;
468 return 0;
469 }
470
471 }
472
Holger Hans Peter Freyther218f8562010-09-18 02:30:02 +0800473 LOGP(DMGCP, LOGL_ERROR, "Allocating a RTP/RTCP port failed 200 times 0x%x.\n",
474 ENDPOINT_NUMBER(endp));
Holger Hans Peter Freytherf138f912010-08-05 08:08:17 +0800475 return -1;
476}
477
478static int allocate_ports(struct mgcp_endpoint *endp)
479{
Holger Hans Peter Freyther218f8562010-09-18 02:30:02 +0800480 if (allocate_port(endp, &endp->net_end, &endp->cfg->net_ports,
481 mgcp_bind_net_rtp_port) != 0)
Holger Hans Peter Freytherf138f912010-08-05 08:08:17 +0800482 return -1;
483
Holger Hans Peter Freyther218f8562010-09-18 02:30:02 +0800484 if (allocate_port(endp, &endp->bts_end, &endp->cfg->bts_ports,
485 mgcp_bind_bts_rtp_port) != 0) {
Holger Hans Peter Freytherf138f912010-08-05 08:08:17 +0800486 mgcp_rtp_end_reset(&endp->net_end);
487 return -1;
488 }
489
Holger Hans Peter Freyther69906872011-02-28 14:51:48 +0100490 if (endp->cfg->transcoder_ip && endp->tcfg->trunk_type == MGCP_TRUNK_VIRTUAL) {
Holger Hans Peter Freyther21262332010-11-01 20:53:31 +0100491 if (allocate_port(endp, &endp->trans_net,
Holger Hans Peter Freytherb54048f2010-11-01 19:57:50 +0100492 &endp->cfg->transcoder_ports,
Holger Hans Peter Freytherbd7b3c52010-11-01 21:04:54 +0100493 mgcp_bind_trans_net_rtp_port) != 0) {
Holger Hans Peter Freytherb54048f2010-11-01 19:57:50 +0100494 mgcp_rtp_end_reset(&endp->net_end);
495 mgcp_rtp_end_reset(&endp->bts_end);
496 return -1;
497 }
498
Holger Hans Peter Freytherbd7b3c52010-11-01 21:04:54 +0100499 if (allocate_port(endp, &endp->trans_bts,
500 &endp->cfg->transcoder_ports,
501 mgcp_bind_trans_bts_rtp_port) != 0) {
502 mgcp_rtp_end_reset(&endp->net_end);
503 mgcp_rtp_end_reset(&endp->bts_end);
504 mgcp_rtp_end_reset(&endp->trans_net);
505 return -1;
506 }
507
Holger Hans Peter Freytherb54048f2010-11-01 19:57:50 +0100508 /* remember that we have set up transcoding */
Pablo Neira Ayuso46bd4242013-07-08 05:09:46 +0200509 endp->type = MGCP_RTP_TRANSCODED;
Holger Hans Peter Freyther218f8562010-09-18 02:30:02 +0800510 }
511
Holger Hans Peter Freytherf138f912010-08-05 08:08:17 +0800512 return 0;
513}
514
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100515static struct msgb *handle_create_con(struct mgcp_parse_data *p)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100516{
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +0100517 struct mgcp_trunk_config *tcfg;
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100518 struct mgcp_endpoint *endp = p->endp;
Holger Hans Peter Freyther9e9392d2010-08-08 16:24:48 +0800519 int error_code = 400;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100520
Holger Hans Peter Freyther3488c3d2011-07-20 20:44:54 +0200521 const char *local_options = NULL;
522 const char *callid = NULL;
523 const char *mode = NULL;
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100524 char *line;
525
526 if (p->found != 0)
527 return create_err_response(NULL, 510, "CRCX", p->trans);
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +0100528
Holger Hans Peter Freyther3488c3d2011-07-20 20:44:54 +0200529 /* parse CallID C: and LocalParameters L: */
Jacob Erlbecka01bd602013-11-29 13:43:43 +0100530 for_each_non_empty_line(line, p->save) {
Harald Welteae199722012-01-27 12:31:36 +0100531 switch (line[0]) {
532 case 'L':
533 local_options = (const char *) line + 3;
534 break;
535 case 'C':
536 callid = (const char *) line + 3;
537 break;
538 case 'M':
539 mode = (const char *) line + 3;
540 break;
541 default:
542 LOGP(DMGCP, LOGL_NOTICE, "Unhandled option: '%c'/%d on 0x%x\n",
543 *line, *line, ENDPOINT_NUMBER(endp));
544 break;
545 }
Holger Hans Peter Freyther3488c3d2011-07-20 20:44:54 +0200546 }
Harald Welteae199722012-01-27 12:31:36 +0100547
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100548 tcfg = p->endp->tcfg;
Holger Hans Peter Freyther3488c3d2011-07-20 20:44:54 +0200549
550 /* Check required data */
551 if (!callid || !mode) {
552 LOGP(DMGCP, LOGL_ERROR, "Missing callid and mode in CRCX on 0x%x\n",
553 ENDPOINT_NUMBER(endp));
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100554 return create_err_response(endp, 400, "CRCX", p->trans);
Holger Hans Peter Freyther3488c3d2011-07-20 20:44:54 +0200555 }
556
Holger Hans Peter Freyther39a97e22010-08-06 18:03:11 +0800557 if (endp->allocated) {
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +0100558 if (tcfg->force_realloc) {
Holger Hans Peter Freyther408cc4a2010-04-07 10:51:27 +0200559 LOGP(DMGCP, LOGL_NOTICE, "Endpoint 0x%x already allocated. Forcing realloc.\n",
560 ENDPOINT_NUMBER(endp));
Holger Hans Peter Freyther32d4e502010-04-24 21:02:48 +0800561 mgcp_free_endp(endp);
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100562 if (p->cfg->realloc_cb)
563 p->cfg->realloc_cb(tcfg, ENDPOINT_NUMBER(endp));
Holger Hans Peter Freyther408cc4a2010-04-07 10:51:27 +0200564 } else {
565 LOGP(DMGCP, LOGL_ERROR, "Endpoint is already used. 0x%x\n",
566 ENDPOINT_NUMBER(endp));
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100567 return create_err_response(endp, 400, "CRCX", p->trans);
Holger Hans Peter Freyther408cc4a2010-04-07 10:51:27 +0200568 }
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100569 }
570
Holger Hans Peter Freyther3488c3d2011-07-20 20:44:54 +0200571 /* copy some parameters */
572 endp->callid = talloc_strdup(tcfg->endpoints, callid);
573
574 if (local_options)
575 endp->local_options = talloc_strdup(tcfg->endpoints, local_options);
576
577 if (parse_conn_mode(mode, &endp->conn_mode) != 0) {
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100578 error_code = 517;
579 goto error2;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100580 }
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100581
582 /* initialize */
Holger Hans Peter Freythera17d7012010-08-05 01:34:51 +0800583 endp->net_end.rtp_port = endp->net_end.rtcp_port = endp->bts_end.rtp_port = endp->bts_end.rtcp_port = 0;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100584
585 /* set to zero until we get the info */
Holger Hans Peter Freythera17d7012010-08-05 01:34:51 +0800586 memset(&endp->net_end.addr, 0, sizeof(endp->net_end.addr));
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100587
588 /* bind to the port now */
Holger Hans Peter Freytherf138f912010-08-05 08:08:17 +0800589 if (allocate_ports(endp) != 0)
590 goto error2;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100591
592 /* assign a local call identifier or fail */
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100593 endp->ci = generate_call_id(p->cfg);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100594 if (endp->ci == CI_UNUSED)
595 goto error2;
596
Holger Hans Peter Freyther39a97e22010-08-06 18:03:11 +0800597 endp->allocated = 1;
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +0100598 endp->bts_end.payload_type = tcfg->audio_payload;
Holger Hans Peter Freyther5ea1bc72012-09-03 00:07:39 +0200599 endp->bts_end.fmtp_extra = talloc_strdup(tcfg->endpoints,
600 tcfg->audio_fmtp_extra);
Holger Hans Peter Freytheref6bb252010-02-26 13:41:22 +0100601
Holger Hans Peter Freytherfe86d3c2010-02-26 13:37:05 +0100602 /* policy CB */
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100603 if (p->cfg->policy_cb) {
604 int rc;
605 rc = p->cfg->policy_cb(tcfg, ENDPOINT_NUMBER(endp),
606 MGCP_ENDP_CRCX, p->trans);
607 switch (rc) {
Holger Hans Peter Freytherfe86d3c2010-02-26 13:37:05 +0100608 case MGCP_POLICY_REJECT:
609 LOGP(DMGCP, LOGL_NOTICE, "CRCX rejected by policy on 0x%x\n",
610 ENDPOINT_NUMBER(endp));
611 mgcp_free_endp(endp);
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100612 return create_err_response(endp, 400, "CRCX", p->trans);
Holger Hans Peter Freytherfe86d3c2010-02-26 13:37:05 +0100613 break;
614 case MGCP_POLICY_DEFER:
615 /* stop processing */
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +0800616 create_transcoder(endp);
Holger Hans Peter Freytherfe86d3c2010-02-26 13:37:05 +0100617 return NULL;
618 break;
619 case MGCP_POLICY_CONT:
620 /* just continue */
621 break;
622 }
623 }
624
Holger Hans Peter Freythere378cb12010-08-06 20:22:23 +0800625 LOGP(DMGCP, LOGL_DEBUG, "Creating endpoint on: 0x%x CI: %u port: %u/%u\n",
Holger Hans Peter Freyther58ff2192010-08-05 03:08:35 +0800626 ENDPOINT_NUMBER(endp), endp->ci,
627 endp->net_end.local_port, endp->bts_end.local_port);
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100628 if (p->cfg->change_cb)
629 p->cfg->change_cb(tcfg, ENDPOINT_NUMBER(endp), MGCP_ENDP_CRCX);
Holger Hans Peter Freyther77f7afe2010-02-03 09:54:43 +0100630
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +0800631 create_transcoder(endp);
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100632 return create_response_with_sdp(endp, "CRCX", p->trans);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100633error2:
Holger Hans Peter Freyther414bf402010-08-06 07:05:13 +0800634 mgcp_free_endp(endp);
Holger Hans Peter Freyther2ada71d2010-02-03 09:13:10 +0100635 LOGP(DMGCP, LOGL_NOTICE, "Resource error on 0x%x\n", ENDPOINT_NUMBER(endp));
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100636 return create_err_response(endp, error_code, "CRCX", p->trans);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100637}
638
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100639static struct msgb *handle_modify_con(struct mgcp_parse_data *p)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100640{
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100641 struct mgcp_endpoint *endp = p->endp;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100642 int error_code = 500;
Holger Hans Peter Freythere3d16bb2010-04-22 11:58:13 +0800643 int silent = 0;
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100644 char *line;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100645
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100646 if (p->found != 0)
647 return create_err_response(NULL, 510, "MDCX", p->trans);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100648
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100649 if (endp->ci == CI_UNUSED) {
650 LOGP(DMGCP, LOGL_ERROR, "Endpoint is not "
651 "holding a connection. 0x%x\n", ENDPOINT_NUMBER(endp));
652 return create_err_response(endp, 400, "MDCX", p->trans);
653 }
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100654
Jacob Erlbecka01bd602013-11-29 13:43:43 +0100655 for_each_non_empty_line(line, p->save) {
Harald Welteae199722012-01-27 12:31:36 +0100656 switch (line[0]) {
657 case 'C': {
658 if (verify_call_id(endp, line + 3) != 0)
659 goto error3;
660 break;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100661 }
Harald Welteae199722012-01-27 12:31:36 +0100662 case 'I': {
663 if (verify_ci(endp, line + 3) != 0)
664 goto error3;
665 break;
666 }
667 case 'L':
668 /* skip */
669 break;
670 case 'M':
671 if (parse_conn_mode(line + 3, &endp->conn_mode) != 0) {
672 error_code = 517;
673 goto error3;
674 }
675 endp->orig_mode = endp->conn_mode;
676 break;
677 case 'Z':
678 silent = strcmp("noanswer", line + 3) == 0;
679 break;
680 case '\0':
681 /* SDP file begins */
682 break;
683 case 'a':
684 case 'o':
685 case 's':
686 case 't':
687 case 'v':
688 /* skip these SDP attributes */
689 break;
690 case 'm': {
691 int port;
692 int payload;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100693
Harald Welteae199722012-01-27 12:31:36 +0100694 if (sscanf(line, "m=audio %d RTP/AVP %d", &port, &payload) == 2) {
695 endp->net_end.rtp_port = htons(port);
696 endp->net_end.rtcp_port = htons(port + 1);
697 endp->net_end.payload_type = payload;
698 }
699 break;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100700 }
Harald Welteae199722012-01-27 12:31:36 +0100701 case 'c': {
702 char ipv4[16];
703
704 if (sscanf(line, "c=IN IP4 %15s", ipv4) == 1) {
705 inet_aton(ipv4, &endp->net_end.addr);
706 }
707 break;
708 }
709 default:
710 LOGP(DMGCP, LOGL_NOTICE, "Unhandled option: '%c'/%d on 0x%x\n",
711 line[0], line[0], ENDPOINT_NUMBER(endp));
712 break;
713 }
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100714 }
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100715
Holger Hans Peter Freytherfe86d3c2010-02-26 13:37:05 +0100716 /* policy CB */
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100717 if (p->cfg->policy_cb) {
718 int rc;
719 rc = p->cfg->policy_cb(endp->tcfg, ENDPOINT_NUMBER(endp),
720 MGCP_ENDP_MDCX, p->trans);
721 switch (rc) {
Holger Hans Peter Freytherfe86d3c2010-02-26 13:37:05 +0100722 case MGCP_POLICY_REJECT:
723 LOGP(DMGCP, LOGL_NOTICE, "MDCX rejected by policy on 0x%x\n",
724 ENDPOINT_NUMBER(endp));
Holger Hans Peter Freythere3d16bb2010-04-22 11:58:13 +0800725 if (silent)
726 goto out_silent;
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100727 return create_err_response(endp, 400, "MDCX", p->trans);
Holger Hans Peter Freytherfe86d3c2010-02-26 13:37:05 +0100728 break;
729 case MGCP_POLICY_DEFER:
730 /* stop processing */
731 return NULL;
732 break;
733 case MGCP_POLICY_CONT:
734 /* just continue */
735 break;
736 }
737 }
738
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100739 /* modify */
Holger Hans Peter Freythere378cb12010-08-06 20:22:23 +0800740 LOGP(DMGCP, LOGL_DEBUG, "Modified endpoint on: 0x%x Server: %s:%u\n",
Holger Hans Peter Freythera17d7012010-08-05 01:34:51 +0800741 ENDPOINT_NUMBER(endp), inet_ntoa(endp->net_end.addr), ntohs(endp->net_end.rtp_port));
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100742 if (p->cfg->change_cb)
743 p->cfg->change_cb(endp->tcfg, ENDPOINT_NUMBER(endp), MGCP_ENDP_MDCX);
Holger Hans Peter Freythere3d16bb2010-04-22 11:58:13 +0800744 if (silent)
745 goto out_silent;
746
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100747 return create_response_with_sdp(endp, "MDCX", p->trans);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100748
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100749error3:
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100750 return create_err_response(endp, error_code, "MDCX", p->trans);
Holger Hans Peter Freythere3d16bb2010-04-22 11:58:13 +0800751
752
753out_silent:
754 return NULL;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100755}
756
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100757static struct msgb *handle_delete_con(struct mgcp_parse_data *p)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100758{
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100759 struct mgcp_endpoint *endp = p->endp;
Holger Hans Peter Freyther9e9392d2010-08-08 16:24:48 +0800760 int error_code = 400;
Holger Hans Peter Freythere3d16bb2010-04-22 11:58:13 +0800761 int silent = 0;
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100762 char *line;
Holger Hans Peter Freyther0bf15a82012-09-14 17:18:12 +0200763 char stats[1048];
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100764
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100765 if (p->found != 0)
766 return create_err_response(NULL, error_code, "DLCX", p->trans);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100767
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100768 if (!p->endp->allocated) {
769 LOGP(DMGCP, LOGL_ERROR, "Endpoint is not used. 0x%x\n",
770 ENDPOINT_NUMBER(endp));
771 return create_err_response(endp, 400, "DLCX", p->trans);
772 }
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100773
Jacob Erlbecka01bd602013-11-29 13:43:43 +0100774 for_each_non_empty_line(line, p->save) {
Harald Welteae199722012-01-27 12:31:36 +0100775 switch (line[0]) {
776 case 'C':
777 if (verify_call_id(endp, line + 3) != 0)
778 goto error3;
779 break;
780 case 'I':
781 if (verify_ci(endp, line + 3) != 0)
782 goto error3;
783 break;
784 case 'Z':
785 silent = strcmp("noanswer", line + 3) == 0;
786 break;
787 default:
788 LOGP(DMGCP, LOGL_NOTICE, "Unhandled option: '%c'/%d on 0x%x\n",
789 line[0], line[0], ENDPOINT_NUMBER(endp));
790 break;
791 }
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100792 }
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100793
Holger Hans Peter Freytherfe86d3c2010-02-26 13:37:05 +0100794 /* policy CB */
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100795 if (p->cfg->policy_cb) {
796 int rc;
797 rc = p->cfg->policy_cb(endp->tcfg, ENDPOINT_NUMBER(endp),
798 MGCP_ENDP_DLCX, p->trans);
799 switch (rc) {
Holger Hans Peter Freytherfe86d3c2010-02-26 13:37:05 +0100800 case MGCP_POLICY_REJECT:
801 LOGP(DMGCP, LOGL_NOTICE, "DLCX rejected by policy on 0x%x\n",
802 ENDPOINT_NUMBER(endp));
Holger Hans Peter Freythere3d16bb2010-04-22 11:58:13 +0800803 if (silent)
804 goto out_silent;
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100805 return create_err_response(endp, 400, "DLCX", p->trans);
Holger Hans Peter Freytherfe86d3c2010-02-26 13:37:05 +0100806 break;
807 case MGCP_POLICY_DEFER:
808 /* stop processing */
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +0800809 delete_transcoder(endp);
Holger Hans Peter Freytherfe86d3c2010-02-26 13:37:05 +0100810 return NULL;
811 break;
812 case MGCP_POLICY_CONT:
813 /* just continue */
814 break;
815 }
816 }
817
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100818 /* free the connection */
Holger Hans Peter Freythere378cb12010-08-06 20:22:23 +0800819 LOGP(DMGCP, LOGL_DEBUG, "Deleted endpoint on: 0x%x Server: %s:%u\n",
Holger Hans Peter Freythera17d7012010-08-05 01:34:51 +0800820 ENDPOINT_NUMBER(endp), inet_ntoa(endp->net_end.addr), ntohs(endp->net_end.rtp_port));
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +0800821
Holger Hans Peter Freyther0bf15a82012-09-14 17:18:12 +0200822 /* save the statistics of the current call */
823 mgcp_format_stats(endp, stats, sizeof(stats));
824
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +0800825 delete_transcoder(endp);
Holger Hans Peter Freyther154b9552010-02-26 13:27:51 +0100826 mgcp_free_endp(endp);
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100827 if (p->cfg->change_cb)
828 p->cfg->change_cb(endp->tcfg, ENDPOINT_NUMBER(endp), MGCP_ENDP_DLCX);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100829
Holger Hans Peter Freythere3d16bb2010-04-22 11:58:13 +0800830 if (silent)
831 goto out_silent;
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100832 return create_ok_resp_with_param(endp, 250, "DLCX", p->trans, stats);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100833
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100834error3:
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100835 return create_err_response(endp, error_code, "DLCX", p->trans);
Holger Hans Peter Freythere3d16bb2010-04-22 11:58:13 +0800836
837out_silent:
838 return NULL;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100839}
840
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100841static struct msgb *handle_rsip(struct mgcp_parse_data *p)
Holger Hans Peter Freyther9bdcc9c2010-03-31 06:39:35 +0200842{
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100843 if (p->found != 0) {
Holger Hans Peter Freyther74db7742011-06-10 00:04:55 +0200844 LOGP(DMGCP, LOGL_ERROR, "Failed to find the endpoint.\n");
845 return NULL;
846 }
847
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100848 if (p->cfg->reset_cb)
849 p->cfg->reset_cb(p->endp->tcfg);
Holger Hans Peter Freyther9bdcc9c2010-03-31 06:39:35 +0200850 return NULL;
851}
852
Holger Hans Peter Freyther8d0be252012-11-29 12:54:22 +0100853static char extract_tone(const char *line)
854{
855 const char *str = strstr(line, "D/");
856 if (!str)
857 return CHAR_MAX;
858
859 return str[2];
860}
861
Holger Hans Peter Freyther6e94d6d2011-01-25 23:33:54 +0100862/*
863 * This can request like DTMF detection and forward, fax detection... it
864 * can also request when the notification should be send and such. We don't
865 * do this right now.
866 */
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100867static struct msgb *handle_noti_req(struct mgcp_parse_data *p)
Holger Hans Peter Freyther6e94d6d2011-01-25 23:33:54 +0100868{
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100869 int res = 0;
870 char *line;
Holger Hans Peter Freyther9f3835b2013-05-21 17:04:35 +0200871 char tone = CHAR_MAX;
Holger Hans Peter Freyther6e94d6d2011-01-25 23:33:54 +0100872
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100873 if (p->found != 0)
874 return create_err_response(NULL, 400, "RQNT", p->trans);
Holger Hans Peter Freyther6e94d6d2011-01-25 23:33:54 +0100875
Jacob Erlbecka01bd602013-11-29 13:43:43 +0100876 for_each_non_empty_line(line, p->save) {
Holger Hans Peter Freyther8d0be252012-11-29 12:54:22 +0100877 switch (line[0]) {
878 case 'S':
879 tone = extract_tone(line);
880 break;
881 }
Holger Hans Peter Freyther6e94d6d2011-01-25 23:33:54 +0100882 }
Holger Hans Peter Freyther8d0be252012-11-29 12:54:22 +0100883
884 /* we didn't see a signal request with a tone */
885 if (tone == CHAR_MAX)
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100886 return create_ok_response(p->endp, 200, "RQNT", p->trans);
Holger Hans Peter Freyther8d0be252012-11-29 12:54:22 +0100887
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100888 if (p->cfg->rqnt_cb)
889 res = p->cfg->rqnt_cb(p->endp, tone);
Holger Hans Peter Freyther8d0be252012-11-29 12:54:22 +0100890
891 return res == 0 ?
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100892 create_ok_response(p->endp, 200, "RQNT", p->trans) :
893 create_err_response(p->endp, res, "RQNT", p->trans);
Holger Hans Peter Freyther6e94d6d2011-01-25 23:33:54 +0100894}
895
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100896struct mgcp_config *mgcp_config_alloc(void)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100897{
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100898 struct mgcp_config *cfg;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100899
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100900 cfg = talloc_zero(NULL, struct mgcp_config);
901 if (!cfg) {
902 LOGP(DMGCP, LOGL_FATAL, "Failed to allocate config.\n");
903 return NULL;
904 }
905
906 cfg->source_port = 2427;
907 cfg->source_addr = talloc_strdup(cfg, "0.0.0.0");
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +0100908
Holger Hans Peter Freytherb98ba722010-09-19 04:21:39 +0800909 cfg->transcoder_remote_base = 4000;
Holger Hans Peter Freyther15e73892010-08-05 07:10:56 +0800910
911 cfg->bts_ports.base_port = RTP_PORT_DEFAULT;
912 cfg->net_ports.base_port = RTP_PORT_NET_DEFAULT;
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100913
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +0100914 /* default trunk handling */
915 cfg->trunk.cfg = cfg;
916 cfg->trunk.trunk_nr = 0;
917 cfg->trunk.trunk_type = MGCP_TRUNK_VIRTUAL;
918 cfg->trunk.audio_name = talloc_strdup(cfg, "AMR/8000");
919 cfg->trunk.audio_payload = 126;
Holger Hans Peter Freythera8090d52012-05-11 13:00:45 +0200920 cfg->trunk.omit_rtcp = 0;
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +0100921
Holger Hans Peter Freyther0e939fe2011-02-28 12:11:02 +0100922 INIT_LLIST_HEAD(&cfg->trunks);
923
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100924 return cfg;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100925}
926
Holger Hans Peter Freyther0e939fe2011-02-28 12:11:02 +0100927struct mgcp_trunk_config *mgcp_trunk_alloc(struct mgcp_config *cfg, int nr)
928{
929 struct mgcp_trunk_config *trunk;
930
931 trunk = talloc_zero(cfg, struct mgcp_trunk_config);
932 if (!trunk) {
933 LOGP(DMGCP, LOGL_ERROR, "Failed to allocate.\n");
934 return NULL;
935 }
936
937 trunk->cfg = cfg;
938 trunk->trunk_type = MGCP_TRUNK_E1;
939 trunk->trunk_nr = nr;
940 trunk->audio_name = talloc_strdup(cfg, "AMR/8000");
941 trunk->audio_payload = 126;
942 trunk->number_endpoints = 33;
Holger Hans Peter Freythera8090d52012-05-11 13:00:45 +0200943 trunk->omit_rtcp = 0;
Holger Hans Peter Freyther0e939fe2011-02-28 12:11:02 +0100944 llist_add_tail(&trunk->entry, &cfg->trunks);
945 return trunk;
946}
947
948struct mgcp_trunk_config *mgcp_trunk_num(struct mgcp_config *cfg, int index)
949{
950 struct mgcp_trunk_config *trunk;
951
952 llist_for_each_entry(trunk, &cfg->trunks, entry)
953 if (trunk->trunk_nr == index)
954 return trunk;
955
956 return NULL;
957}
958
Holger Hans Peter Freythera17d7012010-08-05 01:34:51 +0800959static void mgcp_rtp_end_reset(struct mgcp_rtp_end *end)
960{
Holger Hans Peter Freythere97155a2010-11-02 19:06:13 +0100961 if (end->local_alloc == PORT_ALLOC_DYNAMIC) {
Holger Hans Peter Freytherf138f912010-08-05 08:08:17 +0800962 mgcp_free_rtp_port(end);
Holger Hans Peter Freythere97155a2010-11-02 19:06:13 +0100963 end->local_port = 0;
964 }
Holger Hans Peter Freytherf138f912010-08-05 08:08:17 +0800965
Holger Hans Peter Freytherc4921272010-08-05 03:37:22 +0800966 end->packets = 0;
Holger Hans Peter Freyther952f7522012-09-12 11:38:37 +0200967 end->octets = 0;
Holger Hans Peter Freytherc4921272010-08-05 03:37:22 +0800968 memset(&end->addr, 0, sizeof(end->addr));
Holger Hans Peter Freythere97155a2010-11-02 19:06:13 +0100969 end->rtp_port = end->rtcp_port = 0;
Holger Hans Peter Freythera17d7012010-08-05 01:34:51 +0800970 end->payload_type = -1;
Holger Hans Peter Freytherf138f912010-08-05 08:08:17 +0800971 end->local_alloc = -1;
Holger Hans Peter Freyther5ea1bc72012-09-03 00:07:39 +0200972 talloc_free(end->fmtp_extra);
973 end->fmtp_extra = NULL;
Jacob Erlbeck72c30902013-11-25 15:23:35 +0100974
975 /* Set default values */
976 end->frame_duration_num = DEFAULT_RTP_AUDIO_FRAME_DUR_NUM;
977 end->frame_duration_den = DEFAULT_RTP_AUDIO_FRAME_DUR_DEN;
978 end->frames_per_packet = DEFAULT_RTP_AUDIO_FRAMES_PER_PACKET;
979 end->rate = DEFAULT_RTP_AUDIO_DEFAULT_RATE;
Holger Hans Peter Freythera17d7012010-08-05 01:34:51 +0800980}
981
Holger Hans Peter Freytherc4921272010-08-05 03:37:22 +0800982static void mgcp_rtp_end_init(struct mgcp_rtp_end *end)
983{
984 mgcp_rtp_end_reset(end);
985 end->rtp.fd = -1;
986 end->rtcp.fd = -1;
987}
988
Holger Hans Peter Freyther1f0c5b42011-02-28 14:37:03 +0100989int mgcp_endpoints_allocate(struct mgcp_trunk_config *tcfg)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100990{
991 int i;
992
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100993 /* Initialize all endpoints */
Holger Hans Peter Freyther1f0c5b42011-02-28 14:37:03 +0100994 tcfg->endpoints = _talloc_zero_array(tcfg->cfg,
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100995 sizeof(struct mgcp_endpoint),
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +0100996 tcfg->number_endpoints, "endpoints");
997 if (!tcfg->endpoints)
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100998 return -1;
999
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +01001000 for (i = 0; i < tcfg->number_endpoints; ++i) {
1001 tcfg->endpoints[i].ci = CI_UNUSED;
Holger Hans Peter Freyther1f0c5b42011-02-28 14:37:03 +01001002 tcfg->endpoints[i].cfg = tcfg->cfg;
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +01001003 tcfg->endpoints[i].tcfg = tcfg;
1004 mgcp_rtp_end_init(&tcfg->endpoints[i].net_end);
1005 mgcp_rtp_end_init(&tcfg->endpoints[i].bts_end);
1006 mgcp_rtp_end_init(&tcfg->endpoints[i].trans_net);
1007 mgcp_rtp_end_init(&tcfg->endpoints[i].trans_bts);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +01001008 }
1009
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +01001010 return 0;
1011}
Holger Hans Peter Freyther154b9552010-02-26 13:27:51 +01001012
1013void mgcp_free_endp(struct mgcp_endpoint *endp)
1014{
Holger Hans Peter Freytherc77efdf2010-03-31 12:31:09 +02001015 LOGP(DMGCP, LOGL_DEBUG, "Deleting endpoint on: 0x%x\n", ENDPOINT_NUMBER(endp));
Holger Hans Peter Freyther89976e82010-08-03 15:01:43 +00001016 endp->ci = CI_UNUSED;
Holger Hans Peter Freyther39a97e22010-08-06 18:03:11 +08001017 endp->allocated = 0;
Holger Hans Peter Freyther154b9552010-02-26 13:27:51 +01001018
Holger Hans Peter Freyther01d315f2012-12-07 11:52:16 +01001019 talloc_free(endp->callid);
1020 endp->callid = NULL;
Holger Hans Peter Freyther154b9552010-02-26 13:27:51 +01001021
Holger Hans Peter Freyther01d315f2012-12-07 11:52:16 +01001022 talloc_free(endp->local_options);
1023 endp->local_options = NULL;
Holger Hans Peter Freyther154b9552010-02-26 13:27:51 +01001024
Holger Hans Peter Freythera17d7012010-08-05 01:34:51 +08001025 mgcp_rtp_end_reset(&endp->bts_end);
1026 mgcp_rtp_end_reset(&endp->net_end);
Holger Hans Peter Freyther21262332010-11-01 20:53:31 +01001027 mgcp_rtp_end_reset(&endp->trans_net);
Holger Hans Peter Freytherbd7b3c52010-11-01 21:04:54 +01001028 mgcp_rtp_end_reset(&endp->trans_bts);
Pablo Neira Ayuso46bd4242013-07-08 05:09:46 +02001029 endp->type = MGCP_RTP_DEFAULT;
Holger Hans Peter Freyther380b8712010-07-29 02:38:39 +08001030
Holger Hans Peter Freyther31868922010-08-03 11:59:04 +00001031 memset(&endp->net_state, 0, sizeof(endp->net_state));
1032 memset(&endp->bts_state, 0, sizeof(endp->bts_state));
Holger Hans Peter Freytherc597a4e2010-08-03 02:57:02 +08001033
1034 endp->conn_mode = endp->orig_mode = MGCP_CONN_NONE;
Holger Hans Peter Freyther6357a8e2010-08-05 12:07:00 +00001035 endp->allow_patch = 0;
Holger Hans Peter Freyther260d6ed2010-08-06 01:12:21 +08001036
1037 memset(&endp->taps, 0, sizeof(endp->taps));
Holger Hans Peter Freyther154b9552010-02-26 13:27:51 +01001038}
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +08001039
Holger Hans Peter Freyther557b1ab2010-09-19 04:39:55 +08001040static int send_trans(struct mgcp_config *cfg, const char *buf, int len)
1041{
1042 struct sockaddr_in addr;
1043
1044 memset(&addr, 0, sizeof(addr));
1045 addr.sin_family = AF_INET;
1046 addr.sin_addr = cfg->transcoder_in;
1047 addr.sin_port = htons(2427);
1048 return sendto(cfg->gw_fd.bfd.fd, buf, len, 0,
1049 (struct sockaddr *) &addr, sizeof(addr));
1050}
1051
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +08001052static void send_msg(struct mgcp_endpoint *endp, int endpoint, int port,
1053 const char *msg, const char *mode)
1054{
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +08001055 char buf[2096];
1056 int len;
1057
1058 /* hardcoded to AMR right now, we do not know the real type at this point */
1059 len = snprintf(buf, sizeof(buf),
1060 "%s 42 %x@mgw MGCP 1.0\r\n"
1061 "C: 4256\r\n"
1062 "M: %s\r\n"
1063 "\r\n"
1064 "c=IN IP4 %s\r\n"
1065 "m=audio %d RTP/AVP %d\r\n"
1066 "a=rtpmap:%d %s\r\n",
1067 msg, endpoint, mode, endp->cfg->source_addr,
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +01001068 port, endp->tcfg->audio_payload,
1069 endp->tcfg->audio_payload, endp->tcfg->audio_name);
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +08001070
1071 if (len < 0)
1072 return;
1073
1074 buf[sizeof(buf) - 1] = '\0';
1075
Holger Hans Peter Freyther557b1ab2010-09-19 04:39:55 +08001076 send_trans(endp->cfg, buf, len);
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +08001077}
1078
1079static void send_dlcx(struct mgcp_endpoint *endp, int endpoint)
1080{
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +08001081 char buf[2096];
1082 int len;
1083
1084 len = snprintf(buf, sizeof(buf),
1085 "DLCX 43 %x@mgw MGCP 1.0\r\n"
1086 "C: 4256\r\n"
1087 , endpoint);
1088
1089 if (len < 0)
1090 return;
1091
1092 buf[sizeof(buf) - 1] = '\0';
1093
Holger Hans Peter Freyther557b1ab2010-09-19 04:39:55 +08001094 send_trans(endp->cfg, buf, len);
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +08001095}
1096
Harald Welte6a857052012-01-27 00:41:39 +01001097static int send_agent(struct mgcp_config *cfg, const char *buf, int len)
1098{
1099 return write(cfg->gw_fd.bfd.fd, buf, len);
1100}
1101
1102int mgcp_send_reset_all(struct mgcp_config *cfg)
1103{
1104 static const char mgcp_reset[] = {
1105 "RSIP 1 *@mgw MGCP 1.0\r\n"
1106 };
1107
1108 return send_agent(cfg, mgcp_reset, sizeof mgcp_reset -1);
1109}
1110
1111int mgcp_send_reset_ep(struct mgcp_endpoint *endp, int endpoint)
1112{
1113 char buf[128];
1114 int len;
1115
1116 len = snprintf(buf, sizeof(buf),
1117 "RSIP 39 %x@mgw MGCP 1.0\r\n"
1118 , endpoint);
1119 if (len < 0)
1120 return len;
1121
1122 buf[sizeof(buf) - 1] = '\0';
1123
1124 return send_agent(endp->cfg, buf, len);
1125}
1126
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +08001127static void create_transcoder(struct mgcp_endpoint *endp)
1128{
1129 int port;
1130 int in_endp = ENDPOINT_NUMBER(endp);
Holger Hans Peter Freytherbd7b3c52010-11-01 21:04:54 +01001131 int out_endp = endp_back_channel(in_endp);
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +08001132
Pablo Neira Ayuso46bd4242013-07-08 05:09:46 +02001133 if (endp->type != MGCP_RTP_TRANSCODED)
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +08001134 return;
1135
Holger Hans Peter Freyther8b19dee2010-11-01 22:38:25 +01001136 send_msg(endp, in_endp, endp->trans_bts.local_port, "CRCX", "sendrecv");
1137 send_msg(endp, in_endp, endp->trans_bts.local_port, "MDCX", "sendrecv");
Holger Hans Peter Freyther21262332010-11-01 20:53:31 +01001138 send_msg(endp, out_endp, endp->trans_net.local_port, "CRCX", "sendrecv");
1139 send_msg(endp, out_endp, endp->trans_net.local_port, "MDCX", "sendrecv");
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +08001140
Holger Hans Peter Freytherbd7b3c52010-11-01 21:04:54 +01001141 port = rtp_calculate_port(in_endp, endp->cfg->transcoder_remote_base);
1142 endp->trans_bts.rtp_port = htons(port);
1143 endp->trans_bts.rtcp_port = htons(port + 1);
1144
Holger Hans Peter Freytherb98ba722010-09-19 04:21:39 +08001145 port = rtp_calculate_port(out_endp, endp->cfg->transcoder_remote_base);
Holger Hans Peter Freyther21262332010-11-01 20:53:31 +01001146 endp->trans_net.rtp_port = htons(port);
1147 endp->trans_net.rtcp_port = htons(port + 1);
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +08001148}
1149
1150static void delete_transcoder(struct mgcp_endpoint *endp)
1151{
1152 int in_endp = ENDPOINT_NUMBER(endp);
Holger Hans Peter Freytherbd7b3c52010-11-01 21:04:54 +01001153 int out_endp = endp_back_channel(in_endp);
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +08001154
Pablo Neira Ayuso46bd4242013-07-08 05:09:46 +02001155 if (endp->type != MGCP_RTP_TRANSCODED)
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +08001156 return;
1157
1158 send_dlcx(endp, in_endp);
1159 send_dlcx(endp, out_endp);
1160}
Holger Hans Peter Freytherf2eedff2010-09-19 04:36:07 +08001161
1162int mgcp_reset_transcoder(struct mgcp_config *cfg)
1163{
Holger Hans Peter Freytherf2eedff2010-09-19 04:36:07 +08001164 if (!cfg->transcoder_ip)
Holger Hans Peter Freythercf1c8772010-09-24 04:41:28 +08001165 return 0;
Holger Hans Peter Freytherf2eedff2010-09-19 04:36:07 +08001166
1167 static const char mgcp_reset[] = {
1168 "RSIP 1 13@mgw MGCP 1.0\r\n"
1169 };
1170
Holger Hans Peter Freyther557b1ab2010-09-19 04:39:55 +08001171 return send_trans(cfg, mgcp_reset, sizeof mgcp_reset -1);
Holger Hans Peter Freytherf2eedff2010-09-19 04:36:07 +08001172}
Holger Hans Peter Freyther0bf15a82012-09-14 17:18:12 +02001173
1174void mgcp_format_stats(struct mgcp_endpoint *endp, char *msg, size_t size)
1175{
Holger Hans Peter Freythercb306a62012-10-24 21:22:47 +02001176 uint32_t expected, jitter;
Holger Hans Peter Freyther38e02c52012-10-22 18:09:35 +02001177 int ploss;
Jacob Erlbeck50079a12013-11-25 12:53:28 +01001178 int nchars;
Holger Hans Peter Freyther38e02c52012-10-22 18:09:35 +02001179 mgcp_state_calc_loss(&endp->net_state, &endp->net_end,
1180 &expected, &ploss);
Holger Hans Peter Freythercb306a62012-10-24 21:22:47 +02001181 jitter = mgcp_state_calc_jitter(&endp->net_state);
Holger Hans Peter Freyther38e02c52012-10-22 18:09:35 +02001182
Jacob Erlbeck50079a12013-11-25 12:53:28 +01001183 nchars = snprintf(msg, size,
1184 "\r\nP: PS=%u, OS=%u, PR=%u, OR=%u, PL=%d, JI=%u",
1185 endp->bts_end.packets, endp->bts_end.octets,
1186 endp->net_end.packets, endp->net_end.octets,
1187 ploss, jitter);
1188 if (nchars < 0 || nchars >= size)
1189 goto truncate;
1190
1191 msg += nchars;
1192 size -= nchars;
1193
1194 /* Error Counter */
1195 snprintf(msg, size,
1196 "\r\nX-Osmo-CP: EC TIS=%u, TOS=%u, TIR=%u, TOR=%u",
1197 endp->net_state.in_stream.err_ts_counter,
1198 endp->net_state.out_stream.err_ts_counter,
1199 endp->bts_state.in_stream.err_ts_counter,
1200 endp->bts_state.out_stream.err_ts_counter);
1201truncate:
Holger Hans Peter Freyther0bf15a82012-09-14 17:18:12 +02001202 msg[size - 1] = '\0';
1203}
Holger Hans Peter Freyther462b7d72012-10-24 21:53:40 +02001204
1205int mgcp_parse_stats(struct msgb *msg, uint32_t *ps, uint32_t *os,
1206 uint32_t *pr, uint32_t *_or, int *loss, uint32_t *jitter)
1207{
1208 char *line, *save;
1209 int rc;
1210
1211 /* initialize with bad values */
1212 *ps = *os = *pr = *_or = *jitter = UINT_MAX;
1213 *loss = INT_MAX;
1214
1215
1216 line = strtok_r((char *) msg->l2h, "\r\n", &save);
1217 if (!line)
1218 return -1;
1219
1220 /* this can only parse the message that is created above... */
Jacob Erlbecka01bd602013-11-29 13:43:43 +01001221 for_each_non_empty_line(line, save) {
Holger Hans Peter Freyther462b7d72012-10-24 21:53:40 +02001222 switch (line[0]) {
1223 case 'P':
1224 rc = sscanf(line, "P: PS=%u, OS=%u, PR=%u, OR=%u, PL=%d, JI=%u",
1225 ps, os, pr, _or, loss, jitter);
1226 return rc == 6 ? 0 : -1;
1227 }
1228 }
1229
1230 return -1;
1231}