| module Test { |
| import from GSM_Types all; |
| import from GSM_SystemInformation all; |
| import from GSMTAP_Types all; |
| import from GSMTAP_PortType all; |
| import from IPL4_GSMTAP_CtrlFunct all; |
| import from TELNETasp_PortType all; |
| |
| const octetstring si1 := '5506198fb38000000000000000000000000000e504002b'O; |
| const octetstring si2 := '59061a00000000000000000000000000000000ffe50400'O; |
| const octetstring si3 := '49061b000062f22404d2490301275d40e50400392b2b2b'O; |
| const octetstring si4 := '31061c62f22404d25d40e504002b2b2b2b2b2b2b2b2b2b'O; |
| const octetstring c_si2bis := '550602bfe809b3ff00000000000000000000007900002b'O; |
| const octetstring c_si2ter := '010603bf66b0aa0a00000002000000000000002b2b2b2b'O; |
| const octetstring c_si2quater := '050607a8a0364aa698d72ff424feee0506d5e7fff02043'O; |
| |
| type component dummy_CT { |
| port GSMTAP_PT GSMTAP; |
| port TELNETasp_PT BSCVTY; |
| var boolean initialized := false; |
| var SystemInformationConfig si_cfg := { |
| bcch_extended := false, |
| si1_present := true, |
| si2bis_present := false, |
| si2ter_present := false, |
| si2quater_present := false, |
| si7_present := false, |
| si8_present := false, |
| si9_present := false, |
| si13_present := false, |
| si13alt_present := false, |
| si15_present := false, |
| si16_present := false, |
| si17_present := false, |
| si2n_present := false, |
| si21_present := false, |
| si22_present := false |
| }; |
| }; |
| |
| testcase TC_si1() runs on dummy_CT { |
| log("SI: ", dec_SystemInformation(si1)); |
| log("SI: ", dec_SystemInformation(si2)); |
| log("SI: ", dec_SystemInformation(si3)); |
| log("SI: ", dec_SystemInformation(si4)); |
| setverdict(pass); |
| } |
| |
| template GsmtapHeader t_GsmtapHeader := { |
| version := GSMTAP_VERSION, |
| hdr_len := 4, |
| msg_type := ?, |
| timeslot := ?, |
| arfcn := ?, |
| signal_dbm := ?, |
| snr_db := ?, |
| frame_number := ?, |
| sub_type := ?, |
| antenna_nr := ?, |
| sub_slot := ?, |
| res := ? |
| } |
| |
| template GsmtapHeader t_GsmtapHeaderUm(template GsmtapChannel ch) modifies t_GsmtapHeader := { |
| msg_type := GSMTAP_TYPE_UM, |
| sub_type := ch |
| } |
| |
| template GsmtapMessage t_bcch := { |
| header := t_GsmtapHeaderUm(GSMTAP_CHANNEL_BCCH), |
| payload := ? |
| } |
| |
| template GSMTAP_RecvFrom t_recvfrom(template GsmtapChannel ch) := { |
| connId := ?, |
| remName := ?, |
| remPort := ?, |
| locName := ?, |
| locPort := GSMTAP_PORT, |
| proto := {udp:={}}, |
| userData := ?, |
| msg := { header := t_GsmtapHeaderUm(ch), payload := ?} |
| } |
| |
| /* tuple of gsmtap header + decoded SI */ |
| type record SystemInformationGsmtap { |
| GsmtapHeader gsmtap, |
| SystemInformation si |
| } |
| |
| /* an arbitrary-length vector of decoded SI + gsmtap header */ |
| type record of SystemInformationGsmtap SystemInformationVector; |
| |
| /* an array of SI-vectors indexed by TC value */ |
| type SystemInformationVector SystemInformationVectorPerTc[8]; |
| |
| type record of integer IntegerRecord; |
| |
| function f_array_contains(IntegerRecord arr, integer key) return boolean { |
| for (var integer i:= 0; i< sizeof(arr); i := i + 1) { |
| if (arr[i] == key) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| |
| /* compute TC as per 45.002 6.3.1.3 */ |
| function f_gsm_compute_tc(integer fn) return integer { |
| return (fn / 51) mod 8; |
| } |
| |
| /* determine if a given SI vector contains given SI type at least once */ |
| function f_si_vecslot_contains(SystemInformationVector arr, RrMessageType key, boolean bcch_ext := false) return boolean { |
| for (var integer i:= 0; i< sizeof(arr); i := i + 1) { |
| var integer fn_mod51 := arr[i].gsmtap.frame_number mod 51; |
| if (not bcch_ext and fn_mod51 == 2 or |
| bcch_ext and fn_mod51 == 6) { |
| if (arr[i].si.header.message_type == key) { |
| return true; |
| } |
| } |
| } |
| return false; |
| } |
| |
| /* ensure a given TC slot of the SI vector contains given SI type at least once at TC */ |
| function f_ensure_si_vec_contains(SystemInformationVectorPerTc arr, integer tc, RrMessageType key, boolean ext_bcch := false) { |
| if (not f_si_vecslot_contains(arr[tc], key, ext_bcch)) { |
| log("Fail: No ", key, " in TC=", tc, "!"); |
| setverdict(fail); |
| } |
| } |
| |
| /* check if a given SI vector contains given SI type at least once on any TC */ |
| function f_si_vec_contains(SystemInformationVectorPerTc arr, RrMessageType key) return boolean { |
| for (var integer tc:= 0; tc < sizeof(arr); tc := tc + 1) { |
| if (f_si_vecslot_contains(arr[tc], key) or |
| f_si_vecslot_contains(arr[tc], key, true)) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| /* determine if a given SI vector contains given SI type at least N of M times */ |
| function f_si_vecslot_contains_n_of_m(SystemInformationVector arr, RrMessageType key, boolean bcch_ext := false, integer n := 1, integer m := 4) return boolean { |
| var integer count := 0; |
| if (sizeof(arr) < m) { |
| log("Error: Insufficient SI in array"); |
| setverdict(fail); |
| return false; |
| } |
| for (var integer i:= 0; i < m; i := i + 1) { |
| var integer fn_mod51 := arr[i].gsmtap.frame_number mod 51; |
| if (not bcch_ext and fn_mod51 == 2 or |
| bcch_ext and fn_mod51 == 6) { |
| if (arr[i].si.header.message_type == key) { |
| count := count + 1; |
| } |
| } |
| } |
| if (count >= n) { |
| return true; |
| } else { |
| return false; |
| } |
| } |
| |
| /* ensure a given TC slot of the SI vector contains given SI type at least N out of M times at TC */ |
| function f_ensure_si_vec_contains_n_of_m(SystemInformationVectorPerTc arr, integer tc, RrMessageType key, boolean ext_bcch := false, integer n, integer m) { |
| if (not f_si_vecslot_contains_n_of_m(arr[tc], key, ext_bcch, n, m)) { |
| log("Fail: Not ", n, "/", m, " of ", key, " in TC=", tc, "!"); |
| setverdict(fail); |
| } |
| } |
| |
| /* determine if a given SI vector contains given SI type at least once */ |
| function f_si_vecslot_contains_only(SystemInformationVector arr, RrMessageType key, boolean bcch_ext := false) return boolean { |
| for (var integer i:= 0; i< sizeof(arr); i := i + 1) { |
| var integer fn_mod51 := arr[i].gsmtap.frame_number mod 51; |
| if (not bcch_ext and fn_mod51 == 2 or |
| bcch_ext and fn_mod51 == 6) { |
| if (arr[i].si.header.message_type != key) { |
| return false; |
| } |
| } |
| } |
| return true; |
| } |
| |
| /* ensure a given TC slot of the SI vector contains only given SI type */ |
| function f_ensure_si_vec_contains_only(SystemInformationVectorPerTc arr, integer tc, RrMessageType key, boolean ext_bcch := false) { |
| if (not f_si_vecslot_contains_only(arr[tc], key, ext_bcch)) { |
| log("Fail: Not all ", key, " in TC=", tc, "!"); |
| setverdict(fail); |
| } |
| } |
| |
| /* SI configuration of cell, against which we validate actual SI messages */ |
| type set SystemInformationConfig { |
| boolean bcch_extended, |
| boolean si1_present, |
| boolean si2bis_present, |
| boolean si2ter_present, |
| boolean si2quater_present, |
| boolean si7_present, |
| boolean si8_present, |
| boolean si9_present, |
| boolean si13_present, |
| boolean si13alt_present, |
| boolean si15_present, |
| boolean si16_present, |
| boolean si17_present, |
| boolean si2n_present, |
| boolean si21_present, |
| boolean si22_present |
| } |
| |
| /* validate the SI scheduling according to TS 45.002 version 14.1.0 Release 14, Section 6.3.1.3 */ |
| function f_validate_si_scheduling(SystemInformationConfig cfg, SystemInformationVectorPerTc si_per_tc) { |
| var integer i; |
| for (i := 0; i < sizeof(si_per_tc); i := i + 1) { |
| if (sizeof(si_per_tc[i]) == 0) { |
| setverdict(fail, "No SI messages for TC=0!"); |
| } |
| } |
| if (cfg.si1_present) { |
| /* ii) System Information Type 1 needs to be sent if frequency hopping is in use or |
| * when the NCH is present in a cell. If the MS finds another message on BCCH Norm |
| * when TC = 0, it can assume that System Information Type 1 is not in use. */ |
| f_ensure_si_vec_contains(si_per_tc, 0, SYSTEM_INFORMATION_TYPE_1); |
| /* make sure *ALL* contain SI1 */ |
| f_ensure_si_vec_contains_only(si_per_tc, 0, SYSTEM_INFORMATION_TYPE_1); |
| } |
| f_ensure_si_vec_contains(si_per_tc, 1, SYSTEM_INFORMATION_TYPE_2); |
| /* iii) A SI 2 message will be sent at least every time TC = 1 */ |
| f_ensure_si_vec_contains(si_per_tc, 2, SYSTEM_INFORMATION_TYPE_3); |
| f_ensure_si_vec_contains(si_per_tc, 6, SYSTEM_INFORMATION_TYPE_3); |
| f_ensure_si_vec_contains(si_per_tc, 3, SYSTEM_INFORMATION_TYPE_4); |
| f_ensure_si_vec_contains(si_per_tc, 7, SYSTEM_INFORMATION_TYPE_4); |
| |
| /* iii) System information type 2 bis or 2 ter messages are sent if needed, as determined by the |
| * system operator. If only one of them is needed, it is sent when TC = 5. If both are |
| * needed, 2bis is sent when TC = 5 and 2ter is sent at least once within any of 4 |
| * consecutive occurrences of TC = 4. */ |
| if (cfg.si2bis_present and not cfg.si2ter_present) { |
| f_ensure_si_vec_contains(si_per_tc, 5, SYSTEM_INFORMATION_TYPE_2bis); |
| } else if (cfg.si2ter_present and not cfg.si2bis_present) { |
| f_ensure_si_vec_contains(si_per_tc, 5, SYSTEM_INFORMATION_TYPE_2ter); |
| } else if (cfg.si2ter_present and cfg.si2bis_present) { |
| f_ensure_si_vec_contains(si_per_tc, 5, SYSTEM_INFORMATION_TYPE_2bis); |
| f_ensure_si_vec_contains_n_of_m(si_per_tc, 4, SYSTEM_INFORMATION_TYPE_2ter, false, 1, 4); |
| } |
| |
| if (cfg.si7_present or cfg.si8_present) { |
| /* vi) Use of System Information type 7 and 8 is not always necessary. It is necessary |
| * if System Information type 4 does not contain all information needed for cell |
| * selection and reselection. */ |
| if (not cfg.bcch_extended) { |
| setverdict(fail, "Error: SI7/SI8 require BCCH Extd."); |
| } |
| if (cfg.si7_present) { |
| f_ensure_si_vec_contains(si_per_tc, 7, SYSTEM_INFORMATION_TYPE_7, true); |
| } |
| if (cfg.si8_present) { |
| f_ensure_si_vec_contains(si_per_tc, 3, SYSTEM_INFORMATION_TYPE_8, true); |
| } |
| } |
| |
| if (cfg.si2quater_present) { |
| /* iii) System information type 2 quater is sent if needed, as determined by the system |
| * operator. If sent on BCCH Norm, it shall be sent when TC = 5 if neither of 2bis |
| * and 2ter are used, otherwise it shall be sent at least once within any of 4 |
| * consecutive occurrences of TC = 4. If sent on BCCH Ext, it is sent at least once |
| * within any of 4 consecutive occurrences of TC = 5. */ |
| if (not (cfg.bcch_extended)) { |
| if (not (cfg.si2bis_present or cfg.si2ter_present)) { |
| f_ensure_si_vec_contains(si_per_tc, 5, SYSTEM_INFORMATION_TYPE_2quater); |
| } else { |
| f_ensure_si_vec_contains_n_of_m(si_per_tc, 4, SYSTEM_INFORMATION_TYPE_2quater, false, 1, 4); |
| } |
| } else { |
| f_ensure_si_vec_contains_n_of_m(si_per_tc, 5, SYSTEM_INFORMATION_TYPE_2quater, true, 1, 4); |
| } |
| } |
| if (cfg.si9_present) { |
| /* vi) System Information type 9 is sent in those blocks with TC = 4 which are specified |
| * in system information type 3 as defined in 3GPP TS 44.018. */ |
| f_ensure_si_vec_contains(si_per_tc, 4, SYSTEM_INFORMATION_TYPE_9); // FIXME SI3 |
| } |
| if (cfg.si13_present) { |
| /* vii) System Information type 13 is only related to the GPRS service. System Information |
| * Type 13 need only be sent if GPRS support is indicated in one or more of System |
| * Information Type 3 or 4 or 7 or 8 messages. These messages also indicate if the |
| * message is sent on the BCCH Norm or if the message is transmitted on the BCCH Ext. |
| * In the case that the message is sent on the BCCH Norm, it is sent at least once |
| * within any of 4 consecutive occurrences of TC=4. */ |
| if (not cfg.bcch_extended) { |
| f_ensure_si_vec_contains_n_of_m(si_per_tc, 4, SYSTEM_INFORMATION_TYPE_13, false, 1, 4); |
| } else { |
| f_ensure_si_vec_contains(si_per_tc, 0, SYSTEM_INFORMATION_TYPE_13, true); |
| } |
| if (f_si_vec_contains(si_per_tc, SYSTEM_INFORMATION_TYPE_13alt)) { |
| setverdict(fail, "Cannot have SI13alt and SI13"); |
| } |
| } |
| if (cfg.si16_present or cfg.si17_present) { |
| /* viii) System Information type 16 and 17 are only related to the SoLSA service. They |
| * should not be sent in a cell where network sharing is used (see rule xv). */ |
| if (cfg.si22_present) { |
| setverdict(fail, "Error: Cannot have SI16/SI17 and SI22!"); |
| } |
| if (f_si_vec_contains(si_per_tc, SYSTEM_INFORMATION_TYPE_22)) { |
| setverdict(fail, "Cannot have SI16/SI17 and SI22!"); |
| } |
| if (not cfg.bcch_extended) { |
| setverdict(fail, "Error: SI16/SI17 requires BCCH Extd!"); |
| } |
| if (cfg.si16_present) { |
| f_ensure_si_vec_contains(si_per_tc, 6, SYSTEM_INFORMATION_TYPE_16, true); |
| } |
| if (cfg.si17_present) { |
| f_ensure_si_vec_contains(si_per_tc, 2, SYSTEM_INFORMATION_TYPE_17, true); |
| } |
| } |
| |
| /* ix) System Information type 18 and 20 are sent in order to transmit non-GSM |
| * broadcast information. The frequency with which they are sent is determined by the |
| * system operator. System Information type 9 identifies the scheduling of System |
| * Information type 18 and 20 messages. */ |
| |
| /* x) System Information Type 19 is sent if COMPACT neighbours exist. If System |
| * Information Type 19 is present, then its scheduling shall be indicated in System |
| * Information Type 9. */ |
| |
| if (cfg.si15_present) { |
| /* xi) System Information Type 15 is broadcast if dynamic ARFCN mapping is used in the |
| * PLMN. If sent on BCCH Norm, it is sent at least once within any of 4 consecutive |
| * occurrences of TC = 4. If sent on BCCH Ext, it is sent at least once within any of |
| * 4 consecutive occurrences of TC = 1. */ |
| if (not cfg.bcch_extended) { |
| f_ensure_si_vec_contains_n_of_m(si_per_tc, 4, SYSTEM_INFORMATION_TYPE_15, false, 1, 4); |
| } else { |
| f_ensure_si_vec_contains_n_of_m(si_per_tc, 1, SYSTEM_INFORMATION_TYPE_15, true, 1, 4); |
| } |
| } |
| if (cfg.si13alt_present) { |
| /* xii) System Information type 13 alt is only related to the GERAN Iu mode. System |
| * Information Type 13 alt need only be sent if GERAN Iu mode support is indicated in |
| * one or more of System Information Type 3 or 4 or 7 or 8 messages and SI 13 is not |
| * broadcast. These messages also indicate if the message is sent on the BCCH Norm or |
| * if the message is transmitted on the BCCH Ext. In the case that the message is sent |
| * on the BCCH Norm, it is sent at least once within any of 4 consecutive occurrences |
| * of TC = 4. */ |
| if (cfg.si13_present) { |
| setverdict(fail, "Error: Cannot have SI13alt and SI13"); |
| } |
| if (f_si_vec_contains(si_per_tc, SYSTEM_INFORMATION_TYPE_13)) { |
| setverdict(fail, "Cannot have SI13alt and SI13"); |
| } |
| if (not cfg.bcch_extended) { |
| f_ensure_si_vec_contains_n_of_m(si_per_tc, 4, SYSTEM_INFORMATION_TYPE_13alt, false, 1, 4); |
| } else { |
| f_ensure_si_vec_contains(si_per_tc, 0, SYSTEM_INFORMATION_TYPE_13alt, true); |
| } |
| } |
| if (cfg.si2n_present) { |
| /* xiii) System Information Type 2n is optionally sent on BCCH Norm or BCCH Ext if needed, |
| * as determined by the system operator. In the case that the message is sent on the |
| * BCCH Norm, it is sent at least once within any of 4 consecutive occurrences of TC = |
| * 4. If the message is sent on BCCH Ext, it is sent at least once within any of 2 |
| * consecutive occurrences of TC = 4. */ |
| if (not cfg.bcch_extended) { |
| f_ensure_si_vec_contains_n_of_m(si_per_tc, 4, SYSTEM_INFORMATION_TYPE_2n, false, 1, 4); |
| } else { |
| f_ensure_si_vec_contains_n_of_m(si_per_tc, 4, SYSTEM_INFORMATION_TYPE_2n, true, 2, 4); |
| } |
| } |
| if (cfg.si21_present) { |
| /* xiv) System Information Type 21 is optionally sent on BCCH Norm or BCCH Ext, as |
| * determined by the system operator. If Extended Access Barring is in use in the cell |
| * then this message is sent at least once within any of 4 consecutive occurrences of |
| * TC = 4 regardless if it is sent on BCCH Norm or BCCH Ext. If BCCH Ext is used in a |
| * cell then this message shall only be sent on BCCH Ext. */ |
| if (not cfg.bcch_extended) { |
| f_ensure_si_vec_contains_n_of_m(si_per_tc, 4, SYSTEM_INFORMATION_TYPE_21, false, 1, 4); |
| } else { |
| f_ensure_si_vec_contains_n_of_m(si_per_tc, 4, SYSTEM_INFORMATION_TYPE_21, true, 1, 4); |
| if (f_si_vecslot_contains(si_per_tc[4], SYSTEM_INFORMATION_TYPE_21)) { |
| setverdict(fail, "Cannot have SI21 on BCCH Norm if BCCH Extd enabled!"); |
| } |
| } |
| } |
| if (cfg.si22_present) { |
| /* xv) System Information Type 22 is sent if network sharing is in use in the cell. It |
| * should not be sent in a cell where SoLSA is used (see rule viii). System |
| * Information Type 22 instances shall be sent on BCCH Ext within any occurrence of TC |
| * =2 and TC=6. */ |
| if (cfg.si16_present or cfg.si17_present) { |
| setverdict(fail, "Error: Cannot have SI16/SI17 and SI22!"); |
| } |
| if (f_si_vec_contains(si_per_tc, SYSTEM_INFORMATION_TYPE_16) or |
| f_si_vec_contains(si_per_tc, SYSTEM_INFORMATION_TYPE_17)) { |
| setverdict(fail, "Cannot have SI16/SI17 and SI22!"); |
| } |
| if (not cfg.bcch_extended) { |
| setverdict(fail, "Error: SI22 requires BCCH Extd!"); |
| } else { |
| f_ensure_si_vec_contains_only(si_per_tc, 2, SYSTEM_INFORMATION_TYPE_22, true); |
| f_ensure_si_vec_contains_only(si_per_tc, 6, SYSTEM_INFORMATION_TYPE_22, true); |
| } |
| } |
| } |
| |
| |
| function f_gsmtap_sample_si(GSMTAP_PT pt, float duration := 8.0) return SystemInformationVectorPerTc { |
| timer T := duration; |
| var SystemInformationVectorPerTc si_per_tc; |
| var GSMTAP_RecvFrom rf; |
| |
| /* initialize all per-TC vectors empty */ |
| for (var integer i := 0; i < sizeof(si_per_tc); i := i + 1) { |
| si_per_tc[i] := {}; |
| } |
| |
| /* flush all previous/buffered elements */ |
| pt.clear |
| |
| T.start; |
| alt { |
| [] pt.receive(t_recvfrom(GSMTAP_CHANNEL_BCCH)) -> value rf { |
| var SystemInformation si := dec_SystemInformation(rf.msg.payload); |
| var SystemInformationGsmtap sig := { rf.msg.header, si }; |
| var integer tc := f_gsm_compute_tc(rf.msg.header.frame_number); |
| log("SI received at TC=", tc, ": ", si); |
| /* append to the per-TC bucket */ |
| si_per_tc[tc] := si_per_tc[tc] & { sig }; |
| repeat; |
| } |
| [] pt.receive { repeat; }; |
| [] T.timeout { }; |
| } |
| for (var integer i := 0; i < sizeof(si_per_tc); i := i + 1) { |
| log(testcasename(), ": TC=", i, " has #of SI=", sizeof(si_per_tc[i])); |
| } |
| return si_per_tc; |
| } |
| |
| function f_init() runs on dummy_CT { |
| if (initialized) { |
| return; |
| } |
| /* GSMTAP initialization */ |
| map(self:GSMTAP, system:GSMTAP); |
| IPL4_GSMTAP_CtrlFunct.f_IPL4_listen(GSMTAP, "0.0.0.0", GSMTAP_PORT, {udp := {}}); |
| |
| /* VTY initialization */ |
| map(self:BSCVTY, system:BSCVTY); |
| f_vty_set_prompts(BSCVTY) |
| |
| initialized := true; |
| } |
| |
| testcase TC_si_default() runs on dummy_CT { |
| var SystemInformationVectorPerTc si_per_tc; |
| |
| f_init(); |
| |
| si_per_tc := f_gsmtap_sample_si(GSMTAP); |
| f_validate_si_scheduling(si_cfg, si_per_tc); |
| |
| setverdict(pass); |
| } |
| |
| testcase TC_si_sched_2bis() runs on dummy_CT { |
| var SystemInformationVectorPerTc si_per_tc; |
| f_init(); |
| |
| /* Enable SI2bis + validate scheduling */ |
| f_vty_enter_cfg_bts(BSCVTY, 0); |
| f_vty_si_static(BSCVTY, 0, "2bis", c_si2bis); |
| f_vty_si_resend(BSCVTY, 0); |
| f_vty_transceive(BSCVTY, "do write terminal"); |
| si_cfg.si2bis_present := true; |
| si_per_tc := f_gsmtap_sample_si(GSMTAP); |
| f_validate_si_scheduling(si_cfg, si_per_tc); |
| |
| /* cleanup */ |
| f_vty_si_computed(BSCVTY, 0, "2bis"); |
| f_vty_si_resend(BSCVTY, 0); |
| si_cfg.si2bis_present := false; |
| |
| setverdict(pass); |
| } |
| |
| testcase TC_si_sched_2ter() runs on dummy_CT { |
| var SystemInformationVectorPerTc si_per_tc; |
| f_init(); |
| |
| /* Enable SI2ter + validate scheduling */ |
| f_vty_enter_cfg_bts(BSCVTY, 0); |
| f_vty_si_static(BSCVTY, 0, "2ter", c_si2ter); |
| f_vty_transceive(BSCVTY, "write terminal"); |
| f_vty_si_resend(BSCVTY, 0); |
| si_cfg.si2ter_present := true; |
| si_per_tc := f_gsmtap_sample_si(GSMTAP); |
| f_validate_si_scheduling(si_cfg, si_per_tc); |
| |
| /* cleanup */ |
| f_vty_si_computed(BSCVTY, 0, "2ter"); |
| f_vty_si_resend(BSCVTY, 0); |
| si_cfg.si2ter_present := false; |
| |
| setverdict(pass); |
| } |
| |
| testcase TC_si_sched_2ter_2bis() runs on dummy_CT { |
| var SystemInformationVectorPerTc si_per_tc; |
| f_init(); |
| |
| /* Enable SI2bis + SI2ter + validate scheduling */ |
| f_vty_enter_cfg_bts(BSCVTY, 0); |
| f_vty_si_static(BSCVTY, 0, "2bis", c_si2bis); |
| f_vty_si_static(BSCVTY, 0, "2ter", c_si2ter); |
| f_vty_transceive(BSCVTY, "write terminal"); |
| f_vty_si_resend(BSCVTY, 0); |
| si_cfg.si2bis_present := true; |
| si_cfg.si2ter_present := true; |
| si_per_tc := f_gsmtap_sample_si(GSMTAP); |
| f_validate_si_scheduling(si_cfg, si_per_tc); |
| |
| /* cleanup */ |
| f_vty_si_computed(BSCVTY, 0, "2bis"); |
| f_vty_si_computed(BSCVTY, 0, "2ter"); |
| f_vty_si_resend(BSCVTY, 0); |
| si_cfg.si2bis_present := false; |
| si_cfg.si2ter_present := false; |
| |
| setverdict(pass); |
| } |
| |
| testcase TC_si_sched_2quater() runs on dummy_CT { |
| var SystemInformationVectorPerTc si_per_tc; |
| f_init(); |
| |
| /* Enable SI2quater + validate scheduling */ |
| f_vty_si2q_add_uarfcn(BSCVTY, 0, 23, 42); |
| f_vty_transceive(BSCVTY, "write terminal"); |
| f_vty_si_resend(BSCVTY, 0); |
| si_cfg.si2quater_present := true; |
| si_per_tc := f_gsmtap_sample_si(GSMTAP); |
| f_validate_si_scheduling(si_cfg, si_per_tc); |
| |
| /* cleanup */ |
| f_vty_si2q_del_uarfcn(BSCVTY, 0, 23, 42); |
| f_vty_si_resend(BSCVTY, 0); |
| si_cfg.si2quater_present := false; |
| |
| setverdict(pass); |
| } |
| |
| testcase TC_si_sched_13() runs on dummy_CT { |
| var SystemInformationVectorPerTc si_per_tc; |
| f_init(); |
| |
| /* Enable SI2ter + validate scheduling */ |
| f_vty_enter_cfg_bts(BSCVTY, 0); |
| f_vty_gprs_mode(BSCVTY, 0, "gprs"); |
| f_vty_transceive(BSCVTY, "write terminal"); |
| f_vty_si_resend(BSCVTY, 0); |
| si_cfg.si13_present := true; |
| si_per_tc := f_gsmtap_sample_si(GSMTAP); |
| f_validate_si_scheduling(si_cfg, si_per_tc); |
| |
| /* cleanup */ |
| f_vty_gprs_mode(BSCVTY, 0, "none"); |
| f_vty_si_resend(BSCVTY, 0); |
| si_cfg.si13_present := false; |
| |
| setverdict(pass); |
| } |
| |
| |
| /* permitted prompts on VTY */ |
| const charstring NORMAL_PROMPT := "OpenBSC> "; |
| const charstring ENABLE_PROMPT := "OpenBSC# "; |
| const charstring CONFIG_PROMPT := "OpenBSC(*)\#"; |
| |
| const ASP_TelnetDynamicConfig vty_prompt[3] := { |
| { |
| prompt := { |
| id := 1, |
| prompt := NORMAL_PROMPT, |
| has_wildcards := false |
| } |
| }, { |
| prompt := { |
| id := 2, |
| prompt := ENABLE_PROMPT, |
| has_wildcards := false |
| } |
| }, { |
| prompt := { |
| id := 3, |
| prompt := CONFIG_PROMPT, |
| has_wildcards := true |
| } |
| } |
| }; |
| |
| /* configure prompts in TELNETasp module */ |
| function f_vty_set_prompts(TELNETasp_PT pt) { |
| /* set some configuration that isn't possible to express |
| * in the config file due to syntactic restrictions (Who invents config |
| * files that don't permit regular expressions? */ |
| for (var integer i := 0; i < sizeof(vty_prompt); i:= i + 1) { |
| pt.send(vty_prompt[i]) |
| } |
| } |
| |
| /* wait for any of the permitted prompts; buffer + return all intermediate output */ |
| function f_vty_wait_for_prompt(TELNETasp_PT pt) return charstring { |
| template charstring config_pattern := pattern CONFIG_PROMPT; |
| var charstring rx, buf := ""; |
| timer T := 2.0; |
| |
| T.start; |
| alt { |
| [] pt.receive(NORMAL_PROMPT) { }; |
| [] pt.receive(ENABLE_PROMPT) { }; |
| [] pt.receive(config_pattern) { }; |
| /* FIXME: "% Unknown command" and the like! */ |
| [] pt.receive(charstring:?) -> value rx { buf := buf & rx; repeat }; |
| [] T.timeout { setverdict(fail, "VTY Timeout for prompt"); return ""}; |
| } |
| T.stop; |
| return buf; |
| } |
| |
| /* send a VTY command and obtain response until prompt is received */ |
| function f_vty_transceive(TELNETasp_PT pt, charstring tx) return charstring { |
| pt.send(tx); |
| return f_vty_wait_for_prompt(pt); |
| } |
| |
| type integer BtsNr (0..255); |
| type integer BtsTrxNr (0..255); |
| type integer BtsTimeslotNr (0..7); |
| |
| type charstring BtsGprsMode ("none", "gprs", "egrps"); |
| |
| /* enter the'confiugration' mode of the VTY */ |
| function f_vty_enter_config(TELNETasp_PT pt) { |
| f_vty_transceive(pt, "enable"); |
| f_vty_transceive(pt, "configure terminal") |
| } |
| |
| function f_vty_enter_cfg_network(TELNETasp_PT pt) { |
| f_vty_enter_config(pt); |
| f_vty_transceive(pt, "network") |
| } |
| |
| function f_vty_enter_cfg_bts(TELNETasp_PT pt, BtsNr bts := 0) { |
| f_vty_enter_cfg_network(pt); |
| f_vty_transceive(pt, "bts " & int2str(bts)); |
| } |
| |
| function f_vty_enter_cfg_trx(TELNETasp_PT pt, BtsNr bts := 0, BtsTrxNr trx := 0) { |
| f_vty_enter_cfg_bts(pt, bts); |
| f_vty_transceive(pt, "trx " & int2str(trx)); |
| } |
| |
| function f_vty_enter_cfg_ts(TELNETasp_PT pt, BtsNr bts := 0, BtsTrxNr trx := 0, BtsTimeslotNr ts) { |
| f_vty_enter_cfg_trx(pt, bts, trx); |
| f_vty_transceive(pt, "timeslot " & int2str(ts)); |
| } |
| |
| function f_vty_si_static(TELNETasp_PT pt, BtsNr bts, charstring si, octetstring bytes) { |
| f_vty_enter_cfg_bts(pt, bts); |
| f_vty_transceive(pt, "system-information " & si & " mode static"); |
| f_vty_transceive(pt, "system-information " & si & " static " & hex2str(oct2hex(bytes))); |
| f_vty_transceive(pt, "end"); |
| } |
| |
| function f_vty_si_computed(TELNETasp_PT pt, BtsNr bts, charstring si) { |
| f_vty_enter_cfg_bts(pt, bts); |
| f_vty_transceive(pt, "system-information " & si & " mode computed"); |
| f_vty_transceive(pt, "end"); |
| } |
| |
| function f_vty_si_resend(TELNETasp_PT pt, BtsNr bts := 0) { |
| f_vty_transceive(pt, "bts " & int2str(bts) & " resend-system-information"); |
| /* wait for 1s until changes propagate */ |
| timer T := 1.0; |
| T.start; |
| T.timeout; |
| } |
| |
| function f_vty_gprs_mode(TELNETasp_PT pt, integer bts, BtsGprsMode mode) { |
| f_vty_enter_cfg_bts(pt, bts); |
| f_vty_transceive(pt, "gprs mode " & mode); |
| f_vty_transceive(pt, "end"); |
| } |
| |
| function f_vty_si2q_add_uarfcn(TELNETasp_PT pt, BtsNr bts, UmtsArfcn uarfcn, UmtsScramblingCode sc, integer diversity := 0) { |
| f_vty_enter_cfg_bts(pt, bts); |
| f_vty_transceive(pt, "si2quater neighbor-list add uarfcn " & int2str(uarfcn) & " " & int2str(sc) & " " & int2str(diversity)); |
| f_vty_transceive(pt, "end"); |
| } |
| |
| function f_vty_si2q_del_uarfcn(TELNETasp_PT pt, BtsNr bts, UmtsArfcn uarfcn, UmtsScramblingCode sc) { |
| f_vty_enter_cfg_bts(pt, bts); |
| f_vty_transceive(pt, "si2quater neighbor-list del uarfcn " & int2str(uarfcn) & " " & int2str(sc)); |
| f_vty_transceive(pt, "end"); |
| } |
| |
| testcase TC_telnet() runs on dummy_CT { |
| f_init(); |
| |
| f_vty_transceive(BSCVTY, "show network") |
| f_vty_transceive(BSCVTY, "network") |
| f_vty_transceive(BSCVTY, "bts 0") |
| f_vty_transceive(BSCVTY, "end") |
| setverdict(pass); |
| } |
| |
| control { |
| execute(TC_si1()); |
| execute(TC_telnet()); |
| execute(TC_si_default()); |
| execute(TC_si_sched_2bis()); |
| execute(TC_si_sched_2ter()); |
| execute(TC_si_sched_2ter_2bis()); |
| execute(TC_si_sched_2quater()); |
| execute(TC_si_sched_13()); |
| } |
| } |