summaryrefslogtreecommitdiffstats
path: root/lapdm/L1CTL_Test.ttcn
blob: 97704acb0bbf383f1ea5e5b3578cd8bece0c2ab2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
module L1CTL_Test {
	import from GSM_Types all;
	import from Osmocom_Types all;
	import from LAPDm_RAW_PT all;
	import from LAPDm_Types all;

	type component dummy_CT {
		port LAPDm_PT LAPDM;
		var lapdm_CT lapdm_component;
	};

	function f_init() runs on dummy_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 dummy_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 dummy_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 dummy_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 dummy_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 dummy_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 dummy_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 dummy_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 dummy_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
	  * SABM. This is required during the contention resolution procedure as specified in 8.4.1.4 */
	testcase TC_sabm_retransmit() runs on dummy_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 dummy_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());
*/
	}
}