blob: 7837378f3dec6345c0c5fe28b56a59ac98193797 [file] [log] [blame]
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +01001/* A Media Gateway Control Protocol Media Gateway: RFC 3435 */
2/* The protocol implementation */
3
4/*
Holger Hans Peter Freyther46880c22012-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 Freyther26143c82010-02-03 08:50:33 +01007 * All Rights Reserved
8 *
9 * This program is free software; you can redistribute it and/or modify
Harald Welte0e3e88e2011-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 Freyther26143c82010-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 Welte0e3e88e2011-01-01 15:25:50 +010017 * GNU Affero General Public License for more details.
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +010018 *
Harald Welte0e3e88e2011-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 Freyther26143c82010-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 Erlbeck8f518d62014-03-17 12:30:56 +010031#include <errno.h>
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +010032
Pablo Neira Ayusodd5fff42011-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 Freyther6d419f92011-02-28 22:06:47 +010036
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +010037#include <openbsc/mgcp.h>
Holger Hans Peter Freyther6f38c062010-02-20 21:21:02 +010038#include <openbsc/mgcp_internal.h>
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +010039
Jacob Erlbeck7a6510c2013-11-29 13:43:43 +010040#define for_each_non_empty_line(line, save) \
Holger Hans Peter Freythercd256952012-12-07 15:04:07 +010041 for (line = strtok_r(NULL, "\r\n", &save); line;\
Harald Welteec4f01b2012-01-27 12:31:36 +010042 line = strtok_r(NULL, "\r\n", &save))
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +010043
Jacob Erlbecke7060c42013-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 Erlbeckac9f6ce2013-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 Erlbeckd69cf602013-12-04 10:30:11 +010079#define DEFAULT_RTP_AUDIO_PACKET_DURATION_MS 20
Jacob Erlbeckac9f6ce2013-11-25 15:23:35 +010080#define DEFAULT_RTP_AUDIO_DEFAULT_RATE 8000
Jacob Erlbeck8f518d62014-03-17 12:30:56 +010081#define DEFAULT_RTP_AUDIO_DEFAULT_CHANNELS 1
Jacob Erlbeckac9f6ce2013-11-25 15:23:35 +010082
Holger Hans Peter Freyther05d8f5f2010-08-05 08:08:17 +080083static void mgcp_rtp_end_reset(struct mgcp_rtp_end *end);
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +010084
Holger Hans Peter Freythercd256952012-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 Freyther26143c82010-02-03 08:50:33 +010093struct mgcp_request {
94 char *name;
Holger Hans Peter Freythercd256952012-12-07 15:04:07 +010095 struct msgb *(*handle_request) (struct mgcp_parse_data *data);
Holger Hans Peter Freyther26143c82010-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 Freythercd256952012-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 Freyther26143c82010-02-03 08:50:33 +0100108
Holger Hans Peter Freyther017738d2010-09-18 06:35:29 +0800109static void create_transcoder(struct mgcp_endpoint *endp);
110static void delete_transcoder(struct mgcp_endpoint *endp);
111
Jacob Erlbeck6a163052014-03-13 14:24:52 +0100112static void setup_rtp_processing(struct mgcp_endpoint *endp);
113
Holger Hans Peter Freythercd256952012-12-07 15:04:07 +0100114static int mgcp_analyze_header(struct mgcp_parse_data *parse, char *data);
115
Holger Hans Peter Freyther67f103e2014-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 Freyther526b4d32010-08-06 08:26:54 +0800129static uint32_t generate_call_id(struct mgcp_config *cfg)
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100130{
131 int i;
132
133 /* use the call id */
Holger Hans Peter Freyther6f38c062010-02-20 21:21:02 +0100134 ++cfg->last_call_id;
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100135
136 /* handle wrap around */
Holger Hans Peter Freyther6f38c062010-02-20 21:21:02 +0100137 if (cfg->last_call_id == CI_UNUSED)
138 ++cfg->last_call_id;
Holger Hans Peter Freyther26143c82010-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 Freytherab56ce12011-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 Freyther6f38c062010-02-20 21:21:02 +0100144 return generate_call_id(cfg);
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100145
Holger Hans Peter Freyther6f38c062010-02-20 21:21:02 +0100146 return cfg->last_call_id;
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100147}
148
Holger Hans Peter Freyther26143c82010-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 Freytherac0968e2011-01-25 23:33:54 +0100159 MGCP_REQUEST("RQNT", handle_noti_req, "NotificationRequest")
Holger Hans Peter Freytherd60c6e52010-03-31 06:39:35 +0200160
161 /* SPEC extension */
162 MGCP_REQUEST("RSIP", handle_rsip, "ReSetInProgress")
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100163};
164
Holger Hans Peter Freytherad4e3392010-02-03 11:03:45 +0100165static struct msgb *mgcp_msgb_alloc(void)
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100166{
Holger Hans Peter Freytherad4e3392010-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 Freythercd256952012-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 Freyther3ba9cce2012-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 Freyther8fc6d082012-09-14 17:18:12 +0200188 const char *trans, const char *param,
189 const char *sdp)
Holger Hans Peter Freytherad4e3392010-02-03 11:03:45 +0100190{
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100191 int len;
Holger Hans Peter Freytherad4e3392010-02-03 11:03:45 +0100192 struct msgb *res;
193
194 res = mgcp_msgb_alloc();
195 if (!res)
196 return NULL;
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100197
Holger Hans Peter Freyther8fc6d082012-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 Freyther26143c82010-02-03 08:50:33 +0100204 }
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100205
Holger Hans Peter Freytherad4e3392010-02-03 11:03:45 +0100206 res->l2h = msgb_put(res, len);
Holger Hans Peter Freythercd256952012-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 Freytherad4e3392010-02-03 11:03:45 +0100222 return res;
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100223}
224
Holger Hans Peter Freyther3ba9cce2012-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 Freyther8fc6d082012-09-14 17:18:12 +0200227 const char *trans, const char *param)
228{
Holger Hans Peter Freyther3ba9cce2012-12-07 15:14:27 +0100229 return create_resp(endp, code, " OK", msg, trans, param, NULL);
Holger Hans Peter Freyther8fc6d082012-09-14 17:18:12 +0200230}
231
Holger Hans Peter Freyther3ba9cce2012-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 Freyther26143c82010-02-03 08:50:33 +0100234{
Holger Hans Peter Freyther3ba9cce2012-12-07 15:14:27 +0100235 return create_ok_resp_with_param(endp, code, msg, trans, NULL);
Holger Hans Peter Freyther804019a2011-01-06 16:19:55 +0100236}
237
Holger Hans Peter Freyther3ba9cce2012-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 Freyther804019a2011-01-06 16:19:55 +0100240{
Holger Hans Peter Freyther3ba9cce2012-12-07 15:14:27 +0100241 return create_resp(endp, code, " FAIL", msg, trans, NULL, NULL);
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100242}
243
Holger Hans Peter Freyther60d02a32010-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 Freyther26143c82010-02-03 08:50:33 +0100246{
Holger Hans Peter Freyther6f38c062010-02-20 21:21:02 +0100247 const char *addr = endp->cfg->local_ip;
Jacob Erlbeckfe0301a2014-03-17 12:40:07 +0100248 const char *fmtp_extra;
249 const char *audio_name;
250 int payload_type;
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100251 char sdp_record[4096];
Jacob Erlbecke91324d2013-12-10 13:09:37 +0100252 int len;
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100253
Jacob Erlbeckfe0301a2014-03-17 12:40:07 +0100254 endp->cfg->get_net_downlink_format_cb(endp, &payload_type,
255 &audio_name, &fmtp_extra);
256
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100257 if (!addr)
Holger Hans Peter Freyther6f38c062010-02-20 21:21:02 +0100258 addr = endp->cfg->source_addr;
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100259
Jacob Erlbecke91324d2013-12-10 13:09:37 +0100260 len = snprintf(sdp_record, sizeof(sdp_record) - 1,
Pablo Neira Ayuso4a2f6592014-02-05 18:56:17 +0100261 "I: %u%s\n\n"
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100262 "v=0\r\n"
Holger Hans Peter Freyther2e0af512011-07-20 20:43:15 +0200263 "o=- %u 23 IN IP4 %s\r\n"
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100264 "c=IN IP4 %s\r\n"
Holger Hans Peter Freyther2e0af512011-07-20 20:43:15 +0200265 "t=0 0\r\n"
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100266 "m=audio %d RTP/AVP %d\r\n"
Jacob Erlbeck8f518d62014-03-17 12:30:56 +0100267 "a=rtpmap:%d%s%s\r\n"
Holger Hans Peter Freyther4928d1b2012-09-03 00:07:39 +0200268 "%s%s",
Pablo Neira Ayuso4a2f6592014-02-05 18:56:17 +0100269 endp->ci, endp->cfg->osmux && endp->osmux ? "\nX-Osmux: On" : "",
270 endp->ci, addr, addr,
Jacob Erlbeck8f518d62014-03-17 12:30:56 +0100271 endp->net_end.local_port, payload_type,
272 payload_type,
273 audio_name ? " " : "", audio_name ? audio_name : "",
Holger Hans Peter Freyther4928d1b2012-09-03 00:07:39 +0200274 fmtp_extra ? fmtp_extra : "", fmtp_extra ? "\r\n" : "");
Jacob Erlbecke91324d2013-12-10 13:09:37 +0100275
276 if (len < 0 || len >= sizeof(sdp_record))
277 goto buffer_too_small;
278
279 if (endp->bts_end.packet_duration_ms > 0 && endp->tcfg->audio_send_ptime) {
280 int nchars = snprintf(sdp_record + len, sizeof(sdp_record) - len,
281 "a=ptime:%d\r\n",
282 endp->bts_end.packet_duration_ms);
283 if (nchars < 0 || nchars >= sizeof(sdp_record) - len)
284 goto buffer_too_small;
285
286 len += nchars;
287 }
Holger Hans Peter Freyther3ba9cce2012-12-07 15:14:27 +0100288 return create_resp(endp, 200, " OK", msg, trans_id, NULL, sdp_record);
Jacob Erlbecke91324d2013-12-10 13:09:37 +0100289
290buffer_too_small:
291 LOGP(DMGCP, LOGL_ERROR, "SDP buffer too small: %d (needed %d)\n",
292 sizeof(sdp_record), len);
293 return NULL;
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100294}
295
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100296/*
297 * handle incoming messages:
298 * - this can be a command (four letters, space, transaction id)
299 * - or a response (three numbers, space, transaction id)
300 */
Holger Hans Peter Freyther6f38c062010-02-20 21:21:02 +0100301struct msgb *mgcp_handle_message(struct mgcp_config *cfg, struct msgb *msg)
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100302{
Holger Hans Peter Freythercd256952012-12-07 15:04:07 +0100303 struct mgcp_parse_data pdata;
304 int i, code, handled = 0;
Holger Hans Peter Freytherad4e3392010-02-03 11:03:45 +0100305 struct msgb *resp = NULL;
Holger Hans Peter Freythercd256952012-12-07 15:04:07 +0100306 char *data;
Jacob Erlbeck3c629c62013-12-03 17:14:44 +0100307 unsigned char *tail = msg->l2h + msgb_l2len(msg); /* char after l2 data */
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100308
Holger Hans Peter Freyther0421be72010-03-31 13:26:46 +0200309 if (msgb_l2len(msg) < 4) {
Holger Hans Peter Freytherbed02ba2012-12-07 16:46:19 +0100310 LOGP(DMGCP, LOGL_ERROR, "msg too short: %d\n", msg->len);
Holger Hans Peter Freytherad4e3392010-02-03 11:03:45 +0100311 return NULL;
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100312 }
313
Jacob Erlbeck3c629c62013-12-03 17:14:44 +0100314 /* Ensure that the msg->l2h is NUL terminated. */
315 if (tail[-1] == '\0')
316 /* nothing to do */;
317 else if (msgb_tailroom(msg) > 0)
318 tail[0] = '\0';
319 else if (tail[-1] == '\r' || tail[-1] == '\n')
320 tail[-1] = '\0';
321 else {
322 LOGP(DMGCP, LOGL_ERROR, "Cannot NUL terminate MGCP message: "
323 "Length: %d, Buffer size: %d\n",
324 msgb_l2len(msg), msg->data_len);
325 return NULL;
326 }
327
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100328 /* attempt to treat it as a response */
Holger Hans Peter Freyther0421be72010-03-31 13:26:46 +0200329 if (sscanf((const char *)&msg->l2h[0], "%3d %*s", &code) == 1) {
Holger Hans Peter Freyther40faed82010-02-26 13:30:57 +0100330 LOGP(DMGCP, LOGL_DEBUG, "Response: Code: %d\n", code);
Holger Hans Peter Freytherb139e2c2012-12-07 16:07:46 +0100331 return NULL;
332 }
333
334 msg->l3h = &msg->l2h[4];
335
Holger Hans Peter Freythercd256952012-12-07 15:04:07 +0100336
337 /*
338 * Check for a duplicate message and respond.
Holger Hans Peter Freythercd256952012-12-07 15:04:07 +0100339 */
340 memset(&pdata, 0, sizeof(pdata));
341 pdata.cfg = cfg;
Jacob Erlbeck9cec6672013-11-29 13:43:46 +0100342 data = strline_r((char *) msg->l3h, &pdata.save);
Holger Hans Peter Freythercd256952012-12-07 15:04:07 +0100343 pdata.found = mgcp_analyze_header(&pdata, data);
344 if (pdata.endp && pdata.trans
345 && pdata.endp->last_trans
346 && strcmp(pdata.endp->last_trans, pdata.trans) == 0) {
347 return do_retransmission(pdata.endp);
348 }
349
Holger Hans Peter Freytherb139e2c2012-12-07 16:07:46 +0100350 for (i = 0; i < ARRAY_SIZE(mgcp_requests); ++i) {
351 if (strncmp(mgcp_requests[i].name, (const char *) &msg->l2h[0], 4) == 0) {
352 handled = 1;
Holger Hans Peter Freythercd256952012-12-07 15:04:07 +0100353 resp = mgcp_requests[i].handle_request(&pdata);
Holger Hans Peter Freytherb139e2c2012-12-07 16:07:46 +0100354 break;
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100355 }
356 }
357
Holger Hans Peter Freytherb139e2c2012-12-07 16:07:46 +0100358 if (!handled)
359 LOGP(DMGCP, LOGL_NOTICE, "MSG with type: '%.4s' not handled\n", &msg->l2h[0]);
360
Holger Hans Peter Freytherad4e3392010-02-03 11:03:45 +0100361 return resp;
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100362}
363
Holger Hans Peter Freytherf0bc0752011-01-06 19:32:52 +0100364/**
365 * We have a null terminated string with the endpoint name here. We only
366 * support two kinds. Simple ones as seen on the BSC level and the ones
367 * seen on the trunk side.
368 */
369static struct mgcp_endpoint *find_e1_endpoint(struct mgcp_config *cfg,
370 const char *mgcp)
371{
372 char *rest = NULL;
Holger Hans Peter Freyther1d137122011-02-28 14:13:47 +0100373 struct mgcp_trunk_config *tcfg;
374 int trunk, endp;
Holger Hans Peter Freytherf0bc0752011-01-06 19:32:52 +0100375
376 trunk = strtoul(mgcp + 6, &rest, 10);
Holger Hans Peter Freyther72026c12011-01-07 11:30:21 +0100377 if (rest == NULL || rest[0] != '/' || trunk < 1) {
Holger Hans Peter Freytherf0bc0752011-01-06 19:32:52 +0100378 LOGP(DMGCP, LOGL_ERROR, "Wrong trunk name '%s'\n", mgcp);
379 return NULL;
380 }
381
382 endp = strtoul(rest + 1, &rest, 10);
383 if (rest == NULL || rest[0] != '@') {
Holger Hans Peter Freyther72026c12011-01-07 11:30:21 +0100384 LOGP(DMGCP, LOGL_ERROR, "Wrong endpoint name '%s'\n", mgcp);
Holger Hans Peter Freytherf0bc0752011-01-06 19:32:52 +0100385 return NULL;
386 }
387
388 /* signalling is on timeslot 1 */
389 if (endp == 1)
390 return NULL;
391
Holger Hans Peter Freyther1d137122011-02-28 14:13:47 +0100392 tcfg = mgcp_trunk_num(cfg, trunk);
393 if (!tcfg) {
394 LOGP(DMGCP, LOGL_ERROR, "The trunk %d is not declared.\n", trunk);
395 return NULL;
396 }
397
398 if (!tcfg->endpoints) {
399 LOGP(DMGCP, LOGL_ERROR, "Endpoints of trunk %d not allocated.\n", trunk);
400 return NULL;
401 }
402
403 if (endp < 1 || endp >= tcfg->number_endpoints) {
Holger Hans Peter Freytherf0bc0752011-01-06 19:32:52 +0100404 LOGP(DMGCP, LOGL_ERROR, "Failed to find endpoint '%s'\n", mgcp);
Holger Hans Peter Freyther0f1786f2011-01-07 11:36:54 +0100405 return NULL;
Holger Hans Peter Freytherf0bc0752011-01-06 19:32:52 +0100406 }
407
Holger Hans Peter Freyther1d137122011-02-28 14:13:47 +0100408 return &tcfg->endpoints[endp];
Holger Hans Peter Freytherf0bc0752011-01-06 19:32:52 +0100409}
410
Holger Hans Peter Freyther6f38c062010-02-20 21:21:02 +0100411static struct mgcp_endpoint *find_endpoint(struct mgcp_config *cfg, const char *mgcp)
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100412{
413 char *endptr = NULL;
414 unsigned int gw = INT_MAX;
415
Holger Hans Peter Freytherf0bc0752011-01-06 19:32:52 +0100416 if (strncmp(mgcp, "ds/e1", 5) == 0) {
417 return find_e1_endpoint(cfg, mgcp);
418 } else {
419 gw = strtoul(mgcp, &endptr, 16);
Holger Hans Peter Freytherab56ce12011-02-28 00:56:17 +0100420 if (gw > 0 && gw < cfg->trunk.number_endpoints && strcmp(endptr, "@mgw") == 0)
421 return &cfg->trunk.endpoints[gw];
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100422 }
423
Holger Hans Peter Freytherf0bc0752011-01-06 19:32:52 +0100424 LOGP(DMGCP, LOGL_ERROR, "Not able to find endpoint: '%s'\n", mgcp);
425 return NULL;
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100426}
427
Harald Welteec4f01b2012-01-27 12:31:36 +0100428/**
429 * @returns 0 when the status line was complete and transaction_id and
430 * endp out parameters are set.
431 */
Holger Hans Peter Freythercd256952012-12-07 15:04:07 +0100432static int mgcp_analyze_header(struct mgcp_parse_data *pdata, char *data)
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100433{
Harald Welteec4f01b2012-01-27 12:31:36 +0100434 int i = 0;
Holger Hans Peter Freyther0b6dca72013-07-03 10:23:35 +0200435 char *elem, *save = NULL;
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100436
Holger Hans Peter Freythercd256952012-12-07 15:04:07 +0100437 pdata->trans = "000000";
Holger Hans Peter Freyther275c0442010-02-26 13:32:55 +0100438
Harald Welteec4f01b2012-01-27 12:31:36 +0100439 for (elem = strtok_r(data, " ", &save); elem;
440 elem = strtok_r(NULL, " ", &save)) {
441 switch (i) {
442 case 0:
Holger Hans Peter Freythercd256952012-12-07 15:04:07 +0100443 pdata->trans = elem;
Harald Welteec4f01b2012-01-27 12:31:36 +0100444 break;
445 case 1:
Holger Hans Peter Freythercd256952012-12-07 15:04:07 +0100446 pdata->endp = find_endpoint(pdata->cfg, elem);
447 if (!pdata->endp) {
448 LOGP(DMGCP, LOGL_ERROR,
449 "Unable to find Endpoint `%s'\n", elem);
450 return -1;
Harald Welteec4f01b2012-01-27 12:31:36 +0100451 }
452 break;
453 case 2:
454 if (strcmp("MGCP", elem)) {
455 LOGP(DMGCP, LOGL_ERROR,
456 "MGCP header parsing error\n");
457 return -1;
458 }
459 break;
460 case 3:
461 if (strcmp("1.0", elem)) {
462 LOGP(DMGCP, LOGL_ERROR, "MGCP version `%s' "
463 "not supported\n", elem);
464 return -1;
465 }
466 break;
467 }
468 i++;
469 }
470
471 if (i != 4) {
472 LOGP(DMGCP, LOGL_ERROR, "MGCP status line too short.\n");
Holger Hans Peter Freythercd256952012-12-07 15:04:07 +0100473 pdata->trans = "000000";
474 pdata->endp = NULL;
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100475 return -1;
476 }
477
Holger Hans Peter Freyther96354632010-04-01 03:27:04 +0200478 return 0;
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100479}
480
481static int verify_call_id(const struct mgcp_endpoint *endp,
482 const char *callid)
483{
484 if (strcmp(endp->callid, callid) != 0) {
Holger Hans Peter Freyther02c7a6f2010-02-03 09:13:10 +0100485 LOGP(DMGCP, LOGL_ERROR, "CallIDs does not match on 0x%x. '%s' != '%s'\n",
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100486 ENDPOINT_NUMBER(endp), endp->callid, callid);
487 return -1;
488 }
489
490 return 0;
491}
492
493static int verify_ci(const struct mgcp_endpoint *endp,
Holger Hans Peter Freyther526b4d32010-08-06 08:26:54 +0800494 const char *_ci)
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100495{
Holger Hans Peter Freyther526b4d32010-08-06 08:26:54 +0800496 uint32_t ci = strtoul(_ci, NULL, 10);
497
498 if (ci != endp->ci) {
499 LOGP(DMGCP, LOGL_ERROR, "ConnectionIdentifiers do not match on 0x%x. %u != %s\n",
500 ENDPOINT_NUMBER(endp), endp->ci, _ci);
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100501 return -1;
502 }
503
504 return 0;
505}
506
Holger Hans Peter Freythercd256952012-12-07 15:04:07 +0100507static struct msgb *handle_audit_endpoint(struct mgcp_parse_data *p)
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100508{
Holger Hans Peter Freythercd256952012-12-07 15:04:07 +0100509 if (p->found != 0)
510 return create_err_response(NULL, 500, "AUEP", p->trans);
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100511 else
Holger Hans Peter Freythercd256952012-12-07 15:04:07 +0100512 return create_ok_response(p->endp, 200, "AUEP", p->trans);
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100513}
514
Jacob Erlbeckecd157a2013-12-19 12:23:24 +0100515static int parse_conn_mode(const char *msg, struct mgcp_endpoint *endp)
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100516{
517 int ret = 0;
518 if (strcmp(msg, "recvonly") == 0)
Jacob Erlbeckecd157a2013-12-19 12:23:24 +0100519 endp->conn_mode = MGCP_CONN_RECV_ONLY;
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100520 else if (strcmp(msg, "sendrecv") == 0)
Jacob Erlbeckecd157a2013-12-19 12:23:24 +0100521 endp->conn_mode = MGCP_CONN_RECV_SEND;
Holger Hans Peter Freyther0bfcbee2010-09-18 20:21:44 +0800522 else if (strcmp(msg, "sendonly") == 0)
Jacob Erlbeckecd157a2013-12-19 12:23:24 +0100523 endp->conn_mode = MGCP_CONN_SEND_ONLY;
Holger Hans Peter Freyther0bdf20d2010-08-03 02:27:21 +0800524 else if (strcmp(msg, "loopback") == 0)
Jacob Erlbeckecd157a2013-12-19 12:23:24 +0100525 endp->conn_mode = MGCP_CONN_LOOPBACK;
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100526 else {
Holger Hans Peter Freyther02c7a6f2010-02-03 09:13:10 +0100527 LOGP(DMGCP, LOGL_ERROR, "Unknown connection mode: '%s'\n", msg);
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100528 ret = -1;
529 }
530
Jacob Erlbeckf3188612014-01-16 16:50:40 +0100531 endp->net_end.output_enabled =
532 endp->conn_mode & MGCP_CONN_SEND_ONLY ? 1 : 0;
533 endp->bts_end.output_enabled =
534 endp->conn_mode & MGCP_CONN_RECV_ONLY ? 1 : 0;
Jacob Erlbeckecd157a2013-12-19 12:23:24 +0100535
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100536 return ret;
537}
538
Jacob Erlbeck8f518d62014-03-17 12:30:56 +0100539static int set_audio_info(void *ctx, struct mgcp_rtp_end *rtp,
540 int payload_type, const char *audio_name)
541{
542 int rate = rtp->rate;
543 int channels = rtp->channels;
544 char audio_codec[64];
545
546 talloc_free(rtp->subtype_name);
547 rtp->subtype_name = NULL;
548 talloc_free(rtp->audio_name);
549 rtp->audio_name = NULL;
550
551 rtp->payload_type = payload_type;
552
553 if (!audio_name) {
554 switch (payload_type) {
555 case 3: audio_name = "GSM/8000/1"; break;
556 case 8: audio_name = "PCMA/8000/1"; break;
557 case 18: audio_name = "G729/8000/1"; break;
558 default:
559 /* Payload type is unknown, don't change rate and
560 * channels. */
561 /* TODO: return value? */
562 return 0;
563 }
564 }
565
566 if (sscanf(audio_name, "%63[^/]/%d/%d",
567 audio_codec, &rate, &channels) < 2)
568 return -EINVAL;
569
570 rtp->rate = rate;
571 rtp->channels = channels;
572 rtp->subtype_name = talloc_strdup(ctx, audio_codec);
573 rtp->audio_name = talloc_strdup(ctx, audio_name);
574 if (channels != 1)
575 LOGP(DMGCP, LOGL_NOTICE,
576 "Channels != 1 in SDP: '%s'\n", audio_name);
577
578 return 0;
579}
580
Holger Hans Peter Freyther05d8f5f2010-08-05 08:08:17 +0800581static int allocate_port(struct mgcp_endpoint *endp, struct mgcp_rtp_end *end,
Holger Hans Peter Freyther56ac2692010-09-18 02:30:02 +0800582 struct mgcp_port_range *range,
583 int (*alloc)(struct mgcp_endpoint *endp, int port))
Holger Hans Peter Freyther05d8f5f2010-08-05 08:08:17 +0800584{
585 int i;
586
587 if (range->mode == PORT_ALLOC_STATIC) {
Holger Hans Peter Freyther05d8f5f2010-08-05 08:08:17 +0800588 end->local_alloc = PORT_ALLOC_STATIC;
589 return 0;
590 }
591
592 /* attempt to find a port */
593 for (i = 0; i < 200; ++i) {
594 int rc;
595
596 if (range->last_port >= range->range_end)
597 range->last_port = range->range_start;
598
Holger Hans Peter Freyther56ac2692010-09-18 02:30:02 +0800599 rc = alloc(endp, range->last_port);
Holger Hans Peter Freyther05d8f5f2010-08-05 08:08:17 +0800600
601 range->last_port += 2;
602 if (rc == 0) {
603 end->local_alloc = PORT_ALLOC_DYNAMIC;
604 return 0;
605 }
606
607 }
608
Holger Hans Peter Freyther56ac2692010-09-18 02:30:02 +0800609 LOGP(DMGCP, LOGL_ERROR, "Allocating a RTP/RTCP port failed 200 times 0x%x.\n",
610 ENDPOINT_NUMBER(endp));
Holger Hans Peter Freyther05d8f5f2010-08-05 08:08:17 +0800611 return -1;
612}
613
614static int allocate_ports(struct mgcp_endpoint *endp)
615{
Holger Hans Peter Freyther56ac2692010-09-18 02:30:02 +0800616 if (allocate_port(endp, &endp->net_end, &endp->cfg->net_ports,
617 mgcp_bind_net_rtp_port) != 0)
Holger Hans Peter Freyther05d8f5f2010-08-05 08:08:17 +0800618 return -1;
619
Holger Hans Peter Freyther56ac2692010-09-18 02:30:02 +0800620 if (allocate_port(endp, &endp->bts_end, &endp->cfg->bts_ports,
621 mgcp_bind_bts_rtp_port) != 0) {
Holger Hans Peter Freyther05d8f5f2010-08-05 08:08:17 +0800622 mgcp_rtp_end_reset(&endp->net_end);
623 return -1;
624 }
625
Holger Hans Peter Freyther1b8eaf42011-02-28 14:51:48 +0100626 if (endp->cfg->transcoder_ip && endp->tcfg->trunk_type == MGCP_TRUNK_VIRTUAL) {
Holger Hans Peter Freytherb6345ab2010-11-01 20:53:31 +0100627 if (allocate_port(endp, &endp->trans_net,
Holger Hans Peter Freyther1d9a8eb2010-11-01 19:57:50 +0100628 &endp->cfg->transcoder_ports,
Holger Hans Peter Freytherc983f832010-11-01 21:04:54 +0100629 mgcp_bind_trans_net_rtp_port) != 0) {
Holger Hans Peter Freyther1d9a8eb2010-11-01 19:57:50 +0100630 mgcp_rtp_end_reset(&endp->net_end);
631 mgcp_rtp_end_reset(&endp->bts_end);
632 return -1;
633 }
634
Holger Hans Peter Freytherc983f832010-11-01 21:04:54 +0100635 if (allocate_port(endp, &endp->trans_bts,
636 &endp->cfg->transcoder_ports,
637 mgcp_bind_trans_bts_rtp_port) != 0) {
638 mgcp_rtp_end_reset(&endp->net_end);
639 mgcp_rtp_end_reset(&endp->bts_end);
640 mgcp_rtp_end_reset(&endp->trans_net);
641 return -1;
642 }
643
Holger Hans Peter Freyther1d9a8eb2010-11-01 19:57:50 +0100644 /* remember that we have set up transcoding */
Pablo Neira Ayusoa3f26c02013-07-08 05:09:46 +0200645 endp->type = MGCP_RTP_TRANSCODED;
Holger Hans Peter Freyther56ac2692010-09-18 02:30:02 +0800646 }
647
Holger Hans Peter Freyther05d8f5f2010-08-05 08:08:17 +0800648 return 0;
649}
650
Jacob Erlbeck9cec6672013-11-29 13:43:46 +0100651static int parse_sdp_data(struct mgcp_rtp_end *rtp, struct mgcp_parse_data *p)
652{
653 char *line;
654 int found_media = 0;
Jacob Erlbeckfa3fff42013-12-10 13:09:37 +0100655 int audio_payload = -1;
Jacob Erlbeck9cec6672013-11-29 13:43:46 +0100656
657 for_each_line(line, p->save) {
658 switch (line[0]) {
Jacob Erlbeck9cec6672013-11-29 13:43:46 +0100659 case 'o':
660 case 's':
661 case 't':
662 case 'v':
663 /* skip these SDP attributes */
664 break;
Jacob Erlbeckfa3fff42013-12-10 13:09:37 +0100665 case 'a': {
666 int payload;
Jacob Erlbeckfa3fff42013-12-10 13:09:37 +0100667 int ptime, ptime2 = 0;
668 char audio_name[64];
Jacob Erlbeckfa3fff42013-12-10 13:09:37 +0100669
670 if (audio_payload == -1)
671 break;
672
Holger Hans Peter Freyther4ffdb3c2014-05-28 16:44:34 +0200673 if (sscanf(line, "a=rtpmap:%d %63s",
Jacob Erlbeckfa3fff42013-12-10 13:09:37 +0100674 &payload, audio_name) == 2) {
675 if (payload != audio_payload)
676 break;
677
Jacob Erlbeck8f518d62014-03-17 12:30:56 +0100678 set_audio_info(p->cfg, rtp, payload, audio_name);
Jacob Erlbeckfa3fff42013-12-10 13:09:37 +0100679 } else if (sscanf(line, "a=ptime:%d-%d",
680 &ptime, &ptime2) >= 1) {
681 if (ptime2 > 0 && ptime2 != ptime)
682 rtp->packet_duration_ms = 0;
683 else
684 rtp->packet_duration_ms = ptime;
685 } else if (sscanf(line, "a=maxptime:%d", &ptime2) == 1) {
686 if (ptime2 * rtp->frame_duration_den >
687 rtp->frame_duration_num * 1500)
688 /* more than 1 frame */
689 rtp->packet_duration_ms = 0;
690 }
691 break;
692 }
Jacob Erlbeck9cec6672013-11-29 13:43:46 +0100693 case 'm': {
694 int port;
Jacob Erlbeckfa3fff42013-12-10 13:09:37 +0100695 audio_payload = -1;
Jacob Erlbeck9cec6672013-11-29 13:43:46 +0100696
697 if (sscanf(line, "m=audio %d RTP/AVP %d",
Jacob Erlbeckfa3fff42013-12-10 13:09:37 +0100698 &port, &audio_payload) == 2) {
Jacob Erlbeck9cec6672013-11-29 13:43:46 +0100699 rtp->rtp_port = htons(port);
700 rtp->rtcp_port = htons(port + 1);
Jacob Erlbeck9cec6672013-11-29 13:43:46 +0100701 found_media = 1;
Jacob Erlbeck8f518d62014-03-17 12:30:56 +0100702 set_audio_info(p->cfg, rtp, audio_payload, NULL);
Jacob Erlbeck9cec6672013-11-29 13:43:46 +0100703 }
704 break;
705 }
706 case 'c': {
707 char ipv4[16];
708
709 if (sscanf(line, "c=IN IP4 %15s", ipv4) == 1) {
710 inet_aton(ipv4, &rtp->addr);
711 }
712 break;
713 }
714 default:
715 if (p->endp)
716 LOGP(DMGCP, LOGL_NOTICE,
717 "Unhandled SDP option: '%c'/%d on 0x%x\n",
718 line[0], line[0], ENDPOINT_NUMBER(p->endp));
719 else
720 LOGP(DMGCP, LOGL_NOTICE,
721 "Unhandled SDP option: '%c'/%d\n",
722 line[0], line[0]);
723 break;
724 }
725 }
726
727 if (found_media)
728 LOGP(DMGCP, LOGL_NOTICE,
Jacob Erlbeckfa3fff42013-12-10 13:09:37 +0100729 "Got media info via SDP: port %d, payload %d, "
730 "duration %d, addr %s\n",
731 ntohs(rtp->rtp_port), rtp->payload_type,
732 rtp->packet_duration_ms, inet_ntoa(rtp->addr));
Jacob Erlbeck9cec6672013-11-29 13:43:46 +0100733
734 return found_media;
735}
736
Jacob Erlbeck91cf7432013-12-09 14:32:03 +0100737/* Set the LCO from a string (see RFC 3435).
738 * The string is stored in the 'string' field. A NULL string is handled excatly
739 * like an empty string, the 'string' field is never NULL after this function
740 * has been called. */
741static void set_local_cx_options(void *ctx, struct mgcp_lco *lco,
742 const char *options)
743{
744 char *p_opt;
745
746 talloc_free(lco->string);
747 lco->pkt_period_min = lco->pkt_period_max = 0;
748 lco->string = talloc_strdup(ctx, options ? options : "");
749
750 p_opt = strstr(lco->string, "p:");
751 if (p_opt && sscanf(p_opt, "p:%d-%d",
752 &lco->pkt_period_min, &lco->pkt_period_max) == 1)
753 lco->pkt_period_max = lco->pkt_period_min;
754}
755
Jacob Erlbecke5546cd2013-12-03 14:43:34 +0100756void mgcp_rtp_end_config(struct mgcp_endpoint *endp, int expect_ssrc_change,
757 struct mgcp_rtp_end *rtp)
758{
759 struct mgcp_trunk_config *tcfg = endp->tcfg;
760
Jacob Erlbeck2b57b4c2013-12-03 15:13:12 +0100761 int patch_ssrc = expect_ssrc_change && tcfg->force_constant_ssrc;
762
Jacob Erlbeckf12c8492013-12-18 12:54:51 +0100763 rtp->force_aligned_timing = tcfg->force_aligned_timing;
Jacob Erlbeck2b57b4c2013-12-03 15:13:12 +0100764 rtp->force_constant_ssrc = patch_ssrc ? 1 : 0;
Jacob Erlbecke5546cd2013-12-03 14:43:34 +0100765
766 LOGP(DMGCP, LOGL_DEBUG,
767 "Configuring RTP endpoint: local port %d%s%s\n",
768 ntohs(rtp->rtp_port),
Jacob Erlbeckf12c8492013-12-18 12:54:51 +0100769 rtp->force_aligned_timing ? ", force constant timing" : "",
Jacob Erlbecke5546cd2013-12-03 14:43:34 +0100770 rtp->force_constant_ssrc ? ", force constant ssrc" : "");
771}
772
Jacob Erlbeckd69cf602013-12-04 10:30:11 +0100773uint32_t mgcp_rtp_packet_duration(struct mgcp_endpoint *endp,
774 struct mgcp_rtp_end *rtp)
775{
776 int f = 0;
777
778 /* Get the number of frames per channel and packet */
779 if (rtp->frames_per_packet)
780 f = rtp->frames_per_packet;
781 else if (rtp->packet_duration_ms && rtp->frame_duration_num) {
782 int den = 1000 * rtp->frame_duration_num;
783 f = (rtp->packet_duration_ms * rtp->frame_duration_den + den/2)
784 / den;
785 }
786
787 return rtp->rate * f * rtp->frame_duration_num / rtp->frame_duration_den;
788}
789
Holger Hans Peter Freythercd256952012-12-07 15:04:07 +0100790static struct msgb *handle_create_con(struct mgcp_parse_data *p)
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100791{
Holger Hans Peter Freytherab56ce12011-02-28 00:56:17 +0100792 struct mgcp_trunk_config *tcfg;
Holger Hans Peter Freythercd256952012-12-07 15:04:07 +0100793 struct mgcp_endpoint *endp = p->endp;
Holger Hans Peter Freyther94ed60f2010-08-08 16:24:48 +0800794 int error_code = 400;
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100795
Holger Hans Peter Freytherc9c0fe52011-07-20 20:44:54 +0200796 const char *local_options = NULL;
797 const char *callid = NULL;
798 const char *mode = NULL;
Holger Hans Peter Freythercd256952012-12-07 15:04:07 +0100799 char *line;
Jacob Erlbecke3440c72013-11-29 13:43:49 +0100800 int have_sdp = 0;
Holger Hans Peter Freythercd256952012-12-07 15:04:07 +0100801
802 if (p->found != 0)
803 return create_err_response(NULL, 510, "CRCX", p->trans);
Holger Hans Peter Freytherab56ce12011-02-28 00:56:17 +0100804
Holger Hans Peter Freytherc9c0fe52011-07-20 20:44:54 +0200805 /* parse CallID C: and LocalParameters L: */
Jacob Erlbeck9cec6672013-11-29 13:43:46 +0100806 for_each_line(line, p->save) {
Holger Hans Peter Freyther67f103e2014-05-22 15:03:10 +0200807 if (!mgcp_check_param(endp, line))
808 continue;
809
Harald Welteec4f01b2012-01-27 12:31:36 +0100810 switch (line[0]) {
811 case 'L':
812 local_options = (const char *) line + 3;
813 break;
814 case 'C':
815 callid = (const char *) line + 3;
816 break;
817 case 'M':
818 mode = (const char *) line + 3;
819 break;
Pablo Neira Ayuso4a2f6592014-02-05 18:56:17 +0100820 case 'X':
821 if (strcmp("Osmux: on", line + 2) == 0 &&
822 osmux_enable_endpoint(endp, OSMUX_ROLE_BSC) < 0) {
823 LOGP(DMGCP, LOGL_ERROR,
824 "Could not activate osmux in endpoint %d\n",
825 ENDPOINT_NUMBER(endp));
826 }
827 break;
Jacob Erlbecke3440c72013-11-29 13:43:49 +0100828 case '\0':
829 have_sdp = 1;
830 goto mgcp_header_done;
Harald Welteec4f01b2012-01-27 12:31:36 +0100831 default:
832 LOGP(DMGCP, LOGL_NOTICE, "Unhandled option: '%c'/%d on 0x%x\n",
833 *line, *line, ENDPOINT_NUMBER(endp));
834 break;
835 }
Holger Hans Peter Freytherc9c0fe52011-07-20 20:44:54 +0200836 }
Harald Welteec4f01b2012-01-27 12:31:36 +0100837
Jacob Erlbecke3440c72013-11-29 13:43:49 +0100838mgcp_header_done:
Holger Hans Peter Freythercd256952012-12-07 15:04:07 +0100839 tcfg = p->endp->tcfg;
Holger Hans Peter Freytherc9c0fe52011-07-20 20:44:54 +0200840
841 /* Check required data */
842 if (!callid || !mode) {
843 LOGP(DMGCP, LOGL_ERROR, "Missing callid and mode in CRCX on 0x%x\n",
844 ENDPOINT_NUMBER(endp));
Holger Hans Peter Freythercd256952012-12-07 15:04:07 +0100845 return create_err_response(endp, 400, "CRCX", p->trans);
Holger Hans Peter Freytherc9c0fe52011-07-20 20:44:54 +0200846 }
847
Holger Hans Peter Freythere15223b2010-08-06 18:03:11 +0800848 if (endp->allocated) {
Holger Hans Peter Freytherab56ce12011-02-28 00:56:17 +0100849 if (tcfg->force_realloc) {
Holger Hans Peter Freytherdd67a3b2010-04-07 10:51:27 +0200850 LOGP(DMGCP, LOGL_NOTICE, "Endpoint 0x%x already allocated. Forcing realloc.\n",
851 ENDPOINT_NUMBER(endp));
Holger Hans Peter Freyther5c132ee2010-04-24 21:02:48 +0800852 mgcp_free_endp(endp);
Holger Hans Peter Freythercd256952012-12-07 15:04:07 +0100853 if (p->cfg->realloc_cb)
854 p->cfg->realloc_cb(tcfg, ENDPOINT_NUMBER(endp));
Holger Hans Peter Freytherdd67a3b2010-04-07 10:51:27 +0200855 } else {
856 LOGP(DMGCP, LOGL_ERROR, "Endpoint is already used. 0x%x\n",
857 ENDPOINT_NUMBER(endp));
Holger Hans Peter Freythercd256952012-12-07 15:04:07 +0100858 return create_err_response(endp, 400, "CRCX", p->trans);
Holger Hans Peter Freytherdd67a3b2010-04-07 10:51:27 +0200859 }
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100860 }
861
Holger Hans Peter Freytherc9c0fe52011-07-20 20:44:54 +0200862 /* copy some parameters */
863 endp->callid = talloc_strdup(tcfg->endpoints, callid);
864
Jacob Erlbeck91cf7432013-12-09 14:32:03 +0100865 set_local_cx_options(endp->tcfg->endpoints, &endp->local_options,
866 local_options);
Holger Hans Peter Freytherc9c0fe52011-07-20 20:44:54 +0200867
Jacob Erlbeckecd157a2013-12-19 12:23:24 +0100868 if (parse_conn_mode(mode, endp) != 0) {
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100869 error_code = 517;
870 goto error2;
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100871 }
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100872
873 /* initialize */
Holger Hans Peter Freytherfab76aa2010-08-05 01:34:51 +0800874 endp->net_end.rtp_port = endp->net_end.rtcp_port = endp->bts_end.rtp_port = endp->bts_end.rtcp_port = 0;
Jacob Erlbecke5546cd2013-12-03 14:43:34 +0100875 mgcp_rtp_end_config(endp, 0, &endp->net_end);
876 mgcp_rtp_end_config(endp, 0, &endp->bts_end);
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100877
878 /* set to zero until we get the info */
Holger Hans Peter Freytherfab76aa2010-08-05 01:34:51 +0800879 memset(&endp->net_end.addr, 0, sizeof(endp->net_end.addr));
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100880
881 /* bind to the port now */
Holger Hans Peter Freyther05d8f5f2010-08-05 08:08:17 +0800882 if (allocate_ports(endp) != 0)
883 goto error2;
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100884
885 /* assign a local call identifier or fail */
Holger Hans Peter Freythercd256952012-12-07 15:04:07 +0100886 endp->ci = generate_call_id(p->cfg);
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100887 if (endp->ci == CI_UNUSED)
888 goto error2;
889
Holger Hans Peter Freythere15223b2010-08-06 18:03:11 +0800890 endp->allocated = 1;
Jacob Erlbecke3440c72013-11-29 13:43:49 +0100891
892 /* set up RTP media parameters */
Jacob Erlbeck8f518d62014-03-17 12:30:56 +0100893 set_audio_info(p->cfg, &endp->bts_end, tcfg->audio_payload, tcfg->audio_name);
Holger Hans Peter Freyther4928d1b2012-09-03 00:07:39 +0200894 endp->bts_end.fmtp_extra = talloc_strdup(tcfg->endpoints,
895 tcfg->audio_fmtp_extra);
Jacob Erlbeck6a163052014-03-13 14:24:52 +0100896 if (have_sdp) {
Jacob Erlbecke3440c72013-11-29 13:43:49 +0100897 parse_sdp_data(&endp->net_end, p);
Jacob Erlbeck6a163052014-03-13 14:24:52 +0100898 setup_rtp_processing(endp);
899 }
Holger Hans Peter Freyther001dc612010-02-26 13:41:22 +0100900
Holger Hans Peter Freyther7a8ff2a2010-02-26 13:37:05 +0100901 /* policy CB */
Holger Hans Peter Freythercd256952012-12-07 15:04:07 +0100902 if (p->cfg->policy_cb) {
903 int rc;
904 rc = p->cfg->policy_cb(tcfg, ENDPOINT_NUMBER(endp),
905 MGCP_ENDP_CRCX, p->trans);
906 switch (rc) {
Holger Hans Peter Freyther7a8ff2a2010-02-26 13:37:05 +0100907 case MGCP_POLICY_REJECT:
908 LOGP(DMGCP, LOGL_NOTICE, "CRCX rejected by policy on 0x%x\n",
909 ENDPOINT_NUMBER(endp));
910 mgcp_free_endp(endp);
Holger Hans Peter Freythercd256952012-12-07 15:04:07 +0100911 return create_err_response(endp, 400, "CRCX", p->trans);
Holger Hans Peter Freyther7a8ff2a2010-02-26 13:37:05 +0100912 break;
913 case MGCP_POLICY_DEFER:
914 /* stop processing */
Holger Hans Peter Freyther017738d2010-09-18 06:35:29 +0800915 create_transcoder(endp);
Holger Hans Peter Freyther7a8ff2a2010-02-26 13:37:05 +0100916 return NULL;
917 break;
918 case MGCP_POLICY_CONT:
919 /* just continue */
920 break;
921 }
922 }
923
Holger Hans Peter Freyther73d00472010-08-06 20:22:23 +0800924 LOGP(DMGCP, LOGL_DEBUG, "Creating endpoint on: 0x%x CI: %u port: %u/%u\n",
Holger Hans Peter Freyther148c5d32010-08-05 03:08:35 +0800925 ENDPOINT_NUMBER(endp), endp->ci,
926 endp->net_end.local_port, endp->bts_end.local_port);
Holger Hans Peter Freythercd256952012-12-07 15:04:07 +0100927 if (p->cfg->change_cb)
928 p->cfg->change_cb(tcfg, ENDPOINT_NUMBER(endp), MGCP_ENDP_CRCX);
Holger Hans Peter Freyther25374bd2010-02-03 09:54:43 +0100929
Pablo Neira Ayuso4a2f6592014-02-05 18:56:17 +0100930 if (endp->conn_mode & MGCP_CONN_RECV_ONLY && tcfg->keepalive_interval != 0) {
931 if (endp->osmux)
932 osmux_send_dummy(endp);
933 else
934 mgcp_send_dummy(endp);
935 }
Jacob Erlbecke64bb122013-12-19 18:53:07 +0100936
Holger Hans Peter Freyther017738d2010-09-18 06:35:29 +0800937 create_transcoder(endp);
Holger Hans Peter Freythercd256952012-12-07 15:04:07 +0100938 return create_response_with_sdp(endp, "CRCX", p->trans);
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100939error2:
Holger Hans Peter Freyther411764b2010-08-06 07:05:13 +0800940 mgcp_free_endp(endp);
Holger Hans Peter Freyther02c7a6f2010-02-03 09:13:10 +0100941 LOGP(DMGCP, LOGL_NOTICE, "Resource error on 0x%x\n", ENDPOINT_NUMBER(endp));
Holger Hans Peter Freythercd256952012-12-07 15:04:07 +0100942 return create_err_response(endp, error_code, "CRCX", p->trans);
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100943}
944
Holger Hans Peter Freythercd256952012-12-07 15:04:07 +0100945static struct msgb *handle_modify_con(struct mgcp_parse_data *p)
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100946{
Holger Hans Peter Freythercd256952012-12-07 15:04:07 +0100947 struct mgcp_endpoint *endp = p->endp;
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100948 int error_code = 500;
Pablo Neira Ayuso4a2f6592014-02-05 18:56:17 +0100949 int silent = 0, osmux = 0;
Holger Hans Peter Freythercd256952012-12-07 15:04:07 +0100950 char *line;
Jacob Erlbeck91cf7432013-12-09 14:32:03 +0100951 const char *local_options = NULL;
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100952
Holger Hans Peter Freythercd256952012-12-07 15:04:07 +0100953 if (p->found != 0)
954 return create_err_response(NULL, 510, "MDCX", p->trans);
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100955
Holger Hans Peter Freythercd256952012-12-07 15:04:07 +0100956 if (endp->ci == CI_UNUSED) {
957 LOGP(DMGCP, LOGL_ERROR, "Endpoint is not "
958 "holding a connection. 0x%x\n", ENDPOINT_NUMBER(endp));
959 return create_err_response(endp, 400, "MDCX", p->trans);
960 }
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100961
Jacob Erlbeck9cec6672013-11-29 13:43:46 +0100962 for_each_line(line, p->save) {
Holger Hans Peter Freyther67f103e2014-05-22 15:03:10 +0200963 if (!mgcp_check_param(endp, line))
964 continue;
965
Harald Welteec4f01b2012-01-27 12:31:36 +0100966 switch (line[0]) {
967 case 'C': {
968 if (verify_call_id(endp, line + 3) != 0)
969 goto error3;
970 break;
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100971 }
Harald Welteec4f01b2012-01-27 12:31:36 +0100972 case 'I': {
973 if (verify_ci(endp, line + 3) != 0)
974 goto error3;
975 break;
976 }
977 case 'L':
Jacob Erlbeck91cf7432013-12-09 14:32:03 +0100978 local_options = (const char *) line + 3;
Harald Welteec4f01b2012-01-27 12:31:36 +0100979 break;
980 case 'M':
Jacob Erlbeckecd157a2013-12-19 12:23:24 +0100981 if (parse_conn_mode(line + 3, endp) != 0) {
Harald Welteec4f01b2012-01-27 12:31:36 +0100982 error_code = 517;
983 goto error3;
984 }
985 endp->orig_mode = endp->conn_mode;
986 break;
Pablo Neira Ayuso4a2f6592014-02-05 18:56:17 +0100987 case 'X':
988 if (strcmp("Osmux: on", line + 2) == 0)
989 osmux = 1;
990 break;
Harald Welteec4f01b2012-01-27 12:31:36 +0100991 case 'Z':
992 silent = strcmp("noanswer", line + 3) == 0;
993 break;
994 case '\0':
995 /* SDP file begins */
Jacob Erlbeck9cec6672013-11-29 13:43:46 +0100996 parse_sdp_data(&endp->net_end, p);
997 /* This will exhaust p->save, so the loop will
998 * terminate next time.
999 */
Harald Welteec4f01b2012-01-27 12:31:36 +01001000 break;
Harald Welteec4f01b2012-01-27 12:31:36 +01001001 default:
Jacob Erlbeck9cec6672013-11-29 13:43:46 +01001002 LOGP(DMGCP, LOGL_NOTICE, "Unhandled MGCP option: '%c'/%d on 0x%x\n",
Harald Welteec4f01b2012-01-27 12:31:36 +01001003 line[0], line[0], ENDPOINT_NUMBER(endp));
1004 break;
1005 }
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +01001006 }
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +01001007
Pablo Neira Ayuso4a2f6592014-02-05 18:56:17 +01001008 /* Re-enable Osmux if we receive a MDCX, we have to set up a new
1009 * RTP flow: this generates a randomly allocated RTP SSRC and sequence
1010 * number.
1011 */
1012 if (osmux) {
1013 if (osmux_enable_endpoint(endp, OSMUX_ROLE_BSC) < 0) {
1014 LOGP(DMGCP, LOGL_ERROR,
1015 "Could not update osmux in endpoint %d\n",
1016 ENDPOINT_NUMBER(endp));
1017 }
1018 LOGP(DMGCP, LOGL_NOTICE,
1019 "Re-enabling osmux in endpoint %d, we got updated\n",
1020 ENDPOINT_NUMBER(endp));
1021 }
1022
Jacob Erlbeck91cf7432013-12-09 14:32:03 +01001023 set_local_cx_options(endp->tcfg->endpoints, &endp->local_options,
1024 local_options);
1025
Jacob Erlbeck6a163052014-03-13 14:24:52 +01001026 setup_rtp_processing(endp);
1027
Holger Hans Peter Freyther7a8ff2a2010-02-26 13:37:05 +01001028 /* policy CB */
Holger Hans Peter Freythercd256952012-12-07 15:04:07 +01001029 if (p->cfg->policy_cb) {
1030 int rc;
1031 rc = p->cfg->policy_cb(endp->tcfg, ENDPOINT_NUMBER(endp),
1032 MGCP_ENDP_MDCX, p->trans);
1033 switch (rc) {
Holger Hans Peter Freyther7a8ff2a2010-02-26 13:37:05 +01001034 case MGCP_POLICY_REJECT:
1035 LOGP(DMGCP, LOGL_NOTICE, "MDCX rejected by policy on 0x%x\n",
1036 ENDPOINT_NUMBER(endp));
Holger Hans Peter Freythere077c912010-04-22 11:58:13 +08001037 if (silent)
1038 goto out_silent;
Holger Hans Peter Freythercd256952012-12-07 15:04:07 +01001039 return create_err_response(endp, 400, "MDCX", p->trans);
Holger Hans Peter Freyther7a8ff2a2010-02-26 13:37:05 +01001040 break;
1041 case MGCP_POLICY_DEFER:
1042 /* stop processing */
1043 return NULL;
1044 break;
1045 case MGCP_POLICY_CONT:
1046 /* just continue */
1047 break;
1048 }
1049 }
1050
Jacob Erlbecke5546cd2013-12-03 14:43:34 +01001051 mgcp_rtp_end_config(endp, 1, &endp->net_end);
1052 mgcp_rtp_end_config(endp, 1, &endp->bts_end);
1053
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +01001054 /* modify */
Holger Hans Peter Freyther73d00472010-08-06 20:22:23 +08001055 LOGP(DMGCP, LOGL_DEBUG, "Modified endpoint on: 0x%x Server: %s:%u\n",
Holger Hans Peter Freytherfab76aa2010-08-05 01:34:51 +08001056 ENDPOINT_NUMBER(endp), inet_ntoa(endp->net_end.addr), ntohs(endp->net_end.rtp_port));
Holger Hans Peter Freythercd256952012-12-07 15:04:07 +01001057 if (p->cfg->change_cb)
1058 p->cfg->change_cb(endp->tcfg, ENDPOINT_NUMBER(endp), MGCP_ENDP_MDCX);
Jacob Erlbecke64bb122013-12-19 18:53:07 +01001059
Jacob Erlbeckf3188612014-01-16 16:50:40 +01001060 if (endp->conn_mode & MGCP_CONN_RECV_ONLY &&
1061 endp->tcfg->keepalive_interval != 0)
Jacob Erlbecke64bb122013-12-19 18:53:07 +01001062 mgcp_send_dummy(endp);
1063
Holger Hans Peter Freythere077c912010-04-22 11:58:13 +08001064 if (silent)
1065 goto out_silent;
1066
Holger Hans Peter Freythercd256952012-12-07 15:04:07 +01001067 return create_response_with_sdp(endp, "MDCX", p->trans);
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +01001068
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +01001069error3:
Holger Hans Peter Freythercd256952012-12-07 15:04:07 +01001070 return create_err_response(endp, error_code, "MDCX", p->trans);
Holger Hans Peter Freythere077c912010-04-22 11:58:13 +08001071
1072
1073out_silent:
1074 return NULL;
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +01001075}
1076
Holger Hans Peter Freythercd256952012-12-07 15:04:07 +01001077static struct msgb *handle_delete_con(struct mgcp_parse_data *p)
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +01001078{
Holger Hans Peter Freythercd256952012-12-07 15:04:07 +01001079 struct mgcp_endpoint *endp = p->endp;
Holger Hans Peter Freyther94ed60f2010-08-08 16:24:48 +08001080 int error_code = 400;
Holger Hans Peter Freythere077c912010-04-22 11:58:13 +08001081 int silent = 0;
Holger Hans Peter Freythercd256952012-12-07 15:04:07 +01001082 char *line;
Holger Hans Peter Freyther8fc6d082012-09-14 17:18:12 +02001083 char stats[1048];
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +01001084
Holger Hans Peter Freythercd256952012-12-07 15:04:07 +01001085 if (p->found != 0)
1086 return create_err_response(NULL, error_code, "DLCX", p->trans);
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +01001087
Holger Hans Peter Freythercd256952012-12-07 15:04:07 +01001088 if (!p->endp->allocated) {
1089 LOGP(DMGCP, LOGL_ERROR, "Endpoint is not used. 0x%x\n",
1090 ENDPOINT_NUMBER(endp));
1091 return create_err_response(endp, 400, "DLCX", p->trans);
1092 }
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +01001093
Jacob Erlbeck9cec6672013-11-29 13:43:46 +01001094 for_each_line(line, p->save) {
Holger Hans Peter Freyther67f103e2014-05-22 15:03:10 +02001095 if (!mgcp_check_param(endp, line))
1096 continue;
1097
Harald Welteec4f01b2012-01-27 12:31:36 +01001098 switch (line[0]) {
1099 case 'C':
1100 if (verify_call_id(endp, line + 3) != 0)
1101 goto error3;
1102 break;
1103 case 'I':
1104 if (verify_ci(endp, line + 3) != 0)
1105 goto error3;
1106 break;
1107 case 'Z':
1108 silent = strcmp("noanswer", line + 3) == 0;
1109 break;
1110 default:
1111 LOGP(DMGCP, LOGL_NOTICE, "Unhandled option: '%c'/%d on 0x%x\n",
1112 line[0], line[0], ENDPOINT_NUMBER(endp));
1113 break;
1114 }
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +01001115 }
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +01001116
Holger Hans Peter Freyther7a8ff2a2010-02-26 13:37:05 +01001117 /* policy CB */
Holger Hans Peter Freythercd256952012-12-07 15:04:07 +01001118 if (p->cfg->policy_cb) {
1119 int rc;
1120 rc = p->cfg->policy_cb(endp->tcfg, ENDPOINT_NUMBER(endp),
1121 MGCP_ENDP_DLCX, p->trans);
1122 switch (rc) {
Holger Hans Peter Freyther7a8ff2a2010-02-26 13:37:05 +01001123 case MGCP_POLICY_REJECT:
1124 LOGP(DMGCP, LOGL_NOTICE, "DLCX rejected by policy on 0x%x\n",
1125 ENDPOINT_NUMBER(endp));
Holger Hans Peter Freythere077c912010-04-22 11:58:13 +08001126 if (silent)
1127 goto out_silent;
Holger Hans Peter Freythercd256952012-12-07 15:04:07 +01001128 return create_err_response(endp, 400, "DLCX", p->trans);
Holger Hans Peter Freyther7a8ff2a2010-02-26 13:37:05 +01001129 break;
1130 case MGCP_POLICY_DEFER:
1131 /* stop processing */
Holger Hans Peter Freyther017738d2010-09-18 06:35:29 +08001132 delete_transcoder(endp);
Holger Hans Peter Freyther7a8ff2a2010-02-26 13:37:05 +01001133 return NULL;
1134 break;
1135 case MGCP_POLICY_CONT:
1136 /* just continue */
1137 break;
1138 }
1139 }
1140
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +01001141 /* free the connection */
Holger Hans Peter Freyther73d00472010-08-06 20:22:23 +08001142 LOGP(DMGCP, LOGL_DEBUG, "Deleted endpoint on: 0x%x Server: %s:%u\n",
Holger Hans Peter Freytherfab76aa2010-08-05 01:34:51 +08001143 ENDPOINT_NUMBER(endp), inet_ntoa(endp->net_end.addr), ntohs(endp->net_end.rtp_port));
Holger Hans Peter Freyther017738d2010-09-18 06:35:29 +08001144
Holger Hans Peter Freyther8fc6d082012-09-14 17:18:12 +02001145 /* save the statistics of the current call */
1146 mgcp_format_stats(endp, stats, sizeof(stats));
1147
Holger Hans Peter Freyther017738d2010-09-18 06:35:29 +08001148 delete_transcoder(endp);
Holger Hans Peter Freyther64dcbe22010-02-26 13:27:51 +01001149 mgcp_free_endp(endp);
Holger Hans Peter Freythercd256952012-12-07 15:04:07 +01001150 if (p->cfg->change_cb)
1151 p->cfg->change_cb(endp->tcfg, ENDPOINT_NUMBER(endp), MGCP_ENDP_DLCX);
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +01001152
Holger Hans Peter Freythere077c912010-04-22 11:58:13 +08001153 if (silent)
1154 goto out_silent;
Holger Hans Peter Freythercd256952012-12-07 15:04:07 +01001155 return create_ok_resp_with_param(endp, 250, "DLCX", p->trans, stats);
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +01001156
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +01001157error3:
Holger Hans Peter Freythercd256952012-12-07 15:04:07 +01001158 return create_err_response(endp, error_code, "DLCX", p->trans);
Holger Hans Peter Freythere077c912010-04-22 11:58:13 +08001159
1160out_silent:
1161 return NULL;
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +01001162}
1163
Holger Hans Peter Freythercd256952012-12-07 15:04:07 +01001164static struct msgb *handle_rsip(struct mgcp_parse_data *p)
Holger Hans Peter Freytherd60c6e52010-03-31 06:39:35 +02001165{
Holger Hans Peter Freythercd256952012-12-07 15:04:07 +01001166 if (p->found != 0) {
Holger Hans Peter Freyther26bd8482011-06-10 00:04:55 +02001167 LOGP(DMGCP, LOGL_ERROR, "Failed to find the endpoint.\n");
1168 return NULL;
1169 }
1170
Holger Hans Peter Freythercd256952012-12-07 15:04:07 +01001171 if (p->cfg->reset_cb)
1172 p->cfg->reset_cb(p->endp->tcfg);
Holger Hans Peter Freytherd60c6e52010-03-31 06:39:35 +02001173 return NULL;
1174}
1175
Holger Hans Peter Freyther46880c22012-11-29 12:54:22 +01001176static char extract_tone(const char *line)
1177{
1178 const char *str = strstr(line, "D/");
1179 if (!str)
1180 return CHAR_MAX;
1181
1182 return str[2];
1183}
1184
Holger Hans Peter Freytherac0968e2011-01-25 23:33:54 +01001185/*
1186 * This can request like DTMF detection and forward, fax detection... it
1187 * can also request when the notification should be send and such. We don't
1188 * do this right now.
1189 */
Holger Hans Peter Freythercd256952012-12-07 15:04:07 +01001190static struct msgb *handle_noti_req(struct mgcp_parse_data *p)
Holger Hans Peter Freytherac0968e2011-01-25 23:33:54 +01001191{
Holger Hans Peter Freythercd256952012-12-07 15:04:07 +01001192 int res = 0;
1193 char *line;
Holger Hans Peter Freythera2297482013-05-21 17:04:35 +02001194 char tone = CHAR_MAX;
Holger Hans Peter Freytherac0968e2011-01-25 23:33:54 +01001195
Holger Hans Peter Freythercd256952012-12-07 15:04:07 +01001196 if (p->found != 0)
1197 return create_err_response(NULL, 400, "RQNT", p->trans);
Holger Hans Peter Freytherac0968e2011-01-25 23:33:54 +01001198
Jacob Erlbeck9cec6672013-11-29 13:43:46 +01001199 for_each_line(line, p->save) {
Holger Hans Peter Freyther46880c22012-11-29 12:54:22 +01001200 switch (line[0]) {
1201 case 'S':
1202 tone = extract_tone(line);
1203 break;
1204 }
Holger Hans Peter Freytherac0968e2011-01-25 23:33:54 +01001205 }
Holger Hans Peter Freyther46880c22012-11-29 12:54:22 +01001206
1207 /* we didn't see a signal request with a tone */
1208 if (tone == CHAR_MAX)
Holger Hans Peter Freythercd256952012-12-07 15:04:07 +01001209 return create_ok_response(p->endp, 200, "RQNT", p->trans);
Holger Hans Peter Freyther46880c22012-11-29 12:54:22 +01001210
Holger Hans Peter Freythercd256952012-12-07 15:04:07 +01001211 if (p->cfg->rqnt_cb)
1212 res = p->cfg->rqnt_cb(p->endp, tone);
Holger Hans Peter Freyther46880c22012-11-29 12:54:22 +01001213
1214 return res == 0 ?
Holger Hans Peter Freythercd256952012-12-07 15:04:07 +01001215 create_ok_response(p->endp, 200, "RQNT", p->trans) :
1216 create_err_response(p->endp, res, "RQNT", p->trans);
Holger Hans Peter Freytherac0968e2011-01-25 23:33:54 +01001217}
1218
Jacob Erlbecke64bb122013-12-19 18:53:07 +01001219static void mgcp_keepalive_timer_cb(void *_tcfg)
1220{
1221 struct mgcp_trunk_config *tcfg = _tcfg;
1222 int i;
1223 LOGP(DMGCP, LOGL_DEBUG, "Triggered trunk %d keepalive timer.\n",
1224 tcfg->trunk_nr);
1225
1226 if (tcfg->keepalive_interval <= 0)
1227 return;
1228
1229 for (i = 1; i < tcfg->number_endpoints; ++i) {
1230 struct mgcp_endpoint *endp = &tcfg->endpoints[i];
1231 if (endp->conn_mode == MGCP_CONN_RECV_ONLY)
1232 mgcp_send_dummy(endp);
1233 }
1234
1235 LOGP(DMGCP, LOGL_DEBUG, "Rescheduling trunk %d keepalive timer.\n",
1236 tcfg->trunk_nr);
1237 osmo_timer_schedule(&tcfg->keepalive_timer, tcfg->keepalive_interval, 0);
1238}
1239
1240void mgcp_trunk_set_keepalive(struct mgcp_trunk_config *tcfg, int interval)
1241{
1242 tcfg->keepalive_interval = interval;
1243 tcfg->keepalive_timer.data = tcfg;
1244 tcfg->keepalive_timer.cb = mgcp_keepalive_timer_cb;
1245
1246 if (interval <= 0)
1247 osmo_timer_del(&tcfg->keepalive_timer);
1248 else
1249 osmo_timer_schedule(&tcfg->keepalive_timer,
1250 tcfg->keepalive_interval, 0);
1251}
1252
Holger Hans Peter Freyther6f38c062010-02-20 21:21:02 +01001253struct mgcp_config *mgcp_config_alloc(void)
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +01001254{
Holger Hans Peter Freyther6f38c062010-02-20 21:21:02 +01001255 struct mgcp_config *cfg;
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +01001256
Holger Hans Peter Freyther6f38c062010-02-20 21:21:02 +01001257 cfg = talloc_zero(NULL, struct mgcp_config);
1258 if (!cfg) {
1259 LOGP(DMGCP, LOGL_FATAL, "Failed to allocate config.\n");
1260 return NULL;
1261 }
1262
1263 cfg->source_port = 2427;
1264 cfg->source_addr = talloc_strdup(cfg, "0.0.0.0");
Holger Hans Peter Freytherab56ce12011-02-28 00:56:17 +01001265
Holger Hans Peter Freytherd582b202010-09-19 04:21:39 +08001266 cfg->transcoder_remote_base = 4000;
Holger Hans Peter Freyther2ea91182010-08-05 07:10:56 +08001267
1268 cfg->bts_ports.base_port = RTP_PORT_DEFAULT;
1269 cfg->net_ports.base_port = RTP_PORT_NET_DEFAULT;
Holger Hans Peter Freyther6f38c062010-02-20 21:21:02 +01001270
Jacob Erlbeck6a163052014-03-13 14:24:52 +01001271 cfg->rtp_processing_cb = &mgcp_rtp_processing_default;
1272 cfg->setup_rtp_processing_cb = &mgcp_setup_rtp_processing_default;
1273
Jacob Erlbeckfe0301a2014-03-17 12:40:07 +01001274 cfg->get_net_downlink_format_cb = &mgcp_get_net_downlink_format_default;
1275
Holger Hans Peter Freytherab56ce12011-02-28 00:56:17 +01001276 /* default trunk handling */
1277 cfg->trunk.cfg = cfg;
1278 cfg->trunk.trunk_nr = 0;
1279 cfg->trunk.trunk_type = MGCP_TRUNK_VIRTUAL;
1280 cfg->trunk.audio_name = talloc_strdup(cfg, "AMR/8000");
1281 cfg->trunk.audio_payload = 126;
Jacob Erlbecke91324d2013-12-10 13:09:37 +01001282 cfg->trunk.audio_send_ptime = 1;
Holger Hans Peter Freyther51ade842012-05-11 13:00:45 +02001283 cfg->trunk.omit_rtcp = 0;
Jacob Erlbecke64bb122013-12-19 18:53:07 +01001284 mgcp_trunk_set_keepalive(&cfg->trunk, MGCP_KEEPALIVE_ONCE);
Holger Hans Peter Freytherab56ce12011-02-28 00:56:17 +01001285
Holger Hans Peter Freyther06bfe792011-02-28 12:11:02 +01001286 INIT_LLIST_HEAD(&cfg->trunks);
1287
Holger Hans Peter Freyther6f38c062010-02-20 21:21:02 +01001288 return cfg;
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +01001289}
1290
Holger Hans Peter Freyther06bfe792011-02-28 12:11:02 +01001291struct mgcp_trunk_config *mgcp_trunk_alloc(struct mgcp_config *cfg, int nr)
1292{
1293 struct mgcp_trunk_config *trunk;
1294
1295 trunk = talloc_zero(cfg, struct mgcp_trunk_config);
1296 if (!trunk) {
1297 LOGP(DMGCP, LOGL_ERROR, "Failed to allocate.\n");
1298 return NULL;
1299 }
1300
1301 trunk->cfg = cfg;
1302 trunk->trunk_type = MGCP_TRUNK_E1;
1303 trunk->trunk_nr = nr;
1304 trunk->audio_name = talloc_strdup(cfg, "AMR/8000");
1305 trunk->audio_payload = 126;
Jacob Erlbecke91324d2013-12-10 13:09:37 +01001306 trunk->audio_send_ptime = 1;
Holger Hans Peter Freyther06bfe792011-02-28 12:11:02 +01001307 trunk->number_endpoints = 33;
Holger Hans Peter Freyther51ade842012-05-11 13:00:45 +02001308 trunk->omit_rtcp = 0;
Jacob Erlbecke64bb122013-12-19 18:53:07 +01001309 mgcp_trunk_set_keepalive(trunk, MGCP_KEEPALIVE_ONCE);
Holger Hans Peter Freyther06bfe792011-02-28 12:11:02 +01001310 llist_add_tail(&trunk->entry, &cfg->trunks);
1311 return trunk;
1312}
1313
1314struct mgcp_trunk_config *mgcp_trunk_num(struct mgcp_config *cfg, int index)
1315{
1316 struct mgcp_trunk_config *trunk;
1317
1318 llist_for_each_entry(trunk, &cfg->trunks, entry)
1319 if (trunk->trunk_nr == index)
1320 return trunk;
1321
1322 return NULL;
1323}
1324
Holger Hans Peter Freytherfab76aa2010-08-05 01:34:51 +08001325static void mgcp_rtp_end_reset(struct mgcp_rtp_end *end)
1326{
Holger Hans Peter Freyther6f94bac2010-11-02 19:06:13 +01001327 if (end->local_alloc == PORT_ALLOC_DYNAMIC) {
Holger Hans Peter Freyther05d8f5f2010-08-05 08:08:17 +08001328 mgcp_free_rtp_port(end);
Holger Hans Peter Freyther6f94bac2010-11-02 19:06:13 +01001329 end->local_port = 0;
1330 }
Holger Hans Peter Freyther05d8f5f2010-08-05 08:08:17 +08001331
Holger Hans Peter Freytherbfb68b72010-08-05 03:37:22 +08001332 end->packets = 0;
Holger Hans Peter Freyther3e456102012-09-12 11:38:37 +02001333 end->octets = 0;
Jacob Erlbeck8c1f4b02013-12-19 12:13:32 +01001334 end->dropped_packets = 0;
Holger Hans Peter Freytherbfb68b72010-08-05 03:37:22 +08001335 memset(&end->addr, 0, sizeof(end->addr));
Holger Hans Peter Freyther6f94bac2010-11-02 19:06:13 +01001336 end->rtp_port = end->rtcp_port = 0;
Holger Hans Peter Freytherfab76aa2010-08-05 01:34:51 +08001337 end->payload_type = -1;
Holger Hans Peter Freyther05d8f5f2010-08-05 08:08:17 +08001338 end->local_alloc = -1;
Holger Hans Peter Freyther4928d1b2012-09-03 00:07:39 +02001339 talloc_free(end->fmtp_extra);
1340 end->fmtp_extra = NULL;
Jacob Erlbeck8f518d62014-03-17 12:30:56 +01001341 talloc_free(end->subtype_name);
1342 end->subtype_name = NULL;
1343 talloc_free(end->audio_name);
1344 end->audio_name = NULL;
Jacob Erlbeck6a163052014-03-13 14:24:52 +01001345 talloc_free(end->rtp_process_data);
1346 end->rtp_process_data = NULL;
Jacob Erlbeckac9f6ce2013-11-25 15:23:35 +01001347
1348 /* Set default values */
1349 end->frame_duration_num = DEFAULT_RTP_AUDIO_FRAME_DUR_NUM;
1350 end->frame_duration_den = DEFAULT_RTP_AUDIO_FRAME_DUR_DEN;
Jacob Erlbeckd69cf602013-12-04 10:30:11 +01001351 end->frames_per_packet = 0; /* unknown */
1352 end->packet_duration_ms = DEFAULT_RTP_AUDIO_PACKET_DURATION_MS;
1353 end->rate = DEFAULT_RTP_AUDIO_DEFAULT_RATE;
Jacob Erlbeck8f518d62014-03-17 12:30:56 +01001354 end->channels = DEFAULT_RTP_AUDIO_DEFAULT_CHANNELS;
Jacob Erlbeckb866d3b2014-01-16 16:50:39 +01001355 end->output_enabled = 0;
Holger Hans Peter Freytherfab76aa2010-08-05 01:34:51 +08001356}
1357
Holger Hans Peter Freytherbfb68b72010-08-05 03:37:22 +08001358static void mgcp_rtp_end_init(struct mgcp_rtp_end *end)
1359{
1360 mgcp_rtp_end_reset(end);
1361 end->rtp.fd = -1;
1362 end->rtcp.fd = -1;
1363}
1364
Holger Hans Peter Freyther49e170b2011-02-28 14:37:03 +01001365int mgcp_endpoints_allocate(struct mgcp_trunk_config *tcfg)
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +01001366{
1367 int i;
1368
Holger Hans Peter Freyther6f38c062010-02-20 21:21:02 +01001369 /* Initialize all endpoints */
Holger Hans Peter Freyther49e170b2011-02-28 14:37:03 +01001370 tcfg->endpoints = _talloc_zero_array(tcfg->cfg,
Holger Hans Peter Freyther6f38c062010-02-20 21:21:02 +01001371 sizeof(struct mgcp_endpoint),
Holger Hans Peter Freytherab56ce12011-02-28 00:56:17 +01001372 tcfg->number_endpoints, "endpoints");
1373 if (!tcfg->endpoints)
Holger Hans Peter Freyther6f38c062010-02-20 21:21:02 +01001374 return -1;
1375
Holger Hans Peter Freytherab56ce12011-02-28 00:56:17 +01001376 for (i = 0; i < tcfg->number_endpoints; ++i) {
1377 tcfg->endpoints[i].ci = CI_UNUSED;
Holger Hans Peter Freyther49e170b2011-02-28 14:37:03 +01001378 tcfg->endpoints[i].cfg = tcfg->cfg;
Holger Hans Peter Freytherab56ce12011-02-28 00:56:17 +01001379 tcfg->endpoints[i].tcfg = tcfg;
1380 mgcp_rtp_end_init(&tcfg->endpoints[i].net_end);
1381 mgcp_rtp_end_init(&tcfg->endpoints[i].bts_end);
1382 mgcp_rtp_end_init(&tcfg->endpoints[i].trans_net);
1383 mgcp_rtp_end_init(&tcfg->endpoints[i].trans_bts);
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +01001384 }
1385
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +01001386 return 0;
1387}
Holger Hans Peter Freyther64dcbe22010-02-26 13:27:51 +01001388
1389void mgcp_free_endp(struct mgcp_endpoint *endp)
1390{
Holger Hans Peter Freyther62d3bb72010-03-31 12:31:09 +02001391 LOGP(DMGCP, LOGL_DEBUG, "Deleting endpoint on: 0x%x\n", ENDPOINT_NUMBER(endp));
Holger Hans Peter Freytherfd93fc02010-08-03 15:01:43 +00001392 endp->ci = CI_UNUSED;
Holger Hans Peter Freythere15223b2010-08-06 18:03:11 +08001393 endp->allocated = 0;
Holger Hans Peter Freyther64dcbe22010-02-26 13:27:51 +01001394
Holger Hans Peter Freythere9564b22012-12-07 11:52:16 +01001395 talloc_free(endp->callid);
1396 endp->callid = NULL;
Holger Hans Peter Freyther64dcbe22010-02-26 13:27:51 +01001397
Jacob Erlbeck91cf7432013-12-09 14:32:03 +01001398 talloc_free(endp->local_options.string);
1399 endp->local_options.string = NULL;
Holger Hans Peter Freyther64dcbe22010-02-26 13:27:51 +01001400
Holger Hans Peter Freytherfab76aa2010-08-05 01:34:51 +08001401 mgcp_rtp_end_reset(&endp->bts_end);
1402 mgcp_rtp_end_reset(&endp->net_end);
Holger Hans Peter Freytherb6345ab2010-11-01 20:53:31 +01001403 mgcp_rtp_end_reset(&endp->trans_net);
Holger Hans Peter Freytherc983f832010-11-01 21:04:54 +01001404 mgcp_rtp_end_reset(&endp->trans_bts);
Pablo Neira Ayusoa3f26c02013-07-08 05:09:46 +02001405 endp->type = MGCP_RTP_DEFAULT;
Holger Hans Peter Freythere758d952010-07-29 02:38:39 +08001406
Holger Hans Peter Freyther84ba5282010-08-03 11:59:04 +00001407 memset(&endp->net_state, 0, sizeof(endp->net_state));
1408 memset(&endp->bts_state, 0, sizeof(endp->bts_state));
Holger Hans Peter Freytherb33ded12010-08-03 02:57:02 +08001409
1410 endp->conn_mode = endp->orig_mode = MGCP_CONN_NONE;
Holger Hans Peter Freyther8fdb95e2010-08-06 01:12:21 +08001411
1412 memset(&endp->taps, 0, sizeof(endp->taps));
Holger Hans Peter Freyther64dcbe22010-02-26 13:27:51 +01001413}
Holger Hans Peter Freyther017738d2010-09-18 06:35:29 +08001414
Holger Hans Peter Freyther1adedbb2010-09-19 04:39:55 +08001415static int send_trans(struct mgcp_config *cfg, const char *buf, int len)
1416{
1417 struct sockaddr_in addr;
1418
1419 memset(&addr, 0, sizeof(addr));
1420 addr.sin_family = AF_INET;
1421 addr.sin_addr = cfg->transcoder_in;
1422 addr.sin_port = htons(2427);
1423 return sendto(cfg->gw_fd.bfd.fd, buf, len, 0,
1424 (struct sockaddr *) &addr, sizeof(addr));
1425}
1426
Holger Hans Peter Freyther017738d2010-09-18 06:35:29 +08001427static void send_msg(struct mgcp_endpoint *endp, int endpoint, int port,
1428 const char *msg, const char *mode)
1429{
Holger Hans Peter Freyther017738d2010-09-18 06:35:29 +08001430 char buf[2096];
1431 int len;
Jacob Erlbeckfe0301a2014-03-17 12:40:07 +01001432 const char *fmtp_extra;
1433 const char *audio_name;
1434 int payload_type;
1435
1436 endp->cfg->get_net_downlink_format_cb(endp, &payload_type,
1437 &audio_name, &fmtp_extra);
Holger Hans Peter Freyther017738d2010-09-18 06:35:29 +08001438
1439 /* hardcoded to AMR right now, we do not know the real type at this point */
1440 len = snprintf(buf, sizeof(buf),
1441 "%s 42 %x@mgw MGCP 1.0\r\n"
1442 "C: 4256\r\n"
1443 "M: %s\r\n"
1444 "\r\n"
1445 "c=IN IP4 %s\r\n"
1446 "m=audio %d RTP/AVP %d\r\n"
Jacob Erlbeck8f518d62014-03-17 12:30:56 +01001447 "a=rtpmap:%d%s%s\r\n",
Holger Hans Peter Freyther017738d2010-09-18 06:35:29 +08001448 msg, endpoint, mode, endp->cfg->source_addr,
Jacob Erlbeck8f518d62014-03-17 12:30:56 +01001449 port, payload_type,
1450 payload_type,
1451 audio_name ? " " : "", audio_name ? audio_name : "");
Holger Hans Peter Freyther017738d2010-09-18 06:35:29 +08001452
1453 if (len < 0)
1454 return;
1455
1456 buf[sizeof(buf) - 1] = '\0';
1457
Holger Hans Peter Freyther1adedbb2010-09-19 04:39:55 +08001458 send_trans(endp->cfg, buf, len);
Holger Hans Peter Freyther017738d2010-09-18 06:35:29 +08001459}
1460
1461static void send_dlcx(struct mgcp_endpoint *endp, int endpoint)
1462{
Holger Hans Peter Freyther017738d2010-09-18 06:35:29 +08001463 char buf[2096];
1464 int len;
1465
1466 len = snprintf(buf, sizeof(buf),
1467 "DLCX 43 %x@mgw MGCP 1.0\r\n"
1468 "C: 4256\r\n"
1469 , endpoint);
1470
1471 if (len < 0)
1472 return;
1473
1474 buf[sizeof(buf) - 1] = '\0';
1475
Holger Hans Peter Freyther1adedbb2010-09-19 04:39:55 +08001476 send_trans(endp->cfg, buf, len);
Holger Hans Peter Freyther017738d2010-09-18 06:35:29 +08001477}
1478
Harald Welteba4f8b22012-01-27 00:41:39 +01001479static int send_agent(struct mgcp_config *cfg, const char *buf, int len)
1480{
1481 return write(cfg->gw_fd.bfd.fd, buf, len);
1482}
1483
1484int mgcp_send_reset_all(struct mgcp_config *cfg)
1485{
1486 static const char mgcp_reset[] = {
1487 "RSIP 1 *@mgw MGCP 1.0\r\n"
1488 };
1489
1490 return send_agent(cfg, mgcp_reset, sizeof mgcp_reset -1);
1491}
1492
1493int mgcp_send_reset_ep(struct mgcp_endpoint *endp, int endpoint)
1494{
1495 char buf[128];
1496 int len;
1497
1498 len = snprintf(buf, sizeof(buf),
1499 "RSIP 39 %x@mgw MGCP 1.0\r\n"
1500 , endpoint);
1501 if (len < 0)
1502 return len;
1503
1504 buf[sizeof(buf) - 1] = '\0';
1505
1506 return send_agent(endp->cfg, buf, len);
1507}
1508
Jacob Erlbeck6a163052014-03-13 14:24:52 +01001509static void setup_rtp_processing(struct mgcp_endpoint *endp)
1510{
1511 struct mgcp_config *cfg = endp->cfg;
1512
1513 if (endp->type != MGCP_RTP_DEFAULT)
1514 return;
1515
1516 if (endp->conn_mode == MGCP_CONN_LOOPBACK)
1517 return;
1518
1519 if (endp->conn_mode & MGCP_CONN_SEND_ONLY)
1520 cfg->setup_rtp_processing_cb(endp, &endp->net_end, &endp->bts_end);
1521 else
1522 cfg->setup_rtp_processing_cb(endp, &endp->net_end, NULL);
1523
1524 if (endp->conn_mode & MGCP_CONN_RECV_ONLY)
1525 cfg->setup_rtp_processing_cb(endp, &endp->bts_end, &endp->net_end);
1526 else
1527 cfg->setup_rtp_processing_cb(endp, &endp->bts_end, NULL);
1528}
1529
Holger Hans Peter Freyther017738d2010-09-18 06:35:29 +08001530static void create_transcoder(struct mgcp_endpoint *endp)
1531{
1532 int port;
1533 int in_endp = ENDPOINT_NUMBER(endp);
Holger Hans Peter Freytherc983f832010-11-01 21:04:54 +01001534 int out_endp = endp_back_channel(in_endp);
Holger Hans Peter Freyther017738d2010-09-18 06:35:29 +08001535
Pablo Neira Ayusoa3f26c02013-07-08 05:09:46 +02001536 if (endp->type != MGCP_RTP_TRANSCODED)
Holger Hans Peter Freyther017738d2010-09-18 06:35:29 +08001537 return;
1538
Holger Hans Peter Freytherc9e3bc62010-11-01 22:38:25 +01001539 send_msg(endp, in_endp, endp->trans_bts.local_port, "CRCX", "sendrecv");
1540 send_msg(endp, in_endp, endp->trans_bts.local_port, "MDCX", "sendrecv");
Holger Hans Peter Freytherb6345ab2010-11-01 20:53:31 +01001541 send_msg(endp, out_endp, endp->trans_net.local_port, "CRCX", "sendrecv");
1542 send_msg(endp, out_endp, endp->trans_net.local_port, "MDCX", "sendrecv");
Holger Hans Peter Freyther017738d2010-09-18 06:35:29 +08001543
Holger Hans Peter Freytherc983f832010-11-01 21:04:54 +01001544 port = rtp_calculate_port(in_endp, endp->cfg->transcoder_remote_base);
1545 endp->trans_bts.rtp_port = htons(port);
1546 endp->trans_bts.rtcp_port = htons(port + 1);
1547
Holger Hans Peter Freytherd582b202010-09-19 04:21:39 +08001548 port = rtp_calculate_port(out_endp, endp->cfg->transcoder_remote_base);
Holger Hans Peter Freytherb6345ab2010-11-01 20:53:31 +01001549 endp->trans_net.rtp_port = htons(port);
1550 endp->trans_net.rtcp_port = htons(port + 1);
Holger Hans Peter Freyther017738d2010-09-18 06:35:29 +08001551}
1552
1553static void delete_transcoder(struct mgcp_endpoint *endp)
1554{
1555 int in_endp = ENDPOINT_NUMBER(endp);
Holger Hans Peter Freytherc983f832010-11-01 21:04:54 +01001556 int out_endp = endp_back_channel(in_endp);
Holger Hans Peter Freyther017738d2010-09-18 06:35:29 +08001557
Pablo Neira Ayusoa3f26c02013-07-08 05:09:46 +02001558 if (endp->type != MGCP_RTP_TRANSCODED)
Holger Hans Peter Freyther017738d2010-09-18 06:35:29 +08001559 return;
1560
1561 send_dlcx(endp, in_endp);
1562 send_dlcx(endp, out_endp);
1563}
Holger Hans Peter Freytherf8fd1062010-09-19 04:36:07 +08001564
1565int mgcp_reset_transcoder(struct mgcp_config *cfg)
1566{
Holger Hans Peter Freytherf8fd1062010-09-19 04:36:07 +08001567 if (!cfg->transcoder_ip)
Holger Hans Peter Freytherbafc9872010-09-24 04:41:28 +08001568 return 0;
Holger Hans Peter Freytherf8fd1062010-09-19 04:36:07 +08001569
1570 static const char mgcp_reset[] = {
1571 "RSIP 1 13@mgw MGCP 1.0\r\n"
1572 };
1573
Holger Hans Peter Freyther1adedbb2010-09-19 04:39:55 +08001574 return send_trans(cfg, mgcp_reset, sizeof mgcp_reset -1);
Holger Hans Peter Freytherf8fd1062010-09-19 04:36:07 +08001575}
Holger Hans Peter Freyther8fc6d082012-09-14 17:18:12 +02001576
1577void mgcp_format_stats(struct mgcp_endpoint *endp, char *msg, size_t size)
1578{
Holger Hans Peter Freyther8c87a482012-10-24 21:22:47 +02001579 uint32_t expected, jitter;
Holger Hans Peter Freytherfaa67932012-10-22 18:09:35 +02001580 int ploss;
Jacob Erlbecka2528da2013-11-25 12:53:28 +01001581 int nchars;
Holger Hans Peter Freytherfaa67932012-10-22 18:09:35 +02001582 mgcp_state_calc_loss(&endp->net_state, &endp->net_end,
1583 &expected, &ploss);
Holger Hans Peter Freyther8c87a482012-10-24 21:22:47 +02001584 jitter = mgcp_state_calc_jitter(&endp->net_state);
Holger Hans Peter Freytherfaa67932012-10-22 18:09:35 +02001585
Jacob Erlbecka2528da2013-11-25 12:53:28 +01001586 nchars = snprintf(msg, size,
1587 "\r\nP: PS=%u, OS=%u, PR=%u, OR=%u, PL=%d, JI=%u",
1588 endp->bts_end.packets, endp->bts_end.octets,
1589 endp->net_end.packets, endp->net_end.octets,
1590 ploss, jitter);
1591 if (nchars < 0 || nchars >= size)
1592 goto truncate;
1593
1594 msg += nchars;
1595 size -= nchars;
1596
1597 /* Error Counter */
1598 snprintf(msg, size,
1599 "\r\nX-Osmo-CP: EC TIS=%u, TOS=%u, TIR=%u, TOR=%u",
1600 endp->net_state.in_stream.err_ts_counter,
1601 endp->net_state.out_stream.err_ts_counter,
1602 endp->bts_state.in_stream.err_ts_counter,
1603 endp->bts_state.out_stream.err_ts_counter);
1604truncate:
Holger Hans Peter Freyther8fc6d082012-09-14 17:18:12 +02001605 msg[size - 1] = '\0';
1606}
Holger Hans Peter Freyther931d6982012-10-24 21:53:40 +02001607
1608int mgcp_parse_stats(struct msgb *msg, uint32_t *ps, uint32_t *os,
1609 uint32_t *pr, uint32_t *_or, int *loss, uint32_t *jitter)
1610{
1611 char *line, *save;
1612 int rc;
1613
1614 /* initialize with bad values */
1615 *ps = *os = *pr = *_or = *jitter = UINT_MAX;
1616 *loss = INT_MAX;
1617
1618
1619 line = strtok_r((char *) msg->l2h, "\r\n", &save);
1620 if (!line)
1621 return -1;
1622
1623 /* this can only parse the message that is created above... */
Jacob Erlbeck7a6510c2013-11-29 13:43:43 +01001624 for_each_non_empty_line(line, save) {
Holger Hans Peter Freyther931d6982012-10-24 21:53:40 +02001625 switch (line[0]) {
1626 case 'P':
1627 rc = sscanf(line, "P: PS=%u, OS=%u, PR=%u, OR=%u, PL=%d, JI=%u",
1628 ps, os, pr, _or, loss, jitter);
1629 return rc == 6 ? 0 : -1;
1630 }
1631 }
1632
1633 return -1;
1634}