From b669ee029eb10743ffa17829c63a0f47402de503 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Fri, 9 Mar 2018 12:50:02 +0100 Subject: pcu: First DL TBF hack Change-Id: Ib3f09e125a7a4492d9072f8e9f5896eaac7ed03b --- library/GSM_RR_Types.ttcn | 51 ++++++++++++++++++++ library/L1CTL_PortType.ttcn | 22 +++++++++ library/LAPDm_RAW_PT.ttcn | 104 ++++++++++++++++++++++++++++++++++------- library/RLCMAC_CSN1_Types.ttcn | 26 +++++++++++ library/RLCMAC_Types.ttcn | 15 ++++++ pcu/PCU_Tests.ttcn | 81 +++++++++++++++++++++++++++++++- 6 files changed, 279 insertions(+), 20 deletions(-) diff --git a/library/GSM_RR_Types.ttcn b/library/GSM_RR_Types.ttcn index 75be6f8b..b1e6809c 100644 --- a/library/GSM_RR_Types.ttcn +++ b/library/GSM_RR_Types.ttcn @@ -706,6 +706,57 @@ module GSM_RR_Types { } }; + template ImmediateAssignment t_IMM_ASS_TBF_DL(template GprsTlli tlli) := { + ded_or_tbf := { + spare := ?, + tma := ?, + downlink := ?, + tbf := true + }, + page_mode := ?, + chan_desc := omit, + pkt_chan_desc := { + channel_Type_spare := ?, + tn := ?, + tsc := ?, + presence := ?, + zero := *, + one := omit + }, + req_ref := ?, + timing_advance := ?, + mobile_allocation := ?, + rest_octets := { + presence := '11'B, + ll := omit, + lh := omit, + hl := omit, + hh := { + presence := '01'B, + ul := omit, + dl := { + tlli := tlli, + group1_present := ?, + group1 := *, + ta_index_present := ?, + ta_index := *, + tbf_starting_time_present := ?, + tbf_starting_time := *, + p0_present := ?, + p0 := *, + pr_mode := * + } + } + } + }; + + template GsmRrMessage t_RR_IMM_ASS_TBF_DL(template GprsTlli tlli) := { + header := t_RrHeader(IMMEDIATE_ASSIGNMENT, ?), + payload := { + imm_ass := t_IMM_ASS_TBF_DL(tlli) + } + }; + } with { encode "RAW" ; variant "FIELDORDER(msb)" } diff --git a/library/L1CTL_PortType.ttcn b/library/L1CTL_PortType.ttcn index 2775e195..eadc74a3 100644 --- a/library/L1CTL_PortType.ttcn +++ b/library/L1CTL_PortType.ttcn @@ -90,6 +90,28 @@ module L1CTL_PortType { return rr.payload.imm_ass; } + function f_L1CTL_WAIT_IMM_ASS_TBF_DL(L1CTL_PT pt, GprsTlli tlli) return ImmediateAssignment { + var L1ctlDlMessage dl; + var GsmRrMessage rr; + timer T := 10.0; + T.start; + alt { + [] pt.receive(t_L1CTL_DATA_IND(t_RslChanNr_PCH_AGCH(0))) -> value dl { + rr := dec_GsmRrMessage(dl.payload.data_ind.payload); + log("PCH/AGCN DL RR: ", rr); + if (match(rr, t_RR_IMM_ASS_TBF_DL(tlli))) { + log("Received IMM.ASS for our TLLI!"); + } else { + repeat; + } + }; + [] pt.receive { repeat }; + [] T.timeout { setverdict(fail, "Timeout waiting for IMM ASS") }; + } + T.stop; + return rr.payload.imm_ass; + } + function f_L1CTL_TBF_CFG(L1CTL_PT pt, boolean is_uplink, TfiUsfArr tfi_usf) { timer T := 2.0; T.start; diff --git a/library/LAPDm_RAW_PT.ttcn b/library/LAPDm_RAW_PT.ttcn index ab995389..f5d19264 100644 --- a/library/LAPDm_RAW_PT.ttcn +++ b/library/LAPDm_RAW_PT.ttcn @@ -26,7 +26,21 @@ module LAPDm_RAW_PT { charstring err optional } - type record TBF_establish_res { + type record length(8) of uint8_t TfiList; + type record TbfPars { + GsmArfcn arfcn optional, + /* Temporary Flow Identifier for each TN */ + TfiList tfi + } + type record length(8) of TbfPars TbfParsPerTs; + + template TbfPars t_TbfParsInit := { + arfcn := omit, + tfi := { 255, 255, 255, 255, 255, 255, 255, 255 } + } + + type record TBF_UL_establish_res { + TbfPars pars optional, charstring err optional } @@ -40,10 +54,17 @@ module LAPDm_RAW_PT { LapdmFrame lapdm } - type record TBF_establish_req { + type integer TbfNr (0..7); /* maximum of 8 concurrent TBF per direction */ + type record TBF_UL_establish_req { + TbfNr tbf_nr, uint8_t ra } + type record TBF_DL_establish_req { + TbfNr tbf_nr, + TbfPars pars + } + /* PH-DATA.ind / PH-DATA.req */ type record RLCMAC_ph_data_ind { GprsCodingScheme cs, @@ -74,11 +95,12 @@ module LAPDm_RAW_PT { in BCCH_tune_req, DCCH_establish_req, DCCH_release_req, - TBF_establish_req, + TBF_UL_establish_req, + TBF_DL_establish_req, RLCMAC_ph_data_req, LAPDm_ph_data; out DCCH_establish_res, - TBF_establish_res, + TBF_UL_establish_res, RLCMAC_ph_data_ind, LAPDm_ph_data; } with {extension "internal"}; @@ -86,13 +108,14 @@ module LAPDm_RAW_PT { /* port from user (external) point of view */ type port LAPDm_PT message { in DCCH_establish_res, - TBF_establish_res, + TBF_UL_establish_res, RLCMAC_ph_data_ind, LAPDm_ph_data; out BCCH_tune_req, DCCH_establish_req, DCCH_release_req, - TBF_establish_req, + TBF_UL_establish_req, + TBF_DL_establish_req, RLCMAC_ph_data_req, LAPDm_ph_data; } with {extension "internal"}; @@ -124,6 +147,9 @@ module LAPDm_RAW_PT { /* channel description of the currently active DCH */ var ChannelDescription chan_desc; + + var TbfParsPerTs g_tbf_ul; + var TbfParsPerTs g_tbf_dl; }; /* wrapper function to log state transitions */ @@ -286,6 +312,51 @@ module LAPDm_RAW_PT { set_ph_state(PH_STATE_BCH); } + /* Establish TBF / packet transfer mode */ + private altstep as_tbf_ul_est() runs on lapdm_CT { + var TBF_UL_establish_req tbf_ul_req; + [] LAPDM_SP.receive(TBF_UL_establish_req:?) -> value tbf_ul_req { + var TbfNr tbf_nr := tbf_ul_req.tbf_nr; + var TBF_UL_establish_res res; + if (isvalue(g_tbf_ul[tbf_nr].arfcn)) { + setverdict(fail, "Cannot establish UL TBF ID ", tbf_nr, ": BUSY"); + self.stop; + } + f_establish_tbf(tbf_ul_req.ra); + if (ph_state == PH_STATE_TBF) { + g_tbf_ul[tbf_nr] := valueof(t_TbfParsInit); /* FIXME: Actual TFI[s] */ + log("Established UL TBF ", tbf_nr); + res := { pars := g_tbf_ul[tbf_nr], err := omit }; + } else { + res := { pars := omit, err := "Unable to establish UL TBF" }; + } + LAPDM_SP.send(res); + } + } + + private altstep as_tbf_dl_est() runs on lapdm_CT { + var TBF_DL_establish_req tbf_dl_req; + [] LAPDM_SP.receive(TBF_DL_establish_req:?) -> value tbf_dl_req { + var TbfNr tbf_nr := tbf_dl_req.tbf_nr; + if (isvalue(g_tbf_dl[tbf_nr].arfcn)) { + setverdict(fail, "Cannot establish DL TBF ID ", tbf_nr, ": BUSY"); + self.stop; + } + g_tbf_dl[tbf_nr] := tbf_dl_req.pars; + f_L1CTL_TBF_CFG(L1CTL, false, tbf_dl_req.pars.tfi); + set_ph_state(PH_STATE_TBF); + log("Established DL TBF ", tbf_nr, ": ", tbf_dl_req.pars); + } + } + + private function f_init_tbf() runs on lapdm_CT { + var integer i; + for (i := 0; i < 8; i := i+1) { + g_tbf_ul[i] := valueof(t_TbfParsInit); + g_tbf_dl[i] := valueof(t_TbfParsInit); + } + } + function ScanEvents() runs on lapdm_CT { var L1ctlDlMessage dl; var BCCH_tune_req bt; @@ -294,7 +365,8 @@ module LAPDm_RAW_PT { var RLCMAC_ph_data_req rpdr; var DCCH_establish_req est_req; var DCCH_establish_res est_res; - var TBF_establish_req tbf_req; + + f_init_tbf(); while (true) { if (ph_state == PH_STATE_NULL) { @@ -341,17 +413,8 @@ module LAPDm_RAW_PT { LAPDM_SP.send(res); } - /* Establish TBF / packet transfer mode */ - [] LAPDM_SP.receive(TBF_establish_req:?) -> value tbf_req { - var TBF_establish_res res; - f_establish_tbf(tbf_req.ra); - if (ph_state == PH_STATE_TBF) { - res := { err := omit }; - } else { - res := { err := "Unable to establish TBF" }; - } - LAPDM_SP.send(res); - } + [] as_tbf_ul_est(); + [] as_tbf_dl_est(); [] LAPDM_SP.receive {} [] L1CTL.receive {} @@ -404,6 +467,7 @@ module LAPDm_RAW_PT { /* decode + forward any blocks from L1 to L23*/ [] L1CTL.receive(t_L1CTL_DATA_IND(t_RslChanNr_PDCH(?))) -> value dl { rpdi.block := dec_RlcmacDlBlock(dl.payload.data_ind.payload); + /* FIXME: Filter based on g_tbf_dl */ rpdi.fn := dl.dl_info.frame_nr; rpdi.ts_nr := dl.dl_info.chan_nr.tn; rpdi.cs := CS1; /* FIXME */ @@ -427,10 +491,14 @@ module LAPDm_RAW_PT { } } + [] as_tbf_ul_est(); + [] as_tbf_dl_est(); + /* FIXME: release TBF mode */ [] LAPDM_SP.receive(DCCH_release_req:?) { /* go back to BCCH */ f_release_tbf(); + f_init_tbf(); } } diff --git a/library/RLCMAC_CSN1_Types.ttcn b/library/RLCMAC_CSN1_Types.ttcn index 95b58386..fbd01d4d 100644 --- a/library/RLCMAC_CSN1_Types.ttcn +++ b/library/RLCMAC_CSN1_Types.ttcn @@ -524,5 +524,31 @@ module RLCMAC_CSN1_Types { } } + private const ILevel iNone := { + presence := '0'B, + i_level := omit + } + private const ChannelQualityReport c_ChQualRep_default := { + c_value := 0, + rxqual := 0, + sign_var := 0, + i_levels := { iNone, iNone, iNone, iNone, iNone, iNone, iNone, iNone } + } + template (value) RlcmacUlCtrlMsg ts_RlcMacUlCtrl_PKT_DL_ACK(uint5_t dl_tfi, + AckNackDescription andesc, + ChannelQualityReport qual_rep := c_ChQualRep_default) := { + msg_type := PACKET_DL_ACK_NACK, + u := { + dl_ack_nack := { + dl_tfi := dl_tfi, + ack_nack_desc := andesc, + chreq_desc_presence := '0'B, + chreq_desc := omit, + ch_qual_rep := qual_rep + } + } + } + + } with { encode "RAW"; variant "FIELDORDER(msb)" variant "BYTEORDER(last)" }; diff --git a/library/RLCMAC_Types.ttcn b/library/RLCMAC_Types.ttcn index 78861ffd..3ae12037 100644 --- a/library/RLCMAC_Types.ttcn +++ b/library/RLCMAC_Types.ttcn @@ -323,6 +323,21 @@ uint3_t usf) := { } } + template RlcmacDlBlock tr_RLCMAC_DATA_RRBP := { + data := { + mac_hdr := { + mac_hdr := { + payload_type := MAC_PT_RLC_DATA, + rrbp := ?, + rrbp_valid := true, + usf := ? + }, + hdr_ext := ? + }, + blocks := ? + } + } + /* Template for Uplink MAC Control Header */ template UlMacCtrlHeader t_RLCMAC_UlMacCtrlH(template MacPayloadType pt, template boolean retry := false) := { payload_type := pt, diff --git a/pcu/PCU_Tests.ttcn b/pcu/PCU_Tests.ttcn index ef468317..12b63d63 100644 --- a/pcu/PCU_Tests.ttcn +++ b/pcu/PCU_Tests.ttcn @@ -16,6 +16,7 @@ module PCU_Tests { import from LAPDm_RAW_PT all; import from GPRS_Context all; import from GPRS_TBF all; + import from L1CTL_PortType all; modulepar { BssgpConfig mp_gb_cfg := { @@ -221,12 +222,12 @@ module PCU_Tests { L1.send(tune_req); /* FIXME: wait for confirm */ - var TBF_establish_req est_req := { ra := hex2int('7B'H) }; + var TBF_UL_establish_req est_req := { tbf_nr := 0, ra := hex2int('7B'H) }; L1.send(est_req); T.start; /* FIXME: wait for confirm */ alt { - [] L1.receive(TBF_establish_res:?) {} + [] L1.receive(TBF_UL_establish_res:?) {} [] L1.receive { repeat; } [] T.timeout { setverdict(fail, "Timeout establishing UL TBF"); @@ -526,6 +527,82 @@ function f_ul_tbf(inout UlTbfState us) runs on dummy_CT { f_exit(); } + testcase TC_dl_tbf() runs on dummy_CT { + g_mmctx.imsi := '262420123456789'H; + g_mmctx.tlli := f_random_tlli(); + f_init(); + + f_establish_dl_tbf(); + + f_exit(); + } + + function f_wait_tbf_dl(TbfNr tbf_nr, GprsTlli tlli) runs on dummy_CT return ImmediateAssignment { + var LAPDm_ph_data ph_data; + var GsmRrMessage rr; + timer T := 10.0; + T.start; + alt { + [] L1.receive(LAPDm_ph_data:{sacch:=?,sapi:=0,lapdm:={bbis:=?}}) -> value ph_data { + rr := dec_GsmRrMessage(ph_data.lapdm.bbis.payload); + log("PCH/AGCH DL RR: ", rr); + if (match(rr, t_RR_IMM_ASS_TBF_DL(tlli))) { + var TbfPars tbf_pars := valueof(t_TbfParsInit); + log("Received IMM.ASS for our TLLI!"); + tbf_pars.tfi[rr.payload.imm_ass.pkt_chan_desc.tn] := + rr.payload.imm_ass.rest_octets.hh.dl.group1.tfi_assignment; + L1.send(TBF_DL_establish_req:{tbf_nr, tbf_pars}); + } else { + repeat; + } + } + [] L1.receive { repeat }; + [] T.timeout { + setverdict(fail, "Timeout waiting for IMM ASS") + self.stop; + } + } + T.stop; + return rr.payload.imm_ass; + } + + /* Establish an UL TBF: Tune to ARFCN, send RACH, receive AGCH, enable TBF Rx */ + function f_establish_dl_tbf() runs on dummy_CT { + timer T := 5.0; + var BCCH_tune_req tune_req := { { false, 871 }, true }; + L1.send(tune_req); + /* FIXME: wait for confirm */ + + /* sending a GMM PDU as DL-UNITDATA should trigger Paging + DL TBF Assignment */ + tx_gmm('1'B, '01020304'O, c_LLC_SAPI_LLGMM); + + /* Expect an IMM.ASS for PDCH on the AGCH */ + f_wait_tbf_dl(0, g_mmctx.tlli); + + var RLCMAC_ph_data_ind dl; + alt { + [] L1.receive(RLCMAC_ph_data_ind:{cs:=?, ts_nr:=?, fn:=?, block:=tr_RLCMAC_DATA_RRBP}) -> +value dl { + var uint6_t tfi := dl.block.data.mac_hdr.hdr_ext.tfi; + var GsmFrameNumber ul_fn := f_rrbp_fn(dl.fn, dl.block.data.mac_hdr.mac_hdr.rrbp); + var AckNackDescription an_desc := { /* FIXME: compute this based on state */ + final_ack := '1'B, + starting_seq_nr := 0, + receive_block_bitmap := '0000000000000000000000000000000000000000000000000000000000000001'B + } + var RlcmacUlCtrlMsg ctrl_ack; + ctrl_ack := valueof(ts_RlcMacUlCtrl_PKT_DL_ACK(tfi, an_desc)); + var RlcmacUlBlock ul_block := valueof(ts_RLC_UL_CTRL_ACK(ctrl_ack)); + L1.send(ts_PH_DATA_ABS(0, CS1, dl.ts_nr, ul_fn, {false, 871}, ul_block)); + log("Sent DL ACK: ", ul_block); + } + [] L1.receive { repeat; } + } + + f_sleep(10.0); + } + + control { execute(TC_selftest_bssgp()); execute(TC_selftest_ns()); -- cgit v1.2.3