/* The MSC-T role, a transitional RAN connection during Handover. */ /* * (C) 2019 by sysmocom - s.m.f.c. GmbH * All Rights Reserved * * SPDX-License-Identifier: AGPL-3.0+ * * Author: Neels Hofmeyr * * 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 #include #include static struct osmo_fsm msc_t_fsm; static struct msc_t *msc_t_find_by_handover_number(const char *handover_number) { struct msub *msub; llist_for_each_entry(msub, &msub_list, entry) { struct msc_t *msc_t = msub_msc_t(msub); if (!msc_t) continue; if (!*msc_t->inter_msc.handover_number) continue; if (strcmp(msc_t->inter_msc.handover_number, handover_number)) continue; /* Found the assigned Handover Number */ return msc_t; } return NULL; } static uint64_t net_handover_number_next(struct gsm_network *net) { uint64_t nr; if (net->handover_number.next < net->handover_number.range_start || net->handover_number.next > net->handover_number.range_end) net->handover_number.next = net->handover_number.range_start; nr = net->handover_number.next; net->handover_number.next++; return nr; } static int msc_t_assign_handover_number(struct msc_t *msc_t) { int rc; uint64_t started_at; uint64_t ho_nr; char ho_nr_str[GSM23003_MSISDN_MAX_DIGITS+1]; struct gsm_network *net = msc_t_net(msc_t); bool usable = false; started_at = ho_nr = net_handover_number_next(net); if (!ho_nr) { LOG_MSC_T(msc_t, LOGL_ERROR, "No Handover Number range defined in MSC config\n"); return -ENOENT; } do { rc = snprintf(ho_nr_str, sizeof(ho_nr_str), "%"PRIu64, ho_nr); if (rc <= 0 || rc >= sizeof(ho_nr_str)) { LOG_MSC_T(msc_t, LOGL_ERROR, "Cannot compose Handover Number string (rc=%d)\n", rc); return -EINVAL; } if (!msc_t_find_by_handover_number(ho_nr_str)) { usable = true; break; } ho_nr = net_handover_number_next(net); } while(ho_nr != started_at); if (!usable) { LOG_MSC_T(msc_t, LOGL_ERROR, "No Handover Number available\n"); return -EINVAL; } LOG_MSC_T(msc_t, LOGL_INFO, "Assigning Handover Number %s\n", ho_nr_str); OSMO_STRLCPY_ARRAY(msc_t->inter_msc.handover_number, ho_nr_str); return 0; } static struct msc_t *msc_t_priv(struct osmo_fsm_inst *fi) { OSMO_ASSERT(fi); OSMO_ASSERT(fi->fsm == &msc_t_fsm); OSMO_ASSERT(fi->priv); return fi->priv; } /* As a macro to log the caller's source file and line. * Assumes presence of local msc_t variable. */ #define msc_t_error(fmt, args...) do { \ msc_t->ho_success = false; \ LOG_MSC_T(msc_t, LOGL_ERROR, fmt, ##args); \ msc_t_clear(msc_t); \ } while(0) static void msc_t_send_handover_failure(struct msc_t *msc_t, enum gsm0808_cause cause) { struct ran_msg ran_enc_msg = { .msg_type = RAN_MSG_HANDOVER_FAILURE, .handover_failure = { .cause = cause, }, }; struct an_apdu an_apdu = { .an_proto = msc_t->c.ran->an_proto, .msg = msc_role_ran_encode(msc_t->c.fi, &ran_enc_msg), }; msc_t->ho_fail_sent = true; if (!an_apdu.msg) return; msub_role_dispatch(msc_t->c.msub, MSC_ROLE_A, MSC_A_EV_FROM_T_PREPARE_HANDOVER_FAILURE, &an_apdu); msgb_free(an_apdu.msg); } static int msc_t_ho_request_decode_and_store_cb(struct osmo_fsm_inst *msc_t_fi, void *data, const struct ran_msg *ran_dec) { struct msc_t *msc_t = msc_t_priv(msc_t_fi); if (ran_dec->msg_type != RAN_MSG_HANDOVER_REQUEST) { LOG_MSC_T(msc_t, LOGL_DEBUG, "Expected %s in incoming inter-MSC Handover message, got %s\n", ran_msg_type_name(RAN_MSG_HANDOVER_REQUEST), ran_msg_type_name(ran_dec->msg_type)); return -EINVAL; } msc_t->inter_msc.cell_id_target = ran_dec->handover_request.cell_id_target; msc_t->inter_msc.callref = ran_dec->handover_request.call_id; /* TODO other parameters...? * Global Call Reference */ return 0; } /* On an icoming Handover Request from a remote MSC, we first need to set up an MGW endpoint, because the BSC needs to * know our AoIP Transport Layer Address in the Handover Request message (which obviously the remote MSC doesn't send, * it needs to be our local RTP address). Creating the MGW endpoint this is asynchronous, so we need to store the * Handover Request data to forward to the BSC once the MGW endpoint is known. */ static int msc_t_decode_and_store_ho_request(struct msc_t *msc_t, const struct an_apdu *an_apdu) { if (msc_role_ran_decode(msc_t->c.fi, an_apdu, msc_t_ho_request_decode_and_store_cb, NULL)) { msc_t_error("Failed to decode Handover Request\n"); return -ENOTSUP; } /* Ok, decoding done, and above msc_t_ho_request_decode_and_store_cb() has retrieved what info we need at this * point and stored it in msc_t->inter_msc.* */ /* We're storing this for use after async events, so need to make sure that each and every bit of data is copied * and no longer references some msgb that might be deallocated when this returns, nor remains in a local stack * variable of some ran_decode implementation. The simplest is to store the entire msgb. */ msc_t->inter_msc.ho_request = (struct an_apdu) { .an_proto = an_apdu->an_proto, .msg = msgb_copy(an_apdu->msg, "saved inter-MSC Handover Request"), /* A decoded osmo_gsup_message often still references memory of within the msgb the GSUP was received * in. So, any info from an_apdu->e_info that would be needed would have to be copied separately. * Omit e_info completely. */ }; return 0; } /* On an incoming Handover Request from a remote MSC, the target cell was transmitted in the Handover Request message. * Find the RAN peer and assign from the cell id decoded above in msc_t_decode_and_store_ho_request(). */ static int msc_t_find_ran_peer_from_ho_request(struct msc_t *msc_t) { struct msc_a *msc_a = msub_msc_a(msc_t->c.msub); const struct neighbor_ident_entry *nie; struct ran_peer *rp_from_neighbor_ident; struct ran_peer *rp; switch (msc_ho_find_target_cell(msc_a, &msc_t->inter_msc.cell_id_target, &nie, &rp_from_neighbor_ident, &rp)) { case MSC_NEIGHBOR_TYPE_REMOTE_MSC: msc_t_error("Incoming Handover Request indicated target cell that belongs to a remote MSC:" " Cell ID: %s; remote MSC: %s\n", gsm0808_cell_id_name(&msc_t->inter_msc.cell_id_target), neighbor_ident_addr_name(&nie->addr)); return -EINVAL; case MSC_NEIGHBOR_TYPE_NONE: msc_t_error("Incoming Handover Request for unknown cell %s\n", gsm0808_cell_id_name(&msc_t->inter_msc.cell_id_target)); return -EINVAL; case MSC_NEIGHBOR_TYPE_LOCAL_RAN_PEER: /* That's what is expected: a local RAN peer, e.g. BSC, or a remote BSC from neighbor cfg. */ if (!rp) rp = rp_from_neighbor_ident; break; } OSMO_ASSERT(rp); LOG_MSC_T(msc_t, LOGL_DEBUG, "Incoming Handover Request indicates target cell %s," " which belongs to RAN peer %s\n", gsm0808_cell_id_name(&msc_t->inter_msc.cell_id_target), rp->fi->id); /* Finally we know where to direct the Handover */ msc_t_set_ran_peer(msc_t, rp); return 0; } static int msc_t_send_stored_ho_request__decode_cb(struct osmo_fsm_inst *msc_t_fi, void *data, const struct ran_msg *ran_dec) { int rc; struct an_apdu an_apdu; struct msc_t *msc_t = msc_t_priv(msc_t_fi); struct osmo_sockaddr_str *rtp_ran_local = data; /* Copy ran_dec message to un-const so we can add the AoIP Transport Layer Address. All pointer references still * remain on the same memory as ran_dec, which is fine. We're just going to encode it again right away. */ struct ran_msg ran_enc = *ran_dec; if (ran_dec->msg_type != RAN_MSG_HANDOVER_REQUEST) { LOG_MSC_T(msc_t, LOGL_DEBUG, "Expected %s in incoming inter-MSC Handover message, got %s\n", ran_msg_type_name(RAN_MSG_HANDOVER_REQUEST), ran_msg_type_name(ran_dec->msg_type)); return -EINVAL; } /* Insert AoIP Transport Layer Address */ ran_enc.handover_request.rtp_ran_local = rtp_ran_local; /* Finally ready to forward to BSC: encode and send out. */ an_apdu = (struct an_apdu){ .an_proto = msc_t->inter_msc.ho_request.an_proto, .msg = msc_role_ran_encode(msc_t->c.fi, &ran_enc), }; if (!an_apdu.msg) return -EIO; rc = msc_t_down_l2_co(msc_t, &an_apdu, true); msgb_free(an_apdu.msg); return rc; } /* The MGW endpoint is created, we know our AoIP Transport Layer Address and can send the Handover Request to the RAN * peer. */ static int msc_t_send_stored_ho_request(struct msc_t *msc_t) { struct osmo_sockaddr_str *rtp_ran_local = call_leg_local_ip(msc_t->inter_msc.call_leg, RTP_TO_RAN); if (!rtp_ran_local) { msc_t_error("Local RTP address towards RAN is not set up properly, cannot send Handover Request\n"); return -EINVAL; } /* The Handover Request received from the remote MSC is fed through, except we need to insert our local AoIP * Transport Layer Address, i.e. the RTP IP:port of the MGW towards the RAN side. So we actually need to decode, * add the AoIP and re-encode. By nature of decoding, it goes through the decode callback. */ return msc_role_ran_decode(msc_t->c.fi, &msc_t->inter_msc.ho_request, msc_t_send_stored_ho_request__decode_cb, rtp_ran_local); } static void msc_t_fsm_pending_first_co_initial_msg(struct osmo_fsm_inst *fi, uint32_t event, void *data) { struct msc_t *msc_t = msc_t_priv(fi); struct msc_a *msc_a = msub_msc_a(msc_t->c.msub); struct an_apdu *an_apdu; OSMO_ASSERT(msc_a); switch (event) { case MSC_T_EV_FROM_A_PREPARE_HANDOVER_REQUEST: /* For an inter-MSC Handover coming in from a remote MSC, we do not yet know the RAN peer and AoIP * Transport Layer Address. * - RAN peer is found by decoding the actual Handover Request message and looking for the Cell * Identifier (Target). * - To be able to tell the BSC about an AoIP Transport Layer Address, we first need to create an MGW * endpoint. * For mere inter-BSC Handover, we know all of the above already. Find out which one this is. */ an_apdu = data; if (!msc_a->c.remote_to) { /* Inter-BSC */ osmo_fsm_inst_state_chg(msc_t->c.fi, MSC_T_ST_WAIT_HO_REQUEST_ACK, 0, 0); /* Inter-BSC. All should be set up, just forward the message. */ if (msc_t_down_l2_co(msc_t, an_apdu, true)) msc_t_error("Failed to send AN-APDU to RAN peer\n"); } else { /* Inter-MSC */ if (msc_t->ran_conn) { msc_t_error("Unexpected state for inter-MSC Handover: RAN peer is already set up\n"); return; } if (msc_t_decode_and_store_ho_request(msc_t, an_apdu)) return; if (msc_t_find_ran_peer_from_ho_request(msc_t)) return; /* Relying on timeout of the MGW operations, see onenter() for this state. */ osmo_fsm_inst_state_chg(msc_t->c.fi, MSC_T_ST_WAIT_LOCAL_RTP, 0, 0); } return; case MSC_T_EV_CN_CLOSE: msc_t_clear(msc_t); return; default: OSMO_ASSERT(false); } } void msc_t_fsm_wait_local_rtp_onenter(struct osmo_fsm_inst *fi, uint32_t prev_state) { struct msc_t *msc_t = msc_t_priv(fi); struct msc_a *msc_a = msub_msc_a(msc_t->c.msub); /* This only happens on inter-MSC HO incoming from a remote MSC */ if (!msc_a->c.remote_to) { msc_t_error("Unexpected state: this is not an inter-MSC Handover\n"); return; } if (msc_t->inter_msc.call_leg) { msc_t_error("Unexpected state: call leg already set up\n"); return; } msc_t->inter_msc.call_leg = call_leg_alloc(msc_t->c.fi, MSC_EV_CALL_LEG_TERM, MSC_EV_CALL_LEG_RTP_LOCAL_ADDR_AVAILABLE, MSC_EV_CALL_LEG_RTP_COMPLETE); if (!msc_t->inter_msc.call_leg || call_leg_ensure_ci(msc_t->inter_msc.call_leg, RTP_TO_RAN, msc_t->inter_msc.callref, NULL, NULL, NULL) || call_leg_ensure_ci(msc_t->inter_msc.call_leg, RTP_TO_CN, msc_t->inter_msc.callref, NULL, NULL, NULL)) { msc_t_error("Failed to set up call leg\n"); return; } /* Now wait for two MSC_EV_CALL_LEG_RTP_LOCAL_ADDR_AVAILABLE, one per RTP connection */ } void msc_t_fsm_wait_local_rtp(struct osmo_fsm_inst *fi, uint32_t event, void *data) { struct msc_t *msc_t = msc_t_priv(fi); struct rtp_stream *rtps; switch (event) { case MSC_EV_CALL_LEG_RTP_LOCAL_ADDR_AVAILABLE: rtps = data; if (!rtps) { msc_t_error("Invalid data for MSC_EV_CALL_LEG_RTP_LOCAL_ADDR_AVAILABLE\n"); return; } /* If both to-RAN and to-CN sides have a CI set up, we can continue. */ if (!call_leg_local_ip(msc_t->inter_msc.call_leg, RTP_TO_RAN) || !call_leg_local_ip(msc_t->inter_msc.call_leg, RTP_TO_CN)) return; osmo_fsm_inst_state_chg(msc_t->c.fi, MSC_T_ST_WAIT_HO_REQUEST_ACK, 0, 0); msc_t_send_stored_ho_request(msc_t); return; case MSC_EV_CALL_LEG_TERM: msc_t->inter_msc.call_leg = NULL; msc_t_error("Failed to set up MGW endpoint\n"); return; case MSC_MNCC_EV_CALL_ENDED: msc_t->inter_msc.mncc_forwarding_to_remote_cn = NULL; return; case MSC_T_EV_CN_CLOSE: case MSC_T_EV_MO_CLOSE: msc_t_clear(msc_t); return; default: OSMO_ASSERT(false); } } static int msc_t_patch_and_send_ho_request_ack(struct msc_t *msc_t, const struct an_apdu *incoming_an_apdu, const struct ran_msg *ran_dec) { int rc; struct rtp_stream *rtp_ran = msc_t->inter_msc.call_leg? msc_t->inter_msc.call_leg->rtp[RTP_TO_RAN] : NULL; struct rtp_stream *rtp_cn = msc_t->inter_msc.call_leg? msc_t->inter_msc.call_leg->rtp[RTP_TO_CN] : NULL; /* Since it's BCD, it needs rounded-up half the char* length of an MSISDN plus a type byte. * But no need to introduce obscure math to save a few stack bytes, just have more. */ uint8_t msisdn_enc_buf[GSM23003_MSISDN_MAX_DIGITS+1]; /* Copy an_apdu and an_apdu->e_info in "copy-on-write" method, because they are const and we * need to add the Handover Number to e_info. */ const struct ran_handover_request_ack *r = &ran_dec->handover_request_ack; struct ran_msg ran_enc = *ran_dec; struct osmo_gsup_message e_info = {}; struct an_apdu an_apdu = { .an_proto = incoming_an_apdu->an_proto, .e_info = &e_info, }; if (incoming_an_apdu->e_info) e_info = *incoming_an_apdu->e_info; rc = msc_t_assign_handover_number(msc_t); if (rc) return rc; rc = gsm48_encode_bcd_number(msisdn_enc_buf, sizeof(msisdn_enc_buf), 0, msc_t->inter_msc.handover_number); if (rc <= 0) return -EINVAL; e_info.msisdn_enc = msisdn_enc_buf; e_info.msisdn_enc_len = rc; /* Also need to fetch the RTP IP:port from AoIP Transport Address IE to tell the MGW about it */ if (rtp_ran) { if (osmo_sockaddr_str_is_nonzero(&r->remote_rtp)) { LOG_MSC_T(msc_t, LOGL_DEBUG, "From Handover Request Ack, got " OSMO_SOCKADDR_STR_FMT "\n", OSMO_SOCKADDR_STR_FMT_ARGS(&r->remote_rtp)); rtp_stream_set_remote_addr(rtp_ran, &r->remote_rtp); } else { LOG_MSC_T(msc_t, LOGL_DEBUG, "No RTP IP:port in Handover Request Ack\n"); } if (r->codec_present) { LOG_MSC_T(msc_t, LOGL_DEBUG, "From Handover Request Ack, got %s\n", osmo_mgcpc_codec_name(r->codec)); rtp_stream_set_codec(rtp_ran, r->codec); if (rtp_cn) rtp_stream_set_codec(rtp_cn, r->codec); } else { LOG_MSC_T(msc_t, LOGL_DEBUG, "No codec in Handover Request Ack\n"); } rtp_stream_commit(rtp_ran); } else { LOG_MSC_T(msc_t, LOGL_DEBUG, "No RTP to RAN set up yet\n"); } /* Remove that AoIP Transport Layer IE so it doesn't get sent to the remote MSC */ ran_enc.handover_request_ack.remote_rtp = (struct osmo_sockaddr_str){}; an_apdu.msg = msc_role_ran_encode(msc_t->c.fi, &ran_enc); if (!an_apdu.msg) return -EIO; /* Send to remote MSC via msc_a_remote role */ rc = msub_role_dispatch(msc_t->c.msub, MSC_ROLE_A, MSC_A_EV_FROM_T_PREPARE_HANDOVER_RESPONSE, &an_apdu); msgb_free(an_apdu.msg); return rc; } static int msc_t_wait_ho_request_ack_decode_cb(struct osmo_fsm_inst *msc_t_fi, void *data, const struct ran_msg *ran_dec) { int rc; struct msc_t *msc_t = msc_t_priv(msc_t_fi); struct msc_a *msc_a = msub_msc_a(msc_t->c.msub); const struct an_apdu *an_apdu = data; switch (ran_dec->msg_type) { case RAN_MSG_HANDOVER_REQUEST_ACK: if (msc_a->c.remote_to) { /* inter-MSC. Add Handover Number, remove AoIP Transport Layer Address. */ rc = msc_t_patch_and_send_ho_request_ack(msc_t, an_apdu, ran_dec); } else { /* inter-BSC. Just send as-is, with correct event. */ rc = msub_role_dispatch(msc_t->c.msub, MSC_ROLE_A, MSC_A_EV_FROM_T_PREPARE_HANDOVER_RESPONSE, an_apdu); } if (rc) msc_t_error("Failed to send HO Request Ack\n"); else osmo_fsm_inst_state_chg(msc_t->c.fi, MSC_T_ST_WAIT_HO_COMPLETE, 0, 0); return 0; case RAN_MSG_HANDOVER_FAILURE: msub_role_dispatch(msc_t->c.msub, MSC_ROLE_A, MSC_A_EV_FROM_T_PREPARE_HANDOVER_FAILURE, an_apdu); return 0; case RAN_MSG_CLEAR_REQUEST: msub_role_dispatch(msc_t->c.msub, MSC_ROLE_A, MSC_A_EV_FROM_T_PROCESS_ACCESS_SIGNALLING_REQUEST, an_apdu); return 0; default: LOG_MSC_T(msc_t, LOGL_ERROR, "Unexpected message during Prepare Handover procedure: %s\n", ran_msg_type_name(ran_dec->msg_type)); /* Let's just forward anyway. */ msub_role_dispatch(msc_t->c.msub, MSC_ROLE_A, MSC_A_EV_FROM_T_PROCESS_ACCESS_SIGNALLING_REQUEST, an_apdu); return 0; } } static void msc_t_fsm_wait_ho_request_ack(struct osmo_fsm_inst *fi, uint32_t event, void *data) { struct msc_t *msc_t = msc_t_priv(fi); struct an_apdu *an_apdu; switch (event) { case MSC_EV_FROM_RAN_UP_L2: an_apdu = data; /* For inter-MSC Handover, we need to examine the message type. Depending on the response, we must * dispatch MSC_A_EV_FROM_T_PREPARE_HANDOVER_RESPONSE or MSC_A_EV_FROM_T_PREPARE_HANDOVER_FAILURE, which * ensures the correct E-interface message type. And we need to include the Handover Number. * For mere inter-BSC Handover, we know that our osmo-msc internals don't care much about which event * dispatches a Handover Failure or Handover Request Ack, so we could skip the decoding. But it is a * premature optimization that complicates comparing an inter-BSC with an inter-MSC HO. */ msc_role_ran_decode(msc_t->c.fi, an_apdu, msc_t_wait_ho_request_ack_decode_cb, an_apdu); /* Action continues in msc_t_wait_ho_request_ack_decode_cb() */ return; case MSC_EV_FROM_RAN_CONN_RELEASED: msc_t_clear(msc_t); return; case MSC_T_EV_FROM_A_FORWARD_ACCESS_SIGNALLING_REQUEST: an_apdu = data; msc_t_down_l2_co(msc_t, an_apdu, false); return; case MSC_EV_CALL_LEG_TERM: msc_t->inter_msc.call_leg = NULL; msc_t_error("Failed to set up MGW endpoint\n"); return; case MSC_MNCC_EV_CALL_ENDED: msc_t->inter_msc.mncc_forwarding_to_remote_cn = NULL; return; case MSC_T_EV_CN_CLOSE: case MSC_T_EV_MO_CLOSE: msc_t_clear(msc_t); return; default: OSMO_ASSERT(false); } } static int msc_t_wait_ho_complete_decode_cb(struct osmo_fsm_inst *msc_t_fi, void *data, const struct ran_msg *ran_dec) { struct msc_t *msc_t = msc_t_priv(msc_t_fi); struct msc_a *msc_a = msub_msc_a(msc_t->c.msub); struct msc_i *msc_i; const struct an_apdu *an_apdu = data; switch (ran_dec->msg_type) { case RAN_MSG_HANDOVER_COMPLETE: msc_t->ho_success = true; /* For both inter-BSC local to this MSC and inter-MSC Handover for a remote MSC-A, forward the Handover * Complete message so that the MSC-A can change the MSC-T (transitional) to a proper MSC-I role. */ msub_role_dispatch(msc_t->c.msub, MSC_ROLE_A, MSC_A_EV_FROM_T_SEND_END_SIGNAL_REQUEST, an_apdu); /* For inter-BSC Handover, the Handover Complete event has already cleaned up this msc_t, and it is * already gone and deallocated. */ if (!msc_a->c.remote_to) return 0; /* For inter-MSC Handover, the remote MSC-A only turns its msc_t_remote into an msc_i_remote on * the same GSUP link. We are here on the MSC-B side of the GSUP link and have to take care of * creating an MSC-I over here to match the msc_i_remote at MSC-A. */ msc_i = msc_i_alloc(msc_t->c.msub, msc_t->c.ran); if (!msc_i) { msc_t_error("Failed to create MSC-I role\n"); return -1; } msc_i->inter_msc.mncc_forwarding_to_remote_cn = msc_t->inter_msc.mncc_forwarding_to_remote_cn; mncc_call_reparent(msc_i->inter_msc.mncc_forwarding_to_remote_cn, msc_i->c.fi, -1, MSC_MNCC_EV_CALL_ENDED, NULL, NULL); msc_i->inter_msc.call_leg = msc_t->inter_msc.call_leg; call_leg_reparent(msc_i->inter_msc.call_leg, msc_i->c.fi, MSC_EV_CALL_LEG_TERM, MSC_EV_CALL_LEG_RTP_LOCAL_ADDR_AVAILABLE, MSC_EV_CALL_LEG_RTP_COMPLETE); /* msc_i_set_ran_conn() properly "steals" the ran_conn from msc_t */ msc_i_set_ran_conn(msc_i, msc_t->ran_conn); /* Nicked everything worth keeping from MSC-T, discard now. */ msc_t_clear(msc_t); return 0; case RAN_MSG_HANDOVER_FAILURE: msub_role_dispatch(msc_t->c.msub, MSC_ROLE_A, MSC_A_EV_FROM_T_PREPARE_HANDOVER_FAILURE, an_apdu); return 0; default: LOG_MSC_T(msc_t, LOGL_ERROR, "Unexpected message during Prepare Handover procedure: %s\n", ran_msg_type_name(ran_dec->msg_type)); /* Let's just forward anyway. Fall thru */ case RAN_MSG_HANDOVER_DETECT: case RAN_MSG_CLEAR_REQUEST: msub_role_dispatch(msc_t->c.msub, MSC_ROLE_A, MSC_A_EV_FROM_T_PROCESS_ACCESS_SIGNALLING_REQUEST, an_apdu); return 0; } } static void msc_t_fsm_wait_ho_complete(struct osmo_fsm_inst *fi, uint32_t event, void *data) { struct msc_t *msc_t = msc_t_priv(fi); struct an_apdu *an_apdu; switch (event) { case MSC_EV_FROM_RAN_UP_L2: an_apdu = data; /* We need to catch the Handover Complete message in order to send it as a SendEndSignal Request */ msc_role_ran_decode(msc_t->c.fi, an_apdu, msc_t_wait_ho_complete_decode_cb, an_apdu); return; case MSC_EV_FROM_RAN_CONN_RELEASED: msc_t_clear(msc_t); return; case MSC_T_EV_FROM_A_FORWARD_ACCESS_SIGNALLING_REQUEST: an_apdu = data; msc_t_down_l2_co(msc_t, an_apdu, false); return; case MSC_EV_CALL_LEG_TERM: msc_t->inter_msc.call_leg = NULL; msc_t_error("Failed to set up MGW endpoint\n"); return; case MSC_MNCC_EV_CALL_ENDED: msc_t->inter_msc.mncc_forwarding_to_remote_cn = NULL; return; case MSC_T_EV_CN_CLOSE: case MSC_T_EV_MO_CLOSE: msc_t_clear(msc_t); return; default: OSMO_ASSERT(false); } } void msc_t_mncc_cb(struct mncc_call *mncc_call, const union mncc_msg *mncc_msg, void *data) { struct msc_t *msc_t = data; struct gsm_mncc_number nr = { .plan = 1, }; OSMO_STRLCPY_ARRAY(nr.number, msc_t->inter_msc.handover_number); switch (mncc_msg->msg_type) { case MNCC_RTP_CREATE: mncc_call_incoming_tx_setup_cnf(mncc_call, &nr); return; default: return; } } struct mncc_call *msc_t_check_call_to_handover_number(const struct gsm_mncc *msg) { struct msc_t *msc_t; const char *handover_number; struct mncc_call_incoming_req req; struct mncc_call *mncc_call; if (!(msg->fields & MNCC_F_CALLED)) return NULL; handover_number = msg->called.number; msc_t = msc_t_find_by_handover_number(handover_number); if (!msc_t) return NULL; if (msc_t->inter_msc.mncc_forwarding_to_remote_cn) { LOG_MSC_T(msc_t, LOGL_ERROR, "Incoming call for inter-MSC call forwarding," " but this MSC-T role already has an MNCC FSM set up\n"); return NULL; } if (!msc_t->inter_msc.call_leg || !msc_t->inter_msc.call_leg->rtp[RTP_TO_CN]) { LOG_MSC_T(msc_t, LOGL_ERROR, "Incoming call for inter-MSC call forwarding," " but this MSC-T has no RTP stream ready for MNCC\n"); return NULL; } mncc_call = mncc_call_alloc(msc_t_vsub(msc_t), msc_t->c.fi, MSC_MNCC_EV_CALL_COMPLETE, MSC_MNCC_EV_CALL_ENDED, msc_t_mncc_cb, msc_t); if (!mncc_call) { LOG_MSC_T(msc_t, LOGL_ERROR, "Failed to set up call forwarding from remote MSC\n"); return NULL; } msc_t->inter_msc.mncc_forwarding_to_remote_cn = mncc_call; if (mncc_call_set_rtp_stream(mncc_call, msc_t->inter_msc.call_leg->rtp[RTP_TO_CN])) { LOG_MSC_T(msc_t, LOGL_ERROR, "Failed to set up call forwarding from remote MSC\n"); osmo_fsm_inst_term(mncc_call->fi, OSMO_FSM_TERM_REGULAR, NULL); return NULL; } req = (struct mncc_call_incoming_req){ .setup_req_msg = *msg, .bearer_cap_present = true, .bearer_cap = { /* TODO derive values from actual config */ /* FIXME are there no defines or enums for these numbers!? */ /* Table 10.5.102/3GPP TS 24.008: Bearer capability information element: * octet 3 of bearer cap for speech says 3 = "1 1 dual rate support MS/full rate speech version * 1 preferred, half rate speech version 1 also supported" */ .radio = 3, /* Table 10.5.103/3GPP TS 24.008 Bearer capability information element: * 0: FR1, 2: FR2, 4: FR3, 1: HR1, 5: HR3, actually in this order. -1 marks the end of the list. */ .speech_ver = { 0, 2, 4, 1, 5, -1 }, }, }; if (mncc_call_incoming_start(mncc_call, &req)) { LOG_MSC_T(msc_t, LOGL_ERROR, "Failed to set up call forwarding from remote MSC\n"); osmo_fsm_inst_term(mncc_call->fi, OSMO_FSM_TERM_REGULAR, NULL); return NULL; } return mncc_call; } static void msc_t_fsm_cleanup(struct osmo_fsm_inst *fi, enum osmo_fsm_term_cause cause) { struct msc_t *msc_t = msc_t_priv(fi); if (!msc_t->ho_success && !msc_t->ho_fail_sent) msc_t_send_handover_failure(msc_t, GSM0808_CAUSE_EQUIPMENT_FAILURE); if (msc_t->ran_conn) ran_conn_msc_role_gone(msc_t->ran_conn, msc_t->c.fi); } #define S(x) (1 << (x)) static const struct osmo_fsm_state msc_t_fsm_states[] = { [MSC_T_ST_PENDING_FIRST_CO_INITIAL_MSG] = { .name = "PENDING_FIRST_CO_INITIAL_MSG", .action = msc_t_fsm_pending_first_co_initial_msg, .in_event_mask = 0 | S(MSC_T_EV_FROM_A_PREPARE_HANDOVER_REQUEST) | S(MSC_T_EV_CN_CLOSE) , .out_state_mask = 0 | S(MSC_T_ST_WAIT_LOCAL_RTP) | S(MSC_T_ST_WAIT_HO_REQUEST_ACK) , }, [MSC_T_ST_WAIT_LOCAL_RTP] = { .name = "WAIT_LOCAL_RTP", .onenter = msc_t_fsm_wait_local_rtp_onenter, .action = msc_t_fsm_wait_local_rtp, .in_event_mask = 0 | S(MSC_EV_CALL_LEG_RTP_LOCAL_ADDR_AVAILABLE) | S(MSC_EV_CALL_LEG_TERM) | S(MSC_MNCC_EV_CALL_ENDED) | S(MSC_T_EV_CN_CLOSE) , .out_state_mask = 0 | S(MSC_T_ST_WAIT_HO_REQUEST_ACK) , }, [MSC_T_ST_WAIT_HO_REQUEST_ACK] = { .name = "WAIT_HO_REQUEST_ACK", .action = msc_t_fsm_wait_ho_request_ack, .in_event_mask = 0 | S(MSC_EV_FROM_RAN_UP_L2) | S(MSC_EV_FROM_RAN_CONN_RELEASED) | S(MSC_EV_CALL_LEG_TERM) | S(MSC_MNCC_EV_CALL_ENDED) | S(MSC_T_EV_FROM_A_FORWARD_ACCESS_SIGNALLING_REQUEST) | S(MSC_T_EV_CN_CLOSE) | S(MSC_T_EV_MO_CLOSE) , .out_state_mask = 0 | S(MSC_T_ST_WAIT_HO_COMPLETE) , }, [MSC_T_ST_WAIT_HO_COMPLETE] = { .name = "WAIT_HO_COMPLETE", .action = msc_t_fsm_wait_ho_complete, .in_event_mask = 0 | S(MSC_EV_FROM_RAN_UP_L2) | S(MSC_EV_FROM_RAN_CONN_RELEASED) | S(MSC_EV_CALL_LEG_TERM) | S(MSC_MNCC_EV_CALL_ENDED) | S(MSC_T_EV_FROM_A_FORWARD_ACCESS_SIGNALLING_REQUEST) | S(MSC_T_EV_CN_CLOSE) | S(MSC_T_EV_MO_CLOSE) , }, }; const struct value_string msc_t_fsm_event_names[] = { OSMO_VALUE_STRING(MSC_REMOTE_EV_RX_GSUP), OSMO_VALUE_STRING(MSC_EV_CALL_LEG_RTP_LOCAL_ADDR_AVAILABLE), OSMO_VALUE_STRING(MSC_EV_CALL_LEG_RTP_COMPLETE), OSMO_VALUE_STRING(MSC_EV_CALL_LEG_TERM), OSMO_VALUE_STRING(MSC_MNCC_EV_NEED_LOCAL_RTP), OSMO_VALUE_STRING(MSC_MNCC_EV_CALL_PROCEEDING), OSMO_VALUE_STRING(MSC_MNCC_EV_CALL_COMPLETE), OSMO_VALUE_STRING(MSC_MNCC_EV_CALL_ENDED), OSMO_VALUE_STRING(MSC_EV_FROM_RAN_COMPLETE_LAYER_3), OSMO_VALUE_STRING(MSC_EV_FROM_RAN_UP_L2), OSMO_VALUE_STRING(MSC_EV_FROM_RAN_CONN_RELEASED), OSMO_VALUE_STRING(MSC_T_EV_FROM_A_PREPARE_HANDOVER_REQUEST), OSMO_VALUE_STRING(MSC_T_EV_FROM_A_FORWARD_ACCESS_SIGNALLING_REQUEST), OSMO_VALUE_STRING(MSC_T_EV_CN_CLOSE), OSMO_VALUE_STRING(MSC_T_EV_MO_CLOSE), OSMO_VALUE_STRING(MSC_T_EV_CLEAR_COMPLETE), {} }; static struct osmo_fsm msc_t_fsm = { .name = "msc_t", .states = msc_t_fsm_states, .num_states = ARRAY_SIZE(msc_t_fsm_states), .log_subsys = DMSC, .event_names = msc_t_fsm_event_names, .cleanup = msc_t_fsm_cleanup, }; static __attribute__((constructor)) void msc_t_fsm_init(void) { OSMO_ASSERT(osmo_fsm_register(&msc_t_fsm) == 0); } /* Send connection-oriented L3 message to RAN peer (MSC->[BSC|RNC]) */ int msc_t_down_l2_co(struct msc_t *msc_t, const struct an_apdu *an_apdu, bool initial) { int rc; if (!msc_t->ran_conn) { LOG_MSC_T(msc_t, LOGL_ERROR, "Cannot Tx L2 message: no RAN conn\n"); return -EIO; } if (an_apdu->an_proto != msc_t->c.ran->an_proto) { LOG_MSC_T(msc_t, LOGL_ERROR, "Mismatching AN-APDU proto: %s -- Dropping message\n", an_proto_name(an_apdu->an_proto)); return -EIO; } rc = ran_conn_down_l2_co(msc_t->ran_conn, an_apdu->msg, initial); if (rc) LOG_MSC_T(msc_t, LOGL_ERROR, "Failed to transfer message down to new RAN peer (rc=%d)\n", rc); return rc; } struct gsm_network *msc_t_net(const struct msc_t *msc_t) { return msub_net(msc_t->c.msub); } struct vlr_subscr *msc_t_vsub(const struct msc_t *msc_t) { if (!msc_t) return NULL; return msub_vsub(msc_t->c.msub); } struct msc_t *msc_t_alloc_without_ran_peer(struct msub *msub, struct ran_infra *ran) { struct msc_t *msc_t; msub_role_alloc(msub, MSC_ROLE_T, &msc_t_fsm, struct msc_t, ran); msc_t = msub_msc_t(msub); if (!msc_t) return NULL; return msc_t; } int msc_t_set_ran_peer(struct msc_t *msc_t, struct ran_peer *ran_peer) { if (!ran_peer || !ran_peer->sri || !ran_peer->sri->ran) { LOG_MSC_T(msc_t, LOGL_ERROR, "Invalid RAN peer: %s\n", ran_peer ? ran_peer->fi->id : "NULL"); return -EINVAL; } if (ran_peer->sri->ran != msc_t->c.ran) { LOG_MSC_T(msc_t, LOGL_ERROR, "This MSC-T was set up for %s, cannot assign RAN peer for %s\n", osmo_rat_type_name(msc_t->c.ran->type), osmo_rat_type_name(ran_peer->sri->ran->type)); return -EINVAL; } /* Create a new ran_conn with a fresh conn_id for the outgoing initial message. The msc_t FSM definition ensures * that the first message sent or received is a Connection-Oriented Initial message. */ msc_t->ran_conn = ran_conn_create_outgoing(ran_peer); if (!msc_t->ran_conn) { LOG_MSC_T(msc_t, LOGL_ERROR, "Failed to create outgoing RAN conn\n"); return -EINVAL; } msc_t->ran_conn->msc_role = msc_t->c.fi; msub_update_id(msc_t->c.msub); return 0; } struct msc_t *msc_t_alloc(struct msub *msub, struct ran_peer *ran_peer) { struct msc_t *msc_t = msc_t_alloc_without_ran_peer(msub, ran_peer->sri->ran); if (!msc_t) return NULL; if (msc_t_set_ran_peer(msc_t, ran_peer)) { msc_t_clear(msc_t); return NULL; } return msc_t; } void msc_t_clear(struct msc_t *msc_t) { if (!msc_t) return; osmo_fsm_inst_term(msc_t->c.fi, OSMO_FSM_TERM_REGULAR, msc_t->c.fi); }