blob: c703bec1349827c2053db868e3f0a6be4afe0cd2 [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>
31
Pablo Neira Ayusodd5fff42011-03-22 16:47:59 +010032#include <osmocom/core/msgb.h>
33#include <osmocom/core/talloc.h>
34#include <osmocom/core/select.h>
Holger Hans Peter Freyther6d419f92011-02-28 22:06:47 +010035
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +010036#include <openbsc/mgcp.h>
Holger Hans Peter Freyther6f38c062010-02-20 21:21:02 +010037#include <openbsc/mgcp_internal.h>
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +010038
Jacob Erlbeck7a6510c2013-11-29 13:43:43 +010039#define for_each_non_empty_line(line, save) \
Holger Hans Peter Freythercd256952012-12-07 15:04:07 +010040 for (line = strtok_r(NULL, "\r\n", &save); line;\
Harald Welteec4f01b2012-01-27 12:31:36 +010041 line = strtok_r(NULL, "\r\n", &save))
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +010042
Jacob Erlbecke7060c42013-11-29 13:43:44 +010043#define for_each_line(line, save) \
44 for (line = strline_r(NULL, &save); line;\
45 line = strline_r(NULL, &save))
46
47char *strline_r(char *str, char **saveptr)
48{
49 char *result;
50
51 if (str)
52 *saveptr = str;
53
54 result = *saveptr;
55
56 if (*saveptr != NULL) {
57 *saveptr = strpbrk(*saveptr, "\r\n");
58
59 if (*saveptr != NULL) {
60 char *eos = *saveptr;
61
62 if ((*saveptr)[0] == '\r' && (*saveptr)[1] == '\n')
63 (*saveptr)++;
64 (*saveptr)++;
65 if ((*saveptr)[0] == '\0')
66 *saveptr = NULL;
67
68 *eos = '\0';
69 }
70 }
71
72 return result;
73}
74
Jacob Erlbeckac9f6ce2013-11-25 15:23:35 +010075/* Assume audio frame length of 20ms */
76#define DEFAULT_RTP_AUDIO_FRAME_DUR_NUM 20
77#define DEFAULT_RTP_AUDIO_FRAME_DUR_DEN 1000
78#define DEFAULT_RTP_AUDIO_FRAMES_PER_PACKET 1
79#define DEFAULT_RTP_AUDIO_DEFAULT_RATE 8000
80
Holger Hans Peter Freyther05d8f5f2010-08-05 08:08:17 +080081static void mgcp_rtp_end_reset(struct mgcp_rtp_end *end);
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +010082
Holger Hans Peter Freythercd256952012-12-07 15:04:07 +010083struct mgcp_parse_data {
84 struct mgcp_config *cfg;
85 struct mgcp_endpoint *endp;
86 char *trans;
87 char *save;
88 int found;
89};
90
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +010091struct mgcp_request {
92 char *name;
Holger Hans Peter Freythercd256952012-12-07 15:04:07 +010093 struct msgb *(*handle_request) (struct mgcp_parse_data *data);
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +010094 char *debug_name;
95};
96
97#define MGCP_REQUEST(NAME, REQ, DEBUG_NAME) \
98 { .name = NAME, .handle_request = REQ, .debug_name = DEBUG_NAME },
99
Holger Hans Peter Freythercd256952012-12-07 15:04:07 +0100100static struct msgb *handle_audit_endpoint(struct mgcp_parse_data *data);
101static struct msgb *handle_create_con(struct mgcp_parse_data *data);
102static struct msgb *handle_delete_con(struct mgcp_parse_data *data);
103static struct msgb *handle_modify_con(struct mgcp_parse_data *data);
104static struct msgb *handle_rsip(struct mgcp_parse_data *data);
105static struct msgb *handle_noti_req(struct mgcp_parse_data *data);
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100106
Holger Hans Peter Freyther017738d2010-09-18 06:35:29 +0800107static void create_transcoder(struct mgcp_endpoint *endp);
108static void delete_transcoder(struct mgcp_endpoint *endp);
109
Holger Hans Peter Freythercd256952012-12-07 15:04:07 +0100110static int mgcp_analyze_header(struct mgcp_parse_data *parse, char *data);
111
Holger Hans Peter Freyther526b4d32010-08-06 08:26:54 +0800112static uint32_t generate_call_id(struct mgcp_config *cfg)
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100113{
114 int i;
115
116 /* use the call id */
Holger Hans Peter Freyther6f38c062010-02-20 21:21:02 +0100117 ++cfg->last_call_id;
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100118
119 /* handle wrap around */
Holger Hans Peter Freyther6f38c062010-02-20 21:21:02 +0100120 if (cfg->last_call_id == CI_UNUSED)
121 ++cfg->last_call_id;
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100122
123 /* callstack can only be of size number_of_endpoints */
124 /* verify that the call id is free, e.g. in case of overrun */
Holger Hans Peter Freytherab56ce12011-02-28 00:56:17 +0100125 for (i = 1; i < cfg->trunk.number_endpoints; ++i)
126 if (cfg->trunk.endpoints[i].ci == cfg->last_call_id)
Holger Hans Peter Freyther6f38c062010-02-20 21:21:02 +0100127 return generate_call_id(cfg);
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100128
Holger Hans Peter Freyther6f38c062010-02-20 21:21:02 +0100129 return cfg->last_call_id;
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100130}
131
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100132/*
133 * array of function pointers for handling various
134 * messages. In the future this might be binary sorted
135 * for performance reasons.
136 */
137static const struct mgcp_request mgcp_requests [] = {
138 MGCP_REQUEST("AUEP", handle_audit_endpoint, "AuditEndpoint")
139 MGCP_REQUEST("CRCX", handle_create_con, "CreateConnection")
140 MGCP_REQUEST("DLCX", handle_delete_con, "DeleteConnection")
141 MGCP_REQUEST("MDCX", handle_modify_con, "ModifiyConnection")
Holger Hans Peter Freytherac0968e2011-01-25 23:33:54 +0100142 MGCP_REQUEST("RQNT", handle_noti_req, "NotificationRequest")
Holger Hans Peter Freytherd60c6e52010-03-31 06:39:35 +0200143
144 /* SPEC extension */
145 MGCP_REQUEST("RSIP", handle_rsip, "ReSetInProgress")
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100146};
147
Holger Hans Peter Freytherad4e3392010-02-03 11:03:45 +0100148static struct msgb *mgcp_msgb_alloc(void)
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100149{
Holger Hans Peter Freytherad4e3392010-02-03 11:03:45 +0100150 struct msgb *msg;
151 msg = msgb_alloc_headroom(4096, 128, "MGCP msg");
152 if (!msg)
153 LOGP(DMGCP, LOGL_ERROR, "Failed to msgb for MGCP data.\n");
154
155 return msg;
156}
157
Holger Hans Peter Freythercd256952012-12-07 15:04:07 +0100158static struct msgb *do_retransmission(const struct mgcp_endpoint *endp)
159{
160 struct msgb *msg = mgcp_msgb_alloc();
161 if (!msg)
162 return NULL;
163
164 msg->l2h = msgb_put(msg, strlen(endp->last_response));
165 memcpy(msg->l2h, endp->last_response, msgb_l2len(msg));
166 return msg;
167}
168
Holger Hans Peter Freyther3ba9cce2012-12-07 15:14:27 +0100169static struct msgb *create_resp(struct mgcp_endpoint *endp, int code,
170 const char *txt, const char *msg,
Holger Hans Peter Freyther8fc6d082012-09-14 17:18:12 +0200171 const char *trans, const char *param,
172 const char *sdp)
Holger Hans Peter Freytherad4e3392010-02-03 11:03:45 +0100173{
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100174 int len;
Holger Hans Peter Freytherad4e3392010-02-03 11:03:45 +0100175 struct msgb *res;
176
177 res = mgcp_msgb_alloc();
178 if (!res)
179 return NULL;
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100180
Holger Hans Peter Freyther8fc6d082012-09-14 17:18:12 +0200181 len = snprintf((char *) res->data, 2048, "%d %s%s%s\r\n%s",
182 code, trans, txt, param ? param : "", sdp ? sdp : "");
183 if (len < 0) {
184 LOGP(DMGCP, LOGL_ERROR, "Failed to sprintf MGCP response.\n");
185 msgb_free(res);
186 return NULL;
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100187 }
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100188
Holger Hans Peter Freytherad4e3392010-02-03 11:03:45 +0100189 res->l2h = msgb_put(res, len);
Holger Hans Peter Freythercd256952012-12-07 15:04:07 +0100190 LOGP(DMGCP, LOGL_DEBUG, "Generated response: code: %d for '%s'\n", code, res->l2h);
191
192 /*
193 * Remember the last transmission per endpoint.
194 */
195 if (endp) {
196 struct mgcp_trunk_config *tcfg = endp->tcfg;
197 talloc_free(endp->last_response);
198 talloc_free(endp->last_trans);
199 endp->last_trans = talloc_strdup(tcfg->endpoints, trans);
200 endp->last_response = talloc_strndup(tcfg->endpoints,
201 (const char *) res->l2h,
202 msgb_l2len(res));
203 }
204
Holger Hans Peter Freytherad4e3392010-02-03 11:03:45 +0100205 return res;
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100206}
207
Holger Hans Peter Freyther3ba9cce2012-12-07 15:14:27 +0100208static struct msgb *create_ok_resp_with_param(struct mgcp_endpoint *endp,
209 int code, const char *msg,
Holger Hans Peter Freyther8fc6d082012-09-14 17:18:12 +0200210 const char *trans, const char *param)
211{
Holger Hans Peter Freyther3ba9cce2012-12-07 15:14:27 +0100212 return create_resp(endp, code, " OK", msg, trans, param, NULL);
Holger Hans Peter Freyther8fc6d082012-09-14 17:18:12 +0200213}
214
Holger Hans Peter Freyther3ba9cce2012-12-07 15:14:27 +0100215static struct msgb *create_ok_response(struct mgcp_endpoint *endp,
216 int code, const char *msg, const char *trans)
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100217{
Holger Hans Peter Freyther3ba9cce2012-12-07 15:14:27 +0100218 return create_ok_resp_with_param(endp, code, msg, trans, NULL);
Holger Hans Peter Freyther804019a2011-01-06 16:19:55 +0100219}
220
Holger Hans Peter Freyther3ba9cce2012-12-07 15:14:27 +0100221static struct msgb *create_err_response(struct mgcp_endpoint *endp,
222 int code, const char *msg, const char *trans)
Holger Hans Peter Freyther804019a2011-01-06 16:19:55 +0100223{
Holger Hans Peter Freyther3ba9cce2012-12-07 15:14:27 +0100224 return create_resp(endp, code, " FAIL", msg, trans, NULL, NULL);
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100225}
226
Holger Hans Peter Freyther60d02a32010-02-21 01:44:08 +0100227static struct msgb *create_response_with_sdp(struct mgcp_endpoint *endp,
228 const char *msg, const char *trans_id)
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100229{
Holger Hans Peter Freyther6f38c062010-02-20 21:21:02 +0100230 const char *addr = endp->cfg->local_ip;
Holger Hans Peter Freyther4928d1b2012-09-03 00:07:39 +0200231 const char *fmtp_extra = endp->bts_end.fmtp_extra;
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100232 char sdp_record[4096];
233
234 if (!addr)
Holger Hans Peter Freyther6f38c062010-02-20 21:21:02 +0100235 addr = endp->cfg->source_addr;
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100236
237 snprintf(sdp_record, sizeof(sdp_record) - 1,
Holger Hans Peter Freyther526b4d32010-08-06 08:26:54 +0800238 "I: %u\n\n"
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100239 "v=0\r\n"
Holger Hans Peter Freyther2e0af512011-07-20 20:43:15 +0200240 "o=- %u 23 IN IP4 %s\r\n"
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100241 "c=IN IP4 %s\r\n"
Holger Hans Peter Freyther2e0af512011-07-20 20:43:15 +0200242 "t=0 0\r\n"
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100243 "m=audio %d RTP/AVP %d\r\n"
Holger Hans Peter Freyther4928d1b2012-09-03 00:07:39 +0200244 "a=rtpmap:%d %s\r\n"
245 "%s%s",
Holger Hans Peter Freyther2e0af512011-07-20 20:43:15 +0200246 endp->ci, endp->ci, addr, addr,
247 endp->net_end.local_port, endp->bts_end.payload_type,
Holger Hans Peter Freyther4928d1b2012-09-03 00:07:39 +0200248 endp->bts_end.payload_type, endp->tcfg->audio_name,
249 fmtp_extra ? fmtp_extra : "", fmtp_extra ? "\r\n" : "");
Holger Hans Peter Freyther3ba9cce2012-12-07 15:14:27 +0100250 return create_resp(endp, 200, " OK", msg, trans_id, NULL, sdp_record);
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100251}
252
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100253/*
254 * handle incoming messages:
255 * - this can be a command (four letters, space, transaction id)
256 * - or a response (three numbers, space, transaction id)
257 */
Holger Hans Peter Freyther6f38c062010-02-20 21:21:02 +0100258struct msgb *mgcp_handle_message(struct mgcp_config *cfg, struct msgb *msg)
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100259{
Holger Hans Peter Freythercd256952012-12-07 15:04:07 +0100260 struct mgcp_parse_data pdata;
261 int i, code, handled = 0;
Holger Hans Peter Freytherad4e3392010-02-03 11:03:45 +0100262 struct msgb *resp = NULL;
Holger Hans Peter Freythercd256952012-12-07 15:04:07 +0100263 char *data;
Jacob Erlbeck3c629c62013-12-03 17:14:44 +0100264 unsigned char *tail = msg->l2h + msgb_l2len(msg); /* char after l2 data */
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100265
Holger Hans Peter Freyther0421be72010-03-31 13:26:46 +0200266 if (msgb_l2len(msg) < 4) {
Holger Hans Peter Freytherbed02ba2012-12-07 16:46:19 +0100267 LOGP(DMGCP, LOGL_ERROR, "msg too short: %d\n", msg->len);
Holger Hans Peter Freytherad4e3392010-02-03 11:03:45 +0100268 return NULL;
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100269 }
270
Jacob Erlbeck3c629c62013-12-03 17:14:44 +0100271 /* Ensure that the msg->l2h is NUL terminated. */
272 if (tail[-1] == '\0')
273 /* nothing to do */;
274 else if (msgb_tailroom(msg) > 0)
275 tail[0] = '\0';
276 else if (tail[-1] == '\r' || tail[-1] == '\n')
277 tail[-1] = '\0';
278 else {
279 LOGP(DMGCP, LOGL_ERROR, "Cannot NUL terminate MGCP message: "
280 "Length: %d, Buffer size: %d\n",
281 msgb_l2len(msg), msg->data_len);
282 return NULL;
283 }
284
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100285 /* attempt to treat it as a response */
Holger Hans Peter Freyther0421be72010-03-31 13:26:46 +0200286 if (sscanf((const char *)&msg->l2h[0], "%3d %*s", &code) == 1) {
Holger Hans Peter Freyther40faed82010-02-26 13:30:57 +0100287 LOGP(DMGCP, LOGL_DEBUG, "Response: Code: %d\n", code);
Holger Hans Peter Freytherb139e2c2012-12-07 16:07:46 +0100288 return NULL;
289 }
290
291 msg->l3h = &msg->l2h[4];
292
Holger Hans Peter Freythercd256952012-12-07 15:04:07 +0100293
294 /*
295 * Check for a duplicate message and respond.
Holger Hans Peter Freythercd256952012-12-07 15:04:07 +0100296 */
297 memset(&pdata, 0, sizeof(pdata));
298 pdata.cfg = cfg;
Jacob Erlbeck9cec6672013-11-29 13:43:46 +0100299 data = strline_r((char *) msg->l3h, &pdata.save);
Holger Hans Peter Freythercd256952012-12-07 15:04:07 +0100300 pdata.found = mgcp_analyze_header(&pdata, data);
301 if (pdata.endp && pdata.trans
302 && pdata.endp->last_trans
303 && strcmp(pdata.endp->last_trans, pdata.trans) == 0) {
304 return do_retransmission(pdata.endp);
305 }
306
Holger Hans Peter Freytherb139e2c2012-12-07 16:07:46 +0100307 for (i = 0; i < ARRAY_SIZE(mgcp_requests); ++i) {
308 if (strncmp(mgcp_requests[i].name, (const char *) &msg->l2h[0], 4) == 0) {
309 handled = 1;
Holger Hans Peter Freythercd256952012-12-07 15:04:07 +0100310 resp = mgcp_requests[i].handle_request(&pdata);
Holger Hans Peter Freytherb139e2c2012-12-07 16:07:46 +0100311 break;
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100312 }
313 }
314
Holger Hans Peter Freytherb139e2c2012-12-07 16:07:46 +0100315 if (!handled)
316 LOGP(DMGCP, LOGL_NOTICE, "MSG with type: '%.4s' not handled\n", &msg->l2h[0]);
317
Holger Hans Peter Freytherad4e3392010-02-03 11:03:45 +0100318 return resp;
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100319}
320
Holger Hans Peter Freytherf0bc0752011-01-06 19:32:52 +0100321/**
322 * We have a null terminated string with the endpoint name here. We only
323 * support two kinds. Simple ones as seen on the BSC level and the ones
324 * seen on the trunk side.
325 */
326static struct mgcp_endpoint *find_e1_endpoint(struct mgcp_config *cfg,
327 const char *mgcp)
328{
329 char *rest = NULL;
Holger Hans Peter Freyther1d137122011-02-28 14:13:47 +0100330 struct mgcp_trunk_config *tcfg;
331 int trunk, endp;
Holger Hans Peter Freytherf0bc0752011-01-06 19:32:52 +0100332
333 trunk = strtoul(mgcp + 6, &rest, 10);
Holger Hans Peter Freyther72026c12011-01-07 11:30:21 +0100334 if (rest == NULL || rest[0] != '/' || trunk < 1) {
Holger Hans Peter Freytherf0bc0752011-01-06 19:32:52 +0100335 LOGP(DMGCP, LOGL_ERROR, "Wrong trunk name '%s'\n", mgcp);
336 return NULL;
337 }
338
339 endp = strtoul(rest + 1, &rest, 10);
340 if (rest == NULL || rest[0] != '@') {
Holger Hans Peter Freyther72026c12011-01-07 11:30:21 +0100341 LOGP(DMGCP, LOGL_ERROR, "Wrong endpoint name '%s'\n", mgcp);
Holger Hans Peter Freytherf0bc0752011-01-06 19:32:52 +0100342 return NULL;
343 }
344
345 /* signalling is on timeslot 1 */
346 if (endp == 1)
347 return NULL;
348
Holger Hans Peter Freyther1d137122011-02-28 14:13:47 +0100349 tcfg = mgcp_trunk_num(cfg, trunk);
350 if (!tcfg) {
351 LOGP(DMGCP, LOGL_ERROR, "The trunk %d is not declared.\n", trunk);
352 return NULL;
353 }
354
355 if (!tcfg->endpoints) {
356 LOGP(DMGCP, LOGL_ERROR, "Endpoints of trunk %d not allocated.\n", trunk);
357 return NULL;
358 }
359
360 if (endp < 1 || endp >= tcfg->number_endpoints) {
Holger Hans Peter Freytherf0bc0752011-01-06 19:32:52 +0100361 LOGP(DMGCP, LOGL_ERROR, "Failed to find endpoint '%s'\n", mgcp);
Holger Hans Peter Freyther0f1786f2011-01-07 11:36:54 +0100362 return NULL;
Holger Hans Peter Freytherf0bc0752011-01-06 19:32:52 +0100363 }
364
Holger Hans Peter Freyther1d137122011-02-28 14:13:47 +0100365 return &tcfg->endpoints[endp];
Holger Hans Peter Freytherf0bc0752011-01-06 19:32:52 +0100366}
367
Holger Hans Peter Freyther6f38c062010-02-20 21:21:02 +0100368static struct mgcp_endpoint *find_endpoint(struct mgcp_config *cfg, const char *mgcp)
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100369{
370 char *endptr = NULL;
371 unsigned int gw = INT_MAX;
372
Holger Hans Peter Freytherf0bc0752011-01-06 19:32:52 +0100373 if (strncmp(mgcp, "ds/e1", 5) == 0) {
374 return find_e1_endpoint(cfg, mgcp);
375 } else {
376 gw = strtoul(mgcp, &endptr, 16);
Holger Hans Peter Freytherab56ce12011-02-28 00:56:17 +0100377 if (gw > 0 && gw < cfg->trunk.number_endpoints && strcmp(endptr, "@mgw") == 0)
378 return &cfg->trunk.endpoints[gw];
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100379 }
380
Holger Hans Peter Freytherf0bc0752011-01-06 19:32:52 +0100381 LOGP(DMGCP, LOGL_ERROR, "Not able to find endpoint: '%s'\n", mgcp);
382 return NULL;
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100383}
384
Harald Welteec4f01b2012-01-27 12:31:36 +0100385/**
386 * @returns 0 when the status line was complete and transaction_id and
387 * endp out parameters are set.
388 */
Holger Hans Peter Freythercd256952012-12-07 15:04:07 +0100389static int mgcp_analyze_header(struct mgcp_parse_data *pdata, char *data)
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100390{
Harald Welteec4f01b2012-01-27 12:31:36 +0100391 int i = 0;
Holger Hans Peter Freyther0b6dca72013-07-03 10:23:35 +0200392 char *elem, *save = NULL;
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100393
Holger Hans Peter Freythercd256952012-12-07 15:04:07 +0100394 pdata->trans = "000000";
Holger Hans Peter Freyther275c0442010-02-26 13:32:55 +0100395
Harald Welteec4f01b2012-01-27 12:31:36 +0100396 for (elem = strtok_r(data, " ", &save); elem;
397 elem = strtok_r(NULL, " ", &save)) {
398 switch (i) {
399 case 0:
Holger Hans Peter Freythercd256952012-12-07 15:04:07 +0100400 pdata->trans = elem;
Harald Welteec4f01b2012-01-27 12:31:36 +0100401 break;
402 case 1:
Holger Hans Peter Freythercd256952012-12-07 15:04:07 +0100403 pdata->endp = find_endpoint(pdata->cfg, elem);
404 if (!pdata->endp) {
405 LOGP(DMGCP, LOGL_ERROR,
406 "Unable to find Endpoint `%s'\n", elem);
407 return -1;
Harald Welteec4f01b2012-01-27 12:31:36 +0100408 }
409 break;
410 case 2:
411 if (strcmp("MGCP", elem)) {
412 LOGP(DMGCP, LOGL_ERROR,
413 "MGCP header parsing error\n");
414 return -1;
415 }
416 break;
417 case 3:
418 if (strcmp("1.0", elem)) {
419 LOGP(DMGCP, LOGL_ERROR, "MGCP version `%s' "
420 "not supported\n", elem);
421 return -1;
422 }
423 break;
424 }
425 i++;
426 }
427
428 if (i != 4) {
429 LOGP(DMGCP, LOGL_ERROR, "MGCP status line too short.\n");
Holger Hans Peter Freythercd256952012-12-07 15:04:07 +0100430 pdata->trans = "000000";
431 pdata->endp = NULL;
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100432 return -1;
433 }
434
Holger Hans Peter Freyther96354632010-04-01 03:27:04 +0200435 return 0;
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100436}
437
438static int verify_call_id(const struct mgcp_endpoint *endp,
439 const char *callid)
440{
441 if (strcmp(endp->callid, callid) != 0) {
Holger Hans Peter Freyther02c7a6f2010-02-03 09:13:10 +0100442 LOGP(DMGCP, LOGL_ERROR, "CallIDs does not match on 0x%x. '%s' != '%s'\n",
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100443 ENDPOINT_NUMBER(endp), endp->callid, callid);
444 return -1;
445 }
446
447 return 0;
448}
449
450static int verify_ci(const struct mgcp_endpoint *endp,
Holger Hans Peter Freyther526b4d32010-08-06 08:26:54 +0800451 const char *_ci)
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100452{
Holger Hans Peter Freyther526b4d32010-08-06 08:26:54 +0800453 uint32_t ci = strtoul(_ci, NULL, 10);
454
455 if (ci != endp->ci) {
456 LOGP(DMGCP, LOGL_ERROR, "ConnectionIdentifiers do not match on 0x%x. %u != %s\n",
457 ENDPOINT_NUMBER(endp), endp->ci, _ci);
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100458 return -1;
459 }
460
461 return 0;
462}
463
Holger Hans Peter Freythercd256952012-12-07 15:04:07 +0100464static struct msgb *handle_audit_endpoint(struct mgcp_parse_data *p)
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100465{
Holger Hans Peter Freythercd256952012-12-07 15:04:07 +0100466 if (p->found != 0)
467 return create_err_response(NULL, 500, "AUEP", p->trans);
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100468 else
Holger Hans Peter Freythercd256952012-12-07 15:04:07 +0100469 return create_ok_response(p->endp, 200, "AUEP", p->trans);
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100470}
471
Holger Hans Peter Freytherdfd61a32010-09-18 06:44:24 +0800472static int parse_conn_mode(const char *msg, int *conn_mode)
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100473{
474 int ret = 0;
475 if (strcmp(msg, "recvonly") == 0)
476 *conn_mode = MGCP_CONN_RECV_ONLY;
477 else if (strcmp(msg, "sendrecv") == 0)
478 *conn_mode = MGCP_CONN_RECV_SEND;
Holger Hans Peter Freyther0bfcbee2010-09-18 20:21:44 +0800479 else if (strcmp(msg, "sendonly") == 0)
480 *conn_mode = MGCP_CONN_SEND_ONLY;
Holger Hans Peter Freyther0bdf20d2010-08-03 02:27:21 +0800481 else if (strcmp(msg, "loopback") == 0)
482 *conn_mode = MGCP_CONN_LOOPBACK;
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100483 else {
Holger Hans Peter Freyther02c7a6f2010-02-03 09:13:10 +0100484 LOGP(DMGCP, LOGL_ERROR, "Unknown connection mode: '%s'\n", msg);
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100485 ret = -1;
486 }
487
488 return ret;
489}
490
Holger Hans Peter Freyther05d8f5f2010-08-05 08:08:17 +0800491static int allocate_port(struct mgcp_endpoint *endp, struct mgcp_rtp_end *end,
Holger Hans Peter Freyther56ac2692010-09-18 02:30:02 +0800492 struct mgcp_port_range *range,
493 int (*alloc)(struct mgcp_endpoint *endp, int port))
Holger Hans Peter Freyther05d8f5f2010-08-05 08:08:17 +0800494{
495 int i;
496
497 if (range->mode == PORT_ALLOC_STATIC) {
Holger Hans Peter Freyther05d8f5f2010-08-05 08:08:17 +0800498 end->local_alloc = PORT_ALLOC_STATIC;
499 return 0;
500 }
501
502 /* attempt to find a port */
503 for (i = 0; i < 200; ++i) {
504 int rc;
505
506 if (range->last_port >= range->range_end)
507 range->last_port = range->range_start;
508
Holger Hans Peter Freyther56ac2692010-09-18 02:30:02 +0800509 rc = alloc(endp, range->last_port);
Holger Hans Peter Freyther05d8f5f2010-08-05 08:08:17 +0800510
511 range->last_port += 2;
512 if (rc == 0) {
513 end->local_alloc = PORT_ALLOC_DYNAMIC;
514 return 0;
515 }
516
517 }
518
Holger Hans Peter Freyther56ac2692010-09-18 02:30:02 +0800519 LOGP(DMGCP, LOGL_ERROR, "Allocating a RTP/RTCP port failed 200 times 0x%x.\n",
520 ENDPOINT_NUMBER(endp));
Holger Hans Peter Freyther05d8f5f2010-08-05 08:08:17 +0800521 return -1;
522}
523
524static int allocate_ports(struct mgcp_endpoint *endp)
525{
Holger Hans Peter Freyther56ac2692010-09-18 02:30:02 +0800526 if (allocate_port(endp, &endp->net_end, &endp->cfg->net_ports,
527 mgcp_bind_net_rtp_port) != 0)
Holger Hans Peter Freyther05d8f5f2010-08-05 08:08:17 +0800528 return -1;
529
Holger Hans Peter Freyther56ac2692010-09-18 02:30:02 +0800530 if (allocate_port(endp, &endp->bts_end, &endp->cfg->bts_ports,
531 mgcp_bind_bts_rtp_port) != 0) {
Holger Hans Peter Freyther05d8f5f2010-08-05 08:08:17 +0800532 mgcp_rtp_end_reset(&endp->net_end);
533 return -1;
534 }
535
Holger Hans Peter Freyther1b8eaf42011-02-28 14:51:48 +0100536 if (endp->cfg->transcoder_ip && endp->tcfg->trunk_type == MGCP_TRUNK_VIRTUAL) {
Holger Hans Peter Freytherb6345ab2010-11-01 20:53:31 +0100537 if (allocate_port(endp, &endp->trans_net,
Holger Hans Peter Freyther1d9a8eb2010-11-01 19:57:50 +0100538 &endp->cfg->transcoder_ports,
Holger Hans Peter Freytherc983f832010-11-01 21:04:54 +0100539 mgcp_bind_trans_net_rtp_port) != 0) {
Holger Hans Peter Freyther1d9a8eb2010-11-01 19:57:50 +0100540 mgcp_rtp_end_reset(&endp->net_end);
541 mgcp_rtp_end_reset(&endp->bts_end);
542 return -1;
543 }
544
Holger Hans Peter Freytherc983f832010-11-01 21:04:54 +0100545 if (allocate_port(endp, &endp->trans_bts,
546 &endp->cfg->transcoder_ports,
547 mgcp_bind_trans_bts_rtp_port) != 0) {
548 mgcp_rtp_end_reset(&endp->net_end);
549 mgcp_rtp_end_reset(&endp->bts_end);
550 mgcp_rtp_end_reset(&endp->trans_net);
551 return -1;
552 }
553
Holger Hans Peter Freyther1d9a8eb2010-11-01 19:57:50 +0100554 /* remember that we have set up transcoding */
Pablo Neira Ayusoa3f26c02013-07-08 05:09:46 +0200555 endp->type = MGCP_RTP_TRANSCODED;
Holger Hans Peter Freyther56ac2692010-09-18 02:30:02 +0800556 }
557
Holger Hans Peter Freyther05d8f5f2010-08-05 08:08:17 +0800558 return 0;
559}
560
Jacob Erlbeck9cec6672013-11-29 13:43:46 +0100561static int parse_sdp_data(struct mgcp_rtp_end *rtp, struct mgcp_parse_data *p)
562{
563 char *line;
564 int found_media = 0;
565
566 for_each_line(line, p->save) {
567 switch (line[0]) {
568 case 'a':
569 case 'o':
570 case 's':
571 case 't':
572 case 'v':
573 /* skip these SDP attributes */
574 break;
575 case 'm': {
576 int port;
577 int payload;
578
579 if (sscanf(line, "m=audio %d RTP/AVP %d",
580 &port, &payload) == 2) {
581 rtp->rtp_port = htons(port);
582 rtp->rtcp_port = htons(port + 1);
583 rtp->payload_type = payload;
584 found_media = 1;
585 }
586 break;
587 }
588 case 'c': {
589 char ipv4[16];
590
591 if (sscanf(line, "c=IN IP4 %15s", ipv4) == 1) {
592 inet_aton(ipv4, &rtp->addr);
593 }
594 break;
595 }
596 default:
597 if (p->endp)
598 LOGP(DMGCP, LOGL_NOTICE,
599 "Unhandled SDP option: '%c'/%d on 0x%x\n",
600 line[0], line[0], ENDPOINT_NUMBER(p->endp));
601 else
602 LOGP(DMGCP, LOGL_NOTICE,
603 "Unhandled SDP option: '%c'/%d\n",
604 line[0], line[0]);
605 break;
606 }
607 }
608
609 if (found_media)
610 LOGP(DMGCP, LOGL_NOTICE,
611 "Got media info via SDP: port %d, payload %d, addr %s\n",
612 ntohs(rtp->rtp_port), rtp->payload_type, inet_ntoa(rtp->addr));
613
614 return found_media;
615}
616
Jacob Erlbecke5546cd2013-12-03 14:43:34 +0100617void mgcp_rtp_end_config(struct mgcp_endpoint *endp, int expect_ssrc_change,
618 struct mgcp_rtp_end *rtp)
619{
620 struct mgcp_trunk_config *tcfg = endp->tcfg;
621
622 rtp->force_constant_timing = tcfg->force_constant_timing;
623 rtp->force_constant_ssrc = tcfg->force_constant_ssrc;
624
625 LOGP(DMGCP, LOGL_DEBUG,
626 "Configuring RTP endpoint: local port %d%s%s\n",
627 ntohs(rtp->rtp_port),
628 rtp->force_constant_timing ? ", force constant timing" : "",
629 rtp->force_constant_ssrc ? ", force constant ssrc" : "");
630}
631
Holger Hans Peter Freythercd256952012-12-07 15:04:07 +0100632static struct msgb *handle_create_con(struct mgcp_parse_data *p)
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100633{
Holger Hans Peter Freytherab56ce12011-02-28 00:56:17 +0100634 struct mgcp_trunk_config *tcfg;
Holger Hans Peter Freythercd256952012-12-07 15:04:07 +0100635 struct mgcp_endpoint *endp = p->endp;
Holger Hans Peter Freyther94ed60f2010-08-08 16:24:48 +0800636 int error_code = 400;
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100637
Holger Hans Peter Freytherc9c0fe52011-07-20 20:44:54 +0200638 const char *local_options = NULL;
639 const char *callid = NULL;
640 const char *mode = NULL;
Holger Hans Peter Freythercd256952012-12-07 15:04:07 +0100641 char *line;
Jacob Erlbecke3440c72013-11-29 13:43:49 +0100642 int have_sdp = 0;
Holger Hans Peter Freythercd256952012-12-07 15:04:07 +0100643
644 if (p->found != 0)
645 return create_err_response(NULL, 510, "CRCX", p->trans);
Holger Hans Peter Freytherab56ce12011-02-28 00:56:17 +0100646
Holger Hans Peter Freytherc9c0fe52011-07-20 20:44:54 +0200647 /* parse CallID C: and LocalParameters L: */
Jacob Erlbeck9cec6672013-11-29 13:43:46 +0100648 for_each_line(line, p->save) {
Harald Welteec4f01b2012-01-27 12:31:36 +0100649 switch (line[0]) {
650 case 'L':
651 local_options = (const char *) line + 3;
652 break;
653 case 'C':
654 callid = (const char *) line + 3;
655 break;
656 case 'M':
657 mode = (const char *) line + 3;
658 break;
Jacob Erlbecke3440c72013-11-29 13:43:49 +0100659 case '\0':
660 have_sdp = 1;
661 goto mgcp_header_done;
Harald Welteec4f01b2012-01-27 12:31:36 +0100662 default:
663 LOGP(DMGCP, LOGL_NOTICE, "Unhandled option: '%c'/%d on 0x%x\n",
664 *line, *line, ENDPOINT_NUMBER(endp));
665 break;
666 }
Holger Hans Peter Freytherc9c0fe52011-07-20 20:44:54 +0200667 }
Harald Welteec4f01b2012-01-27 12:31:36 +0100668
Jacob Erlbecke3440c72013-11-29 13:43:49 +0100669mgcp_header_done:
Holger Hans Peter Freythercd256952012-12-07 15:04:07 +0100670 tcfg = p->endp->tcfg;
Holger Hans Peter Freytherc9c0fe52011-07-20 20:44:54 +0200671
672 /* Check required data */
673 if (!callid || !mode) {
674 LOGP(DMGCP, LOGL_ERROR, "Missing callid and mode in CRCX on 0x%x\n",
675 ENDPOINT_NUMBER(endp));
Holger Hans Peter Freythercd256952012-12-07 15:04:07 +0100676 return create_err_response(endp, 400, "CRCX", p->trans);
Holger Hans Peter Freytherc9c0fe52011-07-20 20:44:54 +0200677 }
678
Holger Hans Peter Freythere15223b2010-08-06 18:03:11 +0800679 if (endp->allocated) {
Holger Hans Peter Freytherab56ce12011-02-28 00:56:17 +0100680 if (tcfg->force_realloc) {
Holger Hans Peter Freytherdd67a3b2010-04-07 10:51:27 +0200681 LOGP(DMGCP, LOGL_NOTICE, "Endpoint 0x%x already allocated. Forcing realloc.\n",
682 ENDPOINT_NUMBER(endp));
Holger Hans Peter Freyther5c132ee2010-04-24 21:02:48 +0800683 mgcp_free_endp(endp);
Holger Hans Peter Freythercd256952012-12-07 15:04:07 +0100684 if (p->cfg->realloc_cb)
685 p->cfg->realloc_cb(tcfg, ENDPOINT_NUMBER(endp));
Holger Hans Peter Freytherdd67a3b2010-04-07 10:51:27 +0200686 } else {
687 LOGP(DMGCP, LOGL_ERROR, "Endpoint is already used. 0x%x\n",
688 ENDPOINT_NUMBER(endp));
Holger Hans Peter Freythercd256952012-12-07 15:04:07 +0100689 return create_err_response(endp, 400, "CRCX", p->trans);
Holger Hans Peter Freytherdd67a3b2010-04-07 10:51:27 +0200690 }
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100691 }
692
Holger Hans Peter Freytherc9c0fe52011-07-20 20:44:54 +0200693 /* copy some parameters */
694 endp->callid = talloc_strdup(tcfg->endpoints, callid);
695
696 if (local_options)
697 endp->local_options = talloc_strdup(tcfg->endpoints, local_options);
698
699 if (parse_conn_mode(mode, &endp->conn_mode) != 0) {
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100700 error_code = 517;
701 goto error2;
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100702 }
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100703
704 /* initialize */
Holger Hans Peter Freytherfab76aa2010-08-05 01:34:51 +0800705 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 +0100706 mgcp_rtp_end_config(endp, 0, &endp->net_end);
707 mgcp_rtp_end_config(endp, 0, &endp->bts_end);
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100708
709 /* set to zero until we get the info */
Holger Hans Peter Freytherfab76aa2010-08-05 01:34:51 +0800710 memset(&endp->net_end.addr, 0, sizeof(endp->net_end.addr));
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100711
712 /* bind to the port now */
Holger Hans Peter Freyther05d8f5f2010-08-05 08:08:17 +0800713 if (allocate_ports(endp) != 0)
714 goto error2;
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100715
716 /* assign a local call identifier or fail */
Holger Hans Peter Freythercd256952012-12-07 15:04:07 +0100717 endp->ci = generate_call_id(p->cfg);
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100718 if (endp->ci == CI_UNUSED)
719 goto error2;
720
Holger Hans Peter Freythere15223b2010-08-06 18:03:11 +0800721 endp->allocated = 1;
Jacob Erlbecke3440c72013-11-29 13:43:49 +0100722
723 /* set up RTP media parameters */
Holger Hans Peter Freytherab56ce12011-02-28 00:56:17 +0100724 endp->bts_end.payload_type = tcfg->audio_payload;
Holger Hans Peter Freyther4928d1b2012-09-03 00:07:39 +0200725 endp->bts_end.fmtp_extra = talloc_strdup(tcfg->endpoints,
726 tcfg->audio_fmtp_extra);
Jacob Erlbecke3440c72013-11-29 13:43:49 +0100727 if (have_sdp)
728 parse_sdp_data(&endp->net_end, p);
Holger Hans Peter Freyther001dc612010-02-26 13:41:22 +0100729
Holger Hans Peter Freyther7a8ff2a2010-02-26 13:37:05 +0100730 /* policy CB */
Holger Hans Peter Freythercd256952012-12-07 15:04:07 +0100731 if (p->cfg->policy_cb) {
732 int rc;
733 rc = p->cfg->policy_cb(tcfg, ENDPOINT_NUMBER(endp),
734 MGCP_ENDP_CRCX, p->trans);
735 switch (rc) {
Holger Hans Peter Freyther7a8ff2a2010-02-26 13:37:05 +0100736 case MGCP_POLICY_REJECT:
737 LOGP(DMGCP, LOGL_NOTICE, "CRCX rejected by policy on 0x%x\n",
738 ENDPOINT_NUMBER(endp));
739 mgcp_free_endp(endp);
Holger Hans Peter Freythercd256952012-12-07 15:04:07 +0100740 return create_err_response(endp, 400, "CRCX", p->trans);
Holger Hans Peter Freyther7a8ff2a2010-02-26 13:37:05 +0100741 break;
742 case MGCP_POLICY_DEFER:
743 /* stop processing */
Holger Hans Peter Freyther017738d2010-09-18 06:35:29 +0800744 create_transcoder(endp);
Holger Hans Peter Freyther7a8ff2a2010-02-26 13:37:05 +0100745 return NULL;
746 break;
747 case MGCP_POLICY_CONT:
748 /* just continue */
749 break;
750 }
751 }
752
Holger Hans Peter Freyther73d00472010-08-06 20:22:23 +0800753 LOGP(DMGCP, LOGL_DEBUG, "Creating endpoint on: 0x%x CI: %u port: %u/%u\n",
Holger Hans Peter Freyther148c5d32010-08-05 03:08:35 +0800754 ENDPOINT_NUMBER(endp), endp->ci,
755 endp->net_end.local_port, endp->bts_end.local_port);
Holger Hans Peter Freythercd256952012-12-07 15:04:07 +0100756 if (p->cfg->change_cb)
757 p->cfg->change_cb(tcfg, ENDPOINT_NUMBER(endp), MGCP_ENDP_CRCX);
Holger Hans Peter Freyther25374bd2010-02-03 09:54:43 +0100758
Holger Hans Peter Freyther017738d2010-09-18 06:35:29 +0800759 create_transcoder(endp);
Holger Hans Peter Freythercd256952012-12-07 15:04:07 +0100760 return create_response_with_sdp(endp, "CRCX", p->trans);
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100761error2:
Holger Hans Peter Freyther411764b2010-08-06 07:05:13 +0800762 mgcp_free_endp(endp);
Holger Hans Peter Freyther02c7a6f2010-02-03 09:13:10 +0100763 LOGP(DMGCP, LOGL_NOTICE, "Resource error on 0x%x\n", ENDPOINT_NUMBER(endp));
Holger Hans Peter Freythercd256952012-12-07 15:04:07 +0100764 return create_err_response(endp, error_code, "CRCX", p->trans);
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100765}
766
Holger Hans Peter Freythercd256952012-12-07 15:04:07 +0100767static struct msgb *handle_modify_con(struct mgcp_parse_data *p)
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100768{
Holger Hans Peter Freythercd256952012-12-07 15:04:07 +0100769 struct mgcp_endpoint *endp = p->endp;
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100770 int error_code = 500;
Holger Hans Peter Freythere077c912010-04-22 11:58:13 +0800771 int silent = 0;
Holger Hans Peter Freythercd256952012-12-07 15:04:07 +0100772 char *line;
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100773
Holger Hans Peter Freythercd256952012-12-07 15:04:07 +0100774 if (p->found != 0)
775 return create_err_response(NULL, 510, "MDCX", p->trans);
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100776
Holger Hans Peter Freythercd256952012-12-07 15:04:07 +0100777 if (endp->ci == CI_UNUSED) {
778 LOGP(DMGCP, LOGL_ERROR, "Endpoint is not "
779 "holding a connection. 0x%x\n", ENDPOINT_NUMBER(endp));
780 return create_err_response(endp, 400, "MDCX", p->trans);
781 }
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100782
Jacob Erlbeck9cec6672013-11-29 13:43:46 +0100783 for_each_line(line, p->save) {
Harald Welteec4f01b2012-01-27 12:31:36 +0100784 switch (line[0]) {
785 case 'C': {
786 if (verify_call_id(endp, line + 3) != 0)
787 goto error3;
788 break;
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100789 }
Harald Welteec4f01b2012-01-27 12:31:36 +0100790 case 'I': {
791 if (verify_ci(endp, line + 3) != 0)
792 goto error3;
793 break;
794 }
795 case 'L':
796 /* skip */
797 break;
798 case 'M':
799 if (parse_conn_mode(line + 3, &endp->conn_mode) != 0) {
800 error_code = 517;
801 goto error3;
802 }
803 endp->orig_mode = endp->conn_mode;
804 break;
805 case 'Z':
806 silent = strcmp("noanswer", line + 3) == 0;
807 break;
808 case '\0':
809 /* SDP file begins */
Jacob Erlbeck9cec6672013-11-29 13:43:46 +0100810 parse_sdp_data(&endp->net_end, p);
811 /* This will exhaust p->save, so the loop will
812 * terminate next time.
813 */
Harald Welteec4f01b2012-01-27 12:31:36 +0100814 break;
Harald Welteec4f01b2012-01-27 12:31:36 +0100815 default:
Jacob Erlbeck9cec6672013-11-29 13:43:46 +0100816 LOGP(DMGCP, LOGL_NOTICE, "Unhandled MGCP option: '%c'/%d on 0x%x\n",
Harald Welteec4f01b2012-01-27 12:31:36 +0100817 line[0], line[0], ENDPOINT_NUMBER(endp));
818 break;
819 }
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100820 }
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100821
Holger Hans Peter Freyther7a8ff2a2010-02-26 13:37:05 +0100822 /* policy CB */
Holger Hans Peter Freythercd256952012-12-07 15:04:07 +0100823 if (p->cfg->policy_cb) {
824 int rc;
825 rc = p->cfg->policy_cb(endp->tcfg, ENDPOINT_NUMBER(endp),
826 MGCP_ENDP_MDCX, p->trans);
827 switch (rc) {
Holger Hans Peter Freyther7a8ff2a2010-02-26 13:37:05 +0100828 case MGCP_POLICY_REJECT:
829 LOGP(DMGCP, LOGL_NOTICE, "MDCX rejected by policy on 0x%x\n",
830 ENDPOINT_NUMBER(endp));
Holger Hans Peter Freythere077c912010-04-22 11:58:13 +0800831 if (silent)
832 goto out_silent;
Holger Hans Peter Freythercd256952012-12-07 15:04:07 +0100833 return create_err_response(endp, 400, "MDCX", p->trans);
Holger Hans Peter Freyther7a8ff2a2010-02-26 13:37:05 +0100834 break;
835 case MGCP_POLICY_DEFER:
836 /* stop processing */
837 return NULL;
838 break;
839 case MGCP_POLICY_CONT:
840 /* just continue */
841 break;
842 }
843 }
844
Jacob Erlbecke5546cd2013-12-03 14:43:34 +0100845 mgcp_rtp_end_config(endp, 1, &endp->net_end);
846 mgcp_rtp_end_config(endp, 1, &endp->bts_end);
847
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100848 /* modify */
Holger Hans Peter Freyther73d00472010-08-06 20:22:23 +0800849 LOGP(DMGCP, LOGL_DEBUG, "Modified endpoint on: 0x%x Server: %s:%u\n",
Holger Hans Peter Freytherfab76aa2010-08-05 01:34:51 +0800850 ENDPOINT_NUMBER(endp), inet_ntoa(endp->net_end.addr), ntohs(endp->net_end.rtp_port));
Holger Hans Peter Freythercd256952012-12-07 15:04:07 +0100851 if (p->cfg->change_cb)
852 p->cfg->change_cb(endp->tcfg, ENDPOINT_NUMBER(endp), MGCP_ENDP_MDCX);
Holger Hans Peter Freythere077c912010-04-22 11:58:13 +0800853 if (silent)
854 goto out_silent;
855
Holger Hans Peter Freythercd256952012-12-07 15:04:07 +0100856 return create_response_with_sdp(endp, "MDCX", p->trans);
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100857
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100858error3:
Holger Hans Peter Freythercd256952012-12-07 15:04:07 +0100859 return create_err_response(endp, error_code, "MDCX", p->trans);
Holger Hans Peter Freythere077c912010-04-22 11:58:13 +0800860
861
862out_silent:
863 return NULL;
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100864}
865
Holger Hans Peter Freythercd256952012-12-07 15:04:07 +0100866static struct msgb *handle_delete_con(struct mgcp_parse_data *p)
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100867{
Holger Hans Peter Freythercd256952012-12-07 15:04:07 +0100868 struct mgcp_endpoint *endp = p->endp;
Holger Hans Peter Freyther94ed60f2010-08-08 16:24:48 +0800869 int error_code = 400;
Holger Hans Peter Freythere077c912010-04-22 11:58:13 +0800870 int silent = 0;
Holger Hans Peter Freythercd256952012-12-07 15:04:07 +0100871 char *line;
Holger Hans Peter Freyther8fc6d082012-09-14 17:18:12 +0200872 char stats[1048];
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100873
Holger Hans Peter Freythercd256952012-12-07 15:04:07 +0100874 if (p->found != 0)
875 return create_err_response(NULL, error_code, "DLCX", p->trans);
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100876
Holger Hans Peter Freythercd256952012-12-07 15:04:07 +0100877 if (!p->endp->allocated) {
878 LOGP(DMGCP, LOGL_ERROR, "Endpoint is not used. 0x%x\n",
879 ENDPOINT_NUMBER(endp));
880 return create_err_response(endp, 400, "DLCX", p->trans);
881 }
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100882
Jacob Erlbeck9cec6672013-11-29 13:43:46 +0100883 for_each_line(line, p->save) {
Harald Welteec4f01b2012-01-27 12:31:36 +0100884 switch (line[0]) {
885 case 'C':
886 if (verify_call_id(endp, line + 3) != 0)
887 goto error3;
888 break;
889 case 'I':
890 if (verify_ci(endp, line + 3) != 0)
891 goto error3;
892 break;
893 case 'Z':
894 silent = strcmp("noanswer", line + 3) == 0;
895 break;
896 default:
897 LOGP(DMGCP, LOGL_NOTICE, "Unhandled option: '%c'/%d on 0x%x\n",
898 line[0], line[0], ENDPOINT_NUMBER(endp));
899 break;
900 }
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100901 }
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100902
Holger Hans Peter Freyther7a8ff2a2010-02-26 13:37:05 +0100903 /* policy CB */
Holger Hans Peter Freythercd256952012-12-07 15:04:07 +0100904 if (p->cfg->policy_cb) {
905 int rc;
906 rc = p->cfg->policy_cb(endp->tcfg, ENDPOINT_NUMBER(endp),
907 MGCP_ENDP_DLCX, p->trans);
908 switch (rc) {
Holger Hans Peter Freyther7a8ff2a2010-02-26 13:37:05 +0100909 case MGCP_POLICY_REJECT:
910 LOGP(DMGCP, LOGL_NOTICE, "DLCX rejected by policy on 0x%x\n",
911 ENDPOINT_NUMBER(endp));
Holger Hans Peter Freythere077c912010-04-22 11:58:13 +0800912 if (silent)
913 goto out_silent;
Holger Hans Peter Freythercd256952012-12-07 15:04:07 +0100914 return create_err_response(endp, 400, "DLCX", p->trans);
Holger Hans Peter Freyther7a8ff2a2010-02-26 13:37:05 +0100915 break;
916 case MGCP_POLICY_DEFER:
917 /* stop processing */
Holger Hans Peter Freyther017738d2010-09-18 06:35:29 +0800918 delete_transcoder(endp);
Holger Hans Peter Freyther7a8ff2a2010-02-26 13:37:05 +0100919 return NULL;
920 break;
921 case MGCP_POLICY_CONT:
922 /* just continue */
923 break;
924 }
925 }
926
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100927 /* free the connection */
Holger Hans Peter Freyther73d00472010-08-06 20:22:23 +0800928 LOGP(DMGCP, LOGL_DEBUG, "Deleted endpoint on: 0x%x Server: %s:%u\n",
Holger Hans Peter Freytherfab76aa2010-08-05 01:34:51 +0800929 ENDPOINT_NUMBER(endp), inet_ntoa(endp->net_end.addr), ntohs(endp->net_end.rtp_port));
Holger Hans Peter Freyther017738d2010-09-18 06:35:29 +0800930
Holger Hans Peter Freyther8fc6d082012-09-14 17:18:12 +0200931 /* save the statistics of the current call */
932 mgcp_format_stats(endp, stats, sizeof(stats));
933
Holger Hans Peter Freyther017738d2010-09-18 06:35:29 +0800934 delete_transcoder(endp);
Holger Hans Peter Freyther64dcbe22010-02-26 13:27:51 +0100935 mgcp_free_endp(endp);
Holger Hans Peter Freythercd256952012-12-07 15:04:07 +0100936 if (p->cfg->change_cb)
937 p->cfg->change_cb(endp->tcfg, ENDPOINT_NUMBER(endp), MGCP_ENDP_DLCX);
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100938
Holger Hans Peter Freythere077c912010-04-22 11:58:13 +0800939 if (silent)
940 goto out_silent;
Holger Hans Peter Freythercd256952012-12-07 15:04:07 +0100941 return create_ok_resp_with_param(endp, 250, "DLCX", p->trans, stats);
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100942
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100943error3:
Holger Hans Peter Freythercd256952012-12-07 15:04:07 +0100944 return create_err_response(endp, error_code, "DLCX", p->trans);
Holger Hans Peter Freythere077c912010-04-22 11:58:13 +0800945
946out_silent:
947 return NULL;
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +0100948}
949
Holger Hans Peter Freythercd256952012-12-07 15:04:07 +0100950static struct msgb *handle_rsip(struct mgcp_parse_data *p)
Holger Hans Peter Freytherd60c6e52010-03-31 06:39:35 +0200951{
Holger Hans Peter Freythercd256952012-12-07 15:04:07 +0100952 if (p->found != 0) {
Holger Hans Peter Freyther26bd8482011-06-10 00:04:55 +0200953 LOGP(DMGCP, LOGL_ERROR, "Failed to find the endpoint.\n");
954 return NULL;
955 }
956
Holger Hans Peter Freythercd256952012-12-07 15:04:07 +0100957 if (p->cfg->reset_cb)
958 p->cfg->reset_cb(p->endp->tcfg);
Holger Hans Peter Freytherd60c6e52010-03-31 06:39:35 +0200959 return NULL;
960}
961
Holger Hans Peter Freyther46880c22012-11-29 12:54:22 +0100962static char extract_tone(const char *line)
963{
964 const char *str = strstr(line, "D/");
965 if (!str)
966 return CHAR_MAX;
967
968 return str[2];
969}
970
Holger Hans Peter Freytherac0968e2011-01-25 23:33:54 +0100971/*
972 * This can request like DTMF detection and forward, fax detection... it
973 * can also request when the notification should be send and such. We don't
974 * do this right now.
975 */
Holger Hans Peter Freythercd256952012-12-07 15:04:07 +0100976static struct msgb *handle_noti_req(struct mgcp_parse_data *p)
Holger Hans Peter Freytherac0968e2011-01-25 23:33:54 +0100977{
Holger Hans Peter Freythercd256952012-12-07 15:04:07 +0100978 int res = 0;
979 char *line;
Holger Hans Peter Freythera2297482013-05-21 17:04:35 +0200980 char tone = CHAR_MAX;
Holger Hans Peter Freytherac0968e2011-01-25 23:33:54 +0100981
Holger Hans Peter Freythercd256952012-12-07 15:04:07 +0100982 if (p->found != 0)
983 return create_err_response(NULL, 400, "RQNT", p->trans);
Holger Hans Peter Freytherac0968e2011-01-25 23:33:54 +0100984
Jacob Erlbeck9cec6672013-11-29 13:43:46 +0100985 for_each_line(line, p->save) {
Holger Hans Peter Freyther46880c22012-11-29 12:54:22 +0100986 switch (line[0]) {
987 case 'S':
988 tone = extract_tone(line);
989 break;
990 }
Holger Hans Peter Freytherac0968e2011-01-25 23:33:54 +0100991 }
Holger Hans Peter Freyther46880c22012-11-29 12:54:22 +0100992
993 /* we didn't see a signal request with a tone */
994 if (tone == CHAR_MAX)
Holger Hans Peter Freythercd256952012-12-07 15:04:07 +0100995 return create_ok_response(p->endp, 200, "RQNT", p->trans);
Holger Hans Peter Freyther46880c22012-11-29 12:54:22 +0100996
Holger Hans Peter Freythercd256952012-12-07 15:04:07 +0100997 if (p->cfg->rqnt_cb)
998 res = p->cfg->rqnt_cb(p->endp, tone);
Holger Hans Peter Freyther46880c22012-11-29 12:54:22 +0100999
1000 return res == 0 ?
Holger Hans Peter Freythercd256952012-12-07 15:04:07 +01001001 create_ok_response(p->endp, 200, "RQNT", p->trans) :
1002 create_err_response(p->endp, res, "RQNT", p->trans);
Holger Hans Peter Freytherac0968e2011-01-25 23:33:54 +01001003}
1004
Holger Hans Peter Freyther6f38c062010-02-20 21:21:02 +01001005struct mgcp_config *mgcp_config_alloc(void)
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +01001006{
Holger Hans Peter Freyther6f38c062010-02-20 21:21:02 +01001007 struct mgcp_config *cfg;
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +01001008
Holger Hans Peter Freyther6f38c062010-02-20 21:21:02 +01001009 cfg = talloc_zero(NULL, struct mgcp_config);
1010 if (!cfg) {
1011 LOGP(DMGCP, LOGL_FATAL, "Failed to allocate config.\n");
1012 return NULL;
1013 }
1014
1015 cfg->source_port = 2427;
1016 cfg->source_addr = talloc_strdup(cfg, "0.0.0.0");
Holger Hans Peter Freytherab56ce12011-02-28 00:56:17 +01001017
Holger Hans Peter Freytherd582b202010-09-19 04:21:39 +08001018 cfg->transcoder_remote_base = 4000;
Holger Hans Peter Freyther2ea91182010-08-05 07:10:56 +08001019
1020 cfg->bts_ports.base_port = RTP_PORT_DEFAULT;
1021 cfg->net_ports.base_port = RTP_PORT_NET_DEFAULT;
Holger Hans Peter Freyther6f38c062010-02-20 21:21:02 +01001022
Holger Hans Peter Freytherab56ce12011-02-28 00:56:17 +01001023 /* default trunk handling */
1024 cfg->trunk.cfg = cfg;
1025 cfg->trunk.trunk_nr = 0;
1026 cfg->trunk.trunk_type = MGCP_TRUNK_VIRTUAL;
1027 cfg->trunk.audio_name = talloc_strdup(cfg, "AMR/8000");
1028 cfg->trunk.audio_payload = 126;
Holger Hans Peter Freyther51ade842012-05-11 13:00:45 +02001029 cfg->trunk.omit_rtcp = 0;
Holger Hans Peter Freytherab56ce12011-02-28 00:56:17 +01001030
Holger Hans Peter Freyther06bfe792011-02-28 12:11:02 +01001031 INIT_LLIST_HEAD(&cfg->trunks);
1032
Holger Hans Peter Freyther6f38c062010-02-20 21:21:02 +01001033 return cfg;
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +01001034}
1035
Holger Hans Peter Freyther06bfe792011-02-28 12:11:02 +01001036struct mgcp_trunk_config *mgcp_trunk_alloc(struct mgcp_config *cfg, int nr)
1037{
1038 struct mgcp_trunk_config *trunk;
1039
1040 trunk = talloc_zero(cfg, struct mgcp_trunk_config);
1041 if (!trunk) {
1042 LOGP(DMGCP, LOGL_ERROR, "Failed to allocate.\n");
1043 return NULL;
1044 }
1045
1046 trunk->cfg = cfg;
1047 trunk->trunk_type = MGCP_TRUNK_E1;
1048 trunk->trunk_nr = nr;
1049 trunk->audio_name = talloc_strdup(cfg, "AMR/8000");
1050 trunk->audio_payload = 126;
1051 trunk->number_endpoints = 33;
Holger Hans Peter Freyther51ade842012-05-11 13:00:45 +02001052 trunk->omit_rtcp = 0;
Holger Hans Peter Freyther06bfe792011-02-28 12:11:02 +01001053 llist_add_tail(&trunk->entry, &cfg->trunks);
1054 return trunk;
1055}
1056
1057struct mgcp_trunk_config *mgcp_trunk_num(struct mgcp_config *cfg, int index)
1058{
1059 struct mgcp_trunk_config *trunk;
1060
1061 llist_for_each_entry(trunk, &cfg->trunks, entry)
1062 if (trunk->trunk_nr == index)
1063 return trunk;
1064
1065 return NULL;
1066}
1067
Holger Hans Peter Freytherfab76aa2010-08-05 01:34:51 +08001068static void mgcp_rtp_end_reset(struct mgcp_rtp_end *end)
1069{
Holger Hans Peter Freyther6f94bac2010-11-02 19:06:13 +01001070 if (end->local_alloc == PORT_ALLOC_DYNAMIC) {
Holger Hans Peter Freyther05d8f5f2010-08-05 08:08:17 +08001071 mgcp_free_rtp_port(end);
Holger Hans Peter Freyther6f94bac2010-11-02 19:06:13 +01001072 end->local_port = 0;
1073 }
Holger Hans Peter Freyther05d8f5f2010-08-05 08:08:17 +08001074
Holger Hans Peter Freytherbfb68b72010-08-05 03:37:22 +08001075 end->packets = 0;
Holger Hans Peter Freyther3e456102012-09-12 11:38:37 +02001076 end->octets = 0;
Holger Hans Peter Freytherbfb68b72010-08-05 03:37:22 +08001077 memset(&end->addr, 0, sizeof(end->addr));
Holger Hans Peter Freyther6f94bac2010-11-02 19:06:13 +01001078 end->rtp_port = end->rtcp_port = 0;
Holger Hans Peter Freytherfab76aa2010-08-05 01:34:51 +08001079 end->payload_type = -1;
Holger Hans Peter Freyther05d8f5f2010-08-05 08:08:17 +08001080 end->local_alloc = -1;
Holger Hans Peter Freyther4928d1b2012-09-03 00:07:39 +02001081 talloc_free(end->fmtp_extra);
1082 end->fmtp_extra = NULL;
Jacob Erlbeckac9f6ce2013-11-25 15:23:35 +01001083
1084 /* Set default values */
1085 end->frame_duration_num = DEFAULT_RTP_AUDIO_FRAME_DUR_NUM;
1086 end->frame_duration_den = DEFAULT_RTP_AUDIO_FRAME_DUR_DEN;
1087 end->frames_per_packet = DEFAULT_RTP_AUDIO_FRAMES_PER_PACKET;
1088 end->rate = DEFAULT_RTP_AUDIO_DEFAULT_RATE;
Holger Hans Peter Freytherfab76aa2010-08-05 01:34:51 +08001089}
1090
Holger Hans Peter Freytherbfb68b72010-08-05 03:37:22 +08001091static void mgcp_rtp_end_init(struct mgcp_rtp_end *end)
1092{
1093 mgcp_rtp_end_reset(end);
1094 end->rtp.fd = -1;
1095 end->rtcp.fd = -1;
1096}
1097
Holger Hans Peter Freyther49e170b2011-02-28 14:37:03 +01001098int mgcp_endpoints_allocate(struct mgcp_trunk_config *tcfg)
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +01001099{
1100 int i;
1101
Holger Hans Peter Freyther6f38c062010-02-20 21:21:02 +01001102 /* Initialize all endpoints */
Holger Hans Peter Freyther49e170b2011-02-28 14:37:03 +01001103 tcfg->endpoints = _talloc_zero_array(tcfg->cfg,
Holger Hans Peter Freyther6f38c062010-02-20 21:21:02 +01001104 sizeof(struct mgcp_endpoint),
Holger Hans Peter Freytherab56ce12011-02-28 00:56:17 +01001105 tcfg->number_endpoints, "endpoints");
1106 if (!tcfg->endpoints)
Holger Hans Peter Freyther6f38c062010-02-20 21:21:02 +01001107 return -1;
1108
Holger Hans Peter Freytherab56ce12011-02-28 00:56:17 +01001109 for (i = 0; i < tcfg->number_endpoints; ++i) {
1110 tcfg->endpoints[i].ci = CI_UNUSED;
Holger Hans Peter Freyther49e170b2011-02-28 14:37:03 +01001111 tcfg->endpoints[i].cfg = tcfg->cfg;
Holger Hans Peter Freytherab56ce12011-02-28 00:56:17 +01001112 tcfg->endpoints[i].tcfg = tcfg;
1113 mgcp_rtp_end_init(&tcfg->endpoints[i].net_end);
1114 mgcp_rtp_end_init(&tcfg->endpoints[i].bts_end);
1115 mgcp_rtp_end_init(&tcfg->endpoints[i].trans_net);
1116 mgcp_rtp_end_init(&tcfg->endpoints[i].trans_bts);
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +01001117 }
1118
Holger Hans Peter Freyther26143c82010-02-03 08:50:33 +01001119 return 0;
1120}
Holger Hans Peter Freyther64dcbe22010-02-26 13:27:51 +01001121
1122void mgcp_free_endp(struct mgcp_endpoint *endp)
1123{
Holger Hans Peter Freyther62d3bb72010-03-31 12:31:09 +02001124 LOGP(DMGCP, LOGL_DEBUG, "Deleting endpoint on: 0x%x\n", ENDPOINT_NUMBER(endp));
Holger Hans Peter Freytherfd93fc02010-08-03 15:01:43 +00001125 endp->ci = CI_UNUSED;
Holger Hans Peter Freythere15223b2010-08-06 18:03:11 +08001126 endp->allocated = 0;
Holger Hans Peter Freyther64dcbe22010-02-26 13:27:51 +01001127
Holger Hans Peter Freythere9564b22012-12-07 11:52:16 +01001128 talloc_free(endp->callid);
1129 endp->callid = NULL;
Holger Hans Peter Freyther64dcbe22010-02-26 13:27:51 +01001130
Holger Hans Peter Freythere9564b22012-12-07 11:52:16 +01001131 talloc_free(endp->local_options);
1132 endp->local_options = NULL;
Holger Hans Peter Freyther64dcbe22010-02-26 13:27:51 +01001133
Holger Hans Peter Freytherfab76aa2010-08-05 01:34:51 +08001134 mgcp_rtp_end_reset(&endp->bts_end);
1135 mgcp_rtp_end_reset(&endp->net_end);
Holger Hans Peter Freytherb6345ab2010-11-01 20:53:31 +01001136 mgcp_rtp_end_reset(&endp->trans_net);
Holger Hans Peter Freytherc983f832010-11-01 21:04:54 +01001137 mgcp_rtp_end_reset(&endp->trans_bts);
Pablo Neira Ayusoa3f26c02013-07-08 05:09:46 +02001138 endp->type = MGCP_RTP_DEFAULT;
Holger Hans Peter Freythere758d952010-07-29 02:38:39 +08001139
Holger Hans Peter Freyther84ba5282010-08-03 11:59:04 +00001140 memset(&endp->net_state, 0, sizeof(endp->net_state));
1141 memset(&endp->bts_state, 0, sizeof(endp->bts_state));
Holger Hans Peter Freytherb33ded12010-08-03 02:57:02 +08001142
1143 endp->conn_mode = endp->orig_mode = MGCP_CONN_NONE;
Holger Hans Peter Freyther8fdb95e2010-08-06 01:12:21 +08001144
1145 memset(&endp->taps, 0, sizeof(endp->taps));
Holger Hans Peter Freyther64dcbe22010-02-26 13:27:51 +01001146}
Holger Hans Peter Freyther017738d2010-09-18 06:35:29 +08001147
Holger Hans Peter Freyther1adedbb2010-09-19 04:39:55 +08001148static int send_trans(struct mgcp_config *cfg, const char *buf, int len)
1149{
1150 struct sockaddr_in addr;
1151
1152 memset(&addr, 0, sizeof(addr));
1153 addr.sin_family = AF_INET;
1154 addr.sin_addr = cfg->transcoder_in;
1155 addr.sin_port = htons(2427);
1156 return sendto(cfg->gw_fd.bfd.fd, buf, len, 0,
1157 (struct sockaddr *) &addr, sizeof(addr));
1158}
1159
Holger Hans Peter Freyther017738d2010-09-18 06:35:29 +08001160static void send_msg(struct mgcp_endpoint *endp, int endpoint, int port,
1161 const char *msg, const char *mode)
1162{
Holger Hans Peter Freyther017738d2010-09-18 06:35:29 +08001163 char buf[2096];
1164 int len;
1165
1166 /* hardcoded to AMR right now, we do not know the real type at this point */
1167 len = snprintf(buf, sizeof(buf),
1168 "%s 42 %x@mgw MGCP 1.0\r\n"
1169 "C: 4256\r\n"
1170 "M: %s\r\n"
1171 "\r\n"
1172 "c=IN IP4 %s\r\n"
1173 "m=audio %d RTP/AVP %d\r\n"
1174 "a=rtpmap:%d %s\r\n",
1175 msg, endpoint, mode, endp->cfg->source_addr,
Holger Hans Peter Freytherab56ce12011-02-28 00:56:17 +01001176 port, endp->tcfg->audio_payload,
1177 endp->tcfg->audio_payload, endp->tcfg->audio_name);
Holger Hans Peter Freyther017738d2010-09-18 06:35:29 +08001178
1179 if (len < 0)
1180 return;
1181
1182 buf[sizeof(buf) - 1] = '\0';
1183
Holger Hans Peter Freyther1adedbb2010-09-19 04:39:55 +08001184 send_trans(endp->cfg, buf, len);
Holger Hans Peter Freyther017738d2010-09-18 06:35:29 +08001185}
1186
1187static void send_dlcx(struct mgcp_endpoint *endp, int endpoint)
1188{
Holger Hans Peter Freyther017738d2010-09-18 06:35:29 +08001189 char buf[2096];
1190 int len;
1191
1192 len = snprintf(buf, sizeof(buf),
1193 "DLCX 43 %x@mgw MGCP 1.0\r\n"
1194 "C: 4256\r\n"
1195 , endpoint);
1196
1197 if (len < 0)
1198 return;
1199
1200 buf[sizeof(buf) - 1] = '\0';
1201
Holger Hans Peter Freyther1adedbb2010-09-19 04:39:55 +08001202 send_trans(endp->cfg, buf, len);
Holger Hans Peter Freyther017738d2010-09-18 06:35:29 +08001203}
1204
Harald Welteba4f8b22012-01-27 00:41:39 +01001205static int send_agent(struct mgcp_config *cfg, const char *buf, int len)
1206{
1207 return write(cfg->gw_fd.bfd.fd, buf, len);
1208}
1209
1210int mgcp_send_reset_all(struct mgcp_config *cfg)
1211{
1212 static const char mgcp_reset[] = {
1213 "RSIP 1 *@mgw MGCP 1.0\r\n"
1214 };
1215
1216 return send_agent(cfg, mgcp_reset, sizeof mgcp_reset -1);
1217}
1218
1219int mgcp_send_reset_ep(struct mgcp_endpoint *endp, int endpoint)
1220{
1221 char buf[128];
1222 int len;
1223
1224 len = snprintf(buf, sizeof(buf),
1225 "RSIP 39 %x@mgw MGCP 1.0\r\n"
1226 , endpoint);
1227 if (len < 0)
1228 return len;
1229
1230 buf[sizeof(buf) - 1] = '\0';
1231
1232 return send_agent(endp->cfg, buf, len);
1233}
1234
Holger Hans Peter Freyther017738d2010-09-18 06:35:29 +08001235static void create_transcoder(struct mgcp_endpoint *endp)
1236{
1237 int port;
1238 int in_endp = ENDPOINT_NUMBER(endp);
Holger Hans Peter Freytherc983f832010-11-01 21:04:54 +01001239 int out_endp = endp_back_channel(in_endp);
Holger Hans Peter Freyther017738d2010-09-18 06:35:29 +08001240
Pablo Neira Ayusoa3f26c02013-07-08 05:09:46 +02001241 if (endp->type != MGCP_RTP_TRANSCODED)
Holger Hans Peter Freyther017738d2010-09-18 06:35:29 +08001242 return;
1243
Holger Hans Peter Freytherc9e3bc62010-11-01 22:38:25 +01001244 send_msg(endp, in_endp, endp->trans_bts.local_port, "CRCX", "sendrecv");
1245 send_msg(endp, in_endp, endp->trans_bts.local_port, "MDCX", "sendrecv");
Holger Hans Peter Freytherb6345ab2010-11-01 20:53:31 +01001246 send_msg(endp, out_endp, endp->trans_net.local_port, "CRCX", "sendrecv");
1247 send_msg(endp, out_endp, endp->trans_net.local_port, "MDCX", "sendrecv");
Holger Hans Peter Freyther017738d2010-09-18 06:35:29 +08001248
Holger Hans Peter Freytherc983f832010-11-01 21:04:54 +01001249 port = rtp_calculate_port(in_endp, endp->cfg->transcoder_remote_base);
1250 endp->trans_bts.rtp_port = htons(port);
1251 endp->trans_bts.rtcp_port = htons(port + 1);
1252
Holger Hans Peter Freytherd582b202010-09-19 04:21:39 +08001253 port = rtp_calculate_port(out_endp, endp->cfg->transcoder_remote_base);
Holger Hans Peter Freytherb6345ab2010-11-01 20:53:31 +01001254 endp->trans_net.rtp_port = htons(port);
1255 endp->trans_net.rtcp_port = htons(port + 1);
Holger Hans Peter Freyther017738d2010-09-18 06:35:29 +08001256}
1257
1258static void delete_transcoder(struct mgcp_endpoint *endp)
1259{
1260 int in_endp = ENDPOINT_NUMBER(endp);
Holger Hans Peter Freytherc983f832010-11-01 21:04:54 +01001261 int out_endp = endp_back_channel(in_endp);
Holger Hans Peter Freyther017738d2010-09-18 06:35:29 +08001262
Pablo Neira Ayusoa3f26c02013-07-08 05:09:46 +02001263 if (endp->type != MGCP_RTP_TRANSCODED)
Holger Hans Peter Freyther017738d2010-09-18 06:35:29 +08001264 return;
1265
1266 send_dlcx(endp, in_endp);
1267 send_dlcx(endp, out_endp);
1268}
Holger Hans Peter Freytherf8fd1062010-09-19 04:36:07 +08001269
1270int mgcp_reset_transcoder(struct mgcp_config *cfg)
1271{
Holger Hans Peter Freytherf8fd1062010-09-19 04:36:07 +08001272 if (!cfg->transcoder_ip)
Holger Hans Peter Freytherbafc9872010-09-24 04:41:28 +08001273 return 0;
Holger Hans Peter Freytherf8fd1062010-09-19 04:36:07 +08001274
1275 static const char mgcp_reset[] = {
1276 "RSIP 1 13@mgw MGCP 1.0\r\n"
1277 };
1278
Holger Hans Peter Freyther1adedbb2010-09-19 04:39:55 +08001279 return send_trans(cfg, mgcp_reset, sizeof mgcp_reset -1);
Holger Hans Peter Freytherf8fd1062010-09-19 04:36:07 +08001280}
Holger Hans Peter Freyther8fc6d082012-09-14 17:18:12 +02001281
1282void mgcp_format_stats(struct mgcp_endpoint *endp, char *msg, size_t size)
1283{
Holger Hans Peter Freyther8c87a482012-10-24 21:22:47 +02001284 uint32_t expected, jitter;
Holger Hans Peter Freytherfaa67932012-10-22 18:09:35 +02001285 int ploss;
Jacob Erlbecka2528da2013-11-25 12:53:28 +01001286 int nchars;
Holger Hans Peter Freytherfaa67932012-10-22 18:09:35 +02001287 mgcp_state_calc_loss(&endp->net_state, &endp->net_end,
1288 &expected, &ploss);
Holger Hans Peter Freyther8c87a482012-10-24 21:22:47 +02001289 jitter = mgcp_state_calc_jitter(&endp->net_state);
Holger Hans Peter Freytherfaa67932012-10-22 18:09:35 +02001290
Jacob Erlbecka2528da2013-11-25 12:53:28 +01001291 nchars = snprintf(msg, size,
1292 "\r\nP: PS=%u, OS=%u, PR=%u, OR=%u, PL=%d, JI=%u",
1293 endp->bts_end.packets, endp->bts_end.octets,
1294 endp->net_end.packets, endp->net_end.octets,
1295 ploss, jitter);
1296 if (nchars < 0 || nchars >= size)
1297 goto truncate;
1298
1299 msg += nchars;
1300 size -= nchars;
1301
1302 /* Error Counter */
1303 snprintf(msg, size,
1304 "\r\nX-Osmo-CP: EC TIS=%u, TOS=%u, TIR=%u, TOR=%u",
1305 endp->net_state.in_stream.err_ts_counter,
1306 endp->net_state.out_stream.err_ts_counter,
1307 endp->bts_state.in_stream.err_ts_counter,
1308 endp->bts_state.out_stream.err_ts_counter);
1309truncate:
Holger Hans Peter Freyther8fc6d082012-09-14 17:18:12 +02001310 msg[size - 1] = '\0';
1311}
Holger Hans Peter Freyther931d6982012-10-24 21:53:40 +02001312
1313int mgcp_parse_stats(struct msgb *msg, uint32_t *ps, uint32_t *os,
1314 uint32_t *pr, uint32_t *_or, int *loss, uint32_t *jitter)
1315{
1316 char *line, *save;
1317 int rc;
1318
1319 /* initialize with bad values */
1320 *ps = *os = *pr = *_or = *jitter = UINT_MAX;
1321 *loss = INT_MAX;
1322
1323
1324 line = strtok_r((char *) msg->l2h, "\r\n", &save);
1325 if (!line)
1326 return -1;
1327
1328 /* this can only parse the message that is created above... */
Jacob Erlbeck7a6510c2013-11-29 13:43:43 +01001329 for_each_non_empty_line(line, save) {
Holger Hans Peter Freyther931d6982012-10-24 21:53:40 +02001330 switch (line[0]) {
1331 case 'P':
1332 rc = sscanf(line, "P: PS=%u, OS=%u, PR=%u, OR=%u, PL=%d, JI=%u",
1333 ps, os, pr, _or, loss, jitter);
1334 return rc == 6 ? 0 : -1;
1335 }
1336 }
1337
1338 return -1;
1339}