Merge branch 'feature/multiple-msc-connections'

This commit is contained in:
Holger Hans Peter Freyther 2012-09-11 18:00:59 +02:00
commit c11889f3dd
8 changed files with 174 additions and 54 deletions

View File

@ -32,13 +32,15 @@ struct bsc_api *osmo_bsc_api();
int bsc_queue_for_msc(struct osmo_bsc_sccp_con *conn, struct msgb *msg);
int bsc_open_connection(struct osmo_bsc_sccp_con *sccp, struct msgb *msg);
int bsc_create_new_connection(struct gsm_subscriber_connection *conn);
int bsc_create_new_connection(struct gsm_subscriber_connection *conn,
struct osmo_msc_data *msc);
int bsc_delete_connection(struct osmo_bsc_sccp_con *sccp);
struct osmo_msc_data *bsc_find_msc(struct gsm_subscriber_connection *conn, struct msgb *);
int bsc_scan_bts_msg(struct gsm_subscriber_connection *conn, struct msgb *msg);
int bsc_scan_msc_msg(struct gsm_subscriber_connection *conn, struct msgb *msg);
int bsc_handle_udt(struct gsm_network *net, struct bsc_msc_connection *conn, struct msgb *msg, unsigned int length);
int bsc_handle_udt(struct osmo_msc_data *msc, struct msgb *msg, unsigned int length);
int bsc_handle_dt1(struct osmo_bsc_sccp_con *conn, struct msgb *msg, unsigned int len);
int bsc_ctrl_cmds_install();

View File

@ -34,6 +34,7 @@ enum bsc_vty_node {
TRUNK_NODE,
PGROUP_NODE,
MNCC_INT_NODE,
BSC_NODE,
};
extern int bsc_vty_is_config_node(struct vty *vty, int node);

View File

