diff options
-rw-r--r-- | openbsc/include/openbsc/bsc_msc.h | 1 | ||||
-rw-r--r-- | openbsc/include/openbsc/bsc_nat.h | 14 | ||||
-rw-r--r-- | openbsc/src/osmo-bsc_nat/bsc_nat.c | 68 | ||||
-rw-r--r-- | openbsc/src/osmo-bsc_nat/bsc_nat_call_control.c | 137 | ||||
-rw-r--r-- | openbsc/src/osmo-bsc_nat/bsc_nat_utils.c | 5 |
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; } |