diff --git a/library/RLCMAC_CSN1_Templates.ttcn b/library/RLCMAC_CSN1_Templates.ttcn index 254983a88..943717ed4 100644 --- a/library/RLCMAC_CSN1_Templates.ttcn +++ b/library/RLCMAC_CSN1_Templates.ttcn @@ -19,6 +19,28 @@ module RLCMAC_CSN1_Templates { import from MobileL3_GMM_SM_Types all; import from RLCMAC_CSN1_Types all; + /* 11.2.1 Packet Access Reject */ + template PacketAccessRejectStruct tr_PacketAccessRejectStruct_TLLI(template GprsTlli tlli := ?, + template uint8_t wait_ind := *, + template BIT1 wait_ind_size := *) := { + id_type := '0'B, + id := { + tlli := tlli + }, + wait_ind_presence := ?, + wait_ind := wait_ind, + wait_ind_size := wait_ind_size + } + template RlcmacDlCtrlMsg tr_RlcMacDlCtrl_PKT_ACC_REJ(template PacketAccessRejectStruct rej := ?) := { + msg_type := PACKET_ACCESS_REJECT, + u := { + access_reject := { + page_mode := ?, + reject_struct := rej + } + } + } + template (value) RlcmacUlCtrlMsg ts_RlcMacUlCtrl_PKT_CTRL_ACK(GprsTlli tlli, CtrlAck ack := MS_RCVD_TWO_RLC_SAME_RTI_DIFF_RBSN) := { msg_type := PACKET_CONTROL_ACK, @@ -79,6 +101,18 @@ module RLCMAC_CSN1_Templates { RlcOctetCount := 0 } + template (value) ChannelReqDescription ts_ChannelReqDescription(uint4_t peak_tput_class := 0, + uint2_t priority := 0, + RlcMode rlc_mode := RLC_MODE_ACKNOWLEDGED, + LlcPduType llc_pdu_type := LLC_PDU_IS_NOT_SACK_OR_ACK, + uint16_t RlcOctetCount := 0) := { + peak_tput_class := peak_tput_class, + priority := priority, + rlc_mode := rlc_mode, + llc_pdu_type := llc_pdu_type, + RlcOctetCount := RlcOctetCount + }; + /* TS 44.060 sec 11.2.16 */ template (value) RlcmacUlCtrlMsg ts_RlcMacUlCtrl_PKT_RES_REQ(GprsTlli tlli, template (omit) MSRadioAccessCapabilityV ms_rac, diff --git a/library/RLCMAC_CSN1_Types.ttcn b/library/RLCMAC_CSN1_Types.ttcn index d9a566264..2093f5536 100644 --- a/library/RLCMAC_CSN1_Types.ttcn +++ b/library/RLCMAC_CSN1_Types.ttcn @@ -705,6 +705,7 @@ module RLCMAC_CSN1_Types { /* 11.2.0.1 */ type union RlcmacDlCtrlUnion { + PacketAccessReject access_reject, PacketDlAssignment dl_assignment, PacketMeasOrder meas_order, PacketUlAssignment ul_assignment, @@ -721,7 +722,8 @@ module RLCMAC_CSN1_Types { RlcmacDlCtrlMsgType msg_type, RlcmacDlCtrlUnion u } with { - variant (u) "CROSSTAG(dl_assignment, msg_type = PACKET_DL_ASSIGNMENT; + variant (u) "CROSSTAG(access_reject, msg_type = PACKET_ACCESS_REJECT; + dl_assignment, msg_type = PACKET_DL_ASSIGNMENT; meas_order, msg_type = PACKET_MEASUREMENT_ORDER; ul_assignment, msg_type = PACKET_UL_ASSIGNMENT; paging, msg_type = PACKET_PAGING_REQUEST; @@ -739,6 +741,35 @@ module RLCMAC_CSN1_Types { external function dec_RlcmacDlCtrlMsg(in octetstring stream) return RlcmacDlCtrlMsg with { extension "prototype(convert) decode(RAW)" }; + /* 11.2.1 Packet Access Reject */ + type record PacketAccessRejectIDSub { + BIT1 id_type, + PacketRequestReference req_ref optional, + GlobalTfi gtfi optional + } with { variant (req_ref) "PRESENCE(id_type = '0'B)" + variant (gtfi) "PRESENCE(id_type = '1'B)" + }; + type union PacketAccessRejectID { + GprsTlli tlli, + PacketAccessRejectIDSub id_sub + } with { variant (tlli) "BYTEORDER(first)" }; + type record PacketAccessRejectStruct { + BIT1 id_type, + PacketAccessRejectID id, + BIT1 wait_ind_presence, + uint8_t wait_ind optional, + BIT1 wait_ind_size optional + } with { variant (id) "CROSSTAG(tlli, id_type = '0'B; id_sub, id_type = '1'B)" + variant (wait_ind) "PRESENCE(wait_ind_presence = '1'B)" + variant (wait_ind_size) "PRESENCE(wait_ind_presence = '1'B)" + }; + type record PacketAccessReject { + PageMode page_mode, + PacketAccessRejectStruct reject_struct + /* TODO: Additional Reject */ + /* TODO: Rel5 additions */ + } with { variant "" }; + /* 11.2.6 Packet Downlink Ack/Nack */ type record ILevel { diff --git a/pcu/PCU_Tests.ttcn b/pcu/PCU_Tests.ttcn index 40dd400b3..6c599171a 100644 --- a/pcu/PCU_Tests.ttcn +++ b/pcu/PCU_Tests.ttcn @@ -246,6 +246,15 @@ runs on RAW_PCU_Test_CT { } } +private function f_pcuvty_set_timer(integer t, integer val) +runs on RAW_PCU_Test_CT { + if (t >= 0) { + f_vty_config2(PCUVTY, {"pcu"}, "timer T" & int2str(t) & " " & int2str(val)); + } else { + f_vty_config2(PCUVTY, {"pcu"}, "timer X" & int2str(t * -1) & " " & int2str(val)); + } +} + private function f_init_vty(charstring id, boolean egprs_only) runs on RAW_PCU_Test_CT { map(self:PCUVTY, system:PCUVTY); f_vty_set_prompts(PCUVTY); @@ -2027,6 +2036,107 @@ testcase TC_n3105_max_t3195() runs on RAW_PCU_Test_CT { f_shutdown(__BFILE__, __LINE__, final := true); } +/* Verify configured T3172 is properly transmitted as WAIT_INDICATION in Pkt Access Reject in PACCH. */ +function f_TC_t3172(integer t3172_ms, BIT1 wait_ind_size) runs on RAW_PCU_Test_CT { + var PCUIF_info_ind info_ind; + var template IARRestOctets rest; + var BIT11 ra11; + var GprsMS ms; + var octetstring data := f_rnd_octstring(10); + var RlcmacDlBlock dl_block; + var template RlcmacDlBlock rej_tmpl; + var uint32_t dl_fn; + var uint32_t sched_fn; + var uint8_t wait_ind_val; + + /* Initialize NS/BSSGP side */ + f_init_bssgp(); + /* Initialize GPRS MS side */ + f_init_gprs_ms(); + ms := g_ms[0]; /* We only use first MS in this test */ + + info_ind := valueof(ts_PCUIF_INFO_default); + + /* Only the first TRX is enabled. */ + f_PCUIF_PDCHMask_set(info_ind, '00000000'B, (1 .. 7)); + f_PCUIF_PDCHMask_set(info_ind, '00000001'B, 0); + + /* Initialize the PCU interface abstraction */ + f_init_raw(testcasename(), info_ind); + + f_pcuvty_set_timer(3172, t3172_ms); + + /* Establish BSSGP connection to the PCU */ + f_bssgp_establish(); + f_bssgp_client_llgmm_assign(TLLI_UNUSED, ms.tlli); + + var EGPRSPktChRequest req := { + one_phase := { + tag := '0'B, + multislot_class := '10101'B, + priority := '01'B, + random_bits := '101'B + } + }; + + /* We send 7 requests, the IUT gives us all available USFs (0..6) */ + for (var integer i := 0; i < 7; i := i + 1) { + req.one_phase.random_bits := int2bit(f_rnd_int(8), 3); + f_TC_egprs_pkt_chan_req(req, tr_IMM_TBF_ASS); + } + + /* SGSN sends some DL data, PCU will page on CCCH (PCH) */ + BSSGP[0].send(ts_BSSGP_DL_UD(ms.tlli, data)); + f_ms_exp_dl_tbf_ass_ccch(ms, PCU_IF_SAPI_PCH); + + /* Wait timer X2002 and DL block is available after CCCH IMM ASS: */ + f_sleep(X2002); + f_rx_rlcmac_dl_block_exp_data(dl_block, dl_fn, data, 0); + + /* ACK the DL block */ + f_acknackdesc_ack_block(ms.dl_tbf.acknack_desc, dl_block, '1'B); + f_ms_tx_ul_block(ms, ts_RLCMAC_DL_ACK_NACK(ms.dl_tbf.tfi, ms.dl_tbf.acknack_desc, false, ts_ChannelReqDescription()), + f_dl_block_ack_fn(dl_block, dl_fn)); + + /* Since all USF are taken, we should receive a Reject: */ + + if (wait_ind_size == '0'B) { + wait_ind_val := t3172_ms / 1000; + } else { + wait_ind_val := t3172_ms / 20; + } + rej_tmpl := tr_RLCMAC_DL_CTRL(?, tr_RlcMacDlCtrl_PKT_ACC_REJ( + tr_PacketAccessRejectStruct_TLLI(ms.tlli, + wait_ind_val, + wait_ind_size))); + template (value) TsTrxBtsNum nr := ts_TsTrxBtsNum; + BTS.send(ts_PCUIF_RTS_REQ(nr.bts_nr, nr.trx_nr, nr.ts_nr, + sapi := PCU_IF_SAPI_PDTCH, fn := 0, + arfcn := f_trxnr2arfcn(valueof(nr.trx_nr)), + block_nr := nr.blk_nr)); + alt { + [] BTS.receive(tr_PCUIF_DATA_PDTCH(nr.bts_nr, + tr_PCUIF_DATA(nr.trx_nr, nr.ts_nr, sapi := PCU_IF_SAPI_PDTCH), + rej_tmpl)); + [] BTS.receive { + setverdict(fail, "Unexpected BTS message"); + f_shutdown(__BFILE__, __LINE__); + } + } + f_shutdown(__BFILE__, __LINE__, final := true); +} +testcase TC_t3172_wait_ind_size0() runs on RAW_PCU_Test_CT { + /* size=0 means value is provided in seconds. Due to value being 8 + * bit, in the 20ms step case (size=1) the maximum value possible is 20 * 255 + * = 5100. Hence, values above it should use size=0 to be able to + * provide values in range. Let's use 6 seconds, 6000ms + */ + f_TC_t3172(6000, '0'B); +} +testcase TC_t3172_wait_ind_size1() runs on RAW_PCU_Test_CT { + f_TC_t3172(3000, '1'B); +} + /* Verify PCU handles correctly Countdown Procedure based on BS_CV_MAX */ testcase TC_countdown_procedure() runs on RAW_PCU_Test_CT { var RlcmacDlBlock dl_block; @@ -6576,6 +6686,8 @@ control { execute( TC_zero_x2031_t3191() ); execute( TC_t3193() ); execute( TC_n3105_max_t3195() ); + execute( TC_t3172_wait_ind_size0() ); + execute( TC_t3172_wait_ind_size1() ); execute( TC_countdown_procedure() ); execute( TC_ul_all_sizes() ); execute( TC_ul_data_toolong_fills_padding() );