WIP: Intra-BSC handover testing
Change-Id: Ic47e639a7c8640c736c84a44780fc8e111a64b52
This commit is contained in:
parent
c20b1c4207
commit
261af4b501
|
@ -1277,6 +1277,8 @@ function f_start_handler(void_fn fn, charstring id) runs on test_CT return MSC_C
|
||||||
connect(vc_conn:MGCP_PROC, vc_MGCP:MGCP_PROC);
|
connect(vc_conn:MGCP_PROC, vc_MGCP:MGCP_PROC);
|
||||||
connect(vc_conn:RSL, bts[0].rsl.vc_RSL:CLIENT_PT);
|
connect(vc_conn:RSL, bts[0].rsl.vc_RSL:CLIENT_PT);
|
||||||
connect(vc_conn:RSL_PROC, bts[0].rsl.vc_RSL:RSL_PROC);
|
connect(vc_conn:RSL_PROC, bts[0].rsl.vc_RSL:RSL_PROC);
|
||||||
|
connect(vc_conn:RSL1, bts[1].rsl.vc_RSL:CLIENT_PT);
|
||||||
|
connect(vc_conn:RSL1_PROC, bts[1].rsl.vc_RSL:RSL_PROC);
|
||||||
connect(vc_conn:BSSAP, g_bssap.vc_BSSMAP:CLIENT);
|
connect(vc_conn:BSSAP, g_bssap.vc_BSSMAP:CLIENT);
|
||||||
connect(vc_conn:MGCP, vc_MGCP:MGCP_CLIENT);
|
connect(vc_conn:MGCP, vc_MGCP:MGCP_CLIENT);
|
||||||
vc_conn.start(derefers(fn)(id));
|
vc_conn.start(derefers(fn)(id));
|
||||||
|
@ -1553,6 +1555,71 @@ testcase TC_err_84_unknown_msg() runs on test_CT {
|
||||||
vc_conn.done;
|
vc_conn.done;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* execute a "bts <0-255> trx <0-255> timeslot <0-7> sub-slot <0-7>" command on given Dchan */
|
||||||
|
private function f_vty_ss_action(charstring suffix, integer bts_nr, integer trx_nr, RslChannelNr chan_nr)
|
||||||
|
runs on MSC_ConnHdlr {
|
||||||
|
/* FIXME: resolve those from component-global state */
|
||||||
|
var integer ts_nr := chan_nr.tn;
|
||||||
|
var integer ss_nr;
|
||||||
|
if (ischosen(chan_nr.u.ch0)) {
|
||||||
|
ss_nr := 0;
|
||||||
|
} else if (ischosen(chan_nr.u.lm)) {
|
||||||
|
ss_nr := chan_nr.u.lm.sub_chan;
|
||||||
|
} else if (ischosen(chan_nr.u.sdcch4)) {
|
||||||
|
ss_nr := chan_nr.u.sdcch4.sub_chan;
|
||||||
|
} else if (ischosen(chan_nr.u.sdcch8)) {
|
||||||
|
ss_nr := chan_nr.u.sdcch8.sub_chan;
|
||||||
|
} else {
|
||||||
|
setverdict(fail, "Invalid ChanNr ", chan_nr);
|
||||||
|
self.stop;
|
||||||
|
}
|
||||||
|
|
||||||
|
var charstring cmd := "bts "&int2str(bts_nr)&" trx "&int2str(trx_nr)&
|
||||||
|
" timeslot "&int2str(ts_nr)&" sub-slot "&int2str(ss_nr)&" ";
|
||||||
|
f_vty_transceive(BSCVTY, cmd & suffix);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function f_vty_handover(integer bts_nr, integer trx_nr, RslChannelNr chan_nr,
|
||||||
|
integer new_bts_nr)
|
||||||
|
runs on MSC_ConnHdlr {
|
||||||
|
f_vty_ss_action("handover " & int2str(new_bts_nr), bts_nr, trx_nr, chan_nr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* intra-BSC hand-over between BTS0 and BTS1 */
|
||||||
|
private function f_tc_ho_int(charstring id) runs on MSC_ConnHdlr {
|
||||||
|
var TestHdlrParams pars := valueof(t_def_TestHdlrPars);
|
||||||
|
var template PDU_BSSAP exp_compl := tr_BSSMAP_AssignmentComplete(omit, ?);
|
||||||
|
var BSSMAP_IE_AoIP_TransportLayerAddress tla := valueof(ts_BSSMAP_IE_AoIP_TLA4('01020304'O, 2342));
|
||||||
|
var PDU_BSSAP ass_cmd := valueof(ts_BSSMAP_AssignmentReq(omit, tla));
|
||||||
|
const OCT8 kc := '0001020304050607'O;
|
||||||
|
|
||||||
|
ass_cmd.pdu.bssmap.assignmentRequest.channelType := valueof(ts_BSSMAP_IE_ChannelType);
|
||||||
|
ass_cmd.pdu.bssmap.assignmentRequest.codecList := valueof(ts_BSSMAP_IE_CodecList({ts_CodecFR}));
|
||||||
|
|
||||||
|
f_establish_fully(pars, ass_cmd, exp_compl);
|
||||||
|
|
||||||
|
var HandoverState hs := {
|
||||||
|
rr_ho_cmpl_seen := false,
|
||||||
|
handover_done := false,
|
||||||
|
old_chan_nr := -
|
||||||
|
};
|
||||||
|
/* issue hand-over command on VTY */
|
||||||
|
f_vty_handover(0, 0, g_chan_nr, 1);
|
||||||
|
/* temporarily suspend DChan processing on BTS1 to avoid race with RSLEM_register */
|
||||||
|
f_rslem_suspend(RSL1_PROC);
|
||||||
|
alt {
|
||||||
|
[] as_handover(hs);
|
||||||
|
/* FIXME: somehow determine that the hand-over has completed, by MGCP MDCX? */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
testcase TC_ho_int() runs on test_CT {
|
||||||
|
var MSC_ConnHdlr vc_conn;
|
||||||
|
f_init(2, true);
|
||||||
|
f_sleep(1.0);
|
||||||
|
vc_conn := f_start_handler(refers(f_tc_ho_int), testcasename());
|
||||||
|
vc_conn.done;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
control {
|
control {
|
||||||
|
@ -1623,6 +1690,7 @@ control {
|
||||||
execute( TC_unsol_ho_fail() );
|
execute( TC_unsol_ho_fail() );
|
||||||
execute( TC_err_82_short_msg() );
|
execute( TC_err_82_short_msg() );
|
||||||
execute( TC_err_84_unknown_msg() );
|
execute( TC_err_84_unknown_msg() );
|
||||||
|
execute( TC_ho_int() );
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,7 +62,8 @@ type record BtsMediaState {
|
||||||
type record MediaState {
|
type record MediaState {
|
||||||
MgcpEndpoint mgcp_ep,
|
MgcpEndpoint mgcp_ep,
|
||||||
MgcpConnState mgcp_conn[2],
|
MgcpConnState mgcp_conn[2],
|
||||||
BtsMediaState bts
|
BtsMediaState bts,
|
||||||
|
BtsMediaState bts1 /* only during hand-over */
|
||||||
};
|
};
|
||||||
|
|
||||||
function f_MediaState_init(inout MediaState g_media, integer nr, HostName bts, HostName mgw) {
|
function f_MediaState_init(inout MediaState g_media, integer nr, HostName bts, HostName mgw) {
|
||||||
|
@ -78,6 +79,17 @@ function f_MediaState_init(inout MediaState g_media, integer nr, HostName bts, H
|
||||||
peer := -
|
peer := -
|
||||||
}
|
}
|
||||||
|
|
||||||
|
g_media.bts1 := {
|
||||||
|
ipa_crcx_seen := false,
|
||||||
|
conn_id := nr,
|
||||||
|
rtp_pt := 0,
|
||||||
|
bts := {
|
||||||
|
host := bts, /* FIXME */
|
||||||
|
port_nr := 9000 + nr*2
|
||||||
|
},
|
||||||
|
peer := -
|
||||||
|
}
|
||||||
|
|
||||||
g_media.mgcp_ep := "rtpbridge/" & int2str(nr) & "@mgw";
|
g_media.mgcp_ep := "rtpbridge/" & int2str(nr) & "@mgw";
|
||||||
|
|
||||||
for (var integer i:= 0; i < sizeof(g_media.mgcp_conn); i := i+1) {
|
for (var integer i:= 0; i < sizeof(g_media.mgcp_conn); i := i+1) {
|
||||||
|
@ -166,9 +178,54 @@ altstep as_Media() runs on MSC_ConnHdlr {
|
||||||
oct2int(f_inet_addr(g_media.bts.peer.host)),
|
oct2int(f_inet_addr(g_media.bts.peer.host)),
|
||||||
g_media.bts.peer.port_nr,
|
g_media.bts.peer.port_nr,
|
||||||
g_media.bts.rtp_pt));
|
g_media.bts.rtp_pt));
|
||||||
//g_media.ipa_mdcx_seen := true;
|
//g_media.bts.ipa_mdcx_seen := true;
|
||||||
repeat;
|
repeat;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* on second (new) BTS during hand-over */
|
||||||
|
[not g_media.bts1.ipa_crcx_seen] RSL1.receive(tr_RSL_IPA_CRCX(g_chan_nr)) -> value rsl {
|
||||||
|
/* Extract parameters from request + use in response */
|
||||||
|
if (f_rsl_find_ie(rsl, RSL_IE_IPAC_RTP_PAYLOAD, ie)) {
|
||||||
|
g_media.bts1.rtp_pt := ie.ipa_rtp_pt;
|
||||||
|
}
|
||||||
|
if (f_rsl_find_ie(rsl, RSL_IE_IPAC_RTP_PAYLOAD2, ie)) {
|
||||||
|
g_media.bts1.rtp_pt := ie.ipa_rtp_pt2;
|
||||||
|
}
|
||||||
|
RSL1.send(ts_RSL_IPA_CRCX_ACK(g_chan_nr, g_media.bts1.conn_id,
|
||||||
|
oct2int(f_inet_addr(g_media.bts1.bts.host)),
|
||||||
|
g_media.bts1.bts.port_nr,
|
||||||
|
g_media.bts1.rtp_pt));
|
||||||
|
g_media.bts1.ipa_crcx_seen := true;
|
||||||
|
repeat;
|
||||||
|
}
|
||||||
|
/* on second (new) BTS during hand-over */
|
||||||
|
[g_media.bts1.ipa_crcx_seen] RSL1.receive(tr_RSL_IPA_MDCX(g_chan_nr, ?)) -> value rsl{
|
||||||
|
/* Extract conn_id, ip, port, rtp_pt2 from request + use in response */
|
||||||
|
f_rsl_find_ie(rsl, RSL_IE_IPAC_CONN_ID, ie);
|
||||||
|
if (g_media.bts1.conn_id != ie.ipa_conn_id) {
|
||||||
|
setverdict(fail, "IPA MDCX for unknown ConnId", rsl);
|
||||||
|
self.stop;
|
||||||
|
}
|
||||||
|
/* mandatory */
|
||||||
|
f_rsl_find_ie(rsl, RSL_IE_IPAC_REMOTE_IP, ie);
|
||||||
|
g_media.bts1.peer.host := f_inet_ntoa(int2oct(ie.ipa_remote_ip, 4));
|
||||||
|
f_rsl_find_ie(rsl, RSL_IE_IPAC_REMOTE_PORT, ie);
|
||||||
|
g_media.bts1.peer.port_nr := ie.ipa_remote_port;
|
||||||
|
/* optional */
|
||||||
|
if (f_rsl_find_ie(rsl, RSL_IE_IPAC_RTP_PAYLOAD, ie)) {
|
||||||
|
g_media.bts1.rtp_pt := ie.ipa_rtp_pt;
|
||||||
|
}
|
||||||
|
if (f_rsl_find_ie(rsl, RSL_IE_IPAC_RTP_PAYLOAD2, ie)) {
|
||||||
|
g_media.bts1.rtp_pt := ie.ipa_rtp_pt2;
|
||||||
|
}
|
||||||
|
RSL1.send(ts_RSL_IPA_MDCX_ACK(g_chan_nr, g_media.bts1.conn_id,
|
||||||
|
oct2int(f_inet_addr(g_media.bts1.peer.host)),
|
||||||
|
g_media.bts1.peer.port_nr,
|
||||||
|
g_media.bts1.rtp_pt));
|
||||||
|
//g_media.bts1.ipa_mdcx_seen := true;
|
||||||
|
repeat;
|
||||||
|
}
|
||||||
|
|
||||||
[] MGCP.receive(tr_CRCX) -> value mgcp_cmd {
|
[] MGCP.receive(tr_CRCX) -> value mgcp_cmd {
|
||||||
var SDP_Message sdp;
|
var SDP_Message sdp;
|
||||||
var integer cid := f_get_free_mgcp_conn();
|
var integer cid := f_get_free_mgcp_conn();
|
||||||
|
@ -219,7 +276,7 @@ altstep as_Media() runs on MSC_ConnHdlr {
|
||||||
int2str(mgcp_conn.sample_rate))),
|
int2str(mgcp_conn.sample_rate))),
|
||||||
valueof(ts_SDP_ptime(mgcp_conn.ptime)) } ));
|
valueof(ts_SDP_ptime(mgcp_conn.ptime)) } ));
|
||||||
MGCP.send(ts_MDCX_ACK(mgcp_cmd.line.trans_id, mgcp_conn.conn_id, sdp));
|
MGCP.send(ts_MDCX_ACK(mgcp_cmd.line.trans_id, mgcp_conn.conn_id, sdp));
|
||||||
//mgcp_mdcx_seen := true;
|
//g_media.mgcp_mdcx_seen := true;
|
||||||
repeat;
|
repeat;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -635,5 +692,61 @@ runs on MSC_ConnHdlr return PDU_BSSAP {
|
||||||
return bssap;
|
return bssap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type record HandoverState {
|
||||||
|
/* Assignment related bits */
|
||||||
|
boolean rr_ho_cmpl_seen,
|
||||||
|
boolean handover_done,
|
||||||
|
RslChannelNr old_chan_nr
|
||||||
|
};
|
||||||
|
|
||||||
|
altstep as_handover(inout HandoverState st) runs on MSC_ConnHdlr {
|
||||||
|
var RSL_Message rsl;
|
||||||
|
[not st.rr_ho_cmpl_seen] RSL.receive(tr_RSL_DATA_REQ(g_chan_nr)) -> value rsl {
|
||||||
|
var PDU_ML3_NW_MS l3 := dec_PDU_ML3_NW_MS(rsl.ies[2].body.l3_info.payload);
|
||||||
|
log("Rx L3 from net: ", l3);
|
||||||
|
if (ischosen(l3.msgs.rrm.handoverCommand)) {
|
||||||
|
var RslChannelNr new_chan_nr;
|
||||||
|
var GsmArfcn arfcn;
|
||||||
|
f_ChDesc2RslChanNr(l3.msgs.rrm.handoverCommand.channelDescription2,
|
||||||
|
new_chan_nr, arfcn);
|
||||||
|
/* FIXME: Determine TRX NR by ARFCN, instead of hard-coded TRX0! */
|
||||||
|
|
||||||
|
/* register our component for this channel number at the RSL Emulation */
|
||||||
|
f_rslem_register(0, new_chan_nr, RSL1_PROC);
|
||||||
|
|
||||||
|
/* resume processing of RSL DChan messages, which was temporarily suspended
|
||||||
|
* before performing a hand-over */
|
||||||
|
f_rslem_resume(RSL1_PROC);
|
||||||
|
|
||||||
|
/* send handover complete over the new channel */
|
||||||
|
var PDU_ML3_MS_NW l3_tx := valueof(ts_RRM_HandoverComplete('00'O));
|
||||||
|
RSL1.send(ts_RSL_DATA_IND(new_chan_nr, valueof(ts_RslLinkID_DCCH(0)),
|
||||||
|
enc_PDU_ML3_MS_NW(l3_tx)));
|
||||||
|
/* by default, send via the new channel from now */
|
||||||
|
st.old_chan_nr := g_chan_nr;
|
||||||
|
g_chan_nr := new_chan_nr;
|
||||||
|
st.rr_ho_cmpl_seen := true;
|
||||||
|
repeat;
|
||||||
|
} else {
|
||||||
|
setverdict(fail, "Unexpected L3 received", l3);
|
||||||
|
self.stop;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
[st.rr_ho_cmpl_seen] as_Media();
|
||||||
|
[st.rr_ho_cmpl_seen] RSL.receive(tr_RSL_REL_REQ(st.old_chan_nr, tr_RslLinkID_DCCH(0))) {
|
||||||
|
RSL.send(ts_RSL_REL_CONF(st.old_chan_nr, valueof(ts_RslLinkID_DCCH(0))));
|
||||||
|
repeat;
|
||||||
|
}
|
||||||
|
[st.rr_ho_cmpl_seen] RSL.receive(tr_RSL_RF_CHAN_REL(st.old_chan_nr)) {
|
||||||
|
RSL.send(ts_RSL_RF_CHAN_REL_ACK(st.old_chan_nr));
|
||||||
|
/* unregister for old channel number in RSL emulation */
|
||||||
|
/* FIXME: Determine TRX NR by ARFCN, instead of hard-coded TRX0! */
|
||||||
|
f_rslem_unregister(0, st.old_chan_nr);
|
||||||
|
st.handover_done := true;
|
||||||
|
repeat;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -338,6 +338,25 @@ template (value) PDU_ML3_MS_NW ts_RRM_HandoverFailure(OCT1 cause) := {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template (value) PDU_ML3_MS_NW ts_RRM_HandoverComplete(OCT1 cause) := {
|
||||||
|
discriminator := '0000'B, /* overwritten */
|
||||||
|
tiOrSkip := {
|
||||||
|
skipIndicator := '0000'B
|
||||||
|
},
|
||||||
|
msgs := {
|
||||||
|
rrm := {
|
||||||
|
handoverComplete := {
|
||||||
|
messageType := '00101100'B,
|
||||||
|
rRCause := {
|
||||||
|
valuePart := cause
|
||||||
|
},
|
||||||
|
mobileObsservedTimeDiff := omit,
|
||||||
|
mobileTimeDifferenceHyperframe := omit
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function ts_CM3_TLV(template (omit) OCTN cm3) return template MobileStationClassmark3_TLV {
|
function ts_CM3_TLV(template (omit) OCTN cm3) return template MobileStationClassmark3_TLV {
|
||||||
if (not isvalue(cm3)) {
|
if (not isvalue(cm3)) {
|
||||||
return omit;
|
return omit;
|
||||||
|
|
Loading…
Reference in New Issue