From 908ce54531df42a725482ad91fc6a0d660c74022 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Wed, 4 Sep 2019 23:05:40 +0200 Subject: [PATCH] bts: Add test for ETWS Primary Notification via P1 Rest Octets Change-Id: I247ea0f336e4ae9eecb1e8166f2326bdd2c299f4 Related: OS#4047 --- bts/BTS_Tests_SMSCB.ttcn | 175 +++++++++++++++++++++++++++++++++++++++ library/RSL_Types.ttcn | 24 +++++- 2 files changed, 198 insertions(+), 1 deletion(-) diff --git a/bts/BTS_Tests_SMSCB.ttcn b/bts/BTS_Tests_SMSCB.ttcn index 962b5160e..49416c242 100644 --- a/bts/BTS_Tests_SMSCB.ttcn +++ b/bts/BTS_Tests_SMSCB.ttcn @@ -22,6 +22,7 @@ import from L1CTL_PortType all; import from L1CTL_Types all; import from LAPDm_Types all; import from IPA_Emulation all; +import from GSM_RR_Types all; import from RSL_Types all; @@ -875,6 +876,177 @@ testcase TC_cbc_sdcch8_load_overload() runs on test_CT { } +private template GsmRrMessage tr_PagingType1 := { + header := t_RrHeader(PAGING_REQUEST_TYPE_1, ?), + payload :=? +}; + +private template GsmRrMessage tr_PagingType1_empty := { + header := t_RrHeader(PAGING_REQUEST_TYPE_1, 5), + payload := { + pag_req_1 := { + chan_needed := { + second := CHAN_NEED_ANY, + first := CHAN_NEED_ANY + }, + page_mode := PAGE_MODE_NORMAL, + mi1 := { + len := 1, + mi := { + unused := { + pad := '1111'B, + odd := false, + mi_type := MI_TYPE_NONE + } + } + }, + mi2 := omit, + rest_octets := ? + } + } +}; + +/* we expect four blocks of 14 bytes, let's fill them with content easily distinguishable */ +const octetstring c_etws_seg0 := '000102030405060708090a0b0c0d'O; +const octetstring c_etws_seg1 := '101112131415161718191a1b1c1d'O; +const octetstring c_etws_seg2 := '202122232425262728292a2b2c2d'O; +const octetstring c_etws_seg3 := '303132333435363738393a3b3c3d'O; +const octetstring c_etws := c_etws_seg0 & c_etws_seg1 & c_etws_seg2 & c_etws_seg3; + +/* Ensure only Paging Type 1 with segmented ETWS Primary Notification are sent after RSL_OSMO_ETWS_CMD */ +testcase TC_etws_p1ro() runs on test_CT { + var template RslChannelNr t_chan_nr := ts_RslChanNr_PCH_AGCH(0); + /* decoding the actual entire P1 rest octets by manually generated code is + * too much effort; instead simply do a binary compare to this constant */ + const bitstring c_P1RO_hdr := '00101011101'B; + var integer seg_received[4] := { 0, 0, 0, 0 }; + var L1ctlDlMessage dl; + timer T := 10.0; + + f_init(); + f_init_l1ctl(); + f_l1_tune(L1CTL, ccch_mode := CCCH_MODE_COMBINED_CBCH); + + RSL_CCHAN.send(ts_RSL_UD(ts_RSL_OSMO_ETWS_CMD(c_etws))); + /* wait for a bit until old non-ETWS Paging messages are gone */ + f_sleep(1.0); + L1CTL.clear; + T.start; + alt { + [] L1CTL.receive(tr_L1CTL_DATA_IND(t_chan_nr)) -> value dl { + var GsmRrMessage l3 := dec_GsmRrMessage(dl.payload.data_ind.payload); + select (l3) { + case (tr_PagingType1_empty) { + var octetstring p1ro := l3.payload.pag_req_1.rest_octets; + var bitstring midamble := oct2bit(substr(p1ro, 0, 3)); + var octetstring segment := substr(p1ro, 3, lengthof(p1ro)-3); + var BIT1 not_first := substr(midamble, 11, 1); + var integer seg_nr := bit2int(substr(midamble, 12, 4)); + var boolean err := false; + if (substr(midamble, 0, 11) != c_P1RO_hdr) { + setverdict(fail, "Received unexpected P1 RO header ", midamble); + } + if (not_first == '1'B) { + select (seg_nr) { + case (2) { + if (segment != c_etws_seg1) { + err := true + } else { + seg_received[1] := seg_received[1] + 1; + }} + case (3) { + if (segment != c_etws_seg2) { + err := true + } else { + seg_received[2] := seg_received[2] + 1; + }} + case (4) { + if (segment != c_etws_seg3) { + err := true + } else { + seg_received[3] := seg_received[3] + 1; + }} + case else { setverdict(fail, "Unknown segment Nr ", seg_nr); } + } + if (err) { + setverdict(fail, "Unexpected segment ", seg_nr, ": ", segment); + } + } else { + if (seg_nr != 4) { + setverdict(fail, "Invalid number of segments ", seg_nr); + err := true; + } + if (segment != c_etws_seg0) { + setverdict(fail, "Invalid first segment ", segment); + err := true; + } + if (not err) { + seg_received[0] := seg_received[0] + 1; + } + } + } + case (tr_PagingType1) { + setverdict(fail, "Received unexpected PAGING TYPE 1: ", l3); + } + } + repeat; + } + [] L1CTL.receive { repeat; } + [] T.timeout { + setverdict(pass); + } + } + log("Quantity of received ETWS PN segments: ", seg_received); + var integer i; + for (i := 0; i < 4; i := i+1) { + if (seg_received[i] < 15) { + setverdict(fail, "Segment ", i, " not received often enough"); + } + } +} + +/* Ensure only Paging Type 1 without ETWS Primary Notification are sent after disabling them */ +testcase TC_etws_p1ro_end() runs on test_CT { + var template RslChannelNr t_chan_nr := ts_RslChanNr_PCH_AGCH(0); + /* we expect four blocks of 14 bytes, let's fill them with content easily + * distinguishable */ + /* decoding the actual entire P1 rest octets by manually generated code is + * too much effort; instead simply do a binary compare to this constant */ + const bitstring c_P1RO_hdr := '00101011101'B; + var L1ctlDlMessage dl; + timer T := 10.0; + + f_init(); + f_init_l1ctl(); + f_l1_tune(L1CTL, ccch_mode := CCCH_MODE_COMBINED_CBCH); + + RSL_CCHAN.send(ts_RSL_UD(ts_RSL_OSMO_ETWS_CMD(c_etws))); + /* wait for a bit until old non-ETWS Paging messages are gone */ + f_sleep(3.0); + /* disable the ETWS PN again */ + RSL_CCHAN.send(ts_RSL_UD(ts_RSL_OSMO_ETWS_CMD(''O))); + f_sleep(2.0); + T.start; + L1CTL.clear; + alt { + [] L1CTL.receive(tr_L1CTL_DATA_IND(t_chan_nr)) -> value dl { + var GsmRrMessage l3 := dec_GsmRrMessage(dl.payload.data_ind.payload); + select (l3) { + case (tr_PagingType1_empty) { repeat; } + case (tr_PagingType1) { + setverdict(fail, "Received non-empty PT1 after disabling ETWS PN: ", l3); + } + } + repeat; + } + [] L1CTL.receive { repeat; } + [] T.timeout { + setverdict(pass); + } + } +} + + /* SMSCB TODO: * multiple SMS BC CMD at the same time: Ensure all of them are sent exactly once * extended CBCH vs. normal CBCH @@ -908,6 +1080,9 @@ control { execute( TC_cbc_sdcch8_load_idle() ); execute( TC_cbc_sdcch8_load_overload() ); } + + execute( TC_etws_p1ro() ); + execute( TC_etws_p1ro_end() ); } diff --git a/library/RSL_Types.ttcn b/library/RSL_Types.ttcn index 87de9a47c..da8c7f870 100644 --- a/library/RSL_Types.ttcn +++ b/library/RSL_Types.ttcn @@ -149,7 +149,9 @@ module RSL_Types { RSL_MT_IPAC_DLCX_IND ('01110110'B), RSL_MT_IPAC_DLCX ('01110111'B), RSL_MT_IPAC_DLCX_ACK ('01111000'B), - RSL_MT_IPAC_DLCX_NACK ('01111001'B) + RSL_MT_IPAC_DLCX_NACK ('01111001'B), + + RSL_MT_OSMO_ETWS_CMD ('01111111'B) } with { variant "FIELDLENGTH(8)" }; /*! RSL Information Element Identifiers (Chapter 9.3) */ @@ -2115,6 +2117,26 @@ template RSL_Message tr_RSL_MsgTypeDR(template RSL_MessageType msg_type) modifie } } + template (value) RSL_Message ts_RSL_OSMO_ETWS_CMD(template (value) octetstring msg, + template (value) RslChannelNr chan_nr := ts_RslChanNr_PCH_AGCH(0)) := { + msg_disc := ts_RSL_MsgDisc(RSL_MDISC_CCHAN, false), + msg_type := RSL_MT_OSMO_ETWS_CMD, + ies := { + t_RSL_IE(RSL_IE_CHAN_NR, RSL_IE_Body:{chan_nr := chan_nr}), + t_RSL_IE(RSL_IE_SMSCB_MSG, RSL_IE_Body:{smscb_message := ts_RSL_LV(msg)}) + } + } + template RSL_Message tr_RSL_OSMO_ETWS_CMD(template RslChannelNr chan_nr := ?, + template octetstring msg := ?) := { + msg_disc := tr_RSL_MsgDisc(RSL_MDISC_CCHAN, false), + msg_type := RSL_MT_OSMO_ETWS_CMD, + ies := { + tr_RSL_IE(RSL_IE_Body:{chan_nr := chan_nr}), + tr_RSL_IE(RSL_IE_Body:{smscb_message := tr_RSL_LV(msg)}) + } + } + + function f_rsl_find_ie(RSL_Message msg, RSL_IE_Type iei, out RSL_IE_Body ret) return boolean { for (var integer i := 0; i < sizeof(msg.ies); i := i+1) {