blob: 8f6861d92aa486356cd68110d851f50a0b5a3ac5 [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
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +010039#define for_each_line(line, save) \
40 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
Holger Hans Peter Freytherf138f912010-08-05 08:08:17 +080043static void mgcp_rtp_end_reset(struct mgcp_rtp_end *end);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +010044
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +010045struct mgcp_parse_data {
46 struct mgcp_config *cfg;
47 struct mgcp_endpoint *endp;
48 char *trans;
49 char *save;
50 int found;
51};
52
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +010053struct mgcp_request {
54 char *name;
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +010055 struct msgb *(*handle_request) (struct mgcp_parse_data *data);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +010056 char *debug_name;
57};
58
59#define MGCP_REQUEST(NAME, REQ, DEBUG_NAME) \
60 { .name = NAME, .handle_request = REQ, .debug_name = DEBUG_NAME },
61
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +010062static struct msgb *handle_audit_endpoint(struct mgcp_parse_data *data);
63static struct msgb *handle_create_con(struct mgcp_parse_data *data);
64static struct msgb *handle_delete_con(struct mgcp_parse_data *data);
65static struct msgb *handle_modify_con(struct mgcp_parse_data *data);
66static struct msgb *handle_rsip(struct mgcp_parse_data *data);
67static struct msgb *handle_noti_req(struct mgcp_parse_data *data);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +010068
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +080069static void create_transcoder(struct mgcp_endpoint *endp);
70static void delete_transcoder(struct mgcp_endpoint *endp);
71
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +010072static int mgcp_analyze_header(struct mgcp_parse_data *parse, char *data);
73
Holger Hans Peter Freyther46340132010-08-06 08:26:54 +080074static uint32_t generate_call_id(struct mgcp_config *cfg)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +010075{
76 int i;
77
78 /* use the call id */
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +010079 ++cfg->last_call_id;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +010080
81 /* handle wrap around */
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +010082 if (cfg->last_call_id == CI_UNUSED)
83 ++cfg->last_call_id;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +010084
85 /* callstack can only be of size number_of_endpoints */
86 /* verify that the call id is free, e.g. in case of overrun */
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +010087 for (i = 1; i < cfg->trunk.number_endpoints; ++i)
88 if (cfg->trunk.endpoints[i].ci == cfg->last_call_id)
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +010089 return generate_call_id(cfg);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +010090
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +010091 return cfg->last_call_id;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +010092}
93
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +010094/*
95 * array of function pointers for handling various
96 * messages. In the future this might be binary sorted
97 * for performance reasons.
98 */
99static const struct mgcp_request mgcp_requests [] = {
100 MGCP_REQUEST("AUEP", handle_audit_endpoint, "AuditEndpoint")
101 MGCP_REQUEST("CRCX", handle_create_con, "CreateConnection")
102 MGCP_REQUEST("DLCX", handle_delete_con, "DeleteConnection")
103 MGCP_REQUEST("MDCX", handle_modify_con, "ModifiyConnection")
Holger Hans Peter Freyther6e94d6d2011-01-25 23:33:54 +0100104 MGCP_REQUEST("RQNT", handle_noti_req, "NotificationRequest")
Holger Hans Peter Freyther9bdcc9c2010-03-31 06:39:35 +0200105
106 /* SPEC extension */
107 MGCP_REQUEST("RSIP", handle_rsip, "ReSetInProgress")
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100108};
109
Holger Hans Peter Freyther62e836c2010-02-03 11:03:45 +0100110static struct msgb *mgcp_msgb_alloc(void)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100111{
Holger Hans Peter Freyther62e836c2010-02-03 11:03:45 +0100112 struct msgb *msg;
113 msg = msgb_alloc_headroom(4096, 128, "MGCP msg");
114 if (!msg)
115 LOGP(DMGCP, LOGL_ERROR, "Failed to msgb for MGCP data.\n");
116
117 return msg;
118}
119
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100120static struct msgb *do_retransmission(const struct mgcp_endpoint *endp)
121{
122 struct msgb *msg = mgcp_msgb_alloc();
123 if (!msg)
124 return NULL;
125
126 msg->l2h = msgb_put(msg, strlen(endp->last_response));
127 memcpy(msg->l2h, endp->last_response, msgb_l2len(msg));
128 return msg;
129}
130
Holger Hans Peter Freythera769dcb2012-12-07 15:14:27 +0100131static struct msgb *create_resp(struct mgcp_endpoint *endp, int code,
132 const char *txt, const char *msg,
Holger Hans Peter Freyther0bf15a82012-09-14 17:18:12 +0200133 const char *trans, const char *param,
134 const char *sdp)
Holger Hans Peter Freyther62e836c2010-02-03 11:03:45 +0100135{
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100136 int len;
Holger Hans Peter Freyther62e836c2010-02-03 11:03:45 +0100137 struct msgb *res;
138
139 res = mgcp_msgb_alloc();
140 if (!res)
141 return NULL;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100142
Holger Hans Peter Freyther0bf15a82012-09-14 17:18:12 +0200143 len = snprintf((char *) res->data, 2048, "%d %s%s%s\r\n%s",
144 code, trans, txt, param ? param : "", sdp ? sdp : "");
145 if (len < 0) {
146 LOGP(DMGCP, LOGL_ERROR, "Failed to sprintf MGCP response.\n");
147 msgb_free(res);
148 return NULL;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100149 }
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100150
Holger Hans Peter Freyther62e836c2010-02-03 11:03:45 +0100151 res->l2h = msgb_put(res, len);
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100152 LOGP(DMGCP, LOGL_DEBUG, "Generated response: code: %d for '%s'\n", code, res->l2h);
153
154 /*
155 * Remember the last transmission per endpoint.
156 */
157 if (endp) {
158 struct mgcp_trunk_config *tcfg = endp->tcfg;
159 talloc_free(endp->last_response);
160 talloc_free(endp->last_trans);
161 endp->last_trans = talloc_strdup(tcfg->endpoints, trans);
162 endp->last_response = talloc_strndup(tcfg->endpoints,
163 (const char *) res->l2h,
164 msgb_l2len(res));
165 }
166
Holger Hans Peter Freyther62e836c2010-02-03 11:03:45 +0100167 return res;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100168}
169
Holger Hans Peter Freythera769dcb2012-12-07 15:14:27 +0100170static struct msgb *create_ok_resp_with_param(struct mgcp_endpoint *endp,
171 int code, const char *msg,
Holger Hans Peter Freyther0bf15a82012-09-14 17:18:12 +0200172 const char *trans, const char *param)
173{
Holger Hans Peter Freythera769dcb2012-12-07 15:14:27 +0100174 return create_resp(endp, code, " OK", msg, trans, param, NULL);
Holger Hans Peter Freyther0bf15a82012-09-14 17:18:12 +0200175}
176
Holger Hans Peter Freythera769dcb2012-12-07 15:14:27 +0100177static struct msgb *create_ok_response(struct mgcp_endpoint *endp,
178 int code, const char *msg, const char *trans)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100179{
Holger Hans Peter Freythera769dcb2012-12-07 15:14:27 +0100180 return create_ok_resp_with_param(endp, code, msg, trans, NULL);
Holger Hans Peter Freyther6adac172011-01-06 16:19:55 +0100181}
182
Holger Hans Peter Freythera769dcb2012-12-07 15:14:27 +0100183static struct msgb *create_err_response(struct mgcp_endpoint *endp,
184 int code, const char *msg, const char *trans)
Holger Hans Peter Freyther6adac172011-01-06 16:19:55 +0100185{
Holger Hans Peter Freythera769dcb2012-12-07 15:14:27 +0100186 return create_resp(endp, code, " FAIL", msg, trans, NULL, NULL);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100187}
188
Holger Hans Peter Freyther8d188ed2010-02-21 01:44:08 +0100189static struct msgb *create_response_with_sdp(struct mgcp_endpoint *endp,
190 const char *msg, const char *trans_id)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100191{
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100192 const char *addr = endp->cfg->local_ip;
Holger Hans Peter Freyther5ea1bc72012-09-03 00:07:39 +0200193 const char *fmtp_extra = endp->bts_end.fmtp_extra;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100194 char sdp_record[4096];
195
196 if (!addr)
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100197 addr = endp->cfg->source_addr;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100198
199 snprintf(sdp_record, sizeof(sdp_record) - 1,
Holger Hans Peter Freyther46340132010-08-06 08:26:54 +0800200 "I: %u\n\n"
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100201 "v=0\r\n"
Holger Hans Peter Freytherc7e49d32011-07-20 20:43:15 +0200202 "o=- %u 23 IN IP4 %s\r\n"
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100203 "c=IN IP4 %s\r\n"
Holger Hans Peter Freytherc7e49d32011-07-20 20:43:15 +0200204 "t=0 0\r\n"
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100205 "m=audio %d RTP/AVP %d\r\n"
Holger Hans Peter Freyther5ea1bc72012-09-03 00:07:39 +0200206 "a=rtpmap:%d %s\r\n"
207 "%s%s",
Holger Hans Peter Freytherc7e49d32011-07-20 20:43:15 +0200208 endp->ci, endp->ci, addr, addr,
209 endp->net_end.local_port, endp->bts_end.payload_type,
Holger Hans Peter Freyther5ea1bc72012-09-03 00:07:39 +0200210 endp->bts_end.payload_type, endp->tcfg->audio_name,
211 fmtp_extra ? fmtp_extra : "", fmtp_extra ? "\r\n" : "");
Holger Hans Peter Freythera769dcb2012-12-07 15:14:27 +0100212 return create_resp(endp, 200, " OK", msg, trans_id, NULL, sdp_record);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100213}
214
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100215/*
216 * handle incoming messages:
217 * - this can be a command (four letters, space, transaction id)
218 * - or a response (three numbers, space, transaction id)
219 */
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100220struct msgb *mgcp_handle_message(struct mgcp_config *cfg, struct msgb *msg)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100221{
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100222 struct mgcp_parse_data pdata;
223 int i, code, handled = 0;
Holger Hans Peter Freyther62e836c2010-02-03 11:03:45 +0100224 struct msgb *resp = NULL;
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100225 char *data;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100226
Holger Hans Peter Freytherf36a11a2010-03-31 13:26:46 +0200227 if (msgb_l2len(msg) < 4) {
Holger Hans Peter Freyther0d904e02012-12-07 16:46:19 +0100228 LOGP(DMGCP, LOGL_ERROR, "msg too short: %d\n", msg->len);
Holger Hans Peter Freyther62e836c2010-02-03 11:03:45 +0100229 return NULL;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100230 }
231
232 /* attempt to treat it as a response */
Holger Hans Peter Freytherf36a11a2010-03-31 13:26:46 +0200233 if (sscanf((const char *)&msg->l2h[0], "%3d %*s", &code) == 1) {
Holger Hans Peter Freyther63f2db22010-02-26 13:30:57 +0100234 LOGP(DMGCP, LOGL_DEBUG, "Response: Code: %d\n", code);
Holger Hans Peter Freyther29de3462012-12-07 16:07:46 +0100235 return NULL;
236 }
237
238 msg->l3h = &msg->l2h[4];
239
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100240
241 /*
242 * Check for a duplicate message and respond.
243 * FIXME: Verify that the msg->l3h is NULL terminated.
244 */
245 memset(&pdata, 0, sizeof(pdata));
246 pdata.cfg = cfg;
247 data = strtok_r((char *) msg->l3h, "\r\n", &pdata.save);
248 pdata.found = mgcp_analyze_header(&pdata, data);
249 if (pdata.endp && pdata.trans
250 && pdata.endp->last_trans
251 && strcmp(pdata.endp->last_trans, pdata.trans) == 0) {
252 return do_retransmission(pdata.endp);
253 }
254
Holger Hans Peter Freyther29de3462012-12-07 16:07:46 +0100255 for (i = 0; i < ARRAY_SIZE(mgcp_requests); ++i) {
256 if (strncmp(mgcp_requests[i].name, (const char *) &msg->l2h[0], 4) == 0) {
257 handled = 1;
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100258 resp = mgcp_requests[i].handle_request(&pdata);
Holger Hans Peter Freyther29de3462012-12-07 16:07:46 +0100259 break;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100260 }
261 }
262
Holger Hans Peter Freyther29de3462012-12-07 16:07:46 +0100263 if (!handled)
264 LOGP(DMGCP, LOGL_NOTICE, "MSG with type: '%.4s' not handled\n", &msg->l2h[0]);
265
Holger Hans Peter Freyther62e836c2010-02-03 11:03:45 +0100266 return resp;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100267}
268
Holger Hans Peter Freyther9f239a22011-01-06 19:32:52 +0100269/**
270 * We have a null terminated string with the endpoint name here. We only
271 * support two kinds. Simple ones as seen on the BSC level and the ones
272 * seen on the trunk side.
273 */
274static struct mgcp_endpoint *find_e1_endpoint(struct mgcp_config *cfg,
275 const char *mgcp)
276{
277 char *rest = NULL;
Holger Hans Peter Freyther74e61112011-02-28 14:13:47 +0100278 struct mgcp_trunk_config *tcfg;
279 int trunk, endp;
Holger Hans Peter Freyther9f239a22011-01-06 19:32:52 +0100280
281 trunk = strtoul(mgcp + 6, &rest, 10);
Holger Hans Peter Freytherf43f2fc2011-01-07 11:30:21 +0100282 if (rest == NULL || rest[0] != '/' || trunk < 1) {
Holger Hans Peter Freyther9f239a22011-01-06 19:32:52 +0100283 LOGP(DMGCP, LOGL_ERROR, "Wrong trunk name '%s'\n", mgcp);
284 return NULL;
285 }
286
287 endp = strtoul(rest + 1, &rest, 10);
288 if (rest == NULL || rest[0] != '@') {
Holger Hans Peter Freytherf43f2fc2011-01-07 11:30:21 +0100289 LOGP(DMGCP, LOGL_ERROR, "Wrong endpoint name '%s'\n", mgcp);
Holger Hans Peter Freyther9f239a22011-01-06 19:32:52 +0100290 return NULL;
291 }
292
293 /* signalling is on timeslot 1 */
294 if (endp == 1)
295 return NULL;
296
Holger Hans Peter Freyther74e61112011-02-28 14:13:47 +0100297 tcfg = mgcp_trunk_num(cfg, trunk);
298 if (!tcfg) {
299 LOGP(DMGCP, LOGL_ERROR, "The trunk %d is not declared.\n", trunk);
300 return NULL;
301 }
302
303 if (!tcfg->endpoints) {
304 LOGP(DMGCP, LOGL_ERROR, "Endpoints of trunk %d not allocated.\n", trunk);
305 return NULL;
306 }
307
308 if (endp < 1 || endp >= tcfg->number_endpoints) {
Holger Hans Peter Freyther9f239a22011-01-06 19:32:52 +0100309 LOGP(DMGCP, LOGL_ERROR, "Failed to find endpoint '%s'\n", mgcp);
Holger Hans Peter Freyther45c21842011-01-07 11:36:54 +0100310 return NULL;
Holger Hans Peter Freyther9f239a22011-01-06 19:32:52 +0100311 }
312
Holger Hans Peter Freyther74e61112011-02-28 14:13:47 +0100313 return &tcfg->endpoints[endp];
Holger Hans Peter Freyther9f239a22011-01-06 19:32:52 +0100314}
315
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100316static struct mgcp_endpoint *find_endpoint(struct mgcp_config *cfg, const char *mgcp)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100317{
318 char *endptr = NULL;
319 unsigned int gw = INT_MAX;
320
Holger Hans Peter Freyther9f239a22011-01-06 19:32:52 +0100321 if (strncmp(mgcp, "ds/e1", 5) == 0) {
322 return find_e1_endpoint(cfg, mgcp);
323 } else {
324 gw = strtoul(mgcp, &endptr, 16);
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +0100325 if (gw > 0 && gw < cfg->trunk.number_endpoints && strcmp(endptr, "@mgw") == 0)
326 return &cfg->trunk.endpoints[gw];
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100327 }
328
Holger Hans Peter Freyther9f239a22011-01-06 19:32:52 +0100329 LOGP(DMGCP, LOGL_ERROR, "Not able to find endpoint: '%s'\n", mgcp);
330 return NULL;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100331}
332
Harald Welteae199722012-01-27 12:31:36 +0100333/**
334 * @returns 0 when the status line was complete and transaction_id and
335 * endp out parameters are set.
336 */
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100337static int mgcp_analyze_header(struct mgcp_parse_data *pdata, char *data)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100338{
Harald Welteae199722012-01-27 12:31:36 +0100339 int i = 0;
Holger Hans Peter Freyther1eba7de2013-07-03 10:23:35 +0200340 char *elem, *save = NULL;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100341
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100342 pdata->trans = "000000";
Holger Hans Peter Freythera820c5f2010-02-26 13:32:55 +0100343
Harald Welteae199722012-01-27 12:31:36 +0100344 for (elem = strtok_r(data, " ", &save); elem;
345 elem = strtok_r(NULL, " ", &save)) {
346 switch (i) {
347 case 0:
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100348 pdata->trans = elem;
Harald Welteae199722012-01-27 12:31:36 +0100349 break;
350 case 1:
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100351 pdata->endp = find_endpoint(pdata->cfg, elem);
352 if (!pdata->endp) {
353 LOGP(DMGCP, LOGL_ERROR,
354 "Unable to find Endpoint `%s'\n", elem);
355 return -1;
Harald Welteae199722012-01-27 12:31:36 +0100356 }
357 break;
358 case 2:
359 if (strcmp("MGCP", elem)) {
360 LOGP(DMGCP, LOGL_ERROR,
361 "MGCP header parsing error\n");
362 return -1;
363 }
364 break;
365 case 3:
366 if (strcmp("1.0", elem)) {
367 LOGP(DMGCP, LOGL_ERROR, "MGCP version `%s' "
368 "not supported\n", elem);
369 return -1;
370 }
371 break;
372 }
373 i++;
374 }
375
376 if (i != 4) {
377 LOGP(DMGCP, LOGL_ERROR, "MGCP status line too short.\n");
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100378 pdata->trans = "000000";
379 pdata->endp = NULL;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100380 return -1;
381 }
382
Holger Hans Peter Freytherf2f15912010-04-01 03:27:04 +0200383 return 0;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100384}
385
386static int verify_call_id(const struct mgcp_endpoint *endp,
387 const char *callid)
388{
389 if (strcmp(endp->callid, callid) != 0) {
Holger Hans Peter Freyther2ada71d2010-02-03 09:13:10 +0100390 LOGP(DMGCP, LOGL_ERROR, "CallIDs does not match on 0x%x. '%s' != '%s'\n",
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100391 ENDPOINT_NUMBER(endp), endp->callid, callid);
392 return -1;
393 }
394
395 return 0;
396}
397
398static int verify_ci(const struct mgcp_endpoint *endp,
Holger Hans Peter Freyther46340132010-08-06 08:26:54 +0800399 const char *_ci)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100400{
Holger Hans Peter Freyther46340132010-08-06 08:26:54 +0800401 uint32_t ci = strtoul(_ci, NULL, 10);
402
403 if (ci != endp->ci) {
404 LOGP(DMGCP, LOGL_ERROR, "ConnectionIdentifiers do not match on 0x%x. %u != %s\n",
405 ENDPOINT_NUMBER(endp), endp->ci, _ci);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100406 return -1;
407 }
408
409 return 0;
410}
411
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100412static struct msgb *handle_audit_endpoint(struct mgcp_parse_data *p)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100413{
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100414 if (p->found != 0)
415 return create_err_response(NULL, 500, "AUEP", p->trans);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100416 else
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100417 return create_ok_response(p->endp, 200, "AUEP", p->trans);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100418}
419
Holger Hans Peter Freytheradb6e1c2010-09-18 06:44:24 +0800420static int parse_conn_mode(const char *msg, int *conn_mode)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100421{
422 int ret = 0;
423 if (strcmp(msg, "recvonly") == 0)
424 *conn_mode = MGCP_CONN_RECV_ONLY;
425 else if (strcmp(msg, "sendrecv") == 0)
426 *conn_mode = MGCP_CONN_RECV_SEND;
Holger Hans Peter Freythere02860a2010-09-18 20:21:44 +0800427 else if (strcmp(msg, "sendonly") == 0)
428 *conn_mode = MGCP_CONN_SEND_ONLY;
Holger Hans Peter Freyther98a38772010-08-03 02:27:21 +0800429 else if (strcmp(msg, "loopback") == 0)
430 *conn_mode = MGCP_CONN_LOOPBACK;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100431 else {
Holger Hans Peter Freyther2ada71d2010-02-03 09:13:10 +0100432 LOGP(DMGCP, LOGL_ERROR, "Unknown connection mode: '%s'\n", msg);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100433 ret = -1;
434 }
435
436 return ret;
437}
438
Holger Hans Peter Freytherf138f912010-08-05 08:08:17 +0800439static int allocate_port(struct mgcp_endpoint *endp, struct mgcp_rtp_end *end,
Holger Hans Peter Freyther218f8562010-09-18 02:30:02 +0800440 struct mgcp_port_range *range,
441 int (*alloc)(struct mgcp_endpoint *endp, int port))
Holger Hans Peter Freytherf138f912010-08-05 08:08:17 +0800442{
443 int i;
444
445 if (range->mode == PORT_ALLOC_STATIC) {
Holger Hans Peter Freytherf138f912010-08-05 08:08:17 +0800446 end->local_alloc = PORT_ALLOC_STATIC;
447 return 0;
448 }
449
450 /* attempt to find a port */
451 for (i = 0; i < 200; ++i) {
452 int rc;
453
454 if (range->last_port >= range->range_end)
455 range->last_port = range->range_start;
456
Holger Hans Peter Freyther218f8562010-09-18 02:30:02 +0800457 rc = alloc(endp, range->last_port);
Holger Hans Peter Freytherf138f912010-08-05 08:08:17 +0800458
459 range->last_port += 2;
460 if (rc == 0) {
461 end->local_alloc = PORT_ALLOC_DYNAMIC;
462 return 0;
463 }
464
465 }
466
Holger Hans Peter Freyther218f8562010-09-18 02:30:02 +0800467 LOGP(DMGCP, LOGL_ERROR, "Allocating a RTP/RTCP port failed 200 times 0x%x.\n",
468 ENDPOINT_NUMBER(endp));
Holger Hans Peter Freytherf138f912010-08-05 08:08:17 +0800469 return -1;
470}
471
472static int allocate_ports(struct mgcp_endpoint *endp)
473{
Holger Hans Peter Freyther218f8562010-09-18 02:30:02 +0800474 if (allocate_port(endp, &endp->net_end, &endp->cfg->net_ports,
475 mgcp_bind_net_rtp_port) != 0)
Holger Hans Peter Freytherf138f912010-08-05 08:08:17 +0800476 return -1;
477
Holger Hans Peter Freyther218f8562010-09-18 02:30:02 +0800478 if (allocate_port(endp, &endp->bts_end, &endp->cfg->bts_ports,
479 mgcp_bind_bts_rtp_port) != 0) {
Holger Hans Peter Freytherf138f912010-08-05 08:08:17 +0800480 mgcp_rtp_end_reset(&endp->net_end);
481 return -1;
482 }
483
Holger Hans Peter Freyther69906872011-02-28 14:51:48 +0100484 if (endp->cfg->transcoder_ip && endp->tcfg->trunk_type == MGCP_TRUNK_VIRTUAL) {
Holger Hans Peter Freyther21262332010-11-01 20:53:31 +0100485 if (allocate_port(endp, &endp->trans_net,
Holger Hans Peter Freytherb54048f2010-11-01 19:57:50 +0100486 &endp->cfg->transcoder_ports,
Holger Hans Peter Freytherbd7b3c52010-11-01 21:04:54 +0100487 mgcp_bind_trans_net_rtp_port) != 0) {
Holger Hans Peter Freytherb54048f2010-11-01 19:57:50 +0100488 mgcp_rtp_end_reset(&endp->net_end);
489 mgcp_rtp_end_reset(&endp->bts_end);
490 return -1;
491 }
492
Holger Hans Peter Freytherbd7b3c52010-11-01 21:04:54 +0100493 if (allocate_port(endp, &endp->trans_bts,
494 &endp->cfg->transcoder_ports,
495 mgcp_bind_trans_bts_rtp_port) != 0) {
496 mgcp_rtp_end_reset(&endp->net_end);
497 mgcp_rtp_end_reset(&endp->bts_end);
498 mgcp_rtp_end_reset(&endp->trans_net);
499 return -1;
500 }
501
Holger Hans Peter Freytherb54048f2010-11-01 19:57:50 +0100502 /* remember that we have set up transcoding */
503 endp->is_transcoded = 1;
Holger Hans Peter Freyther218f8562010-09-18 02:30:02 +0800504 }
505
Holger Hans Peter Freytherf138f912010-08-05 08:08:17 +0800506 return 0;
507}
508
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100509static struct msgb *handle_create_con(struct mgcp_parse_data *p)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100510{
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +0100511 struct mgcp_trunk_config *tcfg;
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100512 struct mgcp_endpoint *endp = p->endp;
Holger Hans Peter Freyther9e9392d2010-08-08 16:24:48 +0800513 int error_code = 400;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100514
Holger Hans Peter Freyther3488c3d2011-07-20 20:44:54 +0200515 const char *local_options = NULL;
516 const char *callid = NULL;
517 const char *mode = NULL;
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100518 char *line;
519
520 if (p->found != 0)
521 return create_err_response(NULL, 510, "CRCX", p->trans);
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +0100522
Holger Hans Peter Freyther3488c3d2011-07-20 20:44:54 +0200523 /* parse CallID C: and LocalParameters L: */
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100524 for_each_line(line, p->save) {
Harald Welteae199722012-01-27 12:31:36 +0100525 switch (line[0]) {
526 case 'L':
527 local_options = (const char *) line + 3;
528 break;
529 case 'C':
530 callid = (const char *) line + 3;
531 break;
532 case 'M':
533 mode = (const char *) line + 3;
534 break;
535 default:
536 LOGP(DMGCP, LOGL_NOTICE, "Unhandled option: '%c'/%d on 0x%x\n",
537 *line, *line, ENDPOINT_NUMBER(endp));
538 break;
539 }
Holger Hans Peter Freyther3488c3d2011-07-20 20:44:54 +0200540 }
Harald Welteae199722012-01-27 12:31:36 +0100541
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100542 tcfg = p->endp->tcfg;
Holger Hans Peter Freyther3488c3d2011-07-20 20:44:54 +0200543
544 /* Check required data */
545 if (!callid || !mode) {
546 LOGP(DMGCP, LOGL_ERROR, "Missing callid and mode in CRCX on 0x%x\n",
547 ENDPOINT_NUMBER(endp));
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100548 return create_err_response(endp, 400, "CRCX", p->trans);
Holger Hans Peter Freyther3488c3d2011-07-20 20:44:54 +0200549 }
550
Holger Hans Peter Freyther39a97e22010-08-06 18:03:11 +0800551 if (endp->allocated) {
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +0100552 if (tcfg->force_realloc) {
Holger Hans Peter Freyther408cc4a2010-04-07 10:51:27 +0200553 LOGP(DMGCP, LOGL_NOTICE, "Endpoint 0x%x already allocated. Forcing realloc.\n",
554 ENDPOINT_NUMBER(endp));
Holger Hans Peter Freyther32d4e502010-04-24 21:02:48 +0800555 mgcp_free_endp(endp);
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100556 if (p->cfg->realloc_cb)
557 p->cfg->realloc_cb(tcfg, ENDPOINT_NUMBER(endp));
Holger Hans Peter Freyther408cc4a2010-04-07 10:51:27 +0200558 } else {
559 LOGP(DMGCP, LOGL_ERROR, "Endpoint is already used. 0x%x\n",
560 ENDPOINT_NUMBER(endp));
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100561 return create_err_response(endp, 400, "CRCX", p->trans);
Holger Hans Peter Freyther408cc4a2010-04-07 10:51:27 +0200562 }
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100563 }
564
Holger Hans Peter Freyther3488c3d2011-07-20 20:44:54 +0200565 /* copy some parameters */
566 endp->callid = talloc_strdup(tcfg->endpoints, callid);
567
568 if (local_options)
569 endp->local_options = talloc_strdup(tcfg->endpoints, local_options);
570
571 if (parse_conn_mode(mode, &endp->conn_mode) != 0) {
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100572 error_code = 517;
573 goto error2;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100574 }
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100575
576 /* initialize */
Holger Hans Peter Freythera17d7012010-08-05 01:34:51 +0800577 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 +0100578
579 /* set to zero until we get the info */
Holger Hans Peter Freythera17d7012010-08-05 01:34:51 +0800580 memset(&endp->net_end.addr, 0, sizeof(endp->net_end.addr));
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100581
582 /* bind to the port now */
Holger Hans Peter Freytherf138f912010-08-05 08:08:17 +0800583 if (allocate_ports(endp) != 0)
584 goto error2;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100585
586 /* assign a local call identifier or fail */
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100587 endp->ci = generate_call_id(p->cfg);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100588 if (endp->ci == CI_UNUSED)
589 goto error2;
590
Holger Hans Peter Freyther39a97e22010-08-06 18:03:11 +0800591 endp->allocated = 1;
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +0100592 endp->bts_end.payload_type = tcfg->audio_payload;
Holger Hans Peter Freyther5ea1bc72012-09-03 00:07:39 +0200593 endp->bts_end.fmtp_extra = talloc_strdup(tcfg->endpoints,
594 tcfg->audio_fmtp_extra);
Holger Hans Peter Freytheref6bb252010-02-26 13:41:22 +0100595
Holger Hans Peter Freytherfe86d3c2010-02-26 13:37:05 +0100596 /* policy CB */
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100597 if (p->cfg->policy_cb) {
598 int rc;
599 rc = p->cfg->policy_cb(tcfg, ENDPOINT_NUMBER(endp),
600 MGCP_ENDP_CRCX, p->trans);
601 switch (rc) {
Holger Hans Peter Freytherfe86d3c2010-02-26 13:37:05 +0100602 case MGCP_POLICY_REJECT:
603 LOGP(DMGCP, LOGL_NOTICE, "CRCX rejected by policy on 0x%x\n",
604 ENDPOINT_NUMBER(endp));
605 mgcp_free_endp(endp);
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100606 return create_err_response(endp, 400, "CRCX", p->trans);
Holger Hans Peter Freytherfe86d3c2010-02-26 13:37:05 +0100607 break;
608 case MGCP_POLICY_DEFER:
609 /* stop processing */
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +0800610 create_transcoder(endp);
Holger Hans Peter Freytherfe86d3c2010-02-26 13:37:05 +0100611 return NULL;
612 break;
613 case MGCP_POLICY_CONT:
614 /* just continue */
615 break;
616 }
617 }
618
Holger Hans Peter Freythere378cb12010-08-06 20:22:23 +0800619 LOGP(DMGCP, LOGL_DEBUG, "Creating endpoint on: 0x%x CI: %u port: %u/%u\n",
Holger Hans Peter Freyther58ff2192010-08-05 03:08:35 +0800620 ENDPOINT_NUMBER(endp), endp->ci,
621 endp->net_end.local_port, endp->bts_end.local_port);
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100622 if (p->cfg->change_cb)
623 p->cfg->change_cb(tcfg, ENDPOINT_NUMBER(endp), MGCP_ENDP_CRCX);
Holger Hans Peter Freyther77f7afe2010-02-03 09:54:43 +0100624
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +0800625 create_transcoder(endp);
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100626 return create_response_with_sdp(endp, "CRCX", p->trans);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100627error2:
Holger Hans Peter Freyther414bf402010-08-06 07:05:13 +0800628 mgcp_free_endp(endp);
Holger Hans Peter Freyther2ada71d2010-02-03 09:13:10 +0100629 LOGP(DMGCP, LOGL_NOTICE, "Resource error on 0x%x\n", ENDPOINT_NUMBER(endp));
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100630 return create_err_response(endp, error_code, "CRCX", p->trans);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100631}
632
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100633static struct msgb *handle_modify_con(struct mgcp_parse_data *p)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100634{
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100635 struct mgcp_endpoint *endp = p->endp;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100636 int error_code = 500;
Holger Hans Peter Freythere3d16bb2010-04-22 11:58:13 +0800637 int silent = 0;
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100638 char *line;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100639
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100640 if (p->found != 0)
641 return create_err_response(NULL, 510, "MDCX", p->trans);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100642
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100643 if (endp->ci == CI_UNUSED) {
644 LOGP(DMGCP, LOGL_ERROR, "Endpoint is not "
645 "holding a connection. 0x%x\n", ENDPOINT_NUMBER(endp));
646 return create_err_response(endp, 400, "MDCX", p->trans);
647 }
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100648
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100649 for_each_line(line, p->save) {
Harald Welteae199722012-01-27 12:31:36 +0100650 switch (line[0]) {
651 case 'C': {
652 if (verify_call_id(endp, line + 3) != 0)
653 goto error3;
654 break;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100655 }
Harald Welteae199722012-01-27 12:31:36 +0100656 case 'I': {
657 if (verify_ci(endp, line + 3) != 0)
658 goto error3;
659 break;
660 }
661 case 'L':
662 /* skip */
663 break;
664 case 'M':
665 if (parse_conn_mode(line + 3, &endp->conn_mode) != 0) {
666 error_code = 517;
667 goto error3;
668 }
669 endp->orig_mode = endp->conn_mode;
670 break;
671 case 'Z':
672 silent = strcmp("noanswer", line + 3) == 0;
673 break;
674 case '\0':
675 /* SDP file begins */
676 break;
677 case 'a':
678 case 'o':
679 case 's':
680 case 't':
681 case 'v':
682 /* skip these SDP attributes */
683 break;
684 case 'm': {
685 int port;
686 int payload;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100687
Harald Welteae199722012-01-27 12:31:36 +0100688 if (sscanf(line, "m=audio %d RTP/AVP %d", &port, &payload) == 2) {
689 endp->net_end.rtp_port = htons(port);
690 endp->net_end.rtcp_port = htons(port + 1);
691 endp->net_end.payload_type = payload;
692 }
693 break;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100694 }
Harald Welteae199722012-01-27 12:31:36 +0100695 case 'c': {
696 char ipv4[16];
697
698 if (sscanf(line, "c=IN IP4 %15s", ipv4) == 1) {
699 inet_aton(ipv4, &endp->net_end.addr);
700 }
701 break;
702 }
703 default:
704 LOGP(DMGCP, LOGL_NOTICE, "Unhandled option: '%c'/%d on 0x%x\n",
705 line[0], line[0], ENDPOINT_NUMBER(endp));
706 break;
707 }
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100708 }
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100709
Holger Hans Peter Freytherfe86d3c2010-02-26 13:37:05 +0100710 /* policy CB */
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100711 if (p->cfg->policy_cb) {
712 int rc;
713 rc = p->cfg->policy_cb(endp->tcfg, ENDPOINT_NUMBER(endp),
714 MGCP_ENDP_MDCX, p->trans);
715 switch (rc) {
Holger Hans Peter Freytherfe86d3c2010-02-26 13:37:05 +0100716 case MGCP_POLICY_REJECT:
717 LOGP(DMGCP, LOGL_NOTICE, "MDCX rejected by policy on 0x%x\n",
718 ENDPOINT_NUMBER(endp));
Holger Hans Peter Freythere3d16bb2010-04-22 11:58:13 +0800719 if (silent)
720 goto out_silent;
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100721 return create_err_response(endp, 400, "MDCX", p->trans);
Holger Hans Peter Freytherfe86d3c2010-02-26 13:37:05 +0100722 break;
723 case MGCP_POLICY_DEFER:
724 /* stop processing */
725 return NULL;
726 break;
727 case MGCP_POLICY_CONT:
728 /* just continue */
729 break;
730 }
731 }
732
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100733 /* modify */
Holger Hans Peter Freythere378cb12010-08-06 20:22:23 +0800734 LOGP(DMGCP, LOGL_DEBUG, "Modified endpoint on: 0x%x Server: %s:%u\n",
Holger Hans Peter Freythera17d7012010-08-05 01:34:51 +0800735 ENDPOINT_NUMBER(endp), inet_ntoa(endp->net_end.addr), ntohs(endp->net_end.rtp_port));
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100736 if (p->cfg->change_cb)
737 p->cfg->change_cb(endp->tcfg, ENDPOINT_NUMBER(endp), MGCP_ENDP_MDCX);
Holger Hans Peter Freythere3d16bb2010-04-22 11:58:13 +0800738 if (silent)
739 goto out_silent;
740
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100741 return create_response_with_sdp(endp, "MDCX", p->trans);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100742
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100743error3:
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100744 return create_err_response(endp, error_code, "MDCX", p->trans);
Holger Hans Peter Freythere3d16bb2010-04-22 11:58:13 +0800745
746
747out_silent:
748 return NULL;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100749}
750
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100751static struct msgb *handle_delete_con(struct mgcp_parse_data *p)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100752{
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100753 struct mgcp_endpoint *endp = p->endp;
Holger Hans Peter Freyther9e9392d2010-08-08 16:24:48 +0800754 int error_code = 400;
Holger Hans Peter Freythere3d16bb2010-04-22 11:58:13 +0800755 int silent = 0;
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100756 char *line;
Holger Hans Peter Freyther0bf15a82012-09-14 17:18:12 +0200757 char stats[1048];
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100758
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100759 if (p->found != 0)
760 return create_err_response(NULL, error_code, "DLCX", p->trans);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100761
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100762 if (!p->endp->allocated) {
763 LOGP(DMGCP, LOGL_ERROR, "Endpoint is not used. 0x%x\n",
764 ENDPOINT_NUMBER(endp));
765 return create_err_response(endp, 400, "DLCX", p->trans);
766 }
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100767
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100768 for_each_line(line, p->save) {
Harald Welteae199722012-01-27 12:31:36 +0100769 switch (line[0]) {
770 case 'C':
771 if (verify_call_id(endp, line + 3) != 0)
772 goto error3;
773 break;
774 case 'I':
775 if (verify_ci(endp, line + 3) != 0)
776 goto error3;
777 break;
778 case 'Z':
779 silent = strcmp("noanswer", line + 3) == 0;
780 break;
781 default:
782 LOGP(DMGCP, LOGL_NOTICE, "Unhandled option: '%c'/%d on 0x%x\n",
783 line[0], line[0], ENDPOINT_NUMBER(endp));
784 break;
785 }
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100786 }
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100787
Holger Hans Peter Freytherfe86d3c2010-02-26 13:37:05 +0100788 /* policy CB */
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100789 if (p->cfg->policy_cb) {
790 int rc;
791 rc = p->cfg->policy_cb(endp->tcfg, ENDPOINT_NUMBER(endp),
792 MGCP_ENDP_DLCX, p->trans);
793 switch (rc) {
Holger Hans Peter Freytherfe86d3c2010-02-26 13:37:05 +0100794 case MGCP_POLICY_REJECT:
795 LOGP(DMGCP, LOGL_NOTICE, "DLCX rejected by policy on 0x%x\n",
796 ENDPOINT_NUMBER(endp));
Holger Hans Peter Freythere3d16bb2010-04-22 11:58:13 +0800797 if (silent)
798 goto out_silent;
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100799 return create_err_response(endp, 400, "DLCX", p->trans);
Holger Hans Peter Freytherfe86d3c2010-02-26 13:37:05 +0100800 break;
801 case MGCP_POLICY_DEFER:
802 /* stop processing */
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +0800803 delete_transcoder(endp);
Holger Hans Peter Freytherfe86d3c2010-02-26 13:37:05 +0100804 return NULL;
805 break;
806 case MGCP_POLICY_CONT:
807 /* just continue */
808 break;
809 }
810 }
811
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100812 /* free the connection */
Holger Hans Peter Freythere378cb12010-08-06 20:22:23 +0800813 LOGP(DMGCP, LOGL_DEBUG, "Deleted endpoint on: 0x%x Server: %s:%u\n",
Holger Hans Peter Freythera17d7012010-08-05 01:34:51 +0800814 ENDPOINT_NUMBER(endp), inet_ntoa(endp->net_end.addr), ntohs(endp->net_end.rtp_port));
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +0800815
Holger Hans Peter Freyther0bf15a82012-09-14 17:18:12 +0200816 /* save the statistics of the current call */
817 mgcp_format_stats(endp, stats, sizeof(stats));
818
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +0800819 delete_transcoder(endp);
Holger Hans Peter Freyther154b9552010-02-26 13:27:51 +0100820 mgcp_free_endp(endp);
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100821 if (p->cfg->change_cb)
822 p->cfg->change_cb(endp->tcfg, ENDPOINT_NUMBER(endp), MGCP_ENDP_DLCX);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100823
Holger Hans Peter Freythere3d16bb2010-04-22 11:58:13 +0800824 if (silent)
825 goto out_silent;
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100826 return create_ok_resp_with_param(endp, 250, "DLCX", p->trans, stats);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100827
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100828error3:
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100829 return create_err_response(endp, error_code, "DLCX", p->trans);
Holger Hans Peter Freythere3d16bb2010-04-22 11:58:13 +0800830
831out_silent:
832 return NULL;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100833}
834
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100835static struct msgb *handle_rsip(struct mgcp_parse_data *p)
Holger Hans Peter Freyther9bdcc9c2010-03-31 06:39:35 +0200836{
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100837 if (p->found != 0) {
Holger Hans Peter Freyther74db7742011-06-10 00:04:55 +0200838 LOGP(DMGCP, LOGL_ERROR, "Failed to find the endpoint.\n");
839 return NULL;
840 }
841
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100842 if (p->cfg->reset_cb)
843 p->cfg->reset_cb(p->endp->tcfg);
Holger Hans Peter Freyther9bdcc9c2010-03-31 06:39:35 +0200844 return NULL;
845}
846
Holger Hans Peter Freyther8d0be252012-11-29 12:54:22 +0100847static char extract_tone(const char *line)
848{
849 const char *str = strstr(line, "D/");
850 if (!str)
851 return CHAR_MAX;
852
853 return str[2];
854}
855
Holger Hans Peter Freyther6e94d6d2011-01-25 23:33:54 +0100856/*
857 * This can request like DTMF detection and forward, fax detection... it
858 * can also request when the notification should be send and such. We don't
859 * do this right now.
860 */
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100861static struct msgb *handle_noti_req(struct mgcp_parse_data *p)
Holger Hans Peter Freyther6e94d6d2011-01-25 23:33:54 +0100862{
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100863 int res = 0;
864 char *line;
Holger Hans Peter Freyther9f3835b2013-05-21 17:04:35 +0200865 char tone = CHAR_MAX;
Holger Hans Peter Freyther6e94d6d2011-01-25 23:33:54 +0100866
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100867 if (p->found != 0)
868 return create_err_response(NULL, 400, "RQNT", p->trans);
Holger Hans Peter Freyther6e94d6d2011-01-25 23:33:54 +0100869
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100870 for_each_line(line, p->save) {
Holger Hans Peter Freyther8d0be252012-11-29 12:54:22 +0100871 switch (line[0]) {
872 case 'S':
873 tone = extract_tone(line);
874 break;
875 }
Holger Hans Peter Freyther6e94d6d2011-01-25 23:33:54 +0100876 }
Holger Hans Peter Freyther8d0be252012-11-29 12:54:22 +0100877
878 /* we didn't see a signal request with a tone */
879 if (tone == CHAR_MAX)
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100880 return create_ok_response(p->endp, 200, "RQNT", p->trans);
Holger Hans Peter Freyther8d0be252012-11-29 12:54:22 +0100881
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100882 if (p->cfg->rqnt_cb)
883 res = p->cfg->rqnt_cb(p->endp, tone);
Holger Hans Peter Freyther8d0be252012-11-29 12:54:22 +0100884
885 return res == 0 ?
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100886 create_ok_response(p->endp, 200, "RQNT", p->trans) :
887 create_err_response(p->endp, res, "RQNT", p->trans);
Holger Hans Peter Freyther6e94d6d2011-01-25 23:33:54 +0100888}
889
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100890struct mgcp_config *mgcp_config_alloc(void)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100891{
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100892 struct mgcp_config *cfg;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100893
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100894 cfg = talloc_zero(NULL, struct mgcp_config);
895 if (!cfg) {
896 LOGP(DMGCP, LOGL_FATAL, "Failed to allocate config.\n");
897 return NULL;
898 }
899
900 cfg->source_port = 2427;
901 cfg->source_addr = talloc_strdup(cfg, "0.0.0.0");
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +0100902
Holger Hans Peter Freytherb98ba722010-09-19 04:21:39 +0800903 cfg->transcoder_remote_base = 4000;
Holger Hans Peter Freyther15e73892010-08-05 07:10:56 +0800904
905 cfg->bts_ports.base_port = RTP_PORT_DEFAULT;
906 cfg->net_ports.base_port = RTP_PORT_NET_DEFAULT;
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100907
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +0100908 /* default trunk handling */
909 cfg->trunk.cfg = cfg;
910 cfg->trunk.trunk_nr = 0;
911 cfg->trunk.trunk_type = MGCP_TRUNK_VIRTUAL;
912 cfg->trunk.audio_name = talloc_strdup(cfg, "AMR/8000");
913 cfg->trunk.audio_payload = 126;
Holger Hans Peter Freythera8090d52012-05-11 13:00:45 +0200914 cfg->trunk.omit_rtcp = 0;
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +0100915
Holger Hans Peter Freyther0e939fe2011-02-28 12:11:02 +0100916 INIT_LLIST_HEAD(&cfg->trunks);
917
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100918 return cfg;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100919}
920
Holger Hans Peter Freyther0e939fe2011-02-28 12:11:02 +0100921struct mgcp_trunk_config *mgcp_trunk_alloc(struct mgcp_config *cfg, int nr)
922{
923 struct mgcp_trunk_config *trunk;
924
925 trunk = talloc_zero(cfg, struct mgcp_trunk_config);
926 if (!trunk) {
927 LOGP(DMGCP, LOGL_ERROR, "Failed to allocate.\n");
928 return NULL;
929 }
930
931 trunk->cfg = cfg;
932 trunk->trunk_type = MGCP_TRUNK_E1;
933 trunk->trunk_nr = nr;
934 trunk->audio_name = talloc_strdup(cfg, "AMR/8000");
935 trunk->audio_payload = 126;
936 trunk->number_endpoints = 33;
Holger Hans Peter Freythera8090d52012-05-11 13:00:45 +0200937 trunk->omit_rtcp = 0;
Holger Hans Peter Freyther0e939fe2011-02-28 12:11:02 +0100938 llist_add_tail(&trunk->entry, &cfg->trunks);
939 return trunk;
940}
941
942struct mgcp_trunk_config *mgcp_trunk_num(struct mgcp_config *cfg, int index)
943{
944 struct mgcp_trunk_config *trunk;
945
946 llist_for_each_entry(trunk, &cfg->trunks, entry)
947 if (trunk->trunk_nr == index)
948 return trunk;
949
950 return NULL;
951}
952
Holger Hans Peter Freythera17d7012010-08-05 01:34:51 +0800953static void mgcp_rtp_end_reset(struct mgcp_rtp_end *end)
954{
Holger Hans Peter Freythere97155a2010-11-02 19:06:13 +0100955 if (end->local_alloc == PORT_ALLOC_DYNAMIC) {
Holger Hans Peter Freytherf138f912010-08-05 08:08:17 +0800956 mgcp_free_rtp_port(end);
Holger Hans Peter Freythere97155a2010-11-02 19:06:13 +0100957 end->local_port = 0;
958 }
Holger Hans Peter Freytherf138f912010-08-05 08:08:17 +0800959
Holger Hans Peter Freytherc4921272010-08-05 03:37:22 +0800960 end->packets = 0;
Holger Hans Peter Freyther952f7522012-09-12 11:38:37 +0200961 end->octets = 0;
Holger Hans Peter Freytherc4921272010-08-05 03:37:22 +0800962 memset(&end->addr, 0, sizeof(end->addr));
Holger Hans Peter Freythere97155a2010-11-02 19:06:13 +0100963 end->rtp_port = end->rtcp_port = 0;
Holger Hans Peter Freythera17d7012010-08-05 01:34:51 +0800964 end->payload_type = -1;
Holger Hans Peter Freytherf138f912010-08-05 08:08:17 +0800965 end->local_alloc = -1;
Holger Hans Peter Freyther5ea1bc72012-09-03 00:07:39 +0200966 talloc_free(end->fmtp_extra);
967 end->fmtp_extra = NULL;
Holger Hans Peter Freythera17d7012010-08-05 01:34:51 +0800968}
969
Holger Hans Peter Freytherc4921272010-08-05 03:37:22 +0800970static void mgcp_rtp_end_init(struct mgcp_rtp_end *end)
971{
972 mgcp_rtp_end_reset(end);
973 end->rtp.fd = -1;
974 end->rtcp.fd = -1;
975}
976
Holger Hans Peter Freyther1f0c5b42011-02-28 14:37:03 +0100977int mgcp_endpoints_allocate(struct mgcp_trunk_config *tcfg)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100978{
979 int i;
980
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100981 /* Initialize all endpoints */
Holger Hans Peter Freyther1f0c5b42011-02-28 14:37:03 +0100982 tcfg->endpoints = _talloc_zero_array(tcfg->cfg,
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100983 sizeof(struct mgcp_endpoint),
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +0100984 tcfg->number_endpoints, "endpoints");
985 if (!tcfg->endpoints)
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100986 return -1;
987
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +0100988 for (i = 0; i < tcfg->number_endpoints; ++i) {
989 tcfg->endpoints[i].ci = CI_UNUSED;
Holger Hans Peter Freyther1f0c5b42011-02-28 14:37:03 +0100990 tcfg->endpoints[i].cfg = tcfg->cfg;
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +0100991 tcfg->endpoints[i].tcfg = tcfg;
992 mgcp_rtp_end_init(&tcfg->endpoints[i].net_end);
993 mgcp_rtp_end_init(&tcfg->endpoints[i].bts_end);
994 mgcp_rtp_end_init(&tcfg->endpoints[i].trans_net);
995 mgcp_rtp_end_init(&tcfg->endpoints[i].trans_bts);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100996 }
997
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100998 return 0;
999}
Holger Hans Peter Freyther154b9552010-02-26 13:27:51 +01001000
1001void mgcp_free_endp(struct mgcp_endpoint *endp)
1002{
Holger Hans Peter Freytherc77efdf2010-03-31 12:31:09 +02001003 LOGP(DMGCP, LOGL_DEBUG, "Deleting endpoint on: 0x%x\n", ENDPOINT_NUMBER(endp));
Holger Hans Peter Freyther89976e82010-08-03 15:01:43 +00001004 endp->ci = CI_UNUSED;
Holger Hans Peter Freyther39a97e22010-08-06 18:03:11 +08001005 endp->allocated = 0;
Holger Hans Peter Freyther154b9552010-02-26 13:27:51 +01001006
Holger Hans Peter Freyther01d315f2012-12-07 11:52:16 +01001007 talloc_free(endp->callid);
1008 endp->callid = NULL;
Holger Hans Peter Freyther154b9552010-02-26 13:27:51 +01001009
Holger Hans Peter Freyther01d315f2012-12-07 11:52:16 +01001010 talloc_free(endp->local_options);
1011 endp->local_options = NULL;
Holger Hans Peter Freyther154b9552010-02-26 13:27:51 +01001012
Holger Hans Peter Freythera17d7012010-08-05 01:34:51 +08001013 mgcp_rtp_end_reset(&endp->bts_end);
1014 mgcp_rtp_end_reset(&endp->net_end);
Holger Hans Peter Freyther21262332010-11-01 20:53:31 +01001015 mgcp_rtp_end_reset(&endp->trans_net);
Holger Hans Peter Freytherbd7b3c52010-11-01 21:04:54 +01001016 mgcp_rtp_end_reset(&endp->trans_bts);
Holger Hans Peter Freytherb54048f2010-11-01 19:57:50 +01001017 endp->is_transcoded = 0;
Holger Hans Peter Freyther380b8712010-07-29 02:38:39 +08001018
Holger Hans Peter Freyther31868922010-08-03 11:59:04 +00001019 memset(&endp->net_state, 0, sizeof(endp->net_state));
1020 memset(&endp->bts_state, 0, sizeof(endp->bts_state));
Holger Hans Peter Freytherc597a4e2010-08-03 02:57:02 +08001021
1022 endp->conn_mode = endp->orig_mode = MGCP_CONN_NONE;
Holger Hans Peter Freyther6357a8e2010-08-05 12:07:00 +00001023 endp->allow_patch = 0;
Holger Hans Peter Freyther260d6ed2010-08-06 01:12:21 +08001024
1025 memset(&endp->taps, 0, sizeof(endp->taps));
Holger Hans Peter Freyther154b9552010-02-26 13:27:51 +01001026}
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +08001027
Holger Hans Peter Freyther557b1ab2010-09-19 04:39:55 +08001028static int send_trans(struct mgcp_config *cfg, const char *buf, int len)
1029{
1030 struct sockaddr_in addr;
1031
1032 memset(&addr, 0, sizeof(addr));
1033 addr.sin_family = AF_INET;
1034 addr.sin_addr = cfg->transcoder_in;
1035 addr.sin_port = htons(2427);
1036 return sendto(cfg->gw_fd.bfd.fd, buf, len, 0,
1037 (struct sockaddr *) &addr, sizeof(addr));
1038}
1039
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +08001040static void send_msg(struct mgcp_endpoint *endp, int endpoint, int port,
1041 const char *msg, const char *mode)
1042{
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +08001043 char buf[2096];
1044 int len;
1045
1046 /* hardcoded to AMR right now, we do not know the real type at this point */
1047 len = snprintf(buf, sizeof(buf),
1048 "%s 42 %x@mgw MGCP 1.0\r\n"
1049 "C: 4256\r\n"
1050 "M: %s\r\n"
1051 "\r\n"
1052 "c=IN IP4 %s\r\n"
1053 "m=audio %d RTP/AVP %d\r\n"
1054 "a=rtpmap:%d %s\r\n",
1055 msg, endpoint, mode, endp->cfg->source_addr,
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +01001056 port, endp->tcfg->audio_payload,
1057 endp->tcfg->audio_payload, endp->tcfg->audio_name);
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +08001058
1059 if (len < 0)
1060 return;
1061
1062 buf[sizeof(buf) - 1] = '\0';
1063
Holger Hans Peter Freyther557b1ab2010-09-19 04:39:55 +08001064 send_trans(endp->cfg, buf, len);
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +08001065}
1066
1067static void send_dlcx(struct mgcp_endpoint *endp, int endpoint)
1068{
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +08001069 char buf[2096];
1070 int len;
1071
1072 len = snprintf(buf, sizeof(buf),
1073 "DLCX 43 %x@mgw MGCP 1.0\r\n"
1074 "C: 4256\r\n"
1075 , endpoint);
1076
1077 if (len < 0)
1078 return;
1079
1080 buf[sizeof(buf) - 1] = '\0';
1081
Holger Hans Peter Freyther557b1ab2010-09-19 04:39:55 +08001082 send_trans(endp->cfg, buf, len);
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +08001083}
1084
Harald Welte6a857052012-01-27 00:41:39 +01001085static int send_agent(struct mgcp_config *cfg, const char *buf, int len)
1086{
1087 return write(cfg->gw_fd.bfd.fd, buf, len);
1088}
1089
1090int mgcp_send_reset_all(struct mgcp_config *cfg)
1091{
1092 static const char mgcp_reset[] = {
1093 "RSIP 1 *@mgw MGCP 1.0\r\n"
1094 };
1095
1096 return send_agent(cfg, mgcp_reset, sizeof mgcp_reset -1);
1097}
1098
1099int mgcp_send_reset_ep(struct mgcp_endpoint *endp, int endpoint)
1100{
1101 char buf[128];
1102 int len;
1103
1104 len = snprintf(buf, sizeof(buf),
1105 "RSIP 39 %x@mgw MGCP 1.0\r\n"
1106 , endpoint);
1107 if (len < 0)
1108 return len;
1109
1110 buf[sizeof(buf) - 1] = '\0';
1111
1112 return send_agent(endp->cfg, buf, len);
1113}
1114
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +08001115static void create_transcoder(struct mgcp_endpoint *endp)
1116{
1117 int port;
1118 int in_endp = ENDPOINT_NUMBER(endp);
Holger Hans Peter Freytherbd7b3c52010-11-01 21:04:54 +01001119 int out_endp = endp_back_channel(in_endp);
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +08001120
Holger Hans Peter Freytherb54048f2010-11-01 19:57:50 +01001121 if (!endp->is_transcoded)
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +08001122 return;
1123
Holger Hans Peter Freyther8b19dee2010-11-01 22:38:25 +01001124 send_msg(endp, in_endp, endp->trans_bts.local_port, "CRCX", "sendrecv");
1125 send_msg(endp, in_endp, endp->trans_bts.local_port, "MDCX", "sendrecv");
Holger Hans Peter Freyther21262332010-11-01 20:53:31 +01001126 send_msg(endp, out_endp, endp->trans_net.local_port, "CRCX", "sendrecv");
1127 send_msg(endp, out_endp, endp->trans_net.local_port, "MDCX", "sendrecv");
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +08001128
Holger Hans Peter Freytherbd7b3c52010-11-01 21:04:54 +01001129 port = rtp_calculate_port(in_endp, endp->cfg->transcoder_remote_base);
1130 endp->trans_bts.rtp_port = htons(port);
1131 endp->trans_bts.rtcp_port = htons(port + 1);
1132
Holger Hans Peter Freytherb98ba722010-09-19 04:21:39 +08001133 port = rtp_calculate_port(out_endp, endp->cfg->transcoder_remote_base);
Holger Hans Peter Freyther21262332010-11-01 20:53:31 +01001134 endp->trans_net.rtp_port = htons(port);
1135 endp->trans_net.rtcp_port = htons(port + 1);
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +08001136}
1137
1138static void delete_transcoder(struct mgcp_endpoint *endp)
1139{
1140 int in_endp = ENDPOINT_NUMBER(endp);
Holger Hans Peter Freytherbd7b3c52010-11-01 21:04:54 +01001141 int out_endp = endp_back_channel(in_endp);
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +08001142
Holger Hans Peter Freytherb54048f2010-11-01 19:57:50 +01001143 if (!endp->is_transcoded)
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +08001144 return;
1145
1146 send_dlcx(endp, in_endp);
1147 send_dlcx(endp, out_endp);
1148}
Holger Hans Peter Freytherf2eedff2010-09-19 04:36:07 +08001149
1150int mgcp_reset_transcoder(struct mgcp_config *cfg)
1151{
Holger Hans Peter Freytherf2eedff2010-09-19 04:36:07 +08001152 if (!cfg->transcoder_ip)
Holger Hans Peter Freythercf1c8772010-09-24 04:41:28 +08001153 return 0;
Holger Hans Peter Freytherf2eedff2010-09-19 04:36:07 +08001154
1155 static const char mgcp_reset[] = {
1156 "RSIP 1 13@mgw MGCP 1.0\r\n"
1157 };
1158
Holger Hans Peter Freyther557b1ab2010-09-19 04:39:55 +08001159 return send_trans(cfg, mgcp_reset, sizeof mgcp_reset -1);
Holger Hans Peter Freytherf2eedff2010-09-19 04:36:07 +08001160}
Holger Hans Peter Freyther0bf15a82012-09-14 17:18:12 +02001161
1162void mgcp_format_stats(struct mgcp_endpoint *endp, char *msg, size_t size)
1163{
Holger Hans Peter Freythercb306a62012-10-24 21:22:47 +02001164 uint32_t expected, jitter;
Holger Hans Peter Freyther38e02c52012-10-22 18:09:35 +02001165 int ploss;
1166 mgcp_state_calc_loss(&endp->net_state, &endp->net_end,
1167 &expected, &ploss);
Holger Hans Peter Freythercb306a62012-10-24 21:22:47 +02001168 jitter = mgcp_state_calc_jitter(&endp->net_state);
Holger Hans Peter Freyther38e02c52012-10-22 18:09:35 +02001169
Holger Hans Peter Freyther462b7d72012-10-24 21:53:40 +02001170 snprintf(msg, size, "\r\nP: PS=%u, OS=%u, PR=%u, OR=%u, PL=%d, JI=%u",
Holger Hans Peter Freyther0bf15a82012-09-14 17:18:12 +02001171 endp->bts_end.packets, endp->bts_end.octets,
Holger Hans Peter Freyther38e02c52012-10-22 18:09:35 +02001172 endp->net_end.packets, endp->net_end.octets,
Holger Hans Peter Freythercb306a62012-10-24 21:22:47 +02001173 ploss, jitter);
Holger Hans Peter Freyther0bf15a82012-09-14 17:18:12 +02001174 msg[size - 1] = '\0';
1175}
Holger Hans Peter Freyther462b7d72012-10-24 21:53:40 +02001176
1177int mgcp_parse_stats(struct msgb *msg, uint32_t *ps, uint32_t *os,
1178 uint32_t *pr, uint32_t *_or, int *loss, uint32_t *jitter)
1179{
1180 char *line, *save;
1181 int rc;
1182
1183 /* initialize with bad values */
1184 *ps = *os = *pr = *_or = *jitter = UINT_MAX;
1185 *loss = INT_MAX;
1186
1187
1188 line = strtok_r((char *) msg->l2h, "\r\n", &save);
1189 if (!line)
1190 return -1;
1191
1192 /* this can only parse the message that is created above... */
1193 for_each_line(line, save) {
1194 switch (line[0]) {
1195 case 'P':
1196 rc = sscanf(line, "P: PS=%u, OS=%u, PR=%u, OR=%u, PL=%d, JI=%u",
1197 ps, os, pr, _or, loss, jitter);
1198 return rc == 6 ? 0 : -1;
1199 }
1200 }
1201
1202 return -1;
1203}