msc: fix f_tc_ho_inter_bsc0(): properly patch n_sd

Assuming n_sd should be 3 is only valid for non-A5 testcases, in which
we are *not* doing ciphering and authentication.  For the A5 testcases
(TC_ho_inter_bsc_a5_*), this assumption is incorrect and osmo-msc is
definitely not happy about that:

  Duplicate DTAP: bin=0, expected n_sd == 0, got 3 (ran_msg.c:159)
  Dropping duplicate message ... (msc_a.c:1363)

Why and how the A5 testcases passed so far?  It was a pure luck, which
sailed away when we started executing ttcn3-msc-test with io_uring.

The A5 testcases were passing thanks to the as_optional_cc_rel() that
gets activate()d in background before calling f_call_hangup().  This
altstep does not have the 'repeat' statement, and as a side effect it
may cancel any normal alt-statements and even standalone receive()
statements.

In the successful scenario, it would cancel (unblock) the following
receive operation in f_call_hangup():

  MNCC.receive(tr_MNCC_REL_ind(cpars.mncc_callref));
  log("f_call_hangup 2: rx MNCC REL ind");
  BSSAP.receive(tr_PDU_DTAP_MT(tr_ML3_MT_CC_REL_COMPL(cpars.transaction_id)));
  // ^^^^^^^^^^ as_optional_cc_rel() triggers here and cancels this one

which is a pure luck because our CC RELEASE was sent with incorrect
sequence number and got dropped, so osmo-msc would never send us
CC RELEASE COMPLETE.  It would instead send us CC RELEASE due to
expire of T306, and the as_optional_cc_rel() would kick in handling
this message and responding with CC RELEASE COMPLETE.

In the failing scenario though (when running with io_uring), that
same altstep running in backround may trigger *earlier* and unblock
another standalone receive() statement:

  MNCC.receive(tr_MNCC_REL_ind(cpars.mncc_callref));
  // ^^^^^^^^^ as_optional_cc_rel() triggers here and cancels this one
  log("f_call_hangup 2: rx MNCC REL ind");
  BSSAP.receive(tr_PDU_DTAP_MT(tr_ML3_MT_CC_REL_COMPL(cpars.transaction_id)));

so that we will be stuck waiting for CC RELEASE COMPLETE until the
Tguard expires.

This patch fixes n_sd patching, so that our CC RELEASE message is
handled properly and the call gets released as expected, without
requiring as_optional_cc_rel() to kick in.  The missing 'repeat'
is to be added to as_optional_cc_rel() in a follow-up patch.

Change-Id: Iddde391eade716ca5c6c48cb631450ddb543e0d4
Related: OS#6414
This commit is contained in:
Vadim Yanitskiy 2024-03-27 14:05:27 +07:00
parent 9e8db33f2d
commit 5f1018f954
1 changed files with 7 additions and 5 deletions

View File

@ -5778,6 +5778,10 @@ private function f_tc_ho_inter_bsc0(charstring id, BSC_ConnHdlrPars pars) runs o
f_perform_lu();
f_mo_call_establish(cpars);
/* Remember the last n_sd (sequence number),
* we will need it when the other BSS hands over back to us. */
var N_Sd_Array last_n_sd := f_bssmap_last_n_sd();
f_sleep(1.0);
var default ack_mdcx := activate(as_mgcp_ack_all_mdcx(cpars));
@ -5854,13 +5858,11 @@ private function f_tc_ho_inter_bsc0(charstring id, BSC_ConnHdlrPars pars) runs o
deactivate(ack_mdcx);
var default ccrel := activate(as_optional_cc_rel(cpars, true));
/* blatant cheating */
var N_Sd_Array last_n_sd := f_bssmap_last_n_sd();
last_n_sd[0] := 3;
/* Use the n_sd (sequence number) we stored before the first handover.
* Otherwise the MSC may treat our DTAP messages as duplicates and discard them. */
f_bssmap_continue_after_n_sd(last_n_sd);
var default ccrel := activate(as_optional_cc_rel(cpars, true));
f_call_hangup(cpars, true);
f_sleep(1.0);
deactivate(ccrel);