[PATCH] osmo-ttcn3-hacks[master]: WIP: working UL TBF with segmentation

This is merely a historical archive of years 2008-2021, before the migration to mailman3.

A maintained and still updated list archive can be found at https://lists.osmocom.org/hyperkitty/list/gerrit-log@lists.osmocom.org/.

Harald Welte gerrit-no-reply at lists.osmocom.org
Thu Mar 8 10:53:46 UTC 2018


Review at  https://gerrit.osmocom.org/7153

WIP: working UL TBF with segmentation

Change-Id: I0f93246f02e1bee2e1e9db62af5e1e3559c415e9
---
M gprs_gb/Test.ttcn
M library/GSM_Types.ttcn
M library/LAPDm_RAW_PT.ttcn
M library/Osmocom_Types.ttcn
M library/RLCMAC_EncDec.cc
M library/RLCMAC_Types.ttcn
6 files changed, 275 insertions(+), 150 deletions(-)


  git pull ssh://gerrit.osmocom.org:29418/osmo-ttcn3-hacks refs/changes/53/7153/1

diff --git a/gprs_gb/Test.ttcn b/gprs_gb/Test.ttcn
index 8741e86..f94fe09 100644
--- a/gprs_gb/Test.ttcn
+++ b/gprs_gb/Test.ttcn
@@ -14,6 +14,8 @@
 	import from RLCMAC_Types all;
 	import from RLCMAC_CSN1_Types all;
 	import from LAPDm_RAW_PT all;
+	import from GPRS_Context all;
+	import from GPRS_TBF all;
 
 	modulepar {
 		BssgpConfig mp_gb_cfg := {
@@ -31,13 +33,6 @@
 			sgsn_role := true
 		};
 	}
-
-	type record MmContext {
-		hexstring	imsi optional,
-		GprsTlli	tlli,
-		uint9_t		n_u
-	};
-
 
 	type component dummy_CT extends BSSGP_Client_CT {
 		var lapdm_CT lapdm_component;
@@ -230,123 +225,6 @@
 		T.stop;
 	}
 
-	/* 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, BIT1 more := '0'B, boolean e := true) := {
-		hdr := {
-			length_ind := lengthof(data),
-			more := more,
-			e := e
-		},
-		payload := data
-	}
-
 	/* compute a random TLLI; FIXME: what about TLLI prefix / local/foreign/...? */
 	function f_random_tlli() return GprsTlli {
 		var GprsTlli tlli := f_rnd_octstring(4);
@@ -373,6 +251,60 @@
 		return (fn + add) mod 2715648;
 	}
 
