aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--openbsc/include/openbsc/bsc_msc.h1
-rw-r--r--openbsc/include/openbsc/bsc_nat.h14
-rw-r--r--openbsc/src/osmo-bsc_nat/bsc_nat.c68
-rw-r--r--openbsc/src/osmo-bsc_nat/bsc_nat_call_control.c137
-rw-r--r--openbsc/src/osmo-bsc_nat/bsc_nat_utils.c5
5 files changed, 204 insertions, 21 deletions
diff --git a/openbsc/include/openbsc/bsc_msc.h b/openbsc/include/openbsc/bsc_msc.h
index 647f47e56..50a7551c9 100644
--- a/openbsc/include/openbsc/bsc_msc.h
+++ b/openbsc/include/openbsc/bsc_msc.h
@@ -43,6 +43,7 @@ struct bsc_msc_connection {
struct llist_head *dests;
const char *name;
+ void *data;
void (*connection_loss) (struct bsc_msc_connection *);
void (*connected) (struct bsc_msc_connection *);
diff --git a/openbsc/include/openbsc/bsc_nat.h b/openbsc/include/openbsc/bsc_nat.h
index b6a3781d0..65a8c90ad 100644
--- a/openbsc/include/openbsc/bsc_nat.h
+++ b/openbsc/include/openbsc/bsc_nat.h
@@ -65,6 +65,7 @@ enum {
NAT_CON_END_MSC,
NAT_CON_END_LOCAL,
NAT_CON_END_USSD,
+ NAT_CON_END_CALL,
};
/*
@@ -134,6 +135,7 @@ struct bsc_config_stats {
enum bsc_cfg_ctr {
BCFG_CTR_SCCP_CONN,
BCFG_CTR_SCCP_CALLS,
+ BCFG_CTR_SCCP_LOC_CALLS,
BCFG_CTR_NET_RECONN,
BCFG_CTR_DROPPED_SCCP,
BCFG_CTR_DROPPED_CALLS,
@@ -221,6 +223,11 @@ struct bsc_nat_statistics {
struct {
struct osmo_counter *reconn;
} ussd;
+
+ struct {
+ struct osmo_counter *reconn;
+ struct osmo_counter *calls;
+ } local_cc;
};
enum bsc_nat_acc_ctr {
@@ -325,6 +332,7 @@ struct bsc_nat {
struct bsc_nat_ussd_con *ussd_con;
/* Local Call-Control */
+ struct bsc_msc_connection *local_conn;
struct llist_head local_dests;
struct bsc_msc_dest *local_dest;
char *local_prefix;
@@ -427,6 +435,10 @@ int bsc_do_write(struct osmo_wqueue *queue, struct msgb *msg, int id);
int bsc_write_msg(struct osmo_wqueue *queue, struct msgb *msg);
int bsc_write_cb(struct osmo_fd *bfd, struct msgb *msg);
+/* A-link handling */
+int bsc_base_msc_read_cb(struct osmo_fd *fd, struct msgb **out);
+int bsc_close_connections_by_type(struct bsc_nat *nat, int type);
+
/* IMSI allow/deny handling */
struct bsc_nat_acc_lst *bsc_nat_acc_lst_find(struct bsc_nat *nat, const char *name);
struct bsc_nat_acc_lst *bsc_nat_acc_lst_get(struct bsc_nat *nat, const char *name);
@@ -447,6 +459,8 @@ int bsc_ussd_check(struct nat_sccp_connection *con, struct bsc_nat_parsed *parse
int bsc_ussd_close_connections(struct bsc_nat *nat);
void bsc_cc_update_msc_ip(struct bsc_nat *bsc, const char *ip);
+int bsc_cc_initialize(struct bsc_nat *bsc);
+
struct msgb *bsc_nat_rewrite_msg(struct bsc_nat *nat, struct msgb *msg, struct bsc_nat_parsed *, const char *imsi);
/** paging group handling */
diff --git a/openbsc/src/osmo-bsc_nat/bsc_nat.c b/openbsc/src/osmo-bsc_nat/bsc_nat.c
index d9fc0ca48..9cc02a185 100644
--- a/openbsc/src/osmo-bsc_nat/bsc_nat.c
+++ b/openbsc/src/osmo-bsc_nat/bsc_nat.c
@@ -793,11 +793,11 @@ static void msc_send_reset(struct bsc_msc_connection *msc_con)
LOGP(DMSC, LOGL_NOTICE, "Scheduled GSM0808 reset msg for the MSC.\n");
}
-static int ipaccess_msc_read_cb(struct osmo_fd *bfd)
+int bsc_base_msc_read_cb(struct osmo_fd *bfd, struct msgb **out_msg)
{
+ struct ipaccess_head *hh;
struct bsc_msc_connection *msc_con;
struct msgb *msg;
- struct ipaccess_head *hh;
int ret;
msc_con = (struct bsc_msc_connection *) bfd->data;
@@ -825,33 +825,50 @@ static int ipaccess_msc_read_cb(struct osmo_fd *bfd)
hh = (struct ipaccess_head *) msg->data;
ipaccess_rcvmsg_base(msg, bfd);
- /* initialize the networking. This includes sending a GSM08.08 message */
if (hh->proto == IPAC_PROTO_IPACCESS) {
- if (msg->l2h[0] == IPAC_MSGT_ID_ACK)
+ if (msg->l2h[0] == IPAC_MSGT_ID_ACK) {
initialize_msc_if_needed(msc_con);
- else if (msg->l2h[0] == IPAC_MSGT_ID_GET)
+ goto handled;
+ } else if (msg->l2h[0] == IPAC_MSGT_ID_GET) {
send_id_get_response(msc_con);
- } else if (hh->proto == IPAC_PROTO_SCCP) {
- forward_sccp_to_bts(msc_con, msg);
- } else if (hh->proto == IPAC_PROTO_MGCP_OLD) {
- bsc_nat_handle_mgcp(nat, msg);
+ goto handled;
+ }
}
- msgb_free(msg);
+ /* not handled */
+ *out_msg = msg;
return 0;
+
+handled:
+ msgb_free(msg);
+ return 1;
}
-static int ipaccess_msc_write_cb(struct osmo_fd *bfd, struct msgb *msg)
+static int ipaccess_msc_read_cb(struct osmo_fd *bfd)
{
- int rc;
- rc = write(bfd->fd, msg->data, msg->len);
+ struct bsc_msc_connection *msc_con;
+ struct msgb *msg;
+ struct ipaccess_head *hh;
+ int ret;
- if (rc != msg->len) {
- LOGP(DNAT, LOGL_ERROR, "Failed to write MSG to MSC.\n");
- return -1;
+ msc_con = (struct bsc_msc_connection *) bfd->data;
+
+ ret = bsc_base_msc_read_cb(bfd, &msg);
+ if (ret == -1)
+ return ret;
+ if (ret == 1)
+ return 0;
+
+ hh = (struct ipaccess_head *) msg->data;
+ /* initialize the networking. This includes sending a GSM08.08 message */
+ if (hh->proto == IPAC_PROTO_SCCP) {
+ forward_sccp_to_bts(msc_con, msg);
+ } else if (hh->proto == IPAC_PROTO_MGCP_OLD) {
+ bsc_nat_handle_mgcp(nat, msg);
}
- return rc;
+ msgb_free(msg);
+ return 0;
}
/*
@@ -1559,10 +1576,16 @@ int main(int argc, char **argv)
nat->msc_con->connection_loss = msc_connection_was_lost;
nat->msc_con->connected = msc_connection_connected;
nat->msc_con->write_queue.read_cb = ipaccess_msc_read_cb;
- nat->msc_con->write_queue.write_cb = ipaccess_msc_write_cb;;
+ nat->msc_con->write_queue.write_cb = bsc_write_cb;
nat->msc_con->write_queue.bfd.data = nat->msc_con;
bsc_msc_connect(nat->msc_con);
+ /* prepare the local connection */
+ if (bsc_cc_initialize(nat) != 0) {
+ fprintf(stderr, "Creating local bsc_msc_connection failed.\n");
+ exit(1);
+ }
+
/* wait for the BSC */
rc = make_sock(&bsc_listen, IPPROTO_TCP, ntohl(local_addr.s_addr),
5000, 0, ipaccess_listen_bsc_cb, nat);
@@ -1603,11 +1626,11 @@ int main(int argc, char **argv)
}
/* Close all connections handed out to the USSD module */
-int bsc_ussd_close_connections(struct bsc_nat *nat)
+int bsc_close_connections_by_type(struct bsc_nat *nat, int type)
{
struct nat_sccp_connection *con;
llist_for_each_entry(con, &nat->sccp_connections, list_entry) {
- if (con->con_local != NAT_CON_END_USSD)
+ if (con->con_local != type)
continue;
if (!con->bsc)
continue;
@@ -1618,3 +1641,8 @@ int bsc_ussd_close_connections(struct bsc_nat *nat)
return 0;
}
+
+int bsc_ussd_close_connections(struct bsc_nat *nat)
+{
+ return bsc_close_connections_by_type(nat, NAT_CON_END_USSD);
+}
diff --git a/openbsc/src/osmo-bsc_nat/bsc_nat_call_control.c b/openbsc/src/osmo-bsc_nat/bsc_nat_call_control.c
index 163261e1b..b9a4bbae1 100644
--- a/openbsc/src/osmo-bsc_nat/bsc_nat_call_control.c
+++ b/openbsc/src/osmo-bsc_nat/bsc_nat_call_control.c
@@ -20,9 +20,13 @@
*/
#include <openbsc/bsc_nat.h>
+#include <openbsc/bsc_nat_sccp.h>
#include <openbsc/bsc_msc.h>
+#include <openbsc/ipaccess.h>
#include <openbsc/vty.h>
+#include <osmocom/gsm/protocol/gsm_08_08.h>
+
#include <osmocom/core/talloc.h>
void bsc_cc_update_msc_ip(struct bsc_nat *nat, const char *ip)
@@ -33,5 +37,138 @@ void bsc_cc_update_msc_ip(struct bsc_nat *nat, const char *ip)
talloc_free(nat->local_dest->ip);
nat->local_dest->ip = NULL;
}
+
+ /* re-connect if the local_conn was already created */
+ if (nat->local_conn)
+ bsc_msc_lost(nat->local_conn);
+}
+
+static void local_connection_connected(struct bsc_msc_connection *con)
+{
+ struct bsc_nat *nat = con->data;
+ osmo_counter_inc(nat->stats.local_cc.reconn);
+}
+
+/**
+ * In contrast to forward_sccp_to_bts above we only work on already
+ * authenticated connections and will only forward parts of the connection.
+ * I am not sure how to reduce the copy and paste between the two routines
+ * yet!
+ */
+static int local_forward_sccp_to_bts(struct bsc_msc_connection *local_con,
+ struct msgb *msg)
+{
+ struct nat_sccp_connection *con = NULL;
+ struct bsc_nat_parsed *parsed;
+ struct bsc_nat *nat;
+ int proto;
+
+ nat = local_con->data;
+
+ /* filter, drop, patch the message? */
+ parsed = bsc_nat_parse(msg);
+ if (!parsed) {
+ LOGP(DNAT, LOGL_ERROR, "Can not parse msg from BSC.\n");
+ return -1;
+ }
+
+ if (bsc_nat_filter_ipa(DIR_BSC, msg, parsed))
+ goto exit;
+
+ proto = parsed->ipa_proto;
+ if (proto != IPAC_PROTO_SCCP)
+ return -1;
+
+ switch (parsed->sccp_type) {
+ case SCCP_MSG_TYPE_UDT:
+ /* ignore */
+ break;
+ case SCCP_MSG_TYPE_RLSD:
+ case SCCP_MSG_TYPE_CREF:
+ case SCCP_MSG_TYPE_DT1:
+ case SCCP_MSG_TYPE_IT:
+ con = patch_sccp_src_ref_to_bsc(msg, parsed, nat);
+ if (parsed->gsm_type == BSS_MAP_MSG_ASSIGMENT_RQST) {
+ osmo_counter_inc(nat->stats.local_cc.calls);
+#warning "TODO... MGCP handling needs to be defined..."
+
+ if (con) {
+ struct rate_ctr_group *ctrg;
+ ctrg = con->bsc->cfg->stats.ctrg;
+ rate_ctr_inc(&ctrg->ctr[BCFG_CTR_SCCP_LOC_CALLS]);
+ if (bsc_mgcp_assign_patch(con, msg) != 0)
+ LOGP(DNAT, LOGL_ERROR, "Failed to assign...\n");
+ } else
+ LOGP(DNAT, LOGL_ERROR, "Assignment command but no BSC.\n");
+ }
+ break;
+ case SCCP_MSG_TYPE_CC:
+ /* should not happen */
+ case SCCP_MSG_TYPE_RLC:
+ /* should not happen */
+ case SCCP_MSG_TYPE_CR:
+ /* MSC never opens a SCCP connection, fall through */
+ default:
+ goto exit;
+ }
+
+exit:
+ talloc_free(parsed);
+ return 0;
}
+int local_msc_read_cb(struct osmo_fd *bfd)
+{
+ struct bsc_msc_connection *local_con;
+ struct ipaccess_head *hh;
+ struct msgb *msg;
+ int ret;
+
+ local_con = (struct bsc_msc_connection *) bfd->data;
+ ret = bsc_base_msc_read_cb(bfd, &msg);
+ if (ret == -1)
+ return ret;
+ if (ret == 1)
+ return 0;
+
+ /* TODO: MGCP handling */
+ hh = (struct ipaccess_head *) msg->data;
+ if (hh->proto == IPAC_PROTO_SCCP)
+ local_forward_sccp_to_bts(local_con, msg);
+
+ msgb_free(msg);
+ return 0;
+}
+
+static void local_connection_was_lost(struct bsc_msc_connection *con)
+{
+ struct bsc_nat *nat = con->data;
+
+ LOGP(DMSC, LOGL_ERROR, "Local MSC disconnected. Closing things.\n");
+
+ /* Close local calls */
+ bsc_close_connections_by_type(nat, NAT_CON_END_CALL);
+
+ /* Only schedule the reconnect if we still have an IP address */
+ if (nat->local_dest->ip)
+ bsc_msc_schedule_connect(con);
+}
+
+int bsc_cc_initialize(struct bsc_nat *nat)
+{
+ nat->local_conn = bsc_msc_create(nat, &nat->local_dests);
+ if (!nat->local_conn)
+ return -1;
+
+ nat->local_conn->name = "local MSC";
+ nat->local_conn->connection_loss = local_connection_was_lost;
+ nat->local_conn->connected = local_connection_connected;
+ nat->local_conn->write_queue.read_cb = local_msc_read_cb;
+ nat->local_conn->write_queue.write_cb = bsc_write_cb;
+ nat->local_conn->write_queue.bfd.data = nat->local_conn;
+ nat->local_conn->data = nat;
+ if (nat->local_dest->ip)
+ bsc_msc_connect(nat->local_conn);
+
+ return 0;
+}
diff --git a/openbsc/src/osmo-bsc_nat/bsc_nat_utils.c b/openbsc/src/osmo-bsc_nat/bsc_nat_utils.c
index aa152d50e..35f40033c 100644
--- a/openbsc/src/osmo-bsc_nat/bsc_nat_utils.c
+++ b/openbsc/src/osmo-bsc_nat/bsc_nat_utils.c
@@ -45,6 +45,7 @@
static const struct rate_ctr_desc bsc_cfg_ctr_description[] = {
[BCFG_CTR_SCCP_CONN] = { "sccp.conn", "SCCP Connections "},
[BCFG_CTR_SCCP_CALLS] = { "sccp.calls", "SCCP Assignment Commands "},
+ [BCFG_CTR_SCCP_LOC_CALLS]= { "sccp.local_calls","Local Assignment Commands "},
[BCFG_CTR_NET_RECONN] = { "net.reconnects", "Network reconnects "},
[BCFG_CTR_DROPPED_SCCP] = { "dropped.sccp", "Dropped SCCP connections."},
[BCFG_CTR_DROPPED_CALLS] = { "dropped.calls", "Dropped active calls. "},
@@ -115,6 +116,8 @@ struct bsc_nat *bsc_nat_alloc(void)
nat->stats.bsc.auth_fail = osmo_counter_alloc("nat.bsc.auth_fail");
nat->stats.msc.reconn = osmo_counter_alloc("nat.msc.conn");
nat->stats.ussd.reconn = osmo_counter_alloc("nat.ussd.conn");
+ nat->stats.local_cc.reconn = osmo_counter_alloc("nat.local_cc.conn");
+ nat->stats.local_cc.calls = osmo_counter_alloc("nat.local_cc.calls");
nat->auth_timeout = 2;
nat->ping_timeout = 20;
nat->pong_timeout = 5;
@@ -509,7 +512,7 @@ int bsc_write_cb(struct osmo_fd *bfd, struct msgb *msg)
rc = write(bfd->fd, msg->data, msg->len);
if (rc != msg->len)
- LOGP(DNAT, LOGL_ERROR, "Failed to write message to the BSC.\n");
+ LOGP(DNAT, LOGL_ERROR, "Failed to write message!\n");
return rc;
}