Merge branch 'feature/multiple-msc-connections'
This commit is contained in:
commit
c11889f3dd
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
Loading…
Reference in New Issue