aboutsummaryrefslogtreecommitdiffstats
path: root/openbsc/src/bsc_msc_ip.c
diff options
context:
space:
mode:
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);