blob: cea658c3b1104794e48e1e9078f216236783b433 [file] [log] [blame]
Neels Hofmeyrc4628a32018-12-07 14:47:34 +01001/* MSC Handover implementation */
2/*
Vadim Yanitskiy999a5932023-05-18 17:22:26 +07003 * (C) 2019 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
Neels Hofmeyrc4628a32018-12-07 14:47:34 +01004 * All Rights Reserved
5 *
6 * Author: Neels Hofmeyr
7 *
Harald Welte1b1a39b2024-02-17 10:11:18 +01008 * SPDX-License-Identifier: AGPL-3.0+
Neels Hofmeyrc4628a32018-12-07 14:47:34 +01009 *
10 * This program is free software; you can redistribute it and/or modify
Harald Welte1b1a39b2024-02-17 10:11:18 +010011 * 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
Neels Hofmeyrc4628a32018-12-07 14:47:34 +010013 * (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
Harald Welte1b1a39b2024-02-17 10:11:18 +010018 * GNU Affero General Public License for more details.
Neels Hofmeyrc4628a32018-12-07 14:47:34 +010019 */
20
21#include <osmocom/core/fsm.h>
22#include <osmocom/gsm/protocol/gsm_08_08.h>
23#include <osmocom/sigtran/sccp_helpers.h>
24
25#include <osmocom/msc/msc_ho.h>
Alexander Couzens7900a052024-08-27 16:17:39 +020026#include <osmocom/msc/ran_conn.h>
Neels Hofmeyrc4628a32018-12-07 14:47:34 +010027#include <osmocom/msc/ran_msg.h>
28#include <osmocom/msc/msc_a.h>
29#include <osmocom/msc/msc_i.h>
30#include <osmocom/msc/msc_t.h>
31#include <osmocom/msc/e_link.h>
32#include <osmocom/msc/msc_i_remote.h>
33#include <osmocom/msc/msc_t_remote.h>
34#include <osmocom/msc/neighbor_ident.h>
35#include <osmocom/msc/gsm_data.h>
36#include <osmocom/msc/ran_peer.h>
37#include <osmocom/msc/vlr.h>
38#include <osmocom/msc/transaction.h>
39#include <osmocom/msc/gsm_04_08.h>
40#include <osmocom/msc/call_leg.h>
41#include <osmocom/msc/rtp_stream.h>
42#include <osmocom/msc/mncc_call.h>
Neels Hofmeyr62bfa372022-10-31 18:51:07 +010043#include <osmocom/msc/codec_mapping.h>
Neels Hofmeyrc4628a32018-12-07 14:47:34 +010044
45struct osmo_fsm msc_ho_fsm;
46
47#define MSC_A_USE_HANDOVER "Handover"
48
49static const struct osmo_tdef_state_timeout msc_ho_fsm_timeouts[32] = {
50 [MSC_HO_ST_REQUIRED] = { .keep_timer = true, .T = -3 },
51 [MSC_HO_ST_WAIT_REQUEST_ACK] = { .keep_timer = true },
52 [MSC_HO_ST_WAIT_COMPLETE] = { .T = -3 },
53};
54
55/* Transition to a state, using the T timer defined in msc_a_fsm_timeouts.
56 * The actual timeout value is in turn obtained from network->T_defs.
57 * Assumes local variable fi exists. */
58#define msc_ho_fsm_state_chg(msc_a, state) \
59 osmo_tdef_fsm_inst_state_chg((msc_a)->ho.fi, state, msc_ho_fsm_timeouts, (msc_a)->c.ran->tdefs, 5)
60
61static __attribute__((constructor)) void msc_ho_fsm_init()
62{
Harald Welte34a8cc32019-12-01 15:32:09 +010063 OSMO_ASSERT(osmo_fsm_register(&msc_ho_fsm) == 0);
Neels Hofmeyrc4628a32018-12-07 14:47:34 +010064}
65
66void msc_ho_down_required_reject(struct msc_a *msc_a, enum gsm0808_cause cause)
67{
Vadim Yanitskiydb4839c2019-12-01 18:52:58 +070068 struct msc_i *msc_i;
Neels Hofmeyrc4628a32018-12-07 14:47:34 +010069 uint32_t event;
70
Vadim Yanitskiydb4839c2019-12-01 18:52:58 +070071 msc_i = msc_a_msc_i(msc_a);
72 OSMO_ASSERT(msc_i);
73
Neels Hofmeyrc4628a32018-12-07 14:47:34 +010074 struct ran_msg ran_enc_msg = {
75 .msg_type = RAN_MSG_HANDOVER_REQUIRED_REJECT,
76 .handover_required_reject = {
77 .cause = cause,
78 },
79 };
80
81 if (msc_i->c.remote_to)
82 event = MSC_I_EV_FROM_A_PREPARE_SUBSEQUENT_HANDOVER_ERROR;
83 else
84 event = MSC_I_EV_FROM_A_FORWARD_ACCESS_SIGNALLING_REQUEST;
85
86 msc_a_msg_down(msc_a, MSC_ROLE_I, event, &ran_enc_msg);
87}
88
89/* Even though this is using the 3GPP TS 48.008 definitions and naming, the intention is to be RAN implementation agnostic.
90 * For other RAN types, the 48.008 items shall be translated to their respective counterparts. */
91void msc_ho_start(struct msc_a *msc_a, const struct ran_handover_required *ho_req)
92{
93 if (msc_a->ho.fi) {
94 LOG_HO(msc_a, LOGL_ERROR, "Rx Handover Required, but Handover is still ongoing\n");
95 msc_ho_down_required_reject(msc_a, GSM0808_CAUSE_PROTOCOL_ERROR_BETWEEN_BSS_AND_MSC);
96 return;
97 }
98
99 if (!ho_req->cil.id_list_len) {
100 LOG_HO(msc_a, LOGL_ERROR, "Rx Handover Required without a Cell Identifier List\n");
101 msc_ho_down_required_reject(msc_a, GSM0808_CAUSE_INFORMATION_ELEMENT_OR_FIELD_MISSING);
102 return;
103 }
104
105 if (msc_a_msc_t(msc_a)) {
106 LOG_HO(msc_a, LOGL_ERROR,
107 "Rx Handover Required, but this subscriber still has an active MSC-T role: %s\n",
108 msc_a_msc_t(msc_a)->c.fi->id);
109 /* Protocol error because the BSS is not supposed to send another Handover Required before the previous
110 * attempt has concluded. */
111 msc_ho_down_required_reject(msc_a, GSM0808_CAUSE_PROTOCOL_ERROR_BETWEEN_BSS_AND_MSC);
112 return;
113 }
114
115 /* Paranoia: make sure we start with clean state */
116 msc_a->ho = (struct msc_ho_state){};
117
118 msc_a->ho.fi = osmo_fsm_inst_alloc_child(&msc_ho_fsm, msc_a->c.fi, MSC_A_EV_HANDOVER_END);
119 OSMO_ASSERT(msc_a->ho.fi);
120
121 msc_a->ho.fi->priv = msc_a;
122 msc_a->ho.info = *ho_req;
123 msc_a->ho.next_cil_idx = 0;
124
125 /* Start the timeout */
126 msc_ho_fsm_state_chg(msc_a, MSC_HO_ST_REQUIRED);
127}
128
129static void msc_ho_rtp_rollback_to_old_cell(struct msc_a *msc_a);
130
131static void msc_ho_end(struct msc_a *msc_a, bool success, enum gsm0808_cause cause)
132{
133 struct msc_i *msc_i;
134 struct msc_t *msc_t = msc_a_msc_t(msc_a);
135
136 if (!success) {
137 msc_ho_rtp_rollback_to_old_cell(msc_a);
138 msc_ho_down_required_reject(msc_a, cause);
139 }
140
141 if (success) {
142 /* Any previous call forwarding to a remote MSC becomes obsolete. */
143 if (msc_a->cc.mncc_forwarding_to_remote_ran) {
144 mncc_call_release(msc_a->cc.mncc_forwarding_to_remote_ran);
145 msc_a->cc.mncc_forwarding_to_remote_ran = NULL;
146 }
147
148 /* Replace MSC-I with new MSC-T */
149 if (msc_t->c.remote_to) {
150 /* Inter-MSC Handover. */
151
152 /* The MNCC forwarding set up for inter-MSC handover, so far transitional in msc_a->ho now
153 * becomes the "officially" active MNCC forwarding for this call. */
154 msc_a->cc.mncc_forwarding_to_remote_ran = msc_a->ho.new_cell.mncc_forwarding_to_remote_ran;
155 msc_a->ho.new_cell.mncc_forwarding_to_remote_ran = NULL;
156 mncc_call_reparent(msc_a->cc.mncc_forwarding_to_remote_ran,
157 msc_a->c.fi, -1, MSC_MNCC_EV_CALL_ENDED, NULL, NULL);
158
159 /* inter-MSC link. msc_i_remote_alloc() properly "steals" the e_link from msc_t. */
160 msc_i = msc_i_remote_alloc(msc_a->c.msub, msc_t->c.ran, msc_t->c.remote_to);
161 OSMO_ASSERT(msc_t->c.remote_to == NULL);
162 } else {
163 /* local BSS */
164 msc_i = msc_i_alloc(msc_a->c.msub, msc_t->c.ran);
165 /* msc_i_set_ran_conn() properly "steals" the ran_conn from msc_t */
166 msc_i_set_ran_conn(msc_i, msc_t->ran_conn);
167 }
168 }
169
170 osmo_fsm_inst_term(msc_a->ho.fi, OSMO_FSM_TERM_REGULAR, NULL);
171}
172
173#define msc_ho_failed(msc_a, cause, fmt, args...) do { \
174 LOG_HO(msc_a, LOGL_ERROR, fmt, ##args); \
175 msc_ho_end(msc_a, false, cause); \
176 } while(0)
177#define msc_ho_try_next_cell(msc_a, fmt, args...) do {\
178 LOG_HO(msc_a, LOGL_ERROR, fmt, ##args); \
179 msc_ho_fsm_state_chg(msc_a, MSC_HO_ST_REQUIRED); \
180 } while(0)
181#define msc_ho_success(msc_a) msc_ho_end(msc_a, true, 0)
182
183enum msc_neighbor_type msc_ho_find_target_cell(struct msc_a *msc_a, const struct gsm0808_cell_id *cid,
184 const struct neighbor_ident_entry **remote_msc,
185 struct ran_peer **ran_peer_from_neighbor_ident,
186 struct ran_peer **ran_peer_from_seen_cells)
187{
188 struct gsm_network *net = msc_a_net(msc_a);
189 const struct neighbor_ident_entry *e;
190 struct sccp_ran_inst *sri;
191 struct ran_peer *rp_from_neighbor_ident = NULL;
192 struct ran_peer *rp_from_cell_id = NULL;
193 struct ran_peer *rp;
194 int i;
195
196 OSMO_ASSERT(remote_msc);
197 OSMO_ASSERT(ran_peer_from_neighbor_ident);
198 OSMO_ASSERT(ran_peer_from_seen_cells);
199
200 e = neighbor_ident_find_by_cell(&net->neighbor_ident_list, msc_a->c.ran->type, cid);
201
202 if (e && e->addr.type == MSC_NEIGHBOR_TYPE_REMOTE_MSC) {
203 *remote_msc = e;
204 return MSC_NEIGHBOR_TYPE_REMOTE_MSC;
205 }
206
207 /* It is not a remote MSC target. Figure out local RAN peers. */
208
209 if (e && e->addr.type == MSC_NEIGHBOR_TYPE_LOCAL_RAN_PEER) {
210 /* Find local RAN peer in neighbor config. If anything is wrong with that, just keep
211 * rp_from_neighbor_ident == NULL. */
212
213 struct sccp_ran_inst *sri_from_neighbor_ident = NULL;
214 struct osmo_ss7_instance *ss7 = NULL;
215
216 /* Get the sccp_ran_inst with sanity checkin. If anything is fishy, just keep
217 * sri_from_neighbor_ident == NULL and below code will notice the error. */
218 if (e->addr.ran_type < msc_ran_infra_len) {
219 sri_from_neighbor_ident = msc_ran_infra[e->addr.ran_type].sri;
220 ss7 = osmo_sccp_get_ss7(sri_from_neighbor_ident->sccp);
221 if (!ss7)
222 sri_from_neighbor_ident = NULL;
223 }
224
225 if (!sri_from_neighbor_ident) {
226 LOG_HO(msc_a, LOGL_ERROR, "Cannot handover to RAN type %s\n", osmo_rat_type_name(e->addr.ran_type));
227 } else {
228 /* Interpret the point-code string placed in the neighbors config. */
229 int pc = osmo_ss7_pointcode_parse(ss7, e->addr.local_ran_peer_pc_str);
230
231 if (pc < 0) {
232 LOG_HO(msc_a, LOGL_ERROR, "Invalid point code string: %s\n",
233 osmo_quote_str(e->addr.local_ran_peer_pc_str, -1));
234 } else {
235 struct osmo_sccp_addr addr = {};
236 osmo_sccp_make_addr_pc_ssn(&addr, pc, sri_from_neighbor_ident->ran->ssn);
237 rp_from_neighbor_ident = ran_peer_find_by_addr(sri_from_neighbor_ident, &addr);
238 }
239 }
240
241 if (!rp_from_neighbor_ident) {
242 LOG_HO(msc_a, LOGL_ERROR, "Target RAN peer from neighbor config is not connected:"
243 " Cell ID %s resolves to target address %s\n",
244 gsm0808_cell_id_name(cid), e->addr.local_ran_peer_pc_str);
245 } else if (rp_from_neighbor_ident->fi->state != RAN_PEER_ST_READY) {
246 LOG_HO(msc_a, LOGL_ERROR, "Target RAN peer in invalid state: %s (%s)\n",
247 osmo_fsm_inst_state_name(rp_from_neighbor_ident->fi),
248 rp_from_neighbor_ident->fi->id);
249 rp_from_neighbor_ident = NULL;
250 }
251 }
252
253 /* Figure out actually connected RAN peers for this cell ID.
254 * If no cell has been found yet at all, this might determine a Handover target,
255 * otherwise this is for sanity checking. If none is found, just keep rp_from_cell_id == NULL. */
256
257 /* Iterate all connected RAN peers. Possibly, more than one RAN peer has advertised a match for this Cell ID.
258 * For example, if the handover target is identified as LAC=23 but there are multiple cells with distinct CIs
259 * serving in LAC=23, we have an ambiguity. It's up to the user to configure correctly, help with logging. */
260 for (i = 0; i < msc_ran_infra_len; i++) {
261 sri = msc_ran_infra[i].sri;
262 if (!sri)
263 continue;
264
265 rp = ran_peer_find_by_cell_id(sri, cid, true);
266 if (rp && rp->fi && rp->fi->state == RAN_PEER_ST_READY) {
267 if (rp_from_cell_id) {
268 LOG_HO(msc_a, LOGL_ERROR,
269 "Ambiguous match for cell ID %s: more than one RAN type is serving this cell"
270 " ID: %s and %s\n",
271 gsm0808_cell_id_name(cid),
272 rp_from_cell_id->fi->id,
273 rp->fi->id);
274 /* But logging is all we're going to do about it. */
275 }
276
277 /* Use the first found RAN peer, but if multiple matches are found, favor the one that matches
278 * the current RAN type. */
279 if (!rp_from_cell_id || rp->sri == msc_a->c.ran->sri)
280 rp_from_cell_id = rp;
281 }
282 }
283
284 /* Did we find mismatching targets from neighbor config and from connected cells? */
285 if (rp_from_neighbor_ident && rp_from_cell_id
286 && rp_from_neighbor_ident != rp_from_cell_id) {
287 LOG_HO(msc_a, LOGL_ERROR, "Ambiguous match for cell ID %s:"
288 " neighbor config points at %s; a matching cell is also served by connected RAN peer %s\n",
289 gsm0808_cell_id_name(cid), rp_from_neighbor_ident->fi->id, rp_from_cell_id->fi->id);
290 /* But logging is all we're going to do about it. */
291 }
292
293 if (rp_from_neighbor_ident && rp_from_neighbor_ident->sri != msc_a->c.ran->sri) {
294 LOG_HO(msc_a, LOGL_ERROR,
295 "Neighbor config indicates inter-RAT Handover, which is not implemented. Ignoring target %s\n",
296 rp_from_neighbor_ident->fi->id);
297 rp_from_neighbor_ident = NULL;
298 }
299
300 if (rp_from_cell_id && rp_from_cell_id->sri != msc_a->c.ran->sri) {
301 LOG_HO(msc_a, LOGL_ERROR,
302 "Target RAN peer indicates inter-RAT Handover, which is not implemented. Ignoring target %s\n",
303 rp_from_cell_id->fi->id);
304 rp_from_cell_id = NULL;
305 }
306
307 *ran_peer_from_neighbor_ident = rp_from_neighbor_ident;
308 *ran_peer_from_seen_cells = rp_from_cell_id;
309
310 return rp_from_neighbor_ident || rp_from_cell_id ? MSC_NEIGHBOR_TYPE_LOCAL_RAN_PEER : MSC_NEIGHBOR_TYPE_NONE;
311}
312
313static bool msc_ho_find_next_target_cell(struct msc_a *msc_a)
314{
315 struct vlr_subscr *vsub = msc_a_vsub(msc_a);
316 struct ran_handover_required *info = &msc_a->ho.info;
317 struct gsm0808_cell_id *cid = &msc_a->ho.new_cell.cid;
318 const struct neighbor_ident_entry *e;
319 struct ran_peer *rp_from_neighbor_ident = NULL;
320 struct ran_peer *rp_from_cell_id = NULL;
321 struct ran_peer *rp;
322
323 unsigned int cil_idx = msc_a->ho.next_cil_idx;
324 msc_a->ho.next_cil_idx++;
325
326 msc_a->ho.new_cell.type = MSC_NEIGHBOR_TYPE_NONE;
327
328 if (cil_idx >= info->cil.id_list_len)
329 return false;
330
331 *cid = (struct gsm0808_cell_id){
332 .id_discr = info->cil.id_discr,
333 .id = info->cil.id_list[cil_idx],
334 };
335
336 msc_a->ho.new_cell.cgi = (struct osmo_cell_global_id){
337 .lai = vsub->cgi.lai,
338 };
339 gsm0808_cell_id_to_cgi(&msc_a->ho.new_cell.cgi, cid);
340
341 switch (msc_ho_find_target_cell(msc_a, cid, &e, &rp_from_neighbor_ident, &rp_from_cell_id)) {
342 case MSC_NEIGHBOR_TYPE_REMOTE_MSC:
343 OSMO_ASSERT(e);
344 msc_a->ho.new_cell.ran_type = e->addr.ran_type;
345 msc_a->ho.new_cell.type = MSC_NEIGHBOR_TYPE_REMOTE_MSC;
346 msc_a->ho.new_cell.msc_ipa_name = e->addr.remote_msc_ipa_name.buf;
347 return true;
348
349 case MSC_NEIGHBOR_TYPE_LOCAL_RAN_PEER:
350 rp = rp_from_neighbor_ident ? : rp_from_cell_id;
351 OSMO_ASSERT(rp);
352 msc_a->ho.new_cell.type = MSC_NEIGHBOR_TYPE_LOCAL_RAN_PEER;
353 msc_a->ho.new_cell.ran_peer = rp;
354 return true;
355
356 default:
357 break;
358 }
359
360 LOG_HO(msc_a, LOGL_DEBUG, "Cannot find target peer for cell ID %s\n", gsm0808_cell_id_name(cid));
361 /* Try the next cell id, if any. */
362 return msc_ho_find_next_target_cell(msc_a);
363}
364
365static void msc_ho_fsm_required_onenter(struct osmo_fsm_inst *fi, uint32_t prev_state)
366{
367 struct msc_a *msc_a = fi->priv;
368
369 if (!msc_ho_find_next_target_cell(msc_a)) {
370 int tried = msc_a->ho.next_cil_idx - 1;
371 msc_ho_failed(msc_a, GSM0808_CAUSE_NO_RADIO_RESOURCE_AVAILABLE,
372 "Attempted Handover to %u cells without success\n", tried);
373 return;
374 }
375
376 msc_ho_fsm_state_chg(msc_a, MSC_HO_ST_WAIT_REQUEST_ACK);
377}
378
379static void msc_ho_send_handover_request(struct msc_a *msc_a)
380{
381 struct vlr_subscr *vsub = msc_a_vsub(msc_a);
382 struct gsm_network *net = msc_a_net(msc_a);
383 struct gsm0808_channel_type channel_type;
Neels Hofmeyrd767c732023-11-17 04:12:29 +0100384 struct gsm0808_speech_codec_list scl = {};
Philipp Maier7da956e2020-06-09 14:34:40 +0200385 struct gsm_trans *cc_trans = msc_a->cc.active_trans;
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100386 struct ran_msg ran_enc_msg = {
387 .msg_type = RAN_MSG_HANDOVER_REQUEST,
388 .handover_request = {
389 .imsi = vsub->imsi,
390 .classmark = &vsub->classmark,
391 .geran = {
392 .chosen_encryption = &msc_a->geran_encr,
393 .a5_encryption_mask = net->a5_encryption_mask,
394 },
395 .bssap_cause = GSM0808_CAUSE_BETTER_CELL,
396 .current_channel_type_1_present = msc_a->ho.info.current_channel_type_1_present,
397 .current_channel_type_1 = msc_a->ho.info.current_channel_type_1,
398 .speech_version_used = msc_a->ho.info.speech_version_used,
399 .old_bss_to_new_bss_info_raw = msc_a->ho.info.old_bss_to_new_bss_info_raw,
400 .old_bss_to_new_bss_info_raw_len = msc_a->ho.info.old_bss_to_new_bss_info_raw_len,
401
402 /* Don't send AoIP Transport Layer Address for inter-MSC Handover */
403 .rtp_ran_local = (msc_a->ho.new_cell.type == MSC_NEIGHBOR_TYPE_LOCAL_RAN_PEER)
404 ? call_leg_local_ip(msc_a->cc.call_leg, RTP_TO_RAN) : NULL,
405 },
406 };
407
Neels Hofmeyr73d093a2021-06-23 23:54:43 +0200408 if (msc_a->geran_encr.key_len)
409 LOG_MSC_A(msc_a, LOGL_DEBUG, "HO Request with ciphering: A5/%d kc %s kc128 %s\n",
410 msc_a->geran_encr.alg_id - 1,
411 osmo_hexdump_nospc_c(OTC_SELECT, msc_a->geran_encr.key, msc_a->geran_encr.key_len),
412 msc_a->geran_encr.kc128_present ?
413 osmo_hexdump_nospc_c(OTC_SELECT, msc_a->geran_encr.kc128, sizeof(msc_a->geran_encr.kc128))
414 : "-");
415
Neels Hofmeyrb6c11c42022-08-08 18:15:32 +0200416 if (cc_trans) {
Oliver Smithcfa37cb2023-08-22 13:28:18 +0200417 switch (cc_trans->bearer_cap.transfer) {
418 case GSM48_BCAP_ITCAP_SPEECH:
419 if (sdp_audio_codecs_to_gsm0808_channel_type(&channel_type,
420 &cc_trans->cc.local.audio_codecs)) {
421 msc_ho_failed(msc_a, GSM0808_CAUSE_EQUIPMENT_FAILURE,
422 "Failed to determine Channel Type for Handover Request message (speech)\n");
423 return;
424 }
425 break;
Manawyrm1ed12ea2023-10-14 17:23:04 +0200426 case GSM48_BCAP_ITCAP_3k1_AUDIO:
427 case GSM48_BCAP_ITCAP_FAX_G3:
Oliver Smithcfa37cb2023-08-22 13:28:18 +0200428 case GSM48_BCAP_ITCAP_UNR_DIG_INF:
429 if (csd_bs_list_to_gsm0808_channel_type(&channel_type, &cc_trans->cc.local.bearer_services)) {
430 msc_ho_failed(msc_a, GSM0808_CAUSE_EQUIPMENT_FAILURE,
431 "Failed to determine Channel Type for Handover Request message (CSD)\n");
432 return;
433 }
434 break;
435 default:
436 msc_ho_failed(msc_a, GSM0808_CAUSE_EQUIPMENT_FAILURE, "Failed to create"
437 " Handover Request message for information transfer capability %d\n",
438 cc_trans->bearer_cap.transfer);
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100439 return;
440 }
Oliver Smithcfa37cb2023-08-22 13:28:18 +0200441
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100442 ran_enc_msg.handover_request.geran.channel_type = &channel_type;
Oliver Smith0d4607d2023-06-22 12:26:11 +0200443 ran_enc_msg.handover_request.call_id_present = true;
Andreas Eversberg712b28e2023-06-21 11:17:26 +0200444 ran_enc_msg.handover_request.call_id = cc_trans->call_id;
Neels Hofmeyrb091d212022-08-08 19:11:51 +0200445
Neels Hofmeyrd767c732023-11-17 04:12:29 +0100446 /* Call assignment is now capable of re-assigning to overcome a codec mismatch with the remote call leg.
447 * But for inter-MSC handover, that is not supported yet. So keep here the old limitation of only
448 * offering the assigned codec. */
449 if (sdp_audio_codec_is_set(&cc_trans->cc.codecs.assignment))
450 sdp_audio_codec_to_speech_codec_list(&scl, &cc_trans->cc.codecs.assignment);
451 else
452 sdp_audio_codecs_to_speech_codec_list(&scl, &cc_trans->cc.local.audio_codecs);
Neels Hofmeyrb091d212022-08-08 19:11:51 +0200453 if (!scl.len) {
454 msc_ho_failed(msc_a, GSM0808_CAUSE_EQUIPMENT_FAILURE, "Failed to compose"
455 " Codec List (MSC Preferred) for Handover Request message\n");
456 return;
457 }
458 ran_enc_msg.handover_request.codec_list_msc_preferred = &scl;
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100459 }
460
461 gsm0808_cell_id_from_cgi(&ran_enc_msg.handover_request.cell_id_serving, CELL_IDENT_WHOLE_GLOBAL, &vsub->cgi);
462 ran_enc_msg.handover_request.cell_id_target = msc_a->ho.new_cell.cid;
463
464 if (msc_a_msg_down(msc_a, MSC_ROLE_T, MSC_T_EV_FROM_A_PREPARE_HANDOVER_REQUEST, &ran_enc_msg))
465 msc_ho_try_next_cell(msc_a, "Failed to send Handover Request message\n");
466}
467
468static void msc_ho_fsm_wait_request_ack_onenter(struct osmo_fsm_inst *fi, uint32_t prev_state)
469{
470 struct msc_a *msc_a = fi->priv;
471 struct msc_i *msc_i = msc_a_msc_i(msc_a);
472 struct msc_t *msc_t;
473 struct ran_peer *rp;
474 const char *ipa_name;
475
476 msc_t = msc_a_msc_t(msc_a);
477 if (msc_t) {
478 /* All the other code should prevent this from happening, ever. */
479 msc_ho_failed(msc_a, GSM0808_CAUSE_EQUIPMENT_FAILURE,
480 "Cannot initiate Handover Request, there still is an active MSC-T role: %s\n",
481 msc_t->c.fi->id);
482 return;
483 }
484
485 if (!msc_i) {
486 msc_ho_failed(msc_a, GSM0808_CAUSE_EQUIPMENT_FAILURE,
487 "Cannot initiate Handover Request, there is no MSC-I role\n");
488 return;
489 }
490
491 if (!msc_i->c.remote_to
492 && !(msc_i->ran_conn && msc_i->ran_conn->ran_peer)) {
493 msc_ho_failed(msc_a, GSM0808_CAUSE_EQUIPMENT_FAILURE,
494 "Cannot initiate Handover Request, MSC-I role has no connection\n");
495 return;
496 }
497
498 switch (msc_a->ho.new_cell.type) {
499 case MSC_NEIGHBOR_TYPE_LOCAL_RAN_PEER:
500 rp = msc_a->ho.new_cell.ran_peer;
501 OSMO_ASSERT(rp && rp->fi);
502
503 if (msc_i->c.remote_to) {
504 LOG_HO(msc_a, LOGL_INFO,
505 "Starting inter-MSC Subsequent Handover from remote MSC %s to local %s\n",
506 msc_i->c.remote_to->remote_name, rp->fi->id);
507 msc_a->ho.subsequent_ho = true;
508 } else {
509 LOG_HO(msc_a, LOGL_INFO, "Starting inter-BSC Handover from %s to %s\n",
510 msc_i->ran_conn->ran_peer->fi->id, rp->fi->id);
511 }
512
Vadim Yanitskiya870faf2019-05-11 02:45:46 +0700513 msc_t = msc_t_alloc(msc_a->c.msub, rp);
514 break;
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100515
516 case MSC_NEIGHBOR_TYPE_REMOTE_MSC:
517 ipa_name = msc_a->ho.new_cell.msc_ipa_name;
518 OSMO_ASSERT(ipa_name);
519
520 if (msc_i->c.remote_to) {
521 LOG_HO(msc_a, LOGL_INFO,
522 "Starting inter-MSC Subsequent Handover from remote MSC %s to remote MSC at %s\n",
523 msc_i->c.remote_to->remote_name, osmo_quote_str(ipa_name, -1));
524 msc_a->ho.subsequent_ho = true;
525 } else {
526 LOG_HO(msc_a, LOGL_INFO, "Starting inter-MSC Handover from local %s to remote MSC at %s\n",
527 msc_i->ran_conn->ran_peer->fi->id,
528 osmo_quote_str(ipa_name, -1));
529 }
530
Vadim Yanitskiya870faf2019-05-11 02:45:46 +0700531 msc_t = msc_t_remote_alloc(msc_a->c.msub, msc_a->c.ran,
532 (const uint8_t *) ipa_name,
533 strlen(ipa_name));
534 break;
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100535
536 default:
537 msc_ho_try_next_cell(msc_a, "unknown Handover target type %d\n", msc_a->ho.new_cell.type);
538 return;
539 }
540
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100541 if (!msc_t) {
542 /* There should definitely be one now. */
543 msc_ho_failed(msc_a, GSM0808_CAUSE_EQUIPMENT_FAILURE,
544 "Cannot initiate Handover Request, failed to set up a target MSC-T\n");
545 return;
546 }
Vadim Yanitskiya870faf2019-05-11 02:45:46 +0700547
548 msc_ho_send_handover_request(msc_a);
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100549}
550
551static void msc_ho_rx_request_ack(struct msc_a *msc_a, struct msc_a_ran_dec_data *hra);
552
553static void msc_ho_fsm_wait_request_ack(struct osmo_fsm_inst *fi, uint32_t event, void *data)
554{
555 struct msc_a *msc_a = fi->priv;
556
557 switch (event) {
558
559 case MSC_HO_EV_RX_REQUEST_ACK:
560 msc_ho_rx_request_ack(msc_a, (struct msc_a_ran_dec_data*)data);
561 return;
562
563 case MSC_HO_EV_RX_FAILURE:
564 msc_ho_failed(msc_a, GSM0808_CAUSE_NO_RADIO_RESOURCE_AVAILABLE,
565 "Received Handover Failure message\n");
566 return;
567
568 default:
569 OSMO_ASSERT(false);
570 }
571}
572
573static void msc_ho_rtp_switch_to_new_cell(struct msc_a *msc_a);
574
575void msc_ho_mncc_forward_cb(struct mncc_call *mncc_call, const union mncc_msg *mncc_msg, void *data)
576{
577 struct msc_a *msc_a = data;
578 switch (mncc_msg->msg_type) {
579 case MNCC_RTP_CONNECT:
580 msc_a->ho.rtp_switched_to_new_cell = true;
581 return;
582 default:
583 return;
584 }
585}
586
587/* Initiate call forwarding via MNCC: call the Handover Number that the other MSC assigned. */
588static int msc_ho_start_inter_msc_call_forwarding(struct msc_a *msc_a, struct msc_t *msc_t,
589 const struct msc_a_ran_dec_data *hra)
590{
591 const struct osmo_gsup_message *e_info = hra->an_apdu->e_info;
592 struct gsm_mncc outgoing_call_req = {};
593 struct call_leg *cl = msc_a->cc.call_leg;
594 struct rtp_stream *rtp_to_ran = cl ? cl->rtp[RTP_TO_RAN] : NULL;
595 struct mncc_call *mncc_call;
596
597 if (!e_info || !e_info->msisdn_enc || !e_info->msisdn_enc_len) {
598 msc_ho_try_next_cell(msc_a,
599 "No Handover Number in Handover Request Acknowledge from remote MSC\n");
600 return -EINVAL;
601 }
602
Neels Hofmeyrda3ce712019-05-09 14:16:26 +0200603 if (!rtp_to_ran) {
604 msc_ho_failed(msc_a, GSM0808_CAUSE_EQUIPMENT_FAILURE, "Unexpected: no RTP stream is set up\n");
605 return -EINVAL;
606 }
607
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100608 /* Backup old cell's RTP IP:port and codec data */
609 msc_a->ho.old_cell.ran_remote_rtp = rtp_to_ran->remote;
Neels Hofmeyr62bfa372022-10-31 18:51:07 +0100610 msc_a->ho.old_cell.codecs = rtp_to_ran->codecs;
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100611
612 /* Blindly taken over from an MNCC trace of existing code: send an all-zero CCCAP: */
613 outgoing_call_req.fields |= MNCC_F_CCCAP;
614
615 /* Called number */
616 outgoing_call_req.fields |= MNCC_F_CALLED;
617 outgoing_call_req.called.plan = 1; /* Empirical magic number. There seem to be no enum or defines for this.
618 * The only other place setting this apparently is gsm48_decode_called(). */
619 if (gsm48_decode_bcd_number2(outgoing_call_req.called.number, sizeof(outgoing_call_req.called.number),
620 e_info->msisdn_enc, e_info->msisdn_enc_len, 0)) {
621 msc_ho_try_next_cell(msc_a,
622 "Failed to decode Handover Number in Handover Request Acknowledge"
623 " from remote MSC\n");
624 return -EINVAL;
625 }
626
627 if (msc_a->cc.active_trans) {
628 outgoing_call_req.fields |= MNCC_F_BEARER_CAP;
629 outgoing_call_req.bearer_cap = msc_a->cc.active_trans->bearer_cap;
630 }
631
632 mncc_call = mncc_call_alloc(msc_a_vsub(msc_a),
633 msc_a->ho.fi,
634 MSC_HO_EV_MNCC_FORWARDING_COMPLETE,
635 MSC_HO_EV_MNCC_FORWARDING_FAILED,
636 msc_ho_mncc_forward_cb, msc_a);
637
638 mncc_call_set_rtp_stream(mncc_call, rtp_to_ran);
639 msc_a->ho.new_cell.mncc_forwarding_to_remote_ran = mncc_call;
640 return mncc_call_outgoing_start(mncc_call, &outgoing_call_req);
641}
642
643static void msc_ho_rx_request_ack(struct msc_a *msc_a, struct msc_a_ran_dec_data *hra)
644{
645 struct msc_t *msc_t = msc_a_msc_t(msc_a);
646 struct ran_msg ran_enc_msg;
647
648 OSMO_ASSERT(hra->ran_dec);
649 OSMO_ASSERT(hra->an_apdu);
650
651 if (!msc_t) {
652 msc_ho_failed(msc_a, GSM0808_CAUSE_EQUIPMENT_FAILURE, "MSC-T role missing\n");
653 return;
654 }
655
656 if (!hra->ran_dec->handover_request_ack.rr_ho_command
657 || !hra->ran_dec->handover_request_ack.rr_ho_command_len) {
658 msc_ho_try_next_cell(msc_a, "Missing mandatory IE in Handover Request Acknowledge:"
659 " L3 Info (RR Handover Command)\n");
660 return;
661 }
662
663 if (!hra->ran_dec->handover_request_ack.chosen_channel_present) {
664 LOG_HO(msc_a, LOGL_DEBUG, "No 'Chosen Channel' IE in Handover Request Ack\n");
665 msc_t->geran.chosen_channel = 0;
666 } else
667 msc_t->geran.chosen_channel = hra->ran_dec->handover_request_ack.chosen_channel;
668
669 if (!hra->ran_dec->handover_request_ack.chosen_encr_alg) {
670 LOG_HO(msc_a, LOGL_DEBUG, "No 'Chosen Encryption Algorithm' IE in Handover Request Ack\n");
671 msc_t->geran.chosen_encr_alg = 0;
672 } else {
673 msc_t->geran.chosen_encr_alg = hra->ran_dec->handover_request_ack.chosen_encr_alg;
674 if (msc_t->geran.chosen_encr_alg < 1 || msc_t->geran.chosen_encr_alg > 8) {
675 msc_ho_try_next_cell(msc_a, "Handover Request Ack: Invalid 'Chosen Encryption Algorithm': %u\n",
676 msc_t->geran.chosen_encr_alg);
677 return;
678 }
679 }
680
681 msc_t->geran.chosen_speech_version = hra->ran_dec->handover_request_ack.chosen_speech_version;
682 if (!msc_t->geran.chosen_speech_version)
683 LOG_HO(msc_a, LOGL_DEBUG, "No 'Chosen Speech Version' IE in Handover Request Ack\n");
684
685 /* Inter-MSC call forwarding? */
686 if (msc_a->ho.new_cell.type == MSC_NEIGHBOR_TYPE_REMOTE_MSC) {
687 if (msc_ho_start_inter_msc_call_forwarding(msc_a, msc_t, hra))
688 return;
689 }
690
691 msc_ho_fsm_state_chg(msc_a, MSC_HO_ST_WAIT_COMPLETE);
692
693 /* Forward the RR Handover Command composed by the new RAN peer down to the old RAN peer */
694 ran_enc_msg = (struct ran_msg){
695 .msg_type = RAN_MSG_HANDOVER_COMMAND,
696 .handover_command = {
697 .rr_ho_command = hra->ran_dec->handover_request_ack.rr_ho_command,
698 .rr_ho_command_len = hra->ran_dec->handover_request_ack.rr_ho_command_len,
699 },
700 };
701
702 if (msc_a_msg_down(msc_a, MSC_ROLE_I,
703 msc_a->ho.subsequent_ho ? MSC_I_EV_FROM_A_PREPARE_SUBSEQUENT_HANDOVER_RESULT
704 : MSC_I_EV_FROM_A_FORWARD_ACCESS_SIGNALLING_REQUEST,
705 &ran_enc_msg)) {
706 msc_ho_failed(msc_a, GSM0808_CAUSE_EQUIPMENT_FAILURE, "Failed to send Handover Command\n");
707 return;
708 }
709
710 msc_a->ho.new_cell.ran_remote_rtp = hra->ran_dec->handover_request_ack.remote_rtp;
Neels Hofmeyr84ce2062019-10-05 05:15:25 +0200711 if (osmo_sockaddr_str_is_nonzero(&msc_a->ho.new_cell.ran_remote_rtp)) {
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100712 LOG_HO(msc_a, LOGL_DEBUG, "Request Ack contains cell's RTP address " OSMO_SOCKADDR_STR_FMT "\n",
713 OSMO_SOCKADDR_STR_FMT_ARGS(&msc_a->ho.new_cell.ran_remote_rtp));
714 }
715
716 msc_a->ho.new_cell.codec_present = hra->ran_dec->handover_request_ack.codec_present;
717 msc_a->ho.new_cell.codec = hra->ran_dec->handover_request_ack.codec;
718 if (hra->ran_dec->handover_request_ack.codec_present) {
719 LOG_HO(msc_a, LOGL_DEBUG, "Request Ack contains codec %s\n",
Neels Hofmeyr7934e0d2022-10-31 18:13:47 +0100720 gsm0808_speech_codec_type_name(msc_a->ho.new_cell.codec.type));
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100721 }
722}
723
724static void msc_ho_rtp_switch_to_new_cell(struct msc_a *msc_a)
725{
726 struct call_leg *cl = msc_a->cc.call_leg;
727 struct rtp_stream *rtp_to_ran = cl ? cl->rtp[RTP_TO_RAN] : NULL;
728
729 if (!rtp_to_ran) {
730 LOG_HO(msc_a, LOGL_DEBUG, "No RTP stream, nothing to switch\n");
731 return;
732 }
733
Neels Hofmeyr84ce2062019-10-05 05:15:25 +0200734 if (!osmo_sockaddr_str_is_nonzero(&msc_a->ho.new_cell.ran_remote_rtp)) {
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100735 LOG_HO(msc_a, LOGL_DEBUG, "New cell's RTP IP:port not yet known, not switching RTP stream\n");
736 return;
737 }
738
739 if (msc_a->ho.rtp_switched_to_new_cell) {
740 LOG_HO(msc_a, LOGL_DEBUG, "Already switched RTP to new cell\n");
741 return;
742 }
743 msc_a->ho.rtp_switched_to_new_cell = true;
744
745 /* Backup old cell's RTP IP:port and codec data */
746 msc_a->ho.old_cell.ran_remote_rtp = rtp_to_ran->remote;
Neels Hofmeyr62bfa372022-10-31 18:51:07 +0100747 msc_a->ho.old_cell.codecs = rtp_to_ran->codecs;
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100748
749 LOG_HO(msc_a, LOGL_DEBUG, "Switching RTP stream to new cell: from " OSMO_SOCKADDR_STR_FMT " to " OSMO_SOCKADDR_STR_FMT "\n",
750 OSMO_SOCKADDR_STR_FMT_ARGS(&msc_a->ho.old_cell.ran_remote_rtp),
751 OSMO_SOCKADDR_STR_FMT_ARGS(&msc_a->ho.new_cell.ran_remote_rtp));
752
753 /* If a previous forwarding to a remote MSC is still active, this now becomes no longer responsible for the RTP
754 * stream. */
755 if (msc_a->cc.mncc_forwarding_to_remote_ran) {
756 if (msc_a->cc.mncc_forwarding_to_remote_ran->rtps != rtp_to_ran) {
757 LOG_HO(msc_a, LOGL_ERROR,
758 "Unexpected state: previous MNCC forwarding not using RTP-to-RAN stream\n");
759 /* That would be weird, but carry on anyway... */
760 }
761 mncc_call_detach_rtp_stream(msc_a->cc.mncc_forwarding_to_remote_ran);
762 }
763
764 /* Switch over to the new peer */
765 rtp_stream_set_remote_addr(rtp_to_ran, &msc_a->ho.new_cell.ran_remote_rtp);
Neels Hofmeyr62bfa372022-10-31 18:51:07 +0100766 if (msc_a->ho.new_cell.codec_present) {
Neels Hofmeyr7934e0d2022-10-31 18:13:47 +0100767 const struct codec_mapping *m;
768 m = codec_mapping_by_gsm0808_speech_codec_type(msc_a->ho.new_cell.codec.type);
769 /* TODO: use codec_mapping_by_gsm0808_speech_codec() to also match on codec.cfg */
770 if (!m)
771 LOG_HO(msc_a, LOGL_ERROR, "Cannot resolve codec: %s\n",
772 gsm0808_speech_codec_type_name(msc_a->ho.new_cell.codec.type));
773 else
774 rtp_stream_set_one_codec(rtp_to_ran, &m->sdp);
Neels Hofmeyr62bfa372022-10-31 18:51:07 +0100775 } else {
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100776 LOG_HO(msc_a, LOGL_ERROR, "No codec is set\n");
Neels Hofmeyr62bfa372022-10-31 18:51:07 +0100777 }
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100778 rtp_stream_commit(rtp_to_ran);
779}
780
781static void msc_ho_rtp_rollback_to_old_cell(struct msc_a *msc_a)
782{
783 struct call_leg *cl = msc_a->cc.call_leg;
784 struct rtp_stream *rtp_to_ran = cl ? cl->rtp[RTP_TO_RAN] : NULL;
785
786 if (!msc_a->ho.rtp_switched_to_new_cell) {
787 LOG_HO(msc_a, LOGL_DEBUG, "Not switched RTP to new cell yet, no need to roll back\n");
788 return;
789 }
790
791 if (!rtp_to_ran) {
792 LOG_HO(msc_a, LOGL_DEBUG, "No RTP stream, nothing to switch\n");
793 return;
794 }
795
Neels Hofmeyr84ce2062019-10-05 05:15:25 +0200796 if (!osmo_sockaddr_str_is_nonzero(&msc_a->ho.old_cell.ran_remote_rtp)) {
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100797 LOG_HO(msc_a, LOGL_DEBUG, "Have no RTP IP:port for the old cell, not switching back to\n");
798 return;
799 }
800
801 /* The new call forwarding to a remote MSC is no longer needed because the handover failed */
802 if (msc_a->ho.new_cell.mncc_forwarding_to_remote_ran)
803 mncc_call_detach_rtp_stream(msc_a->ho.new_cell.mncc_forwarding_to_remote_ran);
804
805 /* If before this handover, there was a call forwarding to a remote MSC in place, this now goes back into
806 * responsibility. */
807 if (msc_a->cc.mncc_forwarding_to_remote_ran)
808 mncc_call_set_rtp_stream(msc_a->cc.mncc_forwarding_to_remote_ran, rtp_to_ran);
809
810 msc_a->ho.rtp_switched_to_new_cell = false;
811 msc_a->ho.ready_to_switch_rtp = false;
812 LOG_HO(msc_a, LOGL_NOTICE, "Switching RTP back to old cell\n");
813
814 /* Switch back to the old cell */
815 rtp_stream_set_remote_addr(rtp_to_ran, &msc_a->ho.old_cell.ran_remote_rtp);
Neels Hofmeyr62bfa372022-10-31 18:51:07 +0100816 rtp_stream_set_codecs(rtp_to_ran, &msc_a->ho.old_cell.codecs);
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100817 rtp_stream_commit(rtp_to_ran);
818}
819
820static void msc_ho_send_handover_succeeded(struct msc_a *msc_a)
821{
822 struct ran_msg ran_enc_msg = {
823 .msg_type = RAN_MSG_HANDOVER_SUCCEEDED,
824 };
825
826 if (msc_a_msg_down(msc_a, MSC_ROLE_I, MSC_I_EV_FROM_A_FORWARD_ACCESS_SIGNALLING_REQUEST, &ran_enc_msg))
827 msc_ho_failed(msc_a, GSM0808_CAUSE_EQUIPMENT_FAILURE, "Failed to send Handover Succeeded message\n");
828}
829
830static void msc_ho_fsm_wait_complete(struct osmo_fsm_inst *fi, uint32_t event, void *data)
831{
832 struct msc_a *msc_a = fi->priv;
833
834 switch (event) {
835
836 case MSC_HO_EV_RX_DETECT:
837 msc_a->ho.ready_to_switch_rtp = true;
838 /* For inter-MSC, the mncc_fsm switches the rtp_stream upon MNCC_RTP_CONNECT.
839 * For inter-BSC, need to switch here to the address obtained from Handover Request Ack. */
840 if (msc_a->ho.new_cell.type == MSC_NEIGHBOR_TYPE_LOCAL_RAN_PEER)
841 msc_ho_rtp_switch_to_new_cell(msc_a);
842 msc_ho_send_handover_succeeded(msc_a);
843 return;
844
845 case MSC_HO_EV_RX_COMPLETE:
846 msc_ho_success(msc_a);
847 return;
848
849 case MSC_HO_EV_RX_FAILURE:
850 msc_ho_failed(msc_a, GSM0808_CAUSE_NO_RADIO_RESOURCE_AVAILABLE,
851 "Received Handover Failure message\n");
852 return;
853
854 case MSC_HO_EV_MNCC_FORWARDING_FAILED:
855 msc_ho_failed(msc_a, GSM0808_CAUSE_EQUIPMENT_FAILURE, "MNCC Forwarding failed\n");
856 return;
857
858 case MSC_HO_EV_MNCC_FORWARDING_COMPLETE:
859 return;
860
861 default:
862 OSMO_ASSERT(false);
863 }
864}
865
866static void msc_ho_fsm_cleanup(struct osmo_fsm_inst *fi, enum osmo_fsm_term_cause cause)
867{
868 struct msc_a *msc_a = fi->priv;
869 struct msc_t *msc_t = msc_a_msc_t(msc_a);
870
871 /* paranoia */
872 if (msc_a->ho.fi != fi)
873 return;
874
875 /* Completely clear all handover state */
876 msc_a->ho = (struct msc_ho_state){};
877
878 if (msc_t)
879 msc_t_clear(msc_t);
880}
881
882static int msc_ho_fsm_timer_cb(struct osmo_fsm_inst *fi)
883{
884 return 1;
885}
886
887#define S(x) (1 << (x))
888
889static const struct osmo_fsm_state msc_ho_fsm_states[] = {
890 [MSC_HO_ST_REQUIRED] = {
891 .name = OSMO_STRINGIFY(MSC_HO_ST_REQUIRED),
892 .out_state_mask = 0
893 | S(MSC_HO_ST_REQUIRED)
894 | S(MSC_HO_ST_WAIT_REQUEST_ACK)
895 ,
896 .onenter = msc_ho_fsm_required_onenter,
897 },
898 [MSC_HO_ST_WAIT_REQUEST_ACK] = {
899 .name = OSMO_STRINGIFY(MSC_HO_ST_WAIT_REQUEST_ACK),
900 .in_event_mask = 0
901 | S(MSC_HO_EV_RX_REQUEST_ACK)
902 | S(MSC_HO_EV_RX_FAILURE)
903 ,
904 .out_state_mask = 0
905 | S(MSC_HO_ST_REQUIRED)
906 | S(MSC_HO_ST_WAIT_COMPLETE)
907 ,
908 .onenter = msc_ho_fsm_wait_request_ack_onenter,
909 .action = msc_ho_fsm_wait_request_ack,
910 },
911 [MSC_HO_ST_WAIT_COMPLETE] = {
912 .name = OSMO_STRINGIFY(MSC_HO_ST_WAIT_COMPLETE),
913 .in_event_mask = 0
914 | S(MSC_HO_EV_RX_DETECT)
915 | S(MSC_HO_EV_RX_COMPLETE)
916 | S(MSC_HO_EV_RX_FAILURE)
917 | S(MSC_HO_EV_MNCC_FORWARDING_COMPLETE)
918 | S(MSC_HO_EV_MNCC_FORWARDING_FAILED)
919 ,
920 .action = msc_ho_fsm_wait_complete,
921 },
922};
923
924static const struct value_string msc_ho_fsm_event_names[] = {
925 OSMO_VALUE_STRING(MSC_HO_EV_RX_REQUEST_ACK),
926 OSMO_VALUE_STRING(MSC_HO_EV_RX_DETECT),
927 OSMO_VALUE_STRING(MSC_HO_EV_RX_COMPLETE),
928 OSMO_VALUE_STRING(MSC_HO_EV_RX_FAILURE),
929 {}
930};
931
932struct osmo_fsm msc_ho_fsm = {
933 .name = "handover",
934 .states = msc_ho_fsm_states,
935 .num_states = ARRAY_SIZE(msc_ho_fsm_states),
936 .log_subsys = DHO,
937 .event_names = msc_ho_fsm_event_names,
938 .timer_cb = msc_ho_fsm_timer_cb,
939 .cleanup = msc_ho_fsm_cleanup,
940};