diff options
Diffstat (limited to 'src/libmsc/osmo_msc.c')
-rw-r--r-- | src/libmsc/osmo_msc.c | 387 |
1 files changed, 0 insertions, 387 deletions
diff --git a/src/libmsc/osmo_msc.c b/src/libmsc/osmo_msc.c deleted file mode 100644 index 4d24f22a6..000000000 --- a/src/libmsc/osmo_msc.c +++ /dev/null @@ -1,387 +0,0 @@ -/* main MSC management code... */ - -/* - * (C) 2010,2013 by Holger Hans Peter Freyther <zecke@selfish.org> - * (C) 2010 by On-Waves - * - * 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 <openbsc/osmo_msc.h> -#include <openbsc/bsc_api.h> -#include <openbsc/debug.h> -#include <openbsc/transaction.h> -#include <openbsc/db.h> -#include <openbsc/vlr.h> -#include <openbsc/osmo_msc.h> -#include <openbsc/a_iface.h> - -#include <openbsc/gsm_04_11.h> - -#include "../../bscconfig.h" -#ifdef BUILD_IU -#include <osmocom/ranap/iu_client.h> -#else -#include <openbsc/iu_dummy.h> -#endif - -/* Receive a SAPI-N-REJECT from BSC */ -void msc_sapi_n_reject(struct gsm_subscriber_connection *conn, int dlci) -{ - int sapi = dlci & 0x7; - - if (sapi == UM_SAPI_SMS) - gsm411_sapi_n_reject(conn); -} - -static void subscr_conn_bump(struct gsm_subscriber_connection *conn) -{ - if (!conn) - return; - if (!conn->conn_fsm) - return; - if (!(conn->conn_fsm->state == SUBSCR_CONN_S_ACCEPTED - || conn->conn_fsm->state == SUBSCR_CONN_S_COMMUNICATING)) { - DEBUGP(DMM, "%s: bump: conn still being established (%s)\n", - vlr_subscr_name(conn->vsub), - osmo_fsm_inst_state_name(conn->conn_fsm)); - return; - } - osmo_fsm_inst_dispatch(conn->conn_fsm, SUBSCR_CONN_E_BUMP, 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, - struct msgb *msg, uint16_t chosen_channel) -{ - msc_subscr_conn_get(conn); - gsm0408_dispatch(conn, msg); - - /* Bump whether the conn wants to be closed */ - subscr_conn_bump(conn); - - /* If this should be kept, the conn->conn_fsm has placed a use_count */ - msc_subscr_conn_put(conn); - - /* Always return acceptance, because even if the conn was not accepted, - * we assumed ownership of it and the caller shall not interfere with - * that. We may even already have discarded the conn. */ - return MSC_CONN_ACCEPT; - -#if 0 - /* - * If this is a silent call we want the channel to remain open as long as - * possible and this is why we accept this connection regardless of any - * pending transaction or ongoing operation. - */ - if (conn->silent_call) - return MSC_CONN_ACCEPT; - if (conn->loc_operation || conn->sec_operation || conn->anch_operation) - return MSC_CONN_ACCEPT; - if (trans_has_conn(conn)) - return MSC_CONN_ACCEPT; - - LOGP(DRR, LOGL_INFO, "MSC Complete L3: Rejecting connection.\n"); - return MSC_CONN_REJECT; -#endif -} - -/* Receive a DTAP message from BSC */ -void msc_dtap(struct gsm_subscriber_connection *conn, uint8_t link_id, struct msgb *msg) -{ - msc_subscr_conn_get(conn); - gsm0408_dispatch(conn, msg); - - /* Bump whether the conn wants to be closed */ - subscr_conn_bump(conn); - msc_subscr_conn_put(conn); -} - -/* Receive an ASSIGNMENT COMPLETE from BSC */ -void msc_assign_compl(struct gsm_subscriber_connection *conn, - uint8_t rr_cause, uint8_t chosen_channel, - uint8_t encr_alg_id, uint8_t speec) -{ - LOGP(DRR, LOGL_DEBUG, "MSC assign complete (do nothing).\n"); -} - -/* Receive an ASSIGNMENT FAILURE from BSC */ -void msc_assign_fail(struct gsm_subscriber_connection *conn, - uint8_t cause, uint8_t *rr_cause) -{ - LOGP(DRR, LOGL_DEBUG, "MSC assign failure (do nothing).\n"); -} - -/* Receive a CLASSMARK CHANGE from BSC */ -void msc_classmark_chg(struct gsm_subscriber_connection *conn, - const uint8_t *cm2, uint8_t cm2_len, - const uint8_t *cm3, uint8_t cm3_len) -{ - if (cm2 && cm2_len) { - if (cm2_len > sizeof(conn->classmark.classmark2)) { - LOGP(DRR, LOGL_NOTICE, "%s: classmark2 is %u bytes, truncating at %zu bytes\n", - vlr_subscr_name(conn->vsub), cm2_len, sizeof(conn->classmark.classmark2)); - cm2_len = sizeof(conn->classmark.classmark2); - } - conn->classmark.classmark2_len = cm2_len; - memcpy(conn->classmark.classmark2, cm2, cm2_len); - } - if (cm3 && cm3_len) { - if (cm3_len > sizeof(conn->classmark.classmark3)) { - LOGP(DRR, LOGL_NOTICE, "%s: classmark3 is %u bytes, truncating at %zu bytes\n", - vlr_subscr_name(conn->vsub), cm3_len, sizeof(conn->classmark.classmark3)); - cm3_len = sizeof(conn->classmark.classmark3); - } - conn->classmark.classmark3_len = cm3_len; - memcpy(conn->classmark.classmark3, cm3, cm3_len); - } -} - -/* Receive a CIPHERING MODE COMPLETE from BSC */ -void msc_cipher_mode_compl(struct gsm_subscriber_connection *conn, - struct msgb *msg, uint8_t alg_id) -{ - struct gsm48_hdr *gh = msgb_l3(msg); - unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh); - struct tlv_parsed tp; - uint8_t mi_type; - char imeisv[GSM48_MI_SIZE] = ""; - struct vlr_ciph_result ciph_res = { .cause = VLR_CIPH_REJECT }; - - if (!gh) { - LOGP(DRR, LOGL_ERROR, "invalid: msgb without l3 header\n"); - return; - } - - if (!conn) { - LOGP(DRR, LOGL_ERROR, - "invalid: rx Ciphering Mode Complete on NULL conn\n"); - return; - } - if (!conn->vsub) { - LOGP(DRR, LOGL_ERROR, - "invalid: rx Ciphering Mode Complete for NULL subscr\n"); - return; - } - - DEBUGP(DRR, "%s: CIPHERING MODE COMPLETE\n", - vlr_subscr_name(conn->vsub)); - - tlv_parse(&tp, &gsm48_att_tlvdef, gh->data, payload_len, 0, 0); - - /* bearer capability */ - if (TLVP_PRESENT(&tp, GSM48_IE_MOBILE_ID)) { - mi_type = TLVP_VAL(&tp, GSM48_IE_MOBILE_ID)[0] & GSM_MI_TYPE_MASK; - if (mi_type == GSM_MI_TYPE_IMEISV - && TLVP_LEN(&tp, GSM48_IE_MOBILE_ID) > 0) { - gsm48_mi_to_string(imeisv, sizeof(imeisv), - TLVP_VAL(&tp, GSM48_IE_MOBILE_ID), - TLVP_LEN(&tp, GSM48_IE_MOBILE_ID)); - ciph_res.imeisv = imeisv; - } - } - - ciph_res.cause = VLR_CIPH_COMPL; - 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); - vlr_subscr_put(conn->vsub); - conn->vsub = NULL; - } else - DEBUGP(DRLL, "Freeing subscriber connection" - " with NULL subscriber\n"); - - if (!conn->conn_fsm) - return; - - osmo_fsm_inst_term(conn->conn_fsm, - (conn->conn_fsm->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) -{ - msc_subscr_conn_close(conn, cause); - return 1; -} - -/* MSC-level operations to be called by libbsc in NITB */ -static struct bsc_api msc_handler = { - .sapi_n_reject = msc_sapi_n_reject, - .compl_l3 = msc_compl_l3, - .dtap = msc_dtap, - .clear_request = msc_clear_request, - .assign_compl = msc_assign_compl, - .assign_fail = msc_assign_fail, - .classmark_chg = msc_classmark_chg, - .cipher_mode_compl = msc_cipher_mode_compl, - .conn_cleanup = msc_subscr_con_cleanup, -}; - -struct bsc_api *msc_bsc_api() { - return &msc_handler; -} - -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->conn_fsm is still present, dispatch SUBSCR_CONN_E_CN_CLOSE - * event to gracefully terminate the connection. If the conn_fsm 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->conn_fsm) { - 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 conn_fsm. Release - * anyway to ensure a timely Iu Release / BSSMAP Clear. */ - msc_subscr_conn_release_all(conn, cause); - return; - } - if (conn->conn_fsm->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->conn_fsm, 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, - const char *file, int line) -{ - OSMO_ASSERT(conn); - - if (conn->in_release) - return NULL; - - conn->use_count++; - LOGPSRC(DREF, LOGL_DEBUG, file, line, - "%s: MSC conn use + 1 == %u\n", - vlr_subscr_name(conn->vsub), conn->use_count); - - return conn; -} - -/* decrement the ref-count. Once it reaches zero, we release */ -void _msc_subscr_conn_put(struct gsm_subscriber_connection *conn, - const char *file, int line) -{ - OSMO_ASSERT(conn); - - if (conn->use_count == 0) { - LOGPSRC(DREF, LOGL_ERROR, file, line, - "%s: MSC conn use - 1 failed: is already 0\n", - vlr_subscr_name(conn->vsub)); - return; - } - - conn->use_count--; - LOGPSRC(DREF, LOGL_DEBUG, file, line, - "%s: MSC conn use - 1 == %u\n", - vlr_subscr_name(conn->vsub), conn->use_count); - - if (conn->use_count == 0) - msc_subscr_con_free(conn); -} - -void msc_stop_paging(struct vlr_subscr *vsub) -{ - DEBUGP(DPAG, "Paging can stop for %s\n", vlr_subscr_name(vsub)); - /* tell BSCs and RNCs to stop paging? How? */ -} |