blob: 9996ba7f61823adf2eb5243336487634afd541af [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
Jacob Erlbeckf6ec0e92013-12-04 10:30:11 +010078#define DEFAULT_RTP_AUDIO_PACKET_DURATION_MS 20
Jacob Erlbeck72c30902013-11-25 15:23:35 +010079#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];
Jacob Erlbeck0a1bc562013-12-10 13:09:37 +0100233 int len;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100234
235 if (!addr)
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100236 addr = endp->cfg->source_addr;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100237
Jacob Erlbeck0a1bc562013-12-10 13:09:37 +0100238 len = snprintf(sdp_record, sizeof(sdp_record) - 1,
Holger Hans Peter Freyther46340132010-08-06 08:26:54 +0800239 "I: %u\n\n"
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100240 "v=0\r\n"
Holger Hans Peter Freytherc7e49d32011-07-20 20:43:15 +0200241 "o=- %u 23 IN IP4 %s\r\n"
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100242 "c=IN IP4 %s\r\n"
Holger Hans Peter Freytherc7e49d32011-07-20 20:43:15 +0200243 "t=0 0\r\n"
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100244 "m=audio %d RTP/AVP %d\r\n"
Holger Hans Peter Freyther5ea1bc72012-09-03 00:07:39 +0200245 "a=rtpmap:%d %s\r\n"
246 "%s%s",
Holger Hans Peter Freytherc7e49d32011-07-20 20:43:15 +0200247 endp->ci, endp->ci, addr, addr,
248 endp->net_end.local_port, endp->bts_end.payload_type,
Holger Hans Peter Freyther5ea1bc72012-09-03 00:07:39 +0200249 endp->bts_end.payload_type, endp->tcfg->audio_name,
250 fmtp_extra ? fmtp_extra : "", fmtp_extra ? "\r\n" : "");
Jacob Erlbeck0a1bc562013-12-10 13:09:37 +0100251
252 if (len < 0 || len >= sizeof(sdp_record))
253 goto buffer_too_small;
254
255 if (endp->bts_end.packet_duration_ms > 0 && endp->tcfg->audio_send_ptime) {
256 int nchars = snprintf(sdp_record + len, sizeof(sdp_record) - len,
257 "a=ptime:%d\r\n",
258 endp->bts_end.packet_duration_ms);
259 if (nchars < 0 || nchars >= sizeof(sdp_record) - len)
260 goto buffer_too_small;
261
262 len += nchars;
263 }
Holger Hans Peter Freythera769dcb2012-12-07 15:14:27 +0100264 return create_resp(endp, 200, " OK", msg, trans_id, NULL, sdp_record);
Jacob Erlbeck0a1bc562013-12-10 13:09:37 +0100265
266buffer_too_small:
267 LOGP(DMGCP, LOGL_ERROR, "SDP buffer too small: %d (needed %d)\n",
268 sizeof(sdp_record), len);
269 return NULL;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100270}
271
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100272/*
273 * handle incoming messages:
274 * - this can be a command (four letters, space, transaction id)
275 * - or a response (three numbers, space, transaction id)
276 */
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100277struct msgb *mgcp_handle_message(struct mgcp_config *cfg, struct msgb *msg)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100278{
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100279 struct mgcp_parse_data pdata;
280 int i, code, handled = 0;
Holger Hans Peter Freyther62e836c2010-02-03 11:03:45 +0100281 struct msgb *resp = NULL;
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100282 char *data;
Jacob Erlbeck9107e2d2013-12-03 17:14:44 +0100283 unsigned char *tail = msg->l2h + msgb_l2len(msg); /* char after l2 data */
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100284
Holger Hans Peter Freytherf36a11a2010-03-31 13:26:46 +0200285 if (msgb_l2len(msg) < 4) {
Holger Hans Peter Freyther0d904e02012-12-07 16:46:19 +0100286 LOGP(DMGCP, LOGL_ERROR, "msg too short: %d\n", msg->len);
Holger Hans Peter Freyther62e836c2010-02-03 11:03:45 +0100287 return NULL;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100288 }
289
Jacob Erlbeck9107e2d2013-12-03 17:14:44 +0100290 /* Ensure that the msg->l2h is NUL terminated. */
291 if (tail[-1] == '\0')
292 /* nothing to do */;
293 else if (msgb_tailroom(msg) > 0)
294 tail[0] = '\0';
295 else if (tail[-1] == '\r' || tail[-1] == '\n')
296 tail[-1] = '\0';
297 else {
298 LOGP(DMGCP, LOGL_ERROR, "Cannot NUL terminate MGCP message: "
299 "Length: %d, Buffer size: %d\n",
300 msgb_l2len(msg), msg->data_len);
301 return NULL;
302 }
303
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100304 /* attempt to treat it as a response */
Holger Hans Peter Freytherf36a11a2010-03-31 13:26:46 +0200305 if (sscanf((const char *)&msg->l2h[0], "%3d %*s", &code) == 1) {
Holger Hans Peter Freyther63f2db22010-02-26 13:30:57 +0100306 LOGP(DMGCP, LOGL_DEBUG, "Response: Code: %d\n", code);
Holger Hans Peter Freyther29de3462012-12-07 16:07:46 +0100307 return NULL;
308 }
309
310 msg->l3h = &msg->l2h[4];
311
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100312
313 /*
314 * Check for a duplicate message and respond.
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100315 */
316 memset(&pdata, 0, sizeof(pdata));
317 pdata.cfg = cfg;
Jacob Erlbeck17711712013-11-29 13:43:46 +0100318 data = strline_r((char *) msg->l3h, &pdata.save);
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100319 pdata.found = mgcp_analyze_header(&pdata, data);
320 if (pdata.endp && pdata.trans
321 && pdata.endp->last_trans
322 && strcmp(pdata.endp->last_trans, pdata.trans) == 0) {
323 return do_retransmission(pdata.endp);
324 }
325
Holger Hans Peter Freyther29de3462012-12-07 16:07:46 +0100326 for (i = 0; i < ARRAY_SIZE(mgcp_requests); ++i) {
327 if (strncmp(mgcp_requests[i].name, (const char *) &msg->l2h[0], 4) == 0) {
328 handled = 1;
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100329 resp = mgcp_requests[i].handle_request(&pdata);
Holger Hans Peter Freyther29de3462012-12-07 16:07:46 +0100330 break;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100331 }
332 }
333
Holger Hans Peter Freyther29de3462012-12-07 16:07:46 +0100334 if (!handled)
335 LOGP(DMGCP, LOGL_NOTICE, "MSG with type: '%.4s' not handled\n", &msg->l2h[0]);
336
Holger Hans Peter Freyther62e836c2010-02-03 11:03:45 +0100337 return resp;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100338}
339
Holger Hans Peter Freyther9f239a22011-01-06 19:32:52 +0100340/**
341 * We have a null terminated string with the endpoint name here. We only
342 * support two kinds. Simple ones as seen on the BSC level and the ones
343 * seen on the trunk side.
344 */
345static struct mgcp_endpoint *find_e1_endpoint(struct mgcp_config *cfg,
346 const char *mgcp)
347{
348 char *rest = NULL;
Holger Hans Peter Freyther74e61112011-02-28 14:13:47 +0100349 struct mgcp_trunk_config *tcfg;
350 int trunk, endp;
Holger Hans Peter Freyther9f239a22011-01-06 19:32:52 +0100351
352 trunk = strtoul(mgcp + 6, &rest, 10);
Holger Hans Peter Freytherf43f2fc2011-01-07 11:30:21 +0100353 if (rest == NULL || rest[0] != '/' || trunk < 1) {
Holger Hans Peter Freyther9f239a22011-01-06 19:32:52 +0100354 LOGP(DMGCP, LOGL_ERROR, "Wrong trunk name '%s'\n", mgcp);
355 return NULL;
356 }
357
358 endp = strtoul(rest + 1, &rest, 10);
359 if (rest == NULL || rest[0] != '@') {
Holger Hans Peter Freytherf43f2fc2011-01-07 11:30:21 +0100360 LOGP(DMGCP, LOGL_ERROR, "Wrong endpoint name '%s'\n", mgcp);
Holger Hans Peter Freyther9f239a22011-01-06 19:32:52 +0100361 return NULL;
362 }
363
364 /* signalling is on timeslot 1 */
365 if (endp == 1)
366 return NULL;
367
Holger Hans Peter Freyther74e61112011-02-28 14:13:47 +0100368 tcfg = mgcp_trunk_num(cfg, trunk);
369 if (!tcfg) {
370 LOGP(DMGCP, LOGL_ERROR, "The trunk %d is not declared.\n", trunk);
371 return NULL;
372 }
373
374 if (!tcfg->endpoints) {
375 LOGP(DMGCP, LOGL_ERROR, "Endpoints of trunk %d not allocated.\n", trunk);
376 return NULL;
377 }
378
379 if (endp < 1 || endp >= tcfg->number_endpoints) {
Holger Hans Peter Freyther9f239a22011-01-06 19:32:52 +0100380 LOGP(DMGCP, LOGL_ERROR, "Failed to find endpoint '%s'\n", mgcp);
Holger Hans Peter Freyther45c21842011-01-07 11:36:54 +0100381 return NULL;
Holger Hans Peter Freyther9f239a22011-01-06 19:32:52 +0100382 }
383
Holger Hans Peter Freyther74e61112011-02-28 14:13:47 +0100384 return &tcfg->endpoints[endp];
Holger Hans Peter Freyther9f239a22011-01-06 19:32:52 +0100385}
386
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100387static struct mgcp_endpoint *find_endpoint(struct mgcp_config *cfg, const char *mgcp)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100388{
389 char *endptr = NULL;
390 unsigned int gw = INT_MAX;
391
Holger Hans Peter Freyther9f239a22011-01-06 19:32:52 +0100392 if (strncmp(mgcp, "ds/e1", 5) == 0) {
393 return find_e1_endpoint(cfg, mgcp);
394 } else {
395 gw = strtoul(mgcp, &endptr, 16);
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +0100396 if (gw > 0 && gw < cfg->trunk.number_endpoints && strcmp(endptr, "@mgw") == 0)
397 return &cfg->trunk.endpoints[gw];
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100398 }
399
Holger Hans Peter Freyther9f239a22011-01-06 19:32:52 +0100400 LOGP(DMGCP, LOGL_ERROR, "Not able to find endpoint: '%s'\n", mgcp);
401 return NULL;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100402}
403
Harald Welteae199722012-01-27 12:31:36 +0100404/**
405 * @returns 0 when the status line was complete and transaction_id and
406 * endp out parameters are set.
407 */
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100408static int mgcp_analyze_header(struct mgcp_parse_data *pdata, char *data)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100409{
Harald Welteae199722012-01-27 12:31:36 +0100410 int i = 0;
Holger Hans Peter Freyther1eba7de2013-07-03 10:23:35 +0200411 char *elem, *save = NULL;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100412
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100413 pdata->trans = "000000";
Holger Hans Peter Freythera820c5f2010-02-26 13:32:55 +0100414
Harald Welteae199722012-01-27 12:31:36 +0100415 for (elem = strtok_r(data, " ", &save); elem;
416 elem = strtok_r(NULL, " ", &save)) {
417 switch (i) {
418 case 0:
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100419 pdata->trans = elem;
Harald Welteae199722012-01-27 12:31:36 +0100420 break;
421 case 1:
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100422 pdata->endp = find_endpoint(pdata->cfg, elem);
423 if (!pdata->endp) {
424 LOGP(DMGCP, LOGL_ERROR,
425 "Unable to find Endpoint `%s'\n", elem);
426 return -1;
Harald Welteae199722012-01-27 12:31:36 +0100427 }
428 break;
429 case 2:
430 if (strcmp("MGCP", elem)) {
431 LOGP(DMGCP, LOGL_ERROR,
432 "MGCP header parsing error\n");
433 return -1;
434 }
435 break;
436 case 3:
437 if (strcmp("1.0", elem)) {
438 LOGP(DMGCP, LOGL_ERROR, "MGCP version `%s' "
439 "not supported\n", elem);
440 return -1;
441 }
442 break;
443 }
444 i++;
445 }
446
447 if (i != 4) {
448 LOGP(DMGCP, LOGL_ERROR, "MGCP status line too short.\n");
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100449 pdata->trans = "000000";
450 pdata->endp = NULL;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100451 return -1;
452 }
453
Holger Hans Peter Freytherf2f15912010-04-01 03:27:04 +0200454 return 0;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100455}
456
457static int verify_call_id(const struct mgcp_endpoint *endp,
458 const char *callid)
459{
460 if (strcmp(endp->callid, callid) != 0) {
Holger Hans Peter Freyther2ada71d2010-02-03 09:13:10 +0100461 LOGP(DMGCP, LOGL_ERROR, "CallIDs does not match on 0x%x. '%s' != '%s'\n",
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100462 ENDPOINT_NUMBER(endp), endp->callid, callid);
463 return -1;
464 }
465
466 return 0;
467}
468
469static int verify_ci(const struct mgcp_endpoint *endp,
Holger Hans Peter Freyther46340132010-08-06 08:26:54 +0800470 const char *_ci)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100471{
Holger Hans Peter Freyther46340132010-08-06 08:26:54 +0800472 uint32_t ci = strtoul(_ci, NULL, 10);
473
474 if (ci != endp->ci) {
475 LOGP(DMGCP, LOGL_ERROR, "ConnectionIdentifiers do not match on 0x%x. %u != %s\n",
476 ENDPOINT_NUMBER(endp), endp->ci, _ci);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100477 return -1;
478 }
479
480 return 0;
481}
482
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100483static struct msgb *handle_audit_endpoint(struct mgcp_parse_data *p)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100484{
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100485 if (p->found != 0)
486 return create_err_response(NULL, 500, "AUEP", p->trans);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100487 else
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100488 return create_ok_response(p->endp, 200, "AUEP", p->trans);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100489}
490
Jacob Erlbeck2645c9e2013-12-19 12:23:24 +0100491static int parse_conn_mode(const char *msg, struct mgcp_endpoint *endp)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100492{
493 int ret = 0;
494 if (strcmp(msg, "recvonly") == 0)
Jacob Erlbeck2645c9e2013-12-19 12:23:24 +0100495 endp->conn_mode = MGCP_CONN_RECV_ONLY;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100496 else if (strcmp(msg, "sendrecv") == 0)
Jacob Erlbeck2645c9e2013-12-19 12:23:24 +0100497 endp->conn_mode = MGCP_CONN_RECV_SEND;
Holger Hans Peter Freythere02860a2010-09-18 20:21:44 +0800498 else if (strcmp(msg, "sendonly") == 0)
Jacob Erlbeck2645c9e2013-12-19 12:23:24 +0100499 endp->conn_mode = MGCP_CONN_SEND_ONLY;
Holger Hans Peter Freyther98a38772010-08-03 02:27:21 +0800500 else if (strcmp(msg, "loopback") == 0)
Jacob Erlbeck2645c9e2013-12-19 12:23:24 +0100501 endp->conn_mode = MGCP_CONN_LOOPBACK;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100502 else {
Holger Hans Peter Freyther2ada71d2010-02-03 09:13:10 +0100503 LOGP(DMGCP, LOGL_ERROR, "Unknown connection mode: '%s'\n", msg);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100504 ret = -1;
505 }
506
Jacob Erlbeck2645c9e2013-12-19 12:23:24 +0100507 switch (endp->conn_mode) {
508 case MGCP_CONN_NONE:
509 endp->net_end.output_enabled = 0;
510 endp->bts_end.output_enabled = 0;
511 break;
512
513 case MGCP_CONN_RECV_ONLY:
514 endp->net_end.output_enabled = 0;
515 endp->bts_end.output_enabled = 1;
516 break;
517
518 case MGCP_CONN_SEND_ONLY:
519 endp->net_end.output_enabled = 1;
520 endp->bts_end.output_enabled = 0;
521 break;
522
523 default:
524 endp->net_end.output_enabled = 1;
525 endp->bts_end.output_enabled = 1;
526 break;
527 }
528
529
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100530 return ret;
531}
532
Holger Hans Peter Freytherf138f912010-08-05 08:08:17 +0800533static int allocate_port(struct mgcp_endpoint *endp, struct mgcp_rtp_end *end,
Holger Hans Peter Freyther218f8562010-09-18 02:30:02 +0800534 struct mgcp_port_range *range,
535 int (*alloc)(struct mgcp_endpoint *endp, int port))
Holger Hans Peter Freytherf138f912010-08-05 08:08:17 +0800536{
537 int i;
538
539 if (range->mode == PORT_ALLOC_STATIC) {
Holger Hans Peter Freytherf138f912010-08-05 08:08:17 +0800540 end->local_alloc = PORT_ALLOC_STATIC;
541 return 0;
542 }
543
544 /* attempt to find a port */
545 for (i = 0; i < 200; ++i) {
546 int rc;
547
548 if (range->last_port >= range->range_end)
549 range->last_port = range->range_start;
550
Holger Hans Peter Freyther218f8562010-09-18 02:30:02 +0800551 rc = alloc(endp, range->last_port);
Holger Hans Peter Freytherf138f912010-08-05 08:08:17 +0800552
553 range->last_port += 2;
554 if (rc == 0) {
555 end->local_alloc = PORT_ALLOC_DYNAMIC;
556 return 0;
557 }
558
559 }
560
Holger Hans Peter Freyther218f8562010-09-18 02:30:02 +0800561 LOGP(DMGCP, LOGL_ERROR, "Allocating a RTP/RTCP port failed 200 times 0x%x.\n",
562 ENDPOINT_NUMBER(endp));
Holger Hans Peter Freytherf138f912010-08-05 08:08:17 +0800563 return -1;
564}
565
566static int allocate_ports(struct mgcp_endpoint *endp)
567{
Holger Hans Peter Freyther218f8562010-09-18 02:30:02 +0800568 if (allocate_port(endp, &endp->net_end, &endp->cfg->net_ports,
569 mgcp_bind_net_rtp_port) != 0)
Holger Hans Peter Freytherf138f912010-08-05 08:08:17 +0800570 return -1;
571
Holger Hans Peter Freyther218f8562010-09-18 02:30:02 +0800572 if (allocate_port(endp, &endp->bts_end, &endp->cfg->bts_ports,
573 mgcp_bind_bts_rtp_port) != 0) {
Holger Hans Peter Freytherf138f912010-08-05 08:08:17 +0800574 mgcp_rtp_end_reset(&endp->net_end);
575 return -1;
576 }
577
Holger Hans Peter Freyther69906872011-02-28 14:51:48 +0100578 if (endp->cfg->transcoder_ip && endp->tcfg->trunk_type == MGCP_TRUNK_VIRTUAL) {
Holger Hans Peter Freyther21262332010-11-01 20:53:31 +0100579 if (allocate_port(endp, &endp->trans_net,
Holger Hans Peter Freytherb54048f2010-11-01 19:57:50 +0100580 &endp->cfg->transcoder_ports,
Holger Hans Peter Freytherbd7b3c52010-11-01 21:04:54 +0100581 mgcp_bind_trans_net_rtp_port) != 0) {
Holger Hans Peter Freytherb54048f2010-11-01 19:57:50 +0100582 mgcp_rtp_end_reset(&endp->net_end);
583 mgcp_rtp_end_reset(&endp->bts_end);
584 return -1;
585 }
586
Holger Hans Peter Freytherbd7b3c52010-11-01 21:04:54 +0100587 if (allocate_port(endp, &endp->trans_bts,
588 &endp->cfg->transcoder_ports,
589 mgcp_bind_trans_bts_rtp_port) != 0) {
590 mgcp_rtp_end_reset(&endp->net_end);
591 mgcp_rtp_end_reset(&endp->bts_end);
592 mgcp_rtp_end_reset(&endp->trans_net);
593 return -1;
594 }
595
Holger Hans Peter Freytherb54048f2010-11-01 19:57:50 +0100596 /* remember that we have set up transcoding */
Pablo Neira Ayuso46bd4242013-07-08 05:09:46 +0200597 endp->type = MGCP_RTP_TRANSCODED;
Holger Hans Peter Freyther218f8562010-09-18 02:30:02 +0800598 }
599
Holger Hans Peter Freytherf138f912010-08-05 08:08:17 +0800600 return 0;
601}
602
Jacob Erlbeck17711712013-11-29 13:43:46 +0100603static int parse_sdp_data(struct mgcp_rtp_end *rtp, struct mgcp_parse_data *p)
604{
605 char *line;
606 int found_media = 0;
Jacob Erlbeck24754f02013-12-10 13:09:37 +0100607 int audio_payload = -1;
Jacob Erlbeck17711712013-11-29 13:43:46 +0100608
609 for_each_line(line, p->save) {
610 switch (line[0]) {
Jacob Erlbeck17711712013-11-29 13:43:46 +0100611 case 'o':
612 case 's':
613 case 't':
614 case 'v':
615 /* skip these SDP attributes */
616 break;
Jacob Erlbeck24754f02013-12-10 13:09:37 +0100617 case 'a': {
618 int payload;
619 int rate;
620 int channels = 1;
621 int ptime, ptime2 = 0;
622 char audio_name[64];
623 char audio_codec[64];
624
625 if (audio_payload == -1)
626 break;
627
628 if (sscanf(line, "a=rtpmap:%d %64s",
629 &payload, audio_name) == 2) {
630 if (payload != audio_payload)
631 break;
632
633 if (sscanf(audio_name, "%[^/]/%d/%d",
634 audio_codec, &rate, &channels) < 2)
635 break;
636
637 rtp->rate = rate;
638 if (channels != 1)
639 LOGP(DMGCP, LOGL_NOTICE,
640 "Channels != 1 in SDP: '%s' on 0x%x\n",
641 line, ENDPOINT_NUMBER(p->endp));
642 } else if (sscanf(line, "a=ptime:%d-%d",
643 &ptime, &ptime2) >= 1) {
644 if (ptime2 > 0 && ptime2 != ptime)
645 rtp->packet_duration_ms = 0;
646 else
647 rtp->packet_duration_ms = ptime;
648 } else if (sscanf(line, "a=maxptime:%d", &ptime2) == 1) {
649 if (ptime2 * rtp->frame_duration_den >
650 rtp->frame_duration_num * 1500)
651 /* more than 1 frame */
652 rtp->packet_duration_ms = 0;
653 }
654 break;
655 }
Jacob Erlbeck17711712013-11-29 13:43:46 +0100656 case 'm': {
657 int port;
Jacob Erlbeck24754f02013-12-10 13:09:37 +0100658 audio_payload = -1;
Jacob Erlbeck17711712013-11-29 13:43:46 +0100659
660 if (sscanf(line, "m=audio %d RTP/AVP %d",
Jacob Erlbeck24754f02013-12-10 13:09:37 +0100661 &port, &audio_payload) == 2) {
Jacob Erlbeck17711712013-11-29 13:43:46 +0100662 rtp->rtp_port = htons(port);
663 rtp->rtcp_port = htons(port + 1);
Jacob Erlbeck24754f02013-12-10 13:09:37 +0100664 rtp->payload_type = audio_payload;
Jacob Erlbeck17711712013-11-29 13:43:46 +0100665 found_media = 1;
666 }
667 break;
668 }
669 case 'c': {
670 char ipv4[16];
671
672 if (sscanf(line, "c=IN IP4 %15s", ipv4) == 1) {
673 inet_aton(ipv4, &rtp->addr);
674 }
675 break;
676 }
677 default:
678 if (p->endp)
679 LOGP(DMGCP, LOGL_NOTICE,
680 "Unhandled SDP option: '%c'/%d on 0x%x\n",
681 line[0], line[0], ENDPOINT_NUMBER(p->endp));
682 else
683 LOGP(DMGCP, LOGL_NOTICE,
684 "Unhandled SDP option: '%c'/%d\n",
685 line[0], line[0]);
686 break;
687 }
688 }
689
690 if (found_media)
691 LOGP(DMGCP, LOGL_NOTICE,
Jacob Erlbeck24754f02013-12-10 13:09:37 +0100692 "Got media info via SDP: port %d, payload %d, "
693 "duration %d, addr %s\n",
694 ntohs(rtp->rtp_port), rtp->payload_type,
695 rtp->packet_duration_ms, inet_ntoa(rtp->addr));
Jacob Erlbeck17711712013-11-29 13:43:46 +0100696
697 return found_media;
698}
699
Jacob Erlbeck2c2ca4d2013-12-09 14:32:03 +0100700/* Set the LCO from a string (see RFC 3435).
701 * The string is stored in the 'string' field. A NULL string is handled excatly
702 * like an empty string, the 'string' field is never NULL after this function
703 * has been called. */
704static void set_local_cx_options(void *ctx, struct mgcp_lco *lco,
705 const char *options)
706{
707 char *p_opt;
708
709 talloc_free(lco->string);
710 lco->pkt_period_min = lco->pkt_period_max = 0;
711 lco->string = talloc_strdup(ctx, options ? options : "");
712
713 p_opt = strstr(lco->string, "p:");
714 if (p_opt && sscanf(p_opt, "p:%d-%d",
715 &lco->pkt_period_min, &lco->pkt_period_max) == 1)
716 lco->pkt_period_max = lco->pkt_period_min;
717}
718
Jacob Erlbeckdb2d4312013-12-03 14:43:34 +0100719void mgcp_rtp_end_config(struct mgcp_endpoint *endp, int expect_ssrc_change,
720 struct mgcp_rtp_end *rtp)
721{
722 struct mgcp_trunk_config *tcfg = endp->tcfg;
723
Jacob Erlbecke2292f32013-12-03 15:13:12 +0100724 int patch_ssrc = expect_ssrc_change && tcfg->force_constant_ssrc;
725
Jacob Erlbeck4bbddc62013-12-18 12:54:51 +0100726 rtp->force_aligned_timing = tcfg->force_aligned_timing;
Jacob Erlbecke2292f32013-12-03 15:13:12 +0100727 rtp->force_constant_ssrc = patch_ssrc ? 1 : 0;
Jacob Erlbeckdb2d4312013-12-03 14:43:34 +0100728
729 LOGP(DMGCP, LOGL_DEBUG,
730 "Configuring RTP endpoint: local port %d%s%s\n",
731 ntohs(rtp->rtp_port),
Jacob Erlbeck4bbddc62013-12-18 12:54:51 +0100732 rtp->force_aligned_timing ? ", force constant timing" : "",
Jacob Erlbeckdb2d4312013-12-03 14:43:34 +0100733 rtp->force_constant_ssrc ? ", force constant ssrc" : "");
734}
735
Jacob Erlbeckf6ec0e92013-12-04 10:30:11 +0100736uint32_t mgcp_rtp_packet_duration(struct mgcp_endpoint *endp,
737 struct mgcp_rtp_end *rtp)
738{
739 int f = 0;
740
741 /* Get the number of frames per channel and packet */
742 if (rtp->frames_per_packet)
743 f = rtp->frames_per_packet;
744 else if (rtp->packet_duration_ms && rtp->frame_duration_num) {
745 int den = 1000 * rtp->frame_duration_num;
746 f = (rtp->packet_duration_ms * rtp->frame_duration_den + den/2)
747 / den;
748 }
749
750 return rtp->rate * f * rtp->frame_duration_num / rtp->frame_duration_den;
751}
752
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100753static struct msgb *handle_create_con(struct mgcp_parse_data *p)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100754{
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +0100755 struct mgcp_trunk_config *tcfg;
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100756 struct mgcp_endpoint *endp = p->endp;
Holger Hans Peter Freyther9e9392d2010-08-08 16:24:48 +0800757 int error_code = 400;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100758
Holger Hans Peter Freyther3488c3d2011-07-20 20:44:54 +0200759 const char *local_options = NULL;
760 const char *callid = NULL;
761 const char *mode = NULL;
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100762 char *line;
Jacob Erlbeck78a95012013-11-29 13:43:49 +0100763 int have_sdp = 0;
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100764
765 if (p->found != 0)
766 return create_err_response(NULL, 510, "CRCX", p->trans);
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +0100767
Holger Hans Peter Freyther3488c3d2011-07-20 20:44:54 +0200768 /* parse CallID C: and LocalParameters L: */
Jacob Erlbeck17711712013-11-29 13:43:46 +0100769 for_each_line(line, p->save) {
Harald Welteae199722012-01-27 12:31:36 +0100770 switch (line[0]) {
771 case 'L':
772 local_options = (const char *) line + 3;
773 break;
774 case 'C':
775 callid = (const char *) line + 3;
776 break;
777 case 'M':
778 mode = (const char *) line + 3;
779 break;
Jacob Erlbeck78a95012013-11-29 13:43:49 +0100780 case '\0':
781 have_sdp = 1;
782 goto mgcp_header_done;
Harald Welteae199722012-01-27 12:31:36 +0100783 default:
784 LOGP(DMGCP, LOGL_NOTICE, "Unhandled option: '%c'/%d on 0x%x\n",
785 *line, *line, ENDPOINT_NUMBER(endp));
786 break;
787 }
Holger Hans Peter Freyther3488c3d2011-07-20 20:44:54 +0200788 }
Harald Welteae199722012-01-27 12:31:36 +0100789
Jacob Erlbeck78a95012013-11-29 13:43:49 +0100790mgcp_header_done:
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100791 tcfg = p->endp->tcfg;
Holger Hans Peter Freyther3488c3d2011-07-20 20:44:54 +0200792
793 /* Check required data */
794 if (!callid || !mode) {
795 LOGP(DMGCP, LOGL_ERROR, "Missing callid and mode in CRCX on 0x%x\n",
796 ENDPOINT_NUMBER(endp));
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100797 return create_err_response(endp, 400, "CRCX", p->trans);
Holger Hans Peter Freyther3488c3d2011-07-20 20:44:54 +0200798 }
799
Holger Hans Peter Freyther39a97e22010-08-06 18:03:11 +0800800 if (endp->allocated) {
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +0100801 if (tcfg->force_realloc) {
Holger Hans Peter Freyther408cc4a2010-04-07 10:51:27 +0200802 LOGP(DMGCP, LOGL_NOTICE, "Endpoint 0x%x already allocated. Forcing realloc.\n",
803 ENDPOINT_NUMBER(endp));
Holger Hans Peter Freyther32d4e502010-04-24 21:02:48 +0800804 mgcp_free_endp(endp);
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100805 if (p->cfg->realloc_cb)
806 p->cfg->realloc_cb(tcfg, ENDPOINT_NUMBER(endp));
Holger Hans Peter Freyther408cc4a2010-04-07 10:51:27 +0200807 } else {
808 LOGP(DMGCP, LOGL_ERROR, "Endpoint is already used. 0x%x\n",
809 ENDPOINT_NUMBER(endp));
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100810 return create_err_response(endp, 400, "CRCX", p->trans);
Holger Hans Peter Freyther408cc4a2010-04-07 10:51:27 +0200811 }
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100812 }
813
Holger Hans Peter Freyther3488c3d2011-07-20 20:44:54 +0200814 /* copy some parameters */
815 endp->callid = talloc_strdup(tcfg->endpoints, callid);
816
Jacob Erlbeck2c2ca4d2013-12-09 14:32:03 +0100817 set_local_cx_options(endp->tcfg->endpoints, &endp->local_options,
818 local_options);
Holger Hans Peter Freyther3488c3d2011-07-20 20:44:54 +0200819
Jacob Erlbeck2645c9e2013-12-19 12:23:24 +0100820 if (parse_conn_mode(mode, endp) != 0) {
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100821 error_code = 517;
822 goto error2;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100823 }
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100824
825 /* initialize */
Holger Hans Peter Freythera17d7012010-08-05 01:34:51 +0800826 endp->net_end.rtp_port = endp->net_end.rtcp_port = endp->bts_end.rtp_port = endp->bts_end.rtcp_port = 0;
Jacob Erlbeckdb2d4312013-12-03 14:43:34 +0100827 mgcp_rtp_end_config(endp, 0, &endp->net_end);
828 mgcp_rtp_end_config(endp, 0, &endp->bts_end);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100829
830 /* set to zero until we get the info */
Holger Hans Peter Freythera17d7012010-08-05 01:34:51 +0800831 memset(&endp->net_end.addr, 0, sizeof(endp->net_end.addr));
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100832
833 /* bind to the port now */
Holger Hans Peter Freytherf138f912010-08-05 08:08:17 +0800834 if (allocate_ports(endp) != 0)
835 goto error2;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100836
837 /* assign a local call identifier or fail */
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100838 endp->ci = generate_call_id(p->cfg);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100839 if (endp->ci == CI_UNUSED)
840 goto error2;
841
Holger Hans Peter Freyther39a97e22010-08-06 18:03:11 +0800842 endp->allocated = 1;
Jacob Erlbeck78a95012013-11-29 13:43:49 +0100843
844 /* set up RTP media parameters */
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +0100845 endp->bts_end.payload_type = tcfg->audio_payload;
Holger Hans Peter Freyther5ea1bc72012-09-03 00:07:39 +0200846 endp->bts_end.fmtp_extra = talloc_strdup(tcfg->endpoints,
847 tcfg->audio_fmtp_extra);
Jacob Erlbeck78a95012013-11-29 13:43:49 +0100848 if (have_sdp)
849 parse_sdp_data(&endp->net_end, p);
Holger Hans Peter Freytheref6bb252010-02-26 13:41:22 +0100850
Holger Hans Peter Freytherfe86d3c2010-02-26 13:37:05 +0100851 /* policy CB */
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100852 if (p->cfg->policy_cb) {
853 int rc;
854 rc = p->cfg->policy_cb(tcfg, ENDPOINT_NUMBER(endp),
855 MGCP_ENDP_CRCX, p->trans);
856 switch (rc) {
Holger Hans Peter Freytherfe86d3c2010-02-26 13:37:05 +0100857 case MGCP_POLICY_REJECT:
858 LOGP(DMGCP, LOGL_NOTICE, "CRCX rejected by policy on 0x%x\n",
859 ENDPOINT_NUMBER(endp));
860 mgcp_free_endp(endp);
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100861 return create_err_response(endp, 400, "CRCX", p->trans);
Holger Hans Peter Freytherfe86d3c2010-02-26 13:37:05 +0100862 break;
863 case MGCP_POLICY_DEFER:
864 /* stop processing */
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +0800865 create_transcoder(endp);
Holger Hans Peter Freytherfe86d3c2010-02-26 13:37:05 +0100866 return NULL;
867 break;
868 case MGCP_POLICY_CONT:
869 /* just continue */
870 break;
871 }
872 }
873
Holger Hans Peter Freythere378cb12010-08-06 20:22:23 +0800874 LOGP(DMGCP, LOGL_DEBUG, "Creating endpoint on: 0x%x CI: %u port: %u/%u\n",
Holger Hans Peter Freyther58ff2192010-08-05 03:08:35 +0800875 ENDPOINT_NUMBER(endp), endp->ci,
876 endp->net_end.local_port, endp->bts_end.local_port);
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100877 if (p->cfg->change_cb)
878 p->cfg->change_cb(tcfg, ENDPOINT_NUMBER(endp), MGCP_ENDP_CRCX);
Holger Hans Peter Freyther77f7afe2010-02-03 09:54:43 +0100879
Jacob Erlbeck075a9eb2013-12-19 18:53:07 +0100880 if (endp->bts_end.output_enabled && tcfg->keepalive_interval != 0)
881 mgcp_send_dummy(endp);
882
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +0800883 create_transcoder(endp);
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100884 return create_response_with_sdp(endp, "CRCX", p->trans);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100885error2:
Holger Hans Peter Freyther414bf402010-08-06 07:05:13 +0800886 mgcp_free_endp(endp);
Holger Hans Peter Freyther2ada71d2010-02-03 09:13:10 +0100887 LOGP(DMGCP, LOGL_NOTICE, "Resource error on 0x%x\n", ENDPOINT_NUMBER(endp));
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100888 return create_err_response(endp, error_code, "CRCX", p->trans);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100889}
890
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100891static struct msgb *handle_modify_con(struct mgcp_parse_data *p)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100892{
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100893 struct mgcp_endpoint *endp = p->endp;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100894 int error_code = 500;
Holger Hans Peter Freythere3d16bb2010-04-22 11:58:13 +0800895 int silent = 0;
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100896 char *line;
Jacob Erlbeck2c2ca4d2013-12-09 14:32:03 +0100897 const char *local_options = NULL;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100898
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100899 if (p->found != 0)
900 return create_err_response(NULL, 510, "MDCX", p->trans);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100901
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100902 if (endp->ci == CI_UNUSED) {
903 LOGP(DMGCP, LOGL_ERROR, "Endpoint is not "
904 "holding a connection. 0x%x\n", ENDPOINT_NUMBER(endp));
905 return create_err_response(endp, 400, "MDCX", p->trans);
906 }
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100907
Jacob Erlbeck17711712013-11-29 13:43:46 +0100908 for_each_line(line, p->save) {
Harald Welteae199722012-01-27 12:31:36 +0100909 switch (line[0]) {
910 case 'C': {
911 if (verify_call_id(endp, line + 3) != 0)
912 goto error3;
913 break;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100914 }
Harald Welteae199722012-01-27 12:31:36 +0100915 case 'I': {
916 if (verify_ci(endp, line + 3) != 0)
917 goto error3;
918 break;
919 }
920 case 'L':
Jacob Erlbeck2c2ca4d2013-12-09 14:32:03 +0100921 local_options = (const char *) line + 3;
Harald Welteae199722012-01-27 12:31:36 +0100922 break;
923 case 'M':
Jacob Erlbeck2645c9e2013-12-19 12:23:24 +0100924 if (parse_conn_mode(line + 3, endp) != 0) {
Harald Welteae199722012-01-27 12:31:36 +0100925 error_code = 517;
926 goto error3;
927 }
928 endp->orig_mode = endp->conn_mode;
929 break;
930 case 'Z':
931 silent = strcmp("noanswer", line + 3) == 0;
932 break;
933 case '\0':
934 /* SDP file begins */
Jacob Erlbeck17711712013-11-29 13:43:46 +0100935 parse_sdp_data(&endp->net_end, p);
936 /* This will exhaust p->save, so the loop will
937 * terminate next time.
938 */
Harald Welteae199722012-01-27 12:31:36 +0100939 break;
Harald Welteae199722012-01-27 12:31:36 +0100940 default:
Jacob Erlbeck17711712013-11-29 13:43:46 +0100941 LOGP(DMGCP, LOGL_NOTICE, "Unhandled MGCP option: '%c'/%d on 0x%x\n",
Harald Welteae199722012-01-27 12:31:36 +0100942 line[0], line[0], ENDPOINT_NUMBER(endp));
943 break;
944 }
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100945 }
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100946
Jacob Erlbeck2c2ca4d2013-12-09 14:32:03 +0100947 set_local_cx_options(endp->tcfg->endpoints, &endp->local_options,
948 local_options);
949
Holger Hans Peter Freytherfe86d3c2010-02-26 13:37:05 +0100950 /* policy CB */
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100951 if (p->cfg->policy_cb) {
952 int rc;
953 rc = p->cfg->policy_cb(endp->tcfg, ENDPOINT_NUMBER(endp),
954 MGCP_ENDP_MDCX, p->trans);
955 switch (rc) {
Holger Hans Peter Freytherfe86d3c2010-02-26 13:37:05 +0100956 case MGCP_POLICY_REJECT:
957 LOGP(DMGCP, LOGL_NOTICE, "MDCX rejected by policy on 0x%x\n",
958 ENDPOINT_NUMBER(endp));
Holger Hans Peter Freythere3d16bb2010-04-22 11:58:13 +0800959 if (silent)
960 goto out_silent;
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100961 return create_err_response(endp, 400, "MDCX", p->trans);
Holger Hans Peter Freytherfe86d3c2010-02-26 13:37:05 +0100962 break;
963 case MGCP_POLICY_DEFER:
964 /* stop processing */
965 return NULL;
966 break;
967 case MGCP_POLICY_CONT:
968 /* just continue */
969 break;
970 }
971 }
972
Jacob Erlbeckdb2d4312013-12-03 14:43:34 +0100973 mgcp_rtp_end_config(endp, 1, &endp->net_end);
974 mgcp_rtp_end_config(endp, 1, &endp->bts_end);
975
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100976 /* modify */
Holger Hans Peter Freythere378cb12010-08-06 20:22:23 +0800977 LOGP(DMGCP, LOGL_DEBUG, "Modified endpoint on: 0x%x Server: %s:%u\n",
Holger Hans Peter Freythera17d7012010-08-05 01:34:51 +0800978 ENDPOINT_NUMBER(endp), inet_ntoa(endp->net_end.addr), ntohs(endp->net_end.rtp_port));
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100979 if (p->cfg->change_cb)
980 p->cfg->change_cb(endp->tcfg, ENDPOINT_NUMBER(endp), MGCP_ENDP_MDCX);
Jacob Erlbeck075a9eb2013-12-19 18:53:07 +0100981
982 if (endp->bts_end.output_enabled && endp->tcfg->keepalive_interval != 0)
983 mgcp_send_dummy(endp);
984
Holger Hans Peter Freythere3d16bb2010-04-22 11:58:13 +0800985 if (silent)
986 goto out_silent;
987
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100988 return create_response_with_sdp(endp, "MDCX", p->trans);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100989
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100990error3:
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100991 return create_err_response(endp, error_code, "MDCX", p->trans);
Holger Hans Peter Freythere3d16bb2010-04-22 11:58:13 +0800992
993
994out_silent:
995 return NULL;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100996}
997
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100998static struct msgb *handle_delete_con(struct mgcp_parse_data *p)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100999{
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +01001000 struct mgcp_endpoint *endp = p->endp;
Holger Hans Peter Freyther9e9392d2010-08-08 16:24:48 +08001001 int error_code = 400;
Holger Hans Peter Freythere3d16bb2010-04-22 11:58:13 +08001002 int silent = 0;
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +01001003 char *line;
Holger Hans Peter Freyther0bf15a82012-09-14 17:18:12 +02001004 char stats[1048];
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +01001005
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +01001006 if (p->found != 0)
1007 return create_err_response(NULL, error_code, "DLCX", p->trans);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +01001008
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +01001009 if (!p->endp->allocated) {
1010 LOGP(DMGCP, LOGL_ERROR, "Endpoint is not used. 0x%x\n",
1011 ENDPOINT_NUMBER(endp));
1012 return create_err_response(endp, 400, "DLCX", p->trans);
1013 }
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +01001014
Jacob Erlbeck17711712013-11-29 13:43:46 +01001015 for_each_line(line, p->save) {
Harald Welteae199722012-01-27 12:31:36 +01001016 switch (line[0]) {
1017 case 'C':
1018 if (verify_call_id(endp, line + 3) != 0)
1019 goto error3;
1020 break;
1021 case 'I':
1022 if (verify_ci(endp, line + 3) != 0)
1023 goto error3;
1024 break;
1025 case 'Z':
1026 silent = strcmp("noanswer", line + 3) == 0;
1027 break;
1028 default:
1029 LOGP(DMGCP, LOGL_NOTICE, "Unhandled option: '%c'/%d on 0x%x\n",
1030 line[0], line[0], ENDPOINT_NUMBER(endp));
1031 break;
1032 }
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +01001033 }
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +01001034
Holger Hans Peter Freytherfe86d3c2010-02-26 13:37:05 +01001035 /* policy CB */
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +01001036 if (p->cfg->policy_cb) {
1037 int rc;
1038 rc = p->cfg->policy_cb(endp->tcfg, ENDPOINT_NUMBER(endp),
1039 MGCP_ENDP_DLCX, p->trans);
1040 switch (rc) {
Holger Hans Peter Freytherfe86d3c2010-02-26 13:37:05 +01001041 case MGCP_POLICY_REJECT:
1042 LOGP(DMGCP, LOGL_NOTICE, "DLCX rejected by policy on 0x%x\n",
1043 ENDPOINT_NUMBER(endp));
Holger Hans Peter Freythere3d16bb2010-04-22 11:58:13 +08001044 if (silent)
1045 goto out_silent;
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +01001046 return create_err_response(endp, 400, "DLCX", p->trans);
Holger Hans Peter Freytherfe86d3c2010-02-26 13:37:05 +01001047 break;
1048 case MGCP_POLICY_DEFER:
1049 /* stop processing */
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +08001050 delete_transcoder(endp);
Holger Hans Peter Freytherfe86d3c2010-02-26 13:37:05 +01001051 return NULL;
1052 break;
1053 case MGCP_POLICY_CONT:
1054 /* just continue */
1055 break;
1056 }
1057 }
1058
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +01001059 /* free the connection */
Holger Hans Peter Freythere378cb12010-08-06 20:22:23 +08001060 LOGP(DMGCP, LOGL_DEBUG, "Deleted endpoint on: 0x%x Server: %s:%u\n",
Holger Hans Peter Freythera17d7012010-08-05 01:34:51 +08001061 ENDPOINT_NUMBER(endp), inet_ntoa(endp->net_end.addr), ntohs(endp->net_end.rtp_port));
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +08001062
Holger Hans Peter Freyther0bf15a82012-09-14 17:18:12 +02001063 /* save the statistics of the current call */
1064 mgcp_format_stats(endp, stats, sizeof(stats));
1065
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +08001066 delete_transcoder(endp);
Holger Hans Peter Freyther154b9552010-02-26 13:27:51 +01001067 mgcp_free_endp(endp);
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +01001068 if (p->cfg->change_cb)
1069 p->cfg->change_cb(endp->tcfg, ENDPOINT_NUMBER(endp), MGCP_ENDP_DLCX);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +01001070
Holger Hans Peter Freythere3d16bb2010-04-22 11:58:13 +08001071 if (silent)
1072 goto out_silent;
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +01001073 return create_ok_resp_with_param(endp, 250, "DLCX", p->trans, stats);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +01001074
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +01001075error3:
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +01001076 return create_err_response(endp, error_code, "DLCX", p->trans);
Holger Hans Peter Freythere3d16bb2010-04-22 11:58:13 +08001077
1078out_silent:
1079 return NULL;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +01001080}
1081
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +01001082static struct msgb *handle_rsip(struct mgcp_parse_data *p)
Holger Hans Peter Freyther9bdcc9c2010-03-31 06:39:35 +02001083{
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +01001084 if (p->found != 0) {
Holger Hans Peter Freyther74db7742011-06-10 00:04:55 +02001085 LOGP(DMGCP, LOGL_ERROR, "Failed to find the endpoint.\n");
1086 return NULL;
1087 }
1088
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +01001089 if (p->cfg->reset_cb)
1090 p->cfg->reset_cb(p->endp->tcfg);
Holger Hans Peter Freyther9bdcc9c2010-03-31 06:39:35 +02001091 return NULL;
1092}
1093
Holger Hans Peter Freyther8d0be252012-11-29 12:54:22 +01001094static char extract_tone(const char *line)
1095{
1096 const char *str = strstr(line, "D/");
1097 if (!str)
1098 return CHAR_MAX;
1099
1100 return str[2];
1101}
1102
Holger Hans Peter Freyther6e94d6d2011-01-25 23:33:54 +01001103/*
1104 * This can request like DTMF detection and forward, fax detection... it
1105 * can also request when the notification should be send and such. We don't
1106 * do this right now.
1107 */
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +01001108static struct msgb *handle_noti_req(struct mgcp_parse_data *p)
Holger Hans Peter Freyther6e94d6d2011-01-25 23:33:54 +01001109{
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +01001110 int res = 0;
1111 char *line;
Holger Hans Peter Freyther9f3835b2013-05-21 17:04:35 +02001112 char tone = CHAR_MAX;
Holger Hans Peter Freyther6e94d6d2011-01-25 23:33:54 +01001113
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +01001114 if (p->found != 0)
1115 return create_err_response(NULL, 400, "RQNT", p->trans);
Holger Hans Peter Freyther6e94d6d2011-01-25 23:33:54 +01001116
Jacob Erlbeck17711712013-11-29 13:43:46 +01001117 for_each_line(line, p->save) {
Holger Hans Peter Freyther8d0be252012-11-29 12:54:22 +01001118 switch (line[0]) {
1119 case 'S':
1120 tone = extract_tone(line);
1121 break;
1122 }
Holger Hans Peter Freyther6e94d6d2011-01-25 23:33:54 +01001123 }
Holger Hans Peter Freyther8d0be252012-11-29 12:54:22 +01001124
1125 /* we didn't see a signal request with a tone */
1126 if (tone == CHAR_MAX)
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +01001127 return create_ok_response(p->endp, 200, "RQNT", p->trans);
Holger Hans Peter Freyther8d0be252012-11-29 12:54:22 +01001128
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +01001129 if (p->cfg->rqnt_cb)
1130 res = p->cfg->rqnt_cb(p->endp, tone);
Holger Hans Peter Freyther8d0be252012-11-29 12:54:22 +01001131
1132 return res == 0 ?
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +01001133 create_ok_response(p->endp, 200, "RQNT", p->trans) :
1134 create_err_response(p->endp, res, "RQNT", p->trans);
Holger Hans Peter Freyther6e94d6d2011-01-25 23:33:54 +01001135}
1136
Jacob Erlbeck075a9eb2013-12-19 18:53:07 +01001137static void mgcp_keepalive_timer_cb(void *_tcfg)
1138{
1139 struct mgcp_trunk_config *tcfg = _tcfg;
1140 int i;
1141 LOGP(DMGCP, LOGL_DEBUG, "Triggered trunk %d keepalive timer.\n",
1142 tcfg->trunk_nr);
1143
1144 if (tcfg->keepalive_interval <= 0)
1145 return;
1146
1147 for (i = 1; i < tcfg->number_endpoints; ++i) {
1148 struct mgcp_endpoint *endp = &tcfg->endpoints[i];
1149 if (endp->conn_mode == MGCP_CONN_RECV_ONLY)
1150 mgcp_send_dummy(endp);
1151 }
1152
1153 LOGP(DMGCP, LOGL_DEBUG, "Rescheduling trunk %d keepalive timer.\n",
1154 tcfg->trunk_nr);
1155 osmo_timer_schedule(&tcfg->keepalive_timer, tcfg->keepalive_interval, 0);
1156}
1157
1158void mgcp_trunk_set_keepalive(struct mgcp_trunk_config *tcfg, int interval)
1159{
1160 tcfg->keepalive_interval = interval;
1161 tcfg->keepalive_timer.data = tcfg;
1162 tcfg->keepalive_timer.cb = mgcp_keepalive_timer_cb;
1163
1164 if (interval <= 0)
1165 osmo_timer_del(&tcfg->keepalive_timer);
1166 else
1167 osmo_timer_schedule(&tcfg->keepalive_timer,
1168 tcfg->keepalive_interval, 0);
1169}
1170
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +01001171struct mgcp_config *mgcp_config_alloc(void)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +01001172{
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +01001173 struct mgcp_config *cfg;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +01001174
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +01001175 cfg = talloc_zero(NULL, struct mgcp_config);
1176 if (!cfg) {
1177 LOGP(DMGCP, LOGL_FATAL, "Failed to allocate config.\n");
1178 return NULL;
1179 }
1180
1181 cfg->source_port = 2427;
1182 cfg->source_addr = talloc_strdup(cfg, "0.0.0.0");
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +01001183
Holger Hans Peter Freytherb98ba722010-09-19 04:21:39 +08001184 cfg->transcoder_remote_base = 4000;
Holger Hans Peter Freyther15e73892010-08-05 07:10:56 +08001185
1186 cfg->bts_ports.base_port = RTP_PORT_DEFAULT;
1187 cfg->net_ports.base_port = RTP_PORT_NET_DEFAULT;
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +01001188
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +01001189 /* default trunk handling */
1190 cfg->trunk.cfg = cfg;
1191 cfg->trunk.trunk_nr = 0;
1192 cfg->trunk.trunk_type = MGCP_TRUNK_VIRTUAL;
1193 cfg->trunk.audio_name = talloc_strdup(cfg, "AMR/8000");
1194 cfg->trunk.audio_payload = 126;
Jacob Erlbeck0a1bc562013-12-10 13:09:37 +01001195 cfg->trunk.audio_send_ptime = 1;
Holger Hans Peter Freythera8090d52012-05-11 13:00:45 +02001196 cfg->trunk.omit_rtcp = 0;
Jacob Erlbeck075a9eb2013-12-19 18:53:07 +01001197 mgcp_trunk_set_keepalive(&cfg->trunk, MGCP_KEEPALIVE_ONCE);
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +01001198
Holger Hans Peter Freyther0e939fe2011-02-28 12:11:02 +01001199 INIT_LLIST_HEAD(&cfg->trunks);
1200
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +01001201 return cfg;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +01001202}
1203
Holger Hans Peter Freyther0e939fe2011-02-28 12:11:02 +01001204struct mgcp_trunk_config *mgcp_trunk_alloc(struct mgcp_config *cfg, int nr)
1205{
1206 struct mgcp_trunk_config *trunk;
1207
1208 trunk = talloc_zero(cfg, struct mgcp_trunk_config);
1209 if (!trunk) {
1210 LOGP(DMGCP, LOGL_ERROR, "Failed to allocate.\n");
1211 return NULL;
1212 }
1213
1214 trunk->cfg = cfg;
1215 trunk->trunk_type = MGCP_TRUNK_E1;
1216 trunk->trunk_nr = nr;
1217 trunk->audio_name = talloc_strdup(cfg, "AMR/8000");
1218 trunk->audio_payload = 126;
Jacob Erlbeck0a1bc562013-12-10 13:09:37 +01001219 trunk->audio_send_ptime = 1;
Holger Hans Peter Freyther0e939fe2011-02-28 12:11:02 +01001220 trunk->number_endpoints = 33;
Holger Hans Peter Freythera8090d52012-05-11 13:00:45 +02001221 trunk->omit_rtcp = 0;
Jacob Erlbeck075a9eb2013-12-19 18:53:07 +01001222 mgcp_trunk_set_keepalive(trunk, MGCP_KEEPALIVE_ONCE);
Holger Hans Peter Freyther0e939fe2011-02-28 12:11:02 +01001223 llist_add_tail(&trunk->entry, &cfg->trunks);
1224 return trunk;
1225}
1226
1227struct mgcp_trunk_config *mgcp_trunk_num(struct mgcp_config *cfg, int index)
1228{
1229 struct mgcp_trunk_config *trunk;
1230
1231 llist_for_each_entry(trunk, &cfg->trunks, entry)
1232 if (trunk->trunk_nr == index)
1233 return trunk;
1234
1235 return NULL;
1236}
1237
Holger Hans Peter Freythera17d7012010-08-05 01:34:51 +08001238static void mgcp_rtp_end_reset(struct mgcp_rtp_end *end)
1239{
Holger Hans Peter Freythere97155a2010-11-02 19:06:13 +01001240 if (end->local_alloc == PORT_ALLOC_DYNAMIC) {
Holger Hans Peter Freytherf138f912010-08-05 08:08:17 +08001241 mgcp_free_rtp_port(end);
Holger Hans Peter Freythere97155a2010-11-02 19:06:13 +01001242 end->local_port = 0;
1243 }
Holger Hans Peter Freytherf138f912010-08-05 08:08:17 +08001244
Holger Hans Peter Freytherc4921272010-08-05 03:37:22 +08001245 end->packets = 0;
Holger Hans Peter Freyther952f7522012-09-12 11:38:37 +02001246 end->octets = 0;
Jacob Erlbeck0970bab2013-12-19 12:13:32 +01001247 end->dropped_packets = 0;
Holger Hans Peter Freytherc4921272010-08-05 03:37:22 +08001248 memset(&end->addr, 0, sizeof(end->addr));
Holger Hans Peter Freythere97155a2010-11-02 19:06:13 +01001249 end->rtp_port = end->rtcp_port = 0;
Holger Hans Peter Freythera17d7012010-08-05 01:34:51 +08001250 end->payload_type = -1;
Holger Hans Peter Freytherf138f912010-08-05 08:08:17 +08001251 end->local_alloc = -1;
Holger Hans Peter Freyther5ea1bc72012-09-03 00:07:39 +02001252 talloc_free(end->fmtp_extra);
1253 end->fmtp_extra = NULL;
Jacob Erlbeck72c30902013-11-25 15:23:35 +01001254
1255 /* Set default values */
1256 end->frame_duration_num = DEFAULT_RTP_AUDIO_FRAME_DUR_NUM;
1257 end->frame_duration_den = DEFAULT_RTP_AUDIO_FRAME_DUR_DEN;
Jacob Erlbeckf6ec0e92013-12-04 10:30:11 +01001258 end->frames_per_packet = 0; /* unknown */
1259 end->packet_duration_ms = DEFAULT_RTP_AUDIO_PACKET_DURATION_MS;
1260 end->rate = DEFAULT_RTP_AUDIO_DEFAULT_RATE;
Jacob Erlbeck0970bab2013-12-19 12:13:32 +01001261 end->output_enabled = 1;
Holger Hans Peter Freythera17d7012010-08-05 01:34:51 +08001262}
1263
Holger Hans Peter Freytherc4921272010-08-05 03:37:22 +08001264static void mgcp_rtp_end_init(struct mgcp_rtp_end *end)
1265{
1266 mgcp_rtp_end_reset(end);
1267 end->rtp.fd = -1;
1268 end->rtcp.fd = -1;
1269}
1270
Holger Hans Peter Freyther1f0c5b42011-02-28 14:37:03 +01001271int mgcp_endpoints_allocate(struct mgcp_trunk_config *tcfg)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +01001272{
1273 int i;
1274
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +01001275 /* Initialize all endpoints */
Holger Hans Peter Freyther1f0c5b42011-02-28 14:37:03 +01001276 tcfg->endpoints = _talloc_zero_array(tcfg->cfg,
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +01001277 sizeof(struct mgcp_endpoint),
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +01001278 tcfg->number_endpoints, "endpoints");
1279 if (!tcfg->endpoints)
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +01001280 return -1;
1281
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +01001282 for (i = 0; i < tcfg->number_endpoints; ++i) {
1283 tcfg->endpoints[i].ci = CI_UNUSED;
Holger Hans Peter Freyther1f0c5b42011-02-28 14:37:03 +01001284 tcfg->endpoints[i].cfg = tcfg->cfg;
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +01001285 tcfg->endpoints[i].tcfg = tcfg;
1286 mgcp_rtp_end_init(&tcfg->endpoints[i].net_end);
1287 mgcp_rtp_end_init(&tcfg->endpoints[i].bts_end);
1288 mgcp_rtp_end_init(&tcfg->endpoints[i].trans_net);
1289 mgcp_rtp_end_init(&tcfg->endpoints[i].trans_bts);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +01001290 }
1291
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +01001292 return 0;
1293}
Holger Hans Peter Freyther154b9552010-02-26 13:27:51 +01001294
1295void mgcp_free_endp(struct mgcp_endpoint *endp)
1296{
Holger Hans Peter Freytherc77efdf2010-03-31 12:31:09 +02001297 LOGP(DMGCP, LOGL_DEBUG, "Deleting endpoint on: 0x%x\n", ENDPOINT_NUMBER(endp));
Holger Hans Peter Freyther89976e82010-08-03 15:01:43 +00001298 endp->ci = CI_UNUSED;
Holger Hans Peter Freyther39a97e22010-08-06 18:03:11 +08001299 endp->allocated = 0;
Holger Hans Peter Freyther154b9552010-02-26 13:27:51 +01001300
Holger Hans Peter Freyther01d315f2012-12-07 11:52:16 +01001301 talloc_free(endp->callid);
1302 endp->callid = NULL;
Holger Hans Peter Freyther154b9552010-02-26 13:27:51 +01001303
Jacob Erlbeck2c2ca4d2013-12-09 14:32:03 +01001304 talloc_free(endp->local_options.string);
1305 endp->local_options.string = NULL;
Holger Hans Peter Freyther154b9552010-02-26 13:27:51 +01001306
Holger Hans Peter Freythera17d7012010-08-05 01:34:51 +08001307 mgcp_rtp_end_reset(&endp->bts_end);
1308 mgcp_rtp_end_reset(&endp->net_end);
Holger Hans Peter Freyther21262332010-11-01 20:53:31 +01001309 mgcp_rtp_end_reset(&endp->trans_net);
Holger Hans Peter Freytherbd7b3c52010-11-01 21:04:54 +01001310 mgcp_rtp_end_reset(&endp->trans_bts);
Pablo Neira Ayuso46bd4242013-07-08 05:09:46 +02001311 endp->type = MGCP_RTP_DEFAULT;
Holger Hans Peter Freyther380b8712010-07-29 02:38:39 +08001312
Holger Hans Peter Freyther31868922010-08-03 11:59:04 +00001313 memset(&endp->net_state, 0, sizeof(endp->net_state));
1314 memset(&endp->bts_state, 0, sizeof(endp->bts_state));
Holger Hans Peter Freytherc597a4e2010-08-03 02:57:02 +08001315
1316 endp->conn_mode = endp->orig_mode = MGCP_CONN_NONE;
Holger Hans Peter Freyther260d6ed2010-08-06 01:12:21 +08001317
1318 memset(&endp->taps, 0, sizeof(endp->taps));
Holger Hans Peter Freyther154b9552010-02-26 13:27:51 +01001319}
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +08001320
Holger Hans Peter Freyther557b1ab2010-09-19 04:39:55 +08001321static int send_trans(struct mgcp_config *cfg, const char *buf, int len)
1322{
1323 struct sockaddr_in addr;
1324
1325 memset(&addr, 0, sizeof(addr));
1326 addr.sin_family = AF_INET;
1327 addr.sin_addr = cfg->transcoder_in;
1328 addr.sin_port = htons(2427);
1329 return sendto(cfg->gw_fd.bfd.fd, buf, len, 0,
1330 (struct sockaddr *) &addr, sizeof(addr));
1331}
1332
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +08001333static void send_msg(struct mgcp_endpoint *endp, int endpoint, int port,
1334 const char *msg, const char *mode)
1335{
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +08001336 char buf[2096];
1337 int len;
1338
1339 /* hardcoded to AMR right now, we do not know the real type at this point */
1340 len = snprintf(buf, sizeof(buf),
1341 "%s 42 %x@mgw MGCP 1.0\r\n"
1342 "C: 4256\r\n"
1343 "M: %s\r\n"
1344 "\r\n"
1345 "c=IN IP4 %s\r\n"
1346 "m=audio %d RTP/AVP %d\r\n"
1347 "a=rtpmap:%d %s\r\n",
1348 msg, endpoint, mode, endp->cfg->source_addr,
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +01001349 port, endp->tcfg->audio_payload,
1350 endp->tcfg->audio_payload, endp->tcfg->audio_name);
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +08001351
1352 if (len < 0)
1353 return;
1354
1355 buf[sizeof(buf) - 1] = '\0';
1356
Holger Hans Peter Freyther557b1ab2010-09-19 04:39:55 +08001357 send_trans(endp->cfg, buf, len);
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +08001358}
1359
1360static void send_dlcx(struct mgcp_endpoint *endp, int endpoint)
1361{
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +08001362 char buf[2096];
1363 int len;
1364
1365 len = snprintf(buf, sizeof(buf),
1366 "DLCX 43 %x@mgw MGCP 1.0\r\n"
1367 "C: 4256\r\n"
1368 , endpoint);
1369
1370 if (len < 0)
1371 return;
1372
1373 buf[sizeof(buf) - 1] = '\0';
1374
Holger Hans Peter Freyther557b1ab2010-09-19 04:39:55 +08001375 send_trans(endp->cfg, buf, len);
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +08001376}
1377
Harald Welte6a857052012-01-27 00:41:39 +01001378static int send_agent(struct mgcp_config *cfg, const char *buf, int len)
1379{
1380 return write(cfg->gw_fd.bfd.fd, buf, len);
1381}
1382
1383int mgcp_send_reset_all(struct mgcp_config *cfg)
1384{
1385 static const char mgcp_reset[] = {
1386 "RSIP 1 *@mgw MGCP 1.0\r\n"
1387 };
1388
1389 return send_agent(cfg, mgcp_reset, sizeof mgcp_reset -1);
1390}
1391
1392int mgcp_send_reset_ep(struct mgcp_endpoint *endp, int endpoint)
1393{
1394 char buf[128];
1395 int len;
1396
1397 len = snprintf(buf, sizeof(buf),
1398 "RSIP 39 %x@mgw MGCP 1.0\r\n"
1399 , endpoint);
1400 if (len < 0)
1401 return len;
1402
1403 buf[sizeof(buf) - 1] = '\0';
1404
1405 return send_agent(endp->cfg, buf, len);
1406}
1407
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +08001408static void create_transcoder(struct mgcp_endpoint *endp)
1409{
1410 int port;
1411 int in_endp = ENDPOINT_NUMBER(endp);
Holger Hans Peter Freytherbd7b3c52010-11-01 21:04:54 +01001412 int out_endp = endp_back_channel(in_endp);
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +08001413
Pablo Neira Ayuso46bd4242013-07-08 05:09:46 +02001414 if (endp->type != MGCP_RTP_TRANSCODED)
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +08001415 return;
1416
Holger Hans Peter Freyther8b19dee2010-11-01 22:38:25 +01001417 send_msg(endp, in_endp, endp->trans_bts.local_port, "CRCX", "sendrecv");
1418 send_msg(endp, in_endp, endp->trans_bts.local_port, "MDCX", "sendrecv");
Holger Hans Peter Freyther21262332010-11-01 20:53:31 +01001419 send_msg(endp, out_endp, endp->trans_net.local_port, "CRCX", "sendrecv");
1420 send_msg(endp, out_endp, endp->trans_net.local_port, "MDCX", "sendrecv");
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +08001421
Holger Hans Peter Freytherbd7b3c52010-11-01 21:04:54 +01001422 port = rtp_calculate_port(in_endp, endp->cfg->transcoder_remote_base);
1423 endp->trans_bts.rtp_port = htons(port);
1424 endp->trans_bts.rtcp_port = htons(port + 1);
1425
Holger Hans Peter Freytherb98ba722010-09-19 04:21:39 +08001426 port = rtp_calculate_port(out_endp, endp->cfg->transcoder_remote_base);
Holger Hans Peter Freyther21262332010-11-01 20:53:31 +01001427 endp->trans_net.rtp_port = htons(port);
1428 endp->trans_net.rtcp_port = htons(port + 1);
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +08001429}
1430
1431static void delete_transcoder(struct mgcp_endpoint *endp)
1432{
1433 int in_endp = ENDPOINT_NUMBER(endp);
Holger Hans Peter Freytherbd7b3c52010-11-01 21:04:54 +01001434 int out_endp = endp_back_channel(in_endp);
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +08001435
Pablo Neira Ayuso46bd4242013-07-08 05:09:46 +02001436 if (endp->type != MGCP_RTP_TRANSCODED)
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +08001437 return;
1438
1439 send_dlcx(endp, in_endp);
1440 send_dlcx(endp, out_endp);
1441}
Holger Hans Peter Freytherf2eedff2010-09-19 04:36:07 +08001442
1443int mgcp_reset_transcoder(struct mgcp_config *cfg)
1444{
Holger Hans Peter Freytherf2eedff2010-09-19 04:36:07 +08001445 if (!cfg->transcoder_ip)
Holger Hans Peter Freythercf1c8772010-09-24 04:41:28 +08001446 return 0;
Holger Hans Peter Freytherf2eedff2010-09-19 04:36:07 +08001447
1448 static const char mgcp_reset[] = {
1449 "RSIP 1 13@mgw MGCP 1.0\r\n"
1450 };
1451
Holger Hans Peter Freyther557b1ab2010-09-19 04:39:55 +08001452 return send_trans(cfg, mgcp_reset, sizeof mgcp_reset -1);
Holger Hans Peter Freytherf2eedff2010-09-19 04:36:07 +08001453}
Holger Hans Peter Freyther0bf15a82012-09-14 17:18:12 +02001454
1455void mgcp_format_stats(struct mgcp_endpoint *endp, char *msg, size_t size)
1456{
Holger Hans Peter Freythercb306a62012-10-24 21:22:47 +02001457 uint32_t expected, jitter;
Holger Hans Peter Freyther38e02c52012-10-22 18:09:35 +02001458 int ploss;
Jacob Erlbeck50079a12013-11-25 12:53:28 +01001459 int nchars;
Holger Hans Peter Freyther38e02c52012-10-22 18:09:35 +02001460 mgcp_state_calc_loss(&endp->net_state, &endp->net_end,
1461 &expected, &ploss);
Holger Hans Peter Freythercb306a62012-10-24 21:22:47 +02001462 jitter = mgcp_state_calc_jitter(&endp->net_state);
Holger Hans Peter Freyther38e02c52012-10-22 18:09:35 +02001463
Jacob Erlbeck50079a12013-11-25 12:53:28 +01001464 nchars = snprintf(msg, size,
1465 "\r\nP: PS=%u, OS=%u, PR=%u, OR=%u, PL=%d, JI=%u",
1466 endp->bts_end.packets, endp->bts_end.octets,
1467 endp->net_end.packets, endp->net_end.octets,
1468 ploss, jitter);
1469 if (nchars < 0 || nchars >= size)
1470 goto truncate;
1471
1472 msg += nchars;
1473 size -= nchars;
1474
1475 /* Error Counter */
1476 snprintf(msg, size,
1477 "\r\nX-Osmo-CP: EC TIS=%u, TOS=%u, TIR=%u, TOR=%u",
1478 endp->net_state.in_stream.err_ts_counter,
1479 endp->net_state.out_stream.err_ts_counter,
1480 endp->bts_state.in_stream.err_ts_counter,
1481 endp->bts_state.out_stream.err_ts_counter);
1482truncate:
Holger Hans Peter Freyther0bf15a82012-09-14 17:18:12 +02001483 msg[size - 1] = '\0';
1484}
Holger Hans Peter Freyther462b7d72012-10-24 21:53:40 +02001485
1486int mgcp_parse_stats(struct msgb *msg, uint32_t *ps, uint32_t *os,
1487 uint32_t *pr, uint32_t *_or, int *loss, uint32_t *jitter)
1488{
1489 char *line, *save;
1490 int rc;
1491
1492 /* initialize with bad values */
1493 *ps = *os = *pr = *_or = *jitter = UINT_MAX;
1494 *loss = INT_MAX;
1495
1496
1497 line = strtok_r((char *) msg->l2h, "\r\n", &save);
1498 if (!line)
1499 return -1;
1500
1501 /* this can only parse the message that is created above... */
Jacob Erlbecka01bd602013-11-29 13:43:43 +01001502 for_each_non_empty_line(line, save) {
Holger Hans Peter Freyther462b7d72012-10-24 21:53:40 +02001503 switch (line[0]) {
1504 case 'P':
1505 rc = sscanf(line, "P: PS=%u, OS=%u, PR=%u, OR=%u, PL=%d, JI=%u",
1506 ps, os, pr, _or, loss, jitter);
1507 return rc == 6 ? 0 : -1;
1508 }
1509 }
1510
1511 return -1;
1512}