aboutsummaryrefslogtreecommitdiffstats
path: root/src/libmsc/msc_t.c
blob: af0ddaaef55e791f9e08b35dd5fcaa6d1028ef76 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
/* The MSC-T role, a transitional RAN connection during Handover. */
/*
 * (C) 2019 by sysmocom - s.m.f.c. GmbH <info@sysmocom.de>
 * 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 <http://www.gnu.org/licenses/>.
 */

#include <inttypes.h>

#include <osmocom/gsm/gsm48_ie.h>

#include <osmocom/msc/msc_t.h>
#include <osmocom/msc/msc_a.h>
#include <osmocom/msc/msc_a_remote.h>
#include <osmocom/msc/ran_infra.h>
#include <osmocom/msc/ran_peer.h>
#include <osmocom/msc/ran_conn.h>
#include <osmocom/msc/msub.h>
#include <osmocom/msc/call_leg.h>
#include <osmocom/msc/rtp_stream.h>
#include <osmocom/msc/ran_infra.h>
#include <osmocom/msc/vlr.h>
#include <osmocom/msc/msc_i.h>
#include <osmocom/msc/gsm_data.h>

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);
}