gprs_gb: working UL TBF with segmentation
Change-Id: I0f93246f02e1bee2e1e9db62af5e1e3559c415e9
diff --git a/library/GSM_Types.ttcn b/library/GSM_Types.ttcn
index c7b7991..0289b08 100644
--- a/library/GSM_Types.ttcn
+++ b/library/GSM_Types.ttcn
@@ -26,6 +26,19 @@
CS1, CS2, CS3, CS4
};
+ function f_gprs_blocksize(GprsCodingScheme cs) return integer {
+ select (cs) {
+ case (CS1) { return 22 }
+ case (CS2) { return 32 }
+ case (CS3) { return 38 }
+ case (CS3) { return 52 }
+ case else {
+ setverdict(fail, "Invalid GPRS CS ", cs);
+ return -1;
+ }
+ }
+ }
+
/* 10.5.2.8 */
type enumerated ChannelNeeded {
CHAN_NEED_ANY (0),
diff --git a/library/Osmocom_Types.ttcn b/library/Osmocom_Types.ttcn
index e36d2dc..d01fe37 100644
--- a/library/Osmocom_Types.ttcn
+++ b/library/Osmocom_Types.ttcn
@@ -126,5 +126,14 @@
T.start;
}
+/* divide two integers and return rounded-up result */
+function f_div_round_up(integer dividend, integer divisor) return integer {
+ var integer x := dividend / divisor;
+ if (dividend rem divisor != 0) {
+ x := x+1;
+ }
+ return x;
+}
+
} with { encode "RAW"; variant "FIELDORDER(msb)" }
diff --git a/library/RLCMAC_EncDec.cc b/library/RLCMAC_EncDec.cc
index ad52f91..b911c75 100644
--- a/library/RLCMAC_EncDec.cc
+++ b/library/RLCMAC_EncDec.cc
@@ -32,9 +32,9 @@
for (i = 0; i < in.blocks().size_of(); i++) {
/* fix the 'E' bit in case it is not clear */
if (i < in.blocks().size_of()-1)
- in.blocks()[i].hdr().e() = false;
+ in.blocks()[i].hdr()().e() = false;
else
- in.blocks()[i].hdr().e() = true;
+ in.blocks()[i].hdr()().e() = true;
in.blocks()[i].hdr().encode(LlcBlockHdr_descr_, ttcn_buffer, TTCN_EncDec::CT_RAW);
}
}
@@ -69,7 +69,7 @@
ret_val.blocks()[num_llc_blocks++] = lb;
/* if E == '1'B, we can proceed further */
- if (lb.hdr().e() == true)
+ if (lb.hdr()().e() == true)
break;
}
}
@@ -87,7 +87,7 @@
} else {
if (ret_val.blocks().is_bound()) {
for (int i = 0; i < ret_val.blocks().size_of(); i++) {
- unsigned int length = ret_val.blocks()[i].hdr().length__ind();
+ unsigned int length = ret_val.blocks()[i].hdr()().length__ind();
if (length > ttcn_buffer.get_read_len())
length = ttcn_buffer.get_read_len();
ret_val.blocks()[i].payload() = OCTETSTRING(length, ttcn_buffer.get_read_data());
@@ -107,31 +107,57 @@
TTCN_Buffer ttcn_buffer;
int i;
- /* Fix 'e' bit of initial header based on following blocks */
- if (!in.blocks().is_bound() ||
- (in.blocks().size_of() == 1 && !in.blocks()[0].hdr().is_bound()))
- in.mac__hdr().e() = true;
- else
+ if (!in.blocks().is_bound()) {
+ /* we don't have nay blocks: Add length value (zero) */
+ in.mac__hdr().e() = false; /* E=0: extension octet follows */
+ } else if (in.blocks().size_of() == 1 && in.blocks()[0].hdr() == OMIT_VALUE) {
+ /* If there's only a single block, and that block has no HDR value defined, */
+ in.mac__hdr().e() = true; /* E=0: extension octet follows */
+ } else {
+ /* Length value */
in.mac__hdr().e() = false;
+ }
/* Fix other presence indications */
in.mac__hdr().tlli__ind() = in.tlli().is_bound() && in.tlli() != OMIT_VALUE;
in.mac__hdr().pfi__ind() = in.pfi().is_bound() && in.pfi() != OMIT_VALUE;
- /* use automatic/generated decoder for header */
+ /* use automatic/generated encoder for header */
in.mac__hdr().encode(UlMacDataHeader_descr_, ttcn_buffer, TTCN_EncDec::CT_RAW);
- /* Add LI octets, if any */
- if (in.blocks().is_bound() &&
- (in.blocks().size_of() != 1 || in.blocks()[0].hdr().is_bound())) {
- /* first write LI octets */
- for (i = 0; i < in.blocks().size_of(); i++) {
- /* fix the 'E' bit in case it is not clear */
- if (i < in.blocks().size_of()-1)
- in.blocks()[i].hdr().e() = false;
- else
- in.blocks()[i].hdr().e() = true;
- in.blocks()[i].hdr().encode(LlcBlockHdr_descr_, ttcn_buffer, TTCN_EncDec::CT_RAW);
+ if (in.mac__hdr().e() == false) {
+ /* Add LI octets, if any */
+ if (!in.blocks().is_bound()) {
+ ttcn_buffer.put_c(0x01); /* M=0, E=1 LEN=0 */
+ } else {
+ for (i = 0; i < in.blocks().size_of(); i++) {
+#if 0
+ /* check for penultimate block */
+ if (i == in.blocks().size_of()-2) {
+ /* if last block has no header, no more LI */
+ if (in.blocks()[i+1].hdr() == OMIT_VALUE) {
+ in.blocks()[i].hdr()().more() = true;
+ } else {
+ /* header present, we have to encode LI */
+ in.blocks()[i].hdr()().more() = false;
+ in.blocks()[i].hdr()().length__ind() =
+ in.blocks()[i+1].payload().lengthof();
+ }
+ } else if (i < in.blocks().size_of()-2) {
+ /* one of the first blocks, before the penultimate or last */
+ in.blocks()[i].hdr()().e() = false; /* LI present */
+ /* re-compute length */
+ in.blocks()[i].hdr()().length__ind() =
+ in.blocks()[i+1].payload().lengthof();
+ }
+ /* Encode LI octet if E=0 */
+ }
+#endif
+ if (in.blocks()[i].hdr() != OMIT_VALUE) {
+ in.blocks()[i].hdr()().encode(LlcBlockHdr_descr_, ttcn_buffer,
+ TTCN_EncDec::CT_RAW);
+ }
+ }
}
}
@@ -201,7 +227,7 @@
TTCN_Logger::end_event();
/* if E == '1'B, we can proceed further */
- if (lb.hdr().e() == true)
+ if (lb.hdr()().e() == true)
break;
}
}
@@ -229,7 +255,7 @@
} else {
if (ret_val.blocks().is_bound()) {
for (int i = 0; i < ret_val.blocks().size_of(); i++) {
- unsigned int length = ret_val.blocks()[i].hdr().length__ind();
+ unsigned int length = ret_val.blocks()[i].hdr()().length__ind();
if (length > ttcn_buffer.get_read_len())
length = ttcn_buffer.get_read_len();
ret_val.blocks()[i].payload() = OCTETSTRING(length, ttcn_buffer.get_read_data());
diff --git a/library/RLCMAC_Types.ttcn b/library/RLCMAC_Types.ttcn
index 937aa7b..78861ff 100644
--- a/library/RLCMAC_Types.ttcn
+++ b/library/RLCMAC_Types.ttcn
@@ -108,7 +108,7 @@
type record LlcBlockHdr {
uint6_t length_ind,
/* 1 = new LLC PDU starts */
- BIT1 more,
+ boolean more,
/* 0 = another extension octet after LLC PDU, 1 = no more extension octets */
boolean e
} with {
@@ -116,7 +116,7 @@
};
type record LlcBlock {
/* Header is only present if LI field was present */
- LlcBlockHdr hdr,
+ LlcBlockHdr hdr optional,
octetstring payload
} with { variant "" };
type record of LlcBlock LlcBlocks;
@@ -239,4 +239,119 @@
}
}
+ /* Template fro uplink Data block */
+ template RlcmacUlBlock t_RLCMAC_UL_DATA(template uint5_t tfi, template uint4_t cv, template uint7_t bsn,
+ template LlcBlocks blocks := {}, template boolean stall := false) := {
+ data := {
+ mac_hdr := {
+ payload_type := MAC_PT_RLC_DATA,
+ countdown := cv,
+ stall_ind := false,
+ retry := false,
+ spare := '0'B,
+ pfi_ind := false,
+ tfi := tfi,
+ tlli_ind := false,
+ bsn := bsn,
+ e := false
+ },
+ tlli := omit,
+ pfi := omit,
+ blocks := blocks
+ }
+ }
+ template RlcmacUlBlock t_RLCMAC_UL_DATA_TLLI(template uint5_t tfi, template uint4_t cv, template uint7_t bsn,
+ template LlcBlocks blocks := {}, template boolean stall := false, template GprsTlli tlli) := {
+ data := {
+ mac_hdr := {
+ payload_type := MAC_PT_RLC_DATA,
+ countdown := cv,
+ stall_ind := false,
+ retry := false,
+ spare := '0'B,
+ pfi_ind := false,
+ tfi := tfi,
+ tlli_ind := true,
+ bsn := bsn,
+ e := false
+ },
+ tlli := tlli,
+ pfi := omit,
+ blocks := blocks
+ }
+ }
+
+ template DlMacHeader t_RLCMAC_DlMacH(template MacPayloadType pt, template MacRrbp rrbp, template
+uint3_t usf) := {
+ payload_type := pt,
+ rrbp := rrbp,
+ rrbp_valid := ispresent(rrbp),
+ usf := usf
+ }
+
+ /* Receive Template for Downlink ACK/NACK */
+ template RlcmacDlBlock tr_RLCMAC_ACK_NACK(template uint5_t ul_tfi, template GprsTlli tlli := ?) := {
+ ctrl := {
+ mac_hdr := {
+ payload_type := (MAC_PT_RLCMAC_NO_OPT, MAC_PT_RLCMAC_OPT),
+ rrbp:= ?,
+ rrbp_valid := true,
+ usf := ?
+ },
+ opt := *,
+ payload := {
+ msg_type := PACKET_UL_ACK_NACK,
+ u := {
+ ul_ack_nack := {
+ page_mode := ?,
+ msg_excape := ?,
+ uplink_tfi := ul_tfi,
+ is_egprs := '0'B,
+ gprs := {
+ ch_coding_cmd := ?,
+ ack_nack_desc := ?,
+ cont_res_tlli_present := ?,
+ cont_res_tlli := tlli,
+ pkt_ta_present := ?,
+ pkt_ta := *,
+ pwr_ctrl_present := ?,
+ pwr_ctrl := *
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /* Template for Uplink MAC Control Header */
+ template UlMacCtrlHeader t_RLCMAC_UlMacCtrlH(template MacPayloadType pt, template boolean retry := false) := {
+ payload_type := pt,
+ spare := '00000'B,
+ retry := retry
+ }
+
+ /* Template for Uplink Conntrol ACK */
+ template RlcmacUlBlock ts_RLCMAC_CTRL_ACK(GprsTlli tlli, CtrlAck ack := MS_RCVD_TWO_RLC_SAME_RTI_DIFF_RBSN) := {
+ ctrl := {
+ mac_hdr := t_RLCMAC_UlMacCtrlH(MAC_PT_RLCMAC_NO_OPT),
+ payload := {
+ msg_type := PACKET_CONTROL_ACK,
+ u := {
+ ctrl_ack := {
+ tlli := tlli,
+ ctrl_ack := ack
+ }
+ }
+ }
+ }
+ }
+
+ /* Template for a LlcBlock (part of a LLC frame inside RlcMac?lDataBlock */
+ template LlcBlock t_RLCMAC_LLCBLOCK(octetstring data, boolean more := false, boolean e := true) := {
+ /* let encoder figure out the header */
+ hdr := omit,
+ payload := data
+ }
+
+
} with { encode "RAW"; variant "FIELDORDER(msb)" }