blob: 8adc4c7b4a49859f458ac90302d9a2144c5385d4 [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 Freyther7bdc6372010-02-20 21:21:02 +01005 * (C) 2009-2010 by Holger Hans Peter Freyther <zecke@selfish.org>
6 * (C) 2009-2010 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
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (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
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 *
23 */
24
25#include <ctype.h>
26#include <stdio.h>
27#include <stdlib.h>
28#include <string.h>
29#include <time.h>
30#include <limits.h>
31#include <unistd.h>
32
33#include <sys/socket.h>
34#include <arpa/inet.h>
35
36#include <openbsc/debug.h>
37#include <openbsc/msgb.h>
38#include <openbsc/talloc.h>
39#include <openbsc/gsm_data.h>
40#include <openbsc/select.h>
41#include <openbsc/mgcp.h>
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +010042#include <openbsc/mgcp_internal.h>
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +010043
44#warning "Make use of the rtp proxy code"
45
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +010046enum mgcp_connection_mode {
47 MGCP_CONN_NONE = 0,
48 MGCP_CONN_RECV_ONLY = 1,
49 MGCP_CONN_SEND_ONLY = 2,
50 MGCP_CONN_RECV_SEND = MGCP_CONN_RECV_ONLY | MGCP_CONN_SEND_ONLY,
51};
52
53enum {
54 DEST_NETWORK = 0,
55 DEST_BTS = 1,
56};
57
58enum {
59 PROTO_RTP,
60 PROTO_RTCP,
61};
62
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +010063/**
64 * Macro for tokenizing MGCP messages and SDP in one go.
65 *
66 */
67#define MSG_TOKENIZE_START \
68 line_start = 0; \
69 for (i = 0; i < msgb_l3len(msg); ++i) { \
70 /* we have a line end */ \
71 if (msg->l3h[i] == '\n') { \
72 /* skip the first line */ \
73 if (line_start == 0) { \
74 line_start = i + 1; \
75 continue; \
76 } \
77 \
78 /* check if we have a proper param */ \
79 if (i - line_start == 1 && msg->l3h[line_start] == '\r') { \
80 } else if (i - line_start > 2 \
81 && islower(msg->l3h[line_start]) \
82 && msg->l3h[line_start + 1] == '=') { \
83 } else if (i - line_start < 3 \
84 || msg->l3h[line_start + 1] != ':' \
85 || msg->l3h[line_start + 2] != ' ') \
86 goto error; \
87 \
88 msg->l3h[i] = '\0'; \
89 if (msg->l3h[i-1] == '\r') \
90 msg->l3h[i-1] = '\0';
91
92#define MSG_TOKENIZE_END \
93 line_start = i + 1; \
94 } \
95 }
96
97
98struct mgcp_msg_ptr {
99 unsigned int start;
100 unsigned int length;
101};
102
103struct mgcp_request {
104 char *name;
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100105 struct msgb *(*handle_request) (struct mgcp_config *cfg, struct msgb *msg);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100106 char *debug_name;
107};
108
109#define MGCP_REQUEST(NAME, REQ, DEBUG_NAME) \
110 { .name = NAME, .handle_request = REQ, .debug_name = DEBUG_NAME },
111
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100112static struct msgb *handle_audit_endpoint(struct mgcp_config *cfg, struct msgb *msg);
113static struct msgb *handle_create_con(struct mgcp_config *cfg, struct msgb *msg);
114static struct msgb *handle_delete_con(struct mgcp_config *cfg, struct msgb *msg);
115static struct msgb *handle_modify_con(struct mgcp_config *cfg, struct msgb *msg);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100116
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100117static int generate_call_id(struct mgcp_config *cfg)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100118{
119 int i;
120
121 /* use the call id */
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100122 ++cfg->last_call_id;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100123
124 /* handle wrap around */
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100125 if (cfg->last_call_id == CI_UNUSED)
126 ++cfg->last_call_id;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100127
128 /* callstack can only be of size number_of_endpoints */
129 /* verify that the call id is free, e.g. in case of overrun */
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100130 for (i = 1; i < cfg->number_endpoints; ++i)
131 if (cfg->endpoints[i].ci == cfg->last_call_id)
132 return generate_call_id(cfg);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100133
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100134 return cfg->last_call_id;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100135}
136
137/* FIXIME/TODO: need to have a list of pending transactions and check that */
138static unsigned int generate_transaction_id()
139{
140 return abs(rand());
141}
142
143static int udp_send(int fd, struct in_addr *addr, int port, char *buf, int len)
144{
145 struct sockaddr_in out;
146 out.sin_family = AF_INET;
147 out.sin_port = port;
148 memcpy(&out.sin_addr, addr, sizeof(*addr));
149
150 return sendto(fd, buf, len, 0, (struct sockaddr *)&out, sizeof(out));
151}
152
153/*
154 * There is data coming. We will have to figure out if it
155 * came from the BTS or the MediaGateway of the MSC. On top
156 * of that we need to figure out if it was RTP or RTCP.
157 *
158 * Currently we do not communicate with the BSC so we have
159 * no idea where the BTS is listening for RTP and need to
160 * do the classic routing trick. Wait for the first packet
161 * from the BTS and then go ahead.
162 */
163static int rtp_data_cb(struct bsc_fd *fd, unsigned int what)
164{
165 char buf[4096];
166 struct sockaddr_in addr;
167 socklen_t slen = sizeof(addr);
168 struct mgcp_endpoint *endp;
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100169 struct mgcp_config *cfg;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100170 int rc, dest, proto;
171
172 endp = (struct mgcp_endpoint *) fd->data;
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100173 cfg = endp->cfg;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100174
175 rc = recvfrom(fd->fd, &buf, sizeof(buf), 0,
176 (struct sockaddr *) &addr, &slen);
177 if (rc < 0) {
Holger Hans Peter Freyther2ada71d2010-02-03 09:13:10 +0100178 LOGP(DMGCP, LOGL_ERROR, "Failed to receive message on: 0x%x\n",
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100179 ENDPOINT_NUMBER(endp));
180 return -1;
181 }
182
183 /* do not forward aynthing... maybe there is a packet from the bts */
184 if (endp->ci == CI_UNUSED) {
Holger Hans Peter Freyther2ada71d2010-02-03 09:13:10 +0100185 LOGP(DMGCP, LOGL_ERROR, "Unknown message on endpoint: 0x%x\n", ENDPOINT_NUMBER(endp));
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100186 return -1;
187 }
188
189 /*
190 * Figure out where to forward it to. This code assumes that we
191 * have received the Connection Modify and know who is a legitimate
192 * partner. According to the spec we could attempt to forward even
193 * after the Create Connection but we will not as we are not really
194 * able to tell if this is legitimate.
195 */
196 #warning "Slight spec violation. With connection mode recvonly we should attempt to forward."
197 dest = memcmp(&addr.sin_addr, &endp->remote, sizeof(addr.sin_addr)) == 0 &&
198 (endp->net_rtp == addr.sin_port || endp->net_rtcp == addr.sin_port)
199 ? DEST_BTS : DEST_NETWORK;
200 proto = fd == &endp->local_rtp ? PROTO_RTP : PROTO_RTCP;
201
202 /* We have no idea who called us, maybe it is the BTS. */
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100203 if (dest == DEST_NETWORK && (endp->bts_rtp == 0 || cfg->forward_ip)) {
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100204 /* it was the BTS... */
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100205 if (!cfg->bts_ip || memcmp(&addr.sin_addr, &cfg->bts_in, sizeof(cfg->bts_in)) == 0) {
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100206 if (fd == &endp->local_rtp) {
207 endp->bts_rtp = addr.sin_port;
208 } else {
209 endp->bts_rtcp = addr.sin_port;
210 }
211
212 endp->bts = addr.sin_addr;
Holger Hans Peter Freyther2ada71d2010-02-03 09:13:10 +0100213 LOGP(DMGCP, LOGL_NOTICE, "Found BTS for endpoint: 0x%x on port: %d/%d\n",
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100214 ENDPOINT_NUMBER(endp), ntohs(endp->bts_rtp), ntohs(endp->bts_rtcp));
215 }
216 }
217
218 /* dispatch */
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100219 if (cfg->audio_loop)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100220 dest = !dest;
221
222 if (dest == DEST_NETWORK) {
223 return udp_send(fd->fd, &endp->remote,
224 proto == PROTO_RTP ? endp->net_rtp : endp->net_rtcp,
225 buf, rc);
226 } else {
227 return udp_send(fd->fd, &endp->bts,
228 proto == PROTO_RTP ? endp->bts_rtp : endp->bts_rtcp,
229 buf, rc);
230 }
231}
232
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100233static int create_bind(const char *source_addr, struct bsc_fd *fd, int port)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100234{
235 struct sockaddr_in addr;
236 int on = 1;
237
238 fd->fd = socket(AF_INET, SOCK_DGRAM, 0);
Holger Hans Peter Freyther2ada71d2010-02-03 09:13:10 +0100239 if (fd->fd < 0) {
240 LOGP(DMGCP, LOGL_ERROR, "Failed to create UDP port.\n");
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100241 return -1;
Holger Hans Peter Freyther2ada71d2010-02-03 09:13:10 +0100242 }
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100243
244 setsockopt(fd->fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
245 memset(&addr, 0, sizeof(addr));
246 addr.sin_family = AF_INET;
247 addr.sin_port = htons(port);
248 inet_aton(source_addr, &addr.sin_addr);
249
Holger Hans Peter Freyther2ada71d2010-02-03 09:13:10 +0100250 if (bind(fd->fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100251 return -1;
Holger Hans Peter Freyther2ada71d2010-02-03 09:13:10 +0100252 }
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100253
254 return 0;
255}
256
257static int bind_rtp(struct mgcp_endpoint *endp)
258{
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100259 struct mgcp_config *cfg = endp->cfg;
260
261 if (create_bind(cfg->source_addr, &endp->local_rtp, endp->rtp_port) != 0) {
Holger Hans Peter Freyther2ada71d2010-02-03 09:13:10 +0100262 LOGP(DMGCP, LOGL_ERROR, "Failed to create RTP port: %s:%d on 0x%x\n",
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100263 cfg->source_addr, endp->rtp_port, ENDPOINT_NUMBER(endp));
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100264 goto cleanup0;
265 }
266
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100267 if (create_bind(cfg->source_addr, &endp->local_rtcp, endp->rtp_port + 1) != 0) {
Holger Hans Peter Freyther2ada71d2010-02-03 09:13:10 +0100268 LOGP(DMGCP, LOGL_ERROR, "Failed to create RTCP port: %s:%d on 0x%x\n",
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100269 cfg->source_addr, endp->rtp_port + 1, ENDPOINT_NUMBER(endp));
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100270 goto cleanup1;
271 }
272
273 endp->local_rtp.cb = rtp_data_cb;
274 endp->local_rtp.data = endp;
275 endp->local_rtp.when = BSC_FD_READ;
276 if (bsc_register_fd(&endp->local_rtp) != 0) {
Holger Hans Peter Freyther2ada71d2010-02-03 09:13:10 +0100277 LOGP(DMGCP, LOGL_ERROR, "Failed to register RTP port %d on 0x%x\n",
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100278 endp->rtp_port, ENDPOINT_NUMBER(endp));
279 goto cleanup2;
280 }
281
282 endp->local_rtcp.cb = rtp_data_cb;
283 endp->local_rtcp.data = endp;
284 endp->local_rtcp.when = BSC_FD_READ;
285 if (bsc_register_fd(&endp->local_rtcp) != 0) {
Holger Hans Peter Freyther2ada71d2010-02-03 09:13:10 +0100286 LOGP(DMGCP, LOGL_ERROR, "Failed to register RTCP port %d on 0x%x\n",
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100287 endp->rtp_port + 1, ENDPOINT_NUMBER(endp));
288 goto cleanup3;
289 }
290
291 return 0;
292
293cleanup3:
294 bsc_unregister_fd(&endp->local_rtp);
295cleanup2:
296 close(endp->local_rtcp.fd);
297 endp->local_rtcp.fd = -1;
298cleanup1:
299 close(endp->local_rtp.fd);
300 endp->local_rtp.fd = -1;
301cleanup0:
302 return -1;
303}
304
305/*
306 * array of function pointers for handling various
307 * messages. In the future this might be binary sorted
308 * for performance reasons.
309 */
310static const struct mgcp_request mgcp_requests [] = {
311 MGCP_REQUEST("AUEP", handle_audit_endpoint, "AuditEndpoint")
312 MGCP_REQUEST("CRCX", handle_create_con, "CreateConnection")
313 MGCP_REQUEST("DLCX", handle_delete_con, "DeleteConnection")
314 MGCP_REQUEST("MDCX", handle_modify_con, "ModifiyConnection")
315};
316
Holger Hans Peter Freyther62e836c2010-02-03 11:03:45 +0100317static struct msgb *mgcp_msgb_alloc(void)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100318{
Holger Hans Peter Freyther62e836c2010-02-03 11:03:45 +0100319 struct msgb *msg;
320 msg = msgb_alloc_headroom(4096, 128, "MGCP msg");
321 if (!msg)
322 LOGP(DMGCP, LOGL_ERROR, "Failed to msgb for MGCP data.\n");
323
324 return msg;
325}
326
327static struct msgb *send_response_with_data(int code, const char *msg, const char *trans,
328 const char *data)
329{
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100330 int len;
Holger Hans Peter Freyther62e836c2010-02-03 11:03:45 +0100331 struct msgb *res;
332
333 res = mgcp_msgb_alloc();
334 if (!res)
335 return NULL;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100336
337 if (data) {
Holger Hans Peter Freyther62e836c2010-02-03 11:03:45 +0100338 len = snprintf((char *) res->data, 2048, "%d %s\n%s", code, trans, data);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100339 } else {
Holger Hans Peter Freyther62e836c2010-02-03 11:03:45 +0100340 len = snprintf((char *) res->data, 2048, "%d %s\n", code, trans);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100341 }
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100342
Holger Hans Peter Freyther62e836c2010-02-03 11:03:45 +0100343 res->l2h = msgb_put(res, len);
344 LOGP(DMGCP, LOGL_NOTICE, "Sending response: code: %d for '%s'\n", code, res->l2h);
345 return res;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100346}
347
Holger Hans Peter Freyther62e836c2010-02-03 11:03:45 +0100348static struct msgb *send_response(int code, const char *msg, const char *trans)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100349{
Holger Hans Peter Freyther62e836c2010-02-03 11:03:45 +0100350 return send_response_with_data(code, msg, trans, NULL);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100351}
352
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100353static struct msgb *send_with_sdp(struct mgcp_endpoint *endp,
354 const char *msg, const char *trans_id)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100355{
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100356 const char *addr = endp->cfg->local_ip;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100357 char sdp_record[4096];
358
359 if (!addr)
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100360 addr = endp->cfg->source_addr;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100361
362 snprintf(sdp_record, sizeof(sdp_record) - 1,
363 "I: %d\n\n"
364 "v=0\r\n"
365 "c=IN IP4 %s\r\n"
366 "m=audio %d RTP/AVP %d\r\n"
367 "a=rtpmap:%d %s\r\n",
368 endp->ci, addr, endp->rtp_port,
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100369 endp->cfg->audio_payload, endp->cfg->audio_payload,
370 endp->cfg->audio_name);
Holger Hans Peter Freyther62e836c2010-02-03 11:03:45 +0100371 return send_response_with_data(200, msg, trans_id, sdp_record);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100372}
373
374/* send a static record */
Holger Hans Peter Freyther62e836c2010-02-03 11:03:45 +0100375struct msgb *mgcp_create_rsip(void)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100376{
Holger Hans Peter Freyther62e836c2010-02-03 11:03:45 +0100377 struct msgb *msg;
378 int len;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100379
Holger Hans Peter Freyther62e836c2010-02-03 11:03:45 +0100380 msg = mgcp_msgb_alloc();
381 if (!msg)
382 return NULL;
383
384 len = snprintf((char *) msg->data, 2048,
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100385 "RSIP %u *@mgw MGCP 1.0\n"
386 "RM: restart\n", generate_transaction_id());
Holger Hans Peter Freyther62e836c2010-02-03 11:03:45 +0100387 msg->l2h = msgb_put(msg, len);
388 return msg;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100389}
390
391/*
392 * handle incoming messages:
393 * - this can be a command (four letters, space, transaction id)
394 * - or a response (three numbers, space, transaction id)
395 */
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100396struct msgb *mgcp_handle_message(struct mgcp_config *cfg, struct msgb *msg)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100397{
398 int code;
Holger Hans Peter Freyther62e836c2010-02-03 11:03:45 +0100399 struct msgb *resp = NULL;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100400
401 if (msg->len < 4) {
Holger Hans Peter Freyther2ada71d2010-02-03 09:13:10 +0100402 LOGP(DMGCP, LOGL_ERROR, "mgs too short: %d\n", msg->len);
Holger Hans Peter Freyther62e836c2010-02-03 11:03:45 +0100403 return NULL;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100404 }
405
406 /* attempt to treat it as a response */
407 if (sscanf((const char *)&msg->data[0], "%3d %*s", &code) == 1) {
Holger Hans Peter Freyther2ada71d2010-02-03 09:13:10 +0100408 LOGP(DMGCP, LOGL_NOTICE, "Response: Code: %d\n", code);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100409 } else {
410 int i, handled = 0;
411 msg->l3h = &msg->l2h[4];
412 for (i = 0; i < ARRAY_SIZE(mgcp_requests); ++i)
413 if (strncmp(mgcp_requests[i].name, (const char *) &msg->data[0], 4) == 0) {
414 handled = 1;
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100415 resp = mgcp_requests[i].handle_request(cfg, msg);
Holger Hans Peter Freyther62e836c2010-02-03 11:03:45 +0100416 break;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100417 }
418 if (!handled) {
Holger Hans Peter Freyther2ada71d2010-02-03 09:13:10 +0100419 LOGP(DMGCP, LOGL_NOTICE, "MSG with type: '%.4s' not handled\n", &msg->data[0]);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100420 }
421 }
422
Holger Hans Peter Freyther62e836c2010-02-03 11:03:45 +0100423 return resp;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100424}
425
426/* string tokenizer for the poor */
427static int find_msg_pointers(struct msgb *msg, struct mgcp_msg_ptr *ptrs, int ptrs_length)
428{
429 int i, found = 0;
430
431 int whitespace = 1;
432 for (i = 0; i < msgb_l3len(msg) && ptrs_length > 0; ++i) {
433 /* if we have a space we found an end */
434 if (msg->l3h[i] == ' ' || msg->l3h[i] == '\r' || msg->l3h[i] == '\n') {
435 if (!whitespace) {
436 ++found;
437 whitespace = 1;
438 ptrs->length = i - ptrs->start - 1;
439 ++ptrs;
440 --ptrs_length;
441 } else {
442 /* skip any number of whitespace */
443 }
444
445 /* line end... stop */
446 if (msg->l3h[i] == '\r' || msg->l3h[i] == '\n')
447 break;
448 } else if (msg->l3h[i] == '\r' || msg->l3h[i] == '\n') {
449 /* line end, be done */
450 break;
451 } else if (whitespace) {
452 whitespace = 0;
453 ptrs->start = i;
454 }
455 }
456
457 if (ptrs_length == 0)
458 return -1;
459 return found;
460}
461
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100462static struct mgcp_endpoint *find_endpoint(struct mgcp_config *cfg, const char *mgcp)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100463{
464 char *endptr = NULL;
465 unsigned int gw = INT_MAX;
466
467 gw = strtoul(mgcp, &endptr, 16);
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100468 if (gw == 0 || gw >= cfg->number_endpoints || strcmp(endptr, "@mgw") != 0) {
Holger Hans Peter Freyther2ada71d2010-02-03 09:13:10 +0100469 LOGP(DMGCP, LOGL_ERROR, "Not able to find endpoint: '%s'\n", mgcp);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100470 return NULL;
471 }
472
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100473 return &cfg->endpoints[gw];
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100474}
475
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100476static int analyze_header(struct mgcp_config *cfg, struct msgb *msg,
477 struct mgcp_msg_ptr *ptr, int size,
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100478 const char **transaction_id, struct mgcp_endpoint **endp)
479{
480 int found;
481
482 if (size < 3) {
Holger Hans Peter Freyther2ada71d2010-02-03 09:13:10 +0100483 LOGP(DMGCP, LOGL_ERROR, "Not enough space in ptr\n");
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100484 return -1;
485 }
486
487 found = find_msg_pointers(msg, ptr, size);
488
489 if (found < 3) {
Holger Hans Peter Freyther2ada71d2010-02-03 09:13:10 +0100490 LOGP(DMGCP, LOGL_ERROR, "Gateway: Not enough params. Found: %d\n", found);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100491 return -1;
492 }
493
494 /*
495 * replace the space with \0. the main method gurantess that
496 * we still have + 1 for null termination
497 */
498 msg->l3h[ptr[3].start + ptr[3].length + 1] = '\0';
499 msg->l3h[ptr[2].start + ptr[2].length + 1] = '\0';
500 msg->l3h[ptr[1].start + ptr[1].length + 1] = '\0';
501 msg->l3h[ptr[0].start + ptr[0].length + 1] = '\0';
502
503 if (strncmp("1.0", (const char *)&msg->l3h[ptr[3].start], 3) != 0
504 || strncmp("MGCP", (const char *)&msg->l3h[ptr[2].start], 4) != 0) {
Holger Hans Peter Freyther2ada71d2010-02-03 09:13:10 +0100505 LOGP(DMGCP, LOGL_ERROR, "Wrong MGCP version. Not handling: '%s' '%s'\n",
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100506 (const char *)&msg->l3h[ptr[3].start],
507 (const char *)&msg->l3h[ptr[2].start]);
508 return -1;
509 }
510
511 *transaction_id = (const char *)&msg->l3h[ptr[0].start];
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100512 *endp = find_endpoint(cfg, (const char *)&msg->l3h[ptr[1].start]);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100513 return *endp == NULL;
514}
515
516static int verify_call_id(const struct mgcp_endpoint *endp,
517 const char *callid)
518{
519 if (strcmp(endp->callid, callid) != 0) {
Holger Hans Peter Freyther2ada71d2010-02-03 09:13:10 +0100520 LOGP(DMGCP, LOGL_ERROR, "CallIDs does not match on 0x%x. '%s' != '%s'\n",
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100521 ENDPOINT_NUMBER(endp), endp->callid, callid);
522 return -1;
523 }
524
525 return 0;
526}
527
528static int verify_ci(const struct mgcp_endpoint *endp,
529 const char *ci)
530{
531 if (atoi(ci) != endp->ci) {
Holger Hans Peter Freyther2ada71d2010-02-03 09:13:10 +0100532 LOGP(DMGCP, LOGL_ERROR, "ConnectionIdentifiers do not match on 0x%x. %d != %s\n",
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100533 ENDPOINT_NUMBER(endp), endp->ci, ci);
534 return -1;
535 }
536
537 return 0;
538}
539
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100540static struct msgb *handle_audit_endpoint(struct mgcp_config *cfg, struct msgb *msg)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100541{
542 struct mgcp_msg_ptr data_ptrs[6];
543 int found, response;
544 const char *trans_id;
545 struct mgcp_endpoint *endp;
546
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100547 found = analyze_header(cfg, msg, data_ptrs, ARRAY_SIZE(data_ptrs), &trans_id, &endp);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100548 if (found != 0)
549 response = 500;
550 else
551 response = 200;
552
Holger Hans Peter Freyther62e836c2010-02-03 11:03:45 +0100553 return send_response(response, "AUEP", trans_id);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100554}
555
556static int parse_conn_mode(const char* msg, int *conn_mode)
557{
558 int ret = 0;
559 if (strcmp(msg, "recvonly") == 0)
560 *conn_mode = MGCP_CONN_RECV_ONLY;
561 else if (strcmp(msg, "sendrecv") == 0)
562 *conn_mode = MGCP_CONN_RECV_SEND;
563 else {
Holger Hans Peter Freyther2ada71d2010-02-03 09:13:10 +0100564 LOGP(DMGCP, LOGL_ERROR, "Unknown connection mode: '%s'\n", msg);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100565 ret = -1;
566 }
567
568 return ret;
569}
570
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100571static struct msgb *handle_create_con(struct mgcp_config *cfg, struct msgb *msg)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100572{
573 struct mgcp_msg_ptr data_ptrs[6];
574 int found, i, line_start;
575 const char *trans_id;
576 struct mgcp_endpoint *endp;
577 int error_code = 500;
578
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100579 found = analyze_header(cfg, msg, data_ptrs, ARRAY_SIZE(data_ptrs), &trans_id, &endp);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100580 if (found != 0)
Holger Hans Peter Freyther62e836c2010-02-03 11:03:45 +0100581 return send_response(500, "CRCX", trans_id);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100582
583 if (endp->ci != CI_UNUSED) {
Holger Hans Peter Freyther2ada71d2010-02-03 09:13:10 +0100584 LOGP(DMGCP, LOGL_ERROR, "Endpoint is already used. 0x%x\n", ENDPOINT_NUMBER(endp));
Holger Hans Peter Freyther62e836c2010-02-03 11:03:45 +0100585 return send_response(500, "CRCX", trans_id);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100586 }
587
588 /* parse CallID C: and LocalParameters L: */
589 MSG_TOKENIZE_START
590 switch (msg->l3h[line_start]) {
591 case 'L':
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100592 endp->local_options = talloc_strdup(cfg->endpoints,
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100593 (const char *)&msg->l3h[line_start + 3]);
594 break;
595 case 'C':
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100596 endp->callid = talloc_strdup(cfg->endpoints,
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100597 (const char *)&msg->l3h[line_start + 3]);
598 break;
599 case 'M':
600 if (parse_conn_mode((const char *)&msg->l3h[line_start + 3],
601 &endp->conn_mode) != 0) {
602 error_code = 517;
603 goto error2;
604 }
605 break;
606 default:
Holger Hans Peter Freyther2ada71d2010-02-03 09:13:10 +0100607 LOGP(DMGCP, LOGL_NOTICE, "Unhandled option: '%c'/%d on 0x%x\n",
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100608 msg->l3h[line_start], msg->l3h[line_start],
609 ENDPOINT_NUMBER(endp));
610 break;
611 }
612 MSG_TOKENIZE_END
613
614 /* initialize */
615 endp->net_rtp = endp->net_rtcp = endp->bts_rtp = endp->bts_rtcp = 0;
616
617 /* set to zero until we get the info */
618 memset(&endp->remote, 0, sizeof(endp->remote));
619
620 /* bind to the port now */
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100621 endp->rtp_port = rtp_calculate_port(ENDPOINT_NUMBER(endp), cfg->rtp_base_port);
622 if (!cfg->early_bind && bind_rtp(endp) != 0)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100623 goto error2;
624
625 /* assign a local call identifier or fail */
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100626 endp->ci = generate_call_id(cfg);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100627 if (endp->ci == CI_UNUSED)
628 goto error2;
629
Holger Hans Peter Freyther2ada71d2010-02-03 09:13:10 +0100630 LOGP(DMGCP, LOGL_NOTICE, "Creating endpoint on: 0x%x CI: %u port: %u\n",
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100631 ENDPOINT_NUMBER(endp), endp->ci, endp->rtp_port);
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100632 if (cfg->change_cb)
633 cfg->change_cb(cfg, ENDPOINT_NUMBER(endp), MGCP_ENDP_CRCX, endp->rtp_port);
Holger Hans Peter Freyther77f7afe2010-02-03 09:54:43 +0100634
Holger Hans Peter Freyther62e836c2010-02-03 11:03:45 +0100635 return send_with_sdp(endp, "CRCX", trans_id);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100636error:
Holger Hans Peter Freyther2ada71d2010-02-03 09:13:10 +0100637 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 +0100638 hexdump(msg->l3h, msgb_l3len(msg)),
639 ENDPOINT_NUMBER(endp), line_start, i);
Holger Hans Peter Freyther62e836c2010-02-03 11:03:45 +0100640 return send_response(error_code, "CRCX", trans_id);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100641
642error2:
Holger Hans Peter Freyther2ada71d2010-02-03 09:13:10 +0100643 LOGP(DMGCP, LOGL_NOTICE, "Resource error on 0x%x\n", ENDPOINT_NUMBER(endp));
Holger Hans Peter Freyther62e836c2010-02-03 11:03:45 +0100644 return send_response(error_code, "CRCX", trans_id);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100645}
646
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100647static struct msgb *handle_modify_con(struct mgcp_config *cfg, struct msgb *msg)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100648{
649 struct mgcp_msg_ptr data_ptrs[6];
650 int found, i, line_start;
651 const char *trans_id;
652 struct mgcp_endpoint *endp;
653 int error_code = 500;
654
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100655 found = analyze_header(cfg, msg, data_ptrs, ARRAY_SIZE(data_ptrs), &trans_id, &endp);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100656 if (found != 0)
Holger Hans Peter Freyther62e836c2010-02-03 11:03:45 +0100657 return send_response(error_code, "MDCX", trans_id);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100658
659 if (endp->ci == CI_UNUSED) {
Holger Hans Peter Freyther2ada71d2010-02-03 09:13:10 +0100660 LOGP(DMGCP, LOGL_ERROR, "Endpoint is not holding a connection. 0x%x\n", ENDPOINT_NUMBER(endp));
Holger Hans Peter Freyther62e836c2010-02-03 11:03:45 +0100661 return send_response(error_code, "MDCX", trans_id);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100662 }
663
664 MSG_TOKENIZE_START
665 switch (msg->l3h[line_start]) {
666 case 'C': {
667 if (verify_call_id(endp, (const char *)&msg->l3h[line_start + 3]) != 0)
668 goto error3;
669 break;
670 }
671 case 'I': {
672 if (verify_ci(endp, (const char *)&msg->l3h[line_start + 3]) != 0)
673 goto error3;
674 break;
675 }
676 case 'L':
677 /* skip */
678 break;
679 case 'M':
680 if (parse_conn_mode((const char *)&msg->l3h[line_start + 3],
681 &endp->conn_mode) != 0) {
682 error_code = 517;
683 goto error3;
684 }
685 break;
686 case '\0':
687 /* SDP file begins */
688 break;
689 case 'a':
690 case 'o':
691 case 's':
692 case 't':
693 case 'v':
694 /* skip these SDP attributes */
695 break;
696 case 'm': {
697 int port;
698 const char *param = (const char *)&msg->l3h[line_start];
699
700 if (sscanf(param, "m=audio %d RTP/AVP %*d", &port) == 1) {
701 endp->net_rtp = htons(port);
702 endp->net_rtcp = htons(port + 1);
703 }
704 break;
705 }
706 case 'c': {
707 char ipv4[16];
708 const char *param = (const char *)&msg->l3h[line_start];
709
710 if (sscanf(param, "c=IN IP4 %15s", ipv4) == 1) {
711 inet_aton(ipv4, &endp->remote);
712 }
713 break;
714 }
715 default:
Holger Hans Peter Freyther2ada71d2010-02-03 09:13:10 +0100716 LOGP(DMGCP, LOGL_NOTICE, "Unhandled option: '%c'/%d on 0x%x\n",
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100717 msg->l3h[line_start], msg->l3h[line_start],
718 ENDPOINT_NUMBER(endp));
719 break;
720 }
721 MSG_TOKENIZE_END
722
723 /* modify */
Holger Hans Peter Freyther2ada71d2010-02-03 09:13:10 +0100724 LOGP(DMGCP, LOGL_NOTICE, "Modified endpoint on: 0x%x Server: %s:%u\n",
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100725 ENDPOINT_NUMBER(endp), inet_ntoa(endp->remote), endp->net_rtp);
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100726 if (cfg->change_cb)
727 cfg->change_cb(cfg, ENDPOINT_NUMBER(endp), MGCP_ENDP_MDCX, endp->rtp_port);
Holger Hans Peter Freyther62e836c2010-02-03 11:03:45 +0100728 return send_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 Freyther62e836c2010-02-03 11:03:45 +0100734 return send_response(error_code, "MDCX", trans_id);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100735
736error3:
Holger Hans Peter Freyther62e836c2010-02-03 11:03:45 +0100737 return send_response(error_code, "MDCX", trans_id);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100738}
739
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100740static struct msgb *handle_delete_con(struct mgcp_config *cfg, struct msgb *msg)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100741{
742 struct mgcp_msg_ptr data_ptrs[6];
743 int found, i, line_start;
744 const char *trans_id;
745 struct mgcp_endpoint *endp;
746 int error_code = 500;
747
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100748 found = analyze_header(cfg, msg, data_ptrs, ARRAY_SIZE(data_ptrs), &trans_id, &endp);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100749 if (found != 0)
Holger Hans Peter Freyther62e836c2010-02-03 11:03:45 +0100750 return send_response(error_code, "DLCX", trans_id);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100751
752 if (endp->ci == CI_UNUSED) {
Holger Hans Peter Freyther2ada71d2010-02-03 09:13:10 +0100753 LOGP(DMGCP, LOGL_ERROR, "Endpoint is not used. 0x%x\n", ENDPOINT_NUMBER(endp));
Holger Hans Peter Freyther62e836c2010-02-03 11:03:45 +0100754 return send_response(error_code, "DLCX", trans_id);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100755 }
756
757 MSG_TOKENIZE_START
758 switch (msg->l3h[line_start]) {
759 case 'C': {
760 if (verify_call_id(endp, (const char *)&msg->l3h[line_start + 3]) != 0)
761 goto error3;
762 break;
763 }
764 case 'I': {
765 if (verify_ci(endp, (const char *)&msg->l3h[line_start + 3]) != 0)
766 goto error3;
767 break;
768 }
769 default:
Holger Hans Peter Freyther2ada71d2010-02-03 09:13:10 +0100770 LOGP(DMGCP, LOGL_NOTICE, "Unhandled option: '%c'/%d on 0x%x\n",
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100771 msg->l3h[line_start], msg->l3h[line_start],
772 ENDPOINT_NUMBER(endp));
773 break;
774 }
775 MSG_TOKENIZE_END
776
777
778 /* free the connection */
Holger Hans Peter Freyther2ada71d2010-02-03 09:13:10 +0100779 LOGP(DMGCP, LOGL_NOTICE, "Deleting endpoint on: 0x%x\n", ENDPOINT_NUMBER(endp));
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100780 endp->ci= CI_UNUSED;
781 talloc_free(endp->callid);
782 talloc_free(endp->local_options);
783
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100784 if (!cfg->early_bind) {
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100785 bsc_unregister_fd(&endp->local_rtp);
786 bsc_unregister_fd(&endp->local_rtcp);
787 }
788
789 endp->net_rtp = endp->net_rtcp = endp->bts_rtp = endp->bts_rtcp = 0;
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100790 if (cfg->change_cb)
791 cfg->change_cb(cfg, ENDPOINT_NUMBER(endp), MGCP_ENDP_DLCX, endp->rtp_port);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100792
Holger Hans Peter Freyther62e836c2010-02-03 11:03:45 +0100793 return send_response(250, "DLCX", trans_id);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100794
795error:
Holger Hans Peter Freyther2ada71d2010-02-03 09:13:10 +0100796 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 +0100797 hexdump(msg->l3h, msgb_l3len(msg)),
798 ENDPOINT_NUMBER(endp), line_start, i);
Holger Hans Peter Freyther62e836c2010-02-03 11:03:45 +0100799 return send_response(error_code, "DLCX", trans_id);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100800
801error3:
Holger Hans Peter Freyther62e836c2010-02-03 11:03:45 +0100802 return send_response(error_code, "DLCX", trans_id);
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100803}
804
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100805struct mgcp_config *mgcp_config_alloc(void)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100806{
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100807 struct mgcp_config *cfg;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100808
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100809 cfg = talloc_zero(NULL, struct mgcp_config);
810 if (!cfg) {
811 LOGP(DMGCP, LOGL_FATAL, "Failed to allocate config.\n");
812 return NULL;
813 }
814
815 cfg->source_port = 2427;
816 cfg->source_addr = talloc_strdup(cfg, "0.0.0.0");
817 cfg->audio_name = talloc_strdup(cfg, "GSM-EFR/8000");
818 cfg->audio_payload = 97;
819 cfg->rtp_base_port = RTP_PORT_DEFAULT;
820
821 return cfg;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100822}
823
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100824int mgcp_endpoints_allocate(struct mgcp_config *cfg)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100825{
826 int i;
827
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100828 /* Initialize all endpoints */
829 cfg->endpoints = _talloc_zero_array(cfg,
830 sizeof(struct mgcp_endpoint),
831 cfg->number_endpoints, "endpoints");
832 if (!cfg->endpoints)
833 return -1;
834
835 for (i = 0; i < cfg->number_endpoints; ++i) {
836 cfg->endpoints[i].local_rtp.fd = -1;
837 cfg->endpoints[i].local_rtcp.fd = -1;
838 cfg->endpoints[i].ci = CI_UNUSED;
839 cfg->endpoints[i].cfg = cfg;
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100840 }
841
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100842 return 0;
843}
844
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100845int mgcp_bind_rtp_port(struct mgcp_endpoint *endp, int rtp_port)
Holger Hans Peter Freythere0955022010-02-03 08:50:33 +0100846{
Holger Hans Peter Freyther7bdc6372010-02-20 21:21:02 +0100847 endp->rtp_port = rtp_port;
848 return bind_rtp(endp);
Holger Hans Peter Freyther77f7afe2010-02-03 09:54:43 +0100849}