aboutsummaryrefslogtreecommitdiffstats
path: root/openbsc/src/bsc_msc_ip.c
diff options
context:
space:
mode:
authorHolger Hans Peter Freyther <zecke@selfish.org>2010-03-31 08:39:53 +0200
committerHolger Hans Peter Freyther <zecke@selfish.org>2010-03-31 08:39:53 +0200
commit2ffe7aa340abd2333584730ff6471064b6fcaa1c (patch)
treebd8d629f8c87b5654ea3f7d3d653fe169170b271 /openbsc/src/bsc_msc_ip.c
parent538ea6d5c64cb048ba10bf7ec7e6dae6385ce142 (diff)
bsc_msc_ip: Create a local UDP socket and relay MGCP messages
Attempt to bind to the local callagent port and send messages from the MSC TCP connection to the MGCP and do it the otherway around as well.
Diffstat (limited to 'openbsc/src/bsc_msc_ip.c')
-rw-r--r--openbsc/src/bsc_msc_ip.c149
1 files changed, 144 insertions, 5 deletions
diff --git a/openbsc/src/bsc_msc_ip.c b/openbsc/src/bsc_msc_ip.c
index 01f45c40c..0fcfdbe37 100644
--- a/openbsc/src/bsc_msc_ip.c
+++ b/openbsc/src/bsc_msc_ip.c
@@ -43,6 +43,7 @@
#include <openbsc/signal.h>
#include <openbsc/chan_alloc.h>
#include <openbsc/bsc_msc.h>
+#include <openbsc/bsc_nat.h>
#include <osmocore/select.h>
#include <osmocore/talloc.h>
@@ -61,6 +62,7 @@ static char *msc_address = "127.0.0.1";
static struct bsc_msc_connection *msc_con;
static struct in_addr local_addr;
static LLIST_HEAD(active_connections);
+static struct write_queue mgcp_agent;
extern int ipacc_rtp_direct;
extern int bsc_bootstrap_network(int (*layer4)(struct gsm_network *, int, void *), const char *cfg_file);
@@ -541,6 +543,18 @@ static void print_usage()
/*
* SCCP handling
*/
+static int msc_queue_write(struct msgb *msg, int proto)
+{
+ ipaccess_prepend_header(msg, proto);
+ if (write_queue_enqueue(&msc_con->write_queue, msg) != 0) {
+ LOGP(DMSC, LOGL_FATAL, "Failed to queue IPA/%d\n", proto);
+ msgb_free(msg);
+ return -1;
+ }
+
+ return 0;
+}
+
static int msc_sccp_do_write(struct bsc_fd *fd, struct msgb *msg)
{
int ret;
@@ -557,12 +571,128 @@ static int msc_sccp_do_write(struct bsc_fd *fd, struct msgb *msg)
static void msc_sccp_write_ipa(struct msgb *msg, void *data)
{
- ipaccess_prepend_header(msg, IPAC_PROTO_SCCP);
- if (write_queue_enqueue(&msc_con->write_queue, msg) != 0) {
- LOGP(DMSC, LOGL_FATAL, "Failed to queue IPA/SCCP\n");
- msgb_free(msg);
+ msc_queue_write(msg, IPAC_PROTO_SCCP);
+}
+
+/*
+ * mgcp forwarding is below
+ */
+static int mgcp_do_write(struct bsc_fd *fd, struct msgb *msg)
+{
+ int ret;
+
+ LOGP(DMGCP, LOGL_DEBUG, "Sending msg to MGCP GW size: %u\n", msg->len);
+
+ ret = write(fd->fd, msg->data, msg->len);
+ if (ret != msg->len)
+ LOGP(DMGCP, LOGL_ERROR, "Failed to forward message to MGCP GW.\n");
+
+ return ret;
+}
+
+static int mgcp_do_read(struct bsc_fd *fd)
+{
+ struct msgb *mgcp;
+ int ret;
+
+ mgcp = msgb_alloc_headroom(4096, 128, "mgcp_from_gw");
+ if (!mgcp) {
+ LOGP(DMGCP, LOGL_ERROR, "Failed to allocate MGCP message.\n");
+ return -1;
+ }
+
+ ret = read(fd->fd, mgcp->data, mgcp->len);
+ if (ret <= 0) {
+ LOGP(DMGCP, LOGL_ERROR, "Failed to read: %d\n", errno);
+ msgb_free(mgcp);
+ }
+
+ msgb_put(mgcp, ret);
+ msc_queue_write(mgcp, NAT_IPAC_PROTO_MGCP);
+ return 0;
+}
+
+static void mgcp_forward(struct msgb *msg)
+{
+ struct msgb *mgcp;
+
+ if (msgb_l2len(msg) > 4096) {
+ LOGP(DMGCP, LOGL_ERROR, "Can not forward too big message.\n");
+ return;
+ }
+
+ mgcp = msgb_alloc(4096, "mgcp_to_gw");
+ if (!mgcp) {
+ LOGP(DMGCP, LOGL_ERROR, "Failed to send message.\n");
+ return;
+ }
+
+ msgb_put(mgcp, msgb_l2len(msg));
+ memcpy(mgcp->data, msg->l2h, mgcp->len);
+ if (write_queue_enqueue(&mgcp_agent, mgcp) != 0) {
+ LOGP(DMGCP, LOGL_FATAL, "Could not queue message to MGCP GW.\n");
+ msgb_free(mgcp);
}
}
+static int mgcp_create_port(void)
+{
+ int on;
+ int port;
+ struct sockaddr_in addr;
+
+ mgcp_agent.bfd.fd = socket(AF_INET, SOCK_DGRAM, 0);
+ if (mgcp_agent.bfd.fd < 0) {
+ LOGP(DMGCP, LOGL_FATAL, "Failed to create UDP socket errno: %d\n", errno);
+ return -1;
+ }
+
+ on = 1;
+ setsockopt(mgcp_agent.bfd.fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
+
+ /* try to bind the socket */
+ memset(&addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+ addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+
+ for (port = 2727; port < 3000; ++port) {
+ addr.sin_port = htons(port);
+ if (bind(mgcp_agent.bfd.fd, (struct sockaddr *) &addr, sizeof(addr)) == 0)
+ break;
+ perror("foo");
+ }
+
+ if (port >= 3000) {
+ LOGP(DMGCP, LOGL_FATAL, "Failed to bind to any port.\n");
+ close(mgcp_agent.bfd.fd);
+ mgcp_agent.bfd.fd = -1;
+ return -1;
+ }
+
+ /* connect to the remote */
+ addr.sin_port = htons(2427);
+ if (connect(mgcp_agent.bfd.fd, (struct sockaddr *) & addr, sizeof(addr)) < 0) {
+ LOGP(DMGCP, LOGL_FATAL, "Failed to connect to local MGCP GW. %d\n", errno);
+ close(mgcp_agent.bfd.fd);
+ mgcp_agent.bfd.fd = -1;
+ return -1;
+ }
+
+ write_queue_init(&mgcp_agent, 10);
+ mgcp_agent.bfd.when = BSC_FD_READ;
+ mgcp_agent.read_cb = mgcp_do_read;
+ mgcp_agent.write_cb = mgcp_do_write;
+
+ if (bsc_register_fd(&mgcp_agent.bfd) != 0) {
+ LOGP(DMGCP, LOGL_FATAL, "Failed to register BFD\n");
+ close(mgcp_agent.bfd.fd);
+ mgcp_agent.bfd.fd = -1;
+ return -1;
+ }
+
+
+ return 0;
+}
+
static int msc_sccp_accept(struct sccp_connection *connection, void *data)
{
@@ -723,8 +853,11 @@ static int ipaccess_a_fd_cb(struct bsc_fd *bfd)
else if (msg->l2h[0] == IPAC_MSGT_ID_GET) {
send_id_get_response(bfd->fd);
}
- } else if (hh->proto == IPAC_PROTO_SCCP)
+ } else if (hh->proto == IPAC_PROTO_SCCP) {
sccp_system_incoming(msg);
+ } else if (hh->proto == NAT_IPAC_PROTO_MGCP) {
+ mgcp_forward(msg);
+ }
msgb_free(msg);
return 0;
@@ -888,6 +1021,12 @@ int main(int argc, char **argv)
/* seed the PRNG */
srand(time(NULL));
+ /* attempt to register the local mgcp forward */
+ if (mgcp_create_port() != 0) {
+ fprintf(stderr, "Failed to bind local MGCP port\n");
+ exit(1);
+ }
+
/* initialize sccp */
sccp_system_init(msc_sccp_write_ipa, NULL);
sccp_connection_set_incoming(&sccp_ssn_bssap, msc_sccp_accept, NULL);