@ -148,6 +148,7 @@ gDEFUN(ournode_exit,
case GBPROXY_NODE:
case SGSN_NODE:
case NAT_NODE:
case BSC_NODE:
vty->node = CONFIG_NODE;
vty->index = NULL;
break;
@ -195,6 +196,7 @@ gDEFUN(ournode_end,
case PGROUP_NODE:
case MSC_NODE:
case MNCC_INT_NODE:
case BSC_NODE:
vty_config_unlock(vty);
vty->node = ENABLE_NODE;
vty->index = NULL;

View File

@ -89,13 +89,21 @@ static int bsc_compl_l3(struct gsm_subscriber_connection *conn, struct msgb *msg
uint16_t chosen_channel)
{
struct msgb *resp;
struct osmo_msc_data *msc;
uint16_t network_code;
uint16_t country_code;
LOGP(DMSC, LOGL_INFO, "Tx MSC COMPL L3\n");
/* find the MSC link we want to use */
msc = bsc_find_msc(conn, msg);
if (!msc) {
LOGP(DMSC, LOGL_ERROR, "Failed to find a MSC for a connection.\n");
return -1;
}
/* allocate resource for a new connection */
if (bsc_create_new_connection(conn) != 0)
if (bsc_create_new_connection(conn, msc) != 0)
return BSC_API_CONN_POL_REJECT;
network_code = get_network_code_for_msc(conn->sccp_con->msc);

View File

@ -98,7 +98,7 @@ enum gsm48_chan_mode gsm88_to_chan_mode(enum gsm0808_permitted_speech speech)
return GSM48_CMODE_SPEECH_AMR;
}
static int bssmap_handle_reset_ack(struct gsm_network *net,
static int bssmap_handle_reset_ack(struct osmo_msc_data *msc,
struct msgb *msg, unsigned int length)
{
LOGP(DMSC, LOGL_NOTICE, "Reset ACK from MSC\n");
@ -106,7 +106,7 @@ static int bssmap_handle_reset_ack(struct gsm_network *net,
}
/* GSM 08.08 § 3.2.1.19 */
static int bssmap_handle_paging(struct gsm_network *net,
static int bssmap_handle_paging(struct osmo_msc_data *msc,
struct msgb *msg, unsigned int payload_length)
{
struct gsm_subscriber *subscr;
@ -167,7 +167,7 @@ static int bssmap_handle_paging(struct gsm_network *net,
LOGP(DMSC, LOGL_ERROR, "eMLPP is not handled\n");
}
subscr = subscr_get_or_create(net, mi_string);
subscr = subscr_get_or_create(msc->network, mi_string);
if (!subscr) {
LOGP(DMSC, LOGL_ERROR, "Failed to allocate a subscriber for %s\n", mi_string);
return -1;
@ -177,7 +177,7 @@ static int bssmap_handle_paging(struct gsm_network *net,
subscr->tmsi = tmsi;
LOGP(DMSC, LOGL_INFO, "Paging request from MSC IMSI: '%s' TMSI: '0x%x/%u' LAC: 0x%x\n", mi_string, tmsi, tmsi, lac);
paging_request(net, subscr, chan_needed, NULL, NULL);
paging_request(msc->network, subscr, chan_needed, NULL, msc);
return 0;
}
@ -395,7 +395,7 @@ reject:
return -1;
}
static int bssmap_rcvmsg_udt(struct gsm_network *net,
static int bssmap_rcvmsg_udt(struct osmo_msc_data *msc,
struct msgb *msg, unsigned int length)
{
int ret = 0;
@ -410,11 +410,11 @@ static int bssmap_rcvmsg_udt(struct gsm_network *net,
switch (msg->l4h[0]) {
case BSS_MAP_MSG_RESET_ACKNOWLEDGE:
ret = bssmap_handle_reset_ack(net, msg, length);
ret = bssmap_handle_reset_ack(msc, msg, length);
break;
case BSS_MAP_MSG_PAGING:
if (bsc_grace_allow_new_connection(net))
ret = bssmap_handle_paging(net, msg, length);
if (bsc_grace_allow_new_connection(msc->network))
ret = bssmap_handle_paging(msc, msg, length);
break;
}
@ -499,8 +499,7 @@ static int dtap_rcvmsg(struct osmo_bsc_sccp_con *conn,
return gsm0808_submit_dtap(conn->conn, gsm48, header->link_id, 1);
}
int bsc_handle_udt(struct gsm_network *network,
struct bsc_msc_connection *conn,
int bsc_handle_udt(struct osmo_msc_data *msc,
struct msgb *msgb, unsigned int length)
{
struct bssmap_header *bs;
@ -520,7 +519,7 @@ int bsc_handle_udt(struct gsm_network *network,
switch (bs->type) {
case BSSAP_MSG_BSS_MANAGEMENT:
msgb->l4h = &msgb->l3h[sizeof(*bs)];
bssmap_rcvmsg_udt(network, msgb, length - sizeof(*bs));
bssmap_rcvmsg_udt(msc, msgb, length - sizeof(*bs));
break;
default:
LOGP(DMSC, LOGL_NOTICE, "Unimplemented msg type: %s\n",

View File

@ -53,8 +53,9 @@ static void handle_lu_request(struct gsm_subscriber_connection *conn,
}
}
/* we will need to stop the paging request */
static int handle_page_resp(struct gsm_subscriber_connection *conn, struct msgb *msg)
/* extract a subscriber from the paging response */
static struct gsm_subscriber *extract_sub(struct gsm_subscriber_connection *conn,
struct msgb *msg)
{
uint8_t mi_type;
char mi_string[GSM48_MI_SIZE];
@ -64,7 +65,7 @@ static int handle_page_resp(struct gsm_subscriber_connection *conn, struct msgb
if (msgb_l3len(msg) < sizeof(*gh) + sizeof(*resp)) {
LOGP(DMSC, LOGL_ERROR, "PagingResponse too small: %u\n", msgb_l3len(msg));
return -1;
return NULL;
}
gh = msgb_l3(msg);
@ -88,6 +89,14 @@ static int handle_page_resp(struct gsm_subscriber_connection *conn, struct msgb
break;
}
return subscr;
}
/* we will need to stop the paging request */
static int handle_page_resp(struct gsm_subscriber_connection *conn, struct msgb *msg)
{
struct gsm_subscriber *subscr = extract_sub(conn, msg);
if (!subscr) {
LOGP(DMSC, LOGL_ERROR, "Non active subscriber got paged.\n");
return -1;
@ -97,6 +106,79 @@ static int handle_page_resp(struct gsm_subscriber_connection *conn, struct msgb
subscr_put(subscr);
return 0;
}
struct osmo_msc_data *bsc_find_msc(struct gsm_subscriber_connection *conn,
struct msgb *msg)
{
struct gsm48_hdr *gh;
int8_t pdisc;
uint8_t mtype;
struct osmo_bsc_data *bsc;
struct osmo_msc_data *msc, *pag_msc;
struct gsm_subscriber *subscr;
bsc = conn->bts->network->bsc_data;
if (msgb_l3len(msg) < sizeof(*gh)) {
LOGP(DMSC, LOGL_ERROR, "There is no GSM48 header here.\n");
return NULL;
}
gh = msgb_l3(msg);
pdisc = gh->proto_discr & 0x0f;
mtype = gh->msg_type & 0xbf;
/*
* We are asked to select a MSC here but they are not equal. We
* want to respond to a paging request on the MSC where we got the
* request from. This is where we need to decide where this connection
* will go.
*/
if (pdisc == GSM48_PDISC_RR && mtype == GSM48_MT_RR_PAG_RESP)
goto paging;
else
goto round_robin;
round_robin:
llist_for_each_entry(msc, &bsc->mscs, entry) {
if (!msc->msc_con->is_authenticated)
continue;
/* force round robin by moving it to the end */
llist_move_tail(&msc->entry, &bsc->mscs);
return msc;
}
return NULL;
paging:
subscr = extract_sub(conn, msg);
if (!subscr) {
LOGP(DMSC, LOGL_ERROR, "Got paged but no subscriber found.\n");
return NULL;
}
pag_msc = paging_get_data(conn->bts, subscr);
subscr_put(subscr);
llist_for_each_entry(msc, &bsc->mscs, entry) {
if (msc != pag_msc)
continue;
/*
* We don't check if the MSC is connected. In case it
* is not the connection will be dropped.
*/
/* force round robin by moving it to the end */
llist_move_tail(&msc->entry, &bsc->mscs);
return msc;
}
LOGP(DMSC, LOGL_ERROR, "Got paged but no request found.\n");
return NULL;
}
/**
* This is used to scan a message for extra functionality of the BSC. This

View File

@ -161,7 +161,7 @@ static int msc_sccp_accept(struct sccp_connection *connection, void *data)
static int msc_sccp_read(struct msgb *msgb, unsigned int length, void *data)
{
struct osmo_msc_data *msc = (struct osmo_msc_data *) msgb->cb[0];
return bsc_handle_udt(msc->network, msc->msc_con, msgb, length);
return bsc_handle_udt(msc, msgb, length);
}
int bsc_queue_for_msc(struct osmo_bsc_sccp_con *conn, struct msgb *msg)
@ -187,22 +187,19 @@ int bsc_queue_for_msc(struct osmo_bsc_sccp_con *conn, struct msgb *msg)
return 0;
}
int bsc_create_new_connection(struct gsm_subscriber_connection *conn)
int bsc_create_new_connection(struct gsm_subscriber_connection *conn,
struct osmo_msc_data *msc)
{
struct gsm_network *net;
struct osmo_msc_data *msc;
struct osmo_bsc_sccp_con *bsc_con;
struct sccp_connection *sccp;
net = conn->bts->network;
msc = osmo_msc_data_find(net, 0);
if (!msc) {
LOGP(DMSC, LOGL_ERROR, "Failed to select a MSC.\n");
return -1;
}
/* This should not trigger */
if (!msc->msc_con->is_authenticated) {
LOGP(DMSC, LOGL_ERROR, "Not connected to a MSC. Not forwarding data.\n");
LOGP(DMSC, LOGL_ERROR,
"How did this happen? MSC is not connected. Dropping.\n");
return -1;
}
@ -272,8 +269,10 @@ static void bsc_close_connections(struct bsc_msc_connection *msc_con)
{
struct osmo_bsc_sccp_con *con, *tmp;
llist_for_each_entry_safe(con, tmp, &active_connections, entry)
bsc_sccp_force_free(con);
llist_for_each_entry_safe(con, tmp, &active_connections, entry) {
if (con->msc->msc_con == msc_con)
bsc_sccp_force_free(con);
}
}
static int handle_msc_signal(unsigned int subsys, unsigned int signal,

View File

@ -39,6 +39,12 @@ static struct osmo_msc_data *osmo_msc_data(struct vty *vty)
return osmo_msc_data_find(bsc_gsmnet, (int) vty->index);
}
static struct cmd_node bsc_node = {
BSC_NODE,
"%s(bsc)#",
1,
};
static struct cmd_node msc_node = {
MSC_NODE,
"%s(config-msc)# ",
@ -46,9 +52,9 @@ static struct cmd_node msc_node = {
};
DEFUN(cfg_net_msc, cfg_net_msc_cmd,
"msc", "Configure MSC details")
"msc [<0-1000>]", "Configure MSC details\n" "MSC connection to configure\n")
{
int index = 0;
int index = argc == 1 ? atoi(argv[0]) : 0;
struct osmo_msc_data *msc;
msc = osmo_msc_data_alloc(bsc_gsmnet, index);
@ -62,11 +68,18 @@ DEFUN(cfg_net_msc, cfg_net_msc_cmd,
return CMD_SUCCESS;
}
DEFUN(cfg_net_bsc, cfg_net_bsc_cmd,
"bsc", "Configure BSC\n")
{
vty->node = BSC_NODE;
return CMD_SUCCESS;
}
static void write_msc(struct vty *vty, struct osmo_msc_data *msc)
{
struct bsc_msc_dest *dest;
vty_out(vty, "msc%s", VTY_NEWLINE);
vty_out(vty, "msc %d%s", msc->nr, VTY_NEWLINE);
if (msc->bsc_token)
vty_out(vty, " token %s%s", msc->bsc_token, VTY_NEWLINE);
if (msc->core_ncc != -1)
@ -111,6 +124,14 @@ static int config_write_msc(struct vty *vty)
llist_for_each_entry(msc, &bsc->mscs, entry)
write_msc(vty, msc);
return CMD_SUCCESS;
}
static int config_write_bsc(struct vty *vty)
{
struct osmo_bsc_data *bsc = osmo_bsc_data(vty);
vty_out(vty, "bsc%s", VTY_NEWLINE);
if (bsc->mid_call_txt)
vty_out(vty, " mid-call-text %s%s", bsc->mid_call_txt, VTY_NEWLINE);
vty_out(vty, " mid-call-timeout %d%s", bsc->mid_call_timeout, VTY_NEWLINE);
@ -296,8 +317,23 @@ DEFUN(cfg_net_msc_pong_time,
return CMD_SUCCESS;
}
DEFUN(cfg_net_msc_mid_call_text,
cfg_net_msc_mid_call_text_cmd,
DEFUN(cfg_net_msc_welcome_ussd,
cfg_net_msc_welcome_ussd_cmd,
"bsc-welcome-text .TEXT",
"Set the USSD notification to be sent.\n" "Text to be sent\n")
{
struct osmo_msc_data *data = osmo_msc_data(vty);
char *str = argv_concat(argv, argc, 0);
if (!str)
return CMD_WARNING;
bsc_replace_string(osmo_bsc_data(vty), &data->ussd_welcome_txt, str);
talloc_free(str);
return CMD_SUCCESS;
}
DEFUN(cfg_net_bsc_mid_call_text,
cfg_net_bsc_mid_call_text_cmd,
"mid-call-text .TEXT",
"Set the USSD notifcation to be send.\n" "Text to be sent\n")
{
@ -311,8 +347,8 @@ DEFUN(cfg_net_msc_mid_call_text,
return CMD_SUCCESS;
}
DEFUN(cfg_net_msc_mid_call_timeout,
cfg_net_msc_mid_call_timeout_cmd,
DEFUN(cfg_net_bsc_mid_call_timeout,
cfg_net_bsc_mid_call_timeout_cmd,
"mid-call-timeout NR",
"Switch from Grace to Off in NR seconds.\n" "Timeout in seconds\n")
{
@ -321,21 +357,6 @@ DEFUN(cfg_net_msc_mid_call_timeout,
return CMD_SUCCESS;
}
DEFUN(cfg_net_msc_welcome_ussd,
cfg_net_msc_welcome_ussd_cmd,
"bsc-welcome-text .TEXT",
"Set the USSD notification to be sent.\n" "Text to be sent\n")
{
struct osmo_msc_data *data = osmo_msc_data(vty);
char *str = argv_concat(argv, argc, 0);
if (!str)
return CMD_WARNING;
bsc_replace_string(osmo_bsc_data(vty), &data->ussd_welcome_txt, str);
talloc_free(str);
return CMD_SUCCESS;
}
DEFUN(cfg_net_rf_socket,
cfg_net_rf_socket_cmd,
"bsc-rf-socket PATH",
@ -376,6 +397,16 @@ DEFUN(show_mscs,
int bsc_vty_init_extra(void)
{
install_element(CONFIG_NODE, &cfg_net_msc_cmd);
install_element(CONFIG_NODE, &cfg_net_bsc_cmd);
install_node(&bsc_node, config_write_bsc);
install_default(BSC_NODE);
install_element(BSC_NODE, &cfg_net_bsc_mid_call_text_cmd);
install_element(BSC_NODE, &cfg_net_bsc_mid_call_timeout_cmd);
install_element(BSC_NODE, &cfg_net_rf_socket_cmd);
install_node(&msc_node, config_write_msc);
install_default(MSC_NODE);
install_element(MSC_NODE, &cfg_net_bsc_token_cmd);
@ -389,10 +420,6 @@ int bsc_vty_init_extra(void)
install_element(MSC_NODE, &cfg_net_msc_pong_time_cmd);
install_element(MSC_NODE, &cfg_net_msc_welcome_ussd_cmd);
install_element(MSC_NODE, &cfg_net_msc_mid_call_text_cmd);
install_element(MSC_NODE, &cfg_net_msc_mid_call_timeout_cmd);
install_element(MSC_NODE, &cfg_net_rf_socket_cmd);
install_element_ve(&show_statistics_cmd);
install_element_ve(&show_mscs_cmd);