+
+function f_bssgp_wait_ul_ud(template BssgpDecoded bd_exp) runs on dummy_CT {
+	timer T := 5.0;
+	T.start;
+	alt {
+	[] BSSGP.receive(bd_exp) {
+		log("found matching BSSGP UL-UNITDATA PDU");
+		}
+	[] T.timeout {
+		setverdict(fail, "Timeout waiting for ", bd_exp);
+		}
+	}
+}
+
+
+function f_ul_tbf(inout UlTbfState us) runs on dummy_CT {
+	var RLCMAC_ph_data_ind dl;
+
+	/* Establish an UL-TBF */
+	f_establish_ul_tbf();
+
+	while (true) {
+		var RlcmacUlBlock blk;
+		if (f_ul_tbf_get_next_block(blk, us, g_mmctx, true) == false) {
+			break;
+		}
+
+		/* Send the block to L1 for transmission */
+		log("L1=", blk);
+		L1.send(RLCMAC_ph_data_req:{dyn:={tbf_id := 0, cs := us.tbf.initial_cs, block := blk}});
+	}
+
+	alt {
+	[] L1.receive(RLCMAC_ph_data_ind:{cs:=?, ts_nr:=?, fn:=?, block:=tr_RLCMAC_ACK_NACK(0, g_mmctx.tlli)}) -> value dl {
+		log("found matching ACK/NACK");
+		/* send CTRL ACK in uplink */
+		var GsmFrameNumber ul_fn := f_rrbp_fn(dl.fn, dl.block.ctrl.mac_hdr.rrbp);
+		var RlcmacUlCtrlMsg ctrl_ack := valueof(ts_RlcMacUlCtrl_PKT_CTRL_ACK(g_mmctx.tlli));
+		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));
+		/* wait for the final ACK */
+		if (dl.block.ctrl.payload.u.ul_ack_nack.gprs.ack_nack_desc.final_ack == '0'B) {
+			repeat;
+		}
+		}
+	[] L1.receive { repeat; }
+	}
+
+	for (var integer i := 0; i < sizeof(us.tbf.llc_pdus_enc); i := i+1) {
+		f_bssgp_wait_ul_ud(tr_BD_BSSGP(tr_BSSGP_UL_UD(g_mmctx.tlli, ?, us.tbf.llc_pdus_enc[i])));
+	}
+	setverdict(pass);
+}
+
 	/* Send a single Uplink Block via Um; Verify reception on BSSGP; Expect UL_ACK on Um */
 	function f_single_ul_block(GprsCodingScheme cs) runs on dummy_CT {
 		var octetstring payload := '01020304'O;
@@ -389,7 +321,7 @@
 		/* ensure that this LLC-PDU arrives from the right TLLI at the (simulated) SGSN */
 		BSSGP.receive(tr_BD_BSSGP(tr_BSSGP_UL_UD(g_mmctx.tlli, ?, llc_enc)));
 
-		/* ensure the MS eceives an UL_ACK_NACK */
+		/* ensure the MS receives an UL_ACK_NACK */
 		alt {
 		[] L1.receive(RLCMAC_ph_data_ind:{cs:=?, ts_nr:=?, fn:=?, block:=tr_RLCMAC_ACK_NACK(0, g_mmctx.tlli)}) -> value dl {
 			log("found matching ACK/NACK");
@@ -573,6 +505,35 @@
 		log(dec_GsmRrMessage(c_ia_tbf));
 	}
 
+	function f_seq_octstr(integer len) return octetstring {
+		var octetstring payload := ''O;
+		for (var integer i := 0; i < len; i := i+1 ) {
+			payload := payload & int2oct(i mod 256, 1);
+		}
+		return payload;
+	}
+
+	testcase TC_ul_tbf() runs on dummy_CT {
+		g_mmctx.imsi := '262420123456789'H;
+		g_mmctx.tlli := f_random_tlli();
+		f_init();
+		f_bssgp_client_register(g_mmctx.imsi, g_mmctx.tlli, mp_gb_cfg.cell_id);
+		f_bssgp_establish();
+
+		var octetstring payload := f_seq_octstr(256);
+		var UlTbfPars ul_tbf_pars := {
+			ack_mode := true,
+			initial_cs := CS1,
+			llc_pdus := { 
+				valueof(ts_LLC_UI(payload, c_LLC_SAPI_LLGMM, '0'B, g_mmctx.n_u)),
+				valueof(ts_LLC_UI(payload, c_LLC_SAPI_LLGMM, '0'B, g_mmctx.n_u+1))
+			}
+		};
+		var UlTbfState ul_tbf_state;
+		f_UlTbfState_init(ul_tbf_state, ul_tbf_pars);
+		f_ul_tbf(ul_tbf_state);
+	}
+
 	control {
 		execute(TC_selftest_bssgp());
 		execute(TC_selftest_ns());
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/LAPDm_RAW_PT.ttcn b/library/LAPDm_RAW_PT.ttcn
index ab99538..30dbb3b 100644
--- a/library/LAPDm_RAW_PT.ttcn
+++ b/library/LAPDm_RAW_PT.ttcn
@@ -27,6 +27,7 @@
 	}
 
 	type record TBF_establish_res {
+		//uint8_t tfi,
 		charstring err optional
 	}
 
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)" }

-- 
To view, visit https://gerrit.osmocom.org/7153
To unsubscribe, visit https://gerrit.osmocom.org/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: I0f93246f02e1bee2e1e9db62af5e1e3559c415e9
Gerrit-PatchSet: 1
Gerrit-Project: osmo-ttcn3-hacks
Gerrit-Branch: master
Gerrit-Owner: Harald Welte <laforge at gnumonks.org>



More information about the gerrit-log mailing list