blob: 719a4c743523cc841ecc5196219bb3e069702462 [file] [log] [blame]
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +01001/* A Media Gateway Control Protocol Media Gateway: RFC 3435 */
2/* The protocol implementation */
3
4/*
Holger Hans Peter Freyther6adac172011-01-06 16:19:55 +01005 * (C) 2009-2011 by Holger Hans Peter Freyther <zecke@selfish.org>
6 * (C) 2009-2011 by On-Waves
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +01007 * All Rights Reserved
8 *
9 * This program is free software; you can redistribute it and/or modify
Harald Welte9af6ddf2011-01-01 15:25:50 +010010 * it under the terms of the GNU Affero General Public License as published by
11 * the Free Software Foundation; either version 3 of the License, or
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +010012 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
Harald Welte9af6ddf2011-01-01 15:25:50 +010017 * GNU Affero General Public License for more details.
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +010018 *
Harald Welte9af6ddf2011-01-01 15:25:50 +010019 * You should have received a copy of the GNU Affero General Public License
20 * along with this program. If not, see <http://www.gnu.org/licenses/>.
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +010021 *
22 */
23
24#include <ctype.h>
25#include <stdio.h>
26#include <stdlib.h>
27#include <string.h>
28#include <time.h>
29#include <limits.h>
30#include <unistd.h>
31
Pablo Neira Ayuso136f4532011-03-22 16:47:59 +010032#include <osmocom/core/msgb.h>
33#include <osmocom/core/talloc.h>
34#include <osmocom/core/select.h>
Holger Hans Peter Freyther16b7f5c2011-02-28 22:06:47 +010035
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +010036#include <openbsc/mgcp.h>
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +010037#include <openbsc/mgcp_internal.h>
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +010038
Harald Welteae199722012-01-27 12:31:36 +010039#define for_each_line(input, line, save) \
40 for (line = strtok_r(input, "\r\n", &save); line; \
41 line = strtok_r(NULL, "\r\n", &save))
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +010042
Holger Hans Peter Freytherf138f912010-08-05 08:08:17 +080043static void mgcp_rtp_end_reset(struct mgcp_rtp_end *end);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +010044
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +010045struct mgcp_request {
46 char *name;
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +010047 struct msgb *(*handle_request) (struct mgcp_config *cfg, struct msgb *msg);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +010048 char *debug_name;
49};
50
51#define MGCP_REQUEST(NAME, REQ, DEBUG_NAME) \
52 { .name = NAME, .handle_request = REQ, .debug_name = DEBUG_NAME },
53
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +010054static struct msgb *handle_audit_endpoint(struct mgcp_config *cfg, struct msgb *msg);
55static struct msgb *handle_create_con(struct mgcp_config *cfg, struct msgb *msg);
56static struct msgb *handle_delete_con(struct mgcp_config *cfg, struct msgb *msg);
57static struct msgb *handle_modify_con(struct mgcp_config *cfg, struct msgb *msg);
Holger Hans Peter Freyther9bdcc9c2010-03-31 06:39:35 +020058static struct msgb *handle_rsip(struct mgcp_config *cfg, struct msgb *msg);
Holger Hans Peter Freyther6e94d6d2011-01-25 23:33:54 +010059static struct msgb *handle_noti_req(struct mgcp_config *cfg, struct msgb *msg);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +010060
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +080061static void create_transcoder(struct mgcp_endpoint *endp);
62static void delete_transcoder(struct mgcp_endpoint *endp);
63
Holger Hans Peter Freyther46340132010-08-06 08:26:54 +080064static uint32_t generate_call_id(struct mgcp_config *cfg)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +010065{
66 int i;
67
68 /* use the call id */
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +010069 ++cfg->last_call_id;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +010070
71 /* handle wrap around */
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +010072 if (cfg->last_call_id == CI_UNUSED)
73 ++cfg->last_call_id;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +010074
75 /* callstack can only be of size number_of_endpoints */
76 /* verify that the call id is free, e.g. in case of overrun */
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +010077 for (i = 1; i < cfg->trunk.number_endpoints; ++i)
78 if (cfg->trunk.endpoints[i].ci == cfg->last_call_id)
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +010079 return generate_call_id(cfg);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +010080
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +010081 return cfg->last_call_id;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +010082}
83
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +010084/*
85 * array of function pointers for handling various
86 * messages. In the future this might be binary sorted
87 * for performance reasons.
88 */
89static const struct mgcp_request mgcp_requests [] = {
90 MGCP_REQUEST("AUEP", handle_audit_endpoint, "AuditEndpoint")
91 MGCP_REQUEST("CRCX", handle_create_con, "CreateConnection")
92 MGCP_REQUEST("DLCX", handle_delete_con, "DeleteConnection")
93 MGCP_REQUEST("MDCX", handle_modify_con, "ModifiyConnection")
Holger Hans Peter Freyther6e94d6d2011-01-25 23:33:54 +010094 MGCP_REQUEST("RQNT", handle_noti_req, "NotificationRequest")
Holger Hans Peter Freyther9bdcc9c2010-03-31 06:39:35 +020095
96 /* SPEC extension */
97 MGCP_REQUEST("RSIP", handle_rsip, "ReSetInProgress")
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +010098};
99
Holger Hans Peter Freyther62e836c2010-02-03 11:03:45 +0100100static struct msgb *mgcp_msgb_alloc(void)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100101{
Holger Hans Peter Freyther62e836c2010-02-03 11:03:45 +0100102 struct msgb *msg;
103 msg = msgb_alloc_headroom(4096, 128, "MGCP msg");
104 if (!msg)
105 LOGP(DMGCP, LOGL_ERROR, "Failed to msgb for MGCP data.\n");
106
107 return msg;
108}
109
Holger Hans Peter Freyther6adac172011-01-06 16:19:55 +0100110struct msgb *mgcp_create_response_with_data(int code, const char *txt,
111 const char *msg, const char *trans,
112 const char *data)
Holger Hans Peter Freyther62e836c2010-02-03 11:03:45 +0100113{
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100114 int len;
Holger Hans Peter Freyther62e836c2010-02-03 11:03:45 +0100115 struct msgb *res;
116
117 res = mgcp_msgb_alloc();
118 if (!res)
119 return NULL;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100120
121 if (data) {
Holger Hans Peter Freyther6adac172011-01-06 16:19:55 +0100122 len = snprintf((char *) res->data, 2048, "%d %s%s\r\n%s", code, trans, txt, data);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100123 } else {
Holger Hans Peter Freyther6adac172011-01-06 16:19:55 +0100124 len = snprintf((char *) res->data, 2048, "%d %s%s\r\n", code, trans, txt);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100125 }
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100126
Holger Hans Peter Freyther62e836c2010-02-03 11:03:45 +0100127 res->l2h = msgb_put(res, len);
Holger Hans Peter Freyther63f2db22010-02-26 13:30:57 +0100128 LOGP(DMGCP, LOGL_DEBUG, "Sending response: code: %d for '%s'\n", code, res->l2h);
Holger Hans Peter Freyther62e836c2010-02-03 11:03:45 +0100129 return res;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100130}
131
Holger Hans Peter Freyther6adac172011-01-06 16:19:55 +0100132static struct msgb *create_ok_response(int code, const char *msg, const char *trans)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100133{
Holger Hans Peter Freyther6adac172011-01-06 16:19:55 +0100134 return mgcp_create_response_with_data(code, " OK", msg, trans, NULL);
135}
136
137static struct msgb *create_err_response(int code, const char *msg, const char *trans)
138{
139 return mgcp_create_response_with_data(code, " FAIL", msg, trans, NULL);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100140}
141
Holger Hans Peter Freyther8d188ed2010-02-21 01:44:08 +0100142static struct msgb *create_response_with_sdp(struct mgcp_endpoint *endp,
143 const char *msg, const char *trans_id)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100144{
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100145 const char *addr = endp->cfg->local_ip;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100146 char sdp_record[4096];
147
148 if (!addr)
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100149 addr = endp->cfg->source_addr;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100150
151 snprintf(sdp_record, sizeof(sdp_record) - 1,
Holger Hans Peter Freyther46340132010-08-06 08:26:54 +0800152 "I: %u\n\n"
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100153 "v=0\r\n"
Holger Hans Peter Freytherc7e49d32011-07-20 20:43:15 +0200154 "o=- %u 23 IN IP4 %s\r\n"
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100155 "c=IN IP4 %s\r\n"
Holger Hans Peter Freytherc7e49d32011-07-20 20:43:15 +0200156 "t=0 0\r\n"
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100157 "m=audio %d RTP/AVP %d\r\n"
158 "a=rtpmap:%d %s\r\n",
Holger Hans Peter Freytherc7e49d32011-07-20 20:43:15 +0200159 endp->ci, endp->ci, addr, addr,
160 endp->net_end.local_port, endp->bts_end.payload_type,
161 endp->bts_end.payload_type, endp->tcfg->audio_name);
Holger Hans Peter Freyther6adac172011-01-06 16:19:55 +0100162 return mgcp_create_response_with_data(200, " OK", msg, trans_id, sdp_record);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100163}
164
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100165/*
166 * handle incoming messages:
167 * - this can be a command (four letters, space, transaction id)
168 * - or a response (three numbers, space, transaction id)
169 */
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100170struct msgb *mgcp_handle_message(struct mgcp_config *cfg, struct msgb *msg)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100171{
172 int code;
Holger Hans Peter Freyther62e836c2010-02-03 11:03:45 +0100173 struct msgb *resp = NULL;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100174
Holger Hans Peter Freytherf36a11a2010-03-31 13:26:46 +0200175 if (msgb_l2len(msg) < 4) {
Holger Hans Peter Freyther2ada71d2010-02-03 09:13:10 +0100176 LOGP(DMGCP, LOGL_ERROR, "mgs too short: %d\n", msg->len);
Holger Hans Peter Freyther62e836c2010-02-03 11:03:45 +0100177 return NULL;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100178 }
179
180 /* attempt to treat it as a response */
Holger Hans Peter Freytherf36a11a2010-03-31 13:26:46 +0200181 if (sscanf((const char *)&msg->l2h[0], "%3d %*s", &code) == 1) {
Holger Hans Peter Freyther63f2db22010-02-26 13:30:57 +0100182 LOGP(DMGCP, LOGL_DEBUG, "Response: Code: %d\n", code);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100183 } else {
184 int i, handled = 0;
185 msg->l3h = &msg->l2h[4];
186 for (i = 0; i < ARRAY_SIZE(mgcp_requests); ++i)
Holger Hans Peter Freytherf36a11a2010-03-31 13:26:46 +0200187 if (strncmp(mgcp_requests[i].name, (const char *) &msg->l2h[0], 4) == 0) {
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100188 handled = 1;
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100189 resp = mgcp_requests[i].handle_request(cfg, msg);
Holger Hans Peter Freyther62e836c2010-02-03 11:03:45 +0100190 break;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100191 }
192 if (!handled) {
Holger Hans Peter Freytherf36a11a2010-03-31 13:26:46 +0200193 LOGP(DMGCP, LOGL_NOTICE, "MSG with type: '%.4s' not handled\n", &msg->l2h[0]);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100194 }
195 }
196
Holger Hans Peter Freyther62e836c2010-02-03 11:03:45 +0100197 return resp;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100198}
199
Holger Hans Peter Freyther9f239a22011-01-06 19:32:52 +0100200/**
201 * We have a null terminated string with the endpoint name here. We only
202 * support two kinds. Simple ones as seen on the BSC level and the ones
203 * seen on the trunk side.
204 */
205static struct mgcp_endpoint *find_e1_endpoint(struct mgcp_config *cfg,
206 const char *mgcp)
207{
208 char *rest = NULL;
Holger Hans Peter Freyther74e61112011-02-28 14:13:47 +0100209 struct mgcp_trunk_config *tcfg;
210 int trunk, endp;
Holger Hans Peter Freyther9f239a22011-01-06 19:32:52 +0100211
212 trunk = strtoul(mgcp + 6, &rest, 10);
Holger Hans Peter Freytherf43f2fc2011-01-07 11:30:21 +0100213 if (rest == NULL || rest[0] != '/' || trunk < 1) {
Holger Hans Peter Freyther9f239a22011-01-06 19:32:52 +0100214 LOGP(DMGCP, LOGL_ERROR, "Wrong trunk name '%s'\n", mgcp);
215 return NULL;
216 }
217
218 endp = strtoul(rest + 1, &rest, 10);
219 if (rest == NULL || rest[0] != '@') {
Holger Hans Peter Freytherf43f2fc2011-01-07 11:30:21 +0100220 LOGP(DMGCP, LOGL_ERROR, "Wrong endpoint name '%s'\n", mgcp);
Holger Hans Peter Freyther9f239a22011-01-06 19:32:52 +0100221 return NULL;
222 }
223
224 /* signalling is on timeslot 1 */
225 if (endp == 1)
226 return NULL;
227
Holger Hans Peter Freyther74e61112011-02-28 14:13:47 +0100228 tcfg = mgcp_trunk_num(cfg, trunk);
229 if (!tcfg) {
230 LOGP(DMGCP, LOGL_ERROR, "The trunk %d is not declared.\n", trunk);
231 return NULL;
232 }
233
234 if (!tcfg->endpoints) {
235 LOGP(DMGCP, LOGL_ERROR, "Endpoints of trunk %d not allocated.\n", trunk);
236 return NULL;
237 }
238
239 if (endp < 1 || endp >= tcfg->number_endpoints) {
Holger Hans Peter Freyther9f239a22011-01-06 19:32:52 +0100240 LOGP(DMGCP, LOGL_ERROR, "Failed to find endpoint '%s'\n", mgcp);
Holger Hans Peter Freyther45c21842011-01-07 11:36:54 +0100241 return NULL;
Holger Hans Peter Freyther9f239a22011-01-06 19:32:52 +0100242 }
243
Holger Hans Peter Freyther74e61112011-02-28 14:13:47 +0100244 return &tcfg->endpoints[endp];
Holger Hans Peter Freyther9f239a22011-01-06 19:32:52 +0100245}
246
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100247static struct mgcp_endpoint *find_endpoint(struct mgcp_config *cfg, const char *mgcp)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100248{
249 char *endptr = NULL;
250 unsigned int gw = INT_MAX;
251
Holger Hans Peter Freyther9f239a22011-01-06 19:32:52 +0100252 if (strncmp(mgcp, "ds/e1", 5) == 0) {
253 return find_e1_endpoint(cfg, mgcp);
254 } else {
255 gw = strtoul(mgcp, &endptr, 16);
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +0100256 if (gw > 0 && gw < cfg->trunk.number_endpoints && strcmp(endptr, "@mgw") == 0)
257 return &cfg->trunk.endpoints[gw];
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100258 }
259
Holger Hans Peter Freyther9f239a22011-01-06 19:32:52 +0100260 LOGP(DMGCP, LOGL_ERROR, "Not able to find endpoint: '%s'\n", mgcp);
261 return NULL;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100262}
263
Harald Welteae199722012-01-27 12:31:36 +0100264/**
265 * @returns 0 when the status line was complete and transaction_id and
266 * endp out parameters are set.
267 */
268static int mgcp_analyze_header(struct mgcp_config *cfg, char *data,
Holger Hans Peter Freytherf2f15912010-04-01 03:27:04 +0200269 const char **transaction_id, struct mgcp_endpoint **endp)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100270{
Harald Welteae199722012-01-27 12:31:36 +0100271 int i = 0;
272 char *elem, *save;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100273
Holger Hans Peter Freythera820c5f2010-02-26 13:32:55 +0100274 *transaction_id = "000000";
275
Harald Welteae199722012-01-27 12:31:36 +0100276 for (elem = strtok_r(data, " ", &save); elem;
277 elem = strtok_r(NULL, " ", &save)) {
278 switch (i) {
279 case 0:
280 *transaction_id = elem;
281 break;
282 case 1:
283 if (endp) {
284 *endp = find_endpoint(cfg, elem);
285 if (!*endp) {
286 LOGP(DMGCP, LOGL_ERROR,
287 "Unable to find Endpoint `%s'\n",
288 elem);
289 return -1;
290 }
291 }
292 break;
293 case 2:
294 if (strcmp("MGCP", elem)) {
295 LOGP(DMGCP, LOGL_ERROR,
296 "MGCP header parsing error\n");
297 return -1;
298 }
299 break;
300 case 3:
301 if (strcmp("1.0", elem)) {
302 LOGP(DMGCP, LOGL_ERROR, "MGCP version `%s' "
303 "not supported\n", elem);
304 return -1;
305 }
306 break;
307 }
308 i++;
309 }
310
311 if (i != 4) {
312 LOGP(DMGCP, LOGL_ERROR, "MGCP status line too short.\n");
313 *transaction_id = "000000";
314 *endp = NULL;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100315 return -1;
316 }
317
Holger Hans Peter Freytherf2f15912010-04-01 03:27:04 +0200318 return 0;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100319}
320
321static int verify_call_id(const struct mgcp_endpoint *endp,
322 const char *callid)
323{
324 if (strcmp(endp->callid, callid) != 0) {
Holger Hans Peter Freyther2ada71d2010-02-03 09:13:10 +0100325 LOGP(DMGCP, LOGL_ERROR, "CallIDs does not match on 0x%x. '%s' != '%s'\n",
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100326 ENDPOINT_NUMBER(endp), endp->callid, callid);
327 return -1;
328 }
329
330 return 0;
331}
332
333static int verify_ci(const struct mgcp_endpoint *endp,
Holger Hans Peter Freyther46340132010-08-06 08:26:54 +0800334 const char *_ci)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100335{
Holger Hans Peter Freyther46340132010-08-06 08:26:54 +0800336 uint32_t ci = strtoul(_ci, NULL, 10);
337
338 if (ci != endp->ci) {
339 LOGP(DMGCP, LOGL_ERROR, "ConnectionIdentifiers do not match on 0x%x. %u != %s\n",
340 ENDPOINT_NUMBER(endp), endp->ci, _ci);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100341 return -1;
342 }
343
344 return 0;
345}
346
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100347static struct msgb *handle_audit_endpoint(struct mgcp_config *cfg, struct msgb *msg)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100348{
Holger Hans Peter Freyther6adac172011-01-06 16:19:55 +0100349 int found;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100350 const char *trans_id;
351 struct mgcp_endpoint *endp;
Harald Welteae199722012-01-27 12:31:36 +0100352 char *data = strtok((char *) msg->l3h, "\r\n");
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100353
Harald Welteae199722012-01-27 12:31:36 +0100354 found = mgcp_analyze_header(cfg, data, &trans_id, &endp);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100355 if (found != 0)
Holger Hans Peter Freyther6adac172011-01-06 16:19:55 +0100356 return create_err_response(500, "AUEP", trans_id);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100357 else
Holger Hans Peter Freyther6adac172011-01-06 16:19:55 +0100358 return create_ok_response(200, "AUEP", trans_id);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100359}
360
Holger Hans Peter Freytheradb6e1c2010-09-18 06:44:24 +0800361static int parse_conn_mode(const char *msg, int *conn_mode)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100362{
363 int ret = 0;
364 if (strcmp(msg, "recvonly") == 0)
365 *conn_mode = MGCP_CONN_RECV_ONLY;
366 else if (strcmp(msg, "sendrecv") == 0)
367 *conn_mode = MGCP_CONN_RECV_SEND;
Holger Hans Peter Freythere02860a2010-09-18 20:21:44 +0800368 else if (strcmp(msg, "sendonly") == 0)
369 *conn_mode = MGCP_CONN_SEND_ONLY;
Holger Hans Peter Freyther98a38772010-08-03 02:27:21 +0800370 else if (strcmp(msg, "loopback") == 0)
371 *conn_mode = MGCP_CONN_LOOPBACK;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100372 else {
Holger Hans Peter Freyther2ada71d2010-02-03 09:13:10 +0100373 LOGP(DMGCP, LOGL_ERROR, "Unknown connection mode: '%s'\n", msg);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100374 ret = -1;
375 }
376
377 return ret;
378}
379
Holger Hans Peter Freytherf138f912010-08-05 08:08:17 +0800380static int allocate_port(struct mgcp_endpoint *endp, struct mgcp_rtp_end *end,
Holger Hans Peter Freyther218f8562010-09-18 02:30:02 +0800381 struct mgcp_port_range *range,
382 int (*alloc)(struct mgcp_endpoint *endp, int port))
Holger Hans Peter Freytherf138f912010-08-05 08:08:17 +0800383{
384 int i;
385
386 if (range->mode == PORT_ALLOC_STATIC) {
Holger Hans Peter Freytherf138f912010-08-05 08:08:17 +0800387 end->local_alloc = PORT_ALLOC_STATIC;
388 return 0;
389 }
390
391 /* attempt to find a port */
392 for (i = 0; i < 200; ++i) {
393 int rc;
394
395 if (range->last_port >= range->range_end)
396 range->last_port = range->range_start;
397
Holger Hans Peter Freyther218f8562010-09-18 02:30:02 +0800398 rc = alloc(endp, range->last_port);
Holger Hans Peter Freytherf138f912010-08-05 08:08:17 +0800399
400 range->last_port += 2;
401 if (rc == 0) {
402 end->local_alloc = PORT_ALLOC_DYNAMIC;
403 return 0;
404 }
405
406 }
407
Holger Hans Peter Freyther218f8562010-09-18 02:30:02 +0800408 LOGP(DMGCP, LOGL_ERROR, "Allocating a RTP/RTCP port failed 200 times 0x%x.\n",
409 ENDPOINT_NUMBER(endp));
Holger Hans Peter Freytherf138f912010-08-05 08:08:17 +0800410 return -1;
411}
412
413static int allocate_ports(struct mgcp_endpoint *endp)
414{
Holger Hans Peter Freyther218f8562010-09-18 02:30:02 +0800415 if (allocate_port(endp, &endp->net_end, &endp->cfg->net_ports,
416 mgcp_bind_net_rtp_port) != 0)
Holger Hans Peter Freytherf138f912010-08-05 08:08:17 +0800417 return -1;
418
Holger Hans Peter Freyther218f8562010-09-18 02:30:02 +0800419 if (allocate_port(endp, &endp->bts_end, &endp->cfg->bts_ports,
420 mgcp_bind_bts_rtp_port) != 0) {
Holger Hans Peter Freytherf138f912010-08-05 08:08:17 +0800421 mgcp_rtp_end_reset(&endp->net_end);
422 return -1;
423 }
424
Holger Hans Peter Freyther69906872011-02-28 14:51:48 +0100425 if (endp->cfg->transcoder_ip && endp->tcfg->trunk_type == MGCP_TRUNK_VIRTUAL) {
Holger Hans Peter Freyther21262332010-11-01 20:53:31 +0100426 if (allocate_port(endp, &endp->trans_net,
Holger Hans Peter Freytherb54048f2010-11-01 19:57:50 +0100427 &endp->cfg->transcoder_ports,
Holger Hans Peter Freytherbd7b3c52010-11-01 21:04:54 +0100428 mgcp_bind_trans_net_rtp_port) != 0) {
Holger Hans Peter Freytherb54048f2010-11-01 19:57:50 +0100429 mgcp_rtp_end_reset(&endp->net_end);
430 mgcp_rtp_end_reset(&endp->bts_end);
431 return -1;
432 }
433
Holger Hans Peter Freytherbd7b3c52010-11-01 21:04:54 +0100434 if (allocate_port(endp, &endp->trans_bts,
435 &endp->cfg->transcoder_ports,
436 mgcp_bind_trans_bts_rtp_port) != 0) {
437 mgcp_rtp_end_reset(&endp->net_end);
438 mgcp_rtp_end_reset(&endp->bts_end);
439 mgcp_rtp_end_reset(&endp->trans_net);
440 return -1;
441 }
442
Holger Hans Peter Freytherb54048f2010-11-01 19:57:50 +0100443 /* remember that we have set up transcoding */
444 endp->is_transcoded = 1;
Holger Hans Peter Freyther218f8562010-09-18 02:30:02 +0800445 }
446
Holger Hans Peter Freytherf138f912010-08-05 08:08:17 +0800447 return 0;
448}
449
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100450static struct msgb *handle_create_con(struct mgcp_config *cfg, struct msgb *msg)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100451{
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100452 const char *trans_id;
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +0100453 struct mgcp_trunk_config *tcfg;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100454 struct mgcp_endpoint *endp;
Holger Hans Peter Freyther9e9392d2010-08-08 16:24:48 +0800455 int error_code = 400;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100456
Holger Hans Peter Freyther3488c3d2011-07-20 20:44:54 +0200457 const char *local_options = NULL;
458 const char *callid = NULL;
459 const char *mode = NULL;
Harald Welteae199722012-01-27 12:31:36 +0100460 char *line, *save;
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +0100461
Holger Hans Peter Freyther3488c3d2011-07-20 20:44:54 +0200462 /* parse CallID C: and LocalParameters L: */
Harald Welteae199722012-01-27 12:31:36 +0100463 for_each_line((char *) msg->l3h, line, save) {
464 /* skip first line */
465 if (line == (char *) msg->l3h) {
466 int found = mgcp_analyze_header(cfg, line, &trans_id, &endp);
467 if (found != 0)
468 return create_err_response(510, "CRCX", trans_id);
469 continue;
470 }
471
472 switch (line[0]) {
473 case 'L':
474 local_options = (const char *) line + 3;
475 break;
476 case 'C':
477 callid = (const char *) line + 3;
478 break;
479 case 'M':
480 mode = (const char *) line + 3;
481 break;
482 default:
483 LOGP(DMGCP, LOGL_NOTICE, "Unhandled option: '%c'/%d on 0x%x\n",
484 *line, *line, ENDPOINT_NUMBER(endp));
485 break;
486 }
Holger Hans Peter Freyther3488c3d2011-07-20 20:44:54 +0200487 }
Harald Welteae199722012-01-27 12:31:36 +0100488
489 tcfg = endp->tcfg;
Holger Hans Peter Freyther3488c3d2011-07-20 20:44:54 +0200490
491 /* Check required data */
492 if (!callid || !mode) {
493 LOGP(DMGCP, LOGL_ERROR, "Missing callid and mode in CRCX on 0x%x\n",
494 ENDPOINT_NUMBER(endp));
495 return create_err_response(400, "CRCX", trans_id);
496 }
497
498 /* this appears to be a retransmission, maybe check trans id */
499 if (endp->allocated &&
500 memcmp(endp->callid, callid, strlen(endp->callid)) == 0)
501 return create_response_with_sdp(endp, "CRCX", trans_id);
502
Holger Hans Peter Freyther39a97e22010-08-06 18:03:11 +0800503 if (endp->allocated) {
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +0100504 if (tcfg->force_realloc) {
Holger Hans Peter Freyther408cc4a2010-04-07 10:51:27 +0200505 LOGP(DMGCP, LOGL_NOTICE, "Endpoint 0x%x already allocated. Forcing realloc.\n",
506 ENDPOINT_NUMBER(endp));
Holger Hans Peter Freyther32d4e502010-04-24 21:02:48 +0800507 mgcp_free_endp(endp);
Holger Hans Peter Freyther869e38e2010-08-06 17:54:27 +0800508 if (cfg->realloc_cb)
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +0100509 cfg->realloc_cb(tcfg, ENDPOINT_NUMBER(endp));
Holger Hans Peter Freyther408cc4a2010-04-07 10:51:27 +0200510 } else {
511 LOGP(DMGCP, LOGL_ERROR, "Endpoint is already used. 0x%x\n",
512 ENDPOINT_NUMBER(endp));
Holger Hans Peter Freyther6adac172011-01-06 16:19:55 +0100513 return create_err_response(400, "CRCX", trans_id);
Holger Hans Peter Freyther408cc4a2010-04-07 10:51:27 +0200514 }
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100515 }
516
Holger Hans Peter Freyther3488c3d2011-07-20 20:44:54 +0200517 /* copy some parameters */
518 endp->callid = talloc_strdup(tcfg->endpoints, callid);
519
520 if (local_options)
521 endp->local_options = talloc_strdup(tcfg->endpoints, local_options);
522
523 if (parse_conn_mode(mode, &endp->conn_mode) != 0) {
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100524 error_code = 517;
525 goto error2;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100526 }
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100527
528 /* initialize */
Holger Hans Peter Freythera17d7012010-08-05 01:34:51 +0800529 endp->net_end.rtp_port = endp->net_end.rtcp_port = endp->bts_end.rtp_port = endp->bts_end.rtcp_port = 0;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100530
531 /* set to zero until we get the info */
Holger Hans Peter Freythera17d7012010-08-05 01:34:51 +0800532 memset(&endp->net_end.addr, 0, sizeof(endp->net_end.addr));
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100533
534 /* bind to the port now */
Holger Hans Peter Freytherf138f912010-08-05 08:08:17 +0800535 if (allocate_ports(endp) != 0)
536 goto error2;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100537
538 /* assign a local call identifier or fail */
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100539 endp->ci = generate_call_id(cfg);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100540 if (endp->ci == CI_UNUSED)
541 goto error2;
542
Holger Hans Peter Freyther39a97e22010-08-06 18:03:11 +0800543 endp->allocated = 1;
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +0100544 endp->bts_end.payload_type = tcfg->audio_payload;
Holger Hans Peter Freytheref6bb252010-02-26 13:41:22 +0100545
Holger Hans Peter Freytherfe86d3c2010-02-26 13:37:05 +0100546 /* policy CB */
547 if (cfg->policy_cb) {
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +0100548 switch (cfg->policy_cb(tcfg, ENDPOINT_NUMBER(endp), MGCP_ENDP_CRCX, trans_id)) {
Holger Hans Peter Freytherfe86d3c2010-02-26 13:37:05 +0100549 case MGCP_POLICY_REJECT:
550 LOGP(DMGCP, LOGL_NOTICE, "CRCX rejected by policy on 0x%x\n",
551 ENDPOINT_NUMBER(endp));
552 mgcp_free_endp(endp);
Holger Hans Peter Freyther6adac172011-01-06 16:19:55 +0100553 return create_err_response(400, "CRCX", trans_id);
Holger Hans Peter Freytherfe86d3c2010-02-26 13:37:05 +0100554 break;
555 case MGCP_POLICY_DEFER:
556 /* stop processing */
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +0800557 create_transcoder(endp);
Holger Hans Peter Freytherfe86d3c2010-02-26 13:37:05 +0100558 return NULL;
559 break;
560 case MGCP_POLICY_CONT:
561 /* just continue */
562 break;
563 }
564 }
565
Holger Hans Peter Freythere378cb12010-08-06 20:22:23 +0800566 LOGP(DMGCP, LOGL_DEBUG, "Creating endpoint on: 0x%x CI: %u port: %u/%u\n",
Holger Hans Peter Freyther58ff2192010-08-05 03:08:35 +0800567 ENDPOINT_NUMBER(endp), endp->ci,
568 endp->net_end.local_port, endp->bts_end.local_port);
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100569 if (cfg->change_cb)
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +0100570 cfg->change_cb(tcfg, ENDPOINT_NUMBER(endp), MGCP_ENDP_CRCX);
Holger Hans Peter Freyther77f7afe2010-02-03 09:54:43 +0100571
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +0800572 create_transcoder(endp);
Holger Hans Peter Freyther8d188ed2010-02-21 01:44:08 +0100573 return create_response_with_sdp(endp, "CRCX", trans_id);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100574error2:
Holger Hans Peter Freyther414bf402010-08-06 07:05:13 +0800575 mgcp_free_endp(endp);
Holger Hans Peter Freyther2ada71d2010-02-03 09:13:10 +0100576 LOGP(DMGCP, LOGL_NOTICE, "Resource error on 0x%x\n", ENDPOINT_NUMBER(endp));
Holger Hans Peter Freyther6adac172011-01-06 16:19:55 +0100577 return create_err_response(error_code, "CRCX", trans_id);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100578}
579
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100580static struct msgb *handle_modify_con(struct mgcp_config *cfg, struct msgb *msg)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100581{
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100582 const char *trans_id;
583 struct mgcp_endpoint *endp;
584 int error_code = 500;
Holger Hans Peter Freythere3d16bb2010-04-22 11:58:13 +0800585 int silent = 0;
Harald Welteae199722012-01-27 12:31:36 +0100586 char *line, *save;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100587
Harald Welteae199722012-01-27 12:31:36 +0100588 for_each_line((char *) msg->l3h, line, save) {
589 /* skip first line */
590 if (line == (char *) msg->l3h) {
591 int found = mgcp_analyze_header(cfg, line, &trans_id,
592 &endp);
593 if (found != 0)
594 return create_err_response(510, "MDCX",
595 trans_id);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100596
Harald Welteae199722012-01-27 12:31:36 +0100597 if (endp->ci == CI_UNUSED) {
598 LOGP(DMGCP, LOGL_ERROR, "Endpoint is not "
599 "holding a connection. 0x%x\n",
600 ENDPOINT_NUMBER(endp));
601 return create_err_response(400, "MDCX", trans_id);
602 }
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100603 }
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100604
Harald Welteae199722012-01-27 12:31:36 +0100605 switch (line[0]) {
606 case 'C': {
607 if (verify_call_id(endp, line + 3) != 0)
608 goto error3;
609 break;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100610 }
Harald Welteae199722012-01-27 12:31:36 +0100611 case 'I': {
612 if (verify_ci(endp, line + 3) != 0)
613 goto error3;
614 break;
615 }
616 case 'L':
617 /* skip */
618 break;
619 case 'M':
620 if (parse_conn_mode(line + 3, &endp->conn_mode) != 0) {
621 error_code = 517;
622 goto error3;
623 }
624 endp->orig_mode = endp->conn_mode;
625 break;
626 case 'Z':
627 silent = strcmp("noanswer", line + 3) == 0;
628 break;
629 case '\0':
630 /* SDP file begins */
631 break;
632 case 'a':
633 case 'o':
634 case 's':
635 case 't':
636 case 'v':
637 /* skip these SDP attributes */
638 break;
639 case 'm': {
640 int port;
641 int payload;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100642
Harald Welteae199722012-01-27 12:31:36 +0100643 if (sscanf(line, "m=audio %d RTP/AVP %d", &port, &payload) == 2) {
644 endp->net_end.rtp_port = htons(port);
645 endp->net_end.rtcp_port = htons(port + 1);
646 endp->net_end.payload_type = payload;
647 }
648 break;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100649 }
Harald Welteae199722012-01-27 12:31:36 +0100650 case 'c': {
651 char ipv4[16];
652
653 if (sscanf(line, "c=IN IP4 %15s", ipv4) == 1) {
654 inet_aton(ipv4, &endp->net_end.addr);
655 }
656 break;
657 }
658 default:
659 LOGP(DMGCP, LOGL_NOTICE, "Unhandled option: '%c'/%d on 0x%x\n",
660 line[0], line[0], ENDPOINT_NUMBER(endp));
661 break;
662 }
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100663 }
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100664
Holger Hans Peter Freytherfe86d3c2010-02-26 13:37:05 +0100665 /* policy CB */
666 if (cfg->policy_cb) {
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +0100667 switch (cfg->policy_cb(endp->tcfg, ENDPOINT_NUMBER(endp), MGCP_ENDP_MDCX, trans_id)) {
Holger Hans Peter Freytherfe86d3c2010-02-26 13:37:05 +0100668 case MGCP_POLICY_REJECT:
669 LOGP(DMGCP, LOGL_NOTICE, "MDCX rejected by policy on 0x%x\n",
670 ENDPOINT_NUMBER(endp));
Holger Hans Peter Freythere3d16bb2010-04-22 11:58:13 +0800671 if (silent)
672 goto out_silent;
Holger Hans Peter Freyther6adac172011-01-06 16:19:55 +0100673 return create_err_response(400, "MDCX", trans_id);
Holger Hans Peter Freytherfe86d3c2010-02-26 13:37:05 +0100674 break;
675 case MGCP_POLICY_DEFER:
676 /* stop processing */
677 return NULL;
678 break;
679 case MGCP_POLICY_CONT:
680 /* just continue */
681 break;
682 }
683 }
684
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100685 /* modify */
Holger Hans Peter Freythere378cb12010-08-06 20:22:23 +0800686 LOGP(DMGCP, LOGL_DEBUG, "Modified endpoint on: 0x%x Server: %s:%u\n",
Holger Hans Peter Freythera17d7012010-08-05 01:34:51 +0800687 ENDPOINT_NUMBER(endp), inet_ntoa(endp->net_end.addr), ntohs(endp->net_end.rtp_port));
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100688 if (cfg->change_cb)
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +0100689 cfg->change_cb(endp->tcfg, ENDPOINT_NUMBER(endp), MGCP_ENDP_MDCX);
Holger Hans Peter Freythere3d16bb2010-04-22 11:58:13 +0800690 if (silent)
691 goto out_silent;
692
Holger Hans Peter Freyther8d188ed2010-02-21 01:44:08 +0100693 return create_response_with_sdp(endp, "MDCX", trans_id);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100694
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100695error3:
Holger Hans Peter Freyther6adac172011-01-06 16:19:55 +0100696 return create_err_response(error_code, "MDCX", trans_id);
Holger Hans Peter Freythere3d16bb2010-04-22 11:58:13 +0800697
698
699out_silent:
700 return NULL;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100701}
702
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100703static struct msgb *handle_delete_con(struct mgcp_config *cfg, struct msgb *msg)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100704{
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100705 const char *trans_id;
706 struct mgcp_endpoint *endp;
Holger Hans Peter Freyther9e9392d2010-08-08 16:24:48 +0800707 int error_code = 400;
Holger Hans Peter Freythere3d16bb2010-04-22 11:58:13 +0800708 int silent = 0;
Harald Welteae199722012-01-27 12:31:36 +0100709 char *line, *save;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100710
Harald Welteae199722012-01-27 12:31:36 +0100711 for_each_line((char *) msg->l3h, line, save) {
712 /* skip first line */
713 if ((char *) msg->l3h == line) {
714 int found = mgcp_analyze_header(cfg, line, &trans_id,
715 &endp);
716 if (found != 0)
717 return create_err_response(error_code, "DLCX",
718 trans_id);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100719
Harald Welteae199722012-01-27 12:31:36 +0100720 if (!endp->allocated) {
721 LOGP(DMGCP, LOGL_ERROR, "Endpoint is not "
722 "used. 0x%x\n", ENDPOINT_NUMBER(endp));
723 return create_err_response(400, "DLCX",
724 trans_id);
725 }
726 }
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100727
Harald Welteae199722012-01-27 12:31:36 +0100728 switch (line[0]) {
729 case 'C':
730 if (verify_call_id(endp, line + 3) != 0)
731 goto error3;
732 break;
733 case 'I':
734 if (verify_ci(endp, line + 3) != 0)
735 goto error3;
736 break;
737 case 'Z':
738 silent = strcmp("noanswer", line + 3) == 0;
739 break;
740 default:
741 LOGP(DMGCP, LOGL_NOTICE, "Unhandled option: '%c'/%d on 0x%x\n",
742 line[0], line[0], ENDPOINT_NUMBER(endp));
743 break;
744 }
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100745 }
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100746
Holger Hans Peter Freytherfe86d3c2010-02-26 13:37:05 +0100747 /* policy CB */
748 if (cfg->policy_cb) {
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +0100749 switch (cfg->policy_cb(endp->tcfg, ENDPOINT_NUMBER(endp), MGCP_ENDP_DLCX, trans_id)) {
Holger Hans Peter Freytherfe86d3c2010-02-26 13:37:05 +0100750 case MGCP_POLICY_REJECT:
751 LOGP(DMGCP, LOGL_NOTICE, "DLCX rejected by policy on 0x%x\n",
752 ENDPOINT_NUMBER(endp));
Holger Hans Peter Freythere3d16bb2010-04-22 11:58:13 +0800753 if (silent)
754 goto out_silent;
Holger Hans Peter Freyther6adac172011-01-06 16:19:55 +0100755 return create_err_response(400, "DLCX", trans_id);
Holger Hans Peter Freytherfe86d3c2010-02-26 13:37:05 +0100756 break;
757 case MGCP_POLICY_DEFER:
758 /* stop processing */
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +0800759 delete_transcoder(endp);
Holger Hans Peter Freytherfe86d3c2010-02-26 13:37:05 +0100760 return NULL;
761 break;
762 case MGCP_POLICY_CONT:
763 /* just continue */
764 break;
765 }
766 }
767
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100768 /* free the connection */
Holger Hans Peter Freythere378cb12010-08-06 20:22:23 +0800769 LOGP(DMGCP, LOGL_DEBUG, "Deleted endpoint on: 0x%x Server: %s:%u\n",
Holger Hans Peter Freythera17d7012010-08-05 01:34:51 +0800770 ENDPOINT_NUMBER(endp), inet_ntoa(endp->net_end.addr), ntohs(endp->net_end.rtp_port));
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +0800771
772 delete_transcoder(endp);
Holger Hans Peter Freyther154b9552010-02-26 13:27:51 +0100773 mgcp_free_endp(endp);
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100774 if (cfg->change_cb)
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +0100775 cfg->change_cb(endp->tcfg, ENDPOINT_NUMBER(endp), MGCP_ENDP_DLCX);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100776
Holger Hans Peter Freythere3d16bb2010-04-22 11:58:13 +0800777 if (silent)
778 goto out_silent;
Holger Hans Peter Freyther6adac172011-01-06 16:19:55 +0100779 return create_ok_response(250, "DLCX", trans_id);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100780
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100781error3:
Holger Hans Peter Freyther6adac172011-01-06 16:19:55 +0100782 return create_err_response(error_code, "DLCX", trans_id);
Holger Hans Peter Freythere3d16bb2010-04-22 11:58:13 +0800783
784out_silent:
785 return NULL;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100786}
787
Holger Hans Peter Freyther9bdcc9c2010-03-31 06:39:35 +0200788static struct msgb *handle_rsip(struct mgcp_config *cfg, struct msgb *msg)
789{
Holger Hans Peter Freyther74db7742011-06-10 00:04:55 +0200790 const char *trans_id;
791 struct mgcp_endpoint *endp;
792 int found;
Harald Welteae199722012-01-27 12:31:36 +0100793 char *data = strtok((char *) msg->l3h, "\r\n");
Holger Hans Peter Freyther74db7742011-06-10 00:04:55 +0200794
Harald Welteae199722012-01-27 12:31:36 +0100795 found = mgcp_analyze_header(cfg, data, &trans_id, &endp);
Holger Hans Peter Freyther74db7742011-06-10 00:04:55 +0200796 if (found != 0) {
797 LOGP(DMGCP, LOGL_ERROR, "Failed to find the endpoint.\n");
798 return NULL;
799 }
800
Holger Hans Peter Freyther9bdcc9c2010-03-31 06:39:35 +0200801 if (cfg->reset_cb)
Holger Hans Peter Freyther74db7742011-06-10 00:04:55 +0200802 cfg->reset_cb(endp->tcfg);
Holger Hans Peter Freyther9bdcc9c2010-03-31 06:39:35 +0200803 return NULL;
804}
805
Holger Hans Peter Freyther6e94d6d2011-01-25 23:33:54 +0100806/*
807 * This can request like DTMF detection and forward, fax detection... it
808 * can also request when the notification should be send and such. We don't
809 * do this right now.
810 */
811static struct msgb *handle_noti_req(struct mgcp_config *cfg, struct msgb *msg)
812{
Holger Hans Peter Freyther6e94d6d2011-01-25 23:33:54 +0100813 const char *trans_id;
814 struct mgcp_endpoint *endp;
815 int found;
Harald Welteae199722012-01-27 12:31:36 +0100816 char *data = strtok((char *) msg->l3h, "\r\n");
Holger Hans Peter Freyther6e94d6d2011-01-25 23:33:54 +0100817
Harald Welteae199722012-01-27 12:31:36 +0100818 found = mgcp_analyze_header(cfg, data, &trans_id, &endp);
Holger Hans Peter Freyther6e94d6d2011-01-25 23:33:54 +0100819 if (found != 0)
820 return create_err_response(400, "RQNT", trans_id);
821
822 if (!endp->allocated) {
823 LOGP(DMGCP, LOGL_ERROR, "Endpoint is not used. 0x%x\n", ENDPOINT_NUMBER(endp));
824 return create_err_response(400, "RQNT", trans_id);
825 }
826 return create_ok_response(200, "RQNT", trans_id);
827}
828
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100829struct mgcp_config *mgcp_config_alloc(void)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100830{
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100831 struct mgcp_config *cfg;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100832
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100833 cfg = talloc_zero(NULL, struct mgcp_config);
834 if (!cfg) {
835 LOGP(DMGCP, LOGL_FATAL, "Failed to allocate config.\n");
836 return NULL;
837 }
838
839 cfg->source_port = 2427;
840 cfg->source_addr = talloc_strdup(cfg, "0.0.0.0");
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +0100841
Holger Hans Peter Freytherb98ba722010-09-19 04:21:39 +0800842 cfg->transcoder_remote_base = 4000;
Holger Hans Peter Freyther15e73892010-08-05 07:10:56 +0800843
844 cfg->bts_ports.base_port = RTP_PORT_DEFAULT;
845 cfg->net_ports.base_port = RTP_PORT_NET_DEFAULT;
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100846
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +0100847 /* default trunk handling */
848 cfg->trunk.cfg = cfg;
849 cfg->trunk.trunk_nr = 0;
850 cfg->trunk.trunk_type = MGCP_TRUNK_VIRTUAL;
851 cfg->trunk.audio_name = talloc_strdup(cfg, "AMR/8000");
852 cfg->trunk.audio_payload = 126;
Holger Hans Peter Freythera8090d52012-05-11 13:00:45 +0200853 cfg->trunk.omit_rtcp = 0;
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +0100854
Holger Hans Peter Freyther0e939fe2011-02-28 12:11:02 +0100855 INIT_LLIST_HEAD(&cfg->trunks);
856
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100857 return cfg;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100858}
859
Holger Hans Peter Freyther0e939fe2011-02-28 12:11:02 +0100860struct mgcp_trunk_config *mgcp_trunk_alloc(struct mgcp_config *cfg, int nr)
861{
862 struct mgcp_trunk_config *trunk;
863
864 trunk = talloc_zero(cfg, struct mgcp_trunk_config);
865 if (!trunk) {
866 LOGP(DMGCP, LOGL_ERROR, "Failed to allocate.\n");
867 return NULL;
868 }
869
870 trunk->cfg = cfg;
871 trunk->trunk_type = MGCP_TRUNK_E1;
872 trunk->trunk_nr = nr;
873 trunk->audio_name = talloc_strdup(cfg, "AMR/8000");
874 trunk->audio_payload = 126;
875 trunk->number_endpoints = 33;
Holger Hans Peter Freythera8090d52012-05-11 13:00:45 +0200876 trunk->omit_rtcp = 0;
Holger Hans Peter Freyther0e939fe2011-02-28 12:11:02 +0100877 llist_add_tail(&trunk->entry, &cfg->trunks);
878 return trunk;
879}
880
881struct mgcp_trunk_config *mgcp_trunk_num(struct mgcp_config *cfg, int index)
882{
883 struct mgcp_trunk_config *trunk;
884
885 llist_for_each_entry(trunk, &cfg->trunks, entry)
886 if (trunk->trunk_nr == index)
887 return trunk;
888
889 return NULL;
890}
891
Holger Hans Peter Freythera17d7012010-08-05 01:34:51 +0800892static void mgcp_rtp_end_reset(struct mgcp_rtp_end *end)
893{
Holger Hans Peter Freythere97155a2010-11-02 19:06:13 +0100894 if (end->local_alloc == PORT_ALLOC_DYNAMIC) {
Holger Hans Peter Freytherf138f912010-08-05 08:08:17 +0800895 mgcp_free_rtp_port(end);
Holger Hans Peter Freythere97155a2010-11-02 19:06:13 +0100896 end->local_port = 0;
897 }
Holger Hans Peter Freytherf138f912010-08-05 08:08:17 +0800898
Holger Hans Peter Freytherc4921272010-08-05 03:37:22 +0800899 end->packets = 0;
Holger Hans Peter Freyther952f7522012-09-12 11:38:37 +0200900 end->octets = 0;
Holger Hans Peter Freytherc4921272010-08-05 03:37:22 +0800901 memset(&end->addr, 0, sizeof(end->addr));
Holger Hans Peter Freythere97155a2010-11-02 19:06:13 +0100902 end->rtp_port = end->rtcp_port = 0;
Holger Hans Peter Freythera17d7012010-08-05 01:34:51 +0800903 end->payload_type = -1;
Holger Hans Peter Freytherf138f912010-08-05 08:08:17 +0800904 end->local_alloc = -1;
Holger Hans Peter Freythera17d7012010-08-05 01:34:51 +0800905}
906
Holger Hans Peter Freytherc4921272010-08-05 03:37:22 +0800907static void mgcp_rtp_end_init(struct mgcp_rtp_end *end)
908{
909 mgcp_rtp_end_reset(end);
910 end->rtp.fd = -1;
911 end->rtcp.fd = -1;
912}
913
Holger Hans Peter Freyther1f0c5b42011-02-28 14:37:03 +0100914int mgcp_endpoints_allocate(struct mgcp_trunk_config *tcfg)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100915{
916 int i;
917
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100918 /* Initialize all endpoints */
Holger Hans Peter Freyther1f0c5b42011-02-28 14:37:03 +0100919 tcfg->endpoints = _talloc_zero_array(tcfg->cfg,
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100920 sizeof(struct mgcp_endpoint),
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +0100921 tcfg->number_endpoints, "endpoints");
922 if (!tcfg->endpoints)
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100923 return -1;
924
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +0100925 for (i = 0; i < tcfg->number_endpoints; ++i) {
926 tcfg->endpoints[i].ci = CI_UNUSED;
Holger Hans Peter Freyther1f0c5b42011-02-28 14:37:03 +0100927 tcfg->endpoints[i].cfg = tcfg->cfg;
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +0100928 tcfg->endpoints[i].tcfg = tcfg;
929 mgcp_rtp_end_init(&tcfg->endpoints[i].net_end);
930 mgcp_rtp_end_init(&tcfg->endpoints[i].bts_end);
931 mgcp_rtp_end_init(&tcfg->endpoints[i].trans_net);
932 mgcp_rtp_end_init(&tcfg->endpoints[i].trans_bts);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100933 }
934
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100935 return 0;
936}
Holger Hans Peter Freyther154b9552010-02-26 13:27:51 +0100937
938void mgcp_free_endp(struct mgcp_endpoint *endp)
939{
Holger Hans Peter Freytherc77efdf2010-03-31 12:31:09 +0200940 LOGP(DMGCP, LOGL_DEBUG, "Deleting endpoint on: 0x%x\n", ENDPOINT_NUMBER(endp));
Holger Hans Peter Freyther89976e82010-08-03 15:01:43 +0000941 endp->ci = CI_UNUSED;
Holger Hans Peter Freyther39a97e22010-08-06 18:03:11 +0800942 endp->allocated = 0;
Holger Hans Peter Freyther154b9552010-02-26 13:27:51 +0100943
944 if (endp->callid) {
945 talloc_free(endp->callid);
946 endp->callid = NULL;
947 }
948
949 if (endp->local_options) {
950 talloc_free(endp->local_options);
Holger Hans Peter Freyther88c6eea2010-03-01 18:52:04 +0100951 endp->local_options = NULL;
Holger Hans Peter Freyther154b9552010-02-26 13:27:51 +0100952 }
953
Holger Hans Peter Freythera17d7012010-08-05 01:34:51 +0800954 mgcp_rtp_end_reset(&endp->bts_end);
955 mgcp_rtp_end_reset(&endp->net_end);
Holger Hans Peter Freyther21262332010-11-01 20:53:31 +0100956 mgcp_rtp_end_reset(&endp->trans_net);
Holger Hans Peter Freytherbd7b3c52010-11-01 21:04:54 +0100957 mgcp_rtp_end_reset(&endp->trans_bts);
Holger Hans Peter Freytherb54048f2010-11-01 19:57:50 +0100958 endp->is_transcoded = 0;
Holger Hans Peter Freyther380b8712010-07-29 02:38:39 +0800959
Holger Hans Peter Freyther31868922010-08-03 11:59:04 +0000960 memset(&endp->net_state, 0, sizeof(endp->net_state));
961 memset(&endp->bts_state, 0, sizeof(endp->bts_state));
Holger Hans Peter Freytherc597a4e2010-08-03 02:57:02 +0800962
963 endp->conn_mode = endp->orig_mode = MGCP_CONN_NONE;
Holger Hans Peter Freyther6357a8e2010-08-05 12:07:00 +0000964 endp->allow_patch = 0;
Holger Hans Peter Freyther260d6ed2010-08-06 01:12:21 +0800965
966 memset(&endp->taps, 0, sizeof(endp->taps));
Holger Hans Peter Freyther154b9552010-02-26 13:27:51 +0100967}
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +0800968
Holger Hans Peter Freyther557b1ab2010-09-19 04:39:55 +0800969static int send_trans(struct mgcp_config *cfg, const char *buf, int len)
970{
971 struct sockaddr_in addr;
972
973 memset(&addr, 0, sizeof(addr));
974 addr.sin_family = AF_INET;
975 addr.sin_addr = cfg->transcoder_in;
976 addr.sin_port = htons(2427);
977 return sendto(cfg->gw_fd.bfd.fd, buf, len, 0,
978 (struct sockaddr *) &addr, sizeof(addr));
979}
980
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +0800981static void send_msg(struct mgcp_endpoint *endp, int endpoint, int port,
982 const char *msg, const char *mode)
983{
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +0800984 char buf[2096];
985 int len;
986
987 /* hardcoded to AMR right now, we do not know the real type at this point */
988 len = snprintf(buf, sizeof(buf),
989 "%s 42 %x@mgw MGCP 1.0\r\n"
990 "C: 4256\r\n"
991 "M: %s\r\n"
992 "\r\n"
993 "c=IN IP4 %s\r\n"
994 "m=audio %d RTP/AVP %d\r\n"
995 "a=rtpmap:%d %s\r\n",
996 msg, endpoint, mode, endp->cfg->source_addr,
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +0100997 port, endp->tcfg->audio_payload,
998 endp->tcfg->audio_payload, endp->tcfg->audio_name);
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +0800999
1000 if (len < 0)
1001 return;
1002
1003 buf[sizeof(buf) - 1] = '\0';
1004
Holger Hans Peter Freyther557b1ab2010-09-19 04:39:55 +08001005 send_trans(endp->cfg, buf, len);
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +08001006}
1007
1008static void send_dlcx(struct mgcp_endpoint *endp, int endpoint)
1009{
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +08001010 char buf[2096];
1011 int len;
1012
1013 len = snprintf(buf, sizeof(buf),
1014 "DLCX 43 %x@mgw MGCP 1.0\r\n"
1015 "C: 4256\r\n"
1016 , endpoint);
1017
1018 if (len < 0)
1019 return;
1020
1021 buf[sizeof(buf) - 1] = '\0';
1022
Holger Hans Peter Freyther557b1ab2010-09-19 04:39:55 +08001023 send_trans(endp->cfg, buf, len);
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +08001024}
1025
Harald Welte6a857052012-01-27 00:41:39 +01001026static int send_agent(struct mgcp_config *cfg, const char *buf, int len)
1027{
1028 return write(cfg->gw_fd.bfd.fd, buf, len);
1029}
1030
1031int mgcp_send_reset_all(struct mgcp_config *cfg)
1032{
1033 static const char mgcp_reset[] = {
1034 "RSIP 1 *@mgw MGCP 1.0\r\n"
1035 };
1036
1037 return send_agent(cfg, mgcp_reset, sizeof mgcp_reset -1);
1038}
1039
1040int mgcp_send_reset_ep(struct mgcp_endpoint *endp, int endpoint)
1041{
1042 char buf[128];
1043 int len;
1044
1045 len = snprintf(buf, sizeof(buf),
1046 "RSIP 39 %x@mgw MGCP 1.0\r\n"
1047 , endpoint);
1048 if (len < 0)
1049 return len;
1050
1051 buf[sizeof(buf) - 1] = '\0';
1052
1053 return send_agent(endp->cfg, buf, len);
1054}
1055
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +08001056static void create_transcoder(struct mgcp_endpoint *endp)
1057{
1058 int port;
1059 int in_endp = ENDPOINT_NUMBER(endp);
Holger Hans Peter Freytherbd7b3c52010-11-01 21:04:54 +01001060 int out_endp = endp_back_channel(in_endp);
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +08001061
Holger Hans Peter Freytherb54048f2010-11-01 19:57:50 +01001062 if (!endp->is_transcoded)
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +08001063 return;
1064
Holger Hans Peter Freyther8b19dee2010-11-01 22:38:25 +01001065 send_msg(endp, in_endp, endp->trans_bts.local_port, "CRCX", "sendrecv");
1066 send_msg(endp, in_endp, endp->trans_bts.local_port, "MDCX", "sendrecv");
Holger Hans Peter Freyther21262332010-11-01 20:53:31 +01001067 send_msg(endp, out_endp, endp->trans_net.local_port, "CRCX", "sendrecv");
1068 send_msg(endp, out_endp, endp->trans_net.local_port, "MDCX", "sendrecv");
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +08001069
Holger Hans Peter Freytherbd7b3c52010-11-01 21:04:54 +01001070 port = rtp_calculate_port(in_endp, endp->cfg->transcoder_remote_base);
1071 endp->trans_bts.rtp_port = htons(port);
1072 endp->trans_bts.rtcp_port = htons(port + 1);
1073
Holger Hans Peter Freytherb98ba722010-09-19 04:21:39 +08001074 port = rtp_calculate_port(out_endp, endp->cfg->transcoder_remote_base);
Holger Hans Peter Freyther21262332010-11-01 20:53:31 +01001075 endp->trans_net.rtp_port = htons(port);
1076 endp->trans_net.rtcp_port = htons(port + 1);
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +08001077}
1078
1079static void delete_transcoder(struct mgcp_endpoint *endp)
1080{
1081 int in_endp = ENDPOINT_NUMBER(endp);
Holger Hans Peter Freytherbd7b3c52010-11-01 21:04:54 +01001082 int out_endp = endp_back_channel(in_endp);
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +08001083
Holger Hans Peter Freytherb54048f2010-11-01 19:57:50 +01001084 if (!endp->is_transcoded)
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +08001085 return;
1086
1087 send_dlcx(endp, in_endp);
1088 send_dlcx(endp, out_endp);
1089}
Holger Hans Peter Freytherf2eedff2010-09-19 04:36:07 +08001090
1091int mgcp_reset_transcoder(struct mgcp_config *cfg)
1092{
Holger Hans Peter Freytherf2eedff2010-09-19 04:36:07 +08001093 if (!cfg->transcoder_ip)
Holger Hans Peter Freythercf1c8772010-09-24 04:41:28 +08001094 return 0;
Holger Hans Peter Freytherf2eedff2010-09-19 04:36:07 +08001095
1096 static const char mgcp_reset[] = {
1097 "RSIP 1 13@mgw MGCP 1.0\r\n"
1098 };
1099
Holger Hans Peter Freyther557b1ab2010-09-19 04:39:55 +08001100 return send_trans(cfg, mgcp_reset, sizeof mgcp_reset -1);
Holger Hans Peter Freytherf2eedff2010-09-19 04:36:07 +08001101}