aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHolger Hans Peter Freyther <zecke@selfish.org>2013-03-19 22:29:41 +0100
committerHolger Hans Peter Freyther <zecke@selfish.org>2013-03-19 22:51:09 +0100
commita5a17fa80affe0523689c7c7970391f115dccd51 (patch)
tree57e07a0fcec48cb7583626ea5df6178c1097f3ce
parentd93c84f96e7b7e652ac5a937c1f27df0913fca18 (diff)
msc: Allow to listen for incoming connections.
This is mostly a hack to allow IPA/SCCP routing to SCTP/M2UA/MTP3/SCCP without going through the full stack. The proper way of doing this requires another round of abstraction for the mtp_link_set class.
-rw-r--r--include/msc_connection.h12
-rw-r--r--src/msc_conn.c209
-rw-r--r--src/vty_interface.c32
3 files changed, 248 insertions, 5 deletions
diff --git a/include/msc_connection.h b/include/msc_connection.h
index 74319b3..826eb3a 100644
--- a/include/msc_connection.h
+++ b/include/msc_connection.h
@@ -30,14 +30,22 @@
struct bsc_data;
struct ss7_application;
+enum msc_mode {
+ MSC_MODE_CLIENT,
+ MSC_MODE_SERVER,
+};
+
struct msc_connection {
/* management */
struct llist_head entry;
int nr;
char *name;
+ enum msc_mode mode;
+ int auth;
/* ip management */
int dscp;
+ int port;
char *ip;
char *token;
@@ -62,6 +70,9 @@ struct msc_connection {
/* application pointer */
struct ss7_application *app;
+
+ /* server functions */
+ struct osmo_fd listen_fd;
};
/* msc related functions */
@@ -80,5 +91,6 @@ void msc_mgcp_reset(struct msc_connection *msc);
/* Called by the MSC Connection */
void msc_dispatch_sccp(struct msc_connection *msc, struct msgb *msg);
+const char *msc_mode(struct msc_connection *msc);
#endif
diff --git a/src/msc_conn.c b/src/msc_conn.c
index b52b901..e895e77 100644
--- a/src/msc_conn.c
+++ b/src/msc_conn.c
@@ -1,7 +1,7 @@
/* MSC related stuff... */
/*
- * (C) 2010-2012 by Holger Hans Peter Freyther <zecke@selfish.org>
- * (C) 2010-2012 by On-Waves
+ * (C) 2010-2013 by Holger Hans Peter Freyther <zecke@selfish.org>
+ * (C) 2010-2013 by On-Waves
* All Rights Reserved
*
* This program is free software: you can redistribute it and/or modify
@@ -29,10 +29,11 @@
#include <ss7_application.h>
#include <mgcp_patch.h>
+#include <osmocom/core/socket.h>
#include <osmocom/core/talloc.h>
-#include <osmocom/gsm/tlv.h>
#include <osmocom/core/utils.h>
#include <osmocom/core/write_queue.h>
+#include <osmocom/gsm/tlv.h>
#include <arpa/inet.h>
#include <sys/socket.h>
@@ -49,6 +50,8 @@
static void msc_send_id_response(struct msc_connection *bsc);
static void msc_send(struct msc_connection *bsc, struct msgb *msg, int proto);
static void msc_schedule_reconnect(struct msc_connection *bsc);
+static int msc_conn_bind(struct msc_connection *bsc);
+static void msc_handle_id_response(struct msc_connection *bsc, struct msgb *msg);
void msc_close_connection(struct msc_connection *fw)
{
@@ -157,8 +160,22 @@ static int ipaccess_a_fd_cb(struct osmo_fd *bfd)
msc_send_id_response(fw);
} else if (msg->l2h[0] == IPAC_MSGT_PONG) {
osmo_timer_del(&fw->pong_timeout);
+ } else if (msg->l2h[0] == IPAC_MSGT_ID_RESP) {
+ msc_handle_id_response(fw, msg);
}
- } else if (hh->proto == IPAC_PROTO_SCCP) {
+
+ msgb_free(msg);
+ return 0;
+ }
+
+ if (fw->mode == MSC_MODE_SERVER && !fw->auth) {
+ LOGP(DMSC, LOGL_ERROR,
+ "Ignoring non ipa message for unauth user.\n");
+ msgb_free(msg);
+ return -1;
+ }
+
+ if (hh->proto == IPAC_PROTO_SCCP) {
msc_dispatch_sccp(fw, msg);
} else if (hh->proto == NAT_MUX) {
msg = mgcp_patch(fw->app, msg);
@@ -315,7 +332,7 @@ static void msc_reconnect(void *_data)
osmo_timer_del(&fw->reconnect_timer);
fw->first_contact = 1;
- rc = connect_to_msc(&fw->msc_connection.bfd, fw->ip, 5000, fw->dscp);
+ rc = connect_to_msc(&fw->msc_connection.bfd, fw->ip, fw->port, fw->dscp);
if (rc < 0) {
fprintf(stderr, "Opening the MSC connection failed. Trying again\n");
osmo_timer_schedule(&fw->reconnect_timer, RECONNECT_TIME);
@@ -329,6 +346,8 @@ static void msc_reconnect(void *_data)
static void msc_schedule_reconnect(struct msc_connection *fw)
{
+ if (fw->mode == MSC_MODE_SERVER)
+ return;
osmo_timer_schedule(&fw->reconnect_timer, RECONNECT_TIME);
}
@@ -399,6 +418,14 @@ void msc_send_reset(struct msc_connection *fw)
return;
}
+ /* start the ping/pong but nothing else */
+ if (fw->mode == MSC_MODE_SERVER) {
+ LOGP(DMSC, LOGL_DEBUG, "Not sending BSSMAP resets in server mode.\n");
+ msc_ping_timeout(fw);
+ return;
+ }
+
+
msg = create_reset();
if (!msg)
return;
@@ -411,6 +438,12 @@ static void msc_send_id_response(struct msc_connection *fw)
{
struct msgb *msg;
+ if (fw->mode == MSC_MODE_SERVER) {
+ LOGP(DMSC, LOGL_DEBUG,
+ "Not sending our token in server mode.\n");
+ return;
+ }
+
msg = msgb_alloc_headroom(4096, 128, "id resp");
msg->l2h = msgb_v_put(msg, IPAC_MSGT_ID_RESP);
msgb_l16tv_put(msg, strlen(fw->token) + 1,
@@ -434,6 +467,9 @@ struct msc_connection *msc_connection_create(struct bsc_data *bsc, int mgcp)
return NULL;
}
+ msc->mode = MSC_MODE_CLIENT;
+ msc->port = 5000;
+
osmo_wqueue_init(&msc->msc_connection, 100);
msc->reconnect_timer.cb = msc_reconnect;
msc->reconnect_timer.data = msc;
@@ -482,6 +518,169 @@ int msc_connection_start(struct msc_connection *msc)
return -1;
}
+ /* bind and wait if we are a server */
+ if (msc->mode == MSC_MODE_SERVER)
+ return msc_conn_bind(msc);
+
msc_schedule_reconnect(msc);
return 0;
}
+
+const char *msc_mode(struct msc_connection *msc)
+{
+ switch (msc->mode) {
+ case MSC_MODE_CLIENT:
+ return "client";
+ case MSC_MODE_SERVER:
+ return "server";
+ }
+
+ return "invalid";
+}
+
+/* Non-clean MSC server socket abstraction.. bind and accept */
+static int msc_send_auth_req(struct msc_connection *msc)
+{
+ struct msgb *msg;
+
+ static const uint8_t id_req[] = {
+ IPAC_MSGT_ID_GET,
+ 0x01, IPAC_IDTAG_UNIT,
+ 0x01, IPAC_IDTAG_MACADDR,
+ 0x01, IPAC_IDTAG_LOCATION1,
+ 0x01, IPAC_IDTAG_LOCATION2,
+ 0x01, IPAC_IDTAG_EQUIPVERS,
+ 0x01, IPAC_IDTAG_SWVERSION,
+ 0x01, IPAC_IDTAG_UNITNAME,
+ 0x01, IPAC_IDTAG_SERNR,
+ };
+
+ msg = msgb_alloc_headroom(4096, 128, "auth");
+ if (!msg) {
+ LOGP(DMSC, LOGL_ERROR, "Failed to allocate auth.\n");
+ msc_close_connection(msc);
+ return -1;
+ }
+
+ msg->l2h = msgb_put(msg, ARRAY_SIZE(id_req));
+ memcpy(msg->l2h, id_req, ARRAY_SIZE(id_req));
+
+ msc_send(msc, msg, IPAC_PROTO_IPACCESS);
+ return 0;
+}
+
+static void msc_handle_id_response(struct msc_connection *msc, struct msgb *msg)
+{
+ unsigned int len;
+ const char *token;
+
+ /* only for the server */
+ if (msc->mode != MSC_MODE_SERVER) {
+ LOGP(DMSC, LOGL_ERROR, "Unexpected ID response for client.\n");
+ return;
+ }
+
+ if (!msc->token) {
+ LOGP(DMSC, LOGL_ERROR, "No token defined. Giving up.\n");
+ goto clean;
+ }
+
+ if (msgb_l2len(msg) < 4) {
+ LOGP(DMSC, LOGL_ERROR, "Too short message...%u\n",
+ msgb_l2len(msg));
+ goto clean;
+ }
+
+ /* in lack of ipaccess_idtag_parse we have a very basic method */
+ if (msg->l2h[3] != IPAC_IDTAG_UNITNAME) {
+ LOGP(DMSC, LOGL_ERROR, "Expected unitname tag got %d\n",
+ msg->l2h[3]);
+ goto clean;
+ }
+
+ token = (const char *) &msg->l2h[4];
+ len = msgb_l2len(msg) - 4;
+
+ if (len != strlen(msc->token)) {
+ LOGP(DMSC, LOGL_ERROR, "Wrong length %u vs. %u\n",
+ len, strlen(msc->token));
+ goto clean;
+ }
+
+ if (memcmp(msc->token, token, len) != 0) {
+ LOGP(DMSC, LOGL_ERROR, "Token has the wrong size.\n");
+ goto clean;
+ }
+
+ LOGP(DMSC, LOGL_NOTICE, "Authenticated the connection.\n");
+ msc->auth = 1;
+ return;
+clean:
+ msc_close_connection(msc);
+}
+
+static int msc_conn_accept(struct osmo_fd *bsc_fd, unsigned int what)
+{
+ struct sockaddr_in addr;
+ socklen_t len = sizeof(addr);
+ struct msc_connection *msc = bsc_fd->data;
+ int ret;
+
+ LOGP(DMSC, LOGL_NOTICE, "Going to accept a connection.\n");
+
+ ret = accept(bsc_fd->fd, (struct sockaddr *) &addr, &len);
+ if (ret < 0) {
+ LOGP(DMSC, LOGL_ERROR, "Accept failed with fd(%d) errno(%d)\n",
+ ret, errno);
+ return -1;
+ }
+
+ /*
+ * Close the previous/current connection.
+ * TODO: switch only once we know it is a valid connection
+ */
+ msc_close_connection(msc);
+
+ /* re-set the internal state */
+ msc->auth = 0;
+
+ /* adopt the connection */
+ msc->msc_connection.bfd.fd = ret;
+ msc->msc_connection.bfd.when = BSC_FD_READ;
+ ret = osmo_fd_register(&msc->msc_connection.bfd);
+ if (ret < 0) {
+ LOGP(DMSC, LOGL_ERROR, "Failed to register fd.\n");
+ close(msc->msc_connection.bfd.fd);
+ msc->msc_connection.bfd.fd = -1;
+ return -1;
+ }
+
+ /* consider it up and running */
+ msc->msc_link_down = 0;
+
+ /* msc send auth request */
+ msc_send_auth_req(msc);
+ LOGP(DMSC, LOGL_ERROR, "Registered fd %d and waiting for data.\n",
+ msc->msc_connection.bfd.fd);
+
+ return 0;
+}
+
+static int msc_conn_bind(struct msc_connection *msc)
+{
+ int rc;
+
+ LOGP(DMSC, LOGL_NOTICE, "Going to bind and wait for connections.\n");
+
+ rc = osmo_sock_init_ofd(&msc->listen_fd, AF_UNSPEC, SOCK_STREAM,
+ IPPROTO_TCP, "127.0.0.1", msc->port, OSMO_SOCK_F_BIND);
+ if (rc < 0) {
+ LOGP(DMSC, LOGL_NOTICE, "Failed to bind the socket.\n");
+ return rc;
+ }
+
+ msc->listen_fd.data = msc;
+ msc->listen_fd.cb = msc_conn_accept;
+
+ return 0;
+}
diff --git a/src/vty_interface.c b/src/vty_interface.c
index 001ba44..e9326a9 100644
--- a/src/vty_interface.c
+++ b/src/vty_interface.c
@@ -241,7 +241,9 @@ static void write_msc(struct vty *vty, struct msc_connection *msc)
vty_out(vty, " msc %d%s", msc->nr, VTY_NEWLINE);
vty_out(vty, " description %s%s", name, VTY_NEWLINE);
+ vty_out(vty, " mode %s%s", msc_mode(msc), VTY_NEWLINE);
vty_out(vty, " ip %s%s", msc->ip, VTY_NEWLINE);
+ vty_out(vty, " port %d%s", msc->port, VTY_NEWLINE);
vty_out(vty, " token %s%s", msc->token, VTY_NEWLINE);
vty_out(vty, " dscp %d%s", msc->dscp, VTY_NEWLINE);
vty_out(vty, " timeout ping %d%s", msc->ping_time, VTY_NEWLINE);
@@ -759,6 +761,25 @@ DEFUN(cfg_ss7_msc, cfg_ss7_msc_cmd,
return CMD_SUCCESS;
}
+DEFUN(cfg_msc_mode, cfg_msc_mode_cmd,
+ "mode (server|client)",
+ "Change the mode of the A-link\n"
+ "Accept incoming connection\n" "Open outgoing connection\n")
+{
+ struct msc_connection *msc = vty->index;
+
+ switch (argv[0][0]) {
+ case 's':
+ msc->mode = MSC_MODE_SERVER;
+ break;
+ case 'c':
+ msc->mode = MSC_MODE_CLIENT;
+ break;
+ }
+
+ return CMD_SUCCESS;
+}
+
DEFUN(cfg_msc_ip, cfg_msc_ip_cmd,
"ip ADDR",
"IP Address of the MSC\n" "Address\n")
@@ -781,6 +802,15 @@ DEFUN(cfg_msc_ip, cfg_msc_ip_cmd,
return CMD_SUCCESS;
}
+DEFUN(cfg_msc_port, cfg_msc_port_cmd,
+ "port <1-65535>",
+ "Port for the TCP connection\n" "Port Number\n")
+{
+ struct msc_connection *msc = vty->index;
+ msc->port = atoi(argv[0]);
+ return CMD_SUCCESS;
+}
+
DEFUN(cfg_msc_token, cfg_msc_token_cmd,
"token TOKEN",
"Token for the MSC\n" "The token\n")
@@ -1086,7 +1116,9 @@ void cell_vty_init(void)
install_element(SS7_NODE, &cfg_ss7_msc_cmd);
install_node(&msc_node, config_write_msc);
install_defaults(MSC_NODE);
+ install_element(MSC_NODE, &cfg_msc_mode_cmd);
install_element(MSC_NODE, &cfg_msc_ip_cmd);
+ install_element(MSC_NODE, &cfg_msc_port_cmd);
install_element(MSC_NODE, &cfg_msc_token_cmd);
install_element(MSC_NODE, &cfg_msc_dscp_cmd);
install_element(MSC_NODE, &cfg_msc_timeout_ping_cmd);