blob: d4a23a7d7b1e838569a8691a5b8be85e3d2ed826 [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 Erlbeck2bee7f92013-11-29 13:43:44 +010043#define for_each_line(line, save) \
44 for (line = strline_r(NULL, &save); line;\
45 line = strline_r(NULL, &save))
46
47char *strline_r(char *str, char **saveptr)
48{
49 char *result;
50
51 if (str)
52 *saveptr = str;
53
54 result = *saveptr;
55
56 if (*saveptr != NULL) {
57 *saveptr = strpbrk(*saveptr, "\r\n");
58
59 if (*saveptr != NULL) {
60 char *eos = *saveptr;
61
62 if ((*saveptr)[0] == '\r' && (*saveptr)[1] == '\n')
63 (*saveptr)++;
64 (*saveptr)++;
65 if ((*saveptr)[0] == '\0')
66 *saveptr = NULL;
67
68 *eos = '\0';
69 }
70 }
71
72 return result;
73}
74
Jacob Erlbeck72c30902013-11-25 15:23:35 +010075/* Assume audio frame length of 20ms */
76#define DEFAULT_RTP_AUDIO_FRAME_DUR_NUM 20
77#define DEFAULT_RTP_AUDIO_FRAME_DUR_DEN 1000
78#define DEFAULT_RTP_AUDIO_FRAMES_PER_PACKET 1
79#define DEFAULT_RTP_AUDIO_DEFAULT_RATE 8000
80
Holger Hans Peter Freytherf138f912010-08-05 08:08:17 +080081static void mgcp_rtp_end_reset(struct mgcp_rtp_end *end);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +010082
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +010083struct mgcp_parse_data {
84 struct mgcp_config *cfg;
85 struct mgcp_endpoint *endp;
86 char *trans;
87 char *save;
88 int found;
89};
90
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +010091struct mgcp_request {
92 char *name;
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +010093 struct msgb *(*handle_request) (struct mgcp_parse_data *data);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +010094 char *debug_name;
95};
96
97#define MGCP_REQUEST(NAME, REQ, DEBUG_NAME) \
98 { .name = NAME, .handle_request = REQ, .debug_name = DEBUG_NAME },
99
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100100static struct msgb *handle_audit_endpoint(struct mgcp_parse_data *data);
101static struct msgb *handle_create_con(struct mgcp_parse_data *data);
102static struct msgb *handle_delete_con(struct mgcp_parse_data *data);
103static struct msgb *handle_modify_con(struct mgcp_parse_data *data);
104static struct msgb *handle_rsip(struct mgcp_parse_data *data);
105static struct msgb *handle_noti_req(struct mgcp_parse_data *data);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100106
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +0800107static void create_transcoder(struct mgcp_endpoint *endp);
108static void delete_transcoder(struct mgcp_endpoint *endp);
109
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100110static int mgcp_analyze_header(struct mgcp_parse_data *parse, char *data);
111
Holger Hans Peter Freyther46340132010-08-06 08:26:54 +0800112static uint32_t generate_call_id(struct mgcp_config *cfg)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100113{
114 int i;
115
116 /* use the call id */
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100117 ++cfg->last_call_id;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100118
119 /* handle wrap around */
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100120 if (cfg->last_call_id == CI_UNUSED)
121 ++cfg->last_call_id;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100122
123 /* callstack can only be of size number_of_endpoints */
124 /* verify that the call id is free, e.g. in case of overrun */
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +0100125 for (i = 1; i < cfg->trunk.number_endpoints; ++i)
126 if (cfg->trunk.endpoints[i].ci == cfg->last_call_id)
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100127 return generate_call_id(cfg);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100128
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100129 return cfg->last_call_id;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100130}
131
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100132/*
133 * array of function pointers for handling various
134 * messages. In the future this might be binary sorted
135 * for performance reasons.
136 */
137static const struct mgcp_request mgcp_requests [] = {
138 MGCP_REQUEST("AUEP", handle_audit_endpoint, "AuditEndpoint")
139 MGCP_REQUEST("CRCX", handle_create_con, "CreateConnection")
140 MGCP_REQUEST("DLCX", handle_delete_con, "DeleteConnection")
141 MGCP_REQUEST("MDCX", handle_modify_con, "ModifiyConnection")
Holger Hans Peter Freyther6e94d6d2011-01-25 23:33:54 +0100142 MGCP_REQUEST("RQNT", handle_noti_req, "NotificationRequest")
Holger Hans Peter Freyther9bdcc9c2010-03-31 06:39:35 +0200143
144 /* SPEC extension */
145 MGCP_REQUEST("RSIP", handle_rsip, "ReSetInProgress")
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100146};
147
Holger Hans Peter Freyther62e836c2010-02-03 11:03:45 +0100148static struct msgb *mgcp_msgb_alloc(void)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100149{
Holger Hans Peter Freyther62e836c2010-02-03 11:03:45 +0100150 struct msgb *msg;
151 msg = msgb_alloc_headroom(4096, 128, "MGCP msg");
152 if (!msg)
153 LOGP(DMGCP, LOGL_ERROR, "Failed to msgb for MGCP data.\n");
154
155 return msg;
156}
157
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100158static struct msgb *do_retransmission(const struct mgcp_endpoint *endp)
159{
160 struct msgb *msg = mgcp_msgb_alloc();
161 if (!msg)
162 return NULL;
163
164 msg->l2h = msgb_put(msg, strlen(endp->last_response));
165 memcpy(msg->l2h, endp->last_response, msgb_l2len(msg));
166 return msg;
167}
168
Holger Hans Peter Freythera769dcb2012-12-07 15:14:27 +0100169static struct msgb *create_resp(struct mgcp_endpoint *endp, int code,
170 const char *txt, const char *msg,
Holger Hans Peter Freyther0bf15a82012-09-14 17:18:12 +0200171 const char *trans, const char *param,
172 const char *sdp)
Holger Hans Peter Freyther62e836c2010-02-03 11:03:45 +0100173{
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100174 int len;
Holger Hans Peter Freyther62e836c2010-02-03 11:03:45 +0100175 struct msgb *res;
176
177 res = mgcp_msgb_alloc();
178 if (!res)
179 return NULL;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100180
Holger Hans Peter Freyther0bf15a82012-09-14 17:18:12 +0200181 len = snprintf((char *) res->data, 2048, "%d %s%s%s\r\n%s",
182 code, trans, txt, param ? param : "", sdp ? sdp : "");
183 if (len < 0) {
184 LOGP(DMGCP, LOGL_ERROR, "Failed to sprintf MGCP response.\n");
185 msgb_free(res);
186 return NULL;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100187 }
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100188
Holger Hans Peter Freyther62e836c2010-02-03 11:03:45 +0100189 res->l2h = msgb_put(res, len);
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100190 LOGP(DMGCP, LOGL_DEBUG, "Generated response: code: %d for '%s'\n", code, res->l2h);
191
192 /*
193 * Remember the last transmission per endpoint.
194 */
195 if (endp) {
196 struct mgcp_trunk_config *tcfg = endp->tcfg;
197 talloc_free(endp->last_response);
198 talloc_free(endp->last_trans);
199 endp->last_trans = talloc_strdup(tcfg->endpoints, trans);
200 endp->last_response = talloc_strndup(tcfg->endpoints,
201 (const char *) res->l2h,
202 msgb_l2len(res));
203 }
204
Holger Hans Peter Freyther62e836c2010-02-03 11:03:45 +0100205 return res;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100206}
207
Holger Hans Peter Freythera769dcb2012-12-07 15:14:27 +0100208static struct msgb *create_ok_resp_with_param(struct mgcp_endpoint *endp,
209 int code, const char *msg,
Holger Hans Peter Freyther0bf15a82012-09-14 17:18:12 +0200210 const char *trans, const char *param)
211{
Holger Hans Peter Freythera769dcb2012-12-07 15:14:27 +0100212 return create_resp(endp, code, " OK", msg, trans, param, NULL);
Holger Hans Peter Freyther0bf15a82012-09-14 17:18:12 +0200213}
214
Holger Hans Peter Freythera769dcb2012-12-07 15:14:27 +0100215static struct msgb *create_ok_response(struct mgcp_endpoint *endp,
216 int code, const char *msg, const char *trans)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100217{
Holger Hans Peter Freythera769dcb2012-12-07 15:14:27 +0100218 return create_ok_resp_with_param(endp, code, msg, trans, NULL);
Holger Hans Peter Freyther6adac172011-01-06 16:19:55 +0100219}
220
Holger Hans Peter Freythera769dcb2012-12-07 15:14:27 +0100221static struct msgb *create_err_response(struct mgcp_endpoint *endp,
222 int code, const char *msg, const char *trans)
Holger Hans Peter Freyther6adac172011-01-06 16:19:55 +0100223{
Holger Hans Peter Freythera769dcb2012-12-07 15:14:27 +0100224 return create_resp(endp, code, " FAIL", msg, trans, NULL, NULL);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100225}
226
Holger Hans Peter Freyther8d188ed2010-02-21 01:44:08 +0100227static struct msgb *create_response_with_sdp(struct mgcp_endpoint *endp,
228 const char *msg, const char *trans_id)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100229{
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100230 const char *addr = endp->cfg->local_ip;
Holger Hans Peter Freyther5ea1bc72012-09-03 00:07:39 +0200231 const char *fmtp_extra = endp->bts_end.fmtp_extra;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100232 char sdp_record[4096];
233
234 if (!addr)
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100235 addr = endp->cfg->source_addr;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100236
237 snprintf(sdp_record, sizeof(sdp_record) - 1,
Holger Hans Peter Freyther46340132010-08-06 08:26:54 +0800238 "I: %u\n\n"
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100239 "v=0\r\n"
Holger Hans Peter Freytherc7e49d32011-07-20 20:43:15 +0200240 "o=- %u 23 IN IP4 %s\r\n"
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100241 "c=IN IP4 %s\r\n"
Holger Hans Peter Freytherc7e49d32011-07-20 20:43:15 +0200242 "t=0 0\r\n"
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100243 "m=audio %d RTP/AVP %d\r\n"
Holger Hans Peter Freyther5ea1bc72012-09-03 00:07:39 +0200244 "a=rtpmap:%d %s\r\n"
245 "%s%s",
Holger Hans Peter Freytherc7e49d32011-07-20 20:43:15 +0200246 endp->ci, endp->ci, addr, addr,
247 endp->net_end.local_port, endp->bts_end.payload_type,
Holger Hans Peter Freyther5ea1bc72012-09-03 00:07:39 +0200248 endp->bts_end.payload_type, endp->tcfg->audio_name,
249 fmtp_extra ? fmtp_extra : "", fmtp_extra ? "\r\n" : "");
Holger Hans Peter Freythera769dcb2012-12-07 15:14:27 +0100250 return create_resp(endp, 200, " OK", msg, trans_id, NULL, sdp_record);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100251}
252
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100253/*
254 * handle incoming messages:
255 * - this can be a command (four letters, space, transaction id)
256 * - or a response (three numbers, space, transaction id)
257 */
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100258struct msgb *mgcp_handle_message(struct mgcp_config *cfg, struct msgb *msg)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100259{
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100260 struct mgcp_parse_data pdata;
261 int i, code, handled = 0;
Holger Hans Peter Freyther62e836c2010-02-03 11:03:45 +0100262 struct msgb *resp = NULL;
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100263 char *data;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100264
Holger Hans Peter Freytherf36a11a2010-03-31 13:26:46 +0200265 if (msgb_l2len(msg) < 4) {
Holger Hans Peter Freyther0d904e02012-12-07 16:46:19 +0100266 LOGP(DMGCP, LOGL_ERROR, "msg too short: %d\n", msg->len);
Holger Hans Peter Freyther62e836c2010-02-03 11:03:45 +0100267 return NULL;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100268 }
269
270 /* attempt to treat it as a response */
Holger Hans Peter Freytherf36a11a2010-03-31 13:26:46 +0200271 if (sscanf((const char *)&msg->l2h[0], "%3d %*s", &code) == 1) {
Holger Hans Peter Freyther63f2db22010-02-26 13:30:57 +0100272 LOGP(DMGCP, LOGL_DEBUG, "Response: Code: %d\n", code);
Holger Hans Peter Freyther29de3462012-12-07 16:07:46 +0100273 return NULL;
274 }
275
276 msg->l3h = &msg->l2h[4];
277
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100278
279 /*
280 * Check for a duplicate message and respond.
281 * FIXME: Verify that the msg->l3h is NULL terminated.
282 */
283 memset(&pdata, 0, sizeof(pdata));
284 pdata.cfg = cfg;
Jacob Erlbeck17711712013-11-29 13:43:46 +0100285 data = strline_r((char *) msg->l3h, &pdata.save);
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100286 pdata.found = mgcp_analyze_header(&pdata, data);
287 if (pdata.endp && pdata.trans
288 && pdata.endp->last_trans
289 && strcmp(pdata.endp->last_trans, pdata.trans) == 0) {
290 return do_retransmission(pdata.endp);
291 }
292
Holger Hans Peter Freyther29de3462012-12-07 16:07:46 +0100293 for (i = 0; i < ARRAY_SIZE(mgcp_requests); ++i) {
294 if (strncmp(mgcp_requests[i].name, (const char *) &msg->l2h[0], 4) == 0) {
295 handled = 1;
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100296 resp = mgcp_requests[i].handle_request(&pdata);
Holger Hans Peter Freyther29de3462012-12-07 16:07:46 +0100297 break;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100298 }
299 }
300
Holger Hans Peter Freyther29de3462012-12-07 16:07:46 +0100301 if (!handled)
302 LOGP(DMGCP, LOGL_NOTICE, "MSG with type: '%.4s' not handled\n", &msg->l2h[0]);
303
Holger Hans Peter Freyther62e836c2010-02-03 11:03:45 +0100304 return resp;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100305}
306
Holger Hans Peter Freyther9f239a22011-01-06 19:32:52 +0100307/**
308 * We have a null terminated string with the endpoint name here. We only
309 * support two kinds. Simple ones as seen on the BSC level and the ones
310 * seen on the trunk side.
311 */
312static struct mgcp_endpoint *find_e1_endpoint(struct mgcp_config *cfg,
313 const char *mgcp)
314{
315 char *rest = NULL;
Holger Hans Peter Freyther74e61112011-02-28 14:13:47 +0100316 struct mgcp_trunk_config *tcfg;
317 int trunk, endp;
Holger Hans Peter Freyther9f239a22011-01-06 19:32:52 +0100318
319 trunk = strtoul(mgcp + 6, &rest, 10);
Holger Hans Peter Freytherf43f2fc2011-01-07 11:30:21 +0100320 if (rest == NULL || rest[0] != '/' || trunk < 1) {
Holger Hans Peter Freyther9f239a22011-01-06 19:32:52 +0100321 LOGP(DMGCP, LOGL_ERROR, "Wrong trunk name '%s'\n", mgcp);
322 return NULL;
323 }
324
325 endp = strtoul(rest + 1, &rest, 10);
326 if (rest == NULL || rest[0] != '@') {
Holger Hans Peter Freytherf43f2fc2011-01-07 11:30:21 +0100327 LOGP(DMGCP, LOGL_ERROR, "Wrong endpoint name '%s'\n", mgcp);
Holger Hans Peter Freyther9f239a22011-01-06 19:32:52 +0100328 return NULL;
329 }
330
331 /* signalling is on timeslot 1 */
332 if (endp == 1)
333 return NULL;
334
Holger Hans Peter Freyther74e61112011-02-28 14:13:47 +0100335 tcfg = mgcp_trunk_num(cfg, trunk);
336 if (!tcfg) {
337 LOGP(DMGCP, LOGL_ERROR, "The trunk %d is not declared.\n", trunk);
338 return NULL;
339 }
340
341 if (!tcfg->endpoints) {
342 LOGP(DMGCP, LOGL_ERROR, "Endpoints of trunk %d not allocated.\n", trunk);
343 return NULL;
344 }
345
346 if (endp < 1 || endp >= tcfg->number_endpoints) {
Holger Hans Peter Freyther9f239a22011-01-06 19:32:52 +0100347 LOGP(DMGCP, LOGL_ERROR, "Failed to find endpoint '%s'\n", mgcp);
Holger Hans Peter Freyther45c21842011-01-07 11:36:54 +0100348 return NULL;
Holger Hans Peter Freyther9f239a22011-01-06 19:32:52 +0100349 }
350
Holger Hans Peter Freyther74e61112011-02-28 14:13:47 +0100351 return &tcfg->endpoints[endp];
Holger Hans Peter Freyther9f239a22011-01-06 19:32:52 +0100352}
353
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100354static struct mgcp_endpoint *find_endpoint(struct mgcp_config *cfg, const char *mgcp)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100355{
356 char *endptr = NULL;
357 unsigned int gw = INT_MAX;
358
Holger Hans Peter Freyther9f239a22011-01-06 19:32:52 +0100359 if (strncmp(mgcp, "ds/e1", 5) == 0) {
360 return find_e1_endpoint(cfg, mgcp);
361 } else {
362 gw = strtoul(mgcp, &endptr, 16);
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +0100363 if (gw > 0 && gw < cfg->trunk.number_endpoints && strcmp(endptr, "@mgw") == 0)
364 return &cfg->trunk.endpoints[gw];
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100365 }
366
Holger Hans Peter Freyther9f239a22011-01-06 19:32:52 +0100367 LOGP(DMGCP, LOGL_ERROR, "Not able to find endpoint: '%s'\n", mgcp);
368 return NULL;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100369}
370
Harald Welteae199722012-01-27 12:31:36 +0100371/**
372 * @returns 0 when the status line was complete and transaction_id and
373 * endp out parameters are set.
374 */
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100375static int mgcp_analyze_header(struct mgcp_parse_data *pdata, char *data)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100376{
Harald Welteae199722012-01-27 12:31:36 +0100377 int i = 0;
Holger Hans Peter Freyther1eba7de2013-07-03 10:23:35 +0200378 char *elem, *save = NULL;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100379
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100380 pdata->trans = "000000";
Holger Hans Peter Freythera820c5f2010-02-26 13:32:55 +0100381
Harald Welteae199722012-01-27 12:31:36 +0100382 for (elem = strtok_r(data, " ", &save); elem;
383 elem = strtok_r(NULL, " ", &save)) {
384 switch (i) {
385 case 0:
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100386 pdata->trans = elem;
Harald Welteae199722012-01-27 12:31:36 +0100387 break;
388 case 1:
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100389 pdata->endp = find_endpoint(pdata->cfg, elem);
390 if (!pdata->endp) {
391 LOGP(DMGCP, LOGL_ERROR,
392 "Unable to find Endpoint `%s'\n", elem);
393 return -1;
Harald Welteae199722012-01-27 12:31:36 +0100394 }
395 break;
396 case 2:
397 if (strcmp("MGCP", elem)) {
398 LOGP(DMGCP, LOGL_ERROR,
399 "MGCP header parsing error\n");
400 return -1;
401 }
402 break;
403 case 3:
404 if (strcmp("1.0", elem)) {
405 LOGP(DMGCP, LOGL_ERROR, "MGCP version `%s' "
406 "not supported\n", elem);
407 return -1;
408 }
409 break;
410 }
411 i++;
412 }
413
414 if (i != 4) {
415 LOGP(DMGCP, LOGL_ERROR, "MGCP status line too short.\n");
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100416 pdata->trans = "000000";
417 pdata->endp = NULL;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100418 return -1;
419 }
420
Holger Hans Peter Freytherf2f15912010-04-01 03:27:04 +0200421 return 0;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100422}
423
424static int verify_call_id(const struct mgcp_endpoint *endp,
425 const char *callid)
426{
427 if (strcmp(endp->callid, callid) != 0) {
Holger Hans Peter Freyther2ada71d2010-02-03 09:13:10 +0100428 LOGP(DMGCP, LOGL_ERROR, "CallIDs does not match on 0x%x. '%s' != '%s'\n",
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100429 ENDPOINT_NUMBER(endp), endp->callid, callid);
430 return -1;
431 }
432
433 return 0;
434}
435
436static int verify_ci(const struct mgcp_endpoint *endp,
Holger Hans Peter Freyther46340132010-08-06 08:26:54 +0800437 const char *_ci)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100438{
Holger Hans Peter Freyther46340132010-08-06 08:26:54 +0800439 uint32_t ci = strtoul(_ci, NULL, 10);
440
441 if (ci != endp->ci) {
442 LOGP(DMGCP, LOGL_ERROR, "ConnectionIdentifiers do not match on 0x%x. %u != %s\n",
443 ENDPOINT_NUMBER(endp), endp->ci, _ci);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100444 return -1;
445 }
446
447 return 0;
448}
449
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100450static struct msgb *handle_audit_endpoint(struct mgcp_parse_data *p)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100451{
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100452 if (p->found != 0)
453 return create_err_response(NULL, 500, "AUEP", p->trans);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100454 else
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100455 return create_ok_response(p->endp, 200, "AUEP", p->trans);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100456}
457
Holger Hans Peter Freytheradb6e1c2010-09-18 06:44:24 +0800458static int parse_conn_mode(const char *msg, int *conn_mode)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100459{
460 int ret = 0;
461 if (strcmp(msg, "recvonly") == 0)
462 *conn_mode = MGCP_CONN_RECV_ONLY;
463 else if (strcmp(msg, "sendrecv") == 0)
464 *conn_mode = MGCP_CONN_RECV_SEND;
Holger Hans Peter Freythere02860a2010-09-18 20:21:44 +0800465 else if (strcmp(msg, "sendonly") == 0)
466 *conn_mode = MGCP_CONN_SEND_ONLY;
Holger Hans Peter Freyther98a38772010-08-03 02:27:21 +0800467 else if (strcmp(msg, "loopback") == 0)
468 *conn_mode = MGCP_CONN_LOOPBACK;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100469 else {
Holger Hans Peter Freyther2ada71d2010-02-03 09:13:10 +0100470 LOGP(DMGCP, LOGL_ERROR, "Unknown connection mode: '%s'\n", msg);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100471 ret = -1;
472 }
473
474 return ret;
475}
476
Holger Hans Peter Freytherf138f912010-08-05 08:08:17 +0800477static int allocate_port(struct mgcp_endpoint *endp, struct mgcp_rtp_end *end,
Holger Hans Peter Freyther218f8562010-09-18 02:30:02 +0800478 struct mgcp_port_range *range,
479 int (*alloc)(struct mgcp_endpoint *endp, int port))
Holger Hans Peter Freytherf138f912010-08-05 08:08:17 +0800480{
481 int i;
482
483 if (range->mode == PORT_ALLOC_STATIC) {
Holger Hans Peter Freytherf138f912010-08-05 08:08:17 +0800484 end->local_alloc = PORT_ALLOC_STATIC;
485 return 0;
486 }
487
488 /* attempt to find a port */
489 for (i = 0; i < 200; ++i) {
490 int rc;
491
492 if (range->last_port >= range->range_end)
493 range->last_port = range->range_start;
494
Holger Hans Peter Freyther218f8562010-09-18 02:30:02 +0800495 rc = alloc(endp, range->last_port);
Holger Hans Peter Freytherf138f912010-08-05 08:08:17 +0800496
497 range->last_port += 2;
498 if (rc == 0) {
499 end->local_alloc = PORT_ALLOC_DYNAMIC;
500 return 0;
501 }
502
503 }
504
Holger Hans Peter Freyther218f8562010-09-18 02:30:02 +0800505 LOGP(DMGCP, LOGL_ERROR, "Allocating a RTP/RTCP port failed 200 times 0x%x.\n",
506 ENDPOINT_NUMBER(endp));
Holger Hans Peter Freytherf138f912010-08-05 08:08:17 +0800507 return -1;
508}
509
510static int allocate_ports(struct mgcp_endpoint *endp)
511{
Holger Hans Peter Freyther218f8562010-09-18 02:30:02 +0800512 if (allocate_port(endp, &endp->net_end, &endp->cfg->net_ports,
513 mgcp_bind_net_rtp_port) != 0)
Holger Hans Peter Freytherf138f912010-08-05 08:08:17 +0800514 return -1;
515
Holger Hans Peter Freyther218f8562010-09-18 02:30:02 +0800516 if (allocate_port(endp, &endp->bts_end, &endp->cfg->bts_ports,
517 mgcp_bind_bts_rtp_port) != 0) {
Holger Hans Peter Freytherf138f912010-08-05 08:08:17 +0800518 mgcp_rtp_end_reset(&endp->net_end);
519 return -1;
520 }
521
Holger Hans Peter Freyther69906872011-02-28 14:51:48 +0100522 if (endp->cfg->transcoder_ip && endp->tcfg->trunk_type == MGCP_TRUNK_VIRTUAL) {
Holger Hans Peter Freyther21262332010-11-01 20:53:31 +0100523 if (allocate_port(endp, &endp->trans_net,
Holger Hans Peter Freytherb54048f2010-11-01 19:57:50 +0100524 &endp->cfg->transcoder_ports,
Holger Hans Peter Freytherbd7b3c52010-11-01 21:04:54 +0100525 mgcp_bind_trans_net_rtp_port) != 0) {
Holger Hans Peter Freytherb54048f2010-11-01 19:57:50 +0100526 mgcp_rtp_end_reset(&endp->net_end);
527 mgcp_rtp_end_reset(&endp->bts_end);
528 return -1;
529 }
530
Holger Hans Peter Freytherbd7b3c52010-11-01 21:04:54 +0100531 if (allocate_port(endp, &endp->trans_bts,
532 &endp->cfg->transcoder_ports,
533 mgcp_bind_trans_bts_rtp_port) != 0) {
534 mgcp_rtp_end_reset(&endp->net_end);
535 mgcp_rtp_end_reset(&endp->bts_end);
536 mgcp_rtp_end_reset(&endp->trans_net);
537 return -1;
538 }
539
Holger Hans Peter Freytherb54048f2010-11-01 19:57:50 +0100540 /* remember that we have set up transcoding */
Pablo Neira Ayuso46bd4242013-07-08 05:09:46 +0200541 endp->type = MGCP_RTP_TRANSCODED;
Holger Hans Peter Freyther218f8562010-09-18 02:30:02 +0800542 }
543
Holger Hans Peter Freytherf138f912010-08-05 08:08:17 +0800544 return 0;
545}
546
Jacob Erlbeck17711712013-11-29 13:43:46 +0100547static int parse_sdp_data(struct mgcp_rtp_end *rtp, struct mgcp_parse_data *p)
548{
549 char *line;
550 int found_media = 0;
551
552 for_each_line(line, p->save) {
553 switch (line[0]) {
554 case 'a':
555 case 'o':
556 case 's':
557 case 't':
558 case 'v':
559 /* skip these SDP attributes */
560 break;
561 case 'm': {
562 int port;
563 int payload;
564
565 if (sscanf(line, "m=audio %d RTP/AVP %d",
566 &port, &payload) == 2) {
567 rtp->rtp_port = htons(port);
568 rtp->rtcp_port = htons(port + 1);
569 rtp->payload_type = payload;
570 found_media = 1;
571 }
572 break;
573 }
574 case 'c': {
575 char ipv4[16];
576
577 if (sscanf(line, "c=IN IP4 %15s", ipv4) == 1) {
578 inet_aton(ipv4, &rtp->addr);
579 }
580 break;
581 }
582 default:
583 if (p->endp)
584 LOGP(DMGCP, LOGL_NOTICE,
585 "Unhandled SDP option: '%c'/%d on 0x%x\n",
586 line[0], line[0], ENDPOINT_NUMBER(p->endp));
587 else
588 LOGP(DMGCP, LOGL_NOTICE,
589 "Unhandled SDP option: '%c'/%d\n",
590 line[0], line[0]);
591 break;
592 }
593 }
594
595 if (found_media)
596 LOGP(DMGCP, LOGL_NOTICE,
597 "Got media info via SDP: port %d, payload %d, addr %s\n",
598 ntohs(rtp->rtp_port), rtp->payload_type, inet_ntoa(rtp->addr));
599
600 return found_media;
601}
602
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100603static struct msgb *handle_create_con(struct mgcp_parse_data *p)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100604{
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +0100605 struct mgcp_trunk_config *tcfg;
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100606 struct mgcp_endpoint *endp = p->endp;
Holger Hans Peter Freyther9e9392d2010-08-08 16:24:48 +0800607 int error_code = 400;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100608
Holger Hans Peter Freyther3488c3d2011-07-20 20:44:54 +0200609 const char *local_options = NULL;
610 const char *callid = NULL;
611 const char *mode = NULL;
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100612 char *line;
613
614 if (p->found != 0)
615 return create_err_response(NULL, 510, "CRCX", p->trans);
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +0100616
Holger Hans Peter Freyther3488c3d2011-07-20 20:44:54 +0200617 /* parse CallID C: and LocalParameters L: */
Jacob Erlbeck17711712013-11-29 13:43:46 +0100618 for_each_line(line, p->save) {
Harald Welteae199722012-01-27 12:31:36 +0100619 switch (line[0]) {
620 case 'L':
621 local_options = (const char *) line + 3;
622 break;
623 case 'C':
624 callid = (const char *) line + 3;
625 break;
626 case 'M':
627 mode = (const char *) line + 3;
628 break;
629 default:
630 LOGP(DMGCP, LOGL_NOTICE, "Unhandled option: '%c'/%d on 0x%x\n",
631 *line, *line, ENDPOINT_NUMBER(endp));
632 break;
633 }
Holger Hans Peter Freyther3488c3d2011-07-20 20:44:54 +0200634 }
Harald Welteae199722012-01-27 12:31:36 +0100635
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100636 tcfg = p->endp->tcfg;
Holger Hans Peter Freyther3488c3d2011-07-20 20:44:54 +0200637
638 /* Check required data */
639 if (!callid || !mode) {
640 LOGP(DMGCP, LOGL_ERROR, "Missing callid and mode in CRCX on 0x%x\n",
641 ENDPOINT_NUMBER(endp));
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100642 return create_err_response(endp, 400, "CRCX", p->trans);
Holger Hans Peter Freyther3488c3d2011-07-20 20:44:54 +0200643 }
644
Holger Hans Peter Freyther39a97e22010-08-06 18:03:11 +0800645 if (endp->allocated) {
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +0100646 if (tcfg->force_realloc) {
Holger Hans Peter Freyther408cc4a2010-04-07 10:51:27 +0200647 LOGP(DMGCP, LOGL_NOTICE, "Endpoint 0x%x already allocated. Forcing realloc.\n",
648 ENDPOINT_NUMBER(endp));
Holger Hans Peter Freyther32d4e502010-04-24 21:02:48 +0800649 mgcp_free_endp(endp);
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100650 if (p->cfg->realloc_cb)
651 p->cfg->realloc_cb(tcfg, ENDPOINT_NUMBER(endp));
Holger Hans Peter Freyther408cc4a2010-04-07 10:51:27 +0200652 } else {
653 LOGP(DMGCP, LOGL_ERROR, "Endpoint is already used. 0x%x\n",
654 ENDPOINT_NUMBER(endp));
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100655 return create_err_response(endp, 400, "CRCX", p->trans);
Holger Hans Peter Freyther408cc4a2010-04-07 10:51:27 +0200656 }
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100657 }
658
Holger Hans Peter Freyther3488c3d2011-07-20 20:44:54 +0200659 /* copy some parameters */
660 endp->callid = talloc_strdup(tcfg->endpoints, callid);
661
662 if (local_options)
663 endp->local_options = talloc_strdup(tcfg->endpoints, local_options);
664
665 if (parse_conn_mode(mode, &endp->conn_mode) != 0) {
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100666 error_code = 517;
667 goto error2;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100668 }
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100669
670 /* initialize */
Holger Hans Peter Freythera17d7012010-08-05 01:34:51 +0800671 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 +0100672
673 /* set to zero until we get the info */
Holger Hans Peter Freythera17d7012010-08-05 01:34:51 +0800674 memset(&endp->net_end.addr, 0, sizeof(endp->net_end.addr));
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100675
676 /* bind to the port now */
Holger Hans Peter Freytherf138f912010-08-05 08:08:17 +0800677 if (allocate_ports(endp) != 0)
678 goto error2;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100679
680 /* assign a local call identifier or fail */
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100681 endp->ci = generate_call_id(p->cfg);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100682 if (endp->ci == CI_UNUSED)
683 goto error2;
684
Holger Hans Peter Freyther39a97e22010-08-06 18:03:11 +0800685 endp->allocated = 1;
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +0100686 endp->bts_end.payload_type = tcfg->audio_payload;
Holger Hans Peter Freyther5ea1bc72012-09-03 00:07:39 +0200687 endp->bts_end.fmtp_extra = talloc_strdup(tcfg->endpoints,
688 tcfg->audio_fmtp_extra);
Holger Hans Peter Freytheref6bb252010-02-26 13:41:22 +0100689
Holger Hans Peter Freytherfe86d3c2010-02-26 13:37:05 +0100690 /* policy CB */
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100691 if (p->cfg->policy_cb) {
692 int rc;
693 rc = p->cfg->policy_cb(tcfg, ENDPOINT_NUMBER(endp),
694 MGCP_ENDP_CRCX, p->trans);
695 switch (rc) {
Holger Hans Peter Freytherfe86d3c2010-02-26 13:37:05 +0100696 case MGCP_POLICY_REJECT:
697 LOGP(DMGCP, LOGL_NOTICE, "CRCX rejected by policy on 0x%x\n",
698 ENDPOINT_NUMBER(endp));
699 mgcp_free_endp(endp);
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100700 return create_err_response(endp, 400, "CRCX", p->trans);
Holger Hans Peter Freytherfe86d3c2010-02-26 13:37:05 +0100701 break;
702 case MGCP_POLICY_DEFER:
703 /* stop processing */
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +0800704 create_transcoder(endp);
Holger Hans Peter Freytherfe86d3c2010-02-26 13:37:05 +0100705 return NULL;
706 break;
707 case MGCP_POLICY_CONT:
708 /* just continue */
709 break;
710 }
711 }
712
Holger Hans Peter Freythere378cb12010-08-06 20:22:23 +0800713 LOGP(DMGCP, LOGL_DEBUG, "Creating endpoint on: 0x%x CI: %u port: %u/%u\n",
Holger Hans Peter Freyther58ff2192010-08-05 03:08:35 +0800714 ENDPOINT_NUMBER(endp), endp->ci,
715 endp->net_end.local_port, endp->bts_end.local_port);
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100716 if (p->cfg->change_cb)
717 p->cfg->change_cb(tcfg, ENDPOINT_NUMBER(endp), MGCP_ENDP_CRCX);
Holger Hans Peter Freyther77f7afe2010-02-03 09:54:43 +0100718
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +0800719 create_transcoder(endp);
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100720 return create_response_with_sdp(endp, "CRCX", p->trans);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100721error2:
Holger Hans Peter Freyther414bf402010-08-06 07:05:13 +0800722 mgcp_free_endp(endp);
Holger Hans Peter Freyther2ada71d2010-02-03 09:13:10 +0100723 LOGP(DMGCP, LOGL_NOTICE, "Resource error on 0x%x\n", ENDPOINT_NUMBER(endp));
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100724 return create_err_response(endp, error_code, "CRCX", p->trans);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100725}
726
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100727static struct msgb *handle_modify_con(struct mgcp_parse_data *p)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100728{
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100729 struct mgcp_endpoint *endp = p->endp;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100730 int error_code = 500;
Holger Hans Peter Freythere3d16bb2010-04-22 11:58:13 +0800731 int silent = 0;
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100732 char *line;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100733
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100734 if (p->found != 0)
735 return create_err_response(NULL, 510, "MDCX", p->trans);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100736
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100737 if (endp->ci == CI_UNUSED) {
738 LOGP(DMGCP, LOGL_ERROR, "Endpoint is not "
739 "holding a connection. 0x%x\n", ENDPOINT_NUMBER(endp));
740 return create_err_response(endp, 400, "MDCX", p->trans);
741 }
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100742
Jacob Erlbeck17711712013-11-29 13:43:46 +0100743 for_each_line(line, p->save) {
Harald Welteae199722012-01-27 12:31:36 +0100744 switch (line[0]) {
745 case 'C': {
746 if (verify_call_id(endp, line + 3) != 0)
747 goto error3;
748 break;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100749 }
Harald Welteae199722012-01-27 12:31:36 +0100750 case 'I': {
751 if (verify_ci(endp, line + 3) != 0)
752 goto error3;
753 break;
754 }
755 case 'L':
756 /* skip */
757 break;
758 case 'M':
759 if (parse_conn_mode(line + 3, &endp->conn_mode) != 0) {
760 error_code = 517;
761 goto error3;
762 }
763 endp->orig_mode = endp->conn_mode;
764 break;
765 case 'Z':
766 silent = strcmp("noanswer", line + 3) == 0;
767 break;
768 case '\0':
769 /* SDP file begins */
Jacob Erlbeck17711712013-11-29 13:43:46 +0100770 parse_sdp_data(&endp->net_end, p);
771 /* This will exhaust p->save, so the loop will
772 * terminate next time.
773 */
Harald Welteae199722012-01-27 12:31:36 +0100774 break;
Harald Welteae199722012-01-27 12:31:36 +0100775 default:
Jacob Erlbeck17711712013-11-29 13:43:46 +0100776 LOGP(DMGCP, LOGL_NOTICE, "Unhandled MGCP option: '%c'/%d on 0x%x\n",
Harald Welteae199722012-01-27 12:31:36 +0100777 line[0], line[0], ENDPOINT_NUMBER(endp));
778 break;
779 }
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100780 }
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100781
Holger Hans Peter Freytherfe86d3c2010-02-26 13:37:05 +0100782 /* policy CB */
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100783 if (p->cfg->policy_cb) {
784 int rc;
785 rc = p->cfg->policy_cb(endp->tcfg, ENDPOINT_NUMBER(endp),
786 MGCP_ENDP_MDCX, p->trans);
787 switch (rc) {
Holger Hans Peter Freytherfe86d3c2010-02-26 13:37:05 +0100788 case MGCP_POLICY_REJECT:
789 LOGP(DMGCP, LOGL_NOTICE, "MDCX rejected by policy on 0x%x\n",
790 ENDPOINT_NUMBER(endp));
Holger Hans Peter Freythere3d16bb2010-04-22 11:58:13 +0800791 if (silent)
792 goto out_silent;
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100793 return create_err_response(endp, 400, "MDCX", p->trans);
Holger Hans Peter Freytherfe86d3c2010-02-26 13:37:05 +0100794 break;
795 case MGCP_POLICY_DEFER:
796 /* stop processing */
797 return NULL;
798 break;
799 case MGCP_POLICY_CONT:
800 /* just continue */
801 break;
802 }
803 }
804
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100805 /* modify */
Holger Hans Peter Freythere378cb12010-08-06 20:22:23 +0800806 LOGP(DMGCP, LOGL_DEBUG, "Modified endpoint on: 0x%x Server: %s:%u\n",
Holger Hans Peter Freythera17d7012010-08-05 01:34:51 +0800807 ENDPOINT_NUMBER(endp), inet_ntoa(endp->net_end.addr), ntohs(endp->net_end.rtp_port));
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100808 if (p->cfg->change_cb)
809 p->cfg->change_cb(endp->tcfg, ENDPOINT_NUMBER(endp), MGCP_ENDP_MDCX);
Holger Hans Peter Freythere3d16bb2010-04-22 11:58:13 +0800810 if (silent)
811 goto out_silent;
812
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100813 return create_response_with_sdp(endp, "MDCX", p->trans);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100814
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100815error3:
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100816 return create_err_response(endp, error_code, "MDCX", p->trans);
Holger Hans Peter Freythere3d16bb2010-04-22 11:58:13 +0800817
818
819out_silent:
820 return NULL;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100821}
822
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100823static struct msgb *handle_delete_con(struct mgcp_parse_data *p)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100824{
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100825 struct mgcp_endpoint *endp = p->endp;
Holger Hans Peter Freyther9e9392d2010-08-08 16:24:48 +0800826 int error_code = 400;
Holger Hans Peter Freythere3d16bb2010-04-22 11:58:13 +0800827 int silent = 0;
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100828 char *line;
Holger Hans Peter Freyther0bf15a82012-09-14 17:18:12 +0200829 char stats[1048];
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100830
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100831 if (p->found != 0)
832 return create_err_response(NULL, error_code, "DLCX", p->trans);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100833
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100834 if (!p->endp->allocated) {
835 LOGP(DMGCP, LOGL_ERROR, "Endpoint is not used. 0x%x\n",
836 ENDPOINT_NUMBER(endp));
837 return create_err_response(endp, 400, "DLCX", p->trans);
838 }
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100839
Jacob Erlbeck17711712013-11-29 13:43:46 +0100840 for_each_line(line, p->save) {
Harald Welteae199722012-01-27 12:31:36 +0100841 switch (line[0]) {
842 case 'C':
843 if (verify_call_id(endp, line + 3) != 0)
844 goto error3;
845 break;
846 case 'I':
847 if (verify_ci(endp, line + 3) != 0)
848 goto error3;
849 break;
850 case 'Z':
851 silent = strcmp("noanswer", line + 3) == 0;
852 break;
853 default:
854 LOGP(DMGCP, LOGL_NOTICE, "Unhandled option: '%c'/%d on 0x%x\n",
855 line[0], line[0], ENDPOINT_NUMBER(endp));
856 break;
857 }
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100858 }
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100859
Holger Hans Peter Freytherfe86d3c2010-02-26 13:37:05 +0100860 /* policy CB */
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100861 if (p->cfg->policy_cb) {
862 int rc;
863 rc = p->cfg->policy_cb(endp->tcfg, ENDPOINT_NUMBER(endp),
864 MGCP_ENDP_DLCX, p->trans);
865 switch (rc) {
Holger Hans Peter Freytherfe86d3c2010-02-26 13:37:05 +0100866 case MGCP_POLICY_REJECT:
867 LOGP(DMGCP, LOGL_NOTICE, "DLCX rejected by policy on 0x%x\n",
868 ENDPOINT_NUMBER(endp));
Holger Hans Peter Freythere3d16bb2010-04-22 11:58:13 +0800869 if (silent)
870 goto out_silent;
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100871 return create_err_response(endp, 400, "DLCX", p->trans);
Holger Hans Peter Freytherfe86d3c2010-02-26 13:37:05 +0100872 break;
873 case MGCP_POLICY_DEFER:
874 /* stop processing */
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +0800875 delete_transcoder(endp);
Holger Hans Peter Freytherfe86d3c2010-02-26 13:37:05 +0100876 return NULL;
877 break;
878 case MGCP_POLICY_CONT:
879 /* just continue */
880 break;
881 }
882 }
883
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100884 /* free the connection */
Holger Hans Peter Freythere378cb12010-08-06 20:22:23 +0800885 LOGP(DMGCP, LOGL_DEBUG, "Deleted endpoint on: 0x%x Server: %s:%u\n",
Holger Hans Peter Freythera17d7012010-08-05 01:34:51 +0800886 ENDPOINT_NUMBER(endp), inet_ntoa(endp->net_end.addr), ntohs(endp->net_end.rtp_port));
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +0800887
Holger Hans Peter Freyther0bf15a82012-09-14 17:18:12 +0200888 /* save the statistics of the current call */
889 mgcp_format_stats(endp, stats, sizeof(stats));
890
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +0800891 delete_transcoder(endp);
Holger Hans Peter Freyther154b9552010-02-26 13:27:51 +0100892 mgcp_free_endp(endp);
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100893 if (p->cfg->change_cb)
894 p->cfg->change_cb(endp->tcfg, ENDPOINT_NUMBER(endp), MGCP_ENDP_DLCX);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100895
Holger Hans Peter Freythere3d16bb2010-04-22 11:58:13 +0800896 if (silent)
897 goto out_silent;
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100898 return create_ok_resp_with_param(endp, 250, "DLCX", p->trans, stats);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100899
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100900error3:
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100901 return create_err_response(endp, error_code, "DLCX", p->trans);
Holger Hans Peter Freythere3d16bb2010-04-22 11:58:13 +0800902
903out_silent:
904 return NULL;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100905}
906
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100907static struct msgb *handle_rsip(struct mgcp_parse_data *p)
Holger Hans Peter Freyther9bdcc9c2010-03-31 06:39:35 +0200908{
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100909 if (p->found != 0) {
Holger Hans Peter Freyther74db7742011-06-10 00:04:55 +0200910 LOGP(DMGCP, LOGL_ERROR, "Failed to find the endpoint.\n");
911 return NULL;
912 }
913
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100914 if (p->cfg->reset_cb)
915 p->cfg->reset_cb(p->endp->tcfg);
Holger Hans Peter Freyther9bdcc9c2010-03-31 06:39:35 +0200916 return NULL;
917}
918
Holger Hans Peter Freyther8d0be252012-11-29 12:54:22 +0100919static char extract_tone(const char *line)
920{
921 const char *str = strstr(line, "D/");
922 if (!str)
923 return CHAR_MAX;
924
925 return str[2];
926}
927
Holger Hans Peter Freyther6e94d6d2011-01-25 23:33:54 +0100928/*
929 * This can request like DTMF detection and forward, fax detection... it
930 * can also request when the notification should be send and such. We don't
931 * do this right now.
932 */
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100933static struct msgb *handle_noti_req(struct mgcp_parse_data *p)
Holger Hans Peter Freyther6e94d6d2011-01-25 23:33:54 +0100934{
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100935 int res = 0;
936 char *line;
Holger Hans Peter Freyther9f3835b2013-05-21 17:04:35 +0200937 char tone = CHAR_MAX;
Holger Hans Peter Freyther6e94d6d2011-01-25 23:33:54 +0100938
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100939 if (p->found != 0)
940 return create_err_response(NULL, 400, "RQNT", p->trans);
Holger Hans Peter Freyther6e94d6d2011-01-25 23:33:54 +0100941
Jacob Erlbeck17711712013-11-29 13:43:46 +0100942 for_each_line(line, p->save) {
Holger Hans Peter Freyther8d0be252012-11-29 12:54:22 +0100943 switch (line[0]) {
944 case 'S':
945 tone = extract_tone(line);
946 break;
947 }
Holger Hans Peter Freyther6e94d6d2011-01-25 23:33:54 +0100948 }
Holger Hans Peter Freyther8d0be252012-11-29 12:54:22 +0100949
950 /* we didn't see a signal request with a tone */
951 if (tone == CHAR_MAX)
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100952 return create_ok_response(p->endp, 200, "RQNT", p->trans);
Holger Hans Peter Freyther8d0be252012-11-29 12:54:22 +0100953
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100954 if (p->cfg->rqnt_cb)
955 res = p->cfg->rqnt_cb(p->endp, tone);
Holger Hans Peter Freyther8d0be252012-11-29 12:54:22 +0100956
957 return res == 0 ?
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100958 create_ok_response(p->endp, 200, "RQNT", p->trans) :
959 create_err_response(p->endp, res, "RQNT", p->trans);
Holger Hans Peter Freyther6e94d6d2011-01-25 23:33:54 +0100960}
961
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100962struct mgcp_config *mgcp_config_alloc(void)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100963{
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100964 struct mgcp_config *cfg;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100965
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100966 cfg = talloc_zero(NULL, struct mgcp_config);
967 if (!cfg) {
968 LOGP(DMGCP, LOGL_FATAL, "Failed to allocate config.\n");
969 return NULL;
970 }
971
972 cfg->source_port = 2427;
973 cfg->source_addr = talloc_strdup(cfg, "0.0.0.0");
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +0100974
Holger Hans Peter Freytherb98ba722010-09-19 04:21:39 +0800975 cfg->transcoder_remote_base = 4000;
Holger Hans Peter Freyther15e73892010-08-05 07:10:56 +0800976
977 cfg->bts_ports.base_port = RTP_PORT_DEFAULT;
978 cfg->net_ports.base_port = RTP_PORT_NET_DEFAULT;
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100979
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +0100980 /* default trunk handling */
981 cfg->trunk.cfg = cfg;
982 cfg->trunk.trunk_nr = 0;
983 cfg->trunk.trunk_type = MGCP_TRUNK_VIRTUAL;
984 cfg->trunk.audio_name = talloc_strdup(cfg, "AMR/8000");
985 cfg->trunk.audio_payload = 126;
Holger Hans Peter Freythera8090d52012-05-11 13:00:45 +0200986 cfg->trunk.omit_rtcp = 0;
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +0100987
Holger Hans Peter Freyther0e939fe2011-02-28 12:11:02 +0100988 INIT_LLIST_HEAD(&cfg->trunks);
989
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100990 return cfg;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100991}
992
Holger Hans Peter Freyther0e939fe2011-02-28 12:11:02 +0100993struct mgcp_trunk_config *mgcp_trunk_alloc(struct mgcp_config *cfg, int nr)
994{
995 struct mgcp_trunk_config *trunk;
996
997 trunk = talloc_zero(cfg, struct mgcp_trunk_config);
998 if (!trunk) {
999 LOGP(DMGCP, LOGL_ERROR, "Failed to allocate.\n");
1000 return NULL;
1001 }
1002
1003 trunk->cfg = cfg;
1004 trunk->trunk_type = MGCP_TRUNK_E1;
1005 trunk->trunk_nr = nr;
1006 trunk->audio_name = talloc_strdup(cfg, "AMR/8000");
1007 trunk->audio_payload = 126;
1008 trunk->number_endpoints = 33;
Holger Hans Peter Freythera8090d52012-05-11 13:00:45 +02001009 trunk->omit_rtcp = 0;
Holger Hans Peter Freyther0e939fe2011-02-28 12:11:02 +01001010 llist_add_tail(&trunk->entry, &cfg->trunks);
1011 return trunk;
1012}
1013
1014struct mgcp_trunk_config *mgcp_trunk_num(struct mgcp_config *cfg, int index)
1015{
1016 struct mgcp_trunk_config *trunk;
1017
1018 llist_for_each_entry(trunk, &cfg->trunks, entry)
1019 if (trunk->trunk_nr == index)
1020 return trunk;
1021
1022 return NULL;
1023}
1024
Holger Hans Peter Freythera17d7012010-08-05 01:34:51 +08001025static void mgcp_rtp_end_reset(struct mgcp_rtp_end *end)
1026{
Holger Hans Peter Freythere97155a2010-11-02 19:06:13 +01001027 if (end->local_alloc == PORT_ALLOC_DYNAMIC) {
Holger Hans Peter Freytherf138f912010-08-05 08:08:17 +08001028 mgcp_free_rtp_port(end);
Holger Hans Peter Freythere97155a2010-11-02 19:06:13 +01001029 end->local_port = 0;
1030 }
Holger Hans Peter Freytherf138f912010-08-05 08:08:17 +08001031
Holger Hans Peter Freytherc4921272010-08-05 03:37:22 +08001032 end->packets = 0;
Holger Hans Peter Freyther952f7522012-09-12 11:38:37 +02001033 end->octets = 0;
Holger Hans Peter Freytherc4921272010-08-05 03:37:22 +08001034 memset(&end->addr, 0, sizeof(end->addr));
Holger Hans Peter Freythere97155a2010-11-02 19:06:13 +01001035 end->rtp_port = end->rtcp_port = 0;
Holger Hans Peter Freythera17d7012010-08-05 01:34:51 +08001036 end->payload_type = -1;
Holger Hans Peter Freytherf138f912010-08-05 08:08:17 +08001037 end->local_alloc = -1;
Holger Hans Peter Freyther5ea1bc72012-09-03 00:07:39 +02001038 talloc_free(end->fmtp_extra);
1039 end->fmtp_extra = NULL;
Jacob Erlbeck72c30902013-11-25 15:23:35 +01001040
1041 /* Set default values */
1042 end->frame_duration_num = DEFAULT_RTP_AUDIO_FRAME_DUR_NUM;
1043 end->frame_duration_den = DEFAULT_RTP_AUDIO_FRAME_DUR_DEN;
1044 end->frames_per_packet = DEFAULT_RTP_AUDIO_FRAMES_PER_PACKET;
1045 end->rate = DEFAULT_RTP_AUDIO_DEFAULT_RATE;
Holger Hans Peter Freythera17d7012010-08-05 01:34:51 +08001046}
1047
Holger Hans Peter Freytherc4921272010-08-05 03:37:22 +08001048static void mgcp_rtp_end_init(struct mgcp_rtp_end *end)
1049{
1050 mgcp_rtp_end_reset(end);
1051 end->rtp.fd = -1;
1052 end->rtcp.fd = -1;
1053}
1054
Holger Hans Peter Freyther1f0c5b42011-02-28 14:37:03 +01001055int mgcp_endpoints_allocate(struct mgcp_trunk_config *tcfg)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +01001056{
1057 int i;
1058
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +01001059 /* Initialize all endpoints */
Holger Hans Peter Freyther1f0c5b42011-02-28 14:37:03 +01001060 tcfg->endpoints = _talloc_zero_array(tcfg->cfg,
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +01001061 sizeof(struct mgcp_endpoint),
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +01001062 tcfg->number_endpoints, "endpoints");
1063 if (!tcfg->endpoints)
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +01001064 return -1;
1065
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +01001066 for (i = 0; i < tcfg->number_endpoints; ++i) {
1067 tcfg->endpoints[i].ci = CI_UNUSED;
Holger Hans Peter Freyther1f0c5b42011-02-28 14:37:03 +01001068 tcfg->endpoints[i].cfg = tcfg->cfg;
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +01001069 tcfg->endpoints[i].tcfg = tcfg;
1070 mgcp_rtp_end_init(&tcfg->endpoints[i].net_end);
1071 mgcp_rtp_end_init(&tcfg->endpoints[i].bts_end);
1072 mgcp_rtp_end_init(&tcfg->endpoints[i].trans_net);
1073 mgcp_rtp_end_init(&tcfg->endpoints[i].trans_bts);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +01001074 }
1075
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +01001076 return 0;
1077}
Holger Hans Peter Freyther154b9552010-02-26 13:27:51 +01001078
1079void mgcp_free_endp(struct mgcp_endpoint *endp)
1080{
Holger Hans Peter Freytherc77efdf2010-03-31 12:31:09 +02001081 LOGP(DMGCP, LOGL_DEBUG, "Deleting endpoint on: 0x%x\n", ENDPOINT_NUMBER(endp));
Holger Hans Peter Freyther89976e82010-08-03 15:01:43 +00001082 endp->ci = CI_UNUSED;
Holger Hans Peter Freyther39a97e22010-08-06 18:03:11 +08001083 endp->allocated = 0;
Holger Hans Peter Freyther154b9552010-02-26 13:27:51 +01001084
Holger Hans Peter Freyther01d315f2012-12-07 11:52:16 +01001085 talloc_free(endp->callid);
1086 endp->callid = NULL;
Holger Hans Peter Freyther154b9552010-02-26 13:27:51 +01001087
Holger Hans Peter Freyther01d315f2012-12-07 11:52:16 +01001088 talloc_free(endp->local_options);
1089 endp->local_options = NULL;
Holger Hans Peter Freyther154b9552010-02-26 13:27:51 +01001090
Holger Hans Peter Freythera17d7012010-08-05 01:34:51 +08001091 mgcp_rtp_end_reset(&endp->bts_end);
1092 mgcp_rtp_end_reset(&endp->net_end);
Holger Hans Peter Freyther21262332010-11-01 20:53:31 +01001093 mgcp_rtp_end_reset(&endp->trans_net);
Holger Hans Peter Freytherbd7b3c52010-11-01 21:04:54 +01001094 mgcp_rtp_end_reset(&endp->trans_bts);
Pablo Neira Ayuso46bd4242013-07-08 05:09:46 +02001095 endp->type = MGCP_RTP_DEFAULT;
Holger Hans Peter Freyther380b8712010-07-29 02:38:39 +08001096
Holger Hans Peter Freyther31868922010-08-03 11:59:04 +00001097 memset(&endp->net_state, 0, sizeof(endp->net_state));
1098 memset(&endp->bts_state, 0, sizeof(endp->bts_state));
Holger Hans Peter Freytherc597a4e2010-08-03 02:57:02 +08001099
1100 endp->conn_mode = endp->orig_mode = MGCP_CONN_NONE;
Holger Hans Peter Freyther6357a8e2010-08-05 12:07:00 +00001101 endp->allow_patch = 0;
Holger Hans Peter Freyther260d6ed2010-08-06 01:12:21 +08001102
1103 memset(&endp->taps, 0, sizeof(endp->taps));
Holger Hans Peter Freyther154b9552010-02-26 13:27:51 +01001104}
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +08001105
Holger Hans Peter Freyther557b1ab2010-09-19 04:39:55 +08001106static int send_trans(struct mgcp_config *cfg, const char *buf, int len)
1107{
1108 struct sockaddr_in addr;
1109
1110 memset(&addr, 0, sizeof(addr));
1111 addr.sin_family = AF_INET;
1112 addr.sin_addr = cfg->transcoder_in;
1113 addr.sin_port = htons(2427);
1114 return sendto(cfg->gw_fd.bfd.fd, buf, len, 0,
1115 (struct sockaddr *) &addr, sizeof(addr));
1116}
1117
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +08001118static void send_msg(struct mgcp_endpoint *endp, int endpoint, int port,
1119 const char *msg, const char *mode)
1120{
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +08001121 char buf[2096];
1122 int len;
1123
1124 /* hardcoded to AMR right now, we do not know the real type at this point */
1125 len = snprintf(buf, sizeof(buf),
1126 "%s 42 %x@mgw MGCP 1.0\r\n"
1127 "C: 4256\r\n"
1128 "M: %s\r\n"
1129 "\r\n"
1130 "c=IN IP4 %s\r\n"
1131 "m=audio %d RTP/AVP %d\r\n"
1132 "a=rtpmap:%d %s\r\n",
1133 msg, endpoint, mode, endp->cfg->source_addr,
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +01001134 port, endp->tcfg->audio_payload,
1135 endp->tcfg->audio_payload, endp->tcfg->audio_name);
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +08001136
1137 if (len < 0)
1138 return;
1139
1140 buf[sizeof(buf) - 1] = '\0';
1141
Holger Hans Peter Freyther557b1ab2010-09-19 04:39:55 +08001142 send_trans(endp->cfg, buf, len);
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +08001143}
1144
1145static void send_dlcx(struct mgcp_endpoint *endp, int endpoint)
1146{
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +08001147 char buf[2096];
1148 int len;
1149
1150 len = snprintf(buf, sizeof(buf),
1151 "DLCX 43 %x@mgw MGCP 1.0\r\n"
1152 "C: 4256\r\n"
1153 , endpoint);
1154
1155 if (len < 0)
1156 return;
1157
1158 buf[sizeof(buf) - 1] = '\0';
1159
Holger Hans Peter Freyther557b1ab2010-09-19 04:39:55 +08001160 send_trans(endp->cfg, buf, len);
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +08001161}
1162
Harald Welte6a857052012-01-27 00:41:39 +01001163static int send_agent(struct mgcp_config *cfg, const char *buf, int len)
1164{
1165 return write(cfg->gw_fd.bfd.fd, buf, len);
1166}
1167
1168int mgcp_send_reset_all(struct mgcp_config *cfg)
1169{
1170 static const char mgcp_reset[] = {
1171 "RSIP 1 *@mgw MGCP 1.0\r\n"
1172 };
1173
1174 return send_agent(cfg, mgcp_reset, sizeof mgcp_reset -1);
1175}
1176
1177int mgcp_send_reset_ep(struct mgcp_endpoint *endp, int endpoint)
1178{
1179 char buf[128];
1180 int len;
1181
1182 len = snprintf(buf, sizeof(buf),
1183 "RSIP 39 %x@mgw MGCP 1.0\r\n"
1184 , endpoint);
1185 if (len < 0)
1186 return len;
1187
1188 buf[sizeof(buf) - 1] = '\0';
1189
1190 return send_agent(endp->cfg, buf, len);
1191}
1192
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +08001193static void create_transcoder(struct mgcp_endpoint *endp)
1194{
1195 int port;
1196 int in_endp = ENDPOINT_NUMBER(endp);
Holger Hans Peter Freytherbd7b3c52010-11-01 21:04:54 +01001197 int out_endp = endp_back_channel(in_endp);
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +08001198
Pablo Neira Ayuso46bd4242013-07-08 05:09:46 +02001199 if (endp->type != MGCP_RTP_TRANSCODED)
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +08001200 return;
1201
Holger Hans Peter Freyther8b19dee2010-11-01 22:38:25 +01001202 send_msg(endp, in_endp, endp->trans_bts.local_port, "CRCX", "sendrecv");
1203 send_msg(endp, in_endp, endp->trans_bts.local_port, "MDCX", "sendrecv");
Holger Hans Peter Freyther21262332010-11-01 20:53:31 +01001204 send_msg(endp, out_endp, endp->trans_net.local_port, "CRCX", "sendrecv");
1205 send_msg(endp, out_endp, endp->trans_net.local_port, "MDCX", "sendrecv");
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +08001206
Holger Hans Peter Freytherbd7b3c52010-11-01 21:04:54 +01001207 port = rtp_calculate_port(in_endp, endp->cfg->transcoder_remote_base);
1208 endp->trans_bts.rtp_port = htons(port);
1209 endp->trans_bts.rtcp_port = htons(port + 1);
1210
Holger Hans Peter Freytherb98ba722010-09-19 04:21:39 +08001211 port = rtp_calculate_port(out_endp, endp->cfg->transcoder_remote_base);
Holger Hans Peter Freyther21262332010-11-01 20:53:31 +01001212 endp->trans_net.rtp_port = htons(port);
1213 endp->trans_net.rtcp_port = htons(port + 1);
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +08001214}
1215
1216static void delete_transcoder(struct mgcp_endpoint *endp)
1217{
1218 int in_endp = ENDPOINT_NUMBER(endp);
Holger Hans Peter Freytherbd7b3c52010-11-01 21:04:54 +01001219 int out_endp = endp_back_channel(in_endp);
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +08001220
Pablo Neira Ayuso46bd4242013-07-08 05:09:46 +02001221 if (endp->type != MGCP_RTP_TRANSCODED)
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +08001222 return;
1223
1224 send_dlcx(endp, in_endp);
1225 send_dlcx(endp, out_endp);
1226}
Holger Hans Peter Freytherf2eedff2010-09-19 04:36:07 +08001227
1228int mgcp_reset_transcoder(struct mgcp_config *cfg)
1229{
Holger Hans Peter Freytherf2eedff2010-09-19 04:36:07 +08001230 if (!cfg->transcoder_ip)
Holger Hans Peter Freythercf1c8772010-09-24 04:41:28 +08001231 return 0;
Holger Hans Peter Freytherf2eedff2010-09-19 04:36:07 +08001232
1233 static const char mgcp_reset[] = {
1234 "RSIP 1 13@mgw MGCP 1.0\r\n"
1235 };
1236
Holger Hans Peter Freyther557b1ab2010-09-19 04:39:55 +08001237 return send_trans(cfg, mgcp_reset, sizeof mgcp_reset -1);
Holger Hans Peter Freytherf2eedff2010-09-19 04:36:07 +08001238}
Holger Hans Peter Freyther0bf15a82012-09-14 17:18:12 +02001239
1240void mgcp_format_stats(struct mgcp_endpoint *endp, char *msg, size_t size)
1241{
Holger Hans Peter Freythercb306a62012-10-24 21:22:47 +02001242 uint32_t expected, jitter;
Holger Hans Peter Freyther38e02c52012-10-22 18:09:35 +02001243 int ploss;
Jacob Erlbeck50079a12013-11-25 12:53:28 +01001244 int nchars;
Holger Hans Peter Freyther38e02c52012-10-22 18:09:35 +02001245 mgcp_state_calc_loss(&endp->net_state, &endp->net_end,
1246 &expected, &ploss);
Holger Hans Peter Freythercb306a62012-10-24 21:22:47 +02001247 jitter = mgcp_state_calc_jitter(&endp->net_state);
Holger Hans Peter Freyther38e02c52012-10-22 18:09:35 +02001248
Jacob Erlbeck50079a12013-11-25 12:53:28 +01001249 nchars = snprintf(msg, size,
1250 "\r\nP: PS=%u, OS=%u, PR=%u, OR=%u, PL=%d, JI=%u",
1251 endp->bts_end.packets, endp->bts_end.octets,
1252 endp->net_end.packets, endp->net_end.octets,
1253 ploss, jitter);
1254 if (nchars < 0 || nchars >= size)
1255 goto truncate;
1256
1257 msg += nchars;
1258 size -= nchars;
1259
1260 /* Error Counter */
1261 snprintf(msg, size,
1262 "\r\nX-Osmo-CP: EC TIS=%u, TOS=%u, TIR=%u, TOR=%u",
1263 endp->net_state.in_stream.err_ts_counter,
1264 endp->net_state.out_stream.err_ts_counter,
1265 endp->bts_state.in_stream.err_ts_counter,
1266 endp->bts_state.out_stream.err_ts_counter);
1267truncate:
Holger Hans Peter Freyther0bf15a82012-09-14 17:18:12 +02001268 msg[size - 1] = '\0';
1269}
Holger Hans Peter Freyther462b7d72012-10-24 21:53:40 +02001270
1271int mgcp_parse_stats(struct msgb *msg, uint32_t *ps, uint32_t *os,
1272 uint32_t *pr, uint32_t *_or, int *loss, uint32_t *jitter)
1273{
1274 char *line, *save;
1275 int rc;
1276
1277 /* initialize with bad values */
1278 *ps = *os = *pr = *_or = *jitter = UINT_MAX;
1279 *loss = INT_MAX;
1280
1281
1282 line = strtok_r((char *) msg->l2h, "\r\n", &save);
1283 if (!line)
1284 return -1;
1285
1286 /* this can only parse the message that is created above... */
Jacob Erlbecka01bd602013-11-29 13:43:43 +01001287 for_each_non_empty_line(line, save) {
Holger Hans Peter Freyther462b7d72012-10-24 21:53:40 +02001288 switch (line[0]) {
1289 case 'P':
1290 rc = sscanf(line, "P: PS=%u, OS=%u, PR=%u, OR=%u, PL=%d, JI=%u",
1291 ps, os, pr, _or, loss, jitter);
1292 return rc == 6 ? 0 : -1;
1293 }
1294 }
1295
1296 return -1;
1297}