aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHarald Welte <laforge@gnumonks.org>2018-01-28 03:04:16 +0100
committerNeels Hofmeyr <neels@hofmeyr.de>2018-03-05 22:04:39 +0100
commit4b159cb6f39e7f0516b191575f4420819de3606e (patch)
tree4ed86ace1469310536ca5a503fb1f70e6efb3e7e
parent5eaaf6120e21b5fa4a42fbe4653309db66a574c7 (diff)
WIP: introduce an osmo_fsm for gsm_subscriber_connection
-rw-r--r--include/osmocom/bsc/Makefile.am1
-rw-r--r--include/osmocom/bsc/bsc_api.h3
-rw-r--r--include/osmocom/bsc/bsc_subscr_conn_fsm.h48
-rw-r--r--include/osmocom/bsc/gsm_data.h7
-rw-r--r--include/osmocom/bsc/osmo_bsc_sigtran.h5
-rw-r--r--src/ipaccess/Makefile.am1
-rw-r--r--src/libbsc/abis_rsl.c16
-rw-r--r--src/libbsc/bsc_api.c95
-rw-r--r--src/osmo-bsc/Makefile.am1
-rw-r--r--src/osmo-bsc/bsc_subscr_conn_fsm.c485
-rw-r--r--src/osmo-bsc/osmo_bsc_api.c31
-rw-r--r--src/osmo-bsc/osmo_bsc_bssap.c50
-rw-r--r--src/osmo-bsc/osmo_bsc_mgcp.c9
-rw-r--r--src/osmo-bsc/osmo_bsc_sigtran.c106
-rw-r--r--src/utils/Makefile.am1
-rw-r--r--tests/abis/abis_test.c4
-rw-r--r--tests/bsc/bsc_test.c4
-rw-r--r--tests/bssap/bssap_test.c4
-rw-r--r--tests/gsm0408/gsm0408_test.c4
-rw-r--r--tests/nanobts_omlattr/nanobts_omlattr_test.c4
20 files changed, 645 insertions, 234 deletions
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 <osmocom/core/fsm.h>
+
+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 <osmocom/core/stats.h>
#include <osmocom/core/stat_item.h>
#include <osmocom/gsm/protocol/gsm_08_08.h>
+#include <osmocom/core/fsm.h>
#include <osmocom/crypt/auth.h>
@@ -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 <osmocom/core/talloc.h>
#include <osmocom/bsc/pcu_if.h>
#include <osmocom/bsc/bsc_api.h>
+#include <osmocom/bsc/bsc_subscr_conn_fsm.h>
#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 <laforge@gnumonks.org>
+ * (C) 2009,2017 by Harald Welte <laforge@gnumonks.org>
*
* 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 <laforge@gnumonks.org>
+ * 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <osmocom/core/fsm.h>
+#include <osmocom/core/logging.h>
+#include <osmocom/gsm/gsm0808.h>
+#include <osmocom/sigtran/sccp_sap.h>
+//#include <osmocom/sigtran/sccp_helpers.h>
+
+#include <osmocom/bsc/debug.h>
+#include <osmocom/bsc/bsc_api.h>
+#include <osmocom/bsc/gsm_data.h>
+#include <osmocom/bsc/handover.h>
+#include <osmocom/bsc/chan_alloc.h>
+#include <osmocom/bsc/bsc_subscriber.h>
+#include <osmocom/bsc/osmo_bsc_sigtran.h>
+#include <osmocom/bsc/bsc_subscr_conn_fsm.h>
+
+#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 <osmocom/bsc/bsc_subscr_conn_fsm.h>
#include <osmocom/bsc/osmo_bsc.h>
#include <osmocom/bsc/bsc_msc_data.h>
#include <osmocom/bsc/debug.h>
@@ -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 <zecke@selfish.org>
* (C) 2009-2012 by On-Waves
+ * (C) 2017 by Harald Welte <laforge@gnumonks.org>
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
@@ -27,6 +28,7 @@
#include <osmocom/bsc/osmo_bsc_mgcp.h>
#include <osmocom/bsc/paging.h>
#include <osmocom/bsc/gsm_04_08_utils.h>
+#include <osmocom/bsc/bsc_subscr_conn_fsm.h>
#include <osmocom/gsm/protocol/gsm_08_08.h>
#include <osmocom/gsm/gsm0808.h>
@@ -583,45 +585,6 @@ static int select_best_cipher(uint8_t msc_mask, uint8_t bsc_mask)
}
/*
- * 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
* a cipher we will have to send cipher mode reject to the MSC,
@@ -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, &param);
}
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 <osmocom/core/timer.h>
#include <osmocom/core/fsm.h>
#include <osmocom/bsc/osmo_bsc_sigtran.h>
+#include <osmocom/bsc/bsc_subscr_conn_fsm.h>
#include <osmocom/core/byteswap.h>
#include <arpa/inet.h>
@@ -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, &param);
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 <laforge@gnumonks.org>
* 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 <osmocom/core/utils.h>
#include <osmocom/core/logging.h>
+#include <osmocom/core/fsm.h>
#include <osmocom/sigtran/osmo_ss7.h>
#include <osmocom/sigtran/sccp_sap.h>
#include <osmocom/core/linuxlist.h>
@@ -33,6 +33,7 @@
#include <osmocom/bsc/a_reset.h>
#include <osmocom/bsc/gsm_04_80.h>
#include <osmocom/bsc/osmo_bsc_mgcp.h>
+#include <osmocom/bsc/bsc_subscr_conn_fsm.h>
/* 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);
+}