blob: 9233042ff91e14afc76f4294945e554bc15afaec [file] [log] [blame]
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +08001/* A Media Gateway Control Protocol Media Gateway: RFC 3435 */
2/* The protocol implementation */
3
4/*
Holger Hans Peter Freyther44f848b2011-01-25 23:41:30 +01005 * (C) 2009-2011 by Holger Hans Peter Freyther <zecke@selfish.org>
6 * (C) 2009-2011 by On-Waves
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +08007 * All Rights Reserved
8 *
Holger Hans Peter Freytherdcc33122011-03-01 01:24:10 +01009 * This program is free software; you can redistribute it and/or modify
Holger Hans Peter Freytherde56c222011-01-16 17:45:14 +010010 * it under the terms of the GNU Affero General Public License as published by
Holger Hans Peter Freytherdcc33122011-03-01 01:24:10 +010011 * the Free Software Foundation; either version 3 of the License, or
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080012 * (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
Holger Hans Peter Freytherde56c222011-01-16 17:45:14 +010017 * GNU Affero General Public License for more details.
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080018 *
Holger Hans Peter Freytherde56c222011-01-16 17:45:14 +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 Freyther97f66e22010-07-28 03:32:52 +080021 *
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
Holger Hans Peter Freythercbf7d182010-07-31 05:25:35 +080032#include <osmocore/msgb.h>
33#include <osmocore/talloc.h>
34#include <osmocore/select.h>
Holger Hans Peter Freythercbf7d182010-07-31 05:25:35 +080035
Holger Hans Peter Freytherdcc33122011-03-01 01:24:10 +010036#include <mgcp/mgcp.h>
37#include <mgcp/mgcp_internal.h>
Holger Hans Peter Freythercbf7d182010-07-31 05:25:35 +080038
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080039/**
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 Freytherdcc33122011-03-01 01:24:10 +010073static void mgcp_rtp_end_reset(struct mgcp_rtp_end *end);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080074
75struct mgcp_request {
76 char *name;
77 struct msgb *(*handle_request) (struct mgcp_config *cfg, struct msgb *msg);
78 char *debug_name;
79};
80
81#define MGCP_REQUEST(NAME, REQ, DEBUG_NAME) \
82 { .name = NAME, .handle_request = REQ, .debug_name = DEBUG_NAME },
83
84static 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);
88static struct msgb *handle_rsip(struct mgcp_config *cfg, struct msgb *msg);
Holger Hans Peter Freyther44f848b2011-01-25 23:41:30 +010089static struct msgb *handle_noti_req(struct mgcp_config *cfg, struct msgb *msg);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080090
Holger Hans Peter Freytherdcc33122011-03-01 01:24:10 +010091static void create_transcoder(struct mgcp_endpoint *endp);
92static void delete_transcoder(struct mgcp_endpoint *endp);
93
Holger Hans Peter Freyther5b084012010-08-08 07:51:51 +080094static uint32_t generate_call_id(struct mgcp_config *cfg)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080095{
96 int i;
97
98 /* use the call id */
99 ++cfg->last_call_id;
100
101 /* handle wrap around */
102 if (cfg->last_call_id == CI_UNUSED)
103 ++cfg->last_call_id;
104
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 Freytherdcc33122011-03-01 01:24:10 +0100107 for (i = 1; i < cfg->trunk.number_endpoints; ++i)
108 if (cfg->trunk.endpoints[i].ci == cfg->last_call_id)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800109 return generate_call_id(cfg);
110
111 return cfg->last_call_id;
112}
113
114/*
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 Freyther44f848b2011-01-25 23:41:30 +0100124 MGCP_REQUEST("RQNT", handle_noti_req, "NotificationRequest")
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800125
126 /* SPEC extension */
127 MGCP_REQUEST("RSIP", handle_rsip, "ReSetInProgress")
128};
129
130static struct msgb *mgcp_msgb_alloc(void)
131{
132 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 Freyther7e0936e2011-01-06 19:48: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 Freyther97f66e22010-07-28 03:32:52 +0800143{
144 int len;
145 struct msgb *res;
146
147 res = mgcp_msgb_alloc();
148 if (!res)
149 return NULL;
150
151 if (data) {
Holger Hans Peter Freyther7e0936e2011-01-06 19:48:55 +0100152 len = snprintf((char *) res->data, 2048, "%d %s%s\r\n%s", code, trans, txt, data);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800153 } else {
Holger Hans Peter Freyther7e0936e2011-01-06 19:48:55 +0100154 len = snprintf((char *) res->data, 2048, "%d %s%s\r\n", code, trans, txt);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800155 }
156
157 res->l2h = msgb_put(res, len);
158 LOGP(DMGCP, LOGL_DEBUG, "Sending response: code: %d for '%s'\n", code, res->l2h);
159 return res;
160}
161
Holger Hans Peter Freyther7e0936e2011-01-06 19:48:55 +0100162static struct msgb *create_ok_response(int code, const char *msg, const char *trans)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800163{
Holger Hans Peter Freyther7e0936e2011-01-06 19:48: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 Freyther97f66e22010-07-28 03:32:52 +0800170}
171
172static struct msgb *create_response_with_sdp(struct mgcp_endpoint *endp,
173 const char *msg, const char *trans_id)
174{
175 const char *addr = endp->cfg->local_ip;
176 char sdp_record[4096];
177
178 if (!addr)
179 addr = endp->cfg->source_addr;
180
181 snprintf(sdp_record, sizeof(sdp_record) - 1,
Holger Hans Peter Freyther5b084012010-08-08 07:51:51 +0800182 "I: %u\n\n"
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800183 "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 Freytherdcc33122011-03-01 01:24:10 +0100187 endp->ci, addr, endp->net_end.local_port,
188 endp->bts_end.payload_type, endp->bts_end.payload_type,
189 endp->tcfg->audio_name);
Holger Hans Peter Freyther7e0936e2011-01-06 19:48:55 +0100190 return mgcp_create_response_with_data(200, " OK", msg, trans_id, sdp_record);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800191}
192
193/*
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 */
198struct msgb *mgcp_handle_message(struct mgcp_config *cfg, struct msgb *msg)
199{
200 int code;
201 struct msgb *resp = NULL;
202
203 if (msgb_l2len(msg) < 4) {
204 LOGP(DMGCP, LOGL_ERROR, "mgs too short: %d\n", msg->len);
205 return NULL;
206 }
207
208 /* attempt to treat it as a response */
209 if (sscanf((const char *)&msg->l2h[0], "%3d %*s", &code) == 1) {
210 LOGP(DMGCP, LOGL_DEBUG, "Response: Code: %d\n", code);
211 } else {
212 int i, handled = 0;
213 msg->l3h = &msg->l2h[4];
214 for (i = 0; i < ARRAY_SIZE(mgcp_requests); ++i)
215 if (strncmp(mgcp_requests[i].name, (const char *) &msg->l2h[0], 4) == 0) {
216 handled = 1;
217 resp = mgcp_requests[i].handle_request(cfg, msg);
218 break;
219 }
220 if (!handled) {
221 LOGP(DMGCP, LOGL_NOTICE, "MSG with type: '%.4s' not handled\n", &msg->l2h[0]);
222 }
223 }
224
225 return resp;
226}
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 Freyther7e0936e2011-01-06 19:48:55 +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 Freytherdcc33122011-03-01 01:24:10 +0100273 struct mgcp_trunk_config *tcfg;
274 int trunk, endp;
Holger Hans Peter Freyther7e0936e2011-01-06 19:48:55 +0100275
276 trunk = strtoul(mgcp + 6, &rest, 10);
Holger Hans Peter Freytherea853042011-01-07 11:38:00 +0100277 if (rest == NULL || rest[0] != '/' || trunk < 1) {
Holger Hans Peter Freyther7e0936e2011-01-06 19:48:55 +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 Freytherea853042011-01-07 11:38:00 +0100284 LOGP(DMGCP, LOGL_ERROR, "Wrong endpoint name '%s'\n", mgcp);
Holger Hans Peter Freyther7e0936e2011-01-06 19:48:55 +0100285 return NULL;
286 }
287
288 /* signalling is on timeslot 1 */
289 if (endp == 1)
290 return NULL;
291
Holger Hans Peter Freytherdcc33122011-03-01 01:24:10 +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 Freyther7e0936e2011-01-06 19:48:55 +0100304 LOGP(DMGCP, LOGL_ERROR, "Failed to find endpoint '%s'\n", mgcp);
Holger Hans Peter Freytherea853042011-01-07 11:38:00 +0100305 return NULL;
Holger Hans Peter Freyther7e0936e2011-01-06 19:48:55 +0100306 }
307
Holger Hans Peter Freytherdcc33122011-03-01 01:24:10 +0100308 return &tcfg->endpoints[endp];
Holger Hans Peter Freyther7e0936e2011-01-06 19:48:55 +0100309}
310
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800311static struct mgcp_endpoint *find_endpoint(struct mgcp_config *cfg, const char *mgcp)
312{
313 char *endptr = NULL;
314 unsigned int gw = INT_MAX;
315
Holger Hans Peter Freyther7e0936e2011-01-06 19:48:55 +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 Freytherdcc33122011-03-01 01:24:10 +0100320 if (gw > 0 && gw < cfg->trunk.number_endpoints && strcmp(endptr, "@mgw") == 0)
321 return &cfg->trunk.endpoints[gw];
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800322 }
323
Holger Hans Peter Freyther7e0936e2011-01-06 19:48:55 +0100324 LOGP(DMGCP, LOGL_ERROR, "Not able to find endpoint: '%s'\n", mgcp);
325 return NULL;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800326}
327
328int 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)
331{
332 int found;
333
334 *transaction_id = "000000";
335
336 if (size < 3) {
337 LOGP(DMGCP, LOGL_ERROR, "Not enough space in ptr\n");
338 return -1;
339 }
340
341 found = find_msg_pointers(msg, ptr, size);
342
343 if (found <= 3) {
344 LOGP(DMGCP, LOGL_ERROR, "Gateway: Not enough params. Found: %d\n", found);
345 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) {
359 LOGP(DMGCP, LOGL_ERROR, "Wrong MGCP version. Not handling: '%s' '%s'\n",
360 (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];
366 if (endp) {
367 *endp = find_endpoint(cfg, (const char *)&msg->l3h[ptr[1].start]);
368 return *endp == NULL;
369 }
370 return 0;
371}
372
373static int verify_call_id(const struct mgcp_endpoint *endp,
374 const char *callid)
375{
376 if (strcmp(endp->callid, callid) != 0) {
377 LOGP(DMGCP, LOGL_ERROR, "CallIDs does not match on 0x%x. '%s' != '%s'\n",
378 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 Freyther5b084012010-08-08 07:51:51 +0800386 const char *_ci)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800387{
Holger Hans Peter Freyther5b084012010-08-08 07:51:51 +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 Freyther97f66e22010-07-28 03:32:52 +0800393 return -1;
394 }
395
396 return 0;
397}
398
399static struct msgb *handle_audit_endpoint(struct mgcp_config *cfg, struct msgb *msg)
400{
401 struct mgcp_msg_ptr data_ptrs[6];
Holger Hans Peter Freyther7e0936e2011-01-06 19:48:55 +0100402 int found;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800403 const char *trans_id;
404 struct mgcp_endpoint *endp;
405
406 found = mgcp_analyze_header(cfg, msg, data_ptrs, ARRAY_SIZE(data_ptrs), &trans_id, &endp);
407 if (found != 0)
Holger Hans Peter Freyther7e0936e2011-01-06 19:48:55 +0100408 return create_err_response(500, "AUEP", trans_id);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800409 else
Holger Hans Peter Freyther7e0936e2011-01-06 19:48:55 +0100410 return create_ok_response(200, "AUEP", trans_id);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800411}
412
Holger Hans Peter Freytherdcc33122011-03-01 01:24:10 +0100413static int parse_conn_mode(const char *msg, int *conn_mode)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800414{
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 Freytherb988caa2010-09-18 20:23:05 +0800420 else if (strcmp(msg, "sendonly") == 0)
421 *conn_mode = MGCP_CONN_SEND_ONLY;
Holger Hans Peter Freytherd86208d2010-08-04 06:11:27 +0800422 else if (strcmp(msg, "loopback") == 0)
423 *conn_mode = MGCP_CONN_LOOPBACK;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800424 else {
425 LOGP(DMGCP, LOGL_ERROR, "Unknown connection mode: '%s'\n", msg);
426 ret = -1;
427 }
428
429 return ret;
430}
431
Holger Hans Peter Freytherdcc33122011-03-01 01:24:10 +0100432static int allocate_port(struct mgcp_endpoint *endp, struct mgcp_rtp_end *end,
433 struct mgcp_port_range *range,
434 int (*alloc)(struct mgcp_endpoint *endp, int port))
435{
436 int i;
437
438 if (range->mode == PORT_ALLOC_STATIC) {
439 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
450 rc = alloc(endp, range->last_port);
451
452 range->last_port += 2;
453 if (rc == 0) {
454 end->local_alloc = PORT_ALLOC_DYNAMIC;
455 return 0;
456 }
457
458 }
459
460 LOGP(DMGCP, LOGL_ERROR, "Allocating a RTP/RTCP port failed 200 times 0x%x.\n",
461 ENDPOINT_NUMBER(endp));
462 return -1;
463}
464
465static int allocate_ports(struct mgcp_endpoint *endp)
466{
467 if (allocate_port(endp, &endp->net_end, &endp->cfg->net_ports,
468 mgcp_bind_net_rtp_port) != 0)
469 return -1;
470
471 if (allocate_port(endp, &endp->bts_end, &endp->cfg->bts_ports,
472 mgcp_bind_bts_rtp_port) != 0) {
473 mgcp_rtp_end_reset(&endp->net_end);
474 return -1;
475 }
476
477 if (endp->cfg->transcoder_ip && endp->tcfg->trunk_type == MGCP_TRUNK_VIRTUAL) {
478 if (allocate_port(endp, &endp->trans_net,
479 &endp->cfg->transcoder_ports,
480 mgcp_bind_trans_net_rtp_port) != 0) {
481 mgcp_rtp_end_reset(&endp->net_end);
482 mgcp_rtp_end_reset(&endp->bts_end);
483 return -1;
484 }
485
486 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
495 /* remember that we have set up transcoding */
496 endp->is_transcoded = 1;
497 }
498
499 return 0;
500}
501
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800502static struct msgb *handle_create_con(struct mgcp_config *cfg, struct msgb *msg)
503{
504 struct mgcp_msg_ptr data_ptrs[6];
505 int found, i, line_start;
506 const char *trans_id;
Holger Hans Peter Freytherdcc33122011-03-01 01:24:10 +0100507 struct mgcp_trunk_config *tcfg;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800508 struct mgcp_endpoint *endp;
Holger Hans Peter Freytherdcc33122011-03-01 01:24:10 +0100509 int error_code = 400;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800510
511 found = mgcp_analyze_header(cfg, msg, data_ptrs, ARRAY_SIZE(data_ptrs), &trans_id, &endp);
512 if (found != 0)
Holger Hans Peter Freyther7e0936e2011-01-06 19:48:55 +0100513 return create_err_response(510, "CRCX", trans_id);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800514
Holger Hans Peter Freytherdcc33122011-03-01 01:24:10 +0100515 tcfg = endp->tcfg;
516
517 if (endp->allocated) {
518 if (tcfg->force_realloc) {
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800519 LOGP(DMGCP, LOGL_NOTICE, "Endpoint 0x%x already allocated. Forcing realloc.\n",
520 ENDPOINT_NUMBER(endp));
Holger Hans Peter Freytherd86208d2010-08-04 06:11:27 +0800521 mgcp_free_endp(endp);
Holger Hans Peter Freythere40bc382010-09-18 03:11:00 +0800522 if (cfg->realloc_cb)
Holger Hans Peter Freytherdcc33122011-03-01 01:24:10 +0100523 cfg->realloc_cb(tcfg, ENDPOINT_NUMBER(endp));
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800524 } else {
525 LOGP(DMGCP, LOGL_ERROR, "Endpoint is already used. 0x%x\n",
526 ENDPOINT_NUMBER(endp));
Holger Hans Peter Freyther7e0936e2011-01-06 19:48:55 +0100527 return create_err_response(400, "CRCX", trans_id);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800528 }
529 }
530
531 /* parse CallID C: and LocalParameters L: */
532 MSG_TOKENIZE_START
533 switch (msg->l3h[line_start]) {
534 case 'L':
Holger Hans Peter Freytherdcc33122011-03-01 01:24:10 +0100535 endp->local_options = talloc_strdup(tcfg->endpoints,
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800536 (const char *)&msg->l3h[line_start + 3]);
537 break;
538 case 'C':
Holger Hans Peter Freytherdcc33122011-03-01 01:24:10 +0100539 endp->callid = talloc_strdup(tcfg->endpoints,
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800540 (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 Freytherd86208d2010-08-04 06:11:27 +0800548
549 endp->orig_mode = endp->conn_mode;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800550 break;
551 default:
552 LOGP(DMGCP, LOGL_NOTICE, "Unhandled option: '%c'/%d on 0x%x\n",
553 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 Freytherdcc33122011-03-01 01:24:10 +0100560 endp->net_end.rtp_port = endp->net_end.rtcp_port = endp->bts_end.rtp_port = endp->bts_end.rtcp_port = 0;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800561
562 /* set to zero until we get the info */
Holger Hans Peter Freytherdcc33122011-03-01 01:24:10 +0100563 memset(&endp->net_end.addr, 0, sizeof(endp->net_end.addr));
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800564
565 /* bind to the port now */
Holger Hans Peter Freytherdcc33122011-03-01 01:24:10 +0100566 if (allocate_ports(endp) != 0)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800567 goto error2;
568
569 /* assign a local call identifier or fail */
570 endp->ci = generate_call_id(cfg);
571 if (endp->ci == CI_UNUSED)
572 goto error2;
573
Holger Hans Peter Freytherdcc33122011-03-01 01:24:10 +0100574 endp->allocated = 1;
575 endp->bts_end.payload_type = tcfg->audio_payload;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800576
577 /* policy CB */
578 if (cfg->policy_cb) {
Holger Hans Peter Freytherdcc33122011-03-01 01:24:10 +0100579 switch (cfg->policy_cb(tcfg, ENDPOINT_NUMBER(endp), MGCP_ENDP_CRCX, trans_id)) {
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800580 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 Freyther7e0936e2011-01-06 19:48:55 +0100584 return create_err_response(400, "CRCX", trans_id);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800585 break;
586 case MGCP_POLICY_DEFER:
587 /* stop processing */
Holger Hans Peter Freytherdcc33122011-03-01 01:24:10 +0100588 create_transcoder(endp);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800589 return NULL;
590 break;
591 case MGCP_POLICY_CONT:
592 /* just continue */
593 break;
594 }
595 }
596
Holger Hans Peter Freytherdcc33122011-03-01 01:24:10 +0100597 LOGP(DMGCP, LOGL_DEBUG, "Creating endpoint on: 0x%x CI: %u port: %u/%u\n",
598 ENDPOINT_NUMBER(endp), endp->ci,
599 endp->net_end.local_port, endp->bts_end.local_port);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800600 if (cfg->change_cb)
Holger Hans Peter Freytherdcc33122011-03-01 01:24:10 +0100601 cfg->change_cb(tcfg, ENDPOINT_NUMBER(endp), MGCP_ENDP_CRCX);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800602
Holger Hans Peter Freytherdcc33122011-03-01 01:24:10 +0100603 create_transcoder(endp);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800604 return create_response_with_sdp(endp, "CRCX", trans_id);
605error:
606 LOGP(DMGCP, LOGL_ERROR, "Malformed line: %s on 0x%x with: line_start: %d %d\n",
607 hexdump(msg->l3h, msgb_l3len(msg)),
608 ENDPOINT_NUMBER(endp), line_start, i);
Holger Hans Peter Freyther7e0936e2011-01-06 19:48:55 +0100609 return create_err_response(error_code, "CRCX", trans_id);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800610
611error2:
Holger Hans Peter Freytherdcc33122011-03-01 01:24:10 +0100612 mgcp_free_endp(endp);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800613 LOGP(DMGCP, LOGL_NOTICE, "Resource error on 0x%x\n", ENDPOINT_NUMBER(endp));
Holger Hans Peter Freyther7e0936e2011-01-06 19:48:55 +0100614 return create_err_response(error_code, "CRCX", trans_id);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800615}
616
617static struct msgb *handle_modify_con(struct mgcp_config *cfg, struct msgb *msg)
618{
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;
624 int silent = 0;
625
626 found = mgcp_analyze_header(cfg, msg, data_ptrs, ARRAY_SIZE(data_ptrs), &trans_id, &endp);
627 if (found != 0)
Holger Hans Peter Freyther7e0936e2011-01-06 19:48:55 +0100628 return create_err_response(510, "MDCX", trans_id);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800629
630 if (endp->ci == CI_UNUSED) {
631 LOGP(DMGCP, LOGL_ERROR, "Endpoint is not holding a connection. 0x%x\n", ENDPOINT_NUMBER(endp));
Holger Hans Peter Freyther7e0936e2011-01-06 19:48:55 +0100632 return create_err_response(400, "MDCX", trans_id);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800633 }
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 Freytherd86208d2010-08-04 06:11:27 +0800656 endp->orig_mode = endp->conn_mode;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800657 break;
658 case 'Z':
659 silent = strcmp("noanswer", (const char *)&msg->l3h[line_start + 3]) == 0;
660 break;
661 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;
673 int payload;
674 const char *param = (const char *)&msg->l3h[line_start];
675
676 if (sscanf(param, "m=audio %d RTP/AVP %d", &port, &payload) == 2) {
Holger Hans Peter Freytherdcc33122011-03-01 01:24:10 +0100677 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 Freyther97f66e22010-07-28 03:32:52 +0800680 }
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 Freytherdcc33122011-03-01 01:24:10 +0100688 inet_aton(ipv4, &endp->net_end.addr);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800689 }
690 break;
691 }
692 default:
693 LOGP(DMGCP, LOGL_NOTICE, "Unhandled option: '%c'/%d on 0x%x\n",
694 msg->l3h[line_start], msg->l3h[line_start],
695 ENDPOINT_NUMBER(endp));
696 break;
697 }
698 MSG_TOKENIZE_END
699
700 /* policy CB */
701 if (cfg->policy_cb) {
Holger Hans Peter Freytherdcc33122011-03-01 01:24:10 +0100702 switch (cfg->policy_cb(endp->tcfg, ENDPOINT_NUMBER(endp), MGCP_ENDP_MDCX, trans_id)) {
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800703 case MGCP_POLICY_REJECT:
704 LOGP(DMGCP, LOGL_NOTICE, "MDCX rejected by policy on 0x%x\n",
705 ENDPOINT_NUMBER(endp));
706 if (silent)
707 goto out_silent;
Holger Hans Peter Freyther7e0936e2011-01-06 19:48:55 +0100708 return create_err_response(400, "MDCX", trans_id);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800709 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
720 /* modify */
Holger Hans Peter Freytherdcc33122011-03-01 01:24:10 +0100721 LOGP(DMGCP, LOGL_DEBUG, "Modified endpoint on: 0x%x Server: %s:%u\n",
722 ENDPOINT_NUMBER(endp), inet_ntoa(endp->net_end.addr), ntohs(endp->net_end.rtp_port));
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800723 if (cfg->change_cb)
Holger Hans Peter Freytherdcc33122011-03-01 01:24:10 +0100724 cfg->change_cb(endp->tcfg, ENDPOINT_NUMBER(endp), MGCP_ENDP_MDCX);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800725 if (silent)
726 goto out_silent;
727
728 return create_response_with_sdp(endp, "MDCX", trans_id);
729
730error:
731 LOGP(DMGCP, LOGL_ERROR, "Malformed line: %s on 0x%x with: line_start: %d %d %d\n",
732 hexdump(msg->l3h, msgb_l3len(msg)),
733 ENDPOINT_NUMBER(endp), line_start, i, msg->l3h[line_start]);
Holger Hans Peter Freyther7e0936e2011-01-06 19:48:55 +0100734 return create_err_response(error_code, "MDCX", trans_id);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800735
736error3:
Holger Hans Peter Freyther7e0936e2011-01-06 19:48:55 +0100737 return create_err_response(error_code, "MDCX", trans_id);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800738
739
740out_silent:
741 return NULL;
742}
743
744static struct msgb *handle_delete_con(struct mgcp_config *cfg, struct msgb *msg)
745{
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 Freytherdcc33122011-03-01 01:24:10 +0100750 int error_code = 400;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800751 int silent = 0;
752
753 found = mgcp_analyze_header(cfg, msg, data_ptrs, ARRAY_SIZE(data_ptrs), &trans_id, &endp);
754 if (found != 0)
Holger Hans Peter Freyther7e0936e2011-01-06 19:48:55 +0100755 return create_err_response(error_code, "DLCX", trans_id);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800756
Holger Hans Peter Freytherdcc33122011-03-01 01:24:10 +0100757 if (!endp->allocated) {
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800758 LOGP(DMGCP, LOGL_ERROR, "Endpoint is not used. 0x%x\n", ENDPOINT_NUMBER(endp));
Holger Hans Peter Freyther7e0936e2011-01-06 19:48:55 +0100759 return create_err_response(400, "DLCX", trans_id);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800760 }
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;
773 case 'Z':
774 silent = strcmp("noanswer", (const char *)&msg->l3h[line_start + 3]) == 0;
775 break;
776 }
777 default:
778 LOGP(DMGCP, LOGL_NOTICE, "Unhandled option: '%c'/%d on 0x%x\n",
779 msg->l3h[line_start], msg->l3h[line_start],
780 ENDPOINT_NUMBER(endp));
781 break;
782 }
783 MSG_TOKENIZE_END
784
785 /* policy CB */
786 if (cfg->policy_cb) {
Holger Hans Peter Freytherdcc33122011-03-01 01:24:10 +0100787 switch (cfg->policy_cb(endp->tcfg, ENDPOINT_NUMBER(endp), MGCP_ENDP_DLCX, trans_id)) {
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800788 case MGCP_POLICY_REJECT:
789 LOGP(DMGCP, LOGL_NOTICE, "DLCX rejected by policy on 0x%x\n",
790 ENDPOINT_NUMBER(endp));
791 if (silent)
792 goto out_silent;
Holger Hans Peter Freyther7e0936e2011-01-06 19:48:55 +0100793 return create_err_response(400, "DLCX", trans_id);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800794 break;
795 case MGCP_POLICY_DEFER:
796 /* stop processing */
Holger Hans Peter Freytherdcc33122011-03-01 01:24:10 +0100797 delete_transcoder(endp);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800798 return NULL;
799 break;
800 case MGCP_POLICY_CONT:
801 /* just continue */
802 break;
803 }
804 }
805
806 /* free the connection */
Holger Hans Peter Freytherdcc33122011-03-01 01:24:10 +0100807 LOGP(DMGCP, LOGL_DEBUG, "Deleted endpoint on: 0x%x Server: %s:%u\n",
808 ENDPOINT_NUMBER(endp), inet_ntoa(endp->net_end.addr), ntohs(endp->net_end.rtp_port));
809
810 delete_transcoder(endp);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800811 mgcp_free_endp(endp);
812 if (cfg->change_cb)
Holger Hans Peter Freytherdcc33122011-03-01 01:24:10 +0100813 cfg->change_cb(endp->tcfg, ENDPOINT_NUMBER(endp), MGCP_ENDP_DLCX);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800814
815 if (silent)
816 goto out_silent;
Holger Hans Peter Freyther7e0936e2011-01-06 19:48:55 +0100817 return create_ok_response(250, "DLCX", trans_id);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800818
819error:
820 LOGP(DMGCP, LOGL_ERROR, "Malformed line: %s on 0x%x with: line_start: %d %d\n",
821 hexdump(msg->l3h, msgb_l3len(msg)),
822 ENDPOINT_NUMBER(endp), line_start, i);
Holger Hans Peter Freyther7e0936e2011-01-06 19:48:55 +0100823 return create_err_response(error_code, "DLCX", trans_id);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800824
825error3:
Holger Hans Peter Freyther7e0936e2011-01-06 19:48:55 +0100826 return create_err_response(error_code, "DLCX", trans_id);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800827
828out_silent:
829 return NULL;
830}
831
832static 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 Freyther44f848b2011-01-25 23:41:30 +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
Holger Hans Peter Freytherdcc33122011-03-01 01:24:10 +0100855 if (!endp->allocated) {
Holger Hans Peter Freyther44f848b2011-01-25 23:41:30 +0100856 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 Freytherdcc33122011-03-01 01:24:10 +0100862static void trunk_init(struct mgcp_trunk_config *trunk)
863{
864 trunk->trunk_type = MGCP_TRUNK_VIRTUAL;
865 trunk->audio_name = talloc_strdup(trunk->cfg, "AMR/8000");
866 trunk->audio_payload = 126;
867
868 /* MGW handling */
869 trunk->target_trunk_start = 1;
870 trunk->endp_offset = 1;
871 trunk->vad_enabled = 1;
872 trunk->digital_inp_gain = 31;
873 trunk->digital_out_gain = 31;
874 trunk->upstr_agc_enbl = 0;
875 trunk->upstr_adp_rate = 100;
876 trunk->upstr_max_gain = 46;
877 trunk->upstr_target_lvl = 20;
878 trunk->dwnstr_agc_enbl = 0;
879 trunk->dwnstr_adp_rate = 100;
880 trunk->dwnstr_max_gain = 46;
881 trunk->dwnstr_target_lvl = 20;
882}
883
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800884struct mgcp_config *mgcp_config_alloc(void)
885{
886 struct mgcp_config *cfg;
887
888 cfg = talloc_zero(NULL, struct mgcp_config);
889 if (!cfg) {
890 LOGP(DMGCP, LOGL_FATAL, "Failed to allocate config.\n");
891 return NULL;
892 }
893
894 cfg->source_port = 2427;
895 cfg->source_addr = talloc_strdup(cfg, "0.0.0.0");
Holger Hans Peter Freytherdcc33122011-03-01 01:24:10 +0100896
897 cfg->transcoder_remote_base = 4000;
898
899 cfg->bts_ports.base_port = RTP_PORT_DEFAULT;
900 cfg->net_ports.base_port = RTP_PORT_NET_DEFAULT;
901
902 /* default trunk handling */
903 cfg->trunk.cfg = cfg;
904 cfg->trunk.trunk_nr = 0;
905 trunk_init(&cfg->trunk);
906
907 INIT_LLIST_HEAD(&cfg->trunks);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800908
909 return cfg;
910}
911
Holger Hans Peter Freytherdcc33122011-03-01 01:24:10 +0100912struct mgcp_trunk_config *mgcp_trunk_alloc(struct mgcp_config *cfg, int nr)
913{
914 struct mgcp_trunk_config *trunk;
915
916 trunk = talloc_zero(cfg, struct mgcp_trunk_config);
917 if (!trunk) {
918 LOGP(DMGCP, LOGL_ERROR, "Failed to allocate.\n");
919 return NULL;
920 }
921
922 trunk->cfg = cfg;
923 trunk->trunk_type = MGCP_TRUNK_E1;
924 trunk->trunk_nr = nr;
925 trunk_init(trunk);
926 trunk->number_endpoints = 33;
927 llist_add_tail(&trunk->entry, &cfg->trunks);
928 return trunk;
929}
930
931struct mgcp_trunk_config *mgcp_trunk_num(struct mgcp_config *cfg, int index)
932{
933 struct mgcp_trunk_config *trunk;
934
935 llist_for_each_entry(trunk, &cfg->trunks, entry)
936 if (trunk->trunk_nr == index)
937 return trunk;
938
939 return NULL;
940}
941
942static void mgcp_rtp_end_reset(struct mgcp_rtp_end *end)
943{
944 if (end->local_alloc == PORT_ALLOC_DYNAMIC) {
945 mgcp_free_rtp_port(end);
946 end->local_port = 0;
947 }
948
949 end->packets = 0;
950 memset(&end->addr, 0, sizeof(end->addr));
951 end->rtp_port = end->rtcp_port = 0;
952 end->payload_type = -1;
953 end->local_alloc = -1;
954}
955
956static void mgcp_rtp_end_init(struct mgcp_rtp_end *end)
957{
958 mgcp_rtp_end_reset(end);
959 end->rtp.fd = -1;
960 end->rtcp.fd = -1;
961}
962
963int mgcp_endpoints_allocate(struct mgcp_trunk_config *tcfg)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800964{
965 int i;
966
967 /* Initialize all endpoints */
Holger Hans Peter Freytherdcc33122011-03-01 01:24:10 +0100968 tcfg->endpoints = _talloc_zero_array(tcfg->cfg,
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800969 sizeof(struct mgcp_endpoint),
Holger Hans Peter Freytherdcc33122011-03-01 01:24:10 +0100970 tcfg->number_endpoints, "endpoints");
971 if (!tcfg->endpoints)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800972 return -1;
973
Holger Hans Peter Freytherdcc33122011-03-01 01:24:10 +0100974 for (i = 0; i < tcfg->number_endpoints; ++i) {
975 tcfg->endpoints[i].ci = CI_UNUSED;
976 tcfg->endpoints[i].cfg = tcfg->cfg;
977 tcfg->endpoints[i].tcfg = tcfg;
978 mgcp_rtp_end_init(&tcfg->endpoints[i].net_end);
979 mgcp_rtp_end_init(&tcfg->endpoints[i].bts_end);
980 mgcp_rtp_end_init(&tcfg->endpoints[i].trans_net);
981 mgcp_rtp_end_init(&tcfg->endpoints[i].trans_bts);
982
983 /* MGW code */
984 tcfg->endpoints[i].audio_port = UINT_MAX;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800985 }
986
987 return 0;
988}
989
990void mgcp_free_endp(struct mgcp_endpoint *endp)
991{
992 LOGP(DMGCP, LOGL_DEBUG, "Deleting endpoint on: 0x%x\n", ENDPOINT_NUMBER(endp));
Holger Hans Peter Freytherd86208d2010-08-04 06:11:27 +0800993 endp->ci = CI_UNUSED;
Holger Hans Peter Freytherdcc33122011-03-01 01:24:10 +0100994 endp->allocated = 0;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800995
996 if (endp->callid) {
997 talloc_free(endp->callid);
998 endp->callid = NULL;
999 }
1000
1001 if (endp->local_options) {
1002 talloc_free(endp->local_options);
1003 endp->local_options = NULL;
1004 }
1005
Holger Hans Peter Freytherdcc33122011-03-01 01:24:10 +01001006 mgcp_rtp_end_reset(&endp->bts_end);
1007 mgcp_rtp_end_reset(&endp->net_end);
1008 mgcp_rtp_end_reset(&endp->trans_net);
1009 mgcp_rtp_end_reset(&endp->trans_bts);
1010 endp->is_transcoded = 0;
Holger Hans Peter Freytherd86208d2010-08-04 06:11:27 +08001011
1012 memset(&endp->net_state, 0, sizeof(endp->net_state));
1013 memset(&endp->bts_state, 0, sizeof(endp->bts_state));
1014
1015 endp->conn_mode = endp->orig_mode = MGCP_CONN_NONE;
Holger Hans Peter Freytherdcc33122011-03-01 01:24:10 +01001016 endp->allow_patch = 0;
1017
1018 memset(&endp->taps, 0, sizeof(endp->taps));
1019}
1020
1021static int send_trans(struct mgcp_config *cfg, const char *buf, int len)
1022{
1023 struct sockaddr_in addr;
1024
1025 memset(&addr, 0, sizeof(addr));
1026 addr.sin_family = AF_INET;
1027 addr.sin_addr = cfg->transcoder_in;
1028 addr.sin_port = htons(2427);
1029 return sendto(cfg->gw_fd.bfd.fd, buf, len, 0,
1030 (struct sockaddr *) &addr, sizeof(addr));
1031}
1032
1033static void send_msg(struct mgcp_endpoint *endp, int endpoint, int port,
1034 const char *msg, const char *mode)
1035{
1036 char buf[2096];
1037 int len;
1038
1039 /* hardcoded to AMR right now, we do not know the real type at this point */
1040 len = snprintf(buf, sizeof(buf),
1041 "%s 42 %x@mgw MGCP 1.0\r\n"
1042 "C: 4256\r\n"
1043 "M: %s\r\n"
1044 "\r\n"
1045 "c=IN IP4 %s\r\n"
1046 "m=audio %d RTP/AVP %d\r\n"
1047 "a=rtpmap:%d %s\r\n",
1048 msg, endpoint, mode, endp->cfg->source_addr,
1049 port, endp->tcfg->audio_payload,
1050 endp->tcfg->audio_payload, endp->tcfg->audio_name);
1051
1052 if (len < 0)
1053 return;
1054
1055 buf[sizeof(buf) - 1] = '\0';
1056
1057 send_trans(endp->cfg, buf, len);
1058}
1059
1060static void send_dlcx(struct mgcp_endpoint *endp, int endpoint)
1061{
1062 char buf[2096];
1063 int len;
1064
1065 len = snprintf(buf, sizeof(buf),
1066 "DLCX 43 %x@mgw MGCP 1.0\r\n"
1067 "C: 4256\r\n"
1068 , endpoint);
1069
1070 if (len < 0)
1071 return;
1072
1073 buf[sizeof(buf) - 1] = '\0';
1074
1075 send_trans(endp->cfg, buf, len);
1076}
1077
1078static void create_transcoder(struct mgcp_endpoint *endp)
1079{
1080 int port;
1081 int in_endp = ENDPOINT_NUMBER(endp);
1082 int out_endp = endp_back_channel(in_endp);
1083
1084 if (!endp->is_transcoded)
1085 return;
1086
1087 send_msg(endp, in_endp, endp->trans_bts.local_port, "CRCX", "sendrecv");
1088 send_msg(endp, in_endp, endp->trans_bts.local_port, "MDCX", "sendrecv");
1089 send_msg(endp, out_endp, endp->trans_net.local_port, "CRCX", "sendrecv");
1090 send_msg(endp, out_endp, endp->trans_net.local_port, "MDCX", "sendrecv");
1091
1092 port = rtp_calculate_port(in_endp, endp->cfg->transcoder_remote_base);
1093 endp->trans_bts.rtp_port = htons(port);
1094 endp->trans_bts.rtcp_port = htons(port + 1);
1095
1096 port = rtp_calculate_port(out_endp, endp->cfg->transcoder_remote_base);
1097 endp->trans_net.rtp_port = htons(port);
1098 endp->trans_net.rtcp_port = htons(port + 1);
1099}
1100
1101static void delete_transcoder(struct mgcp_endpoint *endp)
1102{
1103 int in_endp = ENDPOINT_NUMBER(endp);
1104 int out_endp = endp_back_channel(in_endp);
1105
1106 if (!endp->is_transcoded)
1107 return;
1108
1109 send_dlcx(endp, in_endp);
1110 send_dlcx(endp, out_endp);
1111}
1112
1113int mgcp_reset_transcoder(struct mgcp_config *cfg)
1114{
1115 if (!cfg->transcoder_ip)
1116 return 0;
1117
1118 static const char mgcp_reset[] = {
1119 "RSIP 1 13@mgw MGCP 1.0\r\n"
1120 };
1121
1122 return send_trans(cfg, mgcp_reset, sizeof mgcp_reset -1);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +08001123}