From 4b159cb6f39e7f0516b191575f4420819de3606e Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 28 Jan 2018 03:04:16 +0100 Subject: WIP: introduce an osmo_fsm for gsm_subscriber_connection Change-Id: I68286d26e2014048b054f39ef29c35fef420cc97 --- include/osmocom/bsc/Makefile.am | 1 + include/osmocom/bsc/bsc_api.h | 3 + include/osmocom/bsc/bsc_subscr_conn_fsm.h | 48 +++ include/osmocom/bsc/gsm_data.h | 7 +- include/osmocom/bsc/osmo_bsc_sigtran.h | 5 - src/ipaccess/Makefile.am | 1 - src/libbsc/abis_rsl.c | 16 +- src/libbsc/bsc_api.c | 95 +----- src/osmo-bsc/Makefile.am | 1 + src/osmo-bsc/bsc_subscr_conn_fsm.c | 485 +++++++++++++++++++++++++++ src/osmo-bsc/osmo_bsc_api.c | 31 +- src/osmo-bsc/osmo_bsc_bssap.c | 50 +-- src/osmo-bsc/osmo_bsc_mgcp.c | 9 +- src/osmo-bsc/osmo_bsc_sigtran.c | 106 +++--- src/utils/Makefile.am | 1 - tests/abis/abis_test.c | 4 + tests/bsc/bsc_test.c | 4 + tests/bssap/bssap_test.c | 4 + tests/gsm0408/gsm0408_test.c | 4 + tests/nanobts_omlattr/nanobts_omlattr_test.c | 4 + 20 files changed, 645 insertions(+), 234 deletions(-) create mode 100644 include/osmocom/bsc/bsc_subscr_conn_fsm.h create mode 100644 src/osmo-bsc/bsc_subscr_conn_fsm.c diff --git a/include/osmocom/bsc/Makefile.am b/include/osmocom/bsc/Makefile.am index 17e8bd313..da05f1c51 100644 --- a/include/osmocom/bsc/Makefile.am +++ b/include/osmocom/bsc/Makefile.am @@ -12,6 +12,7 @@ noinst_HEADERS = \ bsc_nat_sccp.h \ bsc_rll.h \ bsc_subscriber.h \ + bsc_subscr_conn_fsm.h \ bss.h \ bts_ipaccess_nanobts_omlattr.h \ chan_alloc.h \ diff --git a/include/osmocom/bsc/bsc_api.h b/include/osmocom/bsc/bsc_api.h index 6ee05629f..01f90b158 100644 --- a/include/osmocom/bsc/bsc_api.h +++ b/include/osmocom/bsc/bsc_api.h @@ -46,6 +46,9 @@ struct bsc_api { void (*conn_cleanup)(struct gsm_subscriber_connection *conn); }; +uint8_t lchan_to_chosen_channel(struct gsm_lchan *lchan); +uint8_t chan_mode_to_speech(struct gsm_lchan *lchan); + int bsc_api_init(struct gsm_network *network, struct bsc_api *api); int gsm0808_submit_dtap(struct gsm_subscriber_connection *conn, struct msgb *msg, int link_id, int allow_sacch); int gsm0808_assign_req(struct gsm_subscriber_connection *conn, int chan_mode, int full_rate); diff --git a/include/osmocom/bsc/bsc_subscr_conn_fsm.h b/include/osmocom/bsc/bsc_subscr_conn_fsm.h new file mode 100644 index 000000000..58b7d50a5 --- /dev/null +++ b/include/osmocom/bsc/bsc_subscr_conn_fsm.h @@ -0,0 +1,48 @@ +#pragma once +#include + +enum gscon_fsm_event { + /* local SCCP stack tells us incoming conn from MSC */ + GSCON_EV_A_CONN_IND, + /* RSL side requests CONNECT to MSC */ + GSCON_EV_A_CONN_REQ, + /* MSC confirms the SCCP connection */ + GSCON_EV_A_CONN_CFM, + /* MSC requests assignment */ + GSCON_EV_A_ASSIGNMENT_CMD, + /* MSC has sent BSSMAP CLEAR CMD */ + GSCON_EV_A_CLEAR_CMD, + /* MSC SCCP disconnect indication */ + GSCON_EV_A_DISC_IND, + /* MSC sends Handover Request (in CR) */ + GSCON_EV_A_HO_REQ, + + /* RR ASSIGNMENT COMPLETE received */ + GSCON_EV_RR_ASS_COMPL, + /* RR ASSIGNMENT FAIL received */ + GSCON_EV_RR_ASS_FAIL, + /* RR MODE MODIFY ACK received */ + GSCON_EV_RR_MODE_MODIFY_ACK, + /* RR HO ACC (access burst on ext HO) */ + GSCON_EV_RR_HO_ACC, + /* RR HANDOVER COMPLETE received */ + GSCON_EV_RR_HO_COMPL, + /* RSL RLL Release Indication */ + GSCON_EV_RLL_REL_IND, + /* RSL CONNection FAILure Indication */ + GSCON_EV_RSL_CONN_FAIL, + + /* RSL/lchan tells us clearing is complete */ + GSCON_EV_RSL_CLEAR_COMPL, + + /* Mobile-originated DTAP (from MS) */ + GSCON_EV_MO_DTAP, + /* Mobile-terminated DTAP (from MSC) */ + GSCON_EV_MT_DTAP, +}; + +struct gsm_subscriber_connection; +struct gsm_network; + +/* Allocate a subscriber connection and its associated FSM */ +struct gsm_subscriber_connection *bsc_subscr_con_allocate(struct gsm_network *net); diff --git a/include/osmocom/bsc/gsm_data.h b/include/osmocom/bsc/gsm_data.h index 8692469b4..0aba3746a 100644 --- a/include/osmocom/bsc/gsm_data.h +++ b/include/osmocom/bsc/gsm_data.h @@ -13,6 +13,7 @@ #include #include #include +#include #include @@ -93,6 +94,9 @@ struct gsm_subscriber_connection { /* global linked list of subscriber_connections */ struct llist_head entry; + /* Finite State Machine */ + struct osmo_fsm_inst *fi; + /* libbsc subscriber information (if available) */ struct bsc_subscr *bsub; @@ -1359,8 +1363,7 @@ void gprs_ra_id_by_bts(struct gprs_ra_id *raid, struct gsm_bts *bts); int gsm_btsmodel_set_feature(struct gsm_bts_model *model, enum gsm_bts_features feat); int gsm_bts_model_register(struct gsm_bts_model *model); -struct gsm_subscriber_connection *bsc_subscr_con_allocate(struct gsm_lchan *lchan); -void bsc_subscr_con_free(struct gsm_subscriber_connection *conn); +struct gsm_subscriber_connection *bsc_subscr_con_allocate(struct gsm_network *network); struct gsm_subscriber_connection *msc_subscr_con_allocate(struct gsm_network *network); void msc_subscr_con_free(struct gsm_subscriber_connection *conn); diff --git a/include/osmocom/bsc/osmo_bsc_sigtran.h b/include/osmocom/bsc/osmo_bsc_sigtran.h index 5cb723066..80d4f5b8b 100644 --- a/include/osmocom/bsc/osmo_bsc_sigtran.h +++ b/include/osmocom/bsc/osmo_bsc_sigtran.h @@ -33,11 +33,6 @@ int osmo_bsc_sigtran_open_conn(struct gsm_subscriber_connection *conn, struct ms /* Send data to MSC */ int osmo_bsc_sigtran_send(struct gsm_subscriber_connection *conn, struct msgb *msg); -/* Delete a connection from the list with open connections - * (called by osmo_bsc_api.c on failing open connections and - * locally, when a connection is closed by the MSC */ -int osmo_bsc_sigtran_del_conn(struct gsm_subscriber_connection *sccp); - /* Initalize osmo sigtran backhaul */ int osmo_bsc_sigtran_init(struct llist_head *mscs); diff --git a/src/ipaccess/Makefile.am b/src/ipaccess/Makefile.am index a6195b9c7..9b2a83e31 100644 --- a/src/ipaccess/Makefile.am +++ b/src/ipaccess/Makefile.am @@ -24,7 +24,6 @@ OSMO_LIBS = \ bin_PROGRAMS = \ abisip-find \ - ipaccess-config \ ipaccess-proxy \ $(NULL) diff --git a/src/libbsc/abis_rsl.c b/src/libbsc/abis_rsl.c index 7400f896e..eba428175 100644 --- a/src/libbsc/abis_rsl.c +++ b/src/libbsc/abis_rsl.c @@ -45,6 +45,7 @@ #include #include #include +#include #define RSL_ALLOC_SIZE 1024 #define RSL_ALLOC_HEADROOM 128 @@ -1357,21 +1358,28 @@ static int rsl_rx_chan_act_nack(struct msgb *msg) static int rsl_rx_conn_fail(struct msgb *msg) { struct abis_rsl_dchan_hdr *dh = msgb_l2(msg); + struct gsm_lchan *lchan = msg->lchan; struct tlv_parsed tp; + uint8_t cause = 0; - LOGP(DRSL, LOGL_NOTICE, "%s CONNECTION FAIL: RELEASING state %s ", + LOGP(DRSL, LOGL_NOTICE, "%s CONNECTION FAIL in state %s ", gsm_lchan_name(msg->lchan), gsm_lchans_name(msg->lchan->state)); rsl_tlv_parse(&tp, dh->data, msgb_l2len(msg)-sizeof(*dh)); - if (TLVP_PRESENT(&tp, RSL_IE_CAUSE)) + if (TLVP_PRESENT(&tp, RSL_IE_CAUSE)) { print_rsl_cause(LOGL_NOTICE, TLVP_VAL(&tp, RSL_IE_CAUSE), TLVP_LEN(&tp, RSL_IE_CAUSE)); + cause = *TLVP_VAL(&tp, RSL_IE_CAUSE); + } LOGPC(DRSL, LOGL_NOTICE, "\n"); - rate_ctr_inc(&msg->lchan->ts->trx->bts->bts_ctrs->ctr[BTS_CTR_CHAN_RF_FAIL]); - return rsl_rf_chan_release_err(msg->lchan); + rate_ctr_inc(&lchan->ts->trx->bts->bts_ctrs->ctr[BTS_CTR_CHAN_RF_FAIL]); + + osmo_fsm_inst_dispatch(lchan->conn->fi, GSCON_EV_RSL_CONN_FAIL, &cause); + + return 0; } static void print_meas_rep_uni(struct gsm_meas_rep_unidir *mru, diff --git a/src/libbsc/bsc_api.c b/src/libbsc/bsc_api.c index d792b5899..3c812d183 100644 --- a/src/libbsc/bsc_api.c +++ b/src/libbsc/bsc_api.c @@ -2,7 +2,7 @@ /* (C) 2010-2011 by Holger Hans Peter Freyther * (C) 2010-2011 by On-Waves - * (C) 2009 by Harald Welte + * (C) 2009,2017 by Harald Welte * * All Rights Reserved * @@ -51,7 +51,7 @@ static void handle_chan_ack(struct gsm_subscriber_connection *conn, struct bsc_a static void handle_chan_nack(struct gsm_subscriber_connection *conn, struct bsc_api *bsc, struct gsm_lchan *lchan); /* GSM 08.08 3.2.2.33 */ -static uint8_t lchan_to_chosen_channel(struct gsm_lchan *lchan) +uint8_t lchan_to_chosen_channel(struct gsm_lchan *lchan) { uint8_t channel_mode = 0, channel = 0; @@ -100,7 +100,7 @@ static uint8_t lchan_to_chosen_channel(struct gsm_lchan *lchan) return channel_mode << 4 | channel; } -static uint8_t chan_mode_to_speech(struct gsm_lchan *lchan) +uint8_t chan_mode_to_speech(struct gsm_lchan *lchan) { int mode = 0; @@ -133,27 +133,6 @@ static uint8_t chan_mode_to_speech(struct gsm_lchan *lchan) return mode; } -static void assignment_t10_timeout(void *_conn) -{ - struct bsc_api *api; - struct gsm_subscriber_connection *conn = - (struct gsm_subscriber_connection *) _conn; - - LOGP(DMSC, LOGL_ERROR, "Assignment T10 timeout on %p\n", conn); - - /* - * normal release on the secondary channel but only if the - * secondary_channel has not been released by the handle_chan_nack. - */ - if (conn->secondary_lchan) - lchan_release(conn->secondary_lchan, 0, RSL_REL_LOCAL_END); - conn->secondary_lchan = NULL; - - /* inform them about the failure */ - api = conn->network->bsc_api; - api->assign_fail(conn, GSM0808_CAUSE_NO_RADIO_RESOURCE_AVAILABLE, NULL); -} - /*! \brief Determine and apply AMR multi-rate configuration to lchan * Determine which AMR multi-rate configuration to use and apply it to * the lchan (so it can be communicated to BTS and MS during channel @@ -265,24 +244,6 @@ static int handle_new_assignment(struct gsm_subscriber_connection *conn, int cha return 0; } -struct gsm_subscriber_connection *bsc_subscr_con_allocate(struct gsm_lchan *lchan) -{ - struct gsm_subscriber_connection *conn; - struct gsm_network *net = lchan->ts->trx->bts->network; - - conn = talloc_zero(net, struct gsm_subscriber_connection); - if (!conn) - return NULL; - - conn->network = net; - conn->lchan = lchan; - lchan->conn = conn; - INIT_LLIST_HEAD(&conn->ho_dtap_cache); - conn->sccp.conn_id = -1; - llist_add_tail(&conn->entry, &net->subscr_conns); - return conn; -} - static void ho_dtap_cache_add(struct gsm_subscriber_connection *conn, struct msgb *msg, int link_id, bool allow_sacch) { @@ -301,7 +262,7 @@ static void ho_dtap_cache_add(struct gsm_subscriber_connection *conn, struct msg msgb_enqueue(&conn->ho_dtap_cache, msg); } -static void ho_dtap_cache_flush(struct gsm_subscriber_connection *conn, int send) +void ho_dtap_cache_flush(struct gsm_subscriber_connection *conn, int send) { struct msgb *msg; unsigned int flushed_count = 0; @@ -326,38 +287,6 @@ static void ho_dtap_cache_flush(struct gsm_subscriber_connection *conn, int send } } -void bsc_subscr_con_free(struct gsm_subscriber_connection *conn) -{ - if (!conn) - return; - - if (conn->network->bsc_api->conn_cleanup) - conn->network->bsc_api->conn_cleanup(conn); - - if (conn->ho_lchan) { - LOGP(DNM, LOGL_ERROR, "The ho_lchan should have been cleared.\n"); - conn->ho_lchan->conn = NULL; - } - - if (conn->lchan) { - LOGP(DNM, LOGL_ERROR, "The lchan should have been cleared.\n"); - conn->lchan->conn = NULL; - } - - if (conn->secondary_lchan) { - LOGP(DNM, LOGL_ERROR, "The secondary_lchan should have been cleared.\n"); - conn->secondary_lchan->conn = NULL; - } - - /* drop pending messages */ - ho_dtap_cache_flush(conn, 0); - - penalty_timers_free(&conn->hodec2.penalty_timers); - - llist_del(&conn->entry); - talloc_free(conn); -} - int bsc_api_init(struct gsm_network *network, struct bsc_api *api) { network->bsc_api = api; @@ -478,9 +407,7 @@ int gsm0808_assign_req(struct gsm_subscriber_connection *conn, int chan_mode, in gsm48_lchan_modify(conn->lchan, chan_mode); } - /* we will now start the timer to complete the assignment */ - osmo_timer_setup(&conn->T10, assignment_t10_timeout, conn); - osmo_timer_schedule(&conn->T10, GSM0808_T10_VALUE); + /* we expect the caller will manage T10 */ return 0; error: @@ -796,19 +723,18 @@ int gsm0408_rcvmsg(struct msgb *msg, uint8_t link_id) } else { /* allocate a new connection */ rc = BSC_API_CONN_POL_REJECT; - lchan->conn = bsc_subscr_con_allocate(msg->lchan); + lchan->conn = bsc_subscr_con_allocate(msg->lchan->ts->trx->bts->network); if (!lchan->conn) { lchan_release(lchan, 1, RSL_REL_NORMAL); return -1; } + lchan->conn->lchan = lchan; /* fwd via bsc_api to send COMPLETE L3 INFO to MSC */ rc = api->compl_l3(lchan->conn, msg, 0); if (rc != BSC_API_CONN_POL_ACCEPT) { - lchan->conn->lchan = NULL; - bsc_subscr_con_free(lchan->conn); - lchan_release(lchan, 1, RSL_REL_NORMAL); + //osmo_fsm_inst_dispatch(lchan->conn->fi, FIXME, NULL); } } @@ -964,11 +890,6 @@ static void handle_release(struct gsm_subscriber_connection *conn, conn->ho_lchan = NULL; } lchan->conn = NULL; - - gsm0808_clear(conn); - - if (destruct) - bsc_subscr_con_free(conn); } static void handle_chan_ack(struct gsm_subscriber_connection *conn, diff --git a/src/osmo-bsc/Makefile.am b/src/osmo-bsc/Makefile.am index 3019470d3..37fa3bafa 100644 --- a/src/osmo-bsc/Makefile.am +++ b/src/osmo-bsc/Makefile.am @@ -26,6 +26,7 @@ bin_PROGRAMS = \ $(NULL) osmo_bsc_SOURCES = \ + bsc_subscr_conn_fsm.c \ osmo_bsc_main.c \ osmo_bsc_vty.c \ osmo_bsc_api.c \ diff --git a/src/osmo-bsc/bsc_subscr_conn_fsm.c b/src/osmo-bsc/bsc_subscr_conn_fsm.c new file mode 100644 index 000000000..d12cd1321 --- /dev/null +++ b/src/osmo-bsc/bsc_subscr_conn_fsm.c @@ -0,0 +1,485 @@ +/* (C) 2017 by Harald Welte + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +#include +#include +#include +#include +//#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#define S(x) (1 << (x)) + +#define GSM0808_T10_VALUE 6 + +enum gscon_fsm_states { + ST_INIT, + /* waiting for CC from MSC */ + ST_WAIT_CC, + /* active connection */ + ST_ACTIVE, + /* during assignment; waiting for ASS_CMPL */ + ST_WAIT_ASS_CMPL, + /* during assignment; waiting for MODE_MODIFY_ACK */ + ST_WAIT_MODE_MODIFY_ACK, + + /* BSSMAP CLEAR has bene received */ + ST_CLEARING, + +/* MT (inbound) handover */ + /* Wait for Handover Access from MS/BTS */ + ST_WAIT_MT_HO_ACC, + /* Wait for RR Handover Complete from MS/BTS */ + ST_WAIT_MT_HO_COMPL, + +/* MO (outbound) handover */ + /* Wait for Handover Command / Handover Required Reject from MSC */ + ST_WAIT_MO_HO_CMD, + /* Wait for Clear Command from MSC */ + ST_MO_HO_PROCEEDING, +}; + +static const struct value_string gscon_fsm_event_names[] = { + { GSCON_EV_A_CONN_IND, "MT-CONNECT.ind" }, + { GSCON_EV_A_CONN_REQ, "MO-CONNECT.req" }, + { GSCON_EV_A_CONN_CFM, "MO-CONNET.cfm" }, + { GSCON_EV_A_ASSIGNMENT_CMD, "ASSIGNMENT_CMD" }, + { GSCON_EV_A_CLEAR_CMD, "CLEAR_CMD" }, + { GSCON_EV_A_DISC_IND, "DISCONNET.ind" }, + { GSCON_EV_A_HO_REQ, "HANDOVER_REQUEST" }, + + { GSCON_EV_RR_ASS_COMPL, "RR_ASSIGN_COMPL" }, + { GSCON_EV_RR_ASS_FAIL, "RR_ASSIGN_FAIL" }, + { GSCON_EV_RR_MODE_MODIFY_ACK, "RR_MODE_MODIFY_ACK" }, + { GSCON_EV_RR_HO_ACC, "RR_HO_ACCESS" }, + { GSCON_EV_RR_HO_COMPL, "RR_HO_COMPLETE" }, + { GSCON_EV_RLL_REL_IND, "RLL_RELEASE.ind" }, + { GSCON_EV_RSL_CONN_FAIL, "RSL_CONN_FAIL.ind" }, + { GSCON_EV_RSL_CLEAR_COMPL, "RSL_CLEAR_COMPLETE" }, + + { GSCON_EV_MO_DTAP, "MO-DTAP" }, + { GSCON_EV_MT_DTAP, "MT-DTAP" }, + { 0, NULL } +}; + +static void gscon_fsm_init(struct osmo_fsm_inst *fi, uint32_t event, void *data) +{ + struct gsm_subscriber_connection *conn = fi->priv; + struct osmo_scu_prim *scu_prim = NULL; + struct msgb *msg = NULL; + int rc; + + switch (event) { + case GSCON_EV_A_CONN_REQ: + /* RLL ESTABLISH IND with initial L3 Message */ + msg = data; + /* FIXME: Extract Mobile ID and update FSM using osmo_fsm_inst_set_id() */ + rc = osmo_bsc_sigtran_open_conn(conn, msg); + if (rc < 0) { + osmo_fsm_inst_term(fi, OSMO_FSM_TERM_ERROR, NULL); + } else + osmo_fsm_inst_state_chg(fi, ST_WAIT_CC, 0, 0); + break; + case GSCON_EV_A_CONN_IND: + scu_prim = data; + if (!conn->sccp.msc) { + LOGPFSML(fi, LOGL_NOTICE, "N-CONNET.ind from unknown MSC %s", + osmo_sccp_addr_dump(&scu_prim->u.connect.calling_addr)); + osmo_sccp_tx_disconn(conn->sccp.msc->a.sccp_user, scu_prim->u.connect.conn_id, + &scu_prim->u.connect.called_addr, 0); + osmo_fsm_inst_term(fi, OSMO_FSM_TERM_REGULAR, NULL); + } + /* FIXME: Extract optional IMSI and update FSM using osmo_fsm_inst_set_id() */ + LOGPFSML(fi, LOGL_NOTICE, "No support for MSC-originated SCCP Connections yet\n"); + osmo_sccp_tx_disconn(conn->sccp.msc->a.sccp_user, scu_prim->u.connect.conn_id, + &scu_prim->u.connect.called_addr, 0); + osmo_fsm_inst_term(fi, OSMO_FSM_TERM_REGULAR, NULL); + break; + default: + OSMO_ASSERT(0); + break; + } +} + +/* We've sent the CONNECTION.req to the SCCP provider and are waiting for CC from MSC */ +static void gscon_fsm_wait_cc(struct osmo_fsm_inst *fi, uint32_t event, void *data) +{ + struct gsm_subscriber_connection *conn = fi->priv; + + switch (event) { + case GSCON_EV_A_CONN_CFM: + /* MSC has confirmed the connection */ + osmo_fsm_inst_state_chg(fi, ST_ACTIVE, 0, 0); + /* if there's user payload, forward it just like EV_MT_DTAP */ + break; + default: + OSMO_ASSERT(0); + break; + } +} + +/* We're on an active subscriber connection, passing DTAP back and forth */ +static void gscon_fsm_active(struct osmo_fsm_inst *fi, uint32_t event, void *data) +{ + struct gsm_subscriber_connection *conn = fi->priv; + uint32_t *param = NULL; + struct msgb *msg = NULL; + struct msgb *resp = NULL; + int chan_mode, full_rate; + int rc; + + switch (event) { + case GSCON_EV_A_ASSIGNMENT_CMD: + /* MSC requests us to perform assignment. We need to check if current channel is + * sufficient. If yes, do MODIFY. If not, do assignment */ + param = data; + full_rate = *param >> 16; + chan_mode = *param & 0xffff; + LOGPFSM(fi, "ASSIGNMENT_CMD(full_rate=%d, chan_mode=%d)\n", full_rate, chan_mode); +#if 1 + rc = gsm0808_assign_req(conn, chan_mode, full_rate); + osmo_fsm_inst_state_chg(fi, ST_WAIT_ASS_CMPL, GSM0808_T10_VALUE, 10); +#else + if (chan_compat_with_mode(conn->lchan, chan_mode, full_rate)) { + rc = gsm48_lchan_modify(conn->lchan, chan_mode); + osmo_fsm_inst_state_chg(fi, ST_WAIT_MODE_MODIFY_ACK, GSM0808_T10_VALUE, 10); + } else { + if (handle_new_assignment(conn, chan_mode, full_rate)) { + osmo_fsm_inst_state_chg(fi, ST_WAIT_ASS_CMPL, GSM0808_T10_VALUE, 10); + } else { + /* FIXME: tx assignment failure */ + } + } +#endif + break; + case GSCON_EV_MO_DTAP: + /* forward MO DTAP from RSL side to BSSAP side */ + msg = data; + resp = gsm0808_create_dtap(msg, OBSC_LINKID_CB(msg)); + osmo_bsc_sigtran_send(conn, resp); + break; + case GSCON_EV_MT_DTAP: + /* forward MT DTAP from BSSAP side to RSL side */ + msg = data; + rc = gsm0808_submit_dtap(conn, msg, OBSC_LINKID_CB(msg), 1); + break; + case GSCON_EV_A_HO_REQ: + /* FIXME: reject any handover requests with HO FAIL until implemented */ + break; + default: + OSMO_ASSERT(0); + break; + } +} + +/* We're waiting for an ASSIGNMENT COMPLETE from MS */ +static void gscon_fsm_wait_ass_cmpl(struct osmo_fsm_inst *fi, uint32_t event, void *data) +{ + struct gsm_subscriber_connection *conn = fi->priv; + struct gsm_lchan *lchan = conn->lchan; + struct msgb *resp = NULL; + + switch (event) { + case GSCON_EV_RR_ASS_COMPL: + resp = gsm0808_create_assignment_completed(0, lchan_to_chosen_channel(lchan), + lchan->encr.alg_id, chan_mode_to_speech(lchan)); + osmo_bsc_sigtran_send(conn, resp); + osmo_fsm_inst_state_chg(fi, ST_ACTIVE, 0, 0); + break; + case GSCON_EV_RR_ASS_FAIL: + /* FIXME: Nobody generates this yet? */ + resp = gsm0808_create_assignment_failure(GSM0808_CAUSE_RADIO_INTERFACE_MESSAGE_FAILURE, + data); + osmo_bsc_sigtran_send(conn, resp); + osmo_fsm_inst_state_chg(fi, ST_ACTIVE, 0, 0); + break; + default: + OSMO_ASSERT(0); + break; + } +} + +/* We're waiting for a MODE MODIFY ACK from MS + BTS */ +static void gscon_fsm_wait_mode_modify_ack(struct osmo_fsm_inst *fi, uint32_t event, void *data) +{ + struct gsm_subscriber_connection *conn = fi->priv; + struct gsm_lchan *lchan = conn->lchan; + struct msgb *resp; + + switch (event) { + case GSCON_EV_RR_MODE_MODIFY_ACK: + /* we assume that not only have we received the RR MODE_MODIFY_ACK, but + * actually that also the BTS side of the channel mode has been changed accordingly */ + osmo_fsm_inst_state_chg(fi, ST_ACTIVE, 0, 0); + resp = gsm0808_create_assignment_completed(0, lchan_to_chosen_channel(lchan), + lchan->encr.alg_id, chan_mode_to_speech(lchan)); + osmo_bsc_sigtran_send(conn, resp); + break; + default: + OSMO_ASSERT(0); + break; + } +} + +static void gscon_fsm_clearing(struct osmo_fsm_inst *fi, uint32_t event, void *data) +{ + struct gsm_subscriber_connection *conn = fi->priv; + struct msgb *resp; + + switch (event) { + case GSCON_EV_RSL_CLEAR_COMPL: + /* FIXME: clear any MGCP context */ + resp = gsm0808_create_clear_complete(); + osmo_bsc_sigtran_send(conn, resp); + break; + default: + OSMO_ASSERT(0); + break; + } +} + +static const struct osmo_fsm_state gscon_fsm_states[] = { + [ST_INIT] = { + .in_event_mask = S(GSCON_EV_A_CONN_REQ) | + S(GSCON_EV_A_CONN_IND), + .out_state_mask = S(ST_WAIT_CC), + .name = "INIT", + .action = gscon_fsm_init, + }, + [ST_WAIT_CC] = { + .in_event_mask = S(GSCON_EV_A_CONN_CFM), + .out_state_mask = S(ST_ACTIVE), + .name = "WAIT_CC", + .action = gscon_fsm_wait_cc, + }, + [ST_ACTIVE] = { + .in_event_mask = S(GSCON_EV_A_ASSIGNMENT_CMD) | + S(GSCON_EV_A_HO_REQ) | + S(GSCON_EV_MO_DTAP) | + S(GSCON_EV_MT_DTAP), + .out_state_mask = S(ST_WAIT_ASS_CMPL) | + S(ST_WAIT_MODE_MODIFY_ACK) | + S(ST_CLEARING) | + S(ST_WAIT_MO_HO_CMD) | + S(ST_CLEARING), + .name = "ACTIVE", + .action = gscon_fsm_active, + }, + [ST_WAIT_ASS_CMPL] = { + .in_event_mask = S(GSCON_EV_RR_ASS_COMPL) | + S(GSCON_EV_RR_ASS_FAIL) | + S(GSCON_EV_MO_DTAP) | + S(GSCON_EV_MT_DTAP), + .out_state_mask = S(ST_ACTIVE) | + S(ST_CLEARING), + .name = "WAIT_ASS_CMPL", + .action = gscon_fsm_wait_ass_cmpl, + }, + [ST_WAIT_MODE_MODIFY_ACK] = { + .in_event_mask = S(GSCON_EV_RR_MODE_MODIFY_ACK) | + S(GSCON_EV_MO_DTAP) | + S(GSCON_EV_MT_DTAP), + .out_state_mask = S(ST_ACTIVE) | + S(ST_CLEARING), + .name = "WAIT_MODE_MODIFY_ACK", + .action = gscon_fsm_wait_mode_modify_ack, + }, + [ST_CLEARING] = { + .in_event_mask = S(GSCON_EV_RSL_CLEAR_COMPL), + .name = "CLEARING", + .action = gscon_fsm_clearing, + }, + /* TODO: external handover */ + [ST_WAIT_MT_HO_ACC] = { + .name = "WAIT_MT_HO_ACC", + }, + [ST_WAIT_MT_HO_COMPL] = { + .name = "WAIT_MT_HO_CMPL", + }, + [ST_WAIT_MO_HO_CMD] = { + .name = "WAIT_MO_HO_CMD", + }, + [ST_MO_HO_PROCEEDING] = { + .name = "WAIT_MO_HO_PROCEEDING", + }, +}; + + +static void gscon_fsm_allstate(struct osmo_fsm_inst *fi, uint32_t event, void *data) +{ + struct gsm_subscriber_connection *conn = fi->priv; + struct msgb *resp = NULL; + + switch (event) { + case GSCON_EV_A_CLEAR_CMD: + /* MSC tells us to cleanly shut down */ + osmo_fsm_inst_state_chg(fi, ST_CLEARING, 0, 0); + gsm0808_clear(conn); + /* FIXME: Release all terestrial resources in ST_CLEARING */ + /* According to 3GPP 48.008 3.1.9.1. "The BSS need not wait for the radio channel + * release to be completed or for the guard timer to expire before returning the + * CLEAR COMPLETE message" */ + osmo_fsm_inst_dispatch(conn->fi, GSCON_EV_RSL_CLEAR_COMPL, NULL); + break; + case GSCON_EV_A_DISC_IND: + /* MSC or SIGTRAN network has hard-released SCCP connection */ + /* hard-release the lchan */ + /* hard-release any MGCP state */ + break; + case GSCON_EV_RLL_REL_IND: + /* BTS reports that one of the LAPDm data links was released */ + /* send proper clear request to MSC */ + break; + case GSCON_EV_RSL_CONN_FAIL: + LOGPFSM(fi, "Tx BSSMAP CLEAR REQUEST to MSC"); + resp = gsm0808_create_clear_rqst(GSM0808_CAUSE_RADIO_INTERFACE_FAILURE); + osmo_bsc_sigtran_send(conn, resp); + break; + default: + OSMO_ASSERT(0); + break; + } +} + +void ho_dtap_cache_flush(struct gsm_subscriber_connection *conn, int send); + +static void gscon_cleanup(struct osmo_fsm_inst *fi, enum osmo_fsm_term_cause cause) +{ + struct gsm_subscriber_connection *conn = fi->priv; + + /* FIXME: merge with gsm0808_clear() */ + + if (conn->ho_lchan) { + LOGPFSML(fi, LOGL_DEBUG, "Releasing ho_lchan\n"); + bsc_clear_handover(conn, 1); + conn->ho_lchan = NULL; + } + + if (conn->secondary_lchan) { + LOGPFSML(fi, LOGL_DEBUG, "Releasing secondary_lchan\n"); + lchan_release(conn->secondary_lchan, 0, RSL_REL_LOCAL_END); + conn->secondary_lchan = NULL; + } + if (conn->lchan) { + LOGPFSML(fi, LOGL_DEBUG, "Releasing lchan\n"); + lchan_release(conn->lchan, 0, RSL_REL_LOCAL_END); + conn->lchan = NULL; + } + + if (conn->bsub) { + LOGPFSML(fi, LOGL_DEBUG, "Putting bsc_subscr\n"); + bsc_subscr_put(conn->bsub); + conn->bsub = NULL; + } + + if (conn->user_plane.mgcp_ctx) { + /* FIXME: MGCP side of things */ + //mgcp_clear_complete(conn->user_plane.mgcp_ctx, NULL); + } + + if (conn->sccp.state != SUBSCR_SCCP_ST_NONE) { + LOGPFSML(fi, LOGL_DEBUG, "Disconnecting SCCP\n"); + struct bsc_msc_data *msc = conn->sccp.msc; + /* FIXME: include a proper cause value / error message? */ + osmo_sccp_tx_disconn(msc->a.sccp_user, conn->sccp.conn_id, &msc->a.bsc_addr, 0); + conn->sccp.state = SUBSCR_SCCP_ST_NONE; + } + + /* drop pending messages */ + ho_dtap_cache_flush(conn, 0); + + penalty_timers_free(&conn->hodec2.penalty_timers); + + llist_del(&conn->entry); + talloc_free(conn); + fi->priv = NULL; +} + +static int gscon_timer_cb(struct osmo_fsm_inst *fi) +{ + struct gsm_subscriber_connection *conn = fi->priv; + struct bsc_msc_data *msc = conn->sccp.msc; + struct msgb *resp = NULL; + + switch (fi->T) { + case 10: /* Assignment Failed */ + resp = gsm0808_create_assignment_failure(GSM0808_CAUSE_RADIO_INTERFACE_FAILURE, NULL); + osmo_bsc_sigtran_send(conn, resp); + osmo_fsm_inst_state_chg(fi, ST_ACTIVE, 0, 0); + break; + default: + OSMO_ASSERT(0); + } + return 0; +} + +static struct osmo_fsm gscon_fsm = { + .name = "SUBSCR_CONN", + .states = gscon_fsm_states, + .num_states = ARRAY_SIZE(gscon_fsm_states), + .allstate_event_mask = S(GSCON_EV_A_DISC_IND) | + S(GSCON_EV_A_CLEAR_CMD) | + S(GSCON_EV_RSL_CONN_FAIL) | + S(GSCON_EV_RLL_REL_IND), + .allstate_action = gscon_fsm_allstate, + .cleanup = gscon_cleanup, + .timer_cb = gscon_timer_cb, + .log_subsys = DMSC, + .event_names = gscon_fsm_event_names, +}; + + +/* Allocate a subscriber connection and its associated FSM */ +struct gsm_subscriber_connection *bsc_subscr_con_allocate(struct gsm_network *net) +{ + struct gsm_subscriber_connection *conn; + static bool g_initialized = false; + + if (!g_initialized) { + osmo_fsm_register(&gscon_fsm); + g_initialized = true; + } + + conn = talloc_zero(net, struct gsm_subscriber_connection); + if (!conn) + return NULL; + + conn->network = net; + INIT_LLIST_HEAD(&conn->ho_dtap_cache); + /* BTW, penalty timers will be initialized on-demand. */ + conn->sccp.conn_id = -1; + + /* don't allocate from 'conn' context, as gscon_cleanup() will call talloc_free(conn) before + * libosmocore will call talloc_free(conn->fi), i.e. avoid use-after-free during cleanup */ + conn->fi = osmo_fsm_inst_alloc(&gscon_fsm, net, conn, LOGL_NOTICE, NULL); + if (!conn->fi) { + talloc_free(conn); + return NULL; + } + + llist_add_tail(&conn->entry, &net->subscr_conns); + return conn; +} diff --git a/src/osmo-bsc/osmo_bsc_api.c b/src/osmo-bsc/osmo_bsc_api.c index 465832c82..d48398f49 100644 --- a/src/osmo-bsc/osmo_bsc_api.c +++ b/src/osmo-bsc/osmo_bsc_api.c @@ -17,6 +17,7 @@ * */ +#include #include #include #include @@ -295,15 +296,11 @@ static int complete_layer3(struct gsm_subscriber_connection *conn, resp = gsm0808_create_layer3(msg, network_code, country_code, lac, ci); if (!resp) { LOGP(DMSC, LOGL_DEBUG, "Failed to create layer3 message.\n"); - osmo_bsc_sigtran_del_conn(conn); + //osmo_bsc_sigtran_del_conn(conn); return BSC_API_CONN_POL_REJECT; } - if (osmo_bsc_sigtran_open_conn(conn, resp) != 0) { - osmo_bsc_sigtran_del_conn(conn); - msgb_free(resp); - return BSC_API_CONN_POL_REJECT; - } + osmo_fsm_inst_dispatch(conn->fi, GSCON_EV_A_CONN_REQ, resp); return BSC_API_CONN_POL_ACCEPT; } @@ -328,7 +325,7 @@ static int move_to_msc(struct gsm_subscriber_connection *_conn, */ if (complete_layer3(_conn, msg, msc) != BSC_API_CONN_POL_ACCEPT) { gsm0808_clear(_conn); - bsc_subscr_con_free(_conn); + //bsc_subscr_con_free(_conn); return 1; } @@ -397,7 +394,6 @@ static int handle_cc_setup(struct gsm_subscriber_connection *conn, static void bsc_dtap(struct gsm_subscriber_connection *conn, uint8_t link_id, struct msgb *msg) { int lu_cause; - struct msgb *resp; return_when_not_connected(conn); LOGP(DMSC, LOGL_INFO, "Tx MSC DTAP LINK_ID=0x%02x\n", link_id); @@ -420,17 +416,22 @@ static void bsc_dtap(struct gsm_subscriber_connection *conn, uint8_t link_id, st bsc_scan_bts_msg(conn, msg); - resp = gsm0808_create_dtap(msg, link_id); - queue_msg_or_return(resp); + /* Store link_id in msg->cb */ + OBSC_LINKID_CB(msg) = link_id; + osmo_fsm_inst_dispatch(conn->fi, GSCON_EV_MO_DTAP, msg); } static void bsc_assign_compl(struct gsm_subscriber_connection *conn, uint8_t rr_cause, uint8_t chosen_channel, uint8_t encr_alg_id, uint8_t speech_model) { - struct msgb *resp; return_when_not_connected(conn); + conn->lchan->abis_ip.ass_compl.rr_cause = rr_cause; + conn->lchan->abis_ip.ass_compl.chosen_channel = chosen_channel; + conn->lchan->abis_ip.ass_compl.encr_alg_id = encr_alg_id; + conn->lchan->abis_ip.ass_compl.speech_mode = speech_model; + if (is_ipaccess_bts(conn_get_bts(conn)) && conn->user_plane.rtp_ip) { /* NOTE: In a network that makes use of an IPA base station * and AoIP, we have to wait until the BTS reports its RTP @@ -440,18 +441,12 @@ static void bsc_assign_compl(struct gsm_subscriber_connection *conn, uint8_t rr_ * postpone the AoIP assignment completed message until we * know the RTP IP/Port combination. */ LOGP(DMSC, LOGL_INFO, "POSTPONE MSC ASSIGN COMPL\n"); - conn->lchan->abis_ip.ass_compl.rr_cause = rr_cause; - conn->lchan->abis_ip.ass_compl.chosen_channel = chosen_channel; - conn->lchan->abis_ip.ass_compl.encr_alg_id = encr_alg_id; - conn->lchan->abis_ip.ass_compl.speech_mode = speech_model; conn->lchan->abis_ip.ass_compl.valid = true; } else { /* NOTE: Send the A assignment complete message immediately. */ LOGP(DMSC, LOGL_INFO, "Tx MSC ASSIGN COMPL\n"); - resp = gsm0808_create_assignment_completed(rr_cause, chosen_channel, - encr_alg_id, speech_model); - queue_msg_or_return(resp); + osmo_fsm_inst_dispatch(conn->fi, GSCON_EV_RR_ASS_COMPL, NULL); } } diff --git a/src/osmo-bsc/osmo_bsc_bssap.c b/src/osmo-bsc/osmo_bsc_bssap.c index d07cc558e..30f57fa25 100644 --- a/src/osmo-bsc/osmo_bsc_bssap.c +++ b/src/osmo-bsc/osmo_bsc_bssap.c @@ -1,6 +1,7 @@ /* GSM 08.08 BSSMAP handling */ /* (C) 2009-2012 by Holger Hans Peter Freyther * (C) 2009-2012 by On-Waves + * (C) 2017 by Harald Welte * All Rights Reserved * * This program is free software; you can redistribute it and/or modify @@ -27,6 +28,7 @@ #include #include #include +#include #include #include @@ -582,45 +584,6 @@ static int select_best_cipher(uint8_t msc_mask, uint8_t bsc_mask) return -1; } -/* - * GSM 08.08 § 3.1.9.1 and 3.2.1.21... - * release our gsm_subscriber_connection and send message - */ -static int bssmap_handle_clear_command(struct gsm_subscriber_connection *conn, - struct msgb *msg, unsigned int payload_length) -{ - struct msgb *resp; - - /* TODO: handle the cause of this package */ - - LOGP(DMSC, LOGL_INFO, "Releasing all transactions on %p\n", conn); - gsm0808_clear(conn); - - /* generate the clear complete message */ - resp = gsm0808_create_clear_complete(); - if (!resp) { - LOGP(DMSC, LOGL_ERROR, "Sending clear complete failed.\n"); - return -1; - } - - if (conn->user_plane.mgcp_ctx) { - /* NOTE: This is the AoIP case, osmo-bsc has to negotiate with - * the MGCP-GW. For this an mgcp_ctx should be created that - * contains the FSM and some system data. When the connection - * is removed from the MGCP-GW, then osmo_bsc_sigtran_send() - * calls osmo_bsc_sigtran_send(). */ - mgcp_clear_complete(conn->user_plane.mgcp_ctx, resp); - } else { - /* NOTE: This is the SCCP-Lite case, since we do not handle - * the MGCP-GW switching ourselves, we may skip everything - * that is MGCP-GW related and sent the clear complete message - * directly */ - osmo_bsc_sigtran_send(conn, resp); - } - - return 0; -} - /* * GSM 08.08 § 3.4.7 cipher mode handling. We will have to pick * the cipher to be used for this. In case we are already using @@ -886,7 +849,8 @@ static int bssmap_handle_assignm_req(struct gsm_subscriber_connection *conn, * to sccp-lite. */ conn->user_plane.rtp_port = mgcp_timeslot_to_port(multiplex, timeslot, msc->rtp_base); conn->user_plane.rtp_ip = 0; - return gsm0808_assign_req(conn, chan_mode, full_rate); + uint32_t param = (full_rate << 16 | chan_mode); + return osmo_fsm_inst_dispatch(conn->fi, GSCON_EV_A_ASSIGNMENT_CMD, ¶m); } reject: @@ -944,7 +908,7 @@ static int bssmap_rcvmsg_dt1(struct gsm_subscriber_connection *conn, switch (msg->l4h[0]) { case BSS_MAP_MSG_CLEAR_CMD: - ret = bssmap_handle_clear_command(conn, msg, length); + osmo_fsm_inst_dispatch(conn->fi, GSCON_EV_A_CLEAR_CMD, msg); break; case BSS_MAP_MSG_CIPHER_MODE_CMD: ret = bssmap_handle_cipher_mode(conn, msg, length); @@ -1005,7 +969,9 @@ static int dtap_rcvmsg(struct gsm_subscriber_connection *conn, /* pass it to the filter for extra actions */ rc = bsc_scan_msc_msg(conn, gsm48); - dtap_rc = gsm0808_submit_dtap(conn, gsm48, header->link_id, 1); + /* Store link_id in msgb->cb */ + OBSC_LINKID_CB(msg) = header->link_id; + dtap_rc = osmo_fsm_inst_dispatch(conn->fi, GSCON_EV_MT_DTAP, gsm48); if (rc == BSS_SEND_USSD) bsc_send_welcome_ussd(conn); return dtap_rc; diff --git a/src/osmo-bsc/osmo_bsc_mgcp.c b/src/osmo-bsc/osmo_bsc_mgcp.c index 4b6420e9b..db649c791 100644 --- a/src/osmo-bsc/osmo_bsc_mgcp.c +++ b/src/osmo-bsc/osmo_bsc_mgcp.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -278,12 +279,8 @@ static void fsm_proc_assignmnent_req_cb(struct osmo_fsm_inst *fi, uint32_t event full_rate = mgcp_ctx->full_rate; LOGPFSML(fi, LOGL_DEBUG, "MGW proceeding assignment request...\n"); - rc = gsm0808_assign_req(conn, chan_mode, full_rate); - - if (rc < 0) { - handle_error(mgcp_ctx, MGCP_ERR_ASSGMNT_FAIL); - return; - } + uint32_t param = (full_rate << 16) | chan_mode; + osmo_fsm_inst_dispatch(conn->fi, GSCON_EV_A_ASSIGNMENT_CMD, ¶m); osmo_fsm_inst_state_chg(fi, ST_MDCX_BTS, MGCP_BSS_TIMEOUT, MGCP_BSS_TIMEOUT_TIMER_NR); } diff --git a/src/osmo-bsc/osmo_bsc_sigtran.c b/src/osmo-bsc/osmo_bsc_sigtran.c index ab903b622..5fafe19c3 100644 --- a/src/osmo-bsc/osmo_bsc_sigtran.c +++ b/src/osmo-bsc/osmo_bsc_sigtran.c @@ -1,8 +1,7 @@ -/* (C) 2017 by sysmocom s.f.m.c. GmbH +/* (C) 2017 by sysmocom s.f.m.c. GmbH, Author: Philipp Maier + * (C) 2017 by Harald Welte * All Rights Reserved * - * Author: Philipp Maier - * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation; either version 3 of the License, or @@ -20,6 +19,7 @@ #include #include +#include #include #include #include @@ -33,6 +33,7 @@ #include #include #include +#include /* A pointer to a list with all involved MSCs * (a copy of the pointer location submitted with osmo_bsc_sigtran_init() */ @@ -127,18 +128,10 @@ static struct bsc_msc_data *get_msc_by_addr(const struct osmo_sccp_addr *msc_add } /* Send data to MSC, use the connection id which MSC it is */ -static int handle_data_from_msc(int conn_id, struct msgb *msg) +static int handle_data_from_msc(struct gsm_subscriber_connection *conn, struct msgb *msg) { - struct gsm_subscriber_connection *conn = get_bsc_conn_by_conn_id(conn_id); - int rc = -EINVAL; - - if (conn) { - msg->l3h = msgb_l2(msg); - rc = bsc_handle_dt(conn, msg, msgb_l2len(msg)); - } else - LOGP(DMSC, LOGL_NOTICE, "incoming data from unknown connection id: %i\n", conn_id); - - return rc; + msg->l3h = msgb_l2(msg); + return bsc_handle_dt(conn, msg, msgb_l2len(msg)); } /* Sent unitdata to MSC, use the point code to determine which MSC it is */ @@ -177,23 +170,32 @@ static int sccp_sap_up(struct osmo_prim_hdr *oph, void *_scu) break; case OSMO_PRIM(OSMO_SCU_PRIM_N_CONNECT, PRIM_OP_INDICATION): - /* Handle (Reject) inbound connections */ + /* Handle inbound connections */ DEBUGP(DMSC, "N-CONNECT.ind(X->%u)\n", scu_prim->u.connect.conn_id); - LOGP(DMSC, LOGL_DEBUG, "Rejecting inbound SCCP connection...\n"); - rc = osmo_sccp_tx_disconn(scu, scu_prim->u.connect.conn_id, &scu_prim->u.connect.called_addr, 0); + conn = bsc_subscr_con_allocate(bsc_gsmnet); + if (conn) { + conn->sccp.msc = get_msc_by_addr(&scu_prim->u.connect.calling_addr); + /* MSC may be NULL, let the FSM deal with it */ + osmo_fsm_inst_dispatch(conn->fi, GSCON_EV_A_CONN_IND, scu_prim); + } else + LOGP(DMSC, LOGL_ERROR, "Unable to alloc subscr_conn for inbound N-CONNECT.ind\n"); break; case OSMO_PRIM(OSMO_SCU_PRIM_N_CONNECT, PRIM_OP_CONFIRM): /* Handle outbound connection confirmation */ + DEBUGP(DMSC, "N-CONNECT.cnf(%u, %s)\n", scu_prim->u.connect.conn_id, + osmo_hexdump(msgb_l2(oph->msg), msgb_l2len(oph->msg))); conn = get_bsc_conn_by_conn_id(scu_prim->u.connect.conn_id); - if (conn) + if (conn) { + osmo_fsm_inst_dispatch(conn->fi, GSCON_EV_A_CONN_CFM, scu_prim); conn->sccp.state = SUBSCR_SCCP_ST_CONNECTED; - if (msgb_l2len(oph->msg) > 0) { - DEBUGP(DMSC, "N-CONNECT.cnf(%u, %s)\n", scu_prim->u.connect.conn_id, - osmo_hexdump(msgb_l2(oph->msg), msgb_l2len(oph->msg))); - rc = handle_data_from_msc(scu_prim->u.connect.conn_id, oph->msg); - } else - DEBUGP(DMSC, "N-CONNECT.cnf(%u)\n", scu_prim->u.connect.conn_id); + if (msgb_l2len(oph->msg) > 0) + handle_data_from_msc(conn, oph->msg); + } else { + LOGP(DMSC, LOGL_ERROR, "N-CONNET.cfm(%u, %s) for unknown conn?!?\n", + scu_prim->u.connect.conn_id, osmo_hexdump(msgb_l2(oph->msg), + msgb_l2len(oph->msg))); + } break; case OSMO_PRIM(OSMO_SCU_PRIM_N_DATA, PRIM_OP_INDICATION): @@ -202,28 +204,25 @@ static int sccp_sap_up(struct osmo_prim_hdr *oph, void *_scu) osmo_hexdump(msgb_l2(oph->msg), msgb_l2len(oph->msg))); /* Incoming data is a sign of a vital connection */ - conn = get_bsc_conn_by_conn_id(scu_prim->u.disconnect.conn_id); - if (conn) + conn = get_bsc_conn_by_conn_id(scu_prim->u.data.conn_id); + if (conn) { a_reset_conn_success(conn->sccp.msc->a.reset); - - rc = handle_data_from_msc(scu_prim->u.data.conn_id, oph->msg); + handle_data_from_msc(conn, oph->msg); + } break; case OSMO_PRIM(OSMO_SCU_PRIM_N_DISCONNECT, PRIM_OP_INDICATION): + DEBUGP(DMSC, "N-DISCONNECT.ind(%u, %s, cause=%i)\n", scu_prim->u.disconnect.conn_id, + osmo_hexdump(msgb_l2(oph->msg), msgb_l2len(oph->msg)), + scu_prim->u.disconnect.cause); /* indication of disconnect */ conn = get_bsc_conn_by_conn_id(scu_prim->u.disconnect.conn_id); - if (conn) + if (conn) { conn->sccp.state = SUBSCR_SCCP_ST_NONE; - if (msgb_l2len(oph->msg) > 0) { - DEBUGP(DMSC, "N-DISCONNECT.ind(%u, %s, cause=%i)\n", scu_prim->u.disconnect.conn_id, - osmo_hexdump(msgb_l2(oph->msg), msgb_l2len(oph->msg)), scu_prim->u.disconnect.cause); - handle_data_from_msc(scu_prim->u.disconnect.conn_id, oph->msg); - } else { - DEBUGP(DMSC, "N-DISCONNECT.ind(%u, cause=%i)\n", scu_prim->u.disconnect.conn_id, - scu_prim->u.disconnect.cause); + if (msgb_l2len(oph->msg) > 0) + handle_data_from_msc(conn, oph->msg); + osmo_fsm_inst_dispatch(conn->fi, GSCON_EV_A_DISC_IND, scu_prim); } - if (conn) - rc = osmo_bsc_sigtran_del_conn(conn); break; default: @@ -352,31 +351,6 @@ int osmo_bsc_sigtran_send(struct gsm_subscriber_connection *conn, struct msgb *m return rc; } -/* Delete a connection from the list with open connections - * (called by osmo_bsc_api.c on failing open connections and - * locally, when a connection is closed by the MSC */ -int osmo_bsc_sigtran_del_conn(struct gsm_subscriber_connection *conn) -{ - if (!conn) - return 0; - - LOGP(DMSC, LOGL_ERROR, - "sccp connection (id=%i) not cleared (gsm subscriber connection still active) -- forcefully clearing it now!\n", conn->sccp.conn_id); - - /* This bahaviour might be caused by a bad connection. Maybe we - * will have to go through the reset procedure again */ - a_reset_conn_fail(conn->sccp.msc->a.reset); - - /* Remove mgcp context if existant */ - if (conn->user_plane.mgcp_ctx) - mgcp_free_ctx(conn->user_plane.mgcp_ctx); - - /* free the "conn" and make sure any pending lchans are also free'd */ - bsc_subscr_con_free(conn); - - return 0; -} - /* Send an USSD notification in case we loose the connection to the MSC */ static void bsc_notify_msc_lost(struct gsm_subscriber_connection *conn) { @@ -411,13 +385,9 @@ void osmo_bsc_sigtran_reset(const struct bsc_msc_data *msc) bsc_notify_msc_lost(conn); /* Take down all occopied RF channels */ - gsm0808_clear(conn); - /* Disconnect all Sigtran connections */ - osmo_sccp_tx_disconn(msc->a.sccp_user, conn->sccp.conn_id, &msc->a.bsc_addr, 0); - /* Delete subscriber connection */ - osmo_bsc_sigtran_del_conn(conn); + osmo_fsm_inst_term(conn->fi, OSMO_FSM_TERM_REQUEST, NULL); } } } diff --git a/src/utils/Makefile.am b/src/utils/Makefile.am index 983a3bb04..0c681a560 100644 --- a/src/utils/Makefile.am +++ b/src/utils/Makefile.am @@ -22,7 +22,6 @@ noinst_HEADERS = \ $(NULL) bin_PROGRAMS = \ - bs11_config \ isdnsync \ meas_json \ $(NULL) diff --git a/tests/abis/abis_test.c b/tests/abis/abis_test.c index 6369b0701..f95e40c77 100644 --- a/tests/abis/abis_test.c +++ b/tests/abis/abis_test.c @@ -186,3 +186,7 @@ int main(int argc, char **argv) return EXIT_SUCCESS; } + +struct gsm_subscriber_connection *bsc_subscr_con_allocate(struct gsm_network *net) { + OSMO_ASSERT(0); +} diff --git a/tests/bsc/bsc_test.c b/tests/bsc/bsc_test.c index 541a44caf..744b9e1cb 100644 --- a/tests/bsc/bsc_test.c +++ b/tests/bsc/bsc_test.c @@ -235,3 +235,7 @@ int main(int argc, char **argv) printf("Testing execution completed.\n"); return 0; } + +struct gsm_subscriber_connection *bsc_subscr_con_allocate(struct gsm_network *net) { + OSMO_ASSERT(0); +} diff --git a/tests/bssap/bssap_test.c b/tests/bssap/bssap_test.c index cf60e3871..5601e29a1 100644 --- a/tests/bssap/bssap_test.c +++ b/tests/bssap/bssap_test.c @@ -150,3 +150,7 @@ int main(int argc, char **argv) return 0; } + +struct gsm_subscriber_connection *bsc_subscr_con_allocate(struct gsm_network *net) { + OSMO_ASSERT(0); +} diff --git a/tests/gsm0408/gsm0408_test.c b/tests/gsm0408/gsm0408_test.c index 9f5a5c41f..f5e5fe66a 100644 --- a/tests/gsm0408/gsm0408_test.c +++ b/tests/gsm0408/gsm0408_test.c @@ -862,3 +862,7 @@ int main(int argc, char **argv) return EXIT_SUCCESS; } + +struct gsm_subscriber_connection *bsc_subscr_con_allocate(struct gsm_network *net) { + OSMO_ASSERT(0); +} diff --git a/tests/nanobts_omlattr/nanobts_omlattr_test.c b/tests/nanobts_omlattr/nanobts_omlattr_test.c index 0554f4393..31de5d8d0 100644 --- a/tests/nanobts_omlattr/nanobts_omlattr_test.c +++ b/tests/nanobts_omlattr/nanobts_omlattr_test.c @@ -293,3 +293,7 @@ int bssgp_prim_cb(struct osmo_prim_hdr *oph, void *ctx) { abort(); } + +struct gsm_subscriber_connection *bsc_subscr_con_allocate(struct gsm_network *net) { + OSMO_ASSERT(0); +} -- cgit v1.2.3