From 7bdc637aaeb3159bcb68b9ece31356176c0a0880 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Sat, 20 Feb 2010 21:21:02 +0100 Subject: [PATCH 01/11] [mgcp] Move away from global variables and split out VTY code In separation of using the MGCP parsing in another context, refactor the code to operate on a struct mgcp_config, split out the vty code from the mgcp_protocol.c, and move the callbacks into the mgcp code. There should be no functional changes. --- openbsc/include/openbsc/Makefile.am | 2 +- openbsc/include/openbsc/mgcp.h | 57 ++- openbsc/include/openbsc/mgcp_internal.h | 61 +++ openbsc/src/Makefile.am | 3 +- openbsc/src/mgcp/mgcp_main.c | 30 +- openbsc/src/mgcp/mgcp_protocol.c | 481 +++++------------------- openbsc/src/mgcp/mgcp_vty.c | 338 +++++++++++++++++ 7 files changed, 551 insertions(+), 421 deletions(-) create mode 100644 openbsc/include/openbsc/mgcp_internal.h create mode 100644 openbsc/src/mgcp/mgcp_vty.c diff --git a/openbsc/include/openbsc/Makefile.am b/openbsc/include/openbsc/Makefile.am index b4760252e..05b802d48 100644 --- a/openbsc/include/openbsc/Makefile.am +++ b/openbsc/include/openbsc/Makefile.am @@ -5,4 +5,4 @@ noinst_HEADERS = abis_nm.h abis_rsl.h debug.h db.h gsm_04_08.h gsm_data.h \ gsm_utils.h ipaccess.h rs232.h openbscdefines.h rtp_proxy.h \ bsc_rll.h mncc.h talloc.h transaction.h ussd.h gsm_04_80.h \ silent_call.h mgcp.h meas_rep.h bitvec.h rest_octets.h \ - system_information.h handover.h statistics.h + system_information.h handover.h statistics.h mgcp_internal.h diff --git a/openbsc/include/openbsc/mgcp.h b/openbsc/include/openbsc/mgcp.h index 5b4aa3eec..5baf0ca1d 100644 --- a/openbsc/include/openbsc/mgcp.h +++ b/openbsc/include/openbsc/mgcp.h @@ -1,8 +1,8 @@ /* A Media Gateway Control Protocol Media Gateway: RFC 3435 */ /* - * (C) 2009 by Holger Hans Peter Freyther - * (C) 2009 by On-Waves + * (C) 2009-2010 by Holger Hans Peter Freyther + * (C) 2009-2010 by On-Waves * All Rights Reserved * * This program is free software; you can redistribute it and/or modify @@ -26,8 +26,9 @@ #include "msgb.h" +#include + #define RTP_PORT_DEFAULT 4000 -extern unsigned int rtp_base_port; /** * Calculate the RTP audio port for the given multiplex @@ -53,18 +54,54 @@ static inline int rtp_calculate_port(int multiplex, int base) return base + (multiplex * 2); } -int mgcp_parse_config(const char *config_file, struct gsm_network *dummy_network); -struct msgb *mgcp_handle_message(struct msgb *msg); -struct msgb *mgcp_create_rsip(void); -int mgcp_vty_init(void); +/* + * Handling of MGCP Endpoints and the MGCP Config + */ +struct mgcp_endpoint; +struct mgcp_config; -/* endpoint managed */ #define MGCP_ENDP_CRCX 1 #define MGCP_ENDP_DLCX 2 #define MGCP_ENDP_MDCX 3 -typedef int (*mgcp_change)(int endpoint, int state, int local_rtp, void *); -void mgcp_set_change_cb(mgcp_change cb, void *data); +typedef int (*mgcp_change)(struct mgcp_config *cfg, int endpoint, int state, int local_rtp); + +struct mgcp_config { + int source_port; + char *local_ip; + char *source_addr; + unsigned int number_endpoints; + char *bts_ip; + + struct in_addr bts_in; + char *audio_name; + int audio_payload; + int audio_loop; + int early_bind; + int rtp_base_port; + + char *forward_ip; + int forward_port; + + mgcp_change change_cb; + + struct mgcp_endpoint *endpoints; + unsigned int last_call_id; +}; + +/* config management */ +struct mgcp_config *mgcp_config_alloc(void); +int mgcp_parse_config(const char *config_file, struct mgcp_config *cfg); +int mgcp_vty_init(void); +int mgcp_endpoints_allocate(struct mgcp_config *cfg); +int mgcp_bind_rtp_port(struct mgcp_endpoint *endp, int rtp_port); + +/* + * format helper functions + */ +struct msgb *mgcp_handle_message(struct mgcp_config *cfg, struct msgb *msg); +struct msgb *mgcp_create_rsip(void); + #endif diff --git a/openbsc/include/openbsc/mgcp_internal.h b/openbsc/include/openbsc/mgcp_internal.h new file mode 100644 index 000000000..2848d5bd0 --- /dev/null +++ b/openbsc/include/openbsc/mgcp_internal.h @@ -0,0 +1,61 @@ +/* MGCP Private Data */ + +/* + * (C) 2009-2010 by Holger Hans Peter Freyther + * (C) 2009-2010 by On-Waves + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +#ifndef OPENBSC_MGCP_DATA_H +#define OPENBSC_MGCP_DATA_H + +#include "select.h" + +#define CI_UNUSED 0 + +struct mgcp_endpoint { + int ci; + char *callid; + char *local_options; + int conn_mode; + + /* the local rtp port we are binding to */ + int rtp_port; + + /* + * RTP mangling: + * - we get RTP and RTCP to us and need to forward to the BTS + * - we get RTP and RTCP from the BTS and forward to the network + */ + struct bsc_fd local_rtp; + struct bsc_fd local_rtcp; + + struct in_addr remote; + struct in_addr bts; + + /* in network byte order */ + int net_rtp, net_rtcp; + int bts_rtp, bts_rtcp; + + /* backpointer */ + struct mgcp_config *cfg; +}; + +#define ENDPOINT_NUMBER(endp) abs(endp - endp->cfg->endpoints) + +#endif diff --git a/openbsc/src/Makefile.am b/openbsc/src/Makefile.am index 161c283f6..dec635933 100644 --- a/openbsc/src/Makefile.am +++ b/openbsc/src/Makefile.am @@ -38,7 +38,8 @@ ipaccess_config_LDADD = libbsc.a libmsc.a libbsc.a libvty.a -ldl -ldbi $(LIBCRYP isdnsync_SOURCES = isdnsync.c -bsc_mgcp_SOURCES = mgcp/mgcp_main.c mgcp/mgcp_protocol.c msgb.c talloc.c debug.c select.c timer.c telnet_interface.c +bsc_mgcp_SOURCES = mgcp/mgcp_main.c mgcp/mgcp_protocol.c mgcp/mgcp_vty.c \ + msgb.c talloc.c debug.c select.c timer.c telnet_interface.c bsc_mgcp_LDADD = libvty.a ipaccess_proxy_SOURCES = ipaccess/ipaccess-proxy.c msgb.c select.c talloc.c debug.c timer.c diff --git a/openbsc/src/mgcp/mgcp_main.c b/openbsc/src/mgcp/mgcp_main.c index 7d318b191..32abef2c6 100644 --- a/openbsc/src/mgcp/mgcp_main.c +++ b/openbsc/src/mgcp/mgcp_main.c @@ -31,7 +31,6 @@ #include #include -#include #include #include @@ -41,9 +40,6 @@ #include #include -#include -#include - /* this is here for the vty... it will never be called */ void subscr_put() { abort(); } @@ -52,18 +48,15 @@ void subscr_put() { abort(); } #warning "Make use of the rtp proxy code" -static int source_port = 2427; -static const char *source_addr = "0.0.0.0"; static struct bsc_fd bfd; static int first_request = 1; +static struct mgcp_config *cfg; static char *config_file = "mgcp.cfg"; /* used by msgb and mgcp */ void *tall_bsc_ctx = NULL; -unsigned int rtp_base_port = RTP_PORT_DEFAULT; - static void print_help() { printf("Some useful help...\n"); @@ -136,7 +129,7 @@ static int read_call_agent(struct bsc_fd *fd, unsigned int what) /* handle message now */ msg->l2h = msgb_put(msg, rc); - resp = mgcp_handle_message(msg); + resp = mgcp_handle_message(cfg, msg); msgb_reset(msg); if (resp) { @@ -147,15 +140,6 @@ static int read_call_agent(struct bsc_fd *fd, unsigned int what) } -int bsc_vty_init(struct gsm_network *dummy) -{ - cmd_init(1); - vty_init(); - - mgcp_vty_init(); - return 0; -} - int main(int argc, char** argv) { struct gsm_network dummy_network; @@ -170,10 +154,14 @@ int main(int argc, char** argv) debug_add_target(stderr_target); debug_set_all_filter(stderr_target, 1); + cfg = mgcp_config_alloc(); + if (!cfg) + return -1; + handle_options(argc, argv); telnet_init(&dummy_network, 4243); - rc = mgcp_parse_config(config_file, &dummy_network); + rc = mgcp_parse_config(config_file, cfg); if (rc < 0) return rc; @@ -192,8 +180,8 @@ int main(int argc, char** argv) memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; - addr.sin_port = htons(source_port); - inet_aton(source_addr, &addr.sin_addr); + addr.sin_port = htons(cfg->source_port); + inet_aton(cfg->source_addr, &addr.sin_addr); if (bind(bfd.fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) { perror("Gateway failed to bind"); diff --git a/openbsc/src/mgcp/mgcp_protocol.c b/openbsc/src/mgcp/mgcp_protocol.c index 53573f3b2..8adc4c7b4 100644 --- a/openbsc/src/mgcp/mgcp_protocol.c +++ b/openbsc/src/mgcp/mgcp_protocol.c @@ -2,8 +2,8 @@ /* The protocol implementation */ /* - * (C) 2009 by Holger Hans Peter Freyther - * (C) 2009 by On-Waves + * (C) 2009-2010 by Holger Hans Peter Freyther + * (C) 2009-2010 by On-Waves * All Rights Reserved * * This program is free software; you can redistribute it and/or modify @@ -39,27 +39,10 @@ #include #include #include -#include - -#include -#include +#include #warning "Make use of the rtp proxy code" -static int source_port = 2427; -static const char *local_ip = NULL; -static const char *source_addr = "0.0.0.0"; -static unsigned int number_endpoints = 0; -static const char *bts_ip = NULL; -static struct in_addr bts_in; -static const char *audio_name = "GSM-EFR/8000"; -static int audio_payload = 97; -static int audio_loop = 0; -static int early_bind = 0; - -static char *forward_ip = NULL; -static int forward_port = 0; - enum mgcp_connection_mode { MGCP_CONN_NONE = 0, MGCP_CONN_RECV_ONLY = 1, @@ -77,37 +60,6 @@ enum { PROTO_RTCP, }; -#define CI_UNUSED 0 -static unsigned int last_call_id = 0; - -struct mgcp_endpoint { - int ci; - char *callid; - char *local_options; - int conn_mode; - - /* the local rtp port we are binding to */ - int rtp_port; - - /* - * RTP mangling: - * - we get RTP and RTCP to us and need to forward to the BTS - * - we get RTP and RTCP from the BTS and forward to the network - */ - struct bsc_fd local_rtp; - struct bsc_fd local_rtcp; - - struct in_addr remote; - struct in_addr bts; - - /* in network byte order */ - int net_rtp, net_rtcp; - int bts_rtp, bts_rtcp; -}; - -static struct mgcp_endpoint *endpoints = NULL; -#define ENDPOINT_NUMBER(endp) abs(endp - endpoints) - /** * Macro for tokenizing MGCP messages and SDP in one go. * @@ -150,39 +102,36 @@ struct mgcp_msg_ptr { struct mgcp_request { char *name; - struct msgb *(*handle_request) (struct msgb *msg); + struct msgb *(*handle_request) (struct mgcp_config *cfg, struct msgb *msg); char *debug_name; }; #define MGCP_REQUEST(NAME, REQ, DEBUG_NAME) \ { .name = NAME, .handle_request = REQ, .debug_name = DEBUG_NAME }, -static struct msgb *handle_audit_endpoint(struct msgb *msg); -static struct msgb *handle_create_con(struct msgb *msg); -static struct msgb *handle_delete_con(struct msgb *msg); -static struct msgb *handle_modify_con(struct msgb *msg); +static struct msgb *handle_audit_endpoint(struct mgcp_config *cfg, struct msgb *msg); +static struct msgb *handle_create_con(struct mgcp_config *cfg, struct msgb *msg); +static struct msgb *handle_delete_con(struct mgcp_config *cfg, struct msgb *msg); +static struct msgb *handle_modify_con(struct mgcp_config *cfg, struct msgb *msg); -static mgcp_change change_cb; -static void *change_cb_data; - -static int generate_call_id() +static int generate_call_id(struct mgcp_config *cfg) { int i; /* use the call id */ - ++last_call_id; + ++cfg->last_call_id; /* handle wrap around */ - if (last_call_id == CI_UNUSED) - ++last_call_id; + if (cfg->last_call_id == CI_UNUSED) + ++cfg->last_call_id; /* callstack can only be of size number_of_endpoints */ /* verify that the call id is free, e.g. in case of overrun */ - for (i = 1; i < number_endpoints; ++i) - if (endpoints[i].ci == last_call_id) - return generate_call_id(); + for (i = 1; i < cfg->number_endpoints; ++i) + if (cfg->endpoints[i].ci == cfg->last_call_id) + return generate_call_id(cfg); - return last_call_id; + return cfg->last_call_id; } /* FIXIME/TODO: need to have a list of pending transactions and check that */ @@ -217,9 +166,11 @@ static int rtp_data_cb(struct bsc_fd *fd, unsigned int what) struct sockaddr_in addr; socklen_t slen = sizeof(addr); struct mgcp_endpoint *endp; + struct mgcp_config *cfg; int rc, dest, proto; endp = (struct mgcp_endpoint *) fd->data; + cfg = endp->cfg; rc = recvfrom(fd->fd, &buf, sizeof(buf), 0, (struct sockaddr *) &addr, &slen); @@ -249,9 +200,9 @@ static int rtp_data_cb(struct bsc_fd *fd, unsigned int what) proto = fd == &endp->local_rtp ? PROTO_RTP : PROTO_RTCP; /* We have no idea who called us, maybe it is the BTS. */ - if (dest == DEST_NETWORK && (endp->bts_rtp == 0 || forward_ip)) { + if (dest == DEST_NETWORK && (endp->bts_rtp == 0 || cfg->forward_ip)) { /* it was the BTS... */ - if (!bts_ip || memcmp(&addr.sin_addr, &bts_in, sizeof(bts_in)) == 0) { + if (!cfg->bts_ip || memcmp(&addr.sin_addr, &cfg->bts_in, sizeof(cfg->bts_in)) == 0) { if (fd == &endp->local_rtp) { endp->bts_rtp = addr.sin_port; } else { @@ -265,7 +216,7 @@ static int rtp_data_cb(struct bsc_fd *fd, unsigned int what) } /* dispatch */ - if (audio_loop) + if (cfg->audio_loop) dest = !dest; if (dest == DEST_NETWORK) { @@ -279,7 +230,7 @@ static int rtp_data_cb(struct bsc_fd *fd, unsigned int what) } } -static int create_bind(struct bsc_fd *fd, int port) +static int create_bind(const char *source_addr, struct bsc_fd *fd, int port) { struct sockaddr_in addr; int on = 1; @@ -305,15 +256,17 @@ static int create_bind(struct bsc_fd *fd, int port) static int bind_rtp(struct mgcp_endpoint *endp) { - if (create_bind(&endp->local_rtp, endp->rtp_port) != 0) { + struct mgcp_config *cfg = endp->cfg; + + if (create_bind(cfg->source_addr, &endp->local_rtp, endp->rtp_port) != 0) { LOGP(DMGCP, LOGL_ERROR, "Failed to create RTP port: %s:%d on 0x%x\n", - source_addr, endp->rtp_port, ENDPOINT_NUMBER(endp)); + cfg->source_addr, endp->rtp_port, ENDPOINT_NUMBER(endp)); goto cleanup0; } - if (create_bind(&endp->local_rtcp, endp->rtp_port + 1) != 0) { + if (create_bind(cfg->source_addr, &endp->local_rtcp, endp->rtp_port + 1) != 0) { LOGP(DMGCP, LOGL_ERROR, "Failed to create RTCP port: %s:%d on 0x%x\n", - source_addr, endp->rtp_port + 1, ENDPOINT_NUMBER(endp)); + cfg->source_addr, endp->rtp_port + 1, ENDPOINT_NUMBER(endp)); goto cleanup1; } @@ -397,13 +350,14 @@ static struct msgb *send_response(int code, const char *msg, const char *trans) return send_response_with_data(code, msg, trans, NULL); } -static struct msgb *send_with_sdp(struct mgcp_endpoint *endp, const char *msg, const char *trans_id) +static struct msgb *send_with_sdp(struct mgcp_endpoint *endp, + const char *msg, const char *trans_id) { - const char *addr = local_ip; + const char *addr = endp->cfg->local_ip; char sdp_record[4096]; if (!addr) - addr = source_addr; + addr = endp->cfg->source_addr; snprintf(sdp_record, sizeof(sdp_record) - 1, "I: %d\n\n" @@ -412,7 +366,8 @@ static struct msgb *send_with_sdp(struct mgcp_endpoint *endp, const char *msg, c "m=audio %d RTP/AVP %d\r\n" "a=rtpmap:%d %s\r\n", endp->ci, addr, endp->rtp_port, - audio_payload, audio_payload, audio_name); + endp->cfg->audio_payload, endp->cfg->audio_payload, + endp->cfg->audio_name); return send_response_with_data(200, msg, trans_id, sdp_record); } @@ -438,7 +393,7 @@ struct msgb *mgcp_create_rsip(void) * - this can be a command (four letters, space, transaction id) * - or a response (three numbers, space, transaction id) */ -struct msgb *mgcp_handle_message(struct msgb *msg) +struct msgb *mgcp_handle_message(struct mgcp_config *cfg, struct msgb *msg) { int code; struct msgb *resp = NULL; @@ -457,7 +412,7 @@ struct msgb *mgcp_handle_message(struct msgb *msg) for (i = 0; i < ARRAY_SIZE(mgcp_requests); ++i) if (strncmp(mgcp_requests[i].name, (const char *) &msg->data[0], 4) == 0) { handled = 1; - resp = mgcp_requests[i].handle_request(msg); + resp = mgcp_requests[i].handle_request(cfg, msg); break; } if (!handled) { @@ -504,21 +459,22 @@ static int find_msg_pointers(struct msgb *msg, struct mgcp_msg_ptr *ptrs, int pt return found; } -static struct mgcp_endpoint *find_endpoint(const char *mgcp) +static struct mgcp_endpoint *find_endpoint(struct mgcp_config *cfg, const char *mgcp) { char *endptr = NULL; unsigned int gw = INT_MAX; gw = strtoul(mgcp, &endptr, 16); - if (gw == 0 || gw >= number_endpoints || strcmp(endptr, "@mgw") != 0) { + if (gw == 0 || gw >= cfg->number_endpoints || strcmp(endptr, "@mgw") != 0) { LOGP(DMGCP, LOGL_ERROR, "Not able to find endpoint: '%s'\n", mgcp); return NULL; } - return &endpoints[gw]; + return &cfg->endpoints[gw]; } -static int analyze_header(struct msgb *msg, struct mgcp_msg_ptr *ptr, int size, +static int analyze_header(struct mgcp_config *cfg, struct msgb *msg, + struct mgcp_msg_ptr *ptr, int size, const char **transaction_id, struct mgcp_endpoint **endp) { int found; @@ -553,7 +509,7 @@ static int analyze_header(struct msgb *msg, struct mgcp_msg_ptr *ptr, int size, } *transaction_id = (const char *)&msg->l3h[ptr[0].start]; - *endp = find_endpoint((const char *)&msg->l3h[ptr[1].start]); + *endp = find_endpoint(cfg, (const char *)&msg->l3h[ptr[1].start]); return *endp == NULL; } @@ -581,14 +537,14 @@ static int verify_ci(const struct mgcp_endpoint *endp, return 0; } -static struct msgb *handle_audit_endpoint(struct msgb *msg) +static struct msgb *handle_audit_endpoint(struct mgcp_config *cfg, struct msgb *msg) { struct mgcp_msg_ptr data_ptrs[6]; int found, response; const char *trans_id; struct mgcp_endpoint *endp; - found = analyze_header(msg, data_ptrs, ARRAY_SIZE(data_ptrs), &trans_id, &endp); + found = analyze_header(cfg, msg, data_ptrs, ARRAY_SIZE(data_ptrs), &trans_id, &endp); if (found != 0) response = 500; else @@ -612,7 +568,7 @@ static int parse_conn_mode(const char* msg, int *conn_mode) return ret; } -static struct msgb *handle_create_con(struct msgb *msg) +static struct msgb *handle_create_con(struct mgcp_config *cfg, struct msgb *msg) { struct mgcp_msg_ptr data_ptrs[6]; int found, i, line_start; @@ -620,7 +576,7 @@ static struct msgb *handle_create_con(struct msgb *msg) struct mgcp_endpoint *endp; int error_code = 500; - found = analyze_header(msg, data_ptrs, ARRAY_SIZE(data_ptrs), &trans_id, &endp); + found = analyze_header(cfg, msg, data_ptrs, ARRAY_SIZE(data_ptrs), &trans_id, &endp); if (found != 0) return send_response(500, "CRCX", trans_id); @@ -633,11 +589,11 @@ static struct msgb *handle_create_con(struct msgb *msg) MSG_TOKENIZE_START switch (msg->l3h[line_start]) { case 'L': - endp->local_options = talloc_strdup(endpoints, + endp->local_options = talloc_strdup(cfg->endpoints, (const char *)&msg->l3h[line_start + 3]); break; case 'C': - endp->callid = talloc_strdup(endpoints, + endp->callid = talloc_strdup(cfg->endpoints, (const char *)&msg->l3h[line_start + 3]); break; case 'M': @@ -662,19 +618,19 @@ static struct msgb *handle_create_con(struct msgb *msg) memset(&endp->remote, 0, sizeof(endp->remote)); /* bind to the port now */ - endp->rtp_port = rtp_calculate_port(ENDPOINT_NUMBER(endp), rtp_base_port); - if (!early_bind && bind_rtp(endp) != 0) + endp->rtp_port = rtp_calculate_port(ENDPOINT_NUMBER(endp), cfg->rtp_base_port); + if (!cfg->early_bind && bind_rtp(endp) != 0) goto error2; /* assign a local call identifier or fail */ - endp->ci = generate_call_id(); + endp->ci = generate_call_id(cfg); if (endp->ci == CI_UNUSED) goto error2; LOGP(DMGCP, LOGL_NOTICE, "Creating endpoint on: 0x%x CI: %u port: %u\n", ENDPOINT_NUMBER(endp), endp->ci, endp->rtp_port); - if (change_cb) - change_cb(ENDPOINT_NUMBER(endp), MGCP_ENDP_CRCX, endp->rtp_port, change_cb_data); + if (cfg->change_cb) + cfg->change_cb(cfg, ENDPOINT_NUMBER(endp), MGCP_ENDP_CRCX, endp->rtp_port); return send_with_sdp(endp, "CRCX", trans_id); error: @@ -688,7 +644,7 @@ error2: return send_response(error_code, "CRCX", trans_id); } -static struct msgb *handle_modify_con(struct msgb *msg) +static struct msgb *handle_modify_con(struct mgcp_config *cfg, struct msgb *msg) { struct mgcp_msg_ptr data_ptrs[6]; int found, i, line_start; @@ -696,7 +652,7 @@ static struct msgb *handle_modify_con(struct msgb *msg) struct mgcp_endpoint *endp; int error_code = 500; - found = analyze_header(msg, data_ptrs, ARRAY_SIZE(data_ptrs), &trans_id, &endp); + found = analyze_header(cfg, msg, data_ptrs, ARRAY_SIZE(data_ptrs), &trans_id, &endp); if (found != 0) return send_response(error_code, "MDCX", trans_id); @@ -767,8 +723,8 @@ static struct msgb *handle_modify_con(struct msgb *msg) /* modify */ LOGP(DMGCP, LOGL_NOTICE, "Modified endpoint on: 0x%x Server: %s:%u\n", ENDPOINT_NUMBER(endp), inet_ntoa(endp->remote), endp->net_rtp); - if (change_cb) - change_cb(ENDPOINT_NUMBER(endp), MGCP_ENDP_MDCX, endp->rtp_port, change_cb_data); + if (cfg->change_cb) + cfg->change_cb(cfg, ENDPOINT_NUMBER(endp), MGCP_ENDP_MDCX, endp->rtp_port); return send_with_sdp(endp, "MDCX", trans_id); error: @@ -781,7 +737,7 @@ error3: return send_response(error_code, "MDCX", trans_id); } -static struct msgb *handle_delete_con(struct msgb *msg) +static struct msgb *handle_delete_con(struct mgcp_config *cfg, struct msgb *msg) { struct mgcp_msg_ptr data_ptrs[6]; int found, i, line_start; @@ -789,7 +745,7 @@ static struct msgb *handle_delete_con(struct msgb *msg) struct mgcp_endpoint *endp; int error_code = 500; - found = analyze_header(msg, data_ptrs, ARRAY_SIZE(data_ptrs), &trans_id, &endp); + found = analyze_header(cfg, msg, data_ptrs, ARRAY_SIZE(data_ptrs), &trans_id, &endp); if (found != 0) return send_response(error_code, "DLCX", trans_id); @@ -825,14 +781,14 @@ static struct msgb *handle_delete_con(struct msgb *msg) talloc_free(endp->callid); talloc_free(endp->local_options); - if (!early_bind) { + if (!cfg->early_bind) { bsc_unregister_fd(&endp->local_rtp); bsc_unregister_fd(&endp->local_rtcp); } endp->net_rtp = endp->net_rtcp = endp->bts_rtp = endp->bts_rtcp = 0; - if (change_cb) - change_cb(ENDPOINT_NUMBER(endp), MGCP_ENDP_DLCX, endp->rtp_port, change_cb_data); + if (cfg->change_cb) + cfg->change_cb(cfg, ENDPOINT_NUMBER(endp), MGCP_ENDP_DLCX, endp->rtp_port); return send_response(250, "DLCX", trans_id); @@ -846,299 +802,48 @@ error3: return send_response(error_code, "DLCX", trans_id); } -/* - * vty code for mgcp below - */ -struct cmd_node mgcp_node = { - MGCP_NODE, - "%s(mgcp)#", - 1, -}; - -static int config_write_mgcp(struct vty *vty) +struct mgcp_config *mgcp_config_alloc(void) { - vty_out(vty, "mgcp%s", VTY_NEWLINE); - if (local_ip) - vty_out(vty, " local ip %s%s", local_ip, VTY_NEWLINE); - if (bts_ip) - vty_out(vty, " bts ip %s%s", bts_ip, VTY_NEWLINE); - vty_out(vty, " bind ip %s%s", source_addr, VTY_NEWLINE); - vty_out(vty, " bind port %u%s", source_port, VTY_NEWLINE); - vty_out(vty, " bind early %u%s", !!early_bind, VTY_NEWLINE); - vty_out(vty, " rtp base %u%s", rtp_base_port, VTY_NEWLINE); - vty_out(vty, " sdp audio payload number %u%s", audio_payload, VTY_NEWLINE); - vty_out(vty, " sdp audio payload name %s%s", audio_name, VTY_NEWLINE); - vty_out(vty, " loop %u%s", !!audio_loop, VTY_NEWLINE); - vty_out(vty, " endpoints %u%s", number_endpoints, VTY_NEWLINE); - if (forward_ip) - vty_out(vty, " forward audio ip %s%s", forward_ip, VTY_NEWLINE); - if (forward_port != 0) - vty_out(vty, " forward audio port %d%s", forward_port, VTY_NEWLINE); + struct mgcp_config *cfg; - return CMD_SUCCESS; + cfg = talloc_zero(NULL, struct mgcp_config); + if (!cfg) { + LOGP(DMGCP, LOGL_FATAL, "Failed to allocate config.\n"); + return NULL; + } + + cfg->source_port = 2427; + cfg->source_addr = talloc_strdup(cfg, "0.0.0.0"); + cfg->audio_name = talloc_strdup(cfg, "GSM-EFR/8000"); + cfg->audio_payload = 97; + cfg->rtp_base_port = RTP_PORT_DEFAULT; + + return cfg; } -DEFUN(show_mcgp, show_mgcp_cmd, "show mgcp", - SHOW_STR "Display information about the MGCP Media Gateway") +int mgcp_endpoints_allocate(struct mgcp_config *cfg) { int i; - vty_out(vty, "MGCP is up and running with %u endpoints:%s", number_endpoints - 1, VTY_NEWLINE); - for (i = 1; i < number_endpoints; ++i) { - struct mgcp_endpoint *endp = &endpoints[i]; - vty_out(vty, " Endpoint 0x%.2x: CI: %d net: %u/%u bts: %u/%u%s", - i, endp->ci, - ntohs(endp->net_rtp), ntohs(endp->net_rtcp), - ntohs(endp->bts_rtp), ntohs(endp->bts_rtcp), VTY_NEWLINE); + /* Initialize all endpoints */ + cfg->endpoints = _talloc_zero_array(cfg, + sizeof(struct mgcp_endpoint), + cfg->number_endpoints, "endpoints"); + if (!cfg->endpoints) + return -1; + + for (i = 0; i < cfg->number_endpoints; ++i) { + cfg->endpoints[i].local_rtp.fd = -1; + cfg->endpoints[i].local_rtcp.fd = -1; + cfg->endpoints[i].ci = CI_UNUSED; + cfg->endpoints[i].cfg = cfg; } - return CMD_SUCCESS; -} - -DEFUN(cfg_mgcp, - cfg_mgcp_cmd, - "mgcp", - "Configure the MGCP") -{ - vty->node = MGCP_NODE; - return CMD_SUCCESS; -} - -DEFUN(cfg_mgcp_local_ip, - cfg_mgcp_local_ip_cmd, - "local ip IP", - "Set the IP to be used in SDP records") -{ - local_ip = talloc_strdup(tall_bsc_ctx, argv[0]); - return CMD_SUCCESS; -} - -DEFUN(cfg_mgcp_bts_ip, - cfg_mgcp_bts_ip_cmd, - "bts ip IP", - "Set the IP of the BTS for RTP forwarding") -{ - bts_ip = talloc_strdup(tall_bsc_ctx, argv[0]); - inet_aton(bts_ip, &bts_in); - return CMD_SUCCESS; -} - -DEFUN(cfg_mgcp_bind_ip, - cfg_mgcp_bind_ip_cmd, - "bind ip IP", - "Bind the MGCP to this local addr") -{ - source_addr = talloc_strdup(tall_bsc_ctx, argv[0]); - return CMD_SUCCESS; -} - -DEFUN(cfg_mgcp_bind_port, - cfg_mgcp_bind_port_cmd, - "bind port <0-65534>", - "Bind the MGCP to this port") -{ - unsigned int port = atoi(argv[0]); - if (port > 65534) { - vty_out(vty, "%% wrong bind port '%s'%s", argv[0], VTY_NEWLINE); - return CMD_WARNING; - } - - source_port = port; - return CMD_SUCCESS; -} - -DEFUN(cfg_mgcp_bind_early, - cfg_mgcp_bind_early_cmd, - "bind early (0|1)", - "Bind all RTP ports early") -{ - unsigned int bind = atoi(argv[0]); - if (bind != 0 && bind != 1) { - vty_out(vty, "%% param must be 0 or 1.%s", VTY_NEWLINE); - return CMD_WARNING; - } - - early_bind = bind == 1; - return CMD_SUCCESS; -} - -DEFUN(cfg_mgcp_rtp_base_port, - cfg_mgcp_rtp_base_port_cmd, - "rtp base <0-65534>", - "Base port to use") -{ - unsigned int port = atoi(argv[0]); - if (port > 65534) { - vty_out(vty, "%% wrong base port '%s'%s", argv[0], VTY_NEWLINE); - return CMD_WARNING; - } - - rtp_base_port = port; - return CMD_SUCCESS; -} - -DEFUN(cfg_mgcp_sdp_payload_number, - cfg_mgcp_sdp_payload_number_cmd, - "sdp audio payload number <1-255>", - "Set the audio codec to use") -{ - unsigned int payload = atoi(argv[0]); - if (payload > 255) { - vty_out(vty, "%% wrong payload number '%s'%s", argv[0], VTY_NEWLINE); - return CMD_WARNING; - } - - audio_payload = payload; - return CMD_SUCCESS; -} - -DEFUN(cfg_mgcp_sdp_payload_name, - cfg_mgcp_sdp_payload_name_cmd, - "sdp audio payload name NAME", - "Set the audio name to use") -{ - audio_name = talloc_strdup(tall_bsc_ctx, argv[0]); - return CMD_SUCCESS; -} - -DEFUN(cfg_mgcp_loop, - cfg_mgcp_loop_cmd, - "loop (0|1)", - "Loop the audio") -{ - audio_loop = atoi(argv[0]); - return CMD_SUCCESS; -} - -DEFUN(cfg_mgcp_number_endp, - cfg_mgcp_number_endp_cmd, - "number endpoints <0-65534>", - "The number of endpoints to allocate. This is not dynamic.") -{ - /* + 1 as we start counting at one */ - number_endpoints = atoi(argv[0]) + 1; - return CMD_SUCCESS; -} - -DEFUN(cfg_mgcp_forward_ip, - cfg_mgcp_forward_ip_cmd, - "forward audio ip IP", - "Forward packets from and to the IP. This disables most of the MGCP feature.") -{ - if (forward_ip) - talloc_free(forward_ip); - forward_ip = talloc_strdup(tall_bsc_ctx, argv[0]); - return CMD_SUCCESS; -} - -DEFUN(cfg_mgcp_forward_port, - cfg_mgcp_forward_port_cmd, - "forward audio port <1-15000>", - "Forward packets from and to the port. This disables most of the MGCP feature.") -{ - forward_port = atoi(argv[0]); - return CMD_SUCCESS; -} - -int mgcp_vty_init(void) -{ - install_element(VIEW_NODE, &show_mgcp_cmd); - - install_element(CONFIG_NODE, &cfg_mgcp_cmd); - install_node(&mgcp_node, config_write_mgcp); - install_default(MGCP_NODE); - install_element(MGCP_NODE, &cfg_mgcp_local_ip_cmd); - install_element(MGCP_NODE, &cfg_mgcp_bts_ip_cmd); - install_element(MGCP_NODE, &cfg_mgcp_bind_ip_cmd); - install_element(MGCP_NODE, &cfg_mgcp_bind_port_cmd); - install_element(MGCP_NODE, &cfg_mgcp_bind_early_cmd); - install_element(MGCP_NODE, &cfg_mgcp_rtp_base_port_cmd); - install_element(MGCP_NODE, &cfg_mgcp_sdp_payload_number_cmd); - install_element(MGCP_NODE, &cfg_mgcp_sdp_payload_name_cmd); - install_element(MGCP_NODE, &cfg_mgcp_loop_cmd); - install_element(MGCP_NODE, &cfg_mgcp_number_endp_cmd); - install_element(MGCP_NODE, &cfg_mgcp_forward_ip_cmd); - install_element(MGCP_NODE, &cfg_mgcp_forward_port_cmd); return 0; } -int mgcp_parse_config(const char *config_file, struct gsm_network *dummy_network) +int mgcp_bind_rtp_port(struct mgcp_endpoint *endp, int rtp_port) { - int i, rc; - - rc = vty_read_config_file(config_file); - if (rc < 0) { - fprintf(stderr, "Failed to parse the config file: '%s'\n", config_file); - return rc; - } - - - if (!bts_ip) - fprintf(stderr, "No BTS ip address specified. This will allow everyone to connect.\n"); - - endpoints = _talloc_zero_array(tall_bsc_ctx, - sizeof(struct mgcp_endpoint), - number_endpoints, "endpoints"); - if (!endpoints) { - fprintf(stderr, "Failed to allocate endpoints: %d. Quitting.\n", number_endpoints); - return -1; - } - - /* Initialize all endpoints */ - for (i = 0; i < number_endpoints; ++i) { - endpoints[i].local_rtp.fd = -1; - endpoints[i].local_rtcp.fd = -1; - endpoints[i].ci = CI_UNUSED; - } - - /* - * This application supports two modes. - * 1.) a true MGCP gateway with support for AUEP, CRCX, MDCX, DLCX - * 2.) plain forwarding of RTP packets on the endpoints. - * both modes are mutual exclusive - */ - if (forward_ip) { - int port = rtp_base_port; - if (forward_port != 0) - port = forward_port; - - if (!early_bind) { - LOGP(DMGCP, LOGL_NOTICE, "Forwarding requires early bind.\n"); - return -1; - } - - /* - * Store the forward IP and assign a ci. For early bind - * the sockets will be created after this. - */ - for (i = 1; i < number_endpoints; ++i) { - struct mgcp_endpoint *endp = &endpoints[i]; - inet_aton(forward_ip, &endp->remote); - endp->ci = CI_UNUSED + 23; - endp->net_rtp = htons(rtp_calculate_port(ENDPOINT_NUMBER(endp), port)); - endp->net_rtcp = htons(rtp_calculate_port(ENDPOINT_NUMBER(endp), port) + 1); - } - - LOGP(DMGCP, LOGL_NOTICE, "Configured for Audio Forwarding.\n"); - } - - /* early bind */ - if (early_bind) { - for (i = 1; i < number_endpoints; ++i) { - struct mgcp_endpoint *endp = &endpoints[i]; - endp->rtp_port = rtp_calculate_port(ENDPOINT_NUMBER(endp), rtp_base_port); - if (bind_rtp(endp) != 0) { - LOGP(DMGCP, LOGL_FATAL, "Failed to bind: %d\n", endp->rtp_port); - return -1; - } - } - } - - return !!forward_ip; -} - -void mgcp_set_change_cb(mgcp_change cb, void *data) -{ - change_cb = cb; - change_cb_data = data; + endp->rtp_port = rtp_port; + return bind_rtp(endp); } diff --git a/openbsc/src/mgcp/mgcp_vty.c b/openbsc/src/mgcp/mgcp_vty.c new file mode 100644 index 000000000..b297b42a0 --- /dev/null +++ b/openbsc/src/mgcp/mgcp_vty.c @@ -0,0 +1,338 @@ +/* A Media Gateway Control Protocol Media Gateway: RFC 3435 */ +/* The protocol implementation */ + +/* + * (C) 2009-2010 by Holger Hans Peter Freyther + * (C) 2009-2010 by On-Waves + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +#include + +#include +#include +#include +#include + +#include +#include + +static struct mgcp_config *g_cfg = NULL; + +/* + * vty code for mgcp below + */ +struct cmd_node mgcp_node = { + MGCP_NODE, + "%s(mgcp)#", + 1, +}; + +static int config_write_mgcp(struct vty *vty) +{ + vty_out(vty, "mgcp%s", VTY_NEWLINE); + if (g_cfg->local_ip) + vty_out(vty, " local ip %s%s", g_cfg->local_ip, VTY_NEWLINE); + if (g_cfg->bts_ip) + vty_out(vty, " bts ip %s%s", g_cfg->bts_ip, VTY_NEWLINE); + vty_out(vty, " bind ip %s%s", g_cfg->source_addr, VTY_NEWLINE); + vty_out(vty, " bind port %u%s", g_cfg->source_port, VTY_NEWLINE); + vty_out(vty, " bind early %u%s", !!g_cfg->early_bind, VTY_NEWLINE); + vty_out(vty, " rtp base %u%s", g_cfg->rtp_base_port, VTY_NEWLINE); + vty_out(vty, " sdp audio payload number %u%s", g_cfg->audio_payload, VTY_NEWLINE); + vty_out(vty, " sdp audio payload name %s%s", g_cfg->audio_name, VTY_NEWLINE); + vty_out(vty, " loop %u%s", !!g_cfg->audio_loop, VTY_NEWLINE); + vty_out(vty, " endpoints %u%s", g_cfg->number_endpoints, VTY_NEWLINE); + if (g_cfg->forward_ip) + vty_out(vty, " forward audio ip %s%s", g_cfg->forward_ip, VTY_NEWLINE); + if (g_cfg->forward_port != 0) + vty_out(vty, " forward audio port %d%s", g_cfg->forward_port, VTY_NEWLINE); + + return CMD_SUCCESS; +} + +DEFUN(show_mcgp, show_mgcp_cmd, "show mgcp", + SHOW_STR "Display information about the MGCP Media Gateway") +{ + int i; + + vty_out(vty, "MGCP is up and running with %u endpoints:%s", g_cfg->number_endpoints - 1, VTY_NEWLINE); + for (i = 1; i < g_cfg->number_endpoints; ++i) { + struct mgcp_endpoint *endp = &g_cfg->endpoints[i]; + vty_out(vty, " Endpoint 0x%.2x: CI: %d net: %u/%u bts: %u/%u%s", + i, endp->ci, + ntohs(endp->net_rtp), ntohs(endp->net_rtcp), + ntohs(endp->bts_rtp), ntohs(endp->bts_rtcp), VTY_NEWLINE); + } + + return CMD_SUCCESS; +} + +DEFUN(cfg_mgcp, + cfg_mgcp_cmd, + "mgcp", + "Configure the MGCP") +{ + vty->node = MGCP_NODE; + return CMD_SUCCESS; +} + +DEFUN(cfg_mgcp_local_ip, + cfg_mgcp_local_ip_cmd, + "local ip IP", + "Set the IP to be used in SDP records") +{ + if (g_cfg->local_ip) + talloc_free(g_cfg->local_ip); + g_cfg->local_ip = talloc_strdup(g_cfg, argv[0]); + return CMD_SUCCESS; +} + +DEFUN(cfg_mgcp_bts_ip, + cfg_mgcp_bts_ip_cmd, + "bts ip IP", + "Set the IP of the BTS for RTP forwarding") +{ + if (g_cfg->bts_ip) + talloc_free(g_cfg->bts_ip); + g_cfg->bts_ip = talloc_strdup(g_cfg, argv[0]); + inet_aton(g_cfg->bts_ip, &g_cfg->bts_in); + return CMD_SUCCESS; +} + +DEFUN(cfg_mgcp_bind_ip, + cfg_mgcp_bind_ip_cmd, + "bind ip IP", + "Bind the MGCP to this local addr") +{ + if (g_cfg->source_addr) + talloc_free(g_cfg->source_addr); + g_cfg->source_addr = talloc_strdup(g_cfg, argv[0]); + return CMD_SUCCESS; +} + +DEFUN(cfg_mgcp_bind_port, + cfg_mgcp_bind_port_cmd, + "bind port <0-65534>", + "Bind the MGCP to this port") +{ + unsigned int port = atoi(argv[0]); + if (port > 65534) { + vty_out(vty, "%% wrong bind port '%s'%s", argv[0], VTY_NEWLINE); + return CMD_WARNING; + } + + g_cfg->source_port = port; + return CMD_SUCCESS; +} + +DEFUN(cfg_mgcp_bind_early, + cfg_mgcp_bind_early_cmd, + "bind early (0|1)", + "Bind all RTP ports early") +{ + unsigned int bind = atoi(argv[0]); + if (bind != 0 && bind != 1) { + vty_out(vty, "%% param must be 0 or 1.%s", VTY_NEWLINE); + return CMD_WARNING; + } + + g_cfg->early_bind = bind == 1; + return CMD_SUCCESS; +} + +DEFUN(cfg_mgcp_rtp_base_port, + cfg_mgcp_rtp_base_port_cmd, + "rtp base <0-65534>", + "Base port to use") +{ + unsigned int port = atoi(argv[0]); + if (port > 65534) { + vty_out(vty, "%% wrong base port '%s'%s", argv[0], VTY_NEWLINE); + return CMD_WARNING; + } + + g_cfg->rtp_base_port = port; + return CMD_SUCCESS; +} + +DEFUN(cfg_mgcp_sdp_payload_number, + cfg_mgcp_sdp_payload_number_cmd, + "sdp audio payload number <1-255>", + "Set the audio codec to use") +{ + unsigned int payload = atoi(argv[0]); + if (payload > 255) { + vty_out(vty, "%% wrong payload number '%s'%s", argv[0], VTY_NEWLINE); + return CMD_WARNING; + } + + g_cfg->audio_payload = payload; + return CMD_SUCCESS; +} + +DEFUN(cfg_mgcp_sdp_payload_name, + cfg_mgcp_sdp_payload_name_cmd, + "sdp audio payload name NAME", + "Set the audio name to use") +{ + if (g_cfg->audio_name) + talloc_free(g_cfg->audio_name); + g_cfg->audio_name = talloc_strdup(g_cfg, argv[0]); + return CMD_SUCCESS; +} + +DEFUN(cfg_mgcp_loop, + cfg_mgcp_loop_cmd, + "loop (0|1)", + "Loop the audio") +{ + g_cfg->audio_loop = atoi(argv[0]); + return CMD_SUCCESS; +} + +DEFUN(cfg_mgcp_number_endp, + cfg_mgcp_number_endp_cmd, + "number endpoints <0-65534>", + "The number of endpoints to allocate. This is not dynamic.") +{ + /* + 1 as we start counting at one */ + g_cfg->number_endpoints = atoi(argv[0]) + 1; + return CMD_SUCCESS; +} + +DEFUN(cfg_mgcp_forward_ip, + cfg_mgcp_forward_ip_cmd, + "forward audio ip IP", + "Forward packets from and to the IP. This disables most of the MGCP feature.") +{ + if (g_cfg->forward_ip) + talloc_free(g_cfg->forward_ip); + g_cfg->forward_ip = talloc_strdup(g_cfg, argv[0]); + return CMD_SUCCESS; +} + +DEFUN(cfg_mgcp_forward_port, + cfg_mgcp_forward_port_cmd, + "forward audio port <1-15000>", + "Forward packets from and to the port. This disables most of the MGCP feature.") +{ + g_cfg->forward_port = atoi(argv[0]); + return CMD_SUCCESS; +} + +int mgcp_vty_init(void) +{ + install_element(VIEW_NODE, &show_mgcp_cmd); + + install_element(CONFIG_NODE, &cfg_mgcp_cmd); + install_node(&mgcp_node, config_write_mgcp); + install_default(MGCP_NODE); + install_element(MGCP_NODE, &cfg_mgcp_local_ip_cmd); + install_element(MGCP_NODE, &cfg_mgcp_bts_ip_cmd); + install_element(MGCP_NODE, &cfg_mgcp_bind_ip_cmd); + install_element(MGCP_NODE, &cfg_mgcp_bind_port_cmd); + install_element(MGCP_NODE, &cfg_mgcp_bind_early_cmd); + install_element(MGCP_NODE, &cfg_mgcp_rtp_base_port_cmd); + install_element(MGCP_NODE, &cfg_mgcp_sdp_payload_number_cmd); + install_element(MGCP_NODE, &cfg_mgcp_sdp_payload_name_cmd); + install_element(MGCP_NODE, &cfg_mgcp_loop_cmd); + install_element(MGCP_NODE, &cfg_mgcp_number_endp_cmd); + install_element(MGCP_NODE, &cfg_mgcp_forward_ip_cmd); + install_element(MGCP_NODE, &cfg_mgcp_forward_port_cmd); + return 0; +} + +int mgcp_parse_config(const char *config_file, struct mgcp_config *cfg) +{ + int i, rc; + + g_cfg = cfg; + rc = vty_read_config_file(config_file); + if (rc < 0) { + fprintf(stderr, "Failed to parse the config file: '%s'\n", config_file); + return rc; + } + + + if (!g_cfg->bts_ip) + fprintf(stderr, "No BTS ip address specified. This will allow everyone to connect.\n"); + + if (mgcp_endpoints_allocate(g_cfg) != 0) { + fprintf(stderr, "Failed to allocate endpoints: %d. Quitting.\n", g_cfg->number_endpoints); + return -1; + } + + /* + * This application supports two modes. + * 1.) a true MGCP gateway with support for AUEP, CRCX, MDCX, DLCX + * 2.) plain forwarding of RTP packets on the endpoints. + * both modes are mutual exclusive + */ + if (g_cfg->forward_ip) { + int port = g_cfg->rtp_base_port; + if (g_cfg->forward_port != 0) + port = g_cfg->forward_port; + + if (!g_cfg->early_bind) { + LOGP(DMGCP, LOGL_NOTICE, "Forwarding requires early bind.\n"); + return -1; + } + + /* + * Store the forward IP and assign a ci. For early bind + * the sockets will be created after this. + */ + for (i = 1; i < g_cfg->number_endpoints; ++i) { + struct mgcp_endpoint *endp = &g_cfg->endpoints[i]; + inet_aton(g_cfg->forward_ip, &endp->remote); + endp->ci = CI_UNUSED + 23; + endp->net_rtp = htons(rtp_calculate_port(ENDPOINT_NUMBER(endp), port)); + endp->net_rtcp = htons(rtp_calculate_port(ENDPOINT_NUMBER(endp), port) + 1); + } + + LOGP(DMGCP, LOGL_NOTICE, "Configured for Audio Forwarding.\n"); + } + + /* early bind */ + if (g_cfg->early_bind) { + for (i = 1; i < g_cfg->number_endpoints; ++i) { + struct mgcp_endpoint *endp = &g_cfg->endpoints[i]; + int rtp_port; + + rtp_port = rtp_calculate_port(ENDPOINT_NUMBER(endp), g_cfg->rtp_base_port); + if (mgcp_bind_rtp_port(endp, rtp_port) != 0) { + LOGP(DMGCP, LOGL_FATAL, "Failed to bind: %d\n", endp->rtp_port); + return -1; + } + } + } + + return !!g_cfg->forward_ip; +} + +struct gsm_network; +int bsc_vty_init(struct gsm_network *dummy) +{ + cmd_init(1); + vty_init(); + + mgcp_vty_init(); + return 0; +} + From 8d188eda158c77b0d7c06cc4e990f645267d16f3 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Sun, 21 Feb 2010 01:44:08 +0100 Subject: [PATCH 02/11] [mgcp] Cleanup the code. send_ was a misleading name The send_ methods stopped to send the MGCP messages but was changed to actually just create a msgb_ that can be sent to a mediagateway. Rename the methods now. --- openbsc/src/mgcp/mgcp_protocol.c | 44 ++++++++++++++++---------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/openbsc/src/mgcp/mgcp_protocol.c b/openbsc/src/mgcp/mgcp_protocol.c index 8adc4c7b4..88273fa55 100644 --- a/openbsc/src/mgcp/mgcp_protocol.c +++ b/openbsc/src/mgcp/mgcp_protocol.c @@ -324,7 +324,7 @@ static struct msgb *mgcp_msgb_alloc(void) return msg; } -static struct msgb *send_response_with_data(int code, const char *msg, const char *trans, +static struct msgb *create_response_with_data(int code, const char *msg, const char *trans, const char *data) { int len; @@ -345,13 +345,13 @@ static struct msgb *send_response_with_data(int code, const char *msg, const cha return res; } -static struct msgb *send_response(int code, const char *msg, const char *trans) +static struct msgb *create_response(int code, const char *msg, const char *trans) { - return send_response_with_data(code, msg, trans, NULL); + return create_response_with_data(code, msg, trans, NULL); } -static struct msgb *send_with_sdp(struct mgcp_endpoint *endp, - const char *msg, const char *trans_id) +static struct msgb *create_response_with_sdp(struct mgcp_endpoint *endp, + const char *msg, const char *trans_id) { const char *addr = endp->cfg->local_ip; char sdp_record[4096]; @@ -368,7 +368,7 @@ static struct msgb *send_with_sdp(struct mgcp_endpoint *endp, endp->ci, addr, endp->rtp_port, endp->cfg->audio_payload, endp->cfg->audio_payload, endp->cfg->audio_name); - return send_response_with_data(200, msg, trans_id, sdp_record); + return create_response_with_data(200, msg, trans_id, sdp_record); } /* send a static record */ @@ -550,7 +550,7 @@ static struct msgb *handle_audit_endpoint(struct mgcp_config *cfg, struct msgb * else response = 200; - return send_response(response, "AUEP", trans_id); + return create_response(response, "AUEP", trans_id); } static int parse_conn_mode(const char* msg, int *conn_mode) @@ -578,11 +578,11 @@ static struct msgb *handle_create_con(struct mgcp_config *cfg, struct msgb *msg) found = analyze_header(cfg, msg, data_ptrs, ARRAY_SIZE(data_ptrs), &trans_id, &endp); if (found != 0) - return send_response(500, "CRCX", trans_id); + return create_response(500, "CRCX", trans_id); if (endp->ci != CI_UNUSED) { LOGP(DMGCP, LOGL_ERROR, "Endpoint is already used. 0x%x\n", ENDPOINT_NUMBER(endp)); - return send_response(500, "CRCX", trans_id); + return create_response(500, "CRCX", trans_id); } /* parse CallID C: and LocalParameters L: */ @@ -632,16 +632,16 @@ static struct msgb *handle_create_con(struct mgcp_config *cfg, struct msgb *msg) if (cfg->change_cb) cfg->change_cb(cfg, ENDPOINT_NUMBER(endp), MGCP_ENDP_CRCX, endp->rtp_port); - return send_with_sdp(endp, "CRCX", trans_id); + return create_response_with_sdp(endp, "CRCX", trans_id); error: LOGP(DMGCP, LOGL_ERROR, "Malformed line: %s on 0x%x with: line_start: %d %d\n", hexdump(msg->l3h, msgb_l3len(msg)), ENDPOINT_NUMBER(endp), line_start, i); - return send_response(error_code, "CRCX", trans_id); + return create_response(error_code, "CRCX", trans_id); error2: LOGP(DMGCP, LOGL_NOTICE, "Resource error on 0x%x\n", ENDPOINT_NUMBER(endp)); - return send_response(error_code, "CRCX", trans_id); + return create_response(error_code, "CRCX", trans_id); } static struct msgb *handle_modify_con(struct mgcp_config *cfg, struct msgb *msg) @@ -654,11 +654,11 @@ static struct msgb *handle_modify_con(struct mgcp_config *cfg, struct msgb *msg) found = analyze_header(cfg, msg, data_ptrs, ARRAY_SIZE(data_ptrs), &trans_id, &endp); if (found != 0) - return send_response(error_code, "MDCX", trans_id); + return create_response(error_code, "MDCX", trans_id); if (endp->ci == CI_UNUSED) { LOGP(DMGCP, LOGL_ERROR, "Endpoint is not holding a connection. 0x%x\n", ENDPOINT_NUMBER(endp)); - return send_response(error_code, "MDCX", trans_id); + return create_response(error_code, "MDCX", trans_id); } MSG_TOKENIZE_START @@ -725,16 +725,16 @@ static struct msgb *handle_modify_con(struct mgcp_config *cfg, struct msgb *msg) ENDPOINT_NUMBER(endp), inet_ntoa(endp->remote), endp->net_rtp); if (cfg->change_cb) cfg->change_cb(cfg, ENDPOINT_NUMBER(endp), MGCP_ENDP_MDCX, endp->rtp_port); - return send_with_sdp(endp, "MDCX", trans_id); + return create_response_with_sdp(endp, "MDCX", trans_id); error: LOGP(DMGCP, LOGL_ERROR, "Malformed line: %s on 0x%x with: line_start: %d %d %d\n", hexdump(msg->l3h, msgb_l3len(msg)), ENDPOINT_NUMBER(endp), line_start, i, msg->l3h[line_start]); - return send_response(error_code, "MDCX", trans_id); + return create_response(error_code, "MDCX", trans_id); error3: - return send_response(error_code, "MDCX", trans_id); + return create_response(error_code, "MDCX", trans_id); } static struct msgb *handle_delete_con(struct mgcp_config *cfg, struct msgb *msg) @@ -747,11 +747,11 @@ static struct msgb *handle_delete_con(struct mgcp_config *cfg, struct msgb *msg) found = analyze_header(cfg, msg, data_ptrs, ARRAY_SIZE(data_ptrs), &trans_id, &endp); if (found != 0) - return send_response(error_code, "DLCX", trans_id); + return create_response(error_code, "DLCX", trans_id); if (endp->ci == CI_UNUSED) { LOGP(DMGCP, LOGL_ERROR, "Endpoint is not used. 0x%x\n", ENDPOINT_NUMBER(endp)); - return send_response(error_code, "DLCX", trans_id); + return create_response(error_code, "DLCX", trans_id); } MSG_TOKENIZE_START @@ -790,16 +790,16 @@ static struct msgb *handle_delete_con(struct mgcp_config *cfg, struct msgb *msg) if (cfg->change_cb) cfg->change_cb(cfg, ENDPOINT_NUMBER(endp), MGCP_ENDP_DLCX, endp->rtp_port); - return send_response(250, "DLCX", trans_id); + return create_response(250, "DLCX", trans_id); error: LOGP(DMGCP, LOGL_ERROR, "Malformed line: %s on 0x%x with: line_start: %d %d\n", hexdump(msg->l3h, msgb_l3len(msg)), ENDPOINT_NUMBER(endp), line_start, i); - return send_response(error_code, "DLCX", trans_id); + return create_response(error_code, "DLCX", trans_id); error3: - return send_response(error_code, "DLCX", trans_id); + return create_response(error_code, "DLCX", trans_id); } struct mgcp_config *mgcp_config_alloc(void) From 6414a0cb223f5ec0651ff3423c7cf9f66d4e0909 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Sun, 21 Feb 2010 10:50:46 +0100 Subject: [PATCH 03/11] [mgcp] Make the creation of the mgcp message public. --- openbsc/include/openbsc/mgcp.h | 1 + openbsc/src/mgcp/mgcp_protocol.c | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/openbsc/include/openbsc/mgcp.h b/openbsc/include/openbsc/mgcp.h index 5baf0ca1d..9307f5b36 100644 --- a/openbsc/include/openbsc/mgcp.h +++ b/openbsc/include/openbsc/mgcp.h @@ -102,6 +102,7 @@ int mgcp_bind_rtp_port(struct mgcp_endpoint *endp, int rtp_port); */ struct msgb *mgcp_handle_message(struct mgcp_config *cfg, struct msgb *msg); struct msgb *mgcp_create_rsip(void); +struct msgb *mgcp_create_response_with_data(int code, const char *msg, const char *trans, const char *data); #endif diff --git a/openbsc/src/mgcp/mgcp_protocol.c b/openbsc/src/mgcp/mgcp_protocol.c index 88273fa55..f7588cd38 100644 --- a/openbsc/src/mgcp/mgcp_protocol.c +++ b/openbsc/src/mgcp/mgcp_protocol.c @@ -324,7 +324,7 @@ static struct msgb *mgcp_msgb_alloc(void) return msg; } -static struct msgb *create_response_with_data(int code, const char *msg, const char *trans, +struct msgb *mgcp_create_response_with_data(int code, const char *msg, const char *trans, const char *data) { int len; @@ -347,7 +347,7 @@ static struct msgb *create_response_with_data(int code, const char *msg, const c static struct msgb *create_response(int code, const char *msg, const char *trans) { - return create_response_with_data(code, msg, trans, NULL); + return mgcp_create_response_with_data(code, msg, trans, NULL); } static struct msgb *create_response_with_sdp(struct mgcp_endpoint *endp, @@ -368,7 +368,7 @@ static struct msgb *create_response_with_sdp(struct mgcp_endpoint *endp, endp->ci, addr, endp->rtp_port, endp->cfg->audio_payload, endp->cfg->audio_payload, endp->cfg->audio_name); - return create_response_with_data(200, msg, trans_id, sdp_record); + return mgcp_create_response_with_data(200, msg, trans_id, sdp_record); } /* send a static record */ From 1b0ea97457e6f0c00ad34a44fe77d99668bf840c Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Sun, 21 Feb 2010 11:11:04 +0100 Subject: [PATCH 04/11] [mgcp] Move the network bits to a separate file... This change separates the protocol from the actual network code (bind, forward data). This will allow to more easily hook up the RTP code from OpenBSC and to not use local sockets at all. --- openbsc/src/Makefile.am | 2 +- openbsc/src/mgcp/mgcp_network.c | 218 +++++++++++++++++++++++++++++++ openbsc/src/mgcp/mgcp_protocol.c | 190 +-------------------------- 3 files changed, 224 insertions(+), 186 deletions(-) create mode 100644 openbsc/src/mgcp/mgcp_network.c diff --git a/openbsc/src/Makefile.am b/openbsc/src/Makefile.am index dec635933..a73399ed7 100644 --- a/openbsc/src/Makefile.am +++ b/openbsc/src/Makefile.am @@ -38,7 +38,7 @@ ipaccess_config_LDADD = libbsc.a libmsc.a libbsc.a libvty.a -ldl -ldbi $(LIBCRYP isdnsync_SOURCES = isdnsync.c -bsc_mgcp_SOURCES = mgcp/mgcp_main.c mgcp/mgcp_protocol.c mgcp/mgcp_vty.c \ +bsc_mgcp_SOURCES = mgcp/mgcp_main.c mgcp/mgcp_protocol.c mgcp/mgcp_network.c mgcp/mgcp_vty.c \ msgb.c talloc.c debug.c select.c timer.c telnet_interface.c bsc_mgcp_LDADD = libvty.a diff --git a/openbsc/src/mgcp/mgcp_network.c b/openbsc/src/mgcp/mgcp_network.c new file mode 100644 index 000000000..e92b0742e --- /dev/null +++ b/openbsc/src/mgcp/mgcp_network.c @@ -0,0 +1,218 @@ +/* A Media Gateway Control Protocol Media Gateway: RFC 3435 */ +/* The protocol implementation */ + +/* + * (C) 2009-2010 by Holger Hans Peter Freyther + * (C) 2009-2010 by On-Waves + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +#warning "Make use of the rtp proxy code" + + +enum { + DEST_NETWORK = 0, + DEST_BTS = 1, +}; + +enum { + PROTO_RTP, + PROTO_RTCP, +}; + + +static int udp_send(int fd, struct in_addr *addr, int port, char *buf, int len) +{ + struct sockaddr_in out; + out.sin_family = AF_INET; + out.sin_port = port; + memcpy(&out.sin_addr, addr, sizeof(*addr)); + + return sendto(fd, buf, len, 0, (struct sockaddr *)&out, sizeof(out)); +} + +/* + * There is data coming. We will have to figure out if it + * came from the BTS or the MediaGateway of the MSC. On top + * of that we need to figure out if it was RTP or RTCP. + * + * Currently we do not communicate with the BSC so we have + * no idea where the BTS is listening for RTP and need to + * do the classic routing trick. Wait for the first packet + * from the BTS and then go ahead. + */ +static int rtp_data_cb(struct bsc_fd *fd, unsigned int what) +{ + char buf[4096]; + struct sockaddr_in addr; + socklen_t slen = sizeof(addr); + struct mgcp_endpoint *endp; + struct mgcp_config *cfg; + int rc, dest, proto; + + endp = (struct mgcp_endpoint *) fd->data; + cfg = endp->cfg; + + rc = recvfrom(fd->fd, &buf, sizeof(buf), 0, + (struct sockaddr *) &addr, &slen); + if (rc < 0) { + LOGP(DMGCP, LOGL_ERROR, "Failed to receive message on: 0x%x\n", + ENDPOINT_NUMBER(endp)); + return -1; + } + + /* do not forward aynthing... maybe there is a packet from the bts */ + if (endp->ci == CI_UNUSED) { + LOGP(DMGCP, LOGL_ERROR, "Unknown message on endpoint: 0x%x\n", ENDPOINT_NUMBER(endp)); + return -1; + } + + /* + * Figure out where to forward it to. This code assumes that we + * have received the Connection Modify and know who is a legitimate + * partner. According to the spec we could attempt to forward even + * after the Create Connection but we will not as we are not really + * able to tell if this is legitimate. + */ + #warning "Slight spec violation. With connection mode recvonly we should attempt to forward." + dest = memcmp(&addr.sin_addr, &endp->remote, sizeof(addr.sin_addr)) == 0 && + (endp->net_rtp == addr.sin_port || endp->net_rtcp == addr.sin_port) + ? DEST_BTS : DEST_NETWORK; + proto = fd == &endp->local_rtp ? PROTO_RTP : PROTO_RTCP; + + /* We have no idea who called us, maybe it is the BTS. */ + if (dest == DEST_NETWORK && (endp->bts_rtp == 0 || cfg->forward_ip)) { + /* it was the BTS... */ + if (!cfg->bts_ip || memcmp(&addr.sin_addr, &cfg->bts_in, sizeof(cfg->bts_in)) == 0) { + if (fd == &endp->local_rtp) { + endp->bts_rtp = addr.sin_port; + } else { + endp->bts_rtcp = addr.sin_port; + } + + endp->bts = addr.sin_addr; + LOGP(DMGCP, LOGL_NOTICE, "Found BTS for endpoint: 0x%x on port: %d/%d\n", + ENDPOINT_NUMBER(endp), ntohs(endp->bts_rtp), ntohs(endp->bts_rtcp)); + } + } + + /* dispatch */ + if (cfg->audio_loop) + dest = !dest; + + if (dest == DEST_NETWORK) { + return udp_send(fd->fd, &endp->remote, + proto == PROTO_RTP ? endp->net_rtp : endp->net_rtcp, + buf, rc); + } else { + return udp_send(fd->fd, &endp->bts, + proto == PROTO_RTP ? endp->bts_rtp : endp->bts_rtcp, + buf, rc); + } +} + +static int create_bind(const char *source_addr, struct bsc_fd *fd, int port) +{ + struct sockaddr_in addr; + int on = 1; + + fd->fd = socket(AF_INET, SOCK_DGRAM, 0); + if (fd->fd < 0) { + LOGP(DMGCP, LOGL_ERROR, "Failed to create UDP port.\n"); + return -1; + } + + setsockopt(fd->fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_port = htons(port); + inet_aton(source_addr, &addr.sin_addr); + + if (bind(fd->fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) { + return -1; + } + + return 0; +} + +static int bind_rtp(struct mgcp_endpoint *endp) +{ + struct mgcp_config *cfg = endp->cfg; + + if (create_bind(cfg->source_addr, &endp->local_rtp, endp->rtp_port) != 0) { + LOGP(DMGCP, LOGL_ERROR, "Failed to create RTP port: %s:%d on 0x%x\n", + cfg->source_addr, endp->rtp_port, ENDPOINT_NUMBER(endp)); + goto cleanup0; + } + + if (create_bind(cfg->source_addr, &endp->local_rtcp, endp->rtp_port + 1) != 0) { + LOGP(DMGCP, LOGL_ERROR, "Failed to create RTCP port: %s:%d on 0x%x\n", + cfg->source_addr, endp->rtp_port + 1, ENDPOINT_NUMBER(endp)); + goto cleanup1; + } + + endp->local_rtp.cb = rtp_data_cb; + endp->local_rtp.data = endp; + endp->local_rtp.when = BSC_FD_READ; + if (bsc_register_fd(&endp->local_rtp) != 0) { + LOGP(DMGCP, LOGL_ERROR, "Failed to register RTP port %d on 0x%x\n", + endp->rtp_port, ENDPOINT_NUMBER(endp)); + goto cleanup2; + } + + endp->local_rtcp.cb = rtp_data_cb; + endp->local_rtcp.data = endp; + endp->local_rtcp.when = BSC_FD_READ; + if (bsc_register_fd(&endp->local_rtcp) != 0) { + LOGP(DMGCP, LOGL_ERROR, "Failed to register RTCP port %d on 0x%x\n", + endp->rtp_port + 1, ENDPOINT_NUMBER(endp)); + goto cleanup3; + } + + return 0; + +cleanup3: + bsc_unregister_fd(&endp->local_rtp); +cleanup2: + close(endp->local_rtcp.fd); + endp->local_rtcp.fd = -1; +cleanup1: + close(endp->local_rtp.fd); + endp->local_rtp.fd = -1; +cleanup0: + return -1; +} + +int mgcp_bind_rtp_port(struct mgcp_endpoint *endp, int rtp_port) +{ + endp->rtp_port = rtp_port; + return bind_rtp(endp); +} diff --git a/openbsc/src/mgcp/mgcp_protocol.c b/openbsc/src/mgcp/mgcp_protocol.c index f7588cd38..aaa9bc582 100644 --- a/openbsc/src/mgcp/mgcp_protocol.c +++ b/openbsc/src/mgcp/mgcp_protocol.c @@ -30,9 +30,6 @@ #include #include -#include -#include - #include #include #include @@ -41,8 +38,6 @@ #include #include -#warning "Make use of the rtp proxy code" - enum mgcp_connection_mode { MGCP_CONN_NONE = 0, MGCP_CONN_RECV_ONLY = 1, @@ -50,16 +45,6 @@ enum mgcp_connection_mode { MGCP_CONN_RECV_SEND = MGCP_CONN_RECV_ONLY | MGCP_CONN_SEND_ONLY, }; -enum { - DEST_NETWORK = 0, - DEST_BTS = 1, -}; - -enum { - PROTO_RTP, - PROTO_RTCP, -}; - /** * Macro for tokenizing MGCP messages and SDP in one go. * @@ -140,168 +125,6 @@ static unsigned int generate_transaction_id() return abs(rand()); } -static int udp_send(int fd, struct in_addr *addr, int port, char *buf, int len) -{ - struct sockaddr_in out; - out.sin_family = AF_INET; - out.sin_port = port; - memcpy(&out.sin_addr, addr, sizeof(*addr)); - - return sendto(fd, buf, len, 0, (struct sockaddr *)&out, sizeof(out)); -} - -/* - * There is data coming. We will have to figure out if it - * came from the BTS or the MediaGateway of the MSC. On top - * of that we need to figure out if it was RTP or RTCP. - * - * Currently we do not communicate with the BSC so we have - * no idea where the BTS is listening for RTP and need to - * do the classic routing trick. Wait for the first packet - * from the BTS and then go ahead. - */ -static int rtp_data_cb(struct bsc_fd *fd, unsigned int what) -{ - char buf[4096]; - struct sockaddr_in addr; - socklen_t slen = sizeof(addr); - struct mgcp_endpoint *endp; - struct mgcp_config *cfg; - int rc, dest, proto; - - endp = (struct mgcp_endpoint *) fd->data; - cfg = endp->cfg; - - rc = recvfrom(fd->fd, &buf, sizeof(buf), 0, - (struct sockaddr *) &addr, &slen); - if (rc < 0) { - LOGP(DMGCP, LOGL_ERROR, "Failed to receive message on: 0x%x\n", - ENDPOINT_NUMBER(endp)); - return -1; - } - - /* do not forward aynthing... maybe there is a packet from the bts */ - if (endp->ci == CI_UNUSED) { - LOGP(DMGCP, LOGL_ERROR, "Unknown message on endpoint: 0x%x\n", ENDPOINT_NUMBER(endp)); - return -1; - } - - /* - * Figure out where to forward it to. This code assumes that we - * have received the Connection Modify and know who is a legitimate - * partner. According to the spec we could attempt to forward even - * after the Create Connection but we will not as we are not really - * able to tell if this is legitimate. - */ - #warning "Slight spec violation. With connection mode recvonly we should attempt to forward." - dest = memcmp(&addr.sin_addr, &endp->remote, sizeof(addr.sin_addr)) == 0 && - (endp->net_rtp == addr.sin_port || endp->net_rtcp == addr.sin_port) - ? DEST_BTS : DEST_NETWORK; - proto = fd == &endp->local_rtp ? PROTO_RTP : PROTO_RTCP; - - /* We have no idea who called us, maybe it is the BTS. */ - if (dest == DEST_NETWORK && (endp->bts_rtp == 0 || cfg->forward_ip)) { - /* it was the BTS... */ - if (!cfg->bts_ip || memcmp(&addr.sin_addr, &cfg->bts_in, sizeof(cfg->bts_in)) == 0) { - if (fd == &endp->local_rtp) { - endp->bts_rtp = addr.sin_port; - } else { - endp->bts_rtcp = addr.sin_port; - } - - endp->bts = addr.sin_addr; - LOGP(DMGCP, LOGL_NOTICE, "Found BTS for endpoint: 0x%x on port: %d/%d\n", - ENDPOINT_NUMBER(endp), ntohs(endp->bts_rtp), ntohs(endp->bts_rtcp)); - } - } - - /* dispatch */ - if (cfg->audio_loop) - dest = !dest; - - if (dest == DEST_NETWORK) { - return udp_send(fd->fd, &endp->remote, - proto == PROTO_RTP ? endp->net_rtp : endp->net_rtcp, - buf, rc); - } else { - return udp_send(fd->fd, &endp->bts, - proto == PROTO_RTP ? endp->bts_rtp : endp->bts_rtcp, - buf, rc); - } -} - -static int create_bind(const char *source_addr, struct bsc_fd *fd, int port) -{ - struct sockaddr_in addr; - int on = 1; - - fd->fd = socket(AF_INET, SOCK_DGRAM, 0); - if (fd->fd < 0) { - LOGP(DMGCP, LOGL_ERROR, "Failed to create UDP port.\n"); - return -1; - } - - setsockopt(fd->fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); - memset(&addr, 0, sizeof(addr)); - addr.sin_family = AF_INET; - addr.sin_port = htons(port); - inet_aton(source_addr, &addr.sin_addr); - - if (bind(fd->fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) { - return -1; - } - - return 0; -} - -static int bind_rtp(struct mgcp_endpoint *endp) -{ - struct mgcp_config *cfg = endp->cfg; - - if (create_bind(cfg->source_addr, &endp->local_rtp, endp->rtp_port) != 0) { - LOGP(DMGCP, LOGL_ERROR, "Failed to create RTP port: %s:%d on 0x%x\n", - cfg->source_addr, endp->rtp_port, ENDPOINT_NUMBER(endp)); - goto cleanup0; - } - - if (create_bind(cfg->source_addr, &endp->local_rtcp, endp->rtp_port + 1) != 0) { - LOGP(DMGCP, LOGL_ERROR, "Failed to create RTCP port: %s:%d on 0x%x\n", - cfg->source_addr, endp->rtp_port + 1, ENDPOINT_NUMBER(endp)); - goto cleanup1; - } - - endp->local_rtp.cb = rtp_data_cb; - endp->local_rtp.data = endp; - endp->local_rtp.when = BSC_FD_READ; - if (bsc_register_fd(&endp->local_rtp) != 0) { - LOGP(DMGCP, LOGL_ERROR, "Failed to register RTP port %d on 0x%x\n", - endp->rtp_port, ENDPOINT_NUMBER(endp)); - goto cleanup2; - } - - endp->local_rtcp.cb = rtp_data_cb; - endp->local_rtcp.data = endp; - endp->local_rtcp.when = BSC_FD_READ; - if (bsc_register_fd(&endp->local_rtcp) != 0) { - LOGP(DMGCP, LOGL_ERROR, "Failed to register RTCP port %d on 0x%x\n", - endp->rtp_port + 1, ENDPOINT_NUMBER(endp)); - goto cleanup3; - } - - return 0; - -cleanup3: - bsc_unregister_fd(&endp->local_rtp); -cleanup2: - close(endp->local_rtcp.fd); - endp->local_rtcp.fd = -1; -cleanup1: - close(endp->local_rtp.fd); - endp->local_rtp.fd = -1; -cleanup0: - return -1; -} - /* * array of function pointers for handling various * messages. In the future this might be binary sorted @@ -575,6 +398,7 @@ static struct msgb *handle_create_con(struct mgcp_config *cfg, struct msgb *msg) const char *trans_id; struct mgcp_endpoint *endp; int error_code = 500; + int port; found = analyze_header(cfg, msg, data_ptrs, ARRAY_SIZE(data_ptrs), &trans_id, &endp); if (found != 0) @@ -618,8 +442,10 @@ static struct msgb *handle_create_con(struct mgcp_config *cfg, struct msgb *msg) memset(&endp->remote, 0, sizeof(endp->remote)); /* bind to the port now */ - endp->rtp_port = rtp_calculate_port(ENDPOINT_NUMBER(endp), cfg->rtp_base_port); - if (!cfg->early_bind && bind_rtp(endp) != 0) + port = rtp_calculate_port(ENDPOINT_NUMBER(endp), cfg->rtp_base_port); + if (cfg->early_bind) + endp->rtp_port = port; + else if (mgcp_bind_rtp_port(endp, port) != 0) goto error2; /* assign a local call identifier or fail */ @@ -841,9 +667,3 @@ int mgcp_endpoints_allocate(struct mgcp_config *cfg) return 0; } - -int mgcp_bind_rtp_port(struct mgcp_endpoint *endp, int rtp_port) -{ - endp->rtp_port = rtp_port; - return bind_rtp(endp); -} From 590cd98842effb1118bb10e5daef99c43029003b Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Fri, 26 Feb 2010 13:10:51 +0100 Subject: [PATCH 05/11] [mgcp] Print the rtp_port number, do not assume it was already assigned. --- openbsc/src/mgcp/mgcp_vty.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openbsc/src/mgcp/mgcp_vty.c b/openbsc/src/mgcp/mgcp_vty.c index b297b42a0..d77646dae 100644 --- a/openbsc/src/mgcp/mgcp_vty.c +++ b/openbsc/src/mgcp/mgcp_vty.c @@ -317,7 +317,7 @@ int mgcp_parse_config(const char *config_file, struct mgcp_config *cfg) rtp_port = rtp_calculate_port(ENDPOINT_NUMBER(endp), g_cfg->rtp_base_port); if (mgcp_bind_rtp_port(endp, rtp_port) != 0) { - LOGP(DMGCP, LOGL_FATAL, "Failed to bind: %d\n", endp->rtp_port); + LOGP(DMGCP, LOGL_FATAL, "Failed to bind: %d\n", rtp_port); return -1; } } From 154b9553f758b5a1764097a7cd225d75976c5799 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Fri, 26 Feb 2010 13:27:51 +0100 Subject: [PATCH 06/11] [mgcp] Add a method to free the endpoint. --- openbsc/include/openbsc/mgcp.h | 1 + openbsc/src/mgcp/mgcp_protocol.c | 37 +++++++++++++++++++++----------- 2 files changed, 26 insertions(+), 12 deletions(-) diff --git a/openbsc/include/openbsc/mgcp.h b/openbsc/include/openbsc/mgcp.h index 9307f5b36..fcc4d76ef 100644 --- a/openbsc/include/openbsc/mgcp.h +++ b/openbsc/include/openbsc/mgcp.h @@ -96,6 +96,7 @@ int mgcp_parse_config(const char *config_file, struct mgcp_config *cfg); int mgcp_vty_init(void); int mgcp_endpoints_allocate(struct mgcp_config *cfg); int mgcp_bind_rtp_port(struct mgcp_endpoint *endp, int rtp_port); +void mgcp_free_endp(struct mgcp_endpoint *endp); /* * format helper functions diff --git a/openbsc/src/mgcp/mgcp_protocol.c b/openbsc/src/mgcp/mgcp_protocol.c index aaa9bc582..cc37e0cd6 100644 --- a/openbsc/src/mgcp/mgcp_protocol.c +++ b/openbsc/src/mgcp/mgcp_protocol.c @@ -600,19 +600,8 @@ static struct msgb *handle_delete_con(struct mgcp_config *cfg, struct msgb *msg) } MSG_TOKENIZE_END - /* free the connection */ - LOGP(DMGCP, LOGL_NOTICE, "Deleting endpoint on: 0x%x\n", ENDPOINT_NUMBER(endp)); - endp->ci= CI_UNUSED; - talloc_free(endp->callid); - talloc_free(endp->local_options); - - if (!cfg->early_bind) { - bsc_unregister_fd(&endp->local_rtp); - bsc_unregister_fd(&endp->local_rtcp); - } - - endp->net_rtp = endp->net_rtcp = endp->bts_rtp = endp->bts_rtcp = 0; + mgcp_free_endp(endp); if (cfg->change_cb) cfg->change_cb(cfg, ENDPOINT_NUMBER(endp), MGCP_ENDP_DLCX, endp->rtp_port); @@ -667,3 +656,27 @@ int mgcp_endpoints_allocate(struct mgcp_config *cfg) return 0; } + +void mgcp_free_endp(struct mgcp_endpoint *endp) +{ + LOGP(DMGCP, LOGL_NOTICE, "Deleting endpoint on: 0x%x\n", ENDPOINT_NUMBER(endp)); + endp->ci= CI_UNUSED; + + if (endp->callid) { + talloc_free(endp->callid); + endp->callid = NULL; + } + + if (endp->local_options) { + talloc_free(endp->local_options); + endp->callid = NULL; + } + + if (!endp->cfg->early_bind) { + bsc_unregister_fd(&endp->local_rtp); + bsc_unregister_fd(&endp->local_rtcp); + } + + endp->net_rtp = endp->net_rtcp = endp->bts_rtp = endp->bts_rtcp = 0; + endp->net_payload_type = endp->bts_payload_type = -1; +} From 63f2db2ec94b1e7c7e84b508f3e1ea25b5fb007f Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Fri, 26 Feb 2010 13:30:57 +0100 Subject: [PATCH 07/11] [mgcp] Switch logging from notice to debug --- openbsc/src/mgcp/mgcp_protocol.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/openbsc/src/mgcp/mgcp_protocol.c b/openbsc/src/mgcp/mgcp_protocol.c index cc37e0cd6..43bddf4a5 100644 --- a/openbsc/src/mgcp/mgcp_protocol.c +++ b/openbsc/src/mgcp/mgcp_protocol.c @@ -164,7 +164,7 @@ struct msgb *mgcp_create_response_with_data(int code, const char *msg, const cha } res->l2h = msgb_put(res, len); - LOGP(DMGCP, LOGL_NOTICE, "Sending response: code: %d for '%s'\n", code, res->l2h); + LOGP(DMGCP, LOGL_DEBUG, "Sending response: code: %d for '%s'\n", code, res->l2h); return res; } @@ -228,7 +228,7 @@ struct msgb *mgcp_handle_message(struct mgcp_config *cfg, struct msgb *msg) /* attempt to treat it as a response */ if (sscanf((const char *)&msg->data[0], "%3d %*s", &code) == 1) { - LOGP(DMGCP, LOGL_NOTICE, "Response: Code: %d\n", code); + LOGP(DMGCP, LOGL_DEBUG, "Response: Code: %d\n", code); } else { int i, handled = 0; msg->l3h = &msg->l2h[4]; @@ -548,7 +548,7 @@ static struct msgb *handle_modify_con(struct mgcp_config *cfg, struct msgb *msg) /* modify */ LOGP(DMGCP, LOGL_NOTICE, "Modified endpoint on: 0x%x Server: %s:%u\n", - ENDPOINT_NUMBER(endp), inet_ntoa(endp->remote), endp->net_rtp); + ENDPOINT_NUMBER(endp), inet_ntoa(endp->remote), ntohs(endp->net_rtp)); if (cfg->change_cb) cfg->change_cb(cfg, ENDPOINT_NUMBER(endp), MGCP_ENDP_MDCX, endp->rtp_port); return create_response_with_sdp(endp, "MDCX", trans_id); From a820c5f89d0ea3a7aefd1621d9bf1c9c5a25e8eb Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Fri, 26 Feb 2010 13:32:55 +0100 Subject: [PATCH 08/11] [mgcp] Fix two bugs in the protocol handling In case of a wrongly formatted AUEP, CRCX, DLCX, MDCX the transaction id pointer was a dangling pointer... Initialize the transaction id to a static string.. Also fix a off by one bug. We want to extract four elements from the MGCP message and not only 3... So a short AUEP message made it us read too many things. --- openbsc/src/mgcp/mgcp_protocol.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/openbsc/src/mgcp/mgcp_protocol.c b/openbsc/src/mgcp/mgcp_protocol.c index 43bddf4a5..0fe33dd23 100644 --- a/openbsc/src/mgcp/mgcp_protocol.c +++ b/openbsc/src/mgcp/mgcp_protocol.c @@ -302,6 +302,8 @@ static int analyze_header(struct mgcp_config *cfg, struct msgb *msg, { int found; + *transaction_id = "000000"; + if (size < 3) { LOGP(DMGCP, LOGL_ERROR, "Not enough space in ptr\n"); return -1; @@ -309,7 +311,7 @@ static int analyze_header(struct mgcp_config *cfg, struct msgb *msg, found = find_msg_pointers(msg, ptr, size); - if (found < 3) { + if (found <= 3) { LOGP(DMGCP, LOGL_ERROR, "Gateway: Not enough params. Found: %d\n", found); return -1; } From fe86d3c9f8a229a788a863d1855c9e3d616b04ea Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Fri, 26 Feb 2010 13:37:05 +0100 Subject: [PATCH 09/11] [mgcp] Introduce a policy CB for the MGCP protocol The are three policies. Accept, Reject and Defer. This will allow to handle network connections and such from the policy callback instead of directly acting on it. --- openbsc/include/openbsc/mgcp.h | 13 ++++++++ openbsc/src/mgcp/mgcp_protocol.c | 55 ++++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+) diff --git a/openbsc/include/openbsc/mgcp.h b/openbsc/include/openbsc/mgcp.h index fcc4d76ef..004ae7899 100644 --- a/openbsc/include/openbsc/mgcp.h +++ b/openbsc/include/openbsc/mgcp.h @@ -65,7 +65,18 @@ struct mgcp_config; #define MGCP_ENDP_DLCX 2 #define MGCP_ENDP_MDCX 3 +/* + * what to do with the msg? + * - continue as usual? + * - reject and send a failure code? + * - defer? do not send anything + */ +#define MGCP_POLICY_CONT 4 +#define MGCP_POLICY_REJECT 5 +#define MGCP_POLICY_DEFER 6 + typedef int (*mgcp_change)(struct mgcp_config *cfg, int endpoint, int state, int local_rtp); +typedef int (*mgcp_policy)(struct mgcp_config *cfg, int endpoint, int state, const char *transactio_id); struct mgcp_config { int source_port; @@ -85,6 +96,8 @@ struct mgcp_config { int forward_port; mgcp_change change_cb; + mgcp_policy policy_cb; + void *data; struct mgcp_endpoint *endpoints; unsigned int last_call_id; diff --git a/openbsc/src/mgcp/mgcp_protocol.c b/openbsc/src/mgcp/mgcp_protocol.c index 0fe33dd23..bd47f8c42 100644 --- a/openbsc/src/mgcp/mgcp_protocol.c +++ b/openbsc/src/mgcp/mgcp_protocol.c @@ -455,6 +455,25 @@ static struct msgb *handle_create_con(struct mgcp_config *cfg, struct msgb *msg) if (endp->ci == CI_UNUSED) goto error2; + /* policy CB */ + if (cfg->policy_cb) { + switch (cfg->policy_cb(cfg, ENDPOINT_NUMBER(endp), MGCP_ENDP_CRCX, trans_id)) { + case MGCP_POLICY_REJECT: + LOGP(DMGCP, LOGL_NOTICE, "CRCX rejected by policy on 0x%x\n", + ENDPOINT_NUMBER(endp)); + mgcp_free_endp(endp); + return create_response(500, "CRCX", trans_id); + break; + case MGCP_POLICY_DEFER: + /* stop processing */ + return NULL; + break; + case MGCP_POLICY_CONT: + /* just continue */ + break; + } + } + LOGP(DMGCP, LOGL_NOTICE, "Creating endpoint on: 0x%x CI: %u port: %u\n", ENDPOINT_NUMBER(endp), endp->ci, endp->rtp_port); if (cfg->change_cb) @@ -548,6 +567,24 @@ static struct msgb *handle_modify_con(struct mgcp_config *cfg, struct msgb *msg) } MSG_TOKENIZE_END + /* policy CB */ + if (cfg->policy_cb) { + switch (cfg->policy_cb(cfg, ENDPOINT_NUMBER(endp), MGCP_ENDP_MDCX, trans_id)) { + case MGCP_POLICY_REJECT: + LOGP(DMGCP, LOGL_NOTICE, "MDCX rejected by policy on 0x%x\n", + ENDPOINT_NUMBER(endp)); + return create_response(500, "MDCX", trans_id); + break; + case MGCP_POLICY_DEFER: + /* stop processing */ + return NULL; + break; + case MGCP_POLICY_CONT: + /* just continue */ + break; + } + } + /* modify */ LOGP(DMGCP, LOGL_NOTICE, "Modified endpoint on: 0x%x Server: %s:%u\n", ENDPOINT_NUMBER(endp), inet_ntoa(endp->remote), ntohs(endp->net_rtp)); @@ -602,6 +639,24 @@ static struct msgb *handle_delete_con(struct mgcp_config *cfg, struct msgb *msg) } MSG_TOKENIZE_END + /* policy CB */ + if (cfg->policy_cb) { + switch (cfg->policy_cb(cfg, ENDPOINT_NUMBER(endp), MGCP_ENDP_DLCX, trans_id)) { + case MGCP_POLICY_REJECT: + LOGP(DMGCP, LOGL_NOTICE, "DLCX rejected by policy on 0x%x\n", + ENDPOINT_NUMBER(endp)); + return create_response(500, "DLCX", trans_id); + break; + case MGCP_POLICY_DEFER: + /* stop processing */ + return NULL; + break; + case MGCP_POLICY_CONT: + /* just continue */ + break; + } + } + /* free the connection */ mgcp_free_endp(endp); if (cfg->change_cb) From ef6bb25aa5b7dcb4a10469c6a39ace3534c08376 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Fri, 26 Feb 2010 13:41:22 +0100 Subject: [PATCH 10/11] [mgcp] Keep track of the local and remote RTP payload type Keep track of which RTP payload type to use for which direction. --- openbsc/include/openbsc/mgcp_internal.h | 3 +++ openbsc/src/mgcp/mgcp_protocol.c | 10 ++++++++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/openbsc/include/openbsc/mgcp_internal.h b/openbsc/include/openbsc/mgcp_internal.h index 2848d5bd0..3df986946 100644 --- a/openbsc/include/openbsc/mgcp_internal.h +++ b/openbsc/include/openbsc/mgcp_internal.h @@ -34,6 +34,9 @@ struct mgcp_endpoint { char *local_options; int conn_mode; + int bts_payload_type; + int net_payload_type; + /* the local rtp port we are binding to */ int rtp_port; diff --git a/openbsc/src/mgcp/mgcp_protocol.c b/openbsc/src/mgcp/mgcp_protocol.c index bd47f8c42..e97f1f411 100644 --- a/openbsc/src/mgcp/mgcp_protocol.c +++ b/openbsc/src/mgcp/mgcp_protocol.c @@ -189,7 +189,7 @@ static struct msgb *create_response_with_sdp(struct mgcp_endpoint *endp, "m=audio %d RTP/AVP %d\r\n" "a=rtpmap:%d %s\r\n", endp->ci, addr, endp->rtp_port, - endp->cfg->audio_payload, endp->cfg->audio_payload, + endp->bts_payload_type, endp->bts_payload_type, endp->cfg->audio_name); return mgcp_create_response_with_data(200, msg, trans_id, sdp_record); } @@ -455,6 +455,8 @@ static struct msgb *handle_create_con(struct mgcp_config *cfg, struct msgb *msg) if (endp->ci == CI_UNUSED) goto error2; + endp->bts_payload_type = cfg->audio_payload; + /* policy CB */ if (cfg->policy_cb) { switch (cfg->policy_cb(cfg, ENDPOINT_NUMBER(endp), MGCP_ENDP_CRCX, trans_id)) { @@ -542,11 +544,13 @@ static struct msgb *handle_modify_con(struct mgcp_config *cfg, struct msgb *msg) break; case 'm': { int port; + int payload; const char *param = (const char *)&msg->l3h[line_start]; - if (sscanf(param, "m=audio %d RTP/AVP %*d", &port) == 1) { + if (sscanf(param, "m=audio %d RTP/AVP %d", &port, &payload) == 2) { endp->net_rtp = htons(port); endp->net_rtcp = htons(port + 1); + endp->net_payload_type = payload; } break; } @@ -709,6 +713,8 @@ int mgcp_endpoints_allocate(struct mgcp_config *cfg) cfg->endpoints[i].local_rtcp.fd = -1; cfg->endpoints[i].ci = CI_UNUSED; cfg->endpoints[i].cfg = cfg; + cfg->endpoints[i].net_payload_type = -1; + cfg->endpoints[i].bts_payload_type = -1; } return 0; From 36ed8cc4c33e3b69bb0f84f1b5b593ae46aff08f Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Fri, 26 Feb 2010 13:42:58 +0100 Subject: [PATCH 11/11] [mgcp] Patch the rtp payload depending on the direction. The RTP header code is taken from the rtp_proxy, we will need to figure out how to unite these properly in the long run. --- openbsc/src/mgcp/mgcp_network.c | 36 +++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/openbsc/src/mgcp/mgcp_network.c b/openbsc/src/mgcp/mgcp_network.c index e92b0742e..c61f0a858 100644 --- a/openbsc/src/mgcp/mgcp_network.c +++ b/openbsc/src/mgcp/mgcp_network.c @@ -24,6 +24,7 @@ #include #include +#include #include #include @@ -37,6 +38,28 @@ #warning "Make use of the rtp proxy code" +/* according to rtp_proxy.c RFC 3550 */ +struct rtp_hdr { +#if __BYTE_ORDER == __LITTLE_ENDIAN + u_int8_t csrc_count:4, + extension:1, + padding:1, + version:2; + u_int8_t payload_type:7, + marker:1; +#elif __BYTE_ORDER == __BIG_ENDIAN + u_int8_t version:2, + padding:1, + extension:1, + csrc_count:4; + u_int8_t marker:1, + payload_type:7; +#endif + u_int16_t sequence; + u_int32_t timestamp; + u_int32_t ssrc; +} __attribute__((packed)); + enum { DEST_NETWORK = 0, @@ -59,6 +82,17 @@ static int udp_send(int fd, struct in_addr *addr, int port, char *buf, int len) return sendto(fd, buf, len, 0, (struct sockaddr *)&out, sizeof(out)); } +static void patch_payload(int payload, char *data, int len) +{ + struct rtp_hdr *rtp_hdr; + + if (len < sizeof(*rtp_hdr)) + return; + + rtp_hdr = (struct rtp_hdr *) data; + rtp_hdr->payload_type = payload; +} + /* * There is data coming. We will have to figure out if it * came from the BTS or the MediaGateway of the MSC. On top @@ -129,10 +163,12 @@ static int rtp_data_cb(struct bsc_fd *fd, unsigned int what) dest = !dest; if (dest == DEST_NETWORK) { + patch_payload(endp->net_payload_type, buf, rc); return udp_send(fd->fd, &endp->remote, proto == PROTO_RTP ? endp->net_rtp : endp->net_rtcp, buf, rc); } else { + patch_payload(endp->bts_payload_type, buf, rc); return udp_send(fd->fd, &endp->bts, proto == PROTO_RTP ? endp->bts_rtp : endp->bts_rtcp, buf, rc);