blob: c9a9b7fc087a8d564debd8ea279b2d741b690e7c [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
Harald Weltedfe6c7d2010-02-20 16:24:02 +010032#include <osmocore/msgb.h>
33#include <osmocore/talloc.h>
Harald Weltedfe6c7d2010-02-20 16:24:02 +010034#include <osmocore/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
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +010039/**
40 * Macro for tokenizing MGCP messages and SDP in one go.
41 *
42 */
43#define MSG_TOKENIZE_START \
44 line_start = 0; \
45 for (i = 0; i < msgb_l3len(msg); ++i) { \
46 /* we have a line end */ \
47 if (msg->l3h[i] == '\n') { \
48 /* skip the first line */ \
49 if (line_start == 0) { \
50 line_start = i + 1; \
51 continue; \
52 } \
53 \
54 /* check if we have a proper param */ \
55 if (i - line_start == 1 && msg->l3h[line_start] == '\r') { \
56 } else if (i - line_start > 2 \
57 && islower(msg->l3h[line_start]) \
58 && msg->l3h[line_start + 1] == '=') { \
59 } else if (i - line_start < 3 \
60 || msg->l3h[line_start + 1] != ':' \
61 || msg->l3h[line_start + 2] != ' ') \
62 goto error; \
63 \
64 msg->l3h[i] = '\0'; \
65 if (msg->l3h[i-1] == '\r') \
66 msg->l3h[i-1] = '\0';
67
68#define MSG_TOKENIZE_END \
69 line_start = i + 1; \
70 } \
71 }
72
Holger Hans Peter Freytherf138f912010-08-05 08:08:17 +080073static void mgcp_rtp_end_reset(struct mgcp_rtp_end *end);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +010074
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +010075struct mgcp_request {
76 char *name;
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +010077 struct msgb *(*handle_request) (struct mgcp_config *cfg, struct msgb *msg);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +010078 char *debug_name;
79};
80
81#define MGCP_REQUEST(NAME, REQ, DEBUG_NAME) \
82 { .name = NAME, .handle_request = REQ, .debug_name = DEBUG_NAME },
83
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +010084static struct msgb *handle_audit_endpoint(struct mgcp_config *cfg, struct msgb *msg);
85static struct msgb *handle_create_con(struct mgcp_config *cfg, struct msgb *msg);
86static struct msgb *handle_delete_con(struct mgcp_config *cfg, struct msgb *msg);
87static struct msgb *handle_modify_con(struct mgcp_config *cfg, struct msgb *msg);
Holger Hans Peter Freyther9bdcc9c2010-03-31 06:39:35 +020088static struct msgb *handle_rsip(struct mgcp_config *cfg, struct msgb *msg);
Holger Hans Peter Freyther6e94d6d2011-01-25 23:33:54 +010089static struct msgb *handle_noti_req(struct mgcp_config *cfg, struct msgb *msg);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +010090
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +080091static void create_transcoder(struct mgcp_endpoint *endp);
92static void delete_transcoder(struct mgcp_endpoint *endp);
93
Holger Hans Peter Freyther46340132010-08-06 08:26:54 +080094static uint32_t generate_call_id(struct mgcp_config *cfg)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +010095{
96 int i;
97
98 /* use the call id */
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +010099 ++cfg->last_call_id;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100100
101 /* handle wrap around */
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100102 if (cfg->last_call_id == CI_UNUSED)
103 ++cfg->last_call_id;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100104
105 /* callstack can only be of size number_of_endpoints */
106 /* verify that the call id is free, e.g. in case of overrun */
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +0100107 for (i = 1; i < cfg->trunk.number_endpoints; ++i)
108 if (cfg->trunk.endpoints[i].ci == cfg->last_call_id)
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100109 return generate_call_id(cfg);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100110
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100111 return cfg->last_call_id;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100112}
113
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100114/*
115 * array of function pointers for handling various
116 * messages. In the future this might be binary sorted
117 * for performance reasons.
118 */
119static const struct mgcp_request mgcp_requests [] = {
120 MGCP_REQUEST("AUEP", handle_audit_endpoint, "AuditEndpoint")
121 MGCP_REQUEST("CRCX", handle_create_con, "CreateConnection")
122 MGCP_REQUEST("DLCX", handle_delete_con, "DeleteConnection")
123 MGCP_REQUEST("MDCX", handle_modify_con, "ModifiyConnection")
Holger Hans Peter Freyther6e94d6d2011-01-25 23:33:54 +0100124 MGCP_REQUEST("RQNT", handle_noti_req, "NotificationRequest")
Holger Hans Peter Freyther9bdcc9c2010-03-31 06:39:35 +0200125
126 /* SPEC extension */
127 MGCP_REQUEST("RSIP", handle_rsip, "ReSetInProgress")
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100128};
129
Holger Hans Peter Freyther62e836c2010-02-03 11:03:45 +0100130static struct msgb *mgcp_msgb_alloc(void)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100131{
Holger Hans Peter Freyther62e836c2010-02-03 11:03:45 +0100132 struct msgb *msg;
133 msg = msgb_alloc_headroom(4096, 128, "MGCP msg");
134 if (!msg)
135 LOGP(DMGCP, LOGL_ERROR, "Failed to msgb for MGCP data.\n");
136
137 return msg;
138}
139
Holger Hans Peter Freyther6adac172011-01-06 16:19:55 +0100140struct msgb *mgcp_create_response_with_data(int code, const char *txt,
141 const char *msg, const char *trans,
142 const char *data)
Holger Hans Peter Freyther62e836c2010-02-03 11:03:45 +0100143{
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100144 int len;
Holger Hans Peter Freyther62e836c2010-02-03 11:03:45 +0100145 struct msgb *res;
146
147 res = mgcp_msgb_alloc();
148 if (!res)
149 return NULL;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100150
151 if (data) {
Holger Hans Peter Freyther6adac172011-01-06 16:19:55 +0100152 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 +0100153 } else {
Holger Hans Peter Freyther6adac172011-01-06 16:19:55 +0100154 len = snprintf((char *) res->data, 2048, "%d %s%s\r\n", code, trans, txt);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100155 }
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100156
Holger Hans Peter Freyther62e836c2010-02-03 11:03:45 +0100157 res->l2h = msgb_put(res, len);
Holger Hans Peter Freyther63f2db22010-02-26 13:30:57 +0100158 LOGP(DMGCP, LOGL_DEBUG, "Sending response: code: %d for '%s'\n", code, res->l2h);
Holger Hans Peter Freyther62e836c2010-02-03 11:03:45 +0100159 return res;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100160}
161
Holger Hans Peter Freyther6adac172011-01-06 16:19:55 +0100162static struct msgb *create_ok_response(int code, const char *msg, const char *trans)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100163{
Holger Hans Peter Freyther6adac172011-01-06 16:19:55 +0100164 return mgcp_create_response_with_data(code, " OK", msg, trans, NULL);
165}
166
167static struct msgb *create_err_response(int code, const char *msg, const char *trans)
168{
169 return mgcp_create_response_with_data(code, " FAIL", msg, trans, NULL);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100170}
171
Holger Hans Peter Freyther8d188ed2010-02-21 01:44:08 +0100172static struct msgb *create_response_with_sdp(struct mgcp_endpoint *endp,
173 const char *msg, const char *trans_id)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100174{
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100175 const char *addr = endp->cfg->local_ip;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100176 char sdp_record[4096];
177
178 if (!addr)
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100179 addr = endp->cfg->source_addr;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100180
181 snprintf(sdp_record, sizeof(sdp_record) - 1,
Holger Hans Peter Freyther46340132010-08-06 08:26:54 +0800182 "I: %u\n\n"
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100183 "v=0\r\n"
184 "c=IN IP4 %s\r\n"
185 "m=audio %d RTP/AVP %d\r\n"
186 "a=rtpmap:%d %s\r\n",
Holger Hans Peter Freyther58ff2192010-08-05 03:08:35 +0800187 endp->ci, addr, endp->net_end.local_port,
Holger Hans Peter Freythera17d7012010-08-05 01:34:51 +0800188 endp->bts_end.payload_type, endp->bts_end.payload_type,
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +0100189 endp->tcfg->audio_name);
Holger Hans Peter Freyther6adac172011-01-06 16:19:55 +0100190 return mgcp_create_response_with_data(200, " OK", msg, trans_id, sdp_record);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100191}
192
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100193/*
194 * handle incoming messages:
195 * - this can be a command (four letters, space, transaction id)
196 * - or a response (three numbers, space, transaction id)
197 */
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100198struct msgb *mgcp_handle_message(struct mgcp_config *cfg, struct msgb *msg)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100199{
200 int code;
Holger Hans Peter Freyther62e836c2010-02-03 11:03:45 +0100201 struct msgb *resp = NULL;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100202
Holger Hans Peter Freytherf36a11a2010-03-31 13:26:46 +0200203 if (msgb_l2len(msg) < 4) {
Holger Hans Peter Freyther2ada71d2010-02-03 09:13:10 +0100204 LOGP(DMGCP, LOGL_ERROR, "mgs too short: %d\n", msg->len);
Holger Hans Peter Freyther62e836c2010-02-03 11:03:45 +0100205 return NULL;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100206 }
207
208 /* attempt to treat it as a response */
Holger Hans Peter Freytherf36a11a2010-03-31 13:26:46 +0200209 if (sscanf((const char *)&msg->l2h[0], "%3d %*s", &code) == 1) {
Holger Hans Peter Freyther63f2db22010-02-26 13:30:57 +0100210 LOGP(DMGCP, LOGL_DEBUG, "Response: Code: %d\n", code);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100211 } else {
212 int i, handled = 0;
213 msg->l3h = &msg->l2h[4];
214 for (i = 0; i < ARRAY_SIZE(mgcp_requests); ++i)
Holger Hans Peter Freytherf36a11a2010-03-31 13:26:46 +0200215 if (strncmp(mgcp_requests[i].name, (const char *) &msg->l2h[0], 4) == 0) {
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100216 handled = 1;
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100217 resp = mgcp_requests[i].handle_request(cfg, msg);
Holger Hans Peter Freyther62e836c2010-02-03 11:03:45 +0100218 break;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100219 }
220 if (!handled) {
Holger Hans Peter Freytherf36a11a2010-03-31 13:26:46 +0200221 LOGP(DMGCP, LOGL_NOTICE, "MSG with type: '%.4s' not handled\n", &msg->l2h[0]);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100222 }
223 }
224
Holger Hans Peter Freyther62e836c2010-02-03 11:03:45 +0100225 return resp;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100226}
227
228/* string tokenizer for the poor */
229static int find_msg_pointers(struct msgb *msg, struct mgcp_msg_ptr *ptrs, int ptrs_length)
230{
231 int i, found = 0;
232
233 int whitespace = 1;
234 for (i = 0; i < msgb_l3len(msg) && ptrs_length > 0; ++i) {
235 /* if we have a space we found an end */
236 if (msg->l3h[i] == ' ' || msg->l3h[i] == '\r' || msg->l3h[i] == '\n') {
237 if (!whitespace) {
238 ++found;
239 whitespace = 1;
240 ptrs->length = i - ptrs->start - 1;
241 ++ptrs;
242 --ptrs_length;
243 } else {
244 /* skip any number of whitespace */
245 }
246
247 /* line end... stop */
248 if (msg->l3h[i] == '\r' || msg->l3h[i] == '\n')
249 break;
250 } else if (msg->l3h[i] == '\r' || msg->l3h[i] == '\n') {
251 /* line end, be done */
252 break;
253 } else if (whitespace) {
254 whitespace = 0;
255 ptrs->start = i;
256 }
257 }
258
259 if (ptrs_length == 0)
260 return -1;
261 return found;
262}
263
Holger Hans Peter Freyther9f239a22011-01-06 19:32:52 +0100264/**
265 * We have a null terminated string with the endpoint name here. We only
266 * support two kinds. Simple ones as seen on the BSC level and the ones
267 * seen on the trunk side.
268 */
269static struct mgcp_endpoint *find_e1_endpoint(struct mgcp_config *cfg,
270 const char *mgcp)
271{
272 char *rest = NULL;
Holger Hans Peter Freyther74e61112011-02-28 14:13:47 +0100273 struct mgcp_trunk_config *tcfg;
274 int trunk, endp;
Holger Hans Peter Freyther9f239a22011-01-06 19:32:52 +0100275
276 trunk = strtoul(mgcp + 6, &rest, 10);
Holger Hans Peter Freytherf43f2fc2011-01-07 11:30:21 +0100277 if (rest == NULL || rest[0] != '/' || trunk < 1) {
Holger Hans Peter Freyther9f239a22011-01-06 19:32:52 +0100278 LOGP(DMGCP, LOGL_ERROR, "Wrong trunk name '%s'\n", mgcp);
279 return NULL;
280 }
281
282 endp = strtoul(rest + 1, &rest, 10);
283 if (rest == NULL || rest[0] != '@') {
Holger Hans Peter Freytherf43f2fc2011-01-07 11:30:21 +0100284 LOGP(DMGCP, LOGL_ERROR, "Wrong endpoint name '%s'\n", mgcp);
Holger Hans Peter Freyther9f239a22011-01-06 19:32:52 +0100285 return NULL;
286 }
287
288 /* signalling is on timeslot 1 */
289 if (endp == 1)
290 return NULL;
291
Holger Hans Peter Freyther74e61112011-02-28 14:13:47 +0100292 tcfg = mgcp_trunk_num(cfg, trunk);
293 if (!tcfg) {
294 LOGP(DMGCP, LOGL_ERROR, "The trunk %d is not declared.\n", trunk);
295 return NULL;
296 }
297
298 if (!tcfg->endpoints) {
299 LOGP(DMGCP, LOGL_ERROR, "Endpoints of trunk %d not allocated.\n", trunk);
300 return NULL;
301 }
302
303 if (endp < 1 || endp >= tcfg->number_endpoints) {
Holger Hans Peter Freyther9f239a22011-01-06 19:32:52 +0100304 LOGP(DMGCP, LOGL_ERROR, "Failed to find endpoint '%s'\n", mgcp);
Holger Hans Peter Freyther45c21842011-01-07 11:36:54 +0100305 return NULL;
Holger Hans Peter Freyther9f239a22011-01-06 19:32:52 +0100306 }
307
Holger Hans Peter Freyther74e61112011-02-28 14:13:47 +0100308 return &tcfg->endpoints[endp];
Holger Hans Peter Freyther9f239a22011-01-06 19:32:52 +0100309}
310
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100311static struct mgcp_endpoint *find_endpoint(struct mgcp_config *cfg, const char *mgcp)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100312{
313 char *endptr = NULL;
314 unsigned int gw = INT_MAX;
315
Holger Hans Peter Freyther9f239a22011-01-06 19:32:52 +0100316 if (strncmp(mgcp, "ds/e1", 5) == 0) {
317 return find_e1_endpoint(cfg, mgcp);
318 } else {
319 gw = strtoul(mgcp, &endptr, 16);
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +0100320 if (gw > 0 && gw < cfg->trunk.number_endpoints && strcmp(endptr, "@mgw") == 0)
321 return &cfg->trunk.endpoints[gw];
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100322 }
323
Holger Hans Peter Freyther9f239a22011-01-06 19:32:52 +0100324 LOGP(DMGCP, LOGL_ERROR, "Not able to find endpoint: '%s'\n", mgcp);
325 return NULL;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100326}
327
Holger Hans Peter Freytherf2f15912010-04-01 03:27:04 +0200328int mgcp_analyze_header(struct mgcp_config *cfg, struct msgb *msg,
329 struct mgcp_msg_ptr *ptr, int size,
330 const char **transaction_id, struct mgcp_endpoint **endp)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100331{
332 int found;
333
Holger Hans Peter Freythera820c5f2010-02-26 13:32:55 +0100334 *transaction_id = "000000";
335
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100336 if (size < 3) {
Holger Hans Peter Freyther2ada71d2010-02-03 09:13:10 +0100337 LOGP(DMGCP, LOGL_ERROR, "Not enough space in ptr\n");
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100338 return -1;
339 }
340
341 found = find_msg_pointers(msg, ptr, size);
342
Holger Hans Peter Freythera820c5f2010-02-26 13:32:55 +0100343 if (found <= 3) {
Holger Hans Peter Freyther2ada71d2010-02-03 09:13:10 +0100344 LOGP(DMGCP, LOGL_ERROR, "Gateway: Not enough params. Found: %d\n", found);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100345 return -1;
346 }
347
348 /*
349 * replace the space with \0. the main method gurantess that
350 * we still have + 1 for null termination
351 */
352 msg->l3h[ptr[3].start + ptr[3].length + 1] = '\0';
353 msg->l3h[ptr[2].start + ptr[2].length + 1] = '\0';
354 msg->l3h[ptr[1].start + ptr[1].length + 1] = '\0';
355 msg->l3h[ptr[0].start + ptr[0].length + 1] = '\0';
356
357 if (strncmp("1.0", (const char *)&msg->l3h[ptr[3].start], 3) != 0
358 || strncmp("MGCP", (const char *)&msg->l3h[ptr[2].start], 4) != 0) {
Holger Hans Peter Freyther2ada71d2010-02-03 09:13:10 +0100359 LOGP(DMGCP, LOGL_ERROR, "Wrong MGCP version. Not handling: '%s' '%s'\n",
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100360 (const char *)&msg->l3h[ptr[3].start],
361 (const char *)&msg->l3h[ptr[2].start]);
362 return -1;
363 }
364
365 *transaction_id = (const char *)&msg->l3h[ptr[0].start];
Holger Hans Peter Freytherf2f15912010-04-01 03:27:04 +0200366 if (endp) {
367 *endp = find_endpoint(cfg, (const char *)&msg->l3h[ptr[1].start]);
368 return *endp == NULL;
369 }
370 return 0;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100371}
372
373static int verify_call_id(const struct mgcp_endpoint *endp,
374 const char *callid)
375{
376 if (strcmp(endp->callid, callid) != 0) {
Holger Hans Peter Freyther2ada71d2010-02-03 09:13:10 +0100377 LOGP(DMGCP, LOGL_ERROR, "CallIDs does not match on 0x%x. '%s' != '%s'\n",
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100378 ENDPOINT_NUMBER(endp), endp->callid, callid);
379 return -1;
380 }
381
382 return 0;
383}
384
385static int verify_ci(const struct mgcp_endpoint *endp,
Holger Hans Peter Freyther46340132010-08-06 08:26:54 +0800386 const char *_ci)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100387{
Holger Hans Peter Freyther46340132010-08-06 08:26:54 +0800388 uint32_t ci = strtoul(_ci, NULL, 10);
389
390 if (ci != endp->ci) {
391 LOGP(DMGCP, LOGL_ERROR, "ConnectionIdentifiers do not match on 0x%x. %u != %s\n",
392 ENDPOINT_NUMBER(endp), endp->ci, _ci);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100393 return -1;
394 }
395
396 return 0;
397}
398
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100399static struct msgb *handle_audit_endpoint(struct mgcp_config *cfg, struct msgb *msg)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100400{
401 struct mgcp_msg_ptr data_ptrs[6];
Holger Hans Peter Freyther6adac172011-01-06 16:19:55 +0100402 int found;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100403 const char *trans_id;
404 struct mgcp_endpoint *endp;
405
Holger Hans Peter Freytherf2f15912010-04-01 03:27:04 +0200406 found = mgcp_analyze_header(cfg, msg, data_ptrs, ARRAY_SIZE(data_ptrs), &trans_id, &endp);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100407 if (found != 0)
Holger Hans Peter Freyther6adac172011-01-06 16:19:55 +0100408 return create_err_response(500, "AUEP", trans_id);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100409 else
Holger Hans Peter Freyther6adac172011-01-06 16:19:55 +0100410 return create_ok_response(200, "AUEP", trans_id);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100411}
412
Holger Hans Peter Freytheradb6e1c2010-09-18 06:44:24 +0800413static int parse_conn_mode(const char *msg, int *conn_mode)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100414{
415 int ret = 0;
416 if (strcmp(msg, "recvonly") == 0)
417 *conn_mode = MGCP_CONN_RECV_ONLY;
418 else if (strcmp(msg, "sendrecv") == 0)
419 *conn_mode = MGCP_CONN_RECV_SEND;
Holger Hans Peter Freythere02860a2010-09-18 20:21:44 +0800420 else if (strcmp(msg, "sendonly") == 0)
421 *conn_mode = MGCP_CONN_SEND_ONLY;
Holger Hans Peter Freyther98a38772010-08-03 02:27:21 +0800422 else if (strcmp(msg, "loopback") == 0)
423 *conn_mode = MGCP_CONN_LOOPBACK;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100424 else {
Holger Hans Peter Freyther2ada71d2010-02-03 09:13:10 +0100425 LOGP(DMGCP, LOGL_ERROR, "Unknown connection mode: '%s'\n", msg);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100426 ret = -1;
427 }
428
429 return ret;
430}
431
Holger Hans Peter Freytherf138f912010-08-05 08:08:17 +0800432static int allocate_port(struct mgcp_endpoint *endp, struct mgcp_rtp_end *end,
Holger Hans Peter Freyther218f8562010-09-18 02:30:02 +0800433 struct mgcp_port_range *range,
434 int (*alloc)(struct mgcp_endpoint *endp, int port))
Holger Hans Peter Freytherf138f912010-08-05 08:08:17 +0800435{
436 int i;
437
438 if (range->mode == PORT_ALLOC_STATIC) {
Holger Hans Peter Freytherf138f912010-08-05 08:08:17 +0800439 end->local_alloc = PORT_ALLOC_STATIC;
440 return 0;
441 }
442
443 /* attempt to find a port */
444 for (i = 0; i < 200; ++i) {
445 int rc;
446
447 if (range->last_port >= range->range_end)
448 range->last_port = range->range_start;
449
Holger Hans Peter Freyther218f8562010-09-18 02:30:02 +0800450 rc = alloc(endp, range->last_port);
Holger Hans Peter Freytherf138f912010-08-05 08:08:17 +0800451
452 range->last_port += 2;
453 if (rc == 0) {
454 end->local_alloc = PORT_ALLOC_DYNAMIC;
455 return 0;
456 }
457
458 }
459
Holger Hans Peter Freyther218f8562010-09-18 02:30:02 +0800460 LOGP(DMGCP, LOGL_ERROR, "Allocating a RTP/RTCP port failed 200 times 0x%x.\n",
461 ENDPOINT_NUMBER(endp));
Holger Hans Peter Freytherf138f912010-08-05 08:08:17 +0800462 return -1;
463}
464
465static int allocate_ports(struct mgcp_endpoint *endp)
466{
Holger Hans Peter Freyther218f8562010-09-18 02:30:02 +0800467 if (allocate_port(endp, &endp->net_end, &endp->cfg->net_ports,
468 mgcp_bind_net_rtp_port) != 0)
Holger Hans Peter Freytherf138f912010-08-05 08:08:17 +0800469 return -1;
470
Holger Hans Peter Freyther218f8562010-09-18 02:30:02 +0800471 if (allocate_port(endp, &endp->bts_end, &endp->cfg->bts_ports,
472 mgcp_bind_bts_rtp_port) != 0) {
Holger Hans Peter Freytherf138f912010-08-05 08:08:17 +0800473 mgcp_rtp_end_reset(&endp->net_end);
474 return -1;
475 }
476
Holger Hans Peter Freyther69906872011-02-28 14:51:48 +0100477 if (endp->cfg->transcoder_ip && endp->tcfg->trunk_type == MGCP_TRUNK_VIRTUAL) {
Holger Hans Peter Freyther21262332010-11-01 20:53:31 +0100478 if (allocate_port(endp, &endp->trans_net,
Holger Hans Peter Freytherb54048f2010-11-01 19:57:50 +0100479 &endp->cfg->transcoder_ports,
Holger Hans Peter Freytherbd7b3c52010-11-01 21:04:54 +0100480 mgcp_bind_trans_net_rtp_port) != 0) {
Holger Hans Peter Freytherb54048f2010-11-01 19:57:50 +0100481 mgcp_rtp_end_reset(&endp->net_end);
482 mgcp_rtp_end_reset(&endp->bts_end);
483 return -1;
484 }
485
Holger Hans Peter Freytherbd7b3c52010-11-01 21:04:54 +0100486 if (allocate_port(endp, &endp->trans_bts,
487 &endp->cfg->transcoder_ports,
488 mgcp_bind_trans_bts_rtp_port) != 0) {
489 mgcp_rtp_end_reset(&endp->net_end);
490 mgcp_rtp_end_reset(&endp->bts_end);
491 mgcp_rtp_end_reset(&endp->trans_net);
492 return -1;
493 }
494
Holger Hans Peter Freytherb54048f2010-11-01 19:57:50 +0100495 /* remember that we have set up transcoding */
496 endp->is_transcoded = 1;
Holger Hans Peter Freyther218f8562010-09-18 02:30:02 +0800497 }
498
Holger Hans Peter Freytherf138f912010-08-05 08:08:17 +0800499 return 0;
500}
501
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100502static struct msgb *handle_create_con(struct mgcp_config *cfg, struct msgb *msg)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100503{
504 struct mgcp_msg_ptr data_ptrs[6];
505 int found, i, line_start;
506 const char *trans_id;
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +0100507 struct mgcp_trunk_config *tcfg;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100508 struct mgcp_endpoint *endp;
Holger Hans Peter Freyther9e9392d2010-08-08 16:24:48 +0800509 int error_code = 400;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100510
Holger Hans Peter Freytherf2f15912010-04-01 03:27:04 +0200511 found = mgcp_analyze_header(cfg, msg, data_ptrs, ARRAY_SIZE(data_ptrs), &trans_id, &endp);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100512 if (found != 0)
Holger Hans Peter Freyther6adac172011-01-06 16:19:55 +0100513 return create_err_response(510, "CRCX", trans_id);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100514
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +0100515 tcfg = endp->tcfg;
516
Holger Hans Peter Freyther39a97e22010-08-06 18:03:11 +0800517 if (endp->allocated) {
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +0100518 if (tcfg->force_realloc) {
Holger Hans Peter Freyther408cc4a2010-04-07 10:51:27 +0200519 LOGP(DMGCP, LOGL_NOTICE, "Endpoint 0x%x already allocated. Forcing realloc.\n",
520 ENDPOINT_NUMBER(endp));
Holger Hans Peter Freyther32d4e502010-04-24 21:02:48 +0800521 mgcp_free_endp(endp);
Holger Hans Peter Freyther869e38e2010-08-06 17:54:27 +0800522 if (cfg->realloc_cb)
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +0100523 cfg->realloc_cb(tcfg, ENDPOINT_NUMBER(endp));
Holger Hans Peter Freyther408cc4a2010-04-07 10:51:27 +0200524 } else {
525 LOGP(DMGCP, LOGL_ERROR, "Endpoint is already used. 0x%x\n",
526 ENDPOINT_NUMBER(endp));
Holger Hans Peter Freyther6adac172011-01-06 16:19:55 +0100527 return create_err_response(400, "CRCX", trans_id);
Holger Hans Peter Freyther408cc4a2010-04-07 10:51:27 +0200528 }
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100529 }
530
531 /* parse CallID C: and LocalParameters L: */
532 MSG_TOKENIZE_START
533 switch (msg->l3h[line_start]) {
534 case 'L':
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +0100535 endp->local_options = talloc_strdup(tcfg->endpoints,
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100536 (const char *)&msg->l3h[line_start + 3]);
537 break;
538 case 'C':
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +0100539 endp->callid = talloc_strdup(tcfg->endpoints,
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100540 (const char *)&msg->l3h[line_start + 3]);
541 break;
542 case 'M':
543 if (parse_conn_mode((const char *)&msg->l3h[line_start + 3],
544 &endp->conn_mode) != 0) {
545 error_code = 517;
546 goto error2;
547 }
Holger Hans Peter Freytherc597a4e2010-08-03 02:57:02 +0800548
549 endp->orig_mode = endp->conn_mode;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100550 break;
551 default:
Holger Hans Peter Freyther2ada71d2010-02-03 09:13:10 +0100552 LOGP(DMGCP, LOGL_NOTICE, "Unhandled option: '%c'/%d on 0x%x\n",
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100553 msg->l3h[line_start], msg->l3h[line_start],
554 ENDPOINT_NUMBER(endp));
555 break;
556 }
557 MSG_TOKENIZE_END
558
559 /* initialize */
Holger Hans Peter Freythera17d7012010-08-05 01:34:51 +0800560 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 +0100561
562 /* set to zero until we get the info */
Holger Hans Peter Freythera17d7012010-08-05 01:34:51 +0800563 memset(&endp->net_end.addr, 0, sizeof(endp->net_end.addr));
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100564
565 /* bind to the port now */
Holger Hans Peter Freytherf138f912010-08-05 08:08:17 +0800566 if (allocate_ports(endp) != 0)
567 goto error2;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100568
569 /* assign a local call identifier or fail */
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100570 endp->ci = generate_call_id(cfg);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100571 if (endp->ci == CI_UNUSED)
572 goto error2;
573
Holger Hans Peter Freyther39a97e22010-08-06 18:03:11 +0800574 endp->allocated = 1;
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +0100575 endp->bts_end.payload_type = tcfg->audio_payload;
Holger Hans Peter Freytheref6bb252010-02-26 13:41:22 +0100576
Holger Hans Peter Freytherfe86d3c2010-02-26 13:37:05 +0100577 /* policy CB */
578 if (cfg->policy_cb) {
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +0100579 switch (cfg->policy_cb(tcfg, ENDPOINT_NUMBER(endp), MGCP_ENDP_CRCX, trans_id)) {
Holger Hans Peter Freytherfe86d3c2010-02-26 13:37:05 +0100580 case MGCP_POLICY_REJECT:
581 LOGP(DMGCP, LOGL_NOTICE, "CRCX rejected by policy on 0x%x\n",
582 ENDPOINT_NUMBER(endp));
583 mgcp_free_endp(endp);
Holger Hans Peter Freyther6adac172011-01-06 16:19:55 +0100584 return create_err_response(400, "CRCX", trans_id);
Holger Hans Peter Freytherfe86d3c2010-02-26 13:37:05 +0100585 break;
586 case MGCP_POLICY_DEFER:
587 /* stop processing */
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +0800588 create_transcoder(endp);
Holger Hans Peter Freytherfe86d3c2010-02-26 13:37:05 +0100589 return NULL;
590 break;
591 case MGCP_POLICY_CONT:
592 /* just continue */
593 break;
594 }
595 }
596
Holger Hans Peter Freythere378cb12010-08-06 20:22:23 +0800597 LOGP(DMGCP, LOGL_DEBUG, "Creating endpoint on: 0x%x CI: %u port: %u/%u\n",
Holger Hans Peter Freyther58ff2192010-08-05 03:08:35 +0800598 ENDPOINT_NUMBER(endp), endp->ci,
599 endp->net_end.local_port, endp->bts_end.local_port);
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100600 if (cfg->change_cb)
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +0100601 cfg->change_cb(tcfg, ENDPOINT_NUMBER(endp), MGCP_ENDP_CRCX);
Holger Hans Peter Freyther77f7afe2010-02-03 09:54:43 +0100602
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +0800603 create_transcoder(endp);
Holger Hans Peter Freyther8d188ed2010-02-21 01:44:08 +0100604 return create_response_with_sdp(endp, "CRCX", trans_id);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100605error:
Holger Hans Peter Freyther2ada71d2010-02-03 09:13:10 +0100606 LOGP(DMGCP, LOGL_ERROR, "Malformed line: %s on 0x%x with: line_start: %d %d\n",
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100607 hexdump(msg->l3h, msgb_l3len(msg)),
608 ENDPOINT_NUMBER(endp), line_start, i);
Holger Hans Peter Freyther6adac172011-01-06 16:19:55 +0100609 return create_err_response(error_code, "CRCX", trans_id);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100610
611error2:
Holger Hans Peter Freyther414bf402010-08-06 07:05:13 +0800612 mgcp_free_endp(endp);
Holger Hans Peter Freyther2ada71d2010-02-03 09:13:10 +0100613 LOGP(DMGCP, LOGL_NOTICE, "Resource error on 0x%x\n", ENDPOINT_NUMBER(endp));
Holger Hans Peter Freyther6adac172011-01-06 16:19:55 +0100614 return create_err_response(error_code, "CRCX", trans_id);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100615}
616
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100617static struct msgb *handle_modify_con(struct mgcp_config *cfg, struct msgb *msg)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100618{
619 struct mgcp_msg_ptr data_ptrs[6];
620 int found, i, line_start;
621 const char *trans_id;
622 struct mgcp_endpoint *endp;
623 int error_code = 500;
Holger Hans Peter Freythere3d16bb2010-04-22 11:58:13 +0800624 int silent = 0;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100625
Holger Hans Peter Freytherf2f15912010-04-01 03:27:04 +0200626 found = mgcp_analyze_header(cfg, msg, data_ptrs, ARRAY_SIZE(data_ptrs), &trans_id, &endp);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100627 if (found != 0)
Holger Hans Peter Freyther6adac172011-01-06 16:19:55 +0100628 return create_err_response(510, "MDCX", trans_id);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100629
630 if (endp->ci == CI_UNUSED) {
Holger Hans Peter Freyther2ada71d2010-02-03 09:13:10 +0100631 LOGP(DMGCP, LOGL_ERROR, "Endpoint is not holding a connection. 0x%x\n", ENDPOINT_NUMBER(endp));
Holger Hans Peter Freyther6adac172011-01-06 16:19:55 +0100632 return create_err_response(400, "MDCX", trans_id);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100633 }
634
635 MSG_TOKENIZE_START
636 switch (msg->l3h[line_start]) {
637 case 'C': {
638 if (verify_call_id(endp, (const char *)&msg->l3h[line_start + 3]) != 0)
639 goto error3;
640 break;
641 }
642 case 'I': {
643 if (verify_ci(endp, (const char *)&msg->l3h[line_start + 3]) != 0)
644 goto error3;
645 break;
646 }
647 case 'L':
648 /* skip */
649 break;
650 case 'M':
651 if (parse_conn_mode((const char *)&msg->l3h[line_start + 3],
652 &endp->conn_mode) != 0) {
653 error_code = 517;
654 goto error3;
655 }
Holger Hans Peter Freytherc597a4e2010-08-03 02:57:02 +0800656 endp->orig_mode = endp->conn_mode;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100657 break;
Holger Hans Peter Freythere3d16bb2010-04-22 11:58:13 +0800658 case 'Z':
659 silent = strcmp("noanswer", (const char *)&msg->l3h[line_start + 3]) == 0;
660 break;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100661 case '\0':
662 /* SDP file begins */
663 break;
664 case 'a':
665 case 'o':
666 case 's':
667 case 't':
668 case 'v':
669 /* skip these SDP attributes */
670 break;
671 case 'm': {
672 int port;
Holger Hans Peter Freytheref6bb252010-02-26 13:41:22 +0100673 int payload;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100674 const char *param = (const char *)&msg->l3h[line_start];
675
Holger Hans Peter Freytheref6bb252010-02-26 13:41:22 +0100676 if (sscanf(param, "m=audio %d RTP/AVP %d", &port, &payload) == 2) {
Holger Hans Peter Freythera17d7012010-08-05 01:34:51 +0800677 endp->net_end.rtp_port = htons(port);
678 endp->net_end.rtcp_port = htons(port + 1);
679 endp->net_end.payload_type = payload;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100680 }
681 break;
682 }
683 case 'c': {
684 char ipv4[16];
685 const char *param = (const char *)&msg->l3h[line_start];
686
687 if (sscanf(param, "c=IN IP4 %15s", ipv4) == 1) {
Holger Hans Peter Freythera17d7012010-08-05 01:34:51 +0800688 inet_aton(ipv4, &endp->net_end.addr);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100689 }
690 break;
691 }
692 default:
Holger Hans Peter Freyther2ada71d2010-02-03 09:13:10 +0100693 LOGP(DMGCP, LOGL_NOTICE, "Unhandled option: '%c'/%d on 0x%x\n",
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100694 msg->l3h[line_start], msg->l3h[line_start],
695 ENDPOINT_NUMBER(endp));
696 break;
697 }
698 MSG_TOKENIZE_END
699
Holger Hans Peter Freytherfe86d3c2010-02-26 13:37:05 +0100700 /* policy CB */
701 if (cfg->policy_cb) {
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +0100702 switch (cfg->policy_cb(endp->tcfg, ENDPOINT_NUMBER(endp), MGCP_ENDP_MDCX, trans_id)) {
Holger Hans Peter Freytherfe86d3c2010-02-26 13:37:05 +0100703 case MGCP_POLICY_REJECT:
704 LOGP(DMGCP, LOGL_NOTICE, "MDCX rejected by policy on 0x%x\n",
705 ENDPOINT_NUMBER(endp));
Holger Hans Peter Freythere3d16bb2010-04-22 11:58:13 +0800706 if (silent)
707 goto out_silent;
Holger Hans Peter Freyther6adac172011-01-06 16:19:55 +0100708 return create_err_response(400, "MDCX", trans_id);
Holger Hans Peter Freytherfe86d3c2010-02-26 13:37:05 +0100709 break;
710 case MGCP_POLICY_DEFER:
711 /* stop processing */
712 return NULL;
713 break;
714 case MGCP_POLICY_CONT:
715 /* just continue */
716 break;
717 }
718 }
719
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100720 /* modify */
Holger Hans Peter Freythere378cb12010-08-06 20:22:23 +0800721 LOGP(DMGCP, LOGL_DEBUG, "Modified endpoint on: 0x%x Server: %s:%u\n",
Holger Hans Peter Freythera17d7012010-08-05 01:34:51 +0800722 ENDPOINT_NUMBER(endp), inet_ntoa(endp->net_end.addr), ntohs(endp->net_end.rtp_port));
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100723 if (cfg->change_cb)
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +0100724 cfg->change_cb(endp->tcfg, ENDPOINT_NUMBER(endp), MGCP_ENDP_MDCX);
Holger Hans Peter Freythere3d16bb2010-04-22 11:58:13 +0800725 if (silent)
726 goto out_silent;
727
Holger Hans Peter Freyther8d188ed2010-02-21 01:44:08 +0100728 return create_response_with_sdp(endp, "MDCX", trans_id);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100729
730error:
Holger Hans Peter Freyther2ada71d2010-02-03 09:13:10 +0100731 LOGP(DMGCP, LOGL_ERROR, "Malformed line: %s on 0x%x with: line_start: %d %d %d\n",
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100732 hexdump(msg->l3h, msgb_l3len(msg)),
733 ENDPOINT_NUMBER(endp), line_start, i, msg->l3h[line_start]);
Holger Hans Peter Freyther6adac172011-01-06 16:19:55 +0100734 return create_err_response(error_code, "MDCX", trans_id);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100735
736error3:
Holger Hans Peter Freyther6adac172011-01-06 16:19:55 +0100737 return create_err_response(error_code, "MDCX", trans_id);
Holger Hans Peter Freythere3d16bb2010-04-22 11:58:13 +0800738
739
740out_silent:
741 return NULL;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100742}
743
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100744static struct msgb *handle_delete_con(struct mgcp_config *cfg, struct msgb *msg)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100745{
746 struct mgcp_msg_ptr data_ptrs[6];
747 int found, i, line_start;
748 const char *trans_id;
749 struct mgcp_endpoint *endp;
Holger Hans Peter Freyther9e9392d2010-08-08 16:24:48 +0800750 int error_code = 400;
Holger Hans Peter Freythere3d16bb2010-04-22 11:58:13 +0800751 int silent = 0;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100752
Holger Hans Peter Freytherf2f15912010-04-01 03:27:04 +0200753 found = mgcp_analyze_header(cfg, msg, data_ptrs, ARRAY_SIZE(data_ptrs), &trans_id, &endp);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100754 if (found != 0)
Holger Hans Peter Freyther6adac172011-01-06 16:19:55 +0100755 return create_err_response(error_code, "DLCX", trans_id);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100756
Holger Hans Peter Freyther39a97e22010-08-06 18:03:11 +0800757 if (!endp->allocated) {
Holger Hans Peter Freyther2ada71d2010-02-03 09:13:10 +0100758 LOGP(DMGCP, LOGL_ERROR, "Endpoint is not used. 0x%x\n", ENDPOINT_NUMBER(endp));
Holger Hans Peter Freyther6adac172011-01-06 16:19:55 +0100759 return create_err_response(400, "DLCX", trans_id);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100760 }
761
762 MSG_TOKENIZE_START
763 switch (msg->l3h[line_start]) {
764 case 'C': {
765 if (verify_call_id(endp, (const char *)&msg->l3h[line_start + 3]) != 0)
766 goto error3;
767 break;
768 }
769 case 'I': {
770 if (verify_ci(endp, (const char *)&msg->l3h[line_start + 3]) != 0)
771 goto error3;
772 break;
Holger Hans Peter Freythere3d16bb2010-04-22 11:58:13 +0800773 case 'Z':
774 silent = strcmp("noanswer", (const char *)&msg->l3h[line_start + 3]) == 0;
775 break;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100776 }
777 default:
Holger Hans Peter Freyther2ada71d2010-02-03 09:13:10 +0100778 LOGP(DMGCP, LOGL_NOTICE, "Unhandled option: '%c'/%d on 0x%x\n",
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100779 msg->l3h[line_start], msg->l3h[line_start],
780 ENDPOINT_NUMBER(endp));
781 break;
782 }
783 MSG_TOKENIZE_END
784
Holger Hans Peter Freytherfe86d3c2010-02-26 13:37:05 +0100785 /* policy CB */
786 if (cfg->policy_cb) {
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +0100787 switch (cfg->policy_cb(endp->tcfg, ENDPOINT_NUMBER(endp), MGCP_ENDP_DLCX, trans_id)) {
Holger Hans Peter Freytherfe86d3c2010-02-26 13:37:05 +0100788 case MGCP_POLICY_REJECT:
789 LOGP(DMGCP, LOGL_NOTICE, "DLCX rejected by policy on 0x%x\n",
790 ENDPOINT_NUMBER(endp));
Holger Hans Peter Freythere3d16bb2010-04-22 11:58:13 +0800791 if (silent)
792 goto out_silent;
Holger Hans Peter Freyther6adac172011-01-06 16:19:55 +0100793 return create_err_response(400, "DLCX", trans_id);
Holger Hans Peter Freytherfe86d3c2010-02-26 13:37:05 +0100794 break;
795 case MGCP_POLICY_DEFER:
796 /* stop processing */
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +0800797 delete_transcoder(endp);
Holger Hans Peter Freytherfe86d3c2010-02-26 13:37:05 +0100798 return NULL;
799 break;
800 case MGCP_POLICY_CONT:
801 /* just continue */
802 break;
803 }
804 }
805
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100806 /* free the connection */
Holger Hans Peter Freythere378cb12010-08-06 20:22:23 +0800807 LOGP(DMGCP, LOGL_DEBUG, "Deleted endpoint on: 0x%x Server: %s:%u\n",
Holger Hans Peter Freythera17d7012010-08-05 01:34:51 +0800808 ENDPOINT_NUMBER(endp), inet_ntoa(endp->net_end.addr), ntohs(endp->net_end.rtp_port));
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +0800809
810 delete_transcoder(endp);
Holger Hans Peter Freyther154b9552010-02-26 13:27:51 +0100811 mgcp_free_endp(endp);
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100812 if (cfg->change_cb)
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +0100813 cfg->change_cb(endp->tcfg, ENDPOINT_NUMBER(endp), MGCP_ENDP_DLCX);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100814
Holger Hans Peter Freythere3d16bb2010-04-22 11:58:13 +0800815 if (silent)
816 goto out_silent;
Holger Hans Peter Freyther6adac172011-01-06 16:19:55 +0100817 return create_ok_response(250, "DLCX", trans_id);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100818
819error:
Holger Hans Peter Freyther2ada71d2010-02-03 09:13:10 +0100820 LOGP(DMGCP, LOGL_ERROR, "Malformed line: %s on 0x%x with: line_start: %d %d\n",
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100821 hexdump(msg->l3h, msgb_l3len(msg)),
822 ENDPOINT_NUMBER(endp), line_start, i);
Holger Hans Peter Freyther6adac172011-01-06 16:19:55 +0100823 return create_err_response(error_code, "DLCX", trans_id);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100824
825error3:
Holger Hans Peter Freyther6adac172011-01-06 16:19:55 +0100826 return create_err_response(error_code, "DLCX", trans_id);
Holger Hans Peter Freythere3d16bb2010-04-22 11:58:13 +0800827
828out_silent:
829 return NULL;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100830}
831
Holger Hans Peter Freyther9bdcc9c2010-03-31 06:39:35 +0200832static struct msgb *handle_rsip(struct mgcp_config *cfg, struct msgb *msg)
833{
834 if (cfg->reset_cb)
835 cfg->reset_cb(cfg);
836 return NULL;
837}
838
Holger Hans Peter Freyther6e94d6d2011-01-25 23:33:54 +0100839/*
840 * This can request like DTMF detection and forward, fax detection... it
841 * can also request when the notification should be send and such. We don't
842 * do this right now.
843 */
844static struct msgb *handle_noti_req(struct mgcp_config *cfg, struct msgb *msg)
845{
846 struct mgcp_msg_ptr data_ptrs[6];
847 const char *trans_id;
848 struct mgcp_endpoint *endp;
849 int found;
850
851 found = mgcp_analyze_header(cfg, msg, data_ptrs, ARRAY_SIZE(data_ptrs), &trans_id, &endp);
852 if (found != 0)
853 return create_err_response(400, "RQNT", trans_id);
854
855 if (!endp->allocated) {
856 LOGP(DMGCP, LOGL_ERROR, "Endpoint is not used. 0x%x\n", ENDPOINT_NUMBER(endp));
857 return create_err_response(400, "RQNT", trans_id);
858 }
859 return create_ok_response(200, "RQNT", trans_id);
860}
861
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100862struct mgcp_config *mgcp_config_alloc(void)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100863{
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100864 struct mgcp_config *cfg;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100865
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100866 cfg = talloc_zero(NULL, struct mgcp_config);
867 if (!cfg) {
868 LOGP(DMGCP, LOGL_FATAL, "Failed to allocate config.\n");
869 return NULL;
870 }
871
872 cfg->source_port = 2427;
873 cfg->source_addr = talloc_strdup(cfg, "0.0.0.0");
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +0100874
Holger Hans Peter Freytherb98ba722010-09-19 04:21:39 +0800875 cfg->transcoder_remote_base = 4000;
Holger Hans Peter Freyther15e73892010-08-05 07:10:56 +0800876
877 cfg->bts_ports.base_port = RTP_PORT_DEFAULT;
878 cfg->net_ports.base_port = RTP_PORT_NET_DEFAULT;
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100879
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +0100880 /* default trunk handling */
881 cfg->trunk.cfg = cfg;
882 cfg->trunk.trunk_nr = 0;
883 cfg->trunk.trunk_type = MGCP_TRUNK_VIRTUAL;
884 cfg->trunk.audio_name = talloc_strdup(cfg, "AMR/8000");
885 cfg->trunk.audio_payload = 126;
886
Holger Hans Peter Freyther0e939fe2011-02-28 12:11:02 +0100887 INIT_LLIST_HEAD(&cfg->trunks);
888
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100889 return cfg;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100890}
891
Holger Hans Peter Freyther0e939fe2011-02-28 12:11:02 +0100892struct mgcp_trunk_config *mgcp_trunk_alloc(struct mgcp_config *cfg, int nr)
893{
894 struct mgcp_trunk_config *trunk;
895
896 trunk = talloc_zero(cfg, struct mgcp_trunk_config);
897 if (!trunk) {
898 LOGP(DMGCP, LOGL_ERROR, "Failed to allocate.\n");
899 return NULL;
900 }
901
902 trunk->cfg = cfg;
903 trunk->trunk_type = MGCP_TRUNK_E1;
904 trunk->trunk_nr = nr;
905 trunk->audio_name = talloc_strdup(cfg, "AMR/8000");
906 trunk->audio_payload = 126;
907 trunk->number_endpoints = 33;
908 llist_add_tail(&trunk->entry, &cfg->trunks);
909 return trunk;
910}
911
912struct mgcp_trunk_config *mgcp_trunk_num(struct mgcp_config *cfg, int index)
913{
914 struct mgcp_trunk_config *trunk;
915
916 llist_for_each_entry(trunk, &cfg->trunks, entry)
917 if (trunk->trunk_nr == index)
918 return trunk;
919
920 return NULL;
921}
922
Holger Hans Peter Freythera17d7012010-08-05 01:34:51 +0800923static void mgcp_rtp_end_reset(struct mgcp_rtp_end *end)
924{
Holger Hans Peter Freythere97155a2010-11-02 19:06:13 +0100925 if (end->local_alloc == PORT_ALLOC_DYNAMIC) {
Holger Hans Peter Freytherf138f912010-08-05 08:08:17 +0800926 mgcp_free_rtp_port(end);
Holger Hans Peter Freythere97155a2010-11-02 19:06:13 +0100927 end->local_port = 0;
928 }
Holger Hans Peter Freytherf138f912010-08-05 08:08:17 +0800929
Holger Hans Peter Freytherc4921272010-08-05 03:37:22 +0800930 end->packets = 0;
931 memset(&end->addr, 0, sizeof(end->addr));
Holger Hans Peter Freythere97155a2010-11-02 19:06:13 +0100932 end->rtp_port = end->rtcp_port = 0;
Holger Hans Peter Freythera17d7012010-08-05 01:34:51 +0800933 end->payload_type = -1;
Holger Hans Peter Freytherf138f912010-08-05 08:08:17 +0800934 end->local_alloc = -1;
Holger Hans Peter Freythera17d7012010-08-05 01:34:51 +0800935}
936
Holger Hans Peter Freytherc4921272010-08-05 03:37:22 +0800937static void mgcp_rtp_end_init(struct mgcp_rtp_end *end)
938{
939 mgcp_rtp_end_reset(end);
940 end->rtp.fd = -1;
941 end->rtcp.fd = -1;
942}
943
Holger Hans Peter Freyther1f0c5b42011-02-28 14:37:03 +0100944int mgcp_endpoints_allocate(struct mgcp_trunk_config *tcfg)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100945{
946 int i;
947
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100948 /* Initialize all endpoints */
Holger Hans Peter Freyther1f0c5b42011-02-28 14:37:03 +0100949 tcfg->endpoints = _talloc_zero_array(tcfg->cfg,
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100950 sizeof(struct mgcp_endpoint),
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +0100951 tcfg->number_endpoints, "endpoints");
952 if (!tcfg->endpoints)
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100953 return -1;
954
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +0100955 for (i = 0; i < tcfg->number_endpoints; ++i) {
956 tcfg->endpoints[i].ci = CI_UNUSED;
Holger Hans Peter Freyther1f0c5b42011-02-28 14:37:03 +0100957 tcfg->endpoints[i].cfg = tcfg->cfg;
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +0100958 tcfg->endpoints[i].tcfg = tcfg;
959 mgcp_rtp_end_init(&tcfg->endpoints[i].net_end);
960 mgcp_rtp_end_init(&tcfg->endpoints[i].bts_end);
961 mgcp_rtp_end_init(&tcfg->endpoints[i].trans_net);
962 mgcp_rtp_end_init(&tcfg->endpoints[i].trans_bts);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100963 }
964
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100965 return 0;
966}
Holger Hans Peter Freyther154b9552010-02-26 13:27:51 +0100967
968void mgcp_free_endp(struct mgcp_endpoint *endp)
969{
Holger Hans Peter Freytherc77efdf2010-03-31 12:31:09 +0200970 LOGP(DMGCP, LOGL_DEBUG, "Deleting endpoint on: 0x%x\n", ENDPOINT_NUMBER(endp));
Holger Hans Peter Freyther89976e82010-08-03 15:01:43 +0000971 endp->ci = CI_UNUSED;
Holger Hans Peter Freyther39a97e22010-08-06 18:03:11 +0800972 endp->allocated = 0;
Holger Hans Peter Freyther154b9552010-02-26 13:27:51 +0100973
974 if (endp->callid) {
975 talloc_free(endp->callid);
976 endp->callid = NULL;
977 }
978
979 if (endp->local_options) {
980 talloc_free(endp->local_options);
Holger Hans Peter Freyther88c6eea2010-03-01 18:52:04 +0100981 endp->local_options = NULL;
Holger Hans Peter Freyther154b9552010-02-26 13:27:51 +0100982 }
983
Holger Hans Peter Freythera17d7012010-08-05 01:34:51 +0800984 mgcp_rtp_end_reset(&endp->bts_end);
985 mgcp_rtp_end_reset(&endp->net_end);
Holger Hans Peter Freyther21262332010-11-01 20:53:31 +0100986 mgcp_rtp_end_reset(&endp->trans_net);
Holger Hans Peter Freytherbd7b3c52010-11-01 21:04:54 +0100987 mgcp_rtp_end_reset(&endp->trans_bts);
Holger Hans Peter Freytherb54048f2010-11-01 19:57:50 +0100988 endp->is_transcoded = 0;
Holger Hans Peter Freyther380b8712010-07-29 02:38:39 +0800989
Holger Hans Peter Freyther31868922010-08-03 11:59:04 +0000990 memset(&endp->net_state, 0, sizeof(endp->net_state));
991 memset(&endp->bts_state, 0, sizeof(endp->bts_state));
Holger Hans Peter Freytherc597a4e2010-08-03 02:57:02 +0800992
993 endp->conn_mode = endp->orig_mode = MGCP_CONN_NONE;
Holger Hans Peter Freyther6357a8e2010-08-05 12:07:00 +0000994 endp->allow_patch = 0;
Holger Hans Peter Freyther260d6ed2010-08-06 01:12:21 +0800995
996 memset(&endp->taps, 0, sizeof(endp->taps));
Holger Hans Peter Freyther154b9552010-02-26 13:27:51 +0100997}
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +0800998
Holger Hans Peter Freyther557b1ab2010-09-19 04:39:55 +0800999static int send_trans(struct mgcp_config *cfg, const char *buf, int len)
1000{
1001 struct sockaddr_in addr;
1002
1003 memset(&addr, 0, sizeof(addr));
1004 addr.sin_family = AF_INET;
1005 addr.sin_addr = cfg->transcoder_in;
1006 addr.sin_port = htons(2427);
1007 return sendto(cfg->gw_fd.bfd.fd, buf, len, 0,
1008 (struct sockaddr *) &addr, sizeof(addr));
1009}
1010
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +08001011static void send_msg(struct mgcp_endpoint *endp, int endpoint, int port,
1012 const char *msg, const char *mode)
1013{
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +08001014 char buf[2096];
1015 int len;
1016
1017 /* hardcoded to AMR right now, we do not know the real type at this point */
1018 len = snprintf(buf, sizeof(buf),
1019 "%s 42 %x@mgw MGCP 1.0\r\n"
1020 "C: 4256\r\n"
1021 "M: %s\r\n"
1022 "\r\n"
1023 "c=IN IP4 %s\r\n"
1024 "m=audio %d RTP/AVP %d\r\n"
1025 "a=rtpmap:%d %s\r\n",
1026 msg, endpoint, mode, endp->cfg->source_addr,
Holger Hans Peter Freyther88ad7722011-02-28 00:56:17 +01001027 port, endp->tcfg->audio_payload,
1028 endp->tcfg->audio_payload, endp->tcfg->audio_name);
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +08001029
1030 if (len < 0)
1031 return;
1032
1033 buf[sizeof(buf) - 1] = '\0';
1034
Holger Hans Peter Freyther557b1ab2010-09-19 04:39:55 +08001035 send_trans(endp->cfg, buf, len);
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +08001036}
1037
1038static void send_dlcx(struct mgcp_endpoint *endp, int endpoint)
1039{
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +08001040 char buf[2096];
1041 int len;
1042
1043 len = snprintf(buf, sizeof(buf),
1044 "DLCX 43 %x@mgw MGCP 1.0\r\n"
1045 "C: 4256\r\n"
1046 , endpoint);
1047
1048 if (len < 0)
1049 return;
1050
1051 buf[sizeof(buf) - 1] = '\0';
1052
Holger Hans Peter Freyther557b1ab2010-09-19 04:39:55 +08001053 send_trans(endp->cfg, buf, len);
Holger Hans Peter Freyther3b5e3c42010-09-18 06:35:29 +08001054}
1055
1056static 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}