blob: 862bf175d498f60ed10acbc90574b32ee5459b91 [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>
Jacob Erlbeck845d0052014-03-17 12:30:56 +010031#include <errno.h>
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +010032
Pablo Neira Ayuso136f4532011-03-22 16:47:59 +010033#include <osmocom/core/msgb.h>
34#include <osmocom/core/talloc.h>
35#include <osmocom/core/select.h>
Holger Hans Peter Freyther16b7f5c2011-02-28 22:06:47 +010036
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +010037#include <openbsc/mgcp.h>
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +010038#include <openbsc/mgcp_internal.h>
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +010039
Jacob Erlbecka01bd602013-11-29 13:43:43 +010040#define for_each_non_empty_line(line, save) \
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +010041 for (line = strtok_r(NULL, "\r\n", &save); line;\
Harald Welteae199722012-01-27 12:31:36 +010042 line = strtok_r(NULL, "\r\n", &save))
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +010043
Jacob Erlbeck2bee7f92013-11-29 13:43:44 +010044#define for_each_line(line, save) \
45 for (line = strline_r(NULL, &save); line;\
46 line = strline_r(NULL, &save))
47
48char *strline_r(char *str, char **saveptr)
49{
50 char *result;
51
52 if (str)
53 *saveptr = str;
54
55 result = *saveptr;
56
57 if (*saveptr != NULL) {
58 *saveptr = strpbrk(*saveptr, "\r\n");
59
60 if (*saveptr != NULL) {
61 char *eos = *saveptr;
62
63 if ((*saveptr)[0] == '\r' && (*saveptr)[1] == '\n')
64 (*saveptr)++;
65 (*saveptr)++;
66 if ((*saveptr)[0] == '\0')
67 *saveptr = NULL;
68
69 *eos = '\0';
70 }
71 }
72
73 return result;
74}
75
Jacob Erlbeck72c30902013-11-25 15:23:35 +010076/* Assume audio frame length of 20ms */
77#define DEFAULT_RTP_AUDIO_FRAME_DUR_NUM 20
78#define DEFAULT_RTP_AUDIO_FRAME_DUR_DEN 1000
Jacob Erlbeckf6ec0e92013-12-04 10:30:11 +010079#define DEFAULT_RTP_AUDIO_PACKET_DURATION_MS 20
Jacob Erlbeck72c30902013-11-25 15:23:35 +010080#define DEFAULT_RTP_AUDIO_DEFAULT_RATE 8000
Jacob Erlbeck845d0052014-03-17 12:30:56 +010081#define DEFAULT_RTP_AUDIO_DEFAULT_CHANNELS 1
Jacob Erlbeck72c30902013-11-25 15:23:35 +010082
Holger Hans Peter Freytherf138f912010-08-05 08:08:17 +080083static void mgcp_rtp_end_reset(struct mgcp_rtp_end *end);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +010084
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +010085struct mgcp_parse_data {
86 struct mgcp_config *cfg;
87 struct mgcp_endpoint *endp;
88 char *trans;
89 char *save;
90 int found;
91};
92
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +010093struct mgcp_request {
94 char *name;
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +010095 struct msgb *(*handle_request) (struct mgcp_parse_data *data);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +010096 char *debug_name;
97};
98
99#define MGCP_REQUEST(NAME, REQ, DEBUG_NAME) \
100 { .name = NAME, .handle_request = REQ, .debug_name = DEBUG_NAME },
101
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100102static struct msgb *handle_audit_endpoint(struct mgcp_parse_data *data);
103static struct msgb *handle_create_con(struct mgcp_parse_data *data);
104static struct msgb *handle_delete_con(struct mgcp_parse_data *data);
105static struct msgb *handle_modify_con(struct mgcp_parse_data *data);
106static struct msgb *handle_rsip(struct mgcp_parse_data *data);
107static struct msgb *handle_noti_req(struct mgcp_parse_data *data);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100108
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +0800109static void create_transcoder(struct mgcp_endpoint *endp);
110static void delete_transcoder(struct mgcp_endpoint *endp);
111
Jacob Erlbecka0d64ce2014-03-13 14:24:52 +0100112static void setup_rtp_processing(struct mgcp_endpoint *endp);
113
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100114static int mgcp_analyze_header(struct mgcp_parse_data *parse, char *data);
115
Holger Hans Peter Freyther1cc5ff82014-05-22 15:03:10 +0200116static int mgcp_check_param(const struct mgcp_endpoint *endp, const char *line)
117{
118 const size_t line_len = strlen(line);
119 if (line[0] != '\0' && line_len < 2) {
120 LOGP(DMGCP, LOGL_ERROR,
121 "Wrong MGCP option format: '%s' on 0x%x\n",
122 line, ENDPOINT_NUMBER(endp));
123 return 0;
124 }
125
126 return 1;
127}
128
Holger Hans Peter Freyther46340132010-08-06 08:26:54 +0800129static uint32_t generate_call_id(struct mgcp_config *cfg)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100130{
131 int i;
132
133 /* use the call id */
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100134 ++cfg->last_call_id;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100135
136 /* handle wrap around */
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100137 if (cfg->last_call_id == CI_UNUSED)
138 ++cfg->last_call_id;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100139
140 /* callstack can only be of size number_of_endpoints */
141 /* verify that the call id is free, e.g. in case of overrun */
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +0100142 for (i = 1; i < cfg->trunk.number_endpoints; ++i)
143 if (cfg->trunk.endpoints[i].ci == cfg->last_call_id)
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100144 return generate_call_id(cfg);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100145
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100146 return cfg->last_call_id;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100147}
148
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100149/*
150 * array of function pointers for handling various
151 * messages. In the future this might be binary sorted
152 * for performance reasons.
153 */
154static const struct mgcp_request mgcp_requests [] = {
155 MGCP_REQUEST("AUEP", handle_audit_endpoint, "AuditEndpoint")
156 MGCP_REQUEST("CRCX", handle_create_con, "CreateConnection")
157 MGCP_REQUEST("DLCX", handle_delete_con, "DeleteConnection")
158 MGCP_REQUEST("MDCX", handle_modify_con, "ModifiyConnection")
Holger Hans Peter Freyther6e94d6d2011-01-25 23:33:54 +0100159 MGCP_REQUEST("RQNT", handle_noti_req, "NotificationRequest")
Holger Hans Peter Freyther9bdcc9c2010-03-31 06:39:35 +0200160
161 /* SPEC extension */
162 MGCP_REQUEST("RSIP", handle_rsip, "ReSetInProgress")
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100163};
164
Holger Hans Peter Freyther62e836c2010-02-03 11:03:45 +0100165static struct msgb *mgcp_msgb_alloc(void)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100166{
Holger Hans Peter Freyther62e836c2010-02-03 11:03:45 +0100167 struct msgb *msg;
168 msg = msgb_alloc_headroom(4096, 128, "MGCP msg");
169 if (!msg)
170 LOGP(DMGCP, LOGL_ERROR, "Failed to msgb for MGCP data.\n");
171
172 return msg;
173}
174
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100175static struct msgb *do_retransmission(const struct mgcp_endpoint *endp)
176{
177 struct msgb *msg = mgcp_msgb_alloc();
178 if (!msg)
179 return NULL;
180
181 msg->l2h = msgb_put(msg, strlen(endp->last_response));
182 memcpy(msg->l2h, endp->last_response, msgb_l2len(msg));
183 return msg;
184}
185
Holger Hans Peter Freythera769dcb2012-12-07 15:14:27 +0100186static struct msgb *create_resp(struct mgcp_endpoint *endp, int code,
187 const char *txt, const char *msg,
Holger Hans Peter Freyther0bf15a82012-09-14 17:18:12 +0200188 const char *trans, const char *param,
189 const char *sdp)
Holger Hans Peter Freyther62e836c2010-02-03 11:03:45 +0100190{
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100191 int len;
Holger Hans Peter Freyther62e836c2010-02-03 11:03:45 +0100192 struct msgb *res;
193
194 res = mgcp_msgb_alloc();
195 if (!res)
196 return NULL;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100197
Holger Hans Peter Freyther0bf15a82012-09-14 17:18:12 +0200198 len = snprintf((char *) res->data, 2048, "%d %s%s%s\r\n%s",
199 code, trans, txt, param ? param : "", sdp ? sdp : "");
200 if (len < 0) {
201 LOGP(DMGCP, LOGL_ERROR, "Failed to sprintf MGCP response.\n");
202 msgb_free(res);
203 return NULL;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100204 }
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100205
Holger Hans Peter Freyther62e836c2010-02-03 11:03:45 +0100206 res->l2h = msgb_put(res, len);
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100207 LOGP(DMGCP, LOGL_DEBUG, "Generated response: code: %d for '%s'\n", code, res->l2h);
208
209 /*
210 * Remember the last transmission per endpoint.
211 */
212 if (endp) {
213 struct mgcp_trunk_config *tcfg = endp->tcfg;
214 talloc_free(endp->last_response);
215 talloc_free(endp->last_trans);
216 endp->last_trans = talloc_strdup(tcfg->endpoints, trans);
217 endp->last_response = talloc_strndup(tcfg->endpoints,
218 (const char *) res->l2h,
219 msgb_l2len(res));
220 }
221
Holger Hans Peter Freyther62e836c2010-02-03 11:03:45 +0100222 return res;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100223}
224
Holger Hans Peter Freythera769dcb2012-12-07 15:14:27 +0100225static struct msgb *create_ok_resp_with_param(struct mgcp_endpoint *endp,
226 int code, const char *msg,
Holger Hans Peter Freyther0bf15a82012-09-14 17:18:12 +0200227 const char *trans, const char *param)
228{
Holger Hans Peter Freythera769dcb2012-12-07 15:14:27 +0100229 return create_resp(endp, code, " OK", msg, trans, param, NULL);
Holger Hans Peter Freyther0bf15a82012-09-14 17:18:12 +0200230}
231
Holger Hans Peter Freythera769dcb2012-12-07 15:14:27 +0100232static struct msgb *create_ok_response(struct mgcp_endpoint *endp,
233 int code, const char *msg, const char *trans)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100234{
Holger Hans Peter Freythera769dcb2012-12-07 15:14:27 +0100235 return create_ok_resp_with_param(endp, code, msg, trans, NULL);
Holger Hans Peter Freyther6adac172011-01-06 16:19:55 +0100236}
237
Holger Hans Peter Freythera769dcb2012-12-07 15:14:27 +0100238static struct msgb *create_err_response(struct mgcp_endpoint *endp,
239 int code, const char *msg, const char *trans)
Holger Hans Peter Freyther6adac172011-01-06 16:19:55 +0100240{
Holger Hans Peter Freythera769dcb2012-12-07 15:14:27 +0100241 return create_resp(endp, code, " FAIL", msg, trans, NULL, NULL);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100242}
243
Holger Hans Peter Freyther8d188ed2010-02-21 01:44:08 +0100244static struct msgb *create_response_with_sdp(struct mgcp_endpoint *endp,
245 const char *msg, const char *trans_id)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100246{
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100247 const char *addr = endp->cfg->local_ip;
Holger Hans Peter Freyther5ea1bc72012-09-03 00:07:39 +0200248 const char *fmtp_extra = endp->bts_end.fmtp_extra;
Jacob Erlbeck845d0052014-03-17 12:30:56 +0100249 const char *audio_name = endp->bts_end.audio_name;
250 int payload_type = endp->bts_end.payload_type;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100251 char sdp_record[4096];
Jacob Erlbeck0a1bc562013-12-10 13:09:37 +0100252 int len;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100253
254 if (!addr)
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100255 addr = endp->cfg->source_addr;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100256
Jacob Erlbeck0a1bc562013-12-10 13:09:37 +0100257 len = snprintf(sdp_record, sizeof(sdp_record) - 1,
Pablo Neira Ayusocab6e752014-02-05 18:56:17 +0100258 "I: %u%s\n\n"
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100259 "v=0\r\n"
Holger Hans Peter Freytherc7e49d32011-07-20 20:43:15 +0200260 "o=- %u 23 IN IP4 %s\r\n"
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100261 "c=IN IP4 %s\r\n"
Holger Hans Peter Freytherc7e49d32011-07-20 20:43:15 +0200262 "t=0 0\r\n"
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100263 "m=audio %d RTP/AVP %d\r\n"
Jacob Erlbeck845d0052014-03-17 12:30:56 +0100264 "a=rtpmap:%d%s%s\r\n"
Holger Hans Peter Freyther5ea1bc72012-09-03 00:07:39 +0200265 "%s%s",
Pablo Neira Ayusocab6e752014-02-05 18:56:17 +0100266 endp->ci, endp->cfg->osmux && endp->osmux ? "\nX-Osmux: On" : "",
267 endp->ci, addr, addr,
Jacob Erlbeck845d0052014-03-17 12:30:56 +0100268 endp->net_end.local_port, payload_type,
269 payload_type,
270 audio_name ? " " : "", audio_name ? audio_name : "",
Holger Hans Peter Freyther5ea1bc72012-09-03 00:07:39 +0200271 fmtp_extra ? fmtp_extra : "", fmtp_extra ? "\r\n" : "");
Jacob Erlbeck0a1bc562013-12-10 13:09:37 +0100272
273 if (len < 0 || len >= sizeof(sdp_record))
274 goto buffer_too_small;
275
276 if (endp->bts_end.packet_duration_ms > 0 && endp->tcfg->audio_send_ptime) {
277 int nchars = snprintf(sdp_record + len, sizeof(sdp_record) - len,
278 "a=ptime:%d\r\n",
279 endp->bts_end.packet_duration_ms);
280 if (nchars < 0 || nchars >= sizeof(sdp_record) - len)
281 goto buffer_too_small;
282
283 len += nchars;
284 }
Holger Hans Peter Freythera769dcb2012-12-07 15:14:27 +0100285 return create_resp(endp, 200, " OK", msg, trans_id, NULL, sdp_record);
Jacob Erlbeck0a1bc562013-12-10 13:09:37 +0100286
287buffer_too_small:
288 LOGP(DMGCP, LOGL_ERROR, "SDP buffer too small: %d (needed %d)\n",
289 sizeof(sdp_record), len);
290 return NULL;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100291}
292
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100293/*
294 * handle incoming messages:
295 * - this can be a command (four letters, space, transaction id)
296 * - or a response (three numbers, space, transaction id)
297 */
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100298struct msgb *mgcp_handle_message(struct mgcp_config *cfg, struct msgb *msg)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100299{
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100300 struct mgcp_parse_data pdata;
301 int i, code, handled = 0;
Holger Hans Peter Freyther62e836c2010-02-03 11:03:45 +0100302 struct msgb *resp = NULL;
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100303 char *data;
Jacob Erlbeck9107e2d2013-12-03 17:14:44 +0100304 unsigned char *tail = msg->l2h + msgb_l2len(msg); /* char after l2 data */
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100305
Holger Hans Peter Freytherf36a11a2010-03-31 13:26:46 +0200306 if (msgb_l2len(msg) < 4) {
Holger Hans Peter Freyther0d904e02012-12-07 16:46:19 +0100307 LOGP(DMGCP, LOGL_ERROR, "msg too short: %d\n", msg->len);
Holger Hans Peter Freyther62e836c2010-02-03 11:03:45 +0100308 return NULL;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100309 }
310
Jacob Erlbeck9107e2d2013-12-03 17:14:44 +0100311 /* Ensure that the msg->l2h is NUL terminated. */
312 if (tail[-1] == '\0')
313 /* nothing to do */;
314 else if (msgb_tailroom(msg) > 0)
315 tail[0] = '\0';
316 else if (tail[-1] == '\r' || tail[-1] == '\n')
317 tail[-1] = '\0';
318 else {
319 LOGP(DMGCP, LOGL_ERROR, "Cannot NUL terminate MGCP message: "
320 "Length: %d, Buffer size: %d\n",
321 msgb_l2len(msg), msg->data_len);
322 return NULL;
323 }
324
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100325 /* attempt to treat it as a response */
Holger Hans Peter Freytherf36a11a2010-03-31 13:26:46 +0200326 if (sscanf((const char *)&msg->l2h[0], "%3d %*s", &code) == 1) {
Holger Hans Peter Freyther63f2db22010-02-26 13:30:57 +0100327 LOGP(DMGCP, LOGL_DEBUG, "Response: Code: %d\n", code);
Holger Hans Peter Freyther29de3462012-12-07 16:07:46 +0100328 return NULL;
329 }
330
331 msg->l3h = &msg->l2h[4];
332
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100333
334 /*
335 * Check for a duplicate message and respond.
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100336 */
337 memset(&pdata, 0, sizeof(pdata));
338 pdata.cfg = cfg;
Jacob Erlbeck17711712013-11-29 13:43:46 +0100339 data = strline_r((char *) msg->l3h, &pdata.save);
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100340 pdata.found = mgcp_analyze_header(&pdata, data);
341 if (pdata.endp && pdata.trans
342 && pdata.endp->last_trans
343 && strcmp(pdata.endp->last_trans, pdata.trans) == 0) {
344 return do_retransmission(pdata.endp);
345 }
346
Holger Hans Peter Freyther29de3462012-12-07 16:07:46 +0100347 for (i = 0; i < ARRAY_SIZE(mgcp_requests); ++i) {
348 if (strncmp(mgcp_requests[i].name, (const char *) &msg->l2h[0], 4) == 0) {
349 handled = 1;
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100350 resp = mgcp_requests[i].handle_request(&pdata);
Holger Hans Peter Freyther29de3462012-12-07 16:07:46 +0100351 break;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100352 }
353 }
354
Holger Hans Peter Freyther29de3462012-12-07 16:07:46 +0100355 if (!handled)
356 LOGP(DMGCP, LOGL_NOTICE, "MSG with type: '%.4s' not handled\n", &msg->l2h[0]);
357
Holger Hans Peter Freyther62e836c2010-02-03 11:03:45 +0100358 return resp;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100359}
360
Holger Hans Peter Freyther9f239a22011-01-06 19:32:52 +0100361/**
362 * We have a null terminated string with the endpoint name here. We only
363 * support two kinds. Simple ones as seen on the BSC level and the ones
364 * seen on the trunk side.
365 */
366static struct mgcp_endpoint *find_e1_endpoint(struct mgcp_config *cfg,
367 const char *mgcp)
368{
369 char *rest = NULL;
Holger Hans Peter Freyther74e61112011-02-28 14:13:47 +0100370 struct mgcp_trunk_config *tcfg;
371 int trunk, endp;
Holger Hans Peter Freyther9f239a22011-01-06 19:32:52 +0100372
373 trunk = strtoul(mgcp + 6, &rest, 10);
Holger Hans Peter Freytherf43f2fc2011-01-07 11:30:21 +0100374 if (rest == NULL || rest[0] != '/' || trunk < 1) {
Holger Hans Peter Freyther9f239a22011-01-06 19:32:52 +0100375 LOGP(DMGCP, LOGL_ERROR, "Wrong trunk name '%s'\n", mgcp);
376 return NULL;
377 }
378
379 endp = strtoul(rest + 1, &rest, 10);
380 if (rest == NULL || rest[0] != '@') {
Holger Hans Peter Freytherf43f2fc2011-01-07 11:30:21 +0100381 LOGP(DMGCP, LOGL_ERROR, "Wrong endpoint name '%s'\n", mgcp);
Holger Hans Peter Freyther9f239a22011-01-06 19:32:52 +0100382 return NULL;
383 }
384
385 /* signalling is on timeslot 1 */
386 if (endp == 1)
387 return NULL;
388
Holger Hans Peter Freyther74e61112011-02-28 14:13:47 +0100389 tcfg = mgcp_trunk_num(cfg, trunk);
390 if (!tcfg) {
391 LOGP(DMGCP, LOGL_ERROR, "The trunk %d is not declared.\n", trunk);
392 return NULL;
393 }
394
395 if (!tcfg->endpoints) {
396 LOGP(DMGCP, LOGL_ERROR, "Endpoints of trunk %d not allocated.\n", trunk);
397 return NULL;
398 }
399
400 if (endp < 1 || endp >= tcfg->number_endpoints) {
Holger Hans Peter Freyther9f239a22011-01-06 19:32:52 +0100401 LOGP(DMGCP, LOGL_ERROR, "Failed to find endpoint '%s'\n", mgcp);
Holger Hans Peter Freyther45c21842011-01-07 11:36:54 +0100402 return NULL;
Holger Hans Peter Freyther9f239a22011-01-06 19:32:52 +0100403 }
404
Holger Hans Peter Freyther74e61112011-02-28 14:13:47 +0100405 return &tcfg->endpoints[endp];
Holger Hans Peter Freyther9f239a22011-01-06 19:32:52 +0100406}
407
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100408static struct mgcp_endpoint *find_endpoint(struct mgcp_config *cfg, const char *mgcp)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100409{
410 char *endptr = NULL;
411 unsigned int gw = INT_MAX;
412
Holger Hans Peter Freyther9f239a22011-01-06 19:32:52 +0100413 if (strncmp(mgcp, "ds/e1", 5) == 0) {
414 return find_e1_endpoint(cfg, mgcp);
415 } else {
416 gw = strtoul(mgcp, &endptr, 16);
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +0100417 if (gw > 0 && gw < cfg->trunk.number_endpoints && strcmp(endptr, "@mgw") == 0)
418 return &cfg->trunk.endpoints[gw];
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100419 }
420
Holger Hans Peter Freyther9f239a22011-01-06 19:32:52 +0100421 LOGP(DMGCP, LOGL_ERROR, "Not able to find endpoint: '%s'\n", mgcp);
422 return NULL;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100423}
424
Harald Welteae199722012-01-27 12:31:36 +0100425/**
426 * @returns 0 when the status line was complete and transaction_id and
427 * endp out parameters are set.
428 */
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100429static int mgcp_analyze_header(struct mgcp_parse_data *pdata, char *data)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100430{
Harald Welteae199722012-01-27 12:31:36 +0100431 int i = 0;
Holger Hans Peter Freyther1eba7de2013-07-03 10:23:35 +0200432 char *elem, *save = NULL;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100433
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100434 pdata->trans = "000000";
Holger Hans Peter Freythera820c5f2010-02-26 13:32:55 +0100435
Harald Welteae199722012-01-27 12:31:36 +0100436 for (elem = strtok_r(data, " ", &save); elem;
437 elem = strtok_r(NULL, " ", &save)) {
438 switch (i) {
439 case 0:
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100440 pdata->trans = elem;
Harald Welteae199722012-01-27 12:31:36 +0100441 break;
442 case 1:
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100443 pdata->endp = find_endpoint(pdata->cfg, elem);
444 if (!pdata->endp) {
445 LOGP(DMGCP, LOGL_ERROR,
446 "Unable to find Endpoint `%s'\n", elem);
447 return -1;
Harald Welteae199722012-01-27 12:31:36 +0100448 }
449 break;
450 case 2:
451 if (strcmp("MGCP", elem)) {
452 LOGP(DMGCP, LOGL_ERROR,
453 "MGCP header parsing error\n");
454 return -1;
455 }
456 break;
457 case 3:
458 if (strcmp("1.0", elem)) {
459 LOGP(DMGCP, LOGL_ERROR, "MGCP version `%s' "
460 "not supported\n", elem);
461 return -1;
462 }
463 break;
464 }
465 i++;
466 }
467
468 if (i != 4) {
469 LOGP(DMGCP, LOGL_ERROR, "MGCP status line too short.\n");
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100470 pdata->trans = "000000";
471 pdata->endp = NULL;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100472 return -1;
473 }
474
Holger Hans Peter Freytherf2f15912010-04-01 03:27:04 +0200475 return 0;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100476}
477
478static int verify_call_id(const struct mgcp_endpoint *endp,
479 const char *callid)
480{
481 if (strcmp(endp->callid, callid) != 0) {
Holger Hans Peter Freyther2ada71d2010-02-03 09:13:10 +0100482 LOGP(DMGCP, LOGL_ERROR, "CallIDs does not match on 0x%x. '%s' != '%s'\n",
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100483 ENDPOINT_NUMBER(endp), endp->callid, callid);
484 return -1;
485 }
486
487 return 0;
488}
489
490static int verify_ci(const struct mgcp_endpoint *endp,
Holger Hans Peter Freyther46340132010-08-06 08:26:54 +0800491 const char *_ci)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100492{
Holger Hans Peter Freyther46340132010-08-06 08:26:54 +0800493 uint32_t ci = strtoul(_ci, NULL, 10);
494
495 if (ci != endp->ci) {
496 LOGP(DMGCP, LOGL_ERROR, "ConnectionIdentifiers do not match on 0x%x. %u != %s\n",
497 ENDPOINT_NUMBER(endp), endp->ci, _ci);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100498 return -1;
499 }
500
501 return 0;
502}
503
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100504static struct msgb *handle_audit_endpoint(struct mgcp_parse_data *p)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100505{
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100506 if (p->found != 0)
507 return create_err_response(NULL, 500, "AUEP", p->trans);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100508 else
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100509 return create_ok_response(p->endp, 200, "AUEP", p->trans);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100510}
511
Jacob Erlbeck2645c9e2013-12-19 12:23:24 +0100512static int parse_conn_mode(const char *msg, struct mgcp_endpoint *endp)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100513{
514 int ret = 0;
515 if (strcmp(msg, "recvonly") == 0)
Jacob Erlbeck2645c9e2013-12-19 12:23:24 +0100516 endp->conn_mode = MGCP_CONN_RECV_ONLY;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100517 else if (strcmp(msg, "sendrecv") == 0)
Jacob Erlbeck2645c9e2013-12-19 12:23:24 +0100518 endp->conn_mode = MGCP_CONN_RECV_SEND;
Holger Hans Peter Freythere02860a2010-09-18 20:21:44 +0800519 else if (strcmp(msg, "sendonly") == 0)
Jacob Erlbeck2645c9e2013-12-19 12:23:24 +0100520 endp->conn_mode = MGCP_CONN_SEND_ONLY;
Holger Hans Peter Freyther98a38772010-08-03 02:27:21 +0800521 else if (strcmp(msg, "loopback") == 0)
Jacob Erlbeck2645c9e2013-12-19 12:23:24 +0100522 endp->conn_mode = MGCP_CONN_LOOPBACK;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100523 else {
Holger Hans Peter Freyther2ada71d2010-02-03 09:13:10 +0100524 LOGP(DMGCP, LOGL_ERROR, "Unknown connection mode: '%s'\n", msg);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100525 ret = -1;
526 }
527
Jacob Erlbecke35fd132014-01-16 16:50:40 +0100528 endp->net_end.output_enabled =
529 endp->conn_mode & MGCP_CONN_SEND_ONLY ? 1 : 0;
530 endp->bts_end.output_enabled =
531 endp->conn_mode & MGCP_CONN_RECV_ONLY ? 1 : 0;
Jacob Erlbeck2645c9e2013-12-19 12:23:24 +0100532
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100533 return ret;
534}
535
Jacob Erlbeck845d0052014-03-17 12:30:56 +0100536static int set_audio_info(void *ctx, struct mgcp_rtp_end *rtp,
537 int payload_type, const char *audio_name)
538{
539 int rate = rtp->rate;
540 int channels = rtp->channels;
541 char audio_codec[64];
542
543 talloc_free(rtp->subtype_name);
544 rtp->subtype_name = NULL;
545 talloc_free(rtp->audio_name);
546 rtp->audio_name = NULL;
547
548 rtp->payload_type = payload_type;
549
550 if (!audio_name) {
551 switch (payload_type) {
552 case 3: audio_name = "GSM/8000/1"; break;
553 case 8: audio_name = "PCMA/8000/1"; break;
554 case 18: audio_name = "G729/8000/1"; break;
555 default:
556 /* Payload type is unknown, don't change rate and
557 * channels. */
558 /* TODO: return value? */
559 return 0;
560 }
561 }
562
563 if (sscanf(audio_name, "%63[^/]/%d/%d",
564 audio_codec, &rate, &channels) < 2)
565 return -EINVAL;
566
567 rtp->rate = rate;
568 rtp->channels = channels;
569 rtp->subtype_name = talloc_strdup(ctx, audio_codec);
570 rtp->audio_name = talloc_strdup(ctx, audio_name);
571 if (channels != 1)
572 LOGP(DMGCP, LOGL_NOTICE,
573 "Channels != 1 in SDP: '%s'\n", audio_name);
574
575 return 0;
576}
577
Holger Hans Peter Freytherf138f912010-08-05 08:08:17 +0800578static int allocate_port(struct mgcp_endpoint *endp, struct mgcp_rtp_end *end,
Holger Hans Peter Freyther218f8562010-09-18 02:30:02 +0800579 struct mgcp_port_range *range,
580 int (*alloc)(struct mgcp_endpoint *endp, int port))
Holger Hans Peter Freytherf138f912010-08-05 08:08:17 +0800581{
582 int i;
583
584 if (range->mode == PORT_ALLOC_STATIC) {
Holger Hans Peter Freytherf138f912010-08-05 08:08:17 +0800585 end->local_alloc = PORT_ALLOC_STATIC;
586 return 0;
587 }
588
589 /* attempt to find a port */
590 for (i = 0; i < 200; ++i) {
591 int rc;
592
593 if (range->last_port >= range->range_end)
594 range->last_port = range->range_start;
595
Holger Hans Peter Freyther218f8562010-09-18 02:30:02 +0800596 rc = alloc(endp, range->last_port);
Holger Hans Peter Freytherf138f912010-08-05 08:08:17 +0800597
598 range->last_port += 2;
599 if (rc == 0) {
600 end->local_alloc = PORT_ALLOC_DYNAMIC;
601 return 0;
602 }
603
604 }
605
Holger Hans Peter Freyther218f8562010-09-18 02:30:02 +0800606 LOGP(DMGCP, LOGL_ERROR, "Allocating a RTP/RTCP port failed 200 times 0x%x.\n",
607 ENDPOINT_NUMBER(endp));
Holger Hans Peter Freytherf138f912010-08-05 08:08:17 +0800608 return -1;
609}
610
611static int allocate_ports(struct mgcp_endpoint *endp)
612{
Holger Hans Peter Freyther218f8562010-09-18 02:30:02 +0800613 if (allocate_port(endp, &endp->net_end, &endp->cfg->net_ports,
614 mgcp_bind_net_rtp_port) != 0)
Holger Hans Peter Freytherf138f912010-08-05 08:08:17 +0800615 return -1;
616
Holger Hans Peter Freyther218f8562010-09-18 02:30:02 +0800617 if (allocate_port(endp, &endp->bts_end, &endp->cfg->bts_ports,
618 mgcp_bind_bts_rtp_port) != 0) {
Holger Hans Peter Freytherf138f912010-08-05 08:08:17 +0800619 mgcp_rtp_end_reset(&endp->net_end);
620 return -1;
621 }
622
Holger Hans Peter Freyther69906872011-02-28 14:51:48 +0100623 if (endp->cfg->transcoder_ip && endp->tcfg->trunk_type == MGCP_TRUNK_VIRTUAL) {
Holger Hans Peter Freyther21262332010-11-01 20:53:31 +0100624 if (allocate_port(endp, &endp->trans_net,
Holger Hans Peter Freytherb54048f2010-11-01 19:57:50 +0100625 &endp->cfg->transcoder_ports,
Holger Hans Peter Freytherbd7b3c52010-11-01 21:04:54 +0100626 mgcp_bind_trans_net_rtp_port) != 0) {
Holger Hans Peter Freytherb54048f2010-11-01 19:57:50 +0100627 mgcp_rtp_end_reset(&endp->net_end);
628 mgcp_rtp_end_reset(&endp->bts_end);
629 return -1;
630 }
631
Holger Hans Peter Freytherbd7b3c52010-11-01 21:04:54 +0100632 if (allocate_port(endp, &endp->trans_bts,
633 &endp->cfg->transcoder_ports,
634 mgcp_bind_trans_bts_rtp_port) != 0) {
635 mgcp_rtp_end_reset(&endp->net_end);
636 mgcp_rtp_end_reset(&endp->bts_end);
637 mgcp_rtp_end_reset(&endp->trans_net);
638 return -1;
639 }
640
Holger Hans Peter Freytherb54048f2010-11-01 19:57:50 +0100641 /* remember that we have set up transcoding */
Pablo Neira Ayuso46bd4242013-07-08 05:09:46 +0200642 endp->type = MGCP_RTP_TRANSCODED;
Holger Hans Peter Freyther218f8562010-09-18 02:30:02 +0800643 }
644
Holger Hans Peter Freytherf138f912010-08-05 08:08:17 +0800645 return 0;
646}
647
Jacob Erlbeck17711712013-11-29 13:43:46 +0100648static int parse_sdp_data(struct mgcp_rtp_end *rtp, struct mgcp_parse_data *p)
649{
650 char *line;
651 int found_media = 0;
Jacob Erlbeck24754f02013-12-10 13:09:37 +0100652 int audio_payload = -1;
Jacob Erlbeck17711712013-11-29 13:43:46 +0100653
654 for_each_line(line, p->save) {
655 switch (line[0]) {
Jacob Erlbeck17711712013-11-29 13:43:46 +0100656 case 'o':
657 case 's':
658 case 't':
659 case 'v':
660 /* skip these SDP attributes */
661 break;
Jacob Erlbeck24754f02013-12-10 13:09:37 +0100662 case 'a': {
663 int payload;
Jacob Erlbeck24754f02013-12-10 13:09:37 +0100664 int ptime, ptime2 = 0;
665 char audio_name[64];
Jacob Erlbeck24754f02013-12-10 13:09:37 +0100666
667 if (audio_payload == -1)
668 break;
669
Holger Hans Peter Freyther4f0381b2014-05-28 16:44:34 +0200670 if (sscanf(line, "a=rtpmap:%d %63s",
Jacob Erlbeck24754f02013-12-10 13:09:37 +0100671 &payload, audio_name) == 2) {
672 if (payload != audio_payload)
673 break;
674
Jacob Erlbeck845d0052014-03-17 12:30:56 +0100675 set_audio_info(p->cfg, rtp, payload, audio_name);
Jacob Erlbeck24754f02013-12-10 13:09:37 +0100676 } else if (sscanf(line, "a=ptime:%d-%d",
677 &ptime, &ptime2) >= 1) {
678 if (ptime2 > 0 && ptime2 != ptime)
679 rtp->packet_duration_ms = 0;
680 else
681 rtp->packet_duration_ms = ptime;
682 } else if (sscanf(line, "a=maxptime:%d", &ptime2) == 1) {
683 if (ptime2 * rtp->frame_duration_den >
684 rtp->frame_duration_num * 1500)
685 /* more than 1 frame */
686 rtp->packet_duration_ms = 0;
687 }
688 break;
689 }
Jacob Erlbeck17711712013-11-29 13:43:46 +0100690 case 'm': {
691 int port;
Jacob Erlbeck24754f02013-12-10 13:09:37 +0100692 audio_payload = -1;
Jacob Erlbeck17711712013-11-29 13:43:46 +0100693
694 if (sscanf(line, "m=audio %d RTP/AVP %d",
Jacob Erlbeck24754f02013-12-10 13:09:37 +0100695 &port, &audio_payload) == 2) {
Jacob Erlbeck17711712013-11-29 13:43:46 +0100696 rtp->rtp_port = htons(port);
697 rtp->rtcp_port = htons(port + 1);
Jacob Erlbeck17711712013-11-29 13:43:46 +0100698 found_media = 1;
Jacob Erlbeck845d0052014-03-17 12:30:56 +0100699 set_audio_info(p->cfg, rtp, audio_payload, NULL);
Jacob Erlbeck17711712013-11-29 13:43:46 +0100700 }
701 break;
702 }
703 case 'c': {
704 char ipv4[16];
705
706 if (sscanf(line, "c=IN IP4 %15s", ipv4) == 1) {
707 inet_aton(ipv4, &rtp->addr);
708 }
709 break;
710 }
711 default:
712 if (p->endp)
713 LOGP(DMGCP, LOGL_NOTICE,
714 "Unhandled SDP option: '%c'/%d on 0x%x\n",
715 line[0], line[0], ENDPOINT_NUMBER(p->endp));
716 else
717 LOGP(DMGCP, LOGL_NOTICE,
718 "Unhandled SDP option: '%c'/%d\n",
719 line[0], line[0]);
720 break;
721 }
722 }
723
724 if (found_media)
725 LOGP(DMGCP, LOGL_NOTICE,
Jacob Erlbeck24754f02013-12-10 13:09:37 +0100726 "Got media info via SDP: port %d, payload %d, "
727 "duration %d, addr %s\n",
728 ntohs(rtp->rtp_port), rtp->payload_type,
729 rtp->packet_duration_ms, inet_ntoa(rtp->addr));
Jacob Erlbeck17711712013-11-29 13:43:46 +0100730
731 return found_media;
732}
733
Jacob Erlbeck2c2ca4d2013-12-09 14:32:03 +0100734/* Set the LCO from a string (see RFC 3435).
735 * The string is stored in the 'string' field. A NULL string is handled excatly
736 * like an empty string, the 'string' field is never NULL after this function
737 * has been called. */
738static void set_local_cx_options(void *ctx, struct mgcp_lco *lco,
739 const char *options)
740{
741 char *p_opt;
742
743 talloc_free(lco->string);
744 lco->pkt_period_min = lco->pkt_period_max = 0;
745 lco->string = talloc_strdup(ctx, options ? options : "");
746
747 p_opt = strstr(lco->string, "p:");
748 if (p_opt && sscanf(p_opt, "p:%d-%d",
749 &lco->pkt_period_min, &lco->pkt_period_max) == 1)
750 lco->pkt_period_max = lco->pkt_period_min;
751}
752
Jacob Erlbeckdb2d4312013-12-03 14:43:34 +0100753void mgcp_rtp_end_config(struct mgcp_endpoint *endp, int expect_ssrc_change,
754 struct mgcp_rtp_end *rtp)
755{
756 struct mgcp_trunk_config *tcfg = endp->tcfg;
757
Jacob Erlbecke2292f32013-12-03 15:13:12 +0100758 int patch_ssrc = expect_ssrc_change && tcfg->force_constant_ssrc;
759
Jacob Erlbeck4bbddc62013-12-18 12:54:51 +0100760 rtp->force_aligned_timing = tcfg->force_aligned_timing;
Jacob Erlbecke2292f32013-12-03 15:13:12 +0100761 rtp->force_constant_ssrc = patch_ssrc ? 1 : 0;
Jacob Erlbeckdb2d4312013-12-03 14:43:34 +0100762
763 LOGP(DMGCP, LOGL_DEBUG,
764 "Configuring RTP endpoint: local port %d%s%s\n",
765 ntohs(rtp->rtp_port),
Jacob Erlbeck4bbddc62013-12-18 12:54:51 +0100766 rtp->force_aligned_timing ? ", force constant timing" : "",
Jacob Erlbeckdb2d4312013-12-03 14:43:34 +0100767 rtp->force_constant_ssrc ? ", force constant ssrc" : "");
768}
769
Jacob Erlbeckf6ec0e92013-12-04 10:30:11 +0100770uint32_t mgcp_rtp_packet_duration(struct mgcp_endpoint *endp,
771 struct mgcp_rtp_end *rtp)
772{
773 int f = 0;
774
775 /* Get the number of frames per channel and packet */
776 if (rtp->frames_per_packet)
777 f = rtp->frames_per_packet;
778 else if (rtp->packet_duration_ms && rtp->frame_duration_num) {
779 int den = 1000 * rtp->frame_duration_num;
780 f = (rtp->packet_duration_ms * rtp->frame_duration_den + den/2)
781 / den;
782 }
783
784 return rtp->rate * f * rtp->frame_duration_num / rtp->frame_duration_den;
785}
786
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100787static struct msgb *handle_create_con(struct mgcp_parse_data *p)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100788{
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +0100789 struct mgcp_trunk_config *tcfg;
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100790 struct mgcp_endpoint *endp = p->endp;
Holger Hans Peter Freyther9e9392d2010-08-08 16:24:48 +0800791 int error_code = 400;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100792
Holger Hans Peter Freyther3488c3d2011-07-20 20:44:54 +0200793 const char *local_options = NULL;
794 const char *callid = NULL;
795 const char *mode = NULL;
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100796 char *line;
Jacob Erlbeck78a95012013-11-29 13:43:49 +0100797 int have_sdp = 0;
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100798
799 if (p->found != 0)
800 return create_err_response(NULL, 510, "CRCX", p->trans);
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +0100801
Holger Hans Peter Freyther3488c3d2011-07-20 20:44:54 +0200802 /* parse CallID C: and LocalParameters L: */
Jacob Erlbeck17711712013-11-29 13:43:46 +0100803 for_each_line(line, p->save) {
Holger Hans Peter Freyther1cc5ff82014-05-22 15:03:10 +0200804 if (!mgcp_check_param(endp, line))
805 continue;
806
Harald Welteae199722012-01-27 12:31:36 +0100807 switch (line[0]) {
808 case 'L':
809 local_options = (const char *) line + 3;
810 break;
811 case 'C':
812 callid = (const char *) line + 3;
813 break;
814 case 'M':
815 mode = (const char *) line + 3;
816 break;
Pablo Neira Ayusocab6e752014-02-05 18:56:17 +0100817 case 'X':
818 if (strcmp("Osmux: on", line + 2) == 0 &&
819 osmux_enable_endpoint(endp, OSMUX_ROLE_BSC) < 0) {
820 LOGP(DMGCP, LOGL_ERROR,
821 "Could not activate osmux in endpoint %d\n",
822 ENDPOINT_NUMBER(endp));
823 }
824 break;
Jacob Erlbeck78a95012013-11-29 13:43:49 +0100825 case '\0':
826 have_sdp = 1;
827 goto mgcp_header_done;
Harald Welteae199722012-01-27 12:31:36 +0100828 default:
829 LOGP(DMGCP, LOGL_NOTICE, "Unhandled option: '%c'/%d on 0x%x\n",
830 *line, *line, ENDPOINT_NUMBER(endp));
831 break;
832 }
Holger Hans Peter Freyther3488c3d2011-07-20 20:44:54 +0200833 }
Harald Welteae199722012-01-27 12:31:36 +0100834
Jacob Erlbeck78a95012013-11-29 13:43:49 +0100835mgcp_header_done:
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100836 tcfg = p->endp->tcfg;
Holger Hans Peter Freyther3488c3d2011-07-20 20:44:54 +0200837
838 /* Check required data */
839 if (!callid || !mode) {
840 LOGP(DMGCP, LOGL_ERROR, "Missing callid and mode in CRCX on 0x%x\n",
841 ENDPOINT_NUMBER(endp));
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100842 return create_err_response(endp, 400, "CRCX", p->trans);
Holger Hans Peter Freyther3488c3d2011-07-20 20:44:54 +0200843 }
844
Holger Hans Peter Freyther39a97e22010-08-06 18:03:11 +0800845 if (endp->allocated) {
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +0100846 if (tcfg->force_realloc) {
Holger Hans Peter Freyther408cc4a2010-04-07 10:51:27 +0200847 LOGP(DMGCP, LOGL_NOTICE, "Endpoint 0x%x already allocated. Forcing realloc.\n",
848 ENDPOINT_NUMBER(endp));
Holger Hans Peter Freyther32d4e502010-04-24 21:02:48 +0800849 mgcp_free_endp(endp);
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100850 if (p->cfg->realloc_cb)
851 p->cfg->realloc_cb(tcfg, ENDPOINT_NUMBER(endp));
Holger Hans Peter Freyther408cc4a2010-04-07 10:51:27 +0200852 } else {
853 LOGP(DMGCP, LOGL_ERROR, "Endpoint is already used. 0x%x\n",
854 ENDPOINT_NUMBER(endp));
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100855 return create_err_response(endp, 400, "CRCX", p->trans);
Holger Hans Peter Freyther408cc4a2010-04-07 10:51:27 +0200856 }
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100857 }
858
Holger Hans Peter Freyther3488c3d2011-07-20 20:44:54 +0200859 /* copy some parameters */
860 endp->callid = talloc_strdup(tcfg->endpoints, callid);
861
Jacob Erlbeck2c2ca4d2013-12-09 14:32:03 +0100862 set_local_cx_options(endp->tcfg->endpoints, &endp->local_options,
863 local_options);
Holger Hans Peter Freyther3488c3d2011-07-20 20:44:54 +0200864
Jacob Erlbeck2645c9e2013-12-19 12:23:24 +0100865 if (parse_conn_mode(mode, endp) != 0) {
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100866 error_code = 517;
867 goto error2;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100868 }
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100869
870 /* initialize */
Holger Hans Peter Freythera17d7012010-08-05 01:34:51 +0800871 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 +0100872 mgcp_rtp_end_config(endp, 0, &endp->net_end);
873 mgcp_rtp_end_config(endp, 0, &endp->bts_end);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100874
875 /* set to zero until we get the info */
Holger Hans Peter Freythera17d7012010-08-05 01:34:51 +0800876 memset(&endp->net_end.addr, 0, sizeof(endp->net_end.addr));
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100877
878 /* bind to the port now */
Holger Hans Peter Freytherf138f912010-08-05 08:08:17 +0800879 if (allocate_ports(endp) != 0)
880 goto error2;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100881
882 /* assign a local call identifier or fail */
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100883 endp->ci = generate_call_id(p->cfg);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100884 if (endp->ci == CI_UNUSED)
885 goto error2;
886
Holger Hans Peter Freyther39a97e22010-08-06 18:03:11 +0800887 endp->allocated = 1;
Jacob Erlbeck78a95012013-11-29 13:43:49 +0100888
889 /* set up RTP media parameters */
Jacob Erlbeck845d0052014-03-17 12:30:56 +0100890 set_audio_info(p->cfg, &endp->bts_end, tcfg->audio_payload, tcfg->audio_name);
Holger Hans Peter Freyther5ea1bc72012-09-03 00:07:39 +0200891 endp->bts_end.fmtp_extra = talloc_strdup(tcfg->endpoints,
892 tcfg->audio_fmtp_extra);
Jacob Erlbecka0d64ce2014-03-13 14:24:52 +0100893 if (have_sdp) {
Jacob Erlbeck78a95012013-11-29 13:43:49 +0100894 parse_sdp_data(&endp->net_end, p);
Jacob Erlbecka0d64ce2014-03-13 14:24:52 +0100895 setup_rtp_processing(endp);
896 }
Holger Hans Peter Freytheref6bb252010-02-26 13:41:22 +0100897
Holger Hans Peter Freytherfe86d3c2010-02-26 13:37:05 +0100898 /* policy CB */
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100899 if (p->cfg->policy_cb) {
900 int rc;
901 rc = p->cfg->policy_cb(tcfg, ENDPOINT_NUMBER(endp),
902 MGCP_ENDP_CRCX, p->trans);
903 switch (rc) {
Holger Hans Peter Freytherfe86d3c2010-02-26 13:37:05 +0100904 case MGCP_POLICY_REJECT:
905 LOGP(DMGCP, LOGL_NOTICE, "CRCX rejected by policy on 0x%x\n",
906 ENDPOINT_NUMBER(endp));
907 mgcp_free_endp(endp);
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100908 return create_err_response(endp, 400, "CRCX", p->trans);
Holger Hans Peter Freytherfe86d3c2010-02-26 13:37:05 +0100909 break;
910 case MGCP_POLICY_DEFER:
911 /* stop processing */
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +0800912 create_transcoder(endp);
Holger Hans Peter Freytherfe86d3c2010-02-26 13:37:05 +0100913 return NULL;
914 break;
915 case MGCP_POLICY_CONT:
916 /* just continue */
917 break;
918 }
919 }
920
Holger Hans Peter Freythere378cb12010-08-06 20:22:23 +0800921 LOGP(DMGCP, LOGL_DEBUG, "Creating endpoint on: 0x%x CI: %u port: %u/%u\n",
Holger Hans Peter Freyther58ff2192010-08-05 03:08:35 +0800922 ENDPOINT_NUMBER(endp), endp->ci,
923 endp->net_end.local_port, endp->bts_end.local_port);
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100924 if (p->cfg->change_cb)
925 p->cfg->change_cb(tcfg, ENDPOINT_NUMBER(endp), MGCP_ENDP_CRCX);
Holger Hans Peter Freyther77f7afe2010-02-03 09:54:43 +0100926
Pablo Neira Ayusocab6e752014-02-05 18:56:17 +0100927 if (endp->conn_mode & MGCP_CONN_RECV_ONLY && tcfg->keepalive_interval != 0) {
928 if (endp->osmux)
929 osmux_send_dummy(endp);
930 else
931 mgcp_send_dummy(endp);
932 }
Jacob Erlbeck075a9eb2013-12-19 18:53:07 +0100933
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +0800934 create_transcoder(endp);
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100935 return create_response_with_sdp(endp, "CRCX", p->trans);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100936error2:
Holger Hans Peter Freyther414bf402010-08-06 07:05:13 +0800937 mgcp_free_endp(endp);
Holger Hans Peter Freyther2ada71d2010-02-03 09:13:10 +0100938 LOGP(DMGCP, LOGL_NOTICE, "Resource error on 0x%x\n", ENDPOINT_NUMBER(endp));
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100939 return create_err_response(endp, error_code, "CRCX", p->trans);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100940}
941
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100942static struct msgb *handle_modify_con(struct mgcp_parse_data *p)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100943{
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100944 struct mgcp_endpoint *endp = p->endp;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100945 int error_code = 500;
Pablo Neira Ayusocab6e752014-02-05 18:56:17 +0100946 int silent = 0, osmux = 0;
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100947 char *line;
Jacob Erlbeck2c2ca4d2013-12-09 14:32:03 +0100948 const char *local_options = NULL;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100949
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100950 if (p->found != 0)
951 return create_err_response(NULL, 510, "MDCX", p->trans);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100952
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +0100953 if (endp->ci == CI_UNUSED) {
954 LOGP(DMGCP, LOGL_ERROR, "Endpoint is not "
955 "holding a connection. 0x%x\n", ENDPOINT_NUMBER(endp));
956 return create_err_response(endp, 400, "MDCX", p->trans);
957 }
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100958
Jacob Erlbeck17711712013-11-29 13:43:46 +0100959 for_each_line(line, p->save) {
Holger Hans Peter Freyther1cc5ff82014-05-22 15:03:10 +0200960 if (!mgcp_check_param(endp, line))
961 continue;
962
Harald Welteae199722012-01-27 12:31:36 +0100963 switch (line[0]) {
964 case 'C': {
965 if (verify_call_id(endp, line + 3) != 0)
966 goto error3;
967 break;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100968 }
Harald Welteae199722012-01-27 12:31:36 +0100969 case 'I': {
970 if (verify_ci(endp, line + 3) != 0)
971 goto error3;
972 break;
973 }
974 case 'L':
Jacob Erlbeck2c2ca4d2013-12-09 14:32:03 +0100975 local_options = (const char *) line + 3;
Harald Welteae199722012-01-27 12:31:36 +0100976 break;
977 case 'M':
Jacob Erlbeck2645c9e2013-12-19 12:23:24 +0100978 if (parse_conn_mode(line + 3, endp) != 0) {
Harald Welteae199722012-01-27 12:31:36 +0100979 error_code = 517;
980 goto error3;
981 }
982 endp->orig_mode = endp->conn_mode;
983 break;
Pablo Neira Ayusocab6e752014-02-05 18:56:17 +0100984 case 'X':
985 if (strcmp("Osmux: on", line + 2) == 0)
986 osmux = 1;
987 break;
Harald Welteae199722012-01-27 12:31:36 +0100988 case 'Z':
989 silent = strcmp("noanswer", line + 3) == 0;
990 break;
991 case '\0':
992 /* SDP file begins */
Jacob Erlbeck17711712013-11-29 13:43:46 +0100993 parse_sdp_data(&endp->net_end, p);
994 /* This will exhaust p->save, so the loop will
995 * terminate next time.
996 */
Harald Welteae199722012-01-27 12:31:36 +0100997 break;
Harald Welteae199722012-01-27 12:31:36 +0100998 default:
Jacob Erlbeck17711712013-11-29 13:43:46 +0100999 LOGP(DMGCP, LOGL_NOTICE, "Unhandled MGCP option: '%c'/%d on 0x%x\n",
Harald Welteae199722012-01-27 12:31:36 +01001000 line[0], line[0], ENDPOINT_NUMBER(endp));
1001 break;
1002 }
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +01001003 }
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +01001004
Pablo Neira Ayusocab6e752014-02-05 18:56:17 +01001005 /* Re-enable Osmux if we receive a MDCX, we have to set up a new
1006 * RTP flow: this generates a randomly allocated RTP SSRC and sequence
1007 * number.
1008 */
1009 if (osmux) {
1010 if (osmux_enable_endpoint(endp, OSMUX_ROLE_BSC) < 0) {
1011 LOGP(DMGCP, LOGL_ERROR,
1012 "Could not update osmux in endpoint %d\n",
1013 ENDPOINT_NUMBER(endp));
1014 }
1015 LOGP(DMGCP, LOGL_NOTICE,
1016 "Re-enabling osmux in endpoint %d, we got updated\n",
1017 ENDPOINT_NUMBER(endp));
1018 }
1019
Jacob Erlbeck2c2ca4d2013-12-09 14:32:03 +01001020 set_local_cx_options(endp->tcfg->endpoints, &endp->local_options,
1021 local_options);
1022
Jacob Erlbecka0d64ce2014-03-13 14:24:52 +01001023 setup_rtp_processing(endp);
1024
Holger Hans Peter Freytherfe86d3c2010-02-26 13:37:05 +01001025 /* policy CB */
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +01001026 if (p->cfg->policy_cb) {
1027 int rc;
1028 rc = p->cfg->policy_cb(endp->tcfg, ENDPOINT_NUMBER(endp),
1029 MGCP_ENDP_MDCX, p->trans);
1030 switch (rc) {
Holger Hans Peter Freytherfe86d3c2010-02-26 13:37:05 +01001031 case MGCP_POLICY_REJECT:
1032 LOGP(DMGCP, LOGL_NOTICE, "MDCX rejected by policy on 0x%x\n",
1033 ENDPOINT_NUMBER(endp));
Holger Hans Peter Freythere3d16bb2010-04-22 11:58:13 +08001034 if (silent)
1035 goto out_silent;
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +01001036 return create_err_response(endp, 400, "MDCX", p->trans);
Holger Hans Peter Freytherfe86d3c2010-02-26 13:37:05 +01001037 break;
1038 case MGCP_POLICY_DEFER:
1039 /* stop processing */
1040 return NULL;
1041 break;
1042 case MGCP_POLICY_CONT:
1043 /* just continue */
1044 break;
1045 }
1046 }
1047
Jacob Erlbeckdb2d4312013-12-03 14:43:34 +01001048 mgcp_rtp_end_config(endp, 1, &endp->net_end);
1049 mgcp_rtp_end_config(endp, 1, &endp->bts_end);
1050
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +01001051 /* modify */
Holger Hans Peter Freythere378cb12010-08-06 20:22:23 +08001052 LOGP(DMGCP, LOGL_DEBUG, "Modified endpoint on: 0x%x Server: %s:%u\n",
Holger Hans Peter Freythera17d7012010-08-05 01:34:51 +08001053 ENDPOINT_NUMBER(endp), inet_ntoa(endp->net_end.addr), ntohs(endp->net_end.rtp_port));
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +01001054 if (p->cfg->change_cb)
1055 p->cfg->change_cb(endp->tcfg, ENDPOINT_NUMBER(endp), MGCP_ENDP_MDCX);
Jacob Erlbeck075a9eb2013-12-19 18:53:07 +01001056
Jacob Erlbecke35fd132014-01-16 16:50:40 +01001057 if (endp->conn_mode & MGCP_CONN_RECV_ONLY &&
1058 endp->tcfg->keepalive_interval != 0)
Jacob Erlbeck075a9eb2013-12-19 18:53:07 +01001059 mgcp_send_dummy(endp);
1060
Holger Hans Peter Freythere3d16bb2010-04-22 11:58:13 +08001061 if (silent)
1062 goto out_silent;
1063
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +01001064 return create_response_with_sdp(endp, "MDCX", p->trans);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +01001065
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +01001066error3:
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +01001067 return create_err_response(endp, error_code, "MDCX", p->trans);
Holger Hans Peter Freythere3d16bb2010-04-22 11:58:13 +08001068
1069
1070out_silent:
1071 return NULL;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +01001072}
1073
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +01001074static struct msgb *handle_delete_con(struct mgcp_parse_data *p)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +01001075{
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +01001076 struct mgcp_endpoint *endp = p->endp;
Holger Hans Peter Freyther9e9392d2010-08-08 16:24:48 +08001077 int error_code = 400;
Holger Hans Peter Freythere3d16bb2010-04-22 11:58:13 +08001078 int silent = 0;
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +01001079 char *line;
Holger Hans Peter Freyther0bf15a82012-09-14 17:18:12 +02001080 char stats[1048];
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +01001081
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +01001082 if (p->found != 0)
1083 return create_err_response(NULL, error_code, "DLCX", p->trans);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +01001084
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +01001085 if (!p->endp->allocated) {
1086 LOGP(DMGCP, LOGL_ERROR, "Endpoint is not used. 0x%x\n",
1087 ENDPOINT_NUMBER(endp));
1088 return create_err_response(endp, 400, "DLCX", p->trans);
1089 }
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +01001090
Jacob Erlbeck17711712013-11-29 13:43:46 +01001091 for_each_line(line, p->save) {
Holger Hans Peter Freyther1cc5ff82014-05-22 15:03:10 +02001092 if (!mgcp_check_param(endp, line))
1093 continue;
1094
Harald Welteae199722012-01-27 12:31:36 +01001095 switch (line[0]) {
1096 case 'C':
1097 if (verify_call_id(endp, line + 3) != 0)
1098 goto error3;
1099 break;
1100 case 'I':
1101 if (verify_ci(endp, line + 3) != 0)
1102 goto error3;
1103 break;
1104 case 'Z':
1105 silent = strcmp("noanswer", line + 3) == 0;
1106 break;
1107 default:
1108 LOGP(DMGCP, LOGL_NOTICE, "Unhandled option: '%c'/%d on 0x%x\n",
1109 line[0], line[0], ENDPOINT_NUMBER(endp));
1110 break;
1111 }
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +01001112 }
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +01001113
Holger Hans Peter Freytherfe86d3c2010-02-26 13:37:05 +01001114 /* policy CB */
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +01001115 if (p->cfg->policy_cb) {
1116 int rc;
1117 rc = p->cfg->policy_cb(endp->tcfg, ENDPOINT_NUMBER(endp),
1118 MGCP_ENDP_DLCX, p->trans);
1119 switch (rc) {
Holger Hans Peter Freytherfe86d3c2010-02-26 13:37:05 +01001120 case MGCP_POLICY_REJECT:
1121 LOGP(DMGCP, LOGL_NOTICE, "DLCX rejected by policy on 0x%x\n",
1122 ENDPOINT_NUMBER(endp));
Holger Hans Peter Freythere3d16bb2010-04-22 11:58:13 +08001123 if (silent)
1124 goto out_silent;
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +01001125 return create_err_response(endp, 400, "DLCX", p->trans);
Holger Hans Peter Freytherfe86d3c2010-02-26 13:37:05 +01001126 break;
1127 case MGCP_POLICY_DEFER:
1128 /* stop processing */
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +08001129 delete_transcoder(endp);
Holger Hans Peter Freytherfe86d3c2010-02-26 13:37:05 +01001130 return NULL;
1131 break;
1132 case MGCP_POLICY_CONT:
1133 /* just continue */
1134 break;
1135 }
1136 }
1137
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +01001138 /* free the connection */
Holger Hans Peter Freythere378cb12010-08-06 20:22:23 +08001139 LOGP(DMGCP, LOGL_DEBUG, "Deleted endpoint on: 0x%x Server: %s:%u\n",
Holger Hans Peter Freythera17d7012010-08-05 01:34:51 +08001140 ENDPOINT_NUMBER(endp), inet_ntoa(endp->net_end.addr), ntohs(endp->net_end.rtp_port));
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +08001141
Holger Hans Peter Freyther0bf15a82012-09-14 17:18:12 +02001142 /* save the statistics of the current call */
1143 mgcp_format_stats(endp, stats, sizeof(stats));
1144
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +08001145 delete_transcoder(endp);
Holger Hans Peter Freyther154b9552010-02-26 13:27:51 +01001146 mgcp_free_endp(endp);
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +01001147 if (p->cfg->change_cb)
1148 p->cfg->change_cb(endp->tcfg, ENDPOINT_NUMBER(endp), MGCP_ENDP_DLCX);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +01001149
Holger Hans Peter Freythere3d16bb2010-04-22 11:58:13 +08001150 if (silent)
1151 goto out_silent;
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +01001152 return create_ok_resp_with_param(endp, 250, "DLCX", p->trans, stats);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +01001153
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +01001154error3:
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +01001155 return create_err_response(endp, error_code, "DLCX", p->trans);
Holger Hans Peter Freythere3d16bb2010-04-22 11:58:13 +08001156
1157out_silent:
1158 return NULL;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +01001159}
1160
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +01001161static struct msgb *handle_rsip(struct mgcp_parse_data *p)
Holger Hans Peter Freyther9bdcc9c2010-03-31 06:39:35 +02001162{
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +01001163 if (p->found != 0) {
Holger Hans Peter Freyther74db7742011-06-10 00:04:55 +02001164 LOGP(DMGCP, LOGL_ERROR, "Failed to find the endpoint.\n");
1165 return NULL;
1166 }
1167
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +01001168 if (p->cfg->reset_cb)
1169 p->cfg->reset_cb(p->endp->tcfg);
Holger Hans Peter Freyther9bdcc9c2010-03-31 06:39:35 +02001170 return NULL;
1171}
1172
Holger Hans Peter Freyther8d0be252012-11-29 12:54:22 +01001173static char extract_tone(const char *line)
1174{
1175 const char *str = strstr(line, "D/");
1176 if (!str)
1177 return CHAR_MAX;
1178
1179 return str[2];
1180}
1181
Holger Hans Peter Freyther6e94d6d2011-01-25 23:33:54 +01001182/*
1183 * This can request like DTMF detection and forward, fax detection... it
1184 * can also request when the notification should be send and such. We don't
1185 * do this right now.
1186 */
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +01001187static struct msgb *handle_noti_req(struct mgcp_parse_data *p)
Holger Hans Peter Freyther6e94d6d2011-01-25 23:33:54 +01001188{
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +01001189 int res = 0;
1190 char *line;
Holger Hans Peter Freyther9f3835b2013-05-21 17:04:35 +02001191 char tone = CHAR_MAX;
Holger Hans Peter Freyther6e94d6d2011-01-25 23:33:54 +01001192
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +01001193 if (p->found != 0)
1194 return create_err_response(NULL, 400, "RQNT", p->trans);
Holger Hans Peter Freyther6e94d6d2011-01-25 23:33:54 +01001195
Jacob Erlbeck17711712013-11-29 13:43:46 +01001196 for_each_line(line, p->save) {
Holger Hans Peter Freyther8d0be252012-11-29 12:54:22 +01001197 switch (line[0]) {
1198 case 'S':
1199 tone = extract_tone(line);
1200 break;
1201 }
Holger Hans Peter Freyther6e94d6d2011-01-25 23:33:54 +01001202 }
Holger Hans Peter Freyther8d0be252012-11-29 12:54:22 +01001203
1204 /* we didn't see a signal request with a tone */
1205 if (tone == CHAR_MAX)
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +01001206 return create_ok_response(p->endp, 200, "RQNT", p->trans);
Holger Hans Peter Freyther8d0be252012-11-29 12:54:22 +01001207
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +01001208 if (p->cfg->rqnt_cb)
1209 res = p->cfg->rqnt_cb(p->endp, tone);
Holger Hans Peter Freyther8d0be252012-11-29 12:54:22 +01001210
1211 return res == 0 ?
Holger Hans Peter Freytherce553612012-12-07 15:04:07 +01001212 create_ok_response(p->endp, 200, "RQNT", p->trans) :
1213 create_err_response(p->endp, res, "RQNT", p->trans);
Holger Hans Peter Freyther6e94d6d2011-01-25 23:33:54 +01001214}
1215
Jacob Erlbeck075a9eb2013-12-19 18:53:07 +01001216static void mgcp_keepalive_timer_cb(void *_tcfg)
1217{
1218 struct mgcp_trunk_config *tcfg = _tcfg;
1219 int i;
1220 LOGP(DMGCP, LOGL_DEBUG, "Triggered trunk %d keepalive timer.\n",
1221 tcfg->trunk_nr);
1222
1223 if (tcfg->keepalive_interval <= 0)
1224 return;
1225
1226 for (i = 1; i < tcfg->number_endpoints; ++i) {
1227 struct mgcp_endpoint *endp = &tcfg->endpoints[i];
1228 if (endp->conn_mode == MGCP_CONN_RECV_ONLY)
1229 mgcp_send_dummy(endp);
1230 }
1231
1232 LOGP(DMGCP, LOGL_DEBUG, "Rescheduling trunk %d keepalive timer.\n",
1233 tcfg->trunk_nr);
1234 osmo_timer_schedule(&tcfg->keepalive_timer, tcfg->keepalive_interval, 0);
1235}
1236
1237void mgcp_trunk_set_keepalive(struct mgcp_trunk_config *tcfg, int interval)
1238{
1239 tcfg->keepalive_interval = interval;
1240 tcfg->keepalive_timer.data = tcfg;
1241 tcfg->keepalive_timer.cb = mgcp_keepalive_timer_cb;
1242
1243 if (interval <= 0)
1244 osmo_timer_del(&tcfg->keepalive_timer);
1245 else
1246 osmo_timer_schedule(&tcfg->keepalive_timer,
1247 tcfg->keepalive_interval, 0);
1248}
1249
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +01001250struct mgcp_config *mgcp_config_alloc(void)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +01001251{
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +01001252 struct mgcp_config *cfg;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +01001253
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +01001254 cfg = talloc_zero(NULL, struct mgcp_config);
1255 if (!cfg) {
1256 LOGP(DMGCP, LOGL_FATAL, "Failed to allocate config.\n");
1257 return NULL;
1258 }
1259
1260 cfg->source_port = 2427;
1261 cfg->source_addr = talloc_strdup(cfg, "0.0.0.0");
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +01001262
Holger Hans Peter Freytherb98ba722010-09-19 04:21:39 +08001263 cfg->transcoder_remote_base = 4000;
Holger Hans Peter Freyther15e73892010-08-05 07:10:56 +08001264
1265 cfg->bts_ports.base_port = RTP_PORT_DEFAULT;
1266 cfg->net_ports.base_port = RTP_PORT_NET_DEFAULT;
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +01001267
Jacob Erlbecka0d64ce2014-03-13 14:24:52 +01001268 cfg->rtp_processing_cb = &mgcp_rtp_processing_default;
1269 cfg->setup_rtp_processing_cb = &mgcp_setup_rtp_processing_default;
1270
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +01001271 /* default trunk handling */
1272 cfg->trunk.cfg = cfg;
1273 cfg->trunk.trunk_nr = 0;
1274 cfg->trunk.trunk_type = MGCP_TRUNK_VIRTUAL;
1275 cfg->trunk.audio_name = talloc_strdup(cfg, "AMR/8000");
1276 cfg->trunk.audio_payload = 126;
Jacob Erlbeck0a1bc562013-12-10 13:09:37 +01001277 cfg->trunk.audio_send_ptime = 1;
Holger Hans Peter Freythera8090d52012-05-11 13:00:45 +02001278 cfg->trunk.omit_rtcp = 0;
Jacob Erlbeck075a9eb2013-12-19 18:53:07 +01001279 mgcp_trunk_set_keepalive(&cfg->trunk, MGCP_KEEPALIVE_ONCE);
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +01001280
Holger Hans Peter Freyther0e939fe2011-02-28 12:11:02 +01001281 INIT_LLIST_HEAD(&cfg->trunks);
1282
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +01001283 return cfg;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +01001284}
1285
Holger Hans Peter Freyther0e939fe2011-02-28 12:11:02 +01001286struct mgcp_trunk_config *mgcp_trunk_alloc(struct mgcp_config *cfg, int nr)
1287{
1288 struct mgcp_trunk_config *trunk;
1289
1290 trunk = talloc_zero(cfg, struct mgcp_trunk_config);
1291 if (!trunk) {
1292 LOGP(DMGCP, LOGL_ERROR, "Failed to allocate.\n");
1293 return NULL;
1294 }
1295
1296 trunk->cfg = cfg;
1297 trunk->trunk_type = MGCP_TRUNK_E1;
1298 trunk->trunk_nr = nr;
1299 trunk->audio_name = talloc_strdup(cfg, "AMR/8000");
1300 trunk->audio_payload = 126;
Jacob Erlbeck0a1bc562013-12-10 13:09:37 +01001301 trunk->audio_send_ptime = 1;
Holger Hans Peter Freyther0e939fe2011-02-28 12:11:02 +01001302 trunk->number_endpoints = 33;
Holger Hans Peter Freythera8090d52012-05-11 13:00:45 +02001303 trunk->omit_rtcp = 0;
Jacob Erlbeck075a9eb2013-12-19 18:53:07 +01001304 mgcp_trunk_set_keepalive(trunk, MGCP_KEEPALIVE_ONCE);
Holger Hans Peter Freyther0e939fe2011-02-28 12:11:02 +01001305 llist_add_tail(&trunk->entry, &cfg->trunks);
1306 return trunk;
1307}
1308
1309struct mgcp_trunk_config *mgcp_trunk_num(struct mgcp_config *cfg, int index)
1310{
1311 struct mgcp_trunk_config *trunk;
1312
1313 llist_for_each_entry(trunk, &cfg->trunks, entry)
1314 if (trunk->trunk_nr == index)
1315 return trunk;
1316
1317 return NULL;
1318}
1319
Holger Hans Peter Freythera17d7012010-08-05 01:34:51 +08001320static void mgcp_rtp_end_reset(struct mgcp_rtp_end *end)
1321{
Holger Hans Peter Freythere97155a2010-11-02 19:06:13 +01001322 if (end->local_alloc == PORT_ALLOC_DYNAMIC) {
Holger Hans Peter Freytherf138f912010-08-05 08:08:17 +08001323 mgcp_free_rtp_port(end);
Holger Hans Peter Freythere97155a2010-11-02 19:06:13 +01001324 end->local_port = 0;
1325 }
Holger Hans Peter Freytherf138f912010-08-05 08:08:17 +08001326
Holger Hans Peter Freytherc4921272010-08-05 03:37:22 +08001327 end->packets = 0;
Holger Hans Peter Freyther952f7522012-09-12 11:38:37 +02001328 end->octets = 0;
Jacob Erlbeck0970bab2013-12-19 12:13:32 +01001329 end->dropped_packets = 0;
Holger Hans Peter Freytherc4921272010-08-05 03:37:22 +08001330 memset(&end->addr, 0, sizeof(end->addr));
Holger Hans Peter Freythere97155a2010-11-02 19:06:13 +01001331 end->rtp_port = end->rtcp_port = 0;
Holger Hans Peter Freythera17d7012010-08-05 01:34:51 +08001332 end->payload_type = -1;
Holger Hans Peter Freytherf138f912010-08-05 08:08:17 +08001333 end->local_alloc = -1;
Holger Hans Peter Freyther5ea1bc72012-09-03 00:07:39 +02001334 talloc_free(end->fmtp_extra);
1335 end->fmtp_extra = NULL;
Jacob Erlbeck845d0052014-03-17 12:30:56 +01001336 talloc_free(end->subtype_name);
1337 end->subtype_name = NULL;
1338 talloc_free(end->audio_name);
1339 end->audio_name = NULL;
Jacob Erlbecka0d64ce2014-03-13 14:24:52 +01001340 talloc_free(end->rtp_process_data);
1341 end->rtp_process_data = NULL;
Jacob Erlbeck72c30902013-11-25 15:23:35 +01001342
1343 /* Set default values */
1344 end->frame_duration_num = DEFAULT_RTP_AUDIO_FRAME_DUR_NUM;
1345 end->frame_duration_den = DEFAULT_RTP_AUDIO_FRAME_DUR_DEN;
Jacob Erlbeckf6ec0e92013-12-04 10:30:11 +01001346 end->frames_per_packet = 0; /* unknown */
1347 end->packet_duration_ms = DEFAULT_RTP_AUDIO_PACKET_DURATION_MS;
1348 end->rate = DEFAULT_RTP_AUDIO_DEFAULT_RATE;
Jacob Erlbeck845d0052014-03-17 12:30:56 +01001349 end->channels = DEFAULT_RTP_AUDIO_DEFAULT_CHANNELS;
Jacob Erlbeck8857c902014-01-16 16:50:39 +01001350 end->output_enabled = 0;
Holger Hans Peter Freythera17d7012010-08-05 01:34:51 +08001351}
1352
Holger Hans Peter Freytherc4921272010-08-05 03:37:22 +08001353static void mgcp_rtp_end_init(struct mgcp_rtp_end *end)
1354{
1355 mgcp_rtp_end_reset(end);
1356 end->rtp.fd = -1;
1357 end->rtcp.fd = -1;
1358}
1359
Holger Hans Peter Freyther1f0c5b42011-02-28 14:37:03 +01001360int mgcp_endpoints_allocate(struct mgcp_trunk_config *tcfg)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +01001361{
1362 int i;
1363
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +01001364 /* Initialize all endpoints */
Holger Hans Peter Freyther1f0c5b42011-02-28 14:37:03 +01001365 tcfg->endpoints = _talloc_zero_array(tcfg->cfg,
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +01001366 sizeof(struct mgcp_endpoint),
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +01001367 tcfg->number_endpoints, "endpoints");
1368 if (!tcfg->endpoints)
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +01001369 return -1;
1370
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +01001371 for (i = 0; i < tcfg->number_endpoints; ++i) {
1372 tcfg->endpoints[i].ci = CI_UNUSED;
Holger Hans Peter Freyther1f0c5b42011-02-28 14:37:03 +01001373 tcfg->endpoints[i].cfg = tcfg->cfg;
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +01001374 tcfg->endpoints[i].tcfg = tcfg;
1375 mgcp_rtp_end_init(&tcfg->endpoints[i].net_end);
1376 mgcp_rtp_end_init(&tcfg->endpoints[i].bts_end);
1377 mgcp_rtp_end_init(&tcfg->endpoints[i].trans_net);
1378 mgcp_rtp_end_init(&tcfg->endpoints[i].trans_bts);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +01001379 }
1380
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +01001381 return 0;
1382}
Holger Hans Peter Freyther154b9552010-02-26 13:27:51 +01001383
1384void mgcp_free_endp(struct mgcp_endpoint *endp)
1385{
Holger Hans Peter Freytherc77efdf2010-03-31 12:31:09 +02001386 LOGP(DMGCP, LOGL_DEBUG, "Deleting endpoint on: 0x%x\n", ENDPOINT_NUMBER(endp));
Holger Hans Peter Freyther89976e82010-08-03 15:01:43 +00001387 endp->ci = CI_UNUSED;
Holger Hans Peter Freyther39a97e22010-08-06 18:03:11 +08001388 endp->allocated = 0;
Holger Hans Peter Freyther154b9552010-02-26 13:27:51 +01001389
Holger Hans Peter Freyther01d315f2012-12-07 11:52:16 +01001390 talloc_free(endp->callid);
1391 endp->callid = NULL;
Holger Hans Peter Freyther154b9552010-02-26 13:27:51 +01001392
Jacob Erlbeck2c2ca4d2013-12-09 14:32:03 +01001393 talloc_free(endp->local_options.string);
1394 endp->local_options.string = NULL;
Holger Hans Peter Freyther154b9552010-02-26 13:27:51 +01001395
Holger Hans Peter Freythera17d7012010-08-05 01:34:51 +08001396 mgcp_rtp_end_reset(&endp->bts_end);
1397 mgcp_rtp_end_reset(&endp->net_end);
Holger Hans Peter Freyther21262332010-11-01 20:53:31 +01001398 mgcp_rtp_end_reset(&endp->trans_net);
Holger Hans Peter Freytherbd7b3c52010-11-01 21:04:54 +01001399 mgcp_rtp_end_reset(&endp->trans_bts);
Pablo Neira Ayuso46bd4242013-07-08 05:09:46 +02001400 endp->type = MGCP_RTP_DEFAULT;
Holger Hans Peter Freyther380b8712010-07-29 02:38:39 +08001401
Holger Hans Peter Freyther31868922010-08-03 11:59:04 +00001402 memset(&endp->net_state, 0, sizeof(endp->net_state));
1403 memset(&endp->bts_state, 0, sizeof(endp->bts_state));
Holger Hans Peter Freytherc597a4e2010-08-03 02:57:02 +08001404
1405 endp->conn_mode = endp->orig_mode = MGCP_CONN_NONE;
Holger Hans Peter Freyther260d6ed2010-08-06 01:12:21 +08001406
1407 memset(&endp->taps, 0, sizeof(endp->taps));
Holger Hans Peter Freyther154b9552010-02-26 13:27:51 +01001408}
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +08001409
Holger Hans Peter Freyther557b1ab2010-09-19 04:39:55 +08001410static int send_trans(struct mgcp_config *cfg, const char *buf, int len)
1411{
1412 struct sockaddr_in addr;
1413
1414 memset(&addr, 0, sizeof(addr));
1415 addr.sin_family = AF_INET;
1416 addr.sin_addr = cfg->transcoder_in;
1417 addr.sin_port = htons(2427);
1418 return sendto(cfg->gw_fd.bfd.fd, buf, len, 0,
1419 (struct sockaddr *) &addr, sizeof(addr));
1420}
1421
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +08001422static void send_msg(struct mgcp_endpoint *endp, int endpoint, int port,
1423 const char *msg, const char *mode)
1424{
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +08001425 char buf[2096];
1426 int len;
Jacob Erlbeck845d0052014-03-17 12:30:56 +01001427 const char *audio_name = endp->bts_end.audio_name;
1428 int payload_type = endp->bts_end.payload_type;
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +08001429
1430 /* hardcoded to AMR right now, we do not know the real type at this point */
1431 len = snprintf(buf, sizeof(buf),
1432 "%s 42 %x@mgw MGCP 1.0\r\n"
1433 "C: 4256\r\n"
1434 "M: %s\r\n"
1435 "\r\n"
1436 "c=IN IP4 %s\r\n"
1437 "m=audio %d RTP/AVP %d\r\n"
Jacob Erlbeck845d0052014-03-17 12:30:56 +01001438 "a=rtpmap:%d%s%s\r\n",
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +08001439 msg, endpoint, mode, endp->cfg->source_addr,
Jacob Erlbeck845d0052014-03-17 12:30:56 +01001440 port, payload_type,
1441 payload_type,
1442 audio_name ? " " : "", audio_name ? audio_name : "");
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +08001443
1444 if (len < 0)
1445 return;
1446
1447 buf[sizeof(buf) - 1] = '\0';
1448
Holger Hans Peter Freyther557b1ab2010-09-19 04:39:55 +08001449 send_trans(endp->cfg, buf, len);
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +08001450}
1451
1452static void send_dlcx(struct mgcp_endpoint *endp, int endpoint)
1453{
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +08001454 char buf[2096];
1455 int len;
1456
1457 len = snprintf(buf, sizeof(buf),
1458 "DLCX 43 %x@mgw MGCP 1.0\r\n"
1459 "C: 4256\r\n"
1460 , endpoint);
1461
1462 if (len < 0)
1463 return;
1464
1465 buf[sizeof(buf) - 1] = '\0';
1466
Holger Hans Peter Freyther557b1ab2010-09-19 04:39:55 +08001467 send_trans(endp->cfg, buf, len);
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +08001468}
1469
Harald Welte6a857052012-01-27 00:41:39 +01001470static int send_agent(struct mgcp_config *cfg, const char *buf, int len)
1471{
1472 return write(cfg->gw_fd.bfd.fd, buf, len);
1473}
1474
1475int mgcp_send_reset_all(struct mgcp_config *cfg)
1476{
1477 static const char mgcp_reset[] = {
1478 "RSIP 1 *@mgw MGCP 1.0\r\n"
1479 };
1480
1481 return send_agent(cfg, mgcp_reset, sizeof mgcp_reset -1);
1482}
1483
1484int mgcp_send_reset_ep(struct mgcp_endpoint *endp, int endpoint)
1485{
1486 char buf[128];
1487 int len;
1488
1489 len = snprintf(buf, sizeof(buf),
1490 "RSIP 39 %x@mgw MGCP 1.0\r\n"
1491 , endpoint);
1492 if (len < 0)
1493 return len;
1494
1495 buf[sizeof(buf) - 1] = '\0';
1496
1497 return send_agent(endp->cfg, buf, len);
1498}
1499
Jacob Erlbecka0d64ce2014-03-13 14:24:52 +01001500static void setup_rtp_processing(struct mgcp_endpoint *endp)
1501{
1502 struct mgcp_config *cfg = endp->cfg;
1503
1504 if (endp->type != MGCP_RTP_DEFAULT)
1505 return;
1506
1507 if (endp->conn_mode == MGCP_CONN_LOOPBACK)
1508 return;
1509
1510 if (endp->conn_mode & MGCP_CONN_SEND_ONLY)
1511 cfg->setup_rtp_processing_cb(endp, &endp->net_end, &endp->bts_end);
1512 else
1513 cfg->setup_rtp_processing_cb(endp, &endp->net_end, NULL);
1514
1515 if (endp->conn_mode & MGCP_CONN_RECV_ONLY)
1516 cfg->setup_rtp_processing_cb(endp, &endp->bts_end, &endp->net_end);
1517 else
1518 cfg->setup_rtp_processing_cb(endp, &endp->bts_end, NULL);
1519}
1520
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +08001521static void create_transcoder(struct mgcp_endpoint *endp)
1522{
1523 int port;
1524 int in_endp = ENDPOINT_NUMBER(endp);
Holger Hans Peter Freytherbd7b3c52010-11-01 21:04:54 +01001525 int out_endp = endp_back_channel(in_endp);
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +08001526
Pablo Neira Ayuso46bd4242013-07-08 05:09:46 +02001527 if (endp->type != MGCP_RTP_TRANSCODED)
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +08001528 return;
1529
Holger Hans Peter Freyther8b19dee2010-11-01 22:38:25 +01001530 send_msg(endp, in_endp, endp->trans_bts.local_port, "CRCX", "sendrecv");
1531 send_msg(endp, in_endp, endp->trans_bts.local_port, "MDCX", "sendrecv");
Holger Hans Peter Freyther21262332010-11-01 20:53:31 +01001532 send_msg(endp, out_endp, endp->trans_net.local_port, "CRCX", "sendrecv");
1533 send_msg(endp, out_endp, endp->trans_net.local_port, "MDCX", "sendrecv");
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +08001534
Holger Hans Peter Freytherbd7b3c52010-11-01 21:04:54 +01001535 port = rtp_calculate_port(in_endp, endp->cfg->transcoder_remote_base);
1536 endp->trans_bts.rtp_port = htons(port);
1537 endp->trans_bts.rtcp_port = htons(port + 1);
1538
Holger Hans Peter Freytherb98ba722010-09-19 04:21:39 +08001539 port = rtp_calculate_port(out_endp, endp->cfg->transcoder_remote_base);
Holger Hans Peter Freyther21262332010-11-01 20:53:31 +01001540 endp->trans_net.rtp_port = htons(port);
1541 endp->trans_net.rtcp_port = htons(port + 1);
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +08001542}
1543
1544static void delete_transcoder(struct mgcp_endpoint *endp)
1545{
1546 int in_endp = ENDPOINT_NUMBER(endp);
Holger Hans Peter Freytherbd7b3c52010-11-01 21:04:54 +01001547 int out_endp = endp_back_channel(in_endp);
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +08001548
Pablo Neira Ayuso46bd4242013-07-08 05:09:46 +02001549 if (endp->type != MGCP_RTP_TRANSCODED)
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +08001550 return;
1551
1552 send_dlcx(endp, in_endp);
1553 send_dlcx(endp, out_endp);
1554}
Holger Hans Peter Freytherf2eedff2010-09-19 04:36:07 +08001555
1556int mgcp_reset_transcoder(struct mgcp_config *cfg)
1557{
Holger Hans Peter Freytherf2eedff2010-09-19 04:36:07 +08001558 if (!cfg->transcoder_ip)
Holger Hans Peter Freythercf1c8772010-09-24 04:41:28 +08001559 return 0;
Holger Hans Peter Freytherf2eedff2010-09-19 04:36:07 +08001560
1561 static const char mgcp_reset[] = {
1562 "RSIP 1 13@mgw MGCP 1.0\r\n"
1563 };
1564
Holger Hans Peter Freyther557b1ab2010-09-19 04:39:55 +08001565 return send_trans(cfg, mgcp_reset, sizeof mgcp_reset -1);
Holger Hans Peter Freytherf2eedff2010-09-19 04:36:07 +08001566}
Holger Hans Peter Freyther0bf15a82012-09-14 17:18:12 +02001567
1568void mgcp_format_stats(struct mgcp_endpoint *endp, char *msg, size_t size)
1569{
Holger Hans Peter Freythercb306a62012-10-24 21:22:47 +02001570 uint32_t expected, jitter;
Holger Hans Peter Freyther38e02c52012-10-22 18:09:35 +02001571 int ploss;
Jacob Erlbeck50079a12013-11-25 12:53:28 +01001572 int nchars;
Holger Hans Peter Freyther38e02c52012-10-22 18:09:35 +02001573 mgcp_state_calc_loss(&endp->net_state, &endp->net_end,
1574 &expected, &ploss);
Holger Hans Peter Freythercb306a62012-10-24 21:22:47 +02001575 jitter = mgcp_state_calc_jitter(&endp->net_state);
Holger Hans Peter Freyther38e02c52012-10-22 18:09:35 +02001576
Jacob Erlbeck50079a12013-11-25 12:53:28 +01001577 nchars = snprintf(msg, size,
1578 "\r\nP: PS=%u, OS=%u, PR=%u, OR=%u, PL=%d, JI=%u",
1579 endp->bts_end.packets, endp->bts_end.octets,
1580 endp->net_end.packets, endp->net_end.octets,
1581 ploss, jitter);
1582 if (nchars < 0 || nchars >= size)
1583 goto truncate;
1584
1585 msg += nchars;
1586 size -= nchars;
1587
1588 /* Error Counter */
1589 snprintf(msg, size,
1590 "\r\nX-Osmo-CP: EC TIS=%u, TOS=%u, TIR=%u, TOR=%u",
1591 endp->net_state.in_stream.err_ts_counter,
1592 endp->net_state.out_stream.err_ts_counter,
1593 endp->bts_state.in_stream.err_ts_counter,
1594 endp->bts_state.out_stream.err_ts_counter);
1595truncate:
Holger Hans Peter Freyther0bf15a82012-09-14 17:18:12 +02001596 msg[size - 1] = '\0';
1597}
Holger Hans Peter Freyther462b7d72012-10-24 21:53:40 +02001598
1599int mgcp_parse_stats(struct msgb *msg, uint32_t *ps, uint32_t *os,
1600 uint32_t *pr, uint32_t *_or, int *loss, uint32_t *jitter)
1601{
1602 char *line, *save;
1603 int rc;
1604
1605 /* initialize with bad values */
1606 *ps = *os = *pr = *_or = *jitter = UINT_MAX;
1607 *loss = INT_MAX;
1608
1609
1610 line = strtok_r((char *) msg->l2h, "\r\n", &save);
1611 if (!line)
1612 return -1;
1613
1614 /* this can only parse the message that is created above... */
Jacob Erlbecka01bd602013-11-29 13:43:43 +01001615 for_each_non_empty_line(line, save) {
Holger Hans Peter Freyther462b7d72012-10-24 21:53:40 +02001616 switch (line[0]) {
1617 case 'P':
1618 rc = sscanf(line, "P: PS=%u, OS=%u, PR=%u, OR=%u, PL=%d, JI=%u",
1619 ps, os, pr, _or, loss, jitter);
1620 return rc == 6 ? 0 : -1;
1621 }
1622 }
1623
1624 return -1;
1625}