| module L1CTL_Test { |
| import from GSM_Types all; |
| import from Osmocom_Types all; |
| import from LAPDm_RAW_PT all; |
| import from LAPDm_Types all; |
| |
| type component dummy_CT { |
| port LAPDm_PT LAPDM; |
| var lapdm_CT lapdm_component; |
| }; |
| |
| function f_init() runs on dummy_CT { |
| /* create the LAPDm component */ |
| lapdm_component := lapdm_CT.create; |
| /* connect our own LAPDM port to the LAPDM Service Provider of the LAPDm component */ |
| connect(self:LAPDM, lapdm_component:LAPDM_SP); |
| /* connect the LAPDm compoent's lower-side port to the system L1CTL port (which is internally |
| * connected to the Unix Domain Socket test port */ |
| map(lapdm_component:L1CTL, system:L1CTL); |
| |
| /* start the LAPDm parallel component calling it's local function LAPDmStart */ |
| lapdm_component.start(LAPDmStart()); |
| } |
| |
| /* master function establishing a dedicated radio channel (takes care of RACH/IMM.ASS handling) */ |
| function f_establish_dcch() runs on dummy_CT { |
| var BCCH_tune_req tune_req := { arfcn := { false, 871 }, combined_ccch := true }; |
| var DCCH_establish_req est_req := { ra := 23 }; |
| |
| LAPDM.send(tune_req); |
| LAPDM.send(est_req); |
| LAPDM.receive(DCCH_establish_res:?); |
| } |
| |
| /* helper function releasing dedicated radio channel physically (no Um signaling!) */ |
| function f_release_dcch() runs on dummy_CT { |
| var DCCH_release_req rel_req := {}; |
| LAPDM.send(rel_req); |
| } |
| |
| template LAPDm_ph_data t_PH_DATA(template GsmSapi sapi, template boolean sacch, template LapdmFrame frame) := { |
| sacch := sacch, |
| sapi := sapi, |
| lapdm := frame |
| } |
| /* template for a valid SABM frame */ |
| template LapdmFrame LAPDm_B_SABM(template GsmSapi sapi, octetstring payload) := { |
| b := { |
| addr := tr_LapdmAddr(sapi, false), |
| ctrl := t_LapdmCtrlSABM(true), |
| len := lengthof(payload), |
| m := false, |
| el := 1, |
| payload := payload |
| } |
| } |
| |
| /* template for a valid UA frame */ |
| template LapdmFrame tr_LAPDm_B_UA(template GsmSapi sapi, template octetstring payload) := { |
| b := { |
| addr := tr_LapdmAddr(sapi, false), |
| ctrl := t_LapdmCtrlUA(true), |
| len := ?, |
| m := false, |
| el := 1, |
| payload := payload |
| } |
| } |
| |
| /* template for a valid UA frame */ |
| template LapdmFrame LAPDm_B_UA(template GsmSapi sapi, octetstring payload) := { |
| b := { |
| addr := tr_LapdmAddr(sapi, false), |
| ctrl := t_LapdmCtrlUA(true), |
| len := lengthof(payload), |
| m := false, |
| el := 1, |
| payload := payload |
| } |
| } |
| |
| /* template for a valid UI frame */ |
| template LapdmFrame LAPDm_B_UI(template GsmSapi sapi, octetstring payload) := { |
| b := { |
| addr := tr_LapdmAddr(sapi, true), |
| ctrl := t_LapdmCtrlUI(false), |
| len := lengthof(payload), |
| m := false, |
| el := 1, |
| payload := payload |
| } |
| } |
| |
| template LapdmFrame t_nopayload(template GsmSapi sapi) := { |
| b := { |
| addr := tr_LapdmAddr(sapi, true), |
| ctrl := ?, |
| len := 0, |
| m := false, |
| el := 1, |
| payload := ''O |
| } |
| } |
| |
| template LapdmFrame LAPDm_B_DISC(template GsmSapi sapi) modifies t_nopayload := { |
| b := { |
| ctrl := t_LapdmCtrlDISC(true) |
| } |
| } |
| |
| template LapdmFrame LAPDm_B_RR(template GsmSapi sapi, template uint3_t nr) modifies t_nopayload := { |
| b := { |
| ctrl := t_LapdmCtrlRR(nr, false) |
| } |
| } |
| |
| |
| function f_test_sabm_results_in_ua(uint8_t sapi, boolean use_sacch, octetstring payload) runs on dummy_CT return boolean { |
| var LAPDm_ph_data phd; |
| var boolean result := false; |
| timer T := 5.0; |
| |
| f_establish_dcch(); |
| LAPDM.send(t_PH_DATA(sapi, use_sacch, LAPDm_B_SABM(sapi, payload))); |
| log("====> expecting ", t_PH_DATA(sapi, use_sacch, LAPDm_B_UA(sapi, payload))); |
| T.start |
| alt { |
| [] LAPDM.receive(t_PH_DATA(?, use_sacch, LAPDm_B_UA(sapi, payload))) { result := true; } |
| [] LAPDM.receive(t_PH_DATA(?, use_sacch, ?)) -> value phd { log("Other msg on DCH: ", phd); repeat; } |
| [] LAPDM.receive(t_PH_DATA(?, ?, ?)) -> value phd { log("Other PH-DATA: ", phd); repeat; } |
| [] T.timeout { } |
| } |
| LAPDM.send(t_PH_DATA(sapi, use_sacch, LAPDm_B_RR(sapi, 0))); |
| f_release_dcch(); |
| return result; |
| } |
| |
| testcase TC_sabm_ua_dcch_sapi0() runs on dummy_CT { |
| f_init(); |
| if (not f_test_sabm_results_in_ua(0, false, 'FEFE'O)) { |
| setverdict(fail); |
| } |
| setverdict(pass); |
| } |
| |
| testcase TC_sabm_ua_dcch_sapi0_nopayload() runs on dummy_CT { |
| f_init(); |
| if (f_test_sabm_results_in_ua(0, false, ''O)) { |
| setverdict(fail, "Initial SABM/UA must contain L3 payload but BTS accepts without"); |
| } |
| setverdict(pass); |
| } |
| |
| testcase TC_sabm_ua_dcch_sapi3() runs on dummy_CT { |
| f_init(); |
| if (f_test_sabm_results_in_ua(3, false, 'FEFE'O)) { |
| setverdict(fail, "Initial SABM/UA must be on SAPI0, but BTS accepts SAPI=3"); |
| } |
| setverdict(pass); |
| } |
| |
| testcase TC_sabm_ua_dcch_sapi4() runs on dummy_CT { |
| f_init(); |
| if (f_test_sabm_results_in_ua(4, false, 'FEFE'O)) { |
| setverdict(fail, "Initial SABM/UA must be on SAPI0, but BTS accepts SAPI=4"); |
| } |
| setverdict(pass); |
| } |
| |
| testcase TC_sabm_contention() runs on dummy_CT { |
| var LAPDm_ph_data phd; |
| const octetstring payload := '0102030405'O; |
| const GsmSapi sapi := 0; |
| const boolean use_sacch := false; |
| timer T := 5.0; |
| |
| f_init(); |
| |
| f_establish_dcch(); |
| /* first frame is our real SABM */ |
| LAPDM.send(t_PH_DATA(sapi, use_sacch, LAPDm_B_SABM(sapi, payload))); |
| /* second frame is a SABM with different payload, which BTS has to ignore according to 8.4.1.4 */ |
| LAPDM.send(t_PH_DATA(sapi, use_sacch, LAPDm_B_SABM(sapi, 'ABCDEF'O))); |
| log("====> expecting ", t_PH_DATA(sapi, use_sacch, LAPDm_B_UA(sapi, payload))); |
| T.start |
| alt { |
| [] LAPDM.receive(t_PH_DATA(?, use_sacch, LAPDm_B_UA(sapi, payload))) { setverdict(pass); repeat; } |
| [] LAPDM.receive(t_PH_DATA(?, use_sacch, tr_LAPDm_B_UA(sapi, ?))) { |
| setverdict(fail, "Second SABM was responded to during contention resolution"); |
| } |
| [] LAPDM.receive { repeat }; |
| [] T.timeout { } |
| } |
| f_release_dcch(); |
| } |
| |
| /* we test that a re-transmitted SABM with identical payload will result in the retransmission of a |
| * SABM. This is required during the contention resolution procedure as specified in 8.4.1.4 */ |
| testcase TC_sabm_retransmit() runs on dummy_CT { |
| const octetstring payload := '00FEFEDEADBEEF'O; |
| f_init(); |
| if (not f_test_sabm_results_in_ua(0, false, payload)) { |
| setverdict(fail, "UA not received for first SABM"); |
| } |
| if (not f_test_sabm_results_in_ua(0, false, payload)) { |
| setverdict(fail, "UA not received for second SABM"); |
| } |
| setverdict(pass); |
| } |
| |
| testcase TC_foo() runs on dummy_CT { |
| var LapdmFrame lf; |
| /* |
| var LapdmFrame lf := valueof(LAPDm_B_UA(0, ''O)); |
| log("ENC UA: ", enc_LapdmFrame(lf)); |
| lf := valueof(LAPDm_B_UI(0, ''O)); |
| log("ENC UI B: ", enc_LapdmFrame(lf)); |
| log("ENC UI B: ", enc_LapdmFrameB(lf.b)); |
| |
| log("DEC UI AF: ", dec_LapdmAddressField('03'O)); |
| */ |
| |
| lf := valueof(LAPDm_B_RR(0, 0)); |
| log("ENC RR: ", enc_LapdmFrame(lf)); |
| |
| lf := valueof(LAPDm_B_UA(0, ''O)); |
| log("ENC UA: ", enc_LapdmFrame(lf)); |
| |
| lf := valueof(LAPDm_B_UI(0, ''O)); |
| log("ENC UI: ", enc_LapdmFrame(lf)); |
| |
| log("DEC UI CU: ", dec_LapdmCtrlU('03'O)); |
| log("DEC UI CT: ", dec_LapdmCtrl('03'O)); |
| |
| log("DEC UA: ", dec_LapdmFrameB('017301'O)); |
| log("DEC UI: ", dec_LapdmFrameA('030301'O)); |
| log("DEC I: ", dec_LapdmFrameA('030001'O)); |
| log("DEC S: ", dec_LapdmFrameA('030101'O)); |
| log("DEC: ", dec_LapdmFrameB('030301'O)); |
| log("DEC: ", dec_LapdmFrameB('0303012B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B'O)); |
| } |
| |
| control { |
| execute(TC_foo()); |
| execute(TC_sabm_ua_dcch_sapi0()); |
| /* |
| execute(TC_sabm_ua_dcch_sapi0_nopayload()); |
| execute(TC_sabm_ua_dcch_sapi3()); |
| execute(TC_sabm_ua_dcch_sapi4()); |
| execute(TC_sabm_contention()); |
| execute(TC_sabm_retransmit()); |
| */ |
| } |
| } |