Neels Hofmeyr | c4628a3 | 2018-12-07 14:47:34 +0100 | [diff] [blame] | 1 | /* The MSC-T role, a transitional RAN connection during Handover. */ |
| 2 | /* |
Vadim Yanitskiy | 999a593 | 2023-05-18 17:22:26 +0700 | [diff] [blame] | 3 | * (C) 2019 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de> |
Neels Hofmeyr | c4628a3 | 2018-12-07 14:47:34 +0100 | [diff] [blame] | 4 | * All Rights Reserved |
| 5 | * |
| 6 | * SPDX-License-Identifier: AGPL-3.0+ |
| 7 | * |
| 8 | * Author: Neels Hofmeyr |
| 9 | * |
| 10 | * This program is free software; you can redistribute it and/or modify |
| 11 | * it under the terms of the GNU Affero General Public License as published by |
| 12 | * the Free Software Foundation; either version 3 of the License, or |
| 13 | * (at your option) any later version. |
| 14 | * |
| 15 | * This program is distributed in the hope that it will be useful, |
| 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 18 | * GNU Affero General Public License for more details. |
| 19 | * |
| 20 | * You should have received a copy of the GNU Affero General Public License |
| 21 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 22 | */ |
| 23 | |
| 24 | #include <inttypes.h> |
| 25 | |
| 26 | #include <osmocom/gsm/gsm48_ie.h> |
| 27 | |
| 28 | #include <osmocom/msc/msc_t.h> |
| 29 | #include <osmocom/msc/msc_a.h> |
| 30 | #include <osmocom/msc/msc_a_remote.h> |
| 31 | #include <osmocom/msc/ran_infra.h> |
| 32 | #include <osmocom/msc/ran_peer.h> |
| 33 | #include <osmocom/msc/ran_conn.h> |
| 34 | #include <osmocom/msc/msub.h> |
| 35 | #include <osmocom/msc/call_leg.h> |
| 36 | #include <osmocom/msc/rtp_stream.h> |
| 37 | #include <osmocom/msc/ran_infra.h> |
| 38 | #include <osmocom/msc/vlr.h> |
| 39 | #include <osmocom/msc/msc_i.h> |
| 40 | #include <osmocom/msc/gsm_data.h> |
Neels Hofmeyr | 7934e0d | 2022-10-31 18:13:47 +0100 | [diff] [blame] | 41 | #include <osmocom/msc/codec_mapping.h> |
Neels Hofmeyr | c4628a3 | 2018-12-07 14:47:34 +0100 | [diff] [blame] | 42 | |
| 43 | static struct osmo_fsm msc_t_fsm; |
| 44 | |
| 45 | static struct msc_t *msc_t_find_by_handover_number(const char *handover_number) |
| 46 | { |
| 47 | struct msub *msub; |
| 48 | |
| 49 | llist_for_each_entry(msub, &msub_list, entry) { |
| 50 | struct msc_t *msc_t = msub_msc_t(msub); |
| 51 | if (!msc_t) |
| 52 | continue; |
| 53 | if (!*msc_t->inter_msc.handover_number) |
| 54 | continue; |
| 55 | if (strcmp(msc_t->inter_msc.handover_number, handover_number)) |
| 56 | continue; |
| 57 | /* Found the assigned Handover Number */ |
| 58 | return msc_t; |
| 59 | } |
| 60 | return NULL; |
| 61 | } |
| 62 | |
| 63 | static uint64_t net_handover_number_next(struct gsm_network *net) |
| 64 | { |
| 65 | uint64_t nr; |
| 66 | if (net->handover_number.next < net->handover_number.range_start |
| 67 | || net->handover_number.next > net->handover_number.range_end) |
| 68 | net->handover_number.next = net->handover_number.range_start; |
| 69 | nr = net->handover_number.next; |
| 70 | net->handover_number.next++; |
| 71 | return nr; |
| 72 | } |
| 73 | |
| 74 | static int msc_t_assign_handover_number(struct msc_t *msc_t) |
| 75 | { |
| 76 | int rc; |
| 77 | uint64_t started_at; |
| 78 | uint64_t ho_nr; |
Vadim Yanitskiy | 8b0737f | 2019-05-25 19:27:17 +0700 | [diff] [blame] | 79 | char ho_nr_str[GSM23003_MSISDN_MAX_DIGITS+1]; |
Neels Hofmeyr | c4628a3 | 2018-12-07 14:47:34 +0100 | [diff] [blame] | 80 | struct gsm_network *net = msc_t_net(msc_t); |
| 81 | bool usable = false; |
| 82 | |
| 83 | started_at = ho_nr = net_handover_number_next(net); |
| 84 | |
| 85 | if (!ho_nr) { |
| 86 | LOG_MSC_T(msc_t, LOGL_ERROR, "No Handover Number range defined in MSC config\n"); |
| 87 | return -ENOENT; |
| 88 | } |
| 89 | |
| 90 | do { |
| 91 | rc = snprintf(ho_nr_str, sizeof(ho_nr_str), "%"PRIu64, ho_nr); |
| 92 | if (rc <= 0 || rc >= sizeof(ho_nr_str)) { |
| 93 | LOG_MSC_T(msc_t, LOGL_ERROR, "Cannot compose Handover Number string (rc=%d)\n", rc); |
| 94 | return -EINVAL; |
| 95 | } |
| 96 | |
| 97 | if (!msc_t_find_by_handover_number(ho_nr_str)) { |
| 98 | usable = true; |
| 99 | break; |
| 100 | } |
| 101 | |
| 102 | ho_nr = net_handover_number_next(net); |
| 103 | } while(ho_nr != started_at); |
| 104 | |
| 105 | if (!usable) { |
| 106 | LOG_MSC_T(msc_t, LOGL_ERROR, "No Handover Number available\n"); |
| 107 | return -EINVAL; |
| 108 | } |
| 109 | |
| 110 | LOG_MSC_T(msc_t, LOGL_INFO, "Assigning Handover Number %s\n", ho_nr_str); |
| 111 | OSMO_STRLCPY_ARRAY(msc_t->inter_msc.handover_number, ho_nr_str); |
| 112 | return 0; |
| 113 | } |
| 114 | |
| 115 | |
| 116 | static struct msc_t *msc_t_priv(struct osmo_fsm_inst *fi) |
| 117 | { |
| 118 | OSMO_ASSERT(fi); |
| 119 | OSMO_ASSERT(fi->fsm == &msc_t_fsm); |
| 120 | OSMO_ASSERT(fi->priv); |
| 121 | return fi->priv; |
| 122 | } |
| 123 | |
| 124 | /* As a macro to log the caller's source file and line. |
| 125 | * Assumes presence of local msc_t variable. */ |
| 126 | #define msc_t_error(fmt, args...) do { \ |
| 127 | msc_t->ho_success = false; \ |
| 128 | LOG_MSC_T(msc_t, LOGL_ERROR, fmt, ##args); \ |
| 129 | msc_t_clear(msc_t); \ |
| 130 | } while(0) |
| 131 | |
| 132 | static void msc_t_send_handover_failure(struct msc_t *msc_t, enum gsm0808_cause cause) |
| 133 | { |
| 134 | struct ran_msg ran_enc_msg = { |
| 135 | .msg_type = RAN_MSG_HANDOVER_FAILURE, |
| 136 | .handover_failure = { |
| 137 | .cause = cause, |
| 138 | }, |
| 139 | }; |
| 140 | struct an_apdu an_apdu = { |
| 141 | .an_proto = msc_t->c.ran->an_proto, |
| 142 | .msg = msc_role_ran_encode(msc_t->c.fi, &ran_enc_msg), |
| 143 | }; |
| 144 | msc_t->ho_fail_sent = true; |
| 145 | if (!an_apdu.msg) |
| 146 | return; |
| 147 | |
| 148 | msub_role_dispatch(msc_t->c.msub, MSC_ROLE_A, MSC_A_EV_FROM_T_PREPARE_HANDOVER_FAILURE, &an_apdu); |
Neels Hofmeyr | c4628a3 | 2018-12-07 14:47:34 +0100 | [diff] [blame] | 149 | } |
| 150 | |
| 151 | static int msc_t_ho_request_decode_and_store_cb(struct osmo_fsm_inst *msc_t_fi, void *data, |
| 152 | const struct ran_msg *ran_dec) |
| 153 | { |
| 154 | struct msc_t *msc_t = msc_t_priv(msc_t_fi); |
| 155 | |
| 156 | if (ran_dec->msg_type != RAN_MSG_HANDOVER_REQUEST) { |
| 157 | LOG_MSC_T(msc_t, LOGL_DEBUG, "Expected %s in incoming inter-MSC Handover message, got %s\n", |
| 158 | ran_msg_type_name(RAN_MSG_HANDOVER_REQUEST), ran_msg_type_name(ran_dec->msg_type)); |
| 159 | return -EINVAL; |
| 160 | } |
| 161 | |
| 162 | msc_t->inter_msc.cell_id_target = ran_dec->handover_request.cell_id_target; |
Andreas Eversberg | 712b28e | 2023-06-21 11:17:26 +0200 | [diff] [blame] | 163 | msc_t->inter_msc.call_id = ran_dec->handover_request.call_id; |
Neels Hofmeyr | c4628a3 | 2018-12-07 14:47:34 +0100 | [diff] [blame] | 164 | |
| 165 | /* TODO other parameters...? |
| 166 | * Global Call Reference |
| 167 | */ |
| 168 | return 0; |
| 169 | } |
| 170 | |
| 171 | /* On an icoming Handover Request from a remote MSC, we first need to set up an MGW endpoint, because the BSC needs to |
| 172 | * know our AoIP Transport Layer Address in the Handover Request message (which obviously the remote MSC doesn't send, |
| 173 | * it needs to be our local RTP address). Creating the MGW endpoint this is asynchronous, so we need to store the |
| 174 | * Handover Request data to forward to the BSC once the MGW endpoint is known. |
| 175 | */ |
| 176 | static int msc_t_decode_and_store_ho_request(struct msc_t *msc_t, const struct an_apdu *an_apdu) |
| 177 | { |
| 178 | if (msc_role_ran_decode(msc_t->c.fi, an_apdu, msc_t_ho_request_decode_and_store_cb, NULL)) { |
| 179 | msc_t_error("Failed to decode Handover Request\n"); |
| 180 | return -ENOTSUP; |
| 181 | } |
| 182 | /* Ok, decoding done, and above msc_t_ho_request_decode_and_store_cb() has retrieved what info we need at this |
| 183 | * point and stored it in msc_t->inter_msc.* */ |
| 184 | |
| 185 | /* We're storing this for use after async events, so need to make sure that each and every bit of data is copied |
| 186 | * and no longer references some msgb that might be deallocated when this returns, nor remains in a local stack |
| 187 | * variable of some ran_decode implementation. The simplest is to store the entire msgb. */ |
| 188 | msc_t->inter_msc.ho_request = (struct an_apdu) { |
| 189 | .an_proto = an_apdu->an_proto, |
| 190 | .msg = msgb_copy(an_apdu->msg, "saved inter-MSC Handover Request"), |
| 191 | /* A decoded osmo_gsup_message often still references memory of within the msgb the GSUP was received |
| 192 | * in. So, any info from an_apdu->e_info that would be needed would have to be copied separately. |
| 193 | * Omit e_info completely. */ |
| 194 | }; |
| 195 | return 0; |
| 196 | } |
| 197 | |
| 198 | /* On an incoming Handover Request from a remote MSC, the target cell was transmitted in the Handover Request message. |
| 199 | * Find the RAN peer and assign from the cell id decoded above in msc_t_decode_and_store_ho_request(). */ |
| 200 | static int msc_t_find_ran_peer_from_ho_request(struct msc_t *msc_t) |
| 201 | { |
| 202 | struct msc_a *msc_a = msub_msc_a(msc_t->c.msub); |
| 203 | const struct neighbor_ident_entry *nie; |
| 204 | struct ran_peer *rp_from_neighbor_ident; |
| 205 | struct ran_peer *rp; |
| 206 | |
| 207 | switch (msc_ho_find_target_cell(msc_a, &msc_t->inter_msc.cell_id_target, |
| 208 | &nie, &rp_from_neighbor_ident, &rp)) { |
| 209 | case MSC_NEIGHBOR_TYPE_REMOTE_MSC: |
| 210 | msc_t_error("Incoming Handover Request indicated target cell that belongs to a remote MSC:" |
| 211 | " Cell ID: %s; remote MSC: %s\n", |
| 212 | gsm0808_cell_id_name(&msc_t->inter_msc.cell_id_target), |
| 213 | neighbor_ident_addr_name(&nie->addr)); |
| 214 | return -EINVAL; |
| 215 | |
| 216 | case MSC_NEIGHBOR_TYPE_NONE: |
| 217 | msc_t_error("Incoming Handover Request for unknown cell %s\n", |
| 218 | gsm0808_cell_id_name(&msc_t->inter_msc.cell_id_target)); |
| 219 | return -EINVAL; |
| 220 | |
| 221 | case MSC_NEIGHBOR_TYPE_LOCAL_RAN_PEER: |
| 222 | /* That's what is expected: a local RAN peer, e.g. BSC, or a remote BSC from neighbor cfg. */ |
| 223 | if (!rp) |
| 224 | rp = rp_from_neighbor_ident; |
| 225 | break; |
| 226 | } |
| 227 | |
| 228 | OSMO_ASSERT(rp); |
| 229 | LOG_MSC_T(msc_t, LOGL_DEBUG, "Incoming Handover Request indicates target cell %s," |
| 230 | " which belongs to RAN peer %s\n", |
| 231 | gsm0808_cell_id_name(&msc_t->inter_msc.cell_id_target), rp->fi->id); |
| 232 | |
| 233 | /* Finally we know where to direct the Handover */ |
| 234 | msc_t_set_ran_peer(msc_t, rp); |
| 235 | return 0; |
| 236 | } |
| 237 | |
| 238 | static int msc_t_send_stored_ho_request__decode_cb(struct osmo_fsm_inst *msc_t_fi, void *data, |
| 239 | const struct ran_msg *ran_dec) |
| 240 | { |
Neels Hofmeyr | c4628a3 | 2018-12-07 14:47:34 +0100 | [diff] [blame] | 241 | struct an_apdu an_apdu; |
| 242 | struct msc_t *msc_t = msc_t_priv(msc_t_fi); |
| 243 | struct osmo_sockaddr_str *rtp_ran_local = data; |
| 244 | |
| 245 | /* Copy ran_dec message to un-const so we can add the AoIP Transport Layer Address. All pointer references still |
| 246 | * remain on the same memory as ran_dec, which is fine. We're just going to encode it again right away. */ |
| 247 | struct ran_msg ran_enc = *ran_dec; |
| 248 | |
| 249 | if (ran_dec->msg_type != RAN_MSG_HANDOVER_REQUEST) { |
| 250 | LOG_MSC_T(msc_t, LOGL_DEBUG, "Expected %s in incoming inter-MSC Handover message, got %s\n", |
| 251 | ran_msg_type_name(RAN_MSG_HANDOVER_REQUEST), ran_msg_type_name(ran_dec->msg_type)); |
| 252 | return -EINVAL; |
| 253 | } |
| 254 | |
| 255 | /* Insert AoIP Transport Layer Address */ |
| 256 | ran_enc.handover_request.rtp_ran_local = rtp_ran_local; |
| 257 | |
| 258 | /* Finally ready to forward to BSC: encode and send out. */ |
| 259 | an_apdu = (struct an_apdu){ |
| 260 | .an_proto = msc_t->inter_msc.ho_request.an_proto, |
| 261 | .msg = msc_role_ran_encode(msc_t->c.fi, &ran_enc), |
| 262 | }; |
| 263 | if (!an_apdu.msg) |
| 264 | return -EIO; |
Vadim Yanitskiy | c44342b | 2021-12-07 18:32:35 +0300 | [diff] [blame] | 265 | return msc_t_down_l2_co(msc_t, &an_apdu, true); |
Neels Hofmeyr | c4628a3 | 2018-12-07 14:47:34 +0100 | [diff] [blame] | 266 | } |
| 267 | |
| 268 | /* The MGW endpoint is created, we know our AoIP Transport Layer Address and can send the Handover Request to the RAN |
| 269 | * peer. */ |
| 270 | static int msc_t_send_stored_ho_request(struct msc_t *msc_t) |
| 271 | { |
| 272 | struct osmo_sockaddr_str *rtp_ran_local = call_leg_local_ip(msc_t->inter_msc.call_leg, RTP_TO_RAN); |
| 273 | if (!rtp_ran_local) { |
| 274 | msc_t_error("Local RTP address towards RAN is not set up properly, cannot send Handover Request\n"); |
| 275 | return -EINVAL; |
| 276 | } |
| 277 | |
| 278 | /* The Handover Request received from the remote MSC is fed through, except we need to insert our local AoIP |
| 279 | * Transport Layer Address, i.e. the RTP IP:port of the MGW towards the RAN side. So we actually need to decode, |
| 280 | * add the AoIP and re-encode. By nature of decoding, it goes through the decode callback. */ |
| 281 | return msc_role_ran_decode(msc_t->c.fi, &msc_t->inter_msc.ho_request, |
| 282 | msc_t_send_stored_ho_request__decode_cb, rtp_ran_local); |
| 283 | } |
| 284 | |
| 285 | static void msc_t_fsm_pending_first_co_initial_msg(struct osmo_fsm_inst *fi, uint32_t event, void *data) |
| 286 | { |
| 287 | struct msc_t *msc_t = msc_t_priv(fi); |
| 288 | struct msc_a *msc_a = msub_msc_a(msc_t->c.msub); |
| 289 | struct an_apdu *an_apdu; |
| 290 | |
| 291 | OSMO_ASSERT(msc_a); |
| 292 | |
| 293 | switch (event) { |
| 294 | |
| 295 | case MSC_T_EV_FROM_A_PREPARE_HANDOVER_REQUEST: |
| 296 | /* For an inter-MSC Handover coming in from a remote MSC, we do not yet know the RAN peer and AoIP |
| 297 | * Transport Layer Address. |
| 298 | * - RAN peer is found by decoding the actual Handover Request message and looking for the Cell |
| 299 | * Identifier (Target). |
| 300 | * - To be able to tell the BSC about an AoIP Transport Layer Address, we first need to create an MGW |
| 301 | * endpoint. |
| 302 | * For mere inter-BSC Handover, we know all of the above already. Find out which one this is. |
| 303 | */ |
| 304 | an_apdu = data; |
| 305 | if (!msc_a->c.remote_to) { |
| 306 | /* Inter-BSC */ |
| 307 | |
| 308 | osmo_fsm_inst_state_chg(msc_t->c.fi, MSC_T_ST_WAIT_HO_REQUEST_ACK, 0, 0); |
| 309 | /* Inter-BSC. All should be set up, just forward the message. */ |
| 310 | if (msc_t_down_l2_co(msc_t, an_apdu, true)) |
| 311 | msc_t_error("Failed to send AN-APDU to RAN peer\n"); |
| 312 | } else { |
| 313 | /* Inter-MSC */ |
| 314 | |
| 315 | if (msc_t->ran_conn) { |
| 316 | msc_t_error("Unexpected state for inter-MSC Handover: RAN peer is already set up\n"); |
| 317 | return; |
| 318 | } |
| 319 | |
| 320 | if (msc_t_decode_and_store_ho_request(msc_t, an_apdu)) |
| 321 | return; |
| 322 | |
| 323 | if (msc_t_find_ran_peer_from_ho_request(msc_t)) |
| 324 | return; |
| 325 | |
| 326 | /* Relying on timeout of the MGW operations, see onenter() for this state. */ |
| 327 | osmo_fsm_inst_state_chg(msc_t->c.fi, MSC_T_ST_WAIT_LOCAL_RTP, 0, 0); |
| 328 | } |
| 329 | return; |
| 330 | |
| 331 | case MSC_T_EV_CN_CLOSE: |
| 332 | msc_t_clear(msc_t); |
| 333 | return; |
| 334 | |
| 335 | default: |
| 336 | OSMO_ASSERT(false); |
| 337 | } |
| 338 | } |
| 339 | |
| 340 | void msc_t_fsm_wait_local_rtp_onenter(struct osmo_fsm_inst *fi, uint32_t prev_state) |
| 341 | { |
| 342 | struct msc_t *msc_t = msc_t_priv(fi); |
| 343 | struct msc_a *msc_a = msub_msc_a(msc_t->c.msub); |
| 344 | |
| 345 | /* This only happens on inter-MSC HO incoming from a remote MSC */ |
| 346 | if (!msc_a->c.remote_to) { |
| 347 | msc_t_error("Unexpected state: this is not an inter-MSC Handover\n"); |
| 348 | return; |
| 349 | } |
| 350 | |
| 351 | if (msc_t->inter_msc.call_leg) { |
| 352 | msc_t_error("Unexpected state: call leg already set up\n"); |
| 353 | return; |
| 354 | } |
| 355 | |
| 356 | msc_t->inter_msc.call_leg = call_leg_alloc(msc_t->c.fi, |
| 357 | MSC_EV_CALL_LEG_TERM, |
| 358 | MSC_EV_CALL_LEG_RTP_LOCAL_ADDR_AVAILABLE, |
Neels Hofmeyr | 265a4c7 | 2019-05-09 16:20:51 +0200 | [diff] [blame] | 359 | MSC_EV_CALL_LEG_RTP_COMPLETE); |
Neels Hofmeyr | c4628a3 | 2018-12-07 14:47:34 +0100 | [diff] [blame] | 360 | if (!msc_t->inter_msc.call_leg |
Andreas Eversberg | 712b28e | 2023-06-21 11:17:26 +0200 | [diff] [blame] | 361 | || call_leg_ensure_ci(msc_t->inter_msc.call_leg, RTP_TO_RAN, msc_t->inter_msc.call_id, NULL, NULL, NULL) |
| 362 | || call_leg_ensure_ci(msc_t->inter_msc.call_leg, RTP_TO_CN, msc_t->inter_msc.call_id, NULL, NULL, NULL)) { |
Neels Hofmeyr | c4628a3 | 2018-12-07 14:47:34 +0100 | [diff] [blame] | 363 | msc_t_error("Failed to set up call leg\n"); |
| 364 | return; |
| 365 | } |
| 366 | /* Now wait for two MSC_EV_CALL_LEG_RTP_LOCAL_ADDR_AVAILABLE, one per RTP connection */ |
| 367 | } |
| 368 | |
| 369 | void msc_t_fsm_wait_local_rtp(struct osmo_fsm_inst *fi, uint32_t event, void *data) |
| 370 | { |
| 371 | struct msc_t *msc_t = msc_t_priv(fi); |
| 372 | struct rtp_stream *rtps; |
| 373 | |
| 374 | switch (event) { |
| 375 | case MSC_EV_CALL_LEG_RTP_LOCAL_ADDR_AVAILABLE: |
| 376 | rtps = data; |
| 377 | if (!rtps) { |
| 378 | msc_t_error("Invalid data for MSC_EV_CALL_LEG_RTP_LOCAL_ADDR_AVAILABLE\n"); |
| 379 | return; |
| 380 | } |
| 381 | /* If both to-RAN and to-CN sides have a CI set up, we can continue. */ |
| 382 | if (!call_leg_local_ip(msc_t->inter_msc.call_leg, RTP_TO_RAN) |
| 383 | || !call_leg_local_ip(msc_t->inter_msc.call_leg, RTP_TO_CN)) |
| 384 | return; |
| 385 | |
| 386 | osmo_fsm_inst_state_chg(msc_t->c.fi, MSC_T_ST_WAIT_HO_REQUEST_ACK, 0, 0); |
| 387 | msc_t_send_stored_ho_request(msc_t); |
| 388 | return; |
| 389 | |
Neels Hofmeyr | c4628a3 | 2018-12-07 14:47:34 +0100 | [diff] [blame] | 390 | case MSC_EV_CALL_LEG_TERM: |
| 391 | msc_t->inter_msc.call_leg = NULL; |
| 392 | msc_t_error("Failed to set up MGW endpoint\n"); |
| 393 | return; |
| 394 | |
| 395 | case MSC_MNCC_EV_CALL_ENDED: |
| 396 | msc_t->inter_msc.mncc_forwarding_to_remote_cn = NULL; |
| 397 | return; |
| 398 | |
| 399 | case MSC_T_EV_CN_CLOSE: |
| 400 | case MSC_T_EV_MO_CLOSE: |
| 401 | msc_t_clear(msc_t); |
| 402 | return; |
| 403 | |
| 404 | default: |
| 405 | OSMO_ASSERT(false); |
| 406 | } |
| 407 | } |
| 408 | |
| 409 | static int msc_t_patch_and_send_ho_request_ack(struct msc_t *msc_t, const struct an_apdu *incoming_an_apdu, |
| 410 | const struct ran_msg *ran_dec) |
| 411 | { |
| 412 | int rc; |
| 413 | struct rtp_stream *rtp_ran = msc_t->inter_msc.call_leg? msc_t->inter_msc.call_leg->rtp[RTP_TO_RAN] : NULL; |
| 414 | struct rtp_stream *rtp_cn = msc_t->inter_msc.call_leg? msc_t->inter_msc.call_leg->rtp[RTP_TO_CN] : NULL; |
| 415 | /* Since it's BCD, it needs rounded-up half the char* length of an MSISDN plus a type byte. |
| 416 | * But no need to introduce obscure math to save a few stack bytes, just have more. */ |
Vadim Yanitskiy | 8b0737f | 2019-05-25 19:27:17 +0700 | [diff] [blame] | 417 | uint8_t msisdn_enc_buf[GSM23003_MSISDN_MAX_DIGITS+1]; |
Neels Hofmeyr | c4628a3 | 2018-12-07 14:47:34 +0100 | [diff] [blame] | 418 | /* Copy an_apdu and an_apdu->e_info in "copy-on-write" method, because they are const and we |
| 419 | * need to add the Handover Number to e_info. */ |
| 420 | const struct ran_handover_request_ack *r = &ran_dec->handover_request_ack; |
| 421 | struct ran_msg ran_enc = *ran_dec; |
| 422 | struct osmo_gsup_message e_info = {}; |
| 423 | struct an_apdu an_apdu = { |
| 424 | .an_proto = incoming_an_apdu->an_proto, |
| 425 | .e_info = &e_info, |
| 426 | }; |
| 427 | if (incoming_an_apdu->e_info) |
| 428 | e_info = *incoming_an_apdu->e_info; |
| 429 | |
| 430 | rc = msc_t_assign_handover_number(msc_t); |
| 431 | if (rc) |
| 432 | return rc; |
| 433 | |
| 434 | rc = gsm48_encode_bcd_number(msisdn_enc_buf, sizeof(msisdn_enc_buf), 0, |
| 435 | msc_t->inter_msc.handover_number); |
| 436 | if (rc <= 0) |
| 437 | return -EINVAL; |
| 438 | |
| 439 | e_info.msisdn_enc = msisdn_enc_buf; |
| 440 | e_info.msisdn_enc_len = rc; |
| 441 | |
| 442 | /* Also need to fetch the RTP IP:port from AoIP Transport Address IE to tell the MGW about it */ |
| 443 | if (rtp_ran) { |
Neels Hofmeyr | 84ce206 | 2019-10-05 05:15:25 +0200 | [diff] [blame] | 444 | if (osmo_sockaddr_str_is_nonzero(&r->remote_rtp)) { |
Neels Hofmeyr | c4628a3 | 2018-12-07 14:47:34 +0100 | [diff] [blame] | 445 | LOG_MSC_T(msc_t, LOGL_DEBUG, "From Handover Request Ack, got " OSMO_SOCKADDR_STR_FMT "\n", |
| 446 | OSMO_SOCKADDR_STR_FMT_ARGS(&r->remote_rtp)); |
| 447 | rtp_stream_set_remote_addr(rtp_ran, &r->remote_rtp); |
| 448 | } else { |
| 449 | LOG_MSC_T(msc_t, LOGL_DEBUG, "No RTP IP:port in Handover Request Ack\n"); |
| 450 | } |
| 451 | if (r->codec_present) { |
Neels Hofmeyr | 7934e0d | 2022-10-31 18:13:47 +0100 | [diff] [blame] | 452 | const struct codec_mapping *m = codec_mapping_by_gsm0808_speech_codec_type(r->codec.type); |
| 453 | /* TODO: use codec_mapping_by_gsm0808_speech_codec() to also match on codec.cfg */ |
| 454 | if (!m) { |
| 455 | LOG_MSC_T(msc_t, LOGL_ERROR, "Cannot resolve codec in Handover Request Ack: %s / %s\n", |
| 456 | gsm0808_speech_codec_type_name(r->codec.type), |
| 457 | m ? sdp_audio_codec_to_str(&m->sdp) : "(unknown)"); |
| 458 | } else { |
| 459 | LOG_MSC_T(msc_t, LOGL_DEBUG, "From Handover Request Ack, got codec %s / %s\n", |
| 460 | gsm0808_speech_codec_type_name(r->codec.type), |
| 461 | sdp_audio_codec_to_str(&m->sdp)); |
| 462 | rtp_stream_set_one_codec(rtp_ran, &m->sdp); |
| 463 | if (rtp_cn) |
| 464 | rtp_stream_set_one_codec(rtp_cn, &m->sdp); |
| 465 | } |
Neels Hofmeyr | c4628a3 | 2018-12-07 14:47:34 +0100 | [diff] [blame] | 466 | } else { |
| 467 | LOG_MSC_T(msc_t, LOGL_DEBUG, "No codec in Handover Request Ack\n"); |
| 468 | } |
| 469 | rtp_stream_commit(rtp_ran); |
| 470 | } else { |
| 471 | LOG_MSC_T(msc_t, LOGL_DEBUG, "No RTP to RAN set up yet\n"); |
| 472 | } |
| 473 | |
| 474 | /* Remove that AoIP Transport Layer IE so it doesn't get sent to the remote MSC */ |
| 475 | ran_enc.handover_request_ack.remote_rtp = (struct osmo_sockaddr_str){}; |
| 476 | |
| 477 | an_apdu.msg = msc_role_ran_encode(msc_t->c.fi, &ran_enc); |
| 478 | if (!an_apdu.msg) |
| 479 | return -EIO; |
| 480 | /* Send to remote MSC via msc_a_remote role */ |
Vadim Yanitskiy | c44342b | 2021-12-07 18:32:35 +0300 | [diff] [blame] | 481 | return msub_role_dispatch(msc_t->c.msub, MSC_ROLE_A, MSC_A_EV_FROM_T_PREPARE_HANDOVER_RESPONSE, &an_apdu); |
Neels Hofmeyr | c4628a3 | 2018-12-07 14:47:34 +0100 | [diff] [blame] | 482 | } |
| 483 | |
| 484 | static int msc_t_wait_ho_request_ack_decode_cb(struct osmo_fsm_inst *msc_t_fi, void *data, |
| 485 | const struct ran_msg *ran_dec) |
| 486 | { |
| 487 | int rc; |
| 488 | struct msc_t *msc_t = msc_t_priv(msc_t_fi); |
| 489 | struct msc_a *msc_a = msub_msc_a(msc_t->c.msub); |
| 490 | const struct an_apdu *an_apdu = data; |
| 491 | |
| 492 | switch (ran_dec->msg_type) { |
| 493 | case RAN_MSG_HANDOVER_REQUEST_ACK: |
| 494 | if (msc_a->c.remote_to) { |
| 495 | /* inter-MSC. Add Handover Number, remove AoIP Transport Layer Address. */ |
| 496 | rc = msc_t_patch_and_send_ho_request_ack(msc_t, an_apdu, ran_dec); |
| 497 | } else { |
| 498 | /* inter-BSC. Just send as-is, with correct event. */ |
| 499 | rc = msub_role_dispatch(msc_t->c.msub, MSC_ROLE_A, MSC_A_EV_FROM_T_PREPARE_HANDOVER_RESPONSE, |
| 500 | an_apdu); |
| 501 | } |
| 502 | if (rc) |
| 503 | msc_t_error("Failed to send HO Request Ack\n"); |
| 504 | else |
| 505 | osmo_fsm_inst_state_chg(msc_t->c.fi, MSC_T_ST_WAIT_HO_COMPLETE, 0, 0); |
| 506 | return 0; |
| 507 | |
| 508 | case RAN_MSG_HANDOVER_FAILURE: |
| 509 | msub_role_dispatch(msc_t->c.msub, MSC_ROLE_A, MSC_A_EV_FROM_T_PREPARE_HANDOVER_FAILURE, an_apdu); |
| 510 | return 0; |
| 511 | |
| 512 | case RAN_MSG_CLEAR_REQUEST: |
| 513 | msub_role_dispatch(msc_t->c.msub, MSC_ROLE_A, MSC_A_EV_FROM_T_PROCESS_ACCESS_SIGNALLING_REQUEST, |
| 514 | an_apdu); |
| 515 | return 0; |
| 516 | |
| 517 | default: |
| 518 | LOG_MSC_T(msc_t, LOGL_ERROR, "Unexpected message during Prepare Handover procedure: %s\n", |
| 519 | ran_msg_type_name(ran_dec->msg_type)); |
| 520 | /* Let's just forward anyway. */ |
| 521 | msub_role_dispatch(msc_t->c.msub, MSC_ROLE_A, MSC_A_EV_FROM_T_PROCESS_ACCESS_SIGNALLING_REQUEST, |
| 522 | an_apdu); |
| 523 | return 0; |
| 524 | } |
| 525 | } |
| 526 | |
| 527 | static void msc_t_fsm_wait_ho_request_ack(struct osmo_fsm_inst *fi, uint32_t event, void *data) |
| 528 | { |
| 529 | struct msc_t *msc_t = msc_t_priv(fi); |
| 530 | struct an_apdu *an_apdu; |
| 531 | |
| 532 | switch (event) { |
| 533 | |
| 534 | case MSC_EV_FROM_RAN_UP_L2: |
| 535 | an_apdu = data; |
| 536 | /* For inter-MSC Handover, we need to examine the message type. Depending on the response, we must |
| 537 | * dispatch MSC_A_EV_FROM_T_PREPARE_HANDOVER_RESPONSE or MSC_A_EV_FROM_T_PREPARE_HANDOVER_FAILURE, which |
| 538 | * ensures the correct E-interface message type. And we need to include the Handover Number. |
| 539 | * For mere inter-BSC Handover, we know that our osmo-msc internals don't care much about which event |
| 540 | * dispatches a Handover Failure or Handover Request Ack, so we could skip the decoding. But it is a |
| 541 | * premature optimization that complicates comparing an inter-BSC with an inter-MSC HO. */ |
| 542 | msc_role_ran_decode(msc_t->c.fi, an_apdu, msc_t_wait_ho_request_ack_decode_cb, an_apdu); |
| 543 | /* Action continues in msc_t_wait_ho_request_ack_decode_cb() */ |
| 544 | return; |
| 545 | |
| 546 | case MSC_EV_FROM_RAN_CONN_RELEASED: |
| 547 | msc_t_clear(msc_t); |
| 548 | return; |
| 549 | |
| 550 | case MSC_T_EV_FROM_A_FORWARD_ACCESS_SIGNALLING_REQUEST: |
| 551 | an_apdu = data; |
| 552 | msc_t_down_l2_co(msc_t, an_apdu, false); |
| 553 | return; |
| 554 | |
Neels Hofmeyr | c4628a3 | 2018-12-07 14:47:34 +0100 | [diff] [blame] | 555 | case MSC_EV_CALL_LEG_TERM: |
| 556 | msc_t->inter_msc.call_leg = NULL; |
| 557 | msc_t_error("Failed to set up MGW endpoint\n"); |
| 558 | return; |
| 559 | |
| 560 | case MSC_MNCC_EV_CALL_ENDED: |
| 561 | msc_t->inter_msc.mncc_forwarding_to_remote_cn = NULL; |
| 562 | return; |
| 563 | |
| 564 | case MSC_T_EV_CN_CLOSE: |
| 565 | case MSC_T_EV_MO_CLOSE: |
| 566 | msc_t_clear(msc_t); |
| 567 | return; |
| 568 | |
| 569 | default: |
| 570 | OSMO_ASSERT(false); |
| 571 | } |
| 572 | } |
| 573 | |
| 574 | static int msc_t_wait_ho_complete_decode_cb(struct osmo_fsm_inst *msc_t_fi, void *data, |
| 575 | const struct ran_msg *ran_dec) |
| 576 | { |
| 577 | struct msc_t *msc_t = msc_t_priv(msc_t_fi); |
| 578 | struct msc_a *msc_a = msub_msc_a(msc_t->c.msub); |
| 579 | struct msc_i *msc_i; |
| 580 | const struct an_apdu *an_apdu = data; |
| 581 | |
| 582 | switch (ran_dec->msg_type) { |
| 583 | case RAN_MSG_HANDOVER_COMPLETE: |
| 584 | msc_t->ho_success = true; |
| 585 | |
| 586 | /* For both inter-BSC local to this MSC and inter-MSC Handover for a remote MSC-A, forward the Handover |
| 587 | * Complete message so that the MSC-A can change the MSC-T (transitional) to a proper MSC-I role. */ |
| 588 | msub_role_dispatch(msc_t->c.msub, MSC_ROLE_A, MSC_A_EV_FROM_T_SEND_END_SIGNAL_REQUEST, an_apdu); |
| 589 | |
| 590 | /* For inter-BSC Handover, the Handover Complete event has already cleaned up this msc_t, and it is |
| 591 | * already gone and deallocated. */ |
| 592 | if (!msc_a->c.remote_to) |
| 593 | return 0; |
| 594 | |
| 595 | /* For inter-MSC Handover, the remote MSC-A only turns its msc_t_remote into an msc_i_remote on |
| 596 | * the same GSUP link. We are here on the MSC-B side of the GSUP link and have to take care of |
| 597 | * creating an MSC-I over here to match the msc_i_remote at MSC-A. */ |
| 598 | msc_i = msc_i_alloc(msc_t->c.msub, msc_t->c.ran); |
| 599 | if (!msc_i) { |
| 600 | msc_t_error("Failed to create MSC-I role\n"); |
| 601 | return -1; |
| 602 | } |
| 603 | |
| 604 | msc_i->inter_msc.mncc_forwarding_to_remote_cn = msc_t->inter_msc.mncc_forwarding_to_remote_cn; |
| 605 | mncc_call_reparent(msc_i->inter_msc.mncc_forwarding_to_remote_cn, |
| 606 | msc_i->c.fi, -1, MSC_MNCC_EV_CALL_ENDED, NULL, NULL); |
| 607 | |
| 608 | msc_i->inter_msc.call_leg = msc_t->inter_msc.call_leg; |
| 609 | call_leg_reparent(msc_i->inter_msc.call_leg, |
| 610 | msc_i->c.fi, |
| 611 | MSC_EV_CALL_LEG_TERM, |
| 612 | MSC_EV_CALL_LEG_RTP_LOCAL_ADDR_AVAILABLE, |
Neels Hofmeyr | 265a4c7 | 2019-05-09 16:20:51 +0200 | [diff] [blame] | 613 | MSC_EV_CALL_LEG_RTP_COMPLETE); |
Neels Hofmeyr | c4628a3 | 2018-12-07 14:47:34 +0100 | [diff] [blame] | 614 | |
| 615 | /* msc_i_set_ran_conn() properly "steals" the ran_conn from msc_t */ |
| 616 | msc_i_set_ran_conn(msc_i, msc_t->ran_conn); |
| 617 | |
| 618 | /* Nicked everything worth keeping from MSC-T, discard now. */ |
| 619 | msc_t_clear(msc_t); |
| 620 | return 0; |
| 621 | |
| 622 | case RAN_MSG_HANDOVER_FAILURE: |
| 623 | msub_role_dispatch(msc_t->c.msub, MSC_ROLE_A, MSC_A_EV_FROM_T_PREPARE_HANDOVER_FAILURE, an_apdu); |
| 624 | return 0; |
| 625 | |
| 626 | default: |
| 627 | LOG_MSC_T(msc_t, LOGL_ERROR, "Unexpected message during Prepare Handover procedure: %s\n", |
| 628 | ran_msg_type_name(ran_dec->msg_type)); |
| 629 | /* Let's just forward anyway. Fall thru */ |
| 630 | case RAN_MSG_HANDOVER_DETECT: |
| 631 | case RAN_MSG_CLEAR_REQUEST: |
| 632 | msub_role_dispatch(msc_t->c.msub, MSC_ROLE_A, MSC_A_EV_FROM_T_PROCESS_ACCESS_SIGNALLING_REQUEST, |
| 633 | an_apdu); |
| 634 | return 0; |
| 635 | } |
| 636 | } |
| 637 | |
| 638 | static void msc_t_fsm_wait_ho_complete(struct osmo_fsm_inst *fi, uint32_t event, void *data) |
| 639 | { |
| 640 | struct msc_t *msc_t = msc_t_priv(fi); |
| 641 | struct an_apdu *an_apdu; |
| 642 | |
| 643 | switch (event) { |
| 644 | |
| 645 | case MSC_EV_FROM_RAN_UP_L2: |
| 646 | an_apdu = data; |
| 647 | /* We need to catch the Handover Complete message in order to send it as a SendEndSignal Request */ |
| 648 | msc_role_ran_decode(msc_t->c.fi, an_apdu, msc_t_wait_ho_complete_decode_cb, an_apdu); |
| 649 | return; |
| 650 | |
| 651 | case MSC_EV_FROM_RAN_CONN_RELEASED: |
| 652 | msc_t_clear(msc_t); |
| 653 | return; |
| 654 | |
| 655 | case MSC_T_EV_FROM_A_FORWARD_ACCESS_SIGNALLING_REQUEST: |
| 656 | an_apdu = data; |
| 657 | msc_t_down_l2_co(msc_t, an_apdu, false); |
| 658 | return; |
| 659 | |
Neels Hofmeyr | c4628a3 | 2018-12-07 14:47:34 +0100 | [diff] [blame] | 660 | case MSC_EV_CALL_LEG_TERM: |
| 661 | msc_t->inter_msc.call_leg = NULL; |
| 662 | msc_t_error("Failed to set up MGW endpoint\n"); |
| 663 | return; |
| 664 | |
| 665 | case MSC_MNCC_EV_CALL_ENDED: |
| 666 | msc_t->inter_msc.mncc_forwarding_to_remote_cn = NULL; |
| 667 | return; |
| 668 | |
| 669 | case MSC_T_EV_CN_CLOSE: |
| 670 | case MSC_T_EV_MO_CLOSE: |
| 671 | msc_t_clear(msc_t); |
| 672 | return; |
| 673 | |
| 674 | default: |
| 675 | OSMO_ASSERT(false); |
| 676 | } |
| 677 | } |
| 678 | |
| 679 | void msc_t_mncc_cb(struct mncc_call *mncc_call, const union mncc_msg *mncc_msg, void *data) |
| 680 | { |
| 681 | struct msc_t *msc_t = data; |
| 682 | struct gsm_mncc_number nr = { |
| 683 | .plan = 1, |
| 684 | }; |
| 685 | OSMO_STRLCPY_ARRAY(nr.number, msc_t->inter_msc.handover_number); |
| 686 | |
| 687 | switch (mncc_msg->msg_type) { |
| 688 | case MNCC_RTP_CREATE: |
| 689 | mncc_call_incoming_tx_setup_cnf(mncc_call, &nr); |
| 690 | return; |
| 691 | default: |
| 692 | return; |
| 693 | } |
| 694 | } |
| 695 | |
| 696 | struct mncc_call *msc_t_check_call_to_handover_number(const struct gsm_mncc *msg) |
| 697 | { |
| 698 | struct msc_t *msc_t; |
| 699 | const char *handover_number; |
| 700 | struct mncc_call_incoming_req req; |
| 701 | struct mncc_call *mncc_call; |
| 702 | |
| 703 | if (!(msg->fields & MNCC_F_CALLED)) |
| 704 | return NULL; |
| 705 | |
| 706 | handover_number = msg->called.number; |
| 707 | msc_t = msc_t_find_by_handover_number(handover_number); |
| 708 | |
| 709 | if (!msc_t) |
| 710 | return NULL; |
| 711 | |
| 712 | if (msc_t->inter_msc.mncc_forwarding_to_remote_cn) { |
| 713 | LOG_MSC_T(msc_t, LOGL_ERROR, "Incoming call for inter-MSC call forwarding," |
| 714 | " but this MSC-T role already has an MNCC FSM set up\n"); |
| 715 | return NULL; |
| 716 | } |
| 717 | |
| 718 | if (!msc_t->inter_msc.call_leg |
| 719 | || !msc_t->inter_msc.call_leg->rtp[RTP_TO_CN]) { |
| 720 | LOG_MSC_T(msc_t, LOGL_ERROR, "Incoming call for inter-MSC call forwarding," |
| 721 | " but this MSC-T has no RTP stream ready for MNCC\n"); |
| 722 | return NULL; |
| 723 | } |
| 724 | |
| 725 | mncc_call = mncc_call_alloc(msc_t_vsub(msc_t), |
| 726 | msc_t->c.fi, |
| 727 | MSC_MNCC_EV_CALL_COMPLETE, |
| 728 | MSC_MNCC_EV_CALL_ENDED, |
| 729 | msc_t_mncc_cb, msc_t); |
| 730 | if (!mncc_call) { |
| 731 | LOG_MSC_T(msc_t, LOGL_ERROR, "Failed to set up call forwarding from remote MSC\n"); |
| 732 | return NULL; |
| 733 | } |
| 734 | msc_t->inter_msc.mncc_forwarding_to_remote_cn = mncc_call; |
| 735 | |
| 736 | if (mncc_call_set_rtp_stream(mncc_call, msc_t->inter_msc.call_leg->rtp[RTP_TO_CN])) { |
| 737 | LOG_MSC_T(msc_t, LOGL_ERROR, "Failed to set up call forwarding from remote MSC\n"); |
| 738 | osmo_fsm_inst_term(mncc_call->fi, OSMO_FSM_TERM_REGULAR, NULL); |
| 739 | return NULL; |
| 740 | } |
| 741 | |
| 742 | req = (struct mncc_call_incoming_req){ |
| 743 | .setup_req_msg = *msg, |
| 744 | .bearer_cap_present = true, |
| 745 | .bearer_cap = { |
| 746 | /* TODO derive values from actual config */ |
| 747 | /* FIXME are there no defines or enums for these numbers!? */ |
| 748 | /* Table 10.5.102/3GPP TS 24.008: Bearer capability information element: |
| 749 | * octet 3 of bearer cap for speech says 3 = "1 1 dual rate support MS/full rate speech version |
| 750 | * 1 preferred, half rate speech version 1 also supported" */ |
| 751 | .radio = 3, |
| 752 | /* Table 10.5.103/3GPP TS 24.008 Bearer capability information element: |
| 753 | * 0: FR1, 2: FR2, 4: FR3, 1: HR1, 5: HR3, actually in this order. -1 marks the end of the list. */ |
| 754 | .speech_ver = { 0, 2, 4, 1, 5, -1 }, |
| 755 | }, |
| 756 | }; |
| 757 | if (mncc_call_incoming_start(mncc_call, &req)) { |
| 758 | LOG_MSC_T(msc_t, LOGL_ERROR, "Failed to set up call forwarding from remote MSC\n"); |
| 759 | osmo_fsm_inst_term(mncc_call->fi, OSMO_FSM_TERM_REGULAR, NULL); |
| 760 | return NULL; |
| 761 | } |
| 762 | return mncc_call; |
| 763 | } |
| 764 | |
| 765 | static void msc_t_fsm_cleanup(struct osmo_fsm_inst *fi, enum osmo_fsm_term_cause cause) |
| 766 | { |
| 767 | struct msc_t *msc_t = msc_t_priv(fi); |
| 768 | |
| 769 | if (!msc_t->ho_success && !msc_t->ho_fail_sent) |
| 770 | msc_t_send_handover_failure(msc_t, GSM0808_CAUSE_EQUIPMENT_FAILURE); |
| 771 | |
| 772 | if (msc_t->ran_conn) |
| 773 | ran_conn_msc_role_gone(msc_t->ran_conn, msc_t->c.fi); |
| 774 | } |
| 775 | |
| 776 | #define S(x) (1 << (x)) |
| 777 | |
| 778 | static const struct osmo_fsm_state msc_t_fsm_states[] = { |
| 779 | [MSC_T_ST_PENDING_FIRST_CO_INITIAL_MSG] = { |
| 780 | .name = "PENDING_FIRST_CO_INITIAL_MSG", |
| 781 | .action = msc_t_fsm_pending_first_co_initial_msg, |
| 782 | .in_event_mask = 0 |
| 783 | | S(MSC_T_EV_FROM_A_PREPARE_HANDOVER_REQUEST) |
| 784 | | S(MSC_T_EV_CN_CLOSE) |
| 785 | , |
| 786 | .out_state_mask = 0 |
| 787 | | S(MSC_T_ST_WAIT_LOCAL_RTP) |
| 788 | | S(MSC_T_ST_WAIT_HO_REQUEST_ACK) |
| 789 | , |
| 790 | }, |
| 791 | [MSC_T_ST_WAIT_LOCAL_RTP] = { |
| 792 | .name = "WAIT_LOCAL_RTP", |
| 793 | .onenter = msc_t_fsm_wait_local_rtp_onenter, |
| 794 | .action = msc_t_fsm_wait_local_rtp, |
| 795 | .in_event_mask = 0 |
| 796 | | S(MSC_EV_CALL_LEG_RTP_LOCAL_ADDR_AVAILABLE) |
Neels Hofmeyr | c4628a3 | 2018-12-07 14:47:34 +0100 | [diff] [blame] | 797 | | S(MSC_EV_CALL_LEG_TERM) |
| 798 | | S(MSC_MNCC_EV_CALL_ENDED) |
| 799 | | S(MSC_T_EV_CN_CLOSE) |
| 800 | , |
| 801 | .out_state_mask = 0 |
| 802 | | S(MSC_T_ST_WAIT_HO_REQUEST_ACK) |
| 803 | , |
| 804 | }, |
| 805 | [MSC_T_ST_WAIT_HO_REQUEST_ACK] = { |
| 806 | .name = "WAIT_HO_REQUEST_ACK", |
| 807 | .action = msc_t_fsm_wait_ho_request_ack, |
| 808 | .in_event_mask = 0 |
| 809 | | S(MSC_EV_FROM_RAN_UP_L2) |
| 810 | | S(MSC_EV_FROM_RAN_CONN_RELEASED) |
Neels Hofmeyr | c4628a3 | 2018-12-07 14:47:34 +0100 | [diff] [blame] | 811 | | S(MSC_EV_CALL_LEG_TERM) |
| 812 | | S(MSC_MNCC_EV_CALL_ENDED) |
| 813 | | S(MSC_T_EV_FROM_A_FORWARD_ACCESS_SIGNALLING_REQUEST) |
| 814 | | S(MSC_T_EV_CN_CLOSE) |
| 815 | | S(MSC_T_EV_MO_CLOSE) |
| 816 | , |
| 817 | .out_state_mask = 0 |
| 818 | | S(MSC_T_ST_WAIT_HO_COMPLETE) |
| 819 | , |
| 820 | }, |
| 821 | [MSC_T_ST_WAIT_HO_COMPLETE] = { |
| 822 | .name = "WAIT_HO_COMPLETE", |
| 823 | .action = msc_t_fsm_wait_ho_complete, |
| 824 | .in_event_mask = 0 |
| 825 | | S(MSC_EV_FROM_RAN_UP_L2) |
| 826 | | S(MSC_EV_FROM_RAN_CONN_RELEASED) |
Neels Hofmeyr | c4628a3 | 2018-12-07 14:47:34 +0100 | [diff] [blame] | 827 | | S(MSC_EV_CALL_LEG_TERM) |
| 828 | | S(MSC_MNCC_EV_CALL_ENDED) |
| 829 | | S(MSC_T_EV_FROM_A_FORWARD_ACCESS_SIGNALLING_REQUEST) |
| 830 | | S(MSC_T_EV_CN_CLOSE) |
| 831 | | S(MSC_T_EV_MO_CLOSE) |
| 832 | , |
| 833 | }, |
| 834 | }; |
| 835 | |
| 836 | const struct value_string msc_t_fsm_event_names[] = { |
| 837 | OSMO_VALUE_STRING(MSC_REMOTE_EV_RX_GSUP), |
| 838 | OSMO_VALUE_STRING(MSC_EV_CALL_LEG_RTP_LOCAL_ADDR_AVAILABLE), |
| 839 | OSMO_VALUE_STRING(MSC_EV_CALL_LEG_RTP_COMPLETE), |
Neels Hofmeyr | c4628a3 | 2018-12-07 14:47:34 +0100 | [diff] [blame] | 840 | OSMO_VALUE_STRING(MSC_EV_CALL_LEG_TERM), |
| 841 | OSMO_VALUE_STRING(MSC_MNCC_EV_NEED_LOCAL_RTP), |
| 842 | OSMO_VALUE_STRING(MSC_MNCC_EV_CALL_PROCEEDING), |
| 843 | OSMO_VALUE_STRING(MSC_MNCC_EV_CALL_COMPLETE), |
| 844 | OSMO_VALUE_STRING(MSC_MNCC_EV_CALL_ENDED), |
| 845 | |
| 846 | OSMO_VALUE_STRING(MSC_EV_FROM_RAN_COMPLETE_LAYER_3), |
| 847 | OSMO_VALUE_STRING(MSC_EV_FROM_RAN_UP_L2), |
| 848 | OSMO_VALUE_STRING(MSC_EV_FROM_RAN_CONN_RELEASED), |
| 849 | |
| 850 | OSMO_VALUE_STRING(MSC_T_EV_FROM_A_PREPARE_HANDOVER_REQUEST), |
| 851 | OSMO_VALUE_STRING(MSC_T_EV_FROM_A_FORWARD_ACCESS_SIGNALLING_REQUEST), |
| 852 | OSMO_VALUE_STRING(MSC_T_EV_CN_CLOSE), |
| 853 | OSMO_VALUE_STRING(MSC_T_EV_MO_CLOSE), |
| 854 | OSMO_VALUE_STRING(MSC_T_EV_CLEAR_COMPLETE), |
| 855 | {} |
| 856 | }; |
| 857 | |
| 858 | static struct osmo_fsm msc_t_fsm = { |
| 859 | .name = "msc_t", |
| 860 | .states = msc_t_fsm_states, |
| 861 | .num_states = ARRAY_SIZE(msc_t_fsm_states), |
| 862 | .log_subsys = DMSC, |
| 863 | .event_names = msc_t_fsm_event_names, |
| 864 | .cleanup = msc_t_fsm_cleanup, |
| 865 | }; |
| 866 | |
| 867 | static __attribute__((constructor)) void msc_t_fsm_init(void) |
| 868 | { |
| 869 | OSMO_ASSERT(osmo_fsm_register(&msc_t_fsm) == 0); |
| 870 | } |
| 871 | |
| 872 | /* Send connection-oriented L3 message to RAN peer (MSC->[BSC|RNC]) */ |
| 873 | int msc_t_down_l2_co(struct msc_t *msc_t, const struct an_apdu *an_apdu, bool initial) |
| 874 | { |
| 875 | int rc; |
| 876 | if (!msc_t->ran_conn) { |
| 877 | LOG_MSC_T(msc_t, LOGL_ERROR, "Cannot Tx L2 message: no RAN conn\n"); |
| 878 | return -EIO; |
| 879 | } |
| 880 | |
| 881 | if (an_apdu->an_proto != msc_t->c.ran->an_proto) { |
| 882 | LOG_MSC_T(msc_t, LOGL_ERROR, "Mismatching AN-APDU proto: %s -- Dropping message\n", |
| 883 | an_proto_name(an_apdu->an_proto)); |
| 884 | return -EIO; |
| 885 | } |
| 886 | |
| 887 | rc = ran_conn_down_l2_co(msc_t->ran_conn, an_apdu->msg, initial); |
| 888 | if (rc) |
| 889 | LOG_MSC_T(msc_t, LOGL_ERROR, "Failed to transfer message down to new RAN peer (rc=%d)\n", rc); |
| 890 | return rc; |
| 891 | } |
| 892 | |
| 893 | struct gsm_network *msc_t_net(const struct msc_t *msc_t) |
| 894 | { |
| 895 | return msub_net(msc_t->c.msub); |
| 896 | } |
| 897 | |
| 898 | struct vlr_subscr *msc_t_vsub(const struct msc_t *msc_t) |
| 899 | { |
Neels Hofmeyr | 911e597 | 2019-05-09 13:28:26 +0200 | [diff] [blame] | 900 | if (!msc_t) |
| 901 | return NULL; |
Neels Hofmeyr | c4628a3 | 2018-12-07 14:47:34 +0100 | [diff] [blame] | 902 | return msub_vsub(msc_t->c.msub); |
| 903 | } |
| 904 | |
| 905 | struct msc_t *msc_t_alloc_without_ran_peer(struct msub *msub, struct ran_infra *ran) |
| 906 | { |
| 907 | struct msc_t *msc_t; |
| 908 | |
| 909 | msub_role_alloc(msub, MSC_ROLE_T, &msc_t_fsm, struct msc_t, ran); |
| 910 | msc_t = msub_msc_t(msub); |
| 911 | if (!msc_t) |
| 912 | return NULL; |
| 913 | |
| 914 | return msc_t; |
| 915 | } |
| 916 | |
| 917 | int msc_t_set_ran_peer(struct msc_t *msc_t, struct ran_peer *ran_peer) |
| 918 | { |
| 919 | if (!ran_peer || !ran_peer->sri || !ran_peer->sri->ran) { |
| 920 | LOG_MSC_T(msc_t, LOGL_ERROR, "Invalid RAN peer: %s\n", ran_peer ? ran_peer->fi->id : "NULL"); |
| 921 | return -EINVAL; |
| 922 | } |
| 923 | |
| 924 | if (ran_peer->sri->ran != msc_t->c.ran) { |
| 925 | LOG_MSC_T(msc_t, LOGL_ERROR, "This MSC-T was set up for %s, cannot assign RAN peer for %s\n", |
| 926 | osmo_rat_type_name(msc_t->c.ran->type), osmo_rat_type_name(ran_peer->sri->ran->type)); |
| 927 | return -EINVAL; |
| 928 | } |
| 929 | |
| 930 | /* Create a new ran_conn with a fresh conn_id for the outgoing initial message. The msc_t FSM definition ensures |
| 931 | * that the first message sent or received is a Connection-Oriented Initial message. */ |
| 932 | msc_t->ran_conn = ran_conn_create_outgoing(ran_peer); |
| 933 | if (!msc_t->ran_conn) { |
| 934 | LOG_MSC_T(msc_t, LOGL_ERROR, "Failed to create outgoing RAN conn\n"); |
| 935 | return -EINVAL; |
| 936 | } |
| 937 | msc_t->ran_conn->msc_role = msc_t->c.fi; |
| 938 | msub_update_id(msc_t->c.msub); |
| 939 | return 0; |
| 940 | } |
| 941 | |
| 942 | struct msc_t *msc_t_alloc(struct msub *msub, struct ran_peer *ran_peer) |
| 943 | { |
| 944 | struct msc_t *msc_t = msc_t_alloc_without_ran_peer(msub, ran_peer->sri->ran); |
| 945 | if (!msc_t) |
| 946 | return NULL; |
| 947 | if (msc_t_set_ran_peer(msc_t, ran_peer)) { |
| 948 | msc_t_clear(msc_t); |
| 949 | return NULL; |
| 950 | } |
| 951 | return msc_t; |
| 952 | } |
| 953 | |
| 954 | void msc_t_clear(struct msc_t *msc_t) |
| 955 | { |
| 956 | if (!msc_t) |
| 957 | return; |
| 958 | osmo_fsm_inst_term(msc_t->c.fi, OSMO_FSM_TERM_REGULAR, msc_t->c.fi); |
| 959 | } |