module BTS_Tests_LAPDm { import from GSM_Types all; import from Osmocom_Types all; import from LAPDm_RAW_PT all; import from LAPDm_Types all; import from BTS_Tests all; /* test that use exclusively only LAPDm over L1CTL */ type component lapdm_test_CT { port LAPDm_PT LAPDM; var lapdm_CT lapdm_component; }; /* contrary to BTS_Tests.ttcn, we use LAPDm_PT here, a convenience wrapper * around L1CTL to perform encode/decode of abstract LAPDm frames */ type component lapdm_bts_CT extends lapdm_test_CT, test_CT { } function f_init() runs on lapdm_test_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 lapdm_test_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 lapdm_test_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) := { ab := { addr := tr_LapdmAddr(sapi, false), ctrl := tr_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) := { ab := { addr := tr_LapdmAddr(sapi, false), ctrl := tr_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) := { ab := { addr := tr_LapdmAddr(sapi, false), ctrl := tr_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) := { ab := { addr := tr_LapdmAddr(sapi, true), ctrl := tr_LapdmCtrlUI(false), len := lengthof(payload), m := false, el := 1, payload := payload } } template LapdmFrame t_nopayload(template GsmSapi sapi) := { ab := { 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 := { ab := { ctrl := tr_LapdmCtrlDISC(true) } } template LapdmFrame LAPDm_B_RR(template GsmSapi sapi, template uint3_t nr) modifies t_nopayload := { ab := { ctrl := tr_LapdmCtrlRR(nr, false) } } function f_test_sabm_results_in_ua(uint8_t sapi, boolean use_sacch, octetstring payload) runs on lapdm_test_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 lapdm_test_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 lapdm_test_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 lapdm_test_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 lapdm_test_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 lapdm_test_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 * UA. This is required during the contention resolution procedure as specified in 8.4.1.4 */ testcase TC_sabm_retransmit() runs on lapdm_test_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 lapdm_test_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_LapdmFrameAB('017301'O)); log("DEC UI: ", dec_LapdmFrameAB('030301'O)); log("DEC I: ", dec_LapdmFrameAB('030001'O)); log("DEC S: ", dec_LapdmFrameAB('030101'O)); log("DEC: ", dec_LapdmFrameAB('030301'O)); log("DEC: ", dec_LapdmFrameAB('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()); } }