aboutsummaryrefslogtreecommitdiffstats
path: root/src/libmsc/osmo_msc.c
diff options
context:
space:
mode:
authorNeels Hofmeyr <neels@hofmeyr.de>2018-03-31 00:02:14 +0200
committerHarald Welte <laforge@gnumonks.org>2018-04-11 21:39:44 +0000
commite3d3dc6ea218a07161eeb80ae864a96bef2d8e61 (patch)
treeb0d8bddeda0835e20b4d0592184a4ec2befe7d07 /src/libmsc/osmo_msc.c
parentdc2514b22062af04354c0331f0f5819051c3fdee (diff)
refactor subscr_conn and subscr_conn_fsm de-/alloc
Refactor: 1. Glue the gsm_subscriber_connection alloc to the subscr_conn_fsm. 2. Add separate AUTH_CIPH state to the FSM. 3. Use conn->use_count to trigger conn release. 4. Add separate RELEASING state to the FSM. 5. Add rate counters for each of the three Complete Layer 3 types. Details: 1. Glue the gsm_subscriber_connection alloc to the subscr_conn_fsm. Historically, a gsm_subscriber_connection was allocated in libbsc land, and only upon Complete Layer 3 did libmsc add the fsm instance. After splitting openbsc.git into a separate osmo-msc, this is no longer necessary, hence: Closely tie gsm_subscriber_connection allocation to the subscr_conn_fsm instance: talloc the conn as a child of the FSM instance, and discard the conn as soon as the FSM terminates. 2. Add separate AUTH_CIPH state to the FSM. Decoding the Complete Layer 3 message is distinctly separate from waiting for the VLR FSMs to conclude. Use the NEW state as "we don't know if this is a valid message yet", and the AUTH_CIPH state as "evaluating, don't release". A profound effect of this: should we for any odd reason fail to leave the FSM's NEW state, the conn will be released right at the end of msc_compl_l3(), without needing to trigger release in each code path. 3. Use conn->use_count to trigger conn release. Before, the FSM itself would hold a use count on the conn, and hence we would need to ask it whether it is ready to release the conn yet by dispatching events, to achieve a use_count decrement. Instead, unite the FSM instance and conn, and do not hold a use count by the FSM. Hence, trigger an FSM "UNUSED" event only when the use_count reaches zero. As long as use counts are done correctly, the FSM will terminate correctly. These exceptions: - The new AUTH_CIPH state explicitly ignores UNUSED events, since we expect the use count to reach zero while evaluating Authentication and Ciphering. (I experimented with holding a use count by AUTH_CIPH onenter() and releasing by onleave(), but the use count and thus the conn are released before the next state can initiate transactions that would increment the use count again. Same thing for the VLR FSMs holding a use count, they should be done before we advance to the next state. The easiest is to simply expect zero use count during the AUTH_CIPH state.) - A CM Service Request means that even though the MSC would be through with all it wants to do, we shall still wait for a request to follow from the MS. Hence the FSM holds a use count on itself while a CM Service is pending. - While waiting for a Release/Clear Complete, the FSM holds a use count on itself. 4. Add separate RELEASING state to the FSM. If we decide to release for other reasons than a use count reaching zero, we still need to be able to wait for the msc_dtap() use count on the conn to release. (An upcoming patch will further use the RELEASING state to properly wait for Clear Complete / Release Complete messages.) 5. Add rate counters for each of the three Complete Layer 3 types. Besides LU, also count CM Service Request and Paging Response acceptance/rejections. Without these counters, only very few of the auth+ciph outcomes actually show in the counters. Related: OS#3122 Change-Id: I55feb379e176a96a831e105b86202b17a0ffe889
Diffstat (limited to 'src/libmsc/osmo_msc.c')
-rw-r--r--src/libmsc/osmo_msc.c149
1 files changed, 4 insertions, 145 deletions
diff --git a/src/libmsc/osmo_msc.c b/src/libmsc/osmo_msc.c
index 34f705cbb..a5184b213 100644
--- a/src/libmsc/osmo_msc.c
+++ b/src/libmsc/osmo_msc.c
@@ -84,22 +84,6 @@ void msc_sapi_n_reject(struct gsm_subscriber_connection *conn, int dlci)
gsm411_sapi_n_reject(conn);
}
-void subscr_conn_release_when_unused(struct gsm_subscriber_connection *conn)
-{
- if (!conn)
- return;
- if (!conn->fi)
- return;
- if (!(conn->fi->state == SUBSCR_CONN_S_ACCEPTED
- || conn->fi->state == SUBSCR_CONN_S_COMMUNICATING)) {
- DEBUGP(DMM, "%s: %s: conn still being established (%s)\n",
- vlr_subscr_name(conn->vsub), __func__,
- osmo_fsm_inst_state_name(conn->fi));
- return;
- }
- osmo_fsm_inst_dispatch(conn->fi, SUBSCR_CONN_E_RELEASE_WHEN_UNUSED, NULL);
-}
-
/* receive a Level 3 Complete message and return MSC_CONN_ACCEPT or
* MSC_CONN_REJECT */
int msc_compl_l3(struct gsm_subscriber_connection *conn,
@@ -108,9 +92,6 @@ int msc_compl_l3(struct gsm_subscriber_connection *conn,
msc_subscr_conn_get(conn, MSC_CONN_USE_COMPL_L3);
gsm0408_dispatch(conn, msg);
- subscr_conn_release_when_unused(conn);
-
- /* If this should be kept, the conn->fi has placed a use_count */
msc_subscr_conn_put(conn, MSC_CONN_USE_COMPL_L3);
/* Always return acceptance, because even if the conn was not accepted,
@@ -142,7 +123,6 @@ void msc_dtap(struct gsm_subscriber_connection *conn, uint8_t link_id, struct ms
msc_subscr_conn_get(conn, MSC_CONN_USE_DTAP);
gsm0408_dispatch(conn, msg);
- subscr_conn_release_when_unused(conn);
msc_subscr_conn_put(conn, MSC_CONN_USE_DTAP);
}
@@ -232,63 +212,6 @@ void msc_cipher_mode_compl(struct gsm_subscriber_connection *conn,
vlr_subscr_rx_ciph_res(conn->vsub, &ciph_res);
}
-struct gsm_subscriber_connection *msc_subscr_con_allocate(struct gsm_network *network)
-{
- struct gsm_subscriber_connection *conn;
-
- conn = talloc_zero(network, struct gsm_subscriber_connection);
- if (!conn)
- return NULL;
-
- conn->network = network;
- llist_add_tail(&conn->entry, &network->subscr_conns);
- return conn;
-}
-
-void msc_subscr_cleanup(struct vlr_subscr *vsub)
-{
- if (!vsub)
- return;
- vsub->lu_fsm = NULL;
-}
-
-void msc_subscr_con_cleanup(struct gsm_subscriber_connection *conn)
-{
- if (!conn)
- return;
-
- if (conn->vsub) {
- DEBUGP(DRLL, "subscr %s: Freeing subscriber connection\n",
- vlr_subscr_name(conn->vsub));
- msc_subscr_cleanup(conn->vsub);
- conn->vsub->msc_conn_ref = NULL;
- vlr_subscr_put(conn->vsub);
- conn->vsub = NULL;
- } else
- DEBUGP(DRLL, "Freeing subscriber connection"
- " with NULL subscriber\n");
-
- if (!conn->fi)
- return;
-
- osmo_fsm_inst_term(conn->fi,
- (conn->fi->state == SUBSCR_CONN_S_RELEASED)
- ? OSMO_FSM_TERM_REGULAR
- : OSMO_FSM_TERM_ERROR,
- NULL);
-}
-
-void msc_subscr_con_free(struct gsm_subscriber_connection *conn)
-{
- if (!conn)
- return;
-
- msc_subscr_con_cleanup(conn);
-
- llist_del(&conn->entry);
- talloc_free(conn);
-}
-
/* Receive a CLEAR REQUEST from BSC */
int msc_clear_request(struct gsm_subscriber_connection *conn, uint32_t cause)
{
@@ -296,66 +219,6 @@ int msc_clear_request(struct gsm_subscriber_connection *conn, uint32_t cause)
return 1;
}
-static void msc_subscr_conn_release_all(struct gsm_subscriber_connection *conn, uint32_t cause)
-{
- if (conn->in_release)
- return;
- conn->in_release = true;
-
- /* If we're closing in a middle of a trans, we need to clean up */
- trans_conn_closed(conn);
-
- switch (conn->via_ran) {
- case RAN_UTRAN_IU:
- ranap_iu_tx_release(conn->iu.ue_ctx, NULL);
- /* FIXME: keep the conn until the Iu Release Outcome is
- * received from the UE, or a timeout expires. For now, the log
- * says "unknown UE" for each release outcome. */
- break;
- case RAN_GERAN_A:
- a_iface_tx_clear_cmd(conn);
- break;
- default:
- LOGP(DMM, LOGL_ERROR, "%s: Unknown RAN type, cannot tx release/clear\n",
- vlr_subscr_name(conn->vsub));
- break;
- }
-}
-
-/* If the conn->fi is still present, dispatch SUBSCR_CONN_E_CN_CLOSE
- * event to gracefully terminate the connection. If the fi is already
- * cleared, call msc_subscr_conn_release_all() to take release actions.
- * \param cause a GSM_CAUSE_* constant, e.g. GSM_CAUSE_AUTH_FAILED.
- */
-void msc_subscr_conn_close(struct gsm_subscriber_connection *conn,
- uint32_t cause)
-{
- if (!conn)
- return;
- if (conn->in_release) {
- DEBUGP(DMM, "msc_subscr_conn_close(vsub=%s, cause=%u):"
- " already dispatching release, ignore.\n",
- vlr_subscr_name(conn->vsub), cause);
- return;
- }
- if (!conn->fi) {
- DEBUGP(DMM, "msc_subscr_conn_close(vsub=%s, cause=%u): no conn fsm,"
- " releasing directly without release event.\n",
- vlr_subscr_name(conn->vsub), cause);
- /* In case of an IMSI Detach, we don't have fi. Release
- * anyway to ensure a timely Iu Release / BSSMAP Clear. */
- msc_subscr_conn_release_all(conn, cause);
- return;
- }
- if (conn->fi->state == SUBSCR_CONN_S_RELEASED) {
- DEBUGP(DMM, "msc_subscr_conn_close(vsub=%s, cause=%u):"
- " conn fsm already releasing, ignore.\n",
- vlr_subscr_name(conn->vsub), cause);
- return;
- }
- osmo_fsm_inst_dispatch(conn->fi, SUBSCR_CONN_E_CN_CLOSE, &cause);
-}
-
/* increment the ref-count. Needs to be called by every user */
struct gsm_subscriber_connection *
_msc_subscr_conn_get(struct gsm_subscriber_connection *conn,
@@ -364,12 +227,6 @@ _msc_subscr_conn_get(struct gsm_subscriber_connection *conn,
{
OSMO_ASSERT(conn);
- if (conn->in_release)
- LOGPSRC(DREF, LOGL_ERROR, file, line,
- "%s: MSC conn use error: using conn that is already in release (%s)\n",
- vlr_subscr_name(conn->vsub),
- msc_subscr_conn_use_name(balance_token));
-
if (balance_token != MSC_CONN_USE_UNTRACKED) {
uint32_t flag = 1 << balance_token;
OSMO_ASSERT(balance_token < 32);
@@ -423,18 +280,20 @@ void _msc_subscr_conn_put(struct gsm_subscriber_connection *conn,
conn->use_count, conn->use_tokens);
if (conn->use_count == 0)
- msc_subscr_con_free(conn);
+ osmo_fsm_inst_dispatch(conn->fi, SUBSCR_CONN_E_UNUSED, NULL);
}
const struct value_string msc_subscr_conn_use_names[] = {
{MSC_CONN_USE_UNTRACKED, "UNTRACKED"},
{MSC_CONN_USE_COMPL_L3, "compl_l3"},
{MSC_CONN_USE_DTAP, "dtap"},
- {MSC_CONN_USE_FSM, "fsm"},
+ {MSC_CONN_USE_AUTH_CIPH, "auth+ciph"},
+ {MSC_CONN_USE_CM_SERVICE, "cm_service"},
{MSC_CONN_USE_TRANS_CC, "trans_cc"},
{MSC_CONN_USE_TRANS_SMS, "trans_sms"},
{MSC_CONN_USE_TRANS_USSD, "trans_ussd"},
{MSC_CONN_USE_SILENT_CALL, "silent_call"},
+ {MSC_CONN_USE_RELEASE, "release"},
{0, NULL},
};