Harald Welte has submitted this change and it was merged. ( https://gerrit.osmocom.org/9674 )
Change subject: bsc: inter-BSC HO: add TC_ho_out_of_this_bsc, TC_ho_into_this_bsc ...................................................................... bsc: inter-BSC HO: add TC_ho_out_of_this_bsc, TC_ho_into_this_bsc Add f_gen_handover_req() like f_gen_ass_req(), to match AoIP or SCCPlite requirements. For incoming HO, MSC_ConnHdlr needs to know the SCCP addresses to expect the incoming SCCP Connection from MSC to BSC. Add 'handover' section to TestHdlrParams, and pass in the addresses from test_CT via that. In osmo-bsc.cfg, add a remote neighbor config, so that the VTY command 'handover any to arfcn 123 bsic any' can trigger an outgoing inter-BSC HO. Add various BSSMAP handover templates to BSSMAP_Templates.ttcn. Add RR Ho Command template to L3_Templates.ttcn. Move ts_BSSAP_Conn_Req() from msc/BSC_ConnectionHandler.ttcn to library/BSSMAP_Emulation.ttcn, so we can also model an SCCP Connection Request in BSC_Tests.ttcn (this time from MSC to BSC). Add the two new tests to bsc/expected-results.xml. Related: OS#2283 Change-Id: Id22852d4be7f127d827e7a8beeec55db27c07f03 --- M bsc/BSC_Tests.ttcn M bsc/MSC_ConnectionHandler.ttcn M bsc/expected-results.xml M bsc/osmo-bsc.cfg M library/BSSMAP_Emulation.ttcn M library/BSSMAP_Templates.ttcn M library/L3_Templates.ttcn M msc/BSC_ConnectionHandler.ttcn 8 files changed, 400 insertions(+), 9 deletions(-) Approvals: Harald Welte: Looks good to me, approved Jenkins Builder: Verified diff --git a/bsc/BSC_Tests.ttcn b/bsc/BSC_Tests.ttcn index 9a43ead..4a34310 100644 --- a/bsc/BSC_Tests.ttcn +++ b/bsc/BSC_Tests.ttcn @@ -33,6 +33,8 @@ import from RSL_Types all; import from RSL_Emulation all; import from MGCP_Emulation all; +import from MGCP_Templates all; +import from MGCP_Types all; import from Osmocom_CTRL_Functions all; import from Osmocom_CTRL_Types all; @@ -43,12 +45,15 @@ import from MobileL3_CommonIE_Types all; import from MobileL3_Types all; +import from MobileL3_RRM_Types all; import from L3_Templates all; import from GSM_RR_Types all; import from SCCP_Templates all; import from BSSMAP_Templates all; +import from SCCPasp_Types all; + const integer NUM_BTS := 3; const float T3101_MAX := 12.0; @@ -572,6 +577,19 @@ return ass_cmd; } +function f_gen_handover_req() return PDU_BSSAP { + var PDU_BSSAP ho_req; + if (mp_bssap_cfg.transport == BSSAP_TRANSPORT_AoIP) { + var BSSMAP_IE_AoIP_TransportLayerAddress tla := + valueof(ts_BSSMAP_IE_AoIP_TLA4('01020304'O, 2342)); + ho_req := valueof(ts_BSSMAP_HandoverRequest(omit, tla)); + } else { + var BSSMAP_IE_CircuitIdentityCode cic := valueof(ts_BSSMAP_IE_CIC(0,1)); + ho_req := valueof(ts_BSSMAP_HandoverRequest(cic, omit)); + } + return ho_req; +} + /* generate an assignment complete template for either AoIP or SCCPlite */ function f_gen_exp_compl() return template PDU_BSSAP { var template PDU_BSSAP exp_compl; @@ -2083,6 +2101,10 @@ vc_conn.done; } +/*********************************************************************** + * Handover + ***********************************************************************/ + /* execute a "bts <0-255> trx <0-255> timeslot <0-7> " command on given Dchan */ private function f_vty_ts_action(charstring suffix, integer bts_nr, integer trx_nr, integer ts_nr) runs on test_CT { @@ -2165,6 +2187,158 @@ vc_conn.done; } +private function f_tc_ho_out_of_this_bsc(charstring id) runs on MSC_ConnHdlr { + g_pars := valueof(t_def_TestHdlrPars); + + var PDU_BSSAP ass_req := f_gen_ass_req(); + ass_req.pdu.bssmap.assignmentRequest.channelType := valueof(ts_BSSMAP_IE_ChannelType); + ass_req.pdu.bssmap.assignmentRequest.codecList := valueof(ts_BSSMAP_IE_CodecList({ts_CodecFR})); + var template PDU_BSSAP exp_compl := f_gen_exp_compl(); + f_establish_fully(ass_req, exp_compl); + + f_vty_transceive(BSCVTY, "handover any to arfcn 123 bsic any"); + + BSSAP.receive(tr_BSSMAP_HandoverRequired); + + f_sleep(0.5); + /* The MSC negotiates Handover Request and Handover Request Ack with + * the other BSS and comes back with a BSSMAP Handover Command + * containing an RR Handover Command coming from the target BSS... */ + + var PDU_ML3_NW_MS rr_ho_cmd := valueof(ts_RR_HandoverCommand); + log("Remote cell's RR Handover Command passed through as L3 Info: ", rr_ho_cmd); + var octetstring rr_ho_cmd_enc := enc_PDU_ML3_NW_MS(rr_ho_cmd); + log("Remote cell's RR Handover Command passed through as L3 Info, encoded: ", rr_ho_cmd_enc); + BSSAP.send(ts_BSSMAP_HandoverCommand(rr_ho_cmd_enc)); + + /* expect the Handover Command to go out on RR */ + var RSL_Message rsl_ho_cmd + RSL.receive(tr_RSL_DATA_REQ(g_chan_nr, ?, ?)) -> value rsl_ho_cmd; + log("RSL Data Req went out to first BTS: ", rsl_ho_cmd); + var RSL_IE_Body rsl_ho_cmd_l3; + if (not f_rsl_find_ie(rsl_ho_cmd, RSL_IE_L3_INFO, rsl_ho_cmd_l3)) { + log("RSL message contains no L3 Info IE, expected RR Handover Command"); + setverdict(fail); + } else { + log("Found L3 Info: ", rsl_ho_cmd_l3); + if (rsl_ho_cmd_l3.l3_info.payload != rr_ho_cmd_enc) { + log("FAIL: the BSC sent out a different L3 Info, not matching the RR Handover Command the other BSS forwarded."); + setverdict(fail); + } else { + log("Success: the BSC sent out the same RR Handover Command the other BSS forwarded."); + setverdict(pass); + } + } + + /* When the other BSS has reported a completed handover, this side is + * torn down. */ + + var myBSSMAP_Cause cause_val := GSM0808_CAUSE_HANDOVER_SUCCESSFUL; + var BssmapCause cause := enum2int(cause_val); + BSSAP.send(ts_BSSMAP_ClearCommand(cause)); + + /* Expecting MGCP to DLCX the endpoint's two connections: towards BTS and towards MSC */ + var MgcpCommand mgcp; + interleave { + [] BSSAP.receive(tr_BSSMAP_ClearComplete); + [] MGCP.receive(tr_DLCX()) -> value mgcp { + log("Got first DLCX: ", mgcp); + } + [] MGCP.receive(tr_DLCX()) -> value mgcp { + log("Got second DLCX: ", mgcp); + } + } + setverdict(pass); + f_sleep(1.0); +} +testcase TC_ho_out_of_this_bsc() runs on test_CT { + var MSC_ConnHdlr vc_conn; + + f_init(1, true); + f_sleep(1.0); + + vc_conn := f_start_handler(refers(f_tc_ho_out_of_this_bsc)); + vc_conn.done; +} + +private function f_tc_ho_into_this_bsc(charstring id) runs on MSC_ConnHdlr { + /* Hack: the proper way would be to wait for the BSSMAP Handover Request ACK and extract the + * actual assigned chan_nr from its L3 (RR Handover Command) message. But osmo-bsc starts acting + * on the lchan even before we get a chance to evaluate the BSSMAP Handover Request ACK. So we + * need to assume that osmo-bsc will activate TS 1 and already set up this lchan's RSL emulation + * before we get started. */ + var RslChannelNr new_chan_nr := valueof(t_RslChanNr0(1, RSL_CHAN_NR_Bm_ACCH)); + f_rslem_register(0, new_chan_nr); + g_chan_nr := new_chan_nr; + f_sleep(1.0); + + f_create_mgcp_expect(ExpectCriteria:{omit,omit,omit}); + f_MscConnHdlr_init(g_pars.media_nr, "127.0.0.2", "127.0.0.3", FR_AMR); + activate(as_Media()); + + BSSAP.send(ts_BSSAP_Conn_Req(g_pars.handover.sccp_addr_bsc, g_pars.handover.sccp_addr_msc, + f_gen_handover_req())); + BSSAP.receive(BSSAP_Conn_Prim:MSC_CONN_PRIM_CONF_IND); + + /* The RSL Emulation magically accepts the Chan Activ behind the scenes. */ + + var PDU_BSSAP rx_bssap; + var octetstring ho_command_str; + + BSSAP.receive(tr_BSSMAP_HandoverRequestAcknowledge(?)) -> value rx_bssap; + + ho_command_str := rx_bssap.pdu.bssmap.handoverRequestAck.layer3Information.layer3info; + log("Received L3 Info in HO Request Ack: ", ho_command_str); + var PDU_ML3_NW_MS ho_command := dec_PDU_ML3_NW_MS(ho_command_str); + log("L3 Info in HO Request Ack is ", ho_command); + + var GsmArfcn arfcn; + var RslChannelNr actual_new_chan_nr; + f_ChDesc2RslChanNr(ho_command.msgs.rrm.handoverCommand.channelDescription2, + actual_new_chan_nr, arfcn); + + if (actual_new_chan_nr != new_chan_nr) { + log("ERROR: osmo-bsc assigned a different lchan than we assumed above -- this test will fail now.", + " Assumed: ", new_chan_nr, " Assigned: ", actual_new_chan_nr); + setverdict(fail); + return; + } + log("Handover Command chan_nr is", actual_new_chan_nr); + + /* Now the MSC forwards the RR Handover Command to the other BSC, which + * tells the MS to handover to the new lchan. Here comes the new MS on + * the new lchan with a Handover RACH: */ + + /* send handover detect */ + + RSL.send(ts_RSL_HANDO_DET(new_chan_nr)); + + BSSAP.receive(tr_BSSMAP_HandoverDetect); + + /* send handover complete over the new channel */ + + var PDU_ML3_MS_NW l3_tx := valueof(ts_RRM_HandoverComplete('00'O)); + RSL.send(ts_RSL_EST_IND(new_chan_nr, valueof(ts_RslLinkID_DCCH(0)), + enc_PDU_ML3_MS_NW(l3_tx))); + + BSSAP.receive(tr_BSSMAP_HandoverComplete); + setverdict(pass); +} +testcase TC_ho_into_this_bsc() runs on test_CT { + var MSC_ConnHdlr vc_conn; + var TestHdlrParams pars := valueof(t_def_TestHdlrPars); + + f_init(1, true); + f_sleep(1.0); + + pars.handover.sccp_addr_msc := g_bssap.sccp_addr_own; + pars.handover.sccp_addr_bsc := g_bssap.sccp_addr_peer; + + vc_conn := f_start_handler(refers(f_tc_ho_into_this_bsc), pars); + vc_conn.done; +} + + /* OS#3041: Open and close N connections in a normal fashion, and expect no * BSSMAP Reset just because of that. */ testcase TC_bssap_rlsd_does_not_cause_bssmap_reset() runs on test_CT { @@ -2648,7 +2822,10 @@ execute( TC_unsol_ho_fail() ); execute( TC_err_82_short_msg() ); execute( TC_err_84_unknown_msg() ); + execute( TC_ho_int() ); + execute( TC_ho_out_of_this_bsc() ); + execute( TC_ho_into_this_bsc() ); execute( TC_bssap_rlsd_does_not_cause_bssmap_reset() ); execute( TC_bssmap_clear_does_not_cause_bssmap_reset() ); diff --git a/bsc/MSC_ConnectionHandler.ttcn b/bsc/MSC_ConnectionHandler.ttcn index 9f67f1b..0b11786 100644 --- a/bsc/MSC_ConnectionHandler.ttcn +++ b/bsc/MSC_ConnectionHandler.ttcn @@ -411,6 +411,11 @@ BIT4 exp_sts optional } +type record TestHdlrParamsHandover { + SCCP_PAR_Address sccp_addr_msc, + SCCP_PAR_Address sccp_addr_bsc +} + type record TestHdlrParams { OCT1 ra, GsmFrameNumber fn, @@ -420,7 +425,8 @@ BSSMAP_IE_SpeechCodecList ass_codec_list optional, RSL_IE_Body expect_mr_conf_ie optional, /* typically present for AMR codecs */ TestHdlrEncrParams encr optional, - TestHdlrParamsLcls lcls + TestHdlrParamsLcls lcls, + TestHdlrParamsHandover handover optional }; template (value) TestHdlrParams t_def_TestHdlrPars := { @@ -437,7 +443,8 @@ cfg := omit, csc := omit, exp_sts := omit - } + }, + handover := omit } function f_create_chan_and_exp() runs on MSC_ConnHdlr { diff --git a/bsc/expected-results.xml b/bsc/expected-results.xml index 33bc243..64d0444 100644 --- a/bsc/expected-results.xml +++ b/bsc/expected-results.xml @@ -1,5 +1,5 @@ <?xml version="1.0"?> -<testsuite name='BSC_Tests' tests='89' failures='0' errors='0' skipped='0' inconc='0' time='MASKED'> +<testsuite name='BSC_Tests' tests='91' failures='0' errors='0' skipped='0' inconc='0' time='MASKED'> <testcase classname='BSC_Tests' name='TC_ctrl_msc_connection_status' time='MASKED'/> <testcase classname='BSC_Tests' name='TC_ctrl_msc0_connection_status' time='MASKED'/> <testcase classname='BSC_Tests' name='TC_ctrl' time='MASKED'/> @@ -69,6 +69,8 @@ <testcase classname='BSC_Tests' name='TC_err_82_short_msg' time='MASKED'/> <testcase classname='BSC_Tests' name='TC_err_84_unknown_msg' time='MASKED'/> <testcase classname='BSC_Tests' name='TC_ho_int' time='MASKED'/> + <testcase classname='BSC_Tests' name='TC_ho_out_of_this_bsc' time='MASKED'/> + <testcase classname='BSC_Tests' name='TC_ho_into_this_bsc' time='MASKED'/> <testcase classname='BSC_Tests' name='TC_bssap_rlsd_does_not_cause_bssmap_reset' time='MASKED'/> <testcase classname='BSC_Tests' name='TC_bssmap_clear_does_not_cause_bssmap_reset' time='MASKED'/> <testcase classname='BSC_Tests' name='TC_ms_rel_ind_does_not_cause_bssmap_reset' time='MASKED'/> diff --git a/bsc/osmo-bsc.cfg b/bsc/osmo-bsc.cfg index b85c690..724d567 100644 --- a/bsc/osmo-bsc.cfg +++ b/bsc/osmo-bsc.cfg @@ -88,6 +88,8 @@ early-classmark-sending forbidden ip.access unit_id 1234 0 oml ip.access stream_id 255 line 0 + # remote-BSS neighbor: + neighbor add lac 99 arfcn 123 bsic any neighbor-list mode manual-si5 neighbor-list add arfcn 100 neighbor-list add arfcn 200 diff --git a/library/BSSMAP_Emulation.ttcn b/library/BSSMAP_Emulation.ttcn index 921ac59..55ce2fb 100644 --- a/library/BSSMAP_Emulation.ttcn +++ b/library/BSSMAP_Emulation.ttcn @@ -102,6 +102,12 @@ dtap := dtap } +template BSSAP_Conn_Req ts_BSSAP_Conn_Req(SCCP_PAR_Address peer, SCCP_PAR_Address own, PDU_BSSAP bssap) := { + addr_peer := peer, + addr_own := own, + bssap := bssap +}; + /* port between individual per-connection components and this dispatcher */ type port BSSAP_Conn_PT message { diff --git a/library/BSSMAP_Templates.ttcn b/library/BSSMAP_Templates.ttcn index 70db2ec..adfcc9e 100644 --- a/library/BSSMAP_Templates.ttcn +++ b/library/BSSMAP_Templates.ttcn @@ -670,6 +670,139 @@ } } +template PDU_BSSAP tr_BSSMAP_HandoverRequired modifies tr_BSSAP_BSSMAP := { + pdu := { + bssmap := { + handoverRequired := { + messageType := '11'O + } + } + } +} + +template (value) PDU_BSSAP ts_BSSMAP_HandoverCommand(octetstring layer3info) +modifies ts_BSSAP_BSSMAP := { + pdu := { + bssmap := { + handoverCommand := { + messageType := '13'O, + layer3Information := { + elementIdentifier := '17'O, + lengthIndicator := 0, + layer3info := layer3info + }, + cellIdentifier := omit, + newBSSToOldBSSInfo := omit, + talkerPriority := omit + } + } + } +} + +template PDU_BSSAP ts_BSSMAP_HandoverRequest( + template BSSMAP_IE_CircuitIdentityCode cic := omit, + template BSSMAP_IE_AoIP_TransportLayerAddress aoip_tla := omit, + template BSSMAP_IE_CellIdentifier cell_id_target := ts_CellID_LAC_CI(1, 0), + template BSSMAP_IE_CellIdentifier cell_id_source := ts_CellID_LAC_CI(1, 1) + ) +modifies ts_BSSAP_BSSMAP := { + pdu := { + bssmap := { + handoverRequest := { + messageType := '10'O, + channelType := ts_BSSMAP_IE_ChannelType, + encryptionInformation := + ts_BSSMAP_IE_EncrInfo('0000000000000000'O,'01'O), + classmarkInformationType := { + classmarkInformationType1 := { + elementIdentifier := '1D'O, + rf_PowerCapability := '000'B, + a5_1 := '0'B, + esind := '0'B, + revisionLevel := '10'B, + spare1_1 := '0'B + } + }, + cellIdentifierSource := cell_id_source, + priority := omit, + circuitIdentityCode := cic, + downLinkDTX_Flag := omit, + cellIdentifierTarget := cell_id_target, + interferenceBandToBeUsed := omit, + cause := omit, + classmarkInformationType3 := omit, + currentChannelType1 := omit, + speechVersion := omit, + groupCallReference := omit, + talkerFlag := omit, + configurationEvolutionIndication := omit, + chosenEncryptionAlgorithm := omit, + oldToNewBSSInfo := omit, + lSAInformation := omit, + lSAAccessControlSuppression := omit, + serviceHandover := omit, + iMSI_bssmap := omit, + sourceToTargetRNCTransparentInfo := omit, + sourceToTargetRNCTransparentInfoCDMA := omit, + sNAAccessInformation := omit, + talkerPriority := omit, + aoIPTransportLayer := aoip_tla, + codecList := omit, + callIdentifier := omit, + kC128 := omit, + globalCallReference := omit, + lCLS_Configuration := omit, + connectionStatusControl := omit + } + } + } +} + +template PDU_BSSAP tr_BSSMAP_HandoverRequestAcknowledge(template octetstring layer3info) +modifies tr_BSSAP_BSSMAP := { + pdu := { + bssmap := { + handoverRequestAck := { + messageType := '12'O, + layer3Information := { + elementIdentifier := '17'O, + lengthIndicator := ?, + layer3info := layer3info + } + } + } + } +} + +template PDU_BSSAP tr_BSSMAP_HandoverDetect +modifies tr_BSSAP_BSSMAP := { + pdu := { + bssmap := { + handoverDetect := { + messageType := '1B'O, + talkerPriority := * + } + } + } +} + +template PDU_BSSAP tr_BSSMAP_HandoverComplete +modifies tr_BSSAP_BSSMAP := { + pdu := { + bssmap := { + handoverComplete := { + messageType := '14'O, + rR_Cause := *, + talkerPriority := *, + speechCodec := *, + codecList := *, + chosenEncryptionAlgorithm := *, + chosenChannel := *, + lCLS_BSS_Status := * + } + } + } +} template BSSMAP_IE_IMSI ts_BSSMAP_Imsi(hexstring imsi_digits) := { elementIdentifier := '08'O, diff --git a/library/L3_Templates.ttcn b/library/L3_Templates.ttcn index 1ce84cf..a05aba2 100644 --- a/library/L3_Templates.ttcn +++ b/library/L3_Templates.ttcn @@ -496,6 +496,76 @@ } } +template (value) PDU_ML3_NW_MS ts_RR_HandoverCommand := { + discriminator := '0110'B, + tiOrSkip := { + skipIndicator := '0000'B + }, + msgs := { + rrm := { + handoverCommand := { + messageType := '00101011'B, + cellDescription := { + bcc := '001'B, + ncc := '010'B, + BCCHArfcn_HighPart := '11'B, + BCCHArfcn_LowPart := '04'O + }, + channelDescription2 := { + timeslotNumber := '110'B, + channelTypeandTDMAOffset := '00001'B, + octet3 := '00'O, + octet4 := '09'O + }, + handoverReference := { + handoverReferenceValue := '00'O + }, + powerCommandAndAccesstype := { + powerlevel := '00000'B, + fPC_EP := '0'B, + ePC_Mode := '0'B, + aTC := '0'B + }, + synchronizationIndication := omit, + frequencyShortListAfterTime := omit, + frequencyListAfterTime := omit, + cellChannelDescription := omit, + multislotAllocation := omit, + modeOfChannelSet1 := omit, + modeOfChannelSet2 := omit, + modeOfChannelSet3 := omit, + modeOfChannelSet4 := omit, + modeOfChannelSet5 := omit, + modeOfChannelSet6 := omit, + modeOfChannelSet7 := omit, + modeOfChannelSet8 := omit, + descrOf2ndCh_at := omit, + modeOf2ndChannel := omit, + frequencyChannelSequence_at := omit, + mobileAllocation_at := omit, + startingTime := omit, + timeDifference := omit, + timingAdvance := omit, + frequencyShortListBeforeTime := omit, + frequencyListBeforeTime := omit, + descrOf1stCh_bt := omit, + descrOf2ndCh_bt := omit, + frequencyChannelSequence_bt := omit, + mobileAllocation_bt := omit, + cipherModeSetting := omit, + vGCS_TargetModeIndication := omit, + multiRateConfiguration := omit, + dynamicARFCN_Mapping := omit, + vGCS_Ciphering_Parameters := omit, + dedicatedServiceInformation := omit, + pLMNIndex := omit, + extendedTSCSet_afterTime := omit, + extendedTSCSet_beforeTime := omit + } + } + } +} + function ts_CM3_TLV(template (omit) OCTN cm3) return template MobileStationClassmark3_TLV { if (not isvalue(cm3)) { return omit; diff --git a/msc/BSC_ConnectionHandler.ttcn b/msc/BSC_ConnectionHandler.ttcn index 4e02d6c..bf7a6d2 100644 --- a/msc/BSC_ConnectionHandler.ttcn +++ b/msc/BSC_ConnectionHandler.ttcn @@ -166,12 +166,6 @@ -template BSSAP_Conn_Req ts_BSSAP_Conn_Req(SCCP_PAR_Address peer, SCCP_PAR_Address own, PDU_BSSAP bssap) := { - addr_peer := peer, - addr_own := own, - bssap := bssap -}; - /* Encode 'l3' and ask BSSMAP_Emulation to create new connection with COMPL L3 INFO */ function f_bssap_compl_l3(PDU_ML3_MS_NW l3) runs on BSC_ConnHdlr { -- To view, visit https://gerrit.osmocom.org/9674 To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings Gerrit-Project: osmo-ttcn3-hacks Gerrit-Branch: master Gerrit-MessageType: merged Gerrit-Change-Id: Id22852d4be7f127d827e7a8beeec55db27c07f03 Gerrit-Change-Number: 9674 Gerrit-PatchSet: 8 Gerrit-Owner: Neels Hofmeyr <nhofm...@sysmocom.de> Gerrit-Reviewer: Harald Welte <lafo...@gnumonks.org> Gerrit-Reviewer: Jenkins Builder (1000002) Gerrit-Reviewer: Neels Hofmeyr <nhofm...@sysmocom.de>