blob: d6d3be4c3b51b77362c5b769dad2855d85dd44c2 [file] [log] [blame]
Harald Welted4ba7ff2017-07-17 21:00:48 +02001/* Test Port that stacks on top of L1CTL test port and performs LAPDm encoding/decoding, so the user can send
2 * and receive LAPDm frames in decoded TTCN-3 data types. This is particularly useful for sending/receiving
3 * all kinds of hand-crafted LAPDm frames for testing of the remote LAPDm layer */
4module LAPDm_RAW_PT {
5 import from GSM_Types all;
Harald Welteffcad682017-07-30 22:51:04 +02006 import from GSM_RR_Types all;
Harald Welted4ba7ff2017-07-17 21:00:48 +02007 import from Osmocom_Types all;
8 import from L1CTL_Types all;
9 import from L1CTL_PortType all;
10 import from LAPDm_Types all;
Harald Welte4b6c7722017-08-01 00:07:12 +020011 import from RLCMAC_Types all;
Harald Welted4ba7ff2017-07-17 21:00:48 +020012
13 /* request to tune to a given ARFCN and start BCCH decoding */
14 type record BCCH_tune_req {
15 Arfcn arfcn,
16 boolean combined_ccch
17 }
18
19 /* ask for a dedicated channel to be established */
20 type record DCCH_establish_req {
21 uint8_t ra
22 }
23
24 type record DCCH_establish_res {
25 ChannelDescription chan_desc optional,
26 charstring err optional
27 }
28
Harald Welteb669ee02018-03-09 12:50:02 +010029 type record length(8) of uint8_t TfiList;
30 type record TbfPars {
31 GsmArfcn arfcn optional,
32 /* Temporary Flow Identifier for each TN */
33 TfiList tfi
34 }
35 type record length(8) of TbfPars TbfParsPerTs;
36
37 template TbfPars t_TbfParsInit := {
38 arfcn := omit,
39 tfi := { 255, 255, 255, 255, 255, 255, 255, 255 }
40 }
41
42 type record TBF_UL_establish_res {
43 TbfPars pars optional,
Harald Welte4b6c7722017-08-01 00:07:12 +020044 charstring err optional
45 }
46
Harald Welted4ba7ff2017-07-17 21:00:48 +020047 type record DCCH_release_req {
48 }
49
50 /* PH-DATA.ind / PH-DATA.req */
51 type record LAPDm_ph_data {
52 boolean sacch,
53 GsmSapi sapi,
54 LapdmFrame lapdm
55 }
56
Harald Welteb669ee02018-03-09 12:50:02 +010057 type integer TbfNr (0..7); /* maximum of 8 concurrent TBF per direction */
58 type record TBF_UL_establish_req {
59 TbfNr tbf_nr,
Harald Welte4b6c7722017-08-01 00:07:12 +020060 uint8_t ra
61 }
62
Harald Welteb669ee02018-03-09 12:50:02 +010063 type record TBF_DL_establish_req {
64 TbfNr tbf_nr,
65 TbfPars pars
66 }
67
Harald Welte4b6c7722017-08-01 00:07:12 +020068 /* PH-DATA.ind / PH-DATA.req */
69 type record RLCMAC_ph_data_ind {
70 GprsCodingScheme cs,
Harald Welte7024baa2018-03-02 23:37:51 +010071 uint8_t ts_nr,
72 GsmFrameNumber fn,
Harald Welte4b6c7722017-08-01 00:07:12 +020073 RlcmacDlBlock block
74 }
Harald Welte7024baa2018-03-02 23:37:51 +010075 type record RLCMAC_ph_data_req_dyn {
Harald Welte4b6c7722017-08-01 00:07:12 +020076 uint8_t tbf_id,
77 GprsCodingScheme cs,
78 RlcmacUlBlock block
79 }
Harald Welte7024baa2018-03-02 23:37:51 +010080 type record RLCMAC_ph_data_req_abs {
81 uint8_t tbf_id,
82 GprsCodingScheme cs,
83 uint8_t ts_nr,
84 GsmFrameNumber fn,
85 Arfcn arfcn,
86 RlcmacUlBlock block
87 }
88 type union RLCMAC_ph_data_req {
89 RLCMAC_ph_data_req_dyn dyn,
90 RLCMAC_ph_data_req_abs abs
91 }
Harald Welte4b6c7722017-08-01 00:07:12 +020092
Harald Welted4ba7ff2017-07-17 21:00:48 +020093 /* port from our (internal) point of view */
94 type port LAPDm_SP_PT message {
95 in BCCH_tune_req,
96 DCCH_establish_req,
97 DCCH_release_req,
Harald Welteb669ee02018-03-09 12:50:02 +010098 TBF_UL_establish_req,
99 TBF_DL_establish_req,
Harald Welte4b6c7722017-08-01 00:07:12 +0200100 RLCMAC_ph_data_req,
Harald Welted4ba7ff2017-07-17 21:00:48 +0200101 LAPDm_ph_data;
102 out DCCH_establish_res,
Harald Welteb669ee02018-03-09 12:50:02 +0100103 TBF_UL_establish_res,
Harald Welte4b6c7722017-08-01 00:07:12 +0200104 RLCMAC_ph_data_ind,
Harald Welted4ba7ff2017-07-17 21:00:48 +0200105 LAPDm_ph_data;
106 } with {extension "internal"};
107
108 /* port from user (external) point of view */
109 type port LAPDm_PT message {
110 in DCCH_establish_res,
Harald Welteb669ee02018-03-09 12:50:02 +0100111 TBF_UL_establish_res,
Harald Welte4b6c7722017-08-01 00:07:12 +0200112 RLCMAC_ph_data_ind,
Harald Welted4ba7ff2017-07-17 21:00:48 +0200113 LAPDm_ph_data;
114 out BCCH_tune_req,
115 DCCH_establish_req,
116 DCCH_release_req,
Harald Welteb669ee02018-03-09 12:50:02 +0100117 TBF_UL_establish_req,
118 TBF_DL_establish_req,
Harald Welte4b6c7722017-08-01 00:07:12 +0200119 RLCMAC_ph_data_req,
Harald Welted4ba7ff2017-07-17 21:00:48 +0200120 LAPDm_ph_data;
121 } with {extension "internal"};
122
123 function LAPDmStart() runs on lapdm_CT {
124 f_init();
125 ScanEvents();
126 }
127
128 /* TS 44.004 Figure 5.1 */
129 type enumerated ph_state_enum {
130 PH_STATE_NULL,
131 PH_STATE_BCH,
132 PH_STATE_SEARCHING_BCH,
133 PH_STATE_TUNING_DCH,
Harald Welte4b6c7722017-08-01 00:07:12 +0200134 PH_STATE_DCH,
135 PH_STATE_TBF
Harald Welted4ba7ff2017-07-17 21:00:48 +0200136 }
137
138 type component lapdm_CT {
Harald Welted4ba7ff2017-07-17 21:00:48 +0200139
140 /* L1CTL port towards the bottom */
141 port L1CTL_PT L1CTL;
142 /* Port towards L2 */
143 port LAPDm_SP_PT LAPDM_SP;
144
145 /* physical layer state */
146 var ph_state_enum ph_state := PH_STATE_NULL;
147
148 /* channel description of the currently active DCH */
149 var ChannelDescription chan_desc;
Harald Welteb669ee02018-03-09 12:50:02 +0100150
151 var TbfParsPerTs g_tbf_ul;
152 var TbfParsPerTs g_tbf_dl;
Harald Welted4ba7ff2017-07-17 21:00:48 +0200153 };
154
155 /* wrapper function to log state transitions */
156 private function set_ph_state(ph_state_enum new_state) runs on lapdm_CT {
157 log("PH-STATE ", ph_state, " -> ", new_state);
158 ph_state := new_state;
159 }
160
161 private function f_init() runs on lapdm_CT {
Harald Welteb26cfff2017-08-25 09:56:47 +0200162 f_connect_reset(L1CTL);
Harald Welted4ba7ff2017-07-17 21:00:48 +0200163 set_ph_state(PH_STATE_NULL);
164 }
165
166 /* release the dedicated radio channel */
167 private function f_release_dcch() runs on lapdm_CT {
Harald Weltef8df4cb2018-03-10 15:15:08 +0100168 L1CTL.send(ts_L1CTL_DM_REL_REQ(chan_desc.chan_nr));
Harald Welte4b6c7722017-08-01 00:07:12 +0200169 set_ph_state(PH_STATE_BCH);
Harald Welted4ba7ff2017-07-17 21:00:48 +0200170 }
171
172 /* tune to given ARFCN and start BCCH/CCCH decoding */
173 private function f_tune_bcch(Arfcn arfcn, boolean combined) runs on lapdm_CT {
174 var L1ctlCcchMode mode := CCCH_MODE_NON_COMBINED;
175 if (combined) {
176 mode := CCCH_MODE_COMBINED;
177 }
178
179 if (ph_state == PH_STATE_DCH) {
180 /* release any previous DCH */
181 f_release_dcch();
Harald Welte4b6c7722017-08-01 00:07:12 +0200182 } else if (ph_state == PH_STATE_TBF) {
183 f_release_tbf();
Harald Welted4ba7ff2017-07-17 21:00:48 +0200184 }
185
186 set_ph_state(PH_STATE_SEARCHING_BCH);
187
188 /* send FB/SB req to sync to cell */
189 f_L1CTL_FBSB(L1CTL, arfcn, mode);
190 set_ph_state(PH_STATE_BCH);
191 }
192
193 /* master function establishing a dedicated radio channel */
194 private function f_establish_dcch(uint8_t ra) runs on lapdm_CT {
195 var ImmediateAssignment imm_ass;
196 var GsmFrameNumber rach_fn;
197
198 /* send RACH request and obtain FN at which it was sent */
199 rach_fn := f_L1CTL_RACH(L1CTL, ra);
200 //if (not rach_fn) { return; }
201
202 /* wait for receiving matching IMM ASS */
203 imm_ass := f_L1CTL_WAIT_IMM_ASS(L1CTL, ra, rach_fn)
204 //if (not imm_ass) { return; }
205 set_ph_state(PH_STATE_TUNING_DCH);
206
207 /* store/save channel description */
208 chan_desc := imm_ass.chan_desc;
209
210 /* send DM_EST_REQ */
211 f_L1CTL_DM_EST_REQ_IA(L1CTL, imm_ass);
212 set_ph_state(PH_STATE_DCH);
213 }
214
Harald Welte4b6c7722017-08-01 00:07:12 +0200215 /* initialize a tfi_usf array with "not used" value 255 for all TN */
216 function f_TfiUsfArrInit() return TfiUsfArr {
217 var TfiUsfArr tua := { 255, 255, 255, 255, 255, 255, 255, 255 };
218 return tua;
219 }
220
221 /* set TFI/USF value for one given timeslot number (index) */
222 function f_TfiUsfArrSet(inout TfiUsfArr a, in uint8_t idx, in uint8_t tfi_usf) {
223 a[idx] := tfi_usf;
224 }
225
226 /* Match an IMM.ASS for an Uplink TBF with a dynamic allocation */
227 template ImmediateAssignment t_IMM_ASS_TBF_UL_DYN(uint8_t ra, GsmFrameNumber fn) modifies t_IMM_ASS := {
228 ded_or_tbf := { spare := ?, tma := ?, downlink := false, tbf := true},
229 chan_desc := omit,
230 pkt_chan_desc := ?,
231 rest_octets := {
232 presence := '11'B,
233 ll := omit,
234 lh := omit,
235 hl := omit,
236 hh := {
237 presence := '00'B,
238 ul := {
239 presence := '1'B,
240 dynamic := {
241 tfi_assignment := ?,
242 polling := ?,
243 spare := '0'B,
244 usf := ?,
245 usf_granularity := ?,
246 p0_present := ?,
247 p0 := *,
248 pr_mode := *,
249 ch_coding_cmd := ?,
250 tlli_block_chan_coding:= ?,
251 alpha_present := ?,
252 alpha := *,
253 gamma := ?,
254 ta_index_present := ?,
255 ta_index := *,
256 tbf_starting_time_present := ?,
257 tbf_starting_time := *
258 },
259 single := omit
260 },
261 dl := omit
262 }
263 }
264 };
265
Harald Welte7024baa2018-03-02 23:37:51 +0100266 template (value) RLCMAC_ph_data_req ts_PH_DATA_ABS(uint8_t tbf_id, GprsCodingScheme cs,
267 uint8_t ts, uint32_t fn, Arfcn arfcn,
268 RlcmacUlBlock block) := {
269 abs := {
270 tbf_id := tbf_id,
271 cs := CS1, /* FIXME */
272 ts_nr := ts,
273 fn := fn,
274 arfcn := arfcn,
275 block := block
276 }
277 }
278
Harald Welte4b6c7722017-08-01 00:07:12 +0200279 private function f_establish_tbf(uint8_t ra) runs on lapdm_CT {
280 var ImmediateAssignment imm_ass;
281 var GsmFrameNumber rach_fn;
282 var TfiUsfArr tua := f_TfiUsfArrInit();
283
284 /* send RACH request and obtain FN at which it was sent */
285 rach_fn := f_L1CTL_RACH(L1CTL, ra);
286
287 /* wait for receiving matching IMM ASS */
288 imm_ass := f_L1CTL_WAIT_IMM_ASS(L1CTL, ra, rach_fn);
289
290 if (match(imm_ass, t_IMM_ASS_TBF_UL_DYN(ra, rach_fn))) {
291 set_ph_state(PH_STATE_TBF);
292
293 /* store/save channel description */
294 //chan_desc := imm_ass.chan_desc;
295
296 /* Important: ARFCN, TN, TSC, USF, USF_GRANULARITY, CH_CODING_CMD */
297 f_TfiUsfArrSet(tua, imm_ass.pkt_chan_desc.tn, imm_ass.rest_octets.hh.ul.dynamic.usf);
298 f_L1CTL_TBF_CFG(L1CTL, true, tua);
299 } else {
300 /* FIXME: single block uplink allocation */
301 log("Failed to match ", t_IMM_ASS_TBF_UL_DYN(ra, rach_fn));
302 log("Non-dynamic UL TBF assignment not supported yet");
303 }
304 }
305
306 private function f_release_tbf() runs on lapdm_CT {
307 var TfiUsfArr tua := f_TfiUsfArrInit();
308 /* send "all timeslots unused" for both UL and DL */
309 f_L1CTL_TBF_CFG(L1CTL, true, tua);
310 f_L1CTL_TBF_CFG(L1CTL, false, tua);
311 /* L1 will then fall back to BCCH/CCCH */
312 set_ph_state(PH_STATE_BCH);
313 }
314
Harald Welteb669ee02018-03-09 12:50:02 +0100315 /* Establish TBF / packet transfer mode */
316 private altstep as_tbf_ul_est() runs on lapdm_CT {
317 var TBF_UL_establish_req tbf_ul_req;
318 [] LAPDM_SP.receive(TBF_UL_establish_req:?) -> value tbf_ul_req {
319 var TbfNr tbf_nr := tbf_ul_req.tbf_nr;
320 var TBF_UL_establish_res res;
321 if (isvalue(g_tbf_ul[tbf_nr].arfcn)) {
322 setverdict(fail, "Cannot establish UL TBF ID ", tbf_nr, ": BUSY");
323 self.stop;
324 }
325 f_establish_tbf(tbf_ul_req.ra);
326 if (ph_state == PH_STATE_TBF) {
327 g_tbf_ul[tbf_nr] := valueof(t_TbfParsInit); /* FIXME: Actual TFI[s] */
328 log("Established UL TBF ", tbf_nr);
329 res := { pars := g_tbf_ul[tbf_nr], err := omit };
330 } else {
331 res := { pars := omit, err := "Unable to establish UL TBF" };
332 }
333 LAPDM_SP.send(res);
334 }
335 }
336
337 private altstep as_tbf_dl_est() runs on lapdm_CT {
338 var TBF_DL_establish_req tbf_dl_req;
339 [] LAPDM_SP.receive(TBF_DL_establish_req:?) -> value tbf_dl_req {
340 var TbfNr tbf_nr := tbf_dl_req.tbf_nr;
341 if (isvalue(g_tbf_dl[tbf_nr].arfcn)) {
342 setverdict(fail, "Cannot establish DL TBF ID ", tbf_nr, ": BUSY");
343 self.stop;
344 }
345 g_tbf_dl[tbf_nr] := tbf_dl_req.pars;
346 f_L1CTL_TBF_CFG(L1CTL, false, tbf_dl_req.pars.tfi);
347 set_ph_state(PH_STATE_TBF);
348 log("Established DL TBF ", tbf_nr, ": ", tbf_dl_req.pars);
349 }
350 }
351
352 private function f_init_tbf() runs on lapdm_CT {
353 var integer i;
354 for (i := 0; i < 8; i := i+1) {
355 g_tbf_ul[i] := valueof(t_TbfParsInit);
356 g_tbf_dl[i] := valueof(t_TbfParsInit);
357 }
358 }
359
Harald Welted4ba7ff2017-07-17 21:00:48 +0200360 function ScanEvents() runs on lapdm_CT {
361 var L1ctlDlMessage dl;
362 var BCCH_tune_req bt;
363 var LAPDm_ph_data lpd;
Harald Welte4b6c7722017-08-01 00:07:12 +0200364 var RLCMAC_ph_data_ind rpdi;
365 var RLCMAC_ph_data_req rpdr;
Harald Welted4ba7ff2017-07-17 21:00:48 +0200366 var DCCH_establish_req est_req;
367 var DCCH_establish_res est_res;
Harald Welteb669ee02018-03-09 12:50:02 +0100368
369 f_init_tbf();
Harald Welted4ba7ff2017-07-17 21:00:48 +0200370
371 while (true) {
372 if (ph_state == PH_STATE_NULL) {
373 alt {
374 [] LAPDM_SP.receive(BCCH_tune_req:?) -> value bt {
375 f_tune_bcch(bt.arfcn, bt.combined_ccch);
376 }
377
378 [] LAPDM_SP.receive {}
379 [] L1CTL.receive {}
380
381 }
382 } else if (ph_state == PH_STATE_BCH or ph_state == PH_STATE_SEARCHING_BCH) {
383 alt {
384 [] LAPDM_SP.receive(BCCH_tune_req:?) -> value bt {
385 f_tune_bcch(bt.arfcn, bt.combined_ccch);
386 }
387
388 /* forward CCCH SAPI from L1CTL to User */
Harald Weltef8df4cb2018-03-10 15:15:08 +0100389 [] L1CTL.receive(tr_L1CTL_DATA_IND(t_RslChanNr_BCCH(0))) -> value dl {
Harald Welted4ba7ff2017-07-17 21:00:48 +0200390 lpd.sacch := false;
391 lpd.sapi := 0;
392 lpd.lapdm.bbis := dec_LapdmFrameBbis(dl.payload.data_ind.payload);
393 LAPDM_SP.send(lpd);
394 }
395
396 /* forward BCCH SAPI from L1CTL to User */
Harald Weltef8df4cb2018-03-10 15:15:08 +0100397 [] L1CTL.receive(tr_L1CTL_DATA_IND(t_RslChanNr_PCH_AGCH(0))) -> value dl {
Harald Welted4ba7ff2017-07-17 21:00:48 +0200398 lpd.sacch := false;
399 lpd.sapi := 0;
400 lpd.lapdm.bbis := dec_LapdmFrameBbis(dl.payload.data_ind.payload);
401 LAPDM_SP.send(lpd);
402 }
403
404 /* Establish dedicated channel */
405 [] LAPDM_SP.receive(DCCH_establish_req:?) -> value est_req {
406 var DCCH_establish_res res;
407 f_establish_dcch(est_req.ra);
408 if (ph_state == PH_STATE_DCH) {
409 res := { chan_desc, omit };
410 } else {
411 res := { omit, "Unable to esetablish DCCH" };
412 }
413 LAPDM_SP.send(res);
414 }
415
Harald Welteb669ee02018-03-09 12:50:02 +0100416 [] as_tbf_ul_est();
417 [] as_tbf_dl_est();
Harald Welte4b6c7722017-08-01 00:07:12 +0200418
Harald Welted4ba7ff2017-07-17 21:00:48 +0200419 [] LAPDM_SP.receive {}
420 [] L1CTL.receive {}
421
422 }
423
424 } else if (ph_state == PH_STATE_TUNING_DCH or ph_state == PH_STATE_DCH) {
425 alt {
426
427 /* decode any received DATA frames for the dedicated channel and pass them up */
Harald Weltef8df4cb2018-03-10 15:15:08 +0100428 [] L1CTL.receive(tr_L1CTL_DATA_IND(chan_desc.chan_nr)) -> value dl {
Harald Welted4ba7ff2017-07-17 21:00:48 +0200429 if (dl.dl_info.link_id.c == SACCH) {
430 lpd.sacch := true;
431 /* FIXME: how to deal with UI frames in B4 format (lo length!) */
432 } else {
433 lpd.sacch := false;
434 }
435 lpd.sapi := dl.dl_info.link_id.sapi;
436 lpd.lapdm.b := dec_LapdmFrameB(dl.payload.data_ind.payload);
437 LAPDM_SP.send(lpd);
438 }
439
440 /* encode any LAPDm record from user and pass it on to L1CTL */
441 [] LAPDM_SP.receive(LAPDm_ph_data:?) -> value lpd {
442 var octetstring buf;
443 var RslLinkId link_id;
444 if (lpd.sacch) {
445 link_id := valueof(ts_RslLinkID_SACCH(lpd.sapi));
446 } else {
447 link_id := valueof(ts_RslLinkID_DCCH(lpd.sapi));
448 }
449 buf := enc_LapdmFrame(lpd.lapdm);
Harald Weltef8df4cb2018-03-10 15:15:08 +0100450 L1CTL.send(ts_L1CTL_DATA_REQ(chan_desc.chan_nr, link_id, buf));
Harald Welted4ba7ff2017-07-17 21:00:48 +0200451 }
452
453 /* Release dedicated channel */
454 [] LAPDM_SP.receive(DCCH_release_req:?) {
455 /* go back to BCCH */
456 f_release_dcch();
457 }
458
459 [] LAPDM_SP.receive {}
460 [] L1CTL.receive {}
461
462
463 }
Harald Welte4b6c7722017-08-01 00:07:12 +0200464 } else if (ph_state == PH_STATE_TBF) {
465 alt {
466
467 /* decode + forward any blocks from L1 to L23*/
Harald Weltef8df4cb2018-03-10 15:15:08 +0100468 [] L1CTL.receive(tr_L1CTL_DATA_IND(t_RslChanNr_PDCH(?))) -> value dl {
Harald Welte4b6c7722017-08-01 00:07:12 +0200469 rpdi.block := dec_RlcmacDlBlock(dl.payload.data_ind.payload);
Harald Welteb669ee02018-03-09 12:50:02 +0100470 /* FIXME: Filter based on g_tbf_dl */
Harald Welte7024baa2018-03-02 23:37:51 +0100471 rpdi.fn := dl.dl_info.frame_nr;
472 rpdi.ts_nr := dl.dl_info.chan_nr.tn;
Harald Welte4b6c7722017-08-01 00:07:12 +0200473 rpdi.cs := CS1; /* FIXME */
474 log("RPDI: ", rpdi);
475 LAPDM_SP.send(rpdi);
476 }
477
478 [] L1CTL.receive { }
479
480 /* encode + forward any blocks from L23 to L1 */
481 [] LAPDM_SP.receive(RLCMAC_ph_data_req:?) -> value rpdr {
482 var octetstring buf;
Harald Welte7024baa2018-03-02 23:37:51 +0100483 if (ischosen(rpdr.dyn)) {
484 buf := enc_RlcmacUlBlock(rpdr.dyn.block);
Harald Weltef8df4cb2018-03-10 15:15:08 +0100485 L1CTL.send(ts_L1CTL_DATA_TBF_REQ(buf, L1CTL_CS1, rpdr.dyn.tbf_id));
Harald Welte7024baa2018-03-02 23:37:51 +0100486 } else {
487 buf := enc_RlcmacUlBlock(rpdr.abs.block);
Harald Weltef8df4cb2018-03-10 15:15:08 +0100488 L1CTL.send(ts_L1CTL_DATA_ABS_REQ(buf, rpdr.abs.arfcn,
Harald Welte7024baa2018-03-02 23:37:51 +0100489 rpdr.abs.ts_nr, rpdr.abs.fn,
490 L1CTL_CS1, rpdr.abs.tbf_id));
491 }
Harald Welte4b6c7722017-08-01 00:07:12 +0200492 }
493
Harald Welteb669ee02018-03-09 12:50:02 +0100494 [] as_tbf_ul_est();
495 [] as_tbf_dl_est();
496
Harald Welte4b6c7722017-08-01 00:07:12 +0200497 /* FIXME: release TBF mode */
498 [] LAPDM_SP.receive(DCCH_release_req:?) {
499 /* go back to BCCH */
500 f_release_tbf();
Harald Welteb669ee02018-03-09 12:50:02 +0100501 f_init_tbf();
Harald Welte4b6c7722017-08-01 00:07:12 +0200502 }
503
504 }
Harald Welted4ba7ff2017-07-17 21:00:48 +0200505 }
Harald Welte4b6c7722017-08-01 00:07:12 +0200506
Harald Welted4ba7ff2017-07-17 21:00:48 +0200507 } /* while (1) */
508 }
509}