9
0
Fork 0

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.
This commit is contained in:
Holger Hans Peter Freyther 2013-03-19 22:29:41 +01:00
parent d93c84f96e
commit a5a17fa80a
3 changed files with 248 additions and 5 deletions

View File

@ -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

View File

@ -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;
}

View File

@ -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);