Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* $Id: isdnl3.c,v 2.22.2.3 2004/01/13 14:31:25 keil Exp $ |
2 | * | |
3 | * Author Karsten Keil | |
4 | * based on the teles driver from Jan den Ouden | |
5 | * Copyright by Karsten Keil <keil@isdn4linux.de> | |
475be4d8 | 6 | * |
1da177e4 LT |
7 | * This software may be used and distributed according to the terms |
8 | * of the GNU General Public License, incorporated herein by reference. | |
9 | * | |
10 | * For changes and modifications please read | |
11 | * Documentation/isdn/HiSax.cert | |
12 | * | |
13 | * Thanks to Jan den Ouden | |
14 | * Fritz Elfert | |
15 | * | |
16 | */ | |
17 | ||
18 | #include <linux/init.h> | |
5a0e3ad6 | 19 | #include <linux/slab.h> |
1da177e4 LT |
20 | #include "hisax.h" |
21 | #include "isdnl3.h" | |
1da177e4 LT |
22 | |
23 | const char *l3_revision = "$Revision: 2.22.2.3 $"; | |
24 | ||
25 | static struct Fsm l3fsm; | |
26 | ||
27 | enum { | |
28 | ST_L3_LC_REL, | |
29 | ST_L3_LC_ESTAB_WAIT, | |
475be4d8 | 30 | ST_L3_LC_REL_DELAY, |
1da177e4 LT |
31 | ST_L3_LC_REL_WAIT, |
32 | ST_L3_LC_ESTAB, | |
33 | }; | |
34 | ||
475be4d8 | 35 | #define L3_STATE_COUNT (ST_L3_LC_ESTAB + 1) |
1da177e4 LT |
36 | |
37 | static char *strL3State[] = | |
38 | { | |
39 | "ST_L3_LC_REL", | |
40 | "ST_L3_LC_ESTAB_WAIT", | |
41 | "ST_L3_LC_REL_DELAY", | |
42 | "ST_L3_LC_REL_WAIT", | |
43 | "ST_L3_LC_ESTAB", | |
44 | }; | |
45 | ||
46 | enum { | |
47 | EV_ESTABLISH_REQ, | |
48 | EV_ESTABLISH_IND, | |
49 | EV_ESTABLISH_CNF, | |
50 | EV_RELEASE_REQ, | |
51 | EV_RELEASE_CNF, | |
52 | EV_RELEASE_IND, | |
53 | EV_TIMEOUT, | |
54 | }; | |
55 | ||
475be4d8 | 56 | #define L3_EVENT_COUNT (EV_TIMEOUT + 1) |
1da177e4 LT |
57 | |
58 | static char *strL3Event[] = | |
59 | { | |
60 | "EV_ESTABLISH_REQ", | |
61 | "EV_ESTABLISH_IND", | |
62 | "EV_ESTABLISH_CNF", | |
63 | "EV_RELEASE_REQ", | |
64 | "EV_RELEASE_CNF", | |
65 | "EV_RELEASE_IND", | |
66 | "EV_TIMEOUT", | |
67 | }; | |
68 | ||
b9075fa9 | 69 | static __printf(2, 3) void |
475be4d8 | 70 | l3m_debug(struct FsmInst *fi, char *fmt, ...) |
1da177e4 LT |
71 | { |
72 | va_list args; | |
73 | struct PStack *st = fi->userdata; | |
74 | ||
75 | va_start(args, fmt); | |
76 | VHiSax_putstatus(st->l1.hardware, st->l3.debug_id, fmt, args); | |
77 | va_end(args); | |
78 | } | |
79 | ||
80 | u_char * | |
475be4d8 | 81 | findie(u_char *p, int size, u_char ie, int wanted_set) |
1da177e4 LT |
82 | { |
83 | int l, codeset, maincodeset; | |
84 | u_char *pend = p + size; | |
85 | ||
86 | /* skip protocol discriminator, callref and message type */ | |
87 | p++; | |
88 | l = (*p++) & 0xf; | |
89 | p += l; | |
90 | p++; | |
91 | codeset = 0; | |
92 | maincodeset = 0; | |
93 | /* while there are bytes left... */ | |
94 | while (p < pend) { | |
95 | if ((*p & 0xf0) == 0x90) { | |
96 | codeset = *p & 0x07; | |
97 | if (!(*p & 0x08)) | |
98 | maincodeset = codeset; | |
99 | } | |
100 | if (*p & 0x80) | |
101 | p++; | |
102 | else { | |
103 | if (codeset == wanted_set) { | |
104 | if (*p == ie) | |
475be4d8 JP |
105 | { /* improved length check (Werner Cornelius) */ |
106 | if ((pend - p) < 2) | |
107 | return (NULL); | |
108 | if (*(p + 1) > (pend - (p + 2))) | |
109 | return (NULL); | |
110 | return (p); | |
111 | } | |
112 | ||
1da177e4 LT |
113 | if (*p > ie) |
114 | return (NULL); | |
115 | } | |
116 | p++; | |
117 | l = *p++; | |
118 | p += l; | |
119 | codeset = maincodeset; | |
120 | } | |
121 | } | |
122 | return (NULL); | |
123 | } | |
124 | ||
125 | int | |
475be4d8 | 126 | getcallref(u_char *p) |
1da177e4 LT |
127 | { |
128 | int l, cr = 0; | |
129 | ||
130 | p++; /* prot discr */ | |
131 | if (*p & 0xfe) /* wrong callref BRI only 1 octet*/ | |
475be4d8 | 132 | return (-2); |
1da177e4 LT |
133 | l = 0xf & *p++; /* callref length */ |
134 | if (!l) /* dummy CallRef */ | |
475be4d8 | 135 | return (-1); |
1da177e4 LT |
136 | cr = *p++; |
137 | return (cr); | |
138 | } | |
139 | ||
140 | static int OrigCallRef = 0; | |
141 | ||
142 | int | |
143 | newcallref(void) | |
144 | { | |
145 | if (OrigCallRef == 127) | |
146 | OrigCallRef = 1; | |
147 | else | |
148 | OrigCallRef++; | |
149 | return (OrigCallRef); | |
150 | } | |
151 | ||
152 | void | |
153 | newl3state(struct l3_process *pc, int state) | |
154 | { | |
155 | if (pc->debug & L3_DEB_STATE) | |
eeb4e6d1 | 156 | l3_debug(pc->st, "%s cr %d %d --> %d", __func__, |
1da177e4 LT |
157 | pc->callref & 0x7F, |
158 | pc->state, state); | |
159 | pc->state = state; | |
160 | } | |
161 | ||
162 | static void | |
163 | L3ExpireTimer(struct L3Timer *t) | |
164 | { | |
165 | t->pc->st->lli.l4l3(t->pc->st, t->event, t->pc); | |
166 | } | |
167 | ||
168 | void | |
169 | L3InitTimer(struct l3_process *pc, struct L3Timer *t) | |
170 | { | |
171 | t->pc = pc; | |
aff55a36 | 172 | setup_timer(&t->tl, (void *)L3ExpireTimer, (long)t); |
1da177e4 LT |
173 | } |
174 | ||
175 | void | |
176 | L3DelTimer(struct L3Timer *t) | |
177 | { | |
178 | del_timer(&t->tl); | |
179 | } | |
180 | ||
181 | int | |
182 | L3AddTimer(struct L3Timer *t, | |
183 | int millisec, int event) | |
184 | { | |
185 | if (timer_pending(&t->tl)) { | |
186 | printk(KERN_WARNING "L3AddTimer: timer already active!\n"); | |
187 | return -1; | |
188 | } | |
189 | init_timer(&t->tl); | |
190 | t->event = event; | |
191 | t->tl.expires = jiffies + (millisec * HZ) / 1000; | |
192 | add_timer(&t->tl); | |
193 | return 0; | |
194 | } | |
195 | ||
196 | void | |
197 | StopAllL3Timer(struct l3_process *pc) | |
198 | { | |
199 | L3DelTimer(&pc->timer); | |
200 | } | |
201 | ||
202 | struct sk_buff * | |
203 | l3_alloc_skb(int len) | |
204 | { | |
205 | struct sk_buff *skb; | |
206 | ||
207 | if (!(skb = alloc_skb(len + MAX_HEADER_LEN, GFP_ATOMIC))) { | |
208 | printk(KERN_WARNING "HiSax: No skb for D-channel\n"); | |
209 | return (NULL); | |
210 | } | |
211 | skb_reserve(skb, MAX_HEADER_LEN); | |
212 | return (skb); | |
213 | } | |
214 | ||
215 | static void | |
216 | no_l3_proto(struct PStack *st, int pr, void *arg) | |
217 | { | |
218 | struct sk_buff *skb = arg; | |
219 | ||
220 | HiSax_putstatus(st->l1.hardware, "L3", "no D protocol"); | |
221 | if (skb) { | |
222 | dev_kfree_skb(skb); | |
223 | } | |
224 | } | |
225 | ||
226 | static int | |
227 | no_l3_proto_spec(struct PStack *st, isdn_ctrl *ic) | |
228 | { | |
475be4d8 JP |
229 | printk(KERN_WARNING "HiSax: no specific protocol handler for proto %lu\n", ic->arg & 0xFF); |
230 | return (-1); | |
1da177e4 LT |
231 | } |
232 | ||
1da177e4 LT |
233 | struct l3_process |
234 | *getl3proc(struct PStack *st, int cr) | |
235 | { | |
236 | struct l3_process *p = st->l3.proc; | |
237 | ||
238 | while (p) | |
239 | if (p->callref == cr) | |
240 | return (p); | |
241 | else | |
242 | p = p->next; | |
243 | return (NULL); | |
244 | } | |
245 | ||
246 | struct l3_process | |
247 | *new_l3_process(struct PStack *st, int cr) | |
248 | { | |
249 | struct l3_process *p, *np; | |
250 | ||
251 | if (!(p = kmalloc(sizeof(struct l3_process), GFP_ATOMIC))) { | |
252 | printk(KERN_ERR "HiSax can't get memory for cr %d\n", cr); | |
253 | return (NULL); | |
254 | } | |
255 | if (!st->l3.proc) | |
256 | st->l3.proc = p; | |
257 | else { | |
258 | np = st->l3.proc; | |
259 | while (np->next) | |
260 | np = np->next; | |
261 | np->next = p; | |
262 | } | |
263 | p->next = NULL; | |
264 | p->debug = st->l3.debug; | |
265 | p->callref = cr; | |
266 | p->state = 0; | |
267 | p->chan = NULL; | |
268 | p->st = st; | |
269 | p->N303 = st->l3.N303; | |
270 | L3InitTimer(p, &p->timer); | |
271 | return (p); | |
272 | }; | |
273 | ||
274 | void | |
275 | release_l3_process(struct l3_process *p) | |
276 | { | |
277 | struct l3_process *np, *pp = NULL; | |
278 | ||
279 | if (!p) | |
280 | return; | |
281 | np = p->st->l3.proc; | |
282 | while (np) { | |
283 | if (np == p) { | |
284 | StopAllL3Timer(p); | |
285 | if (pp) | |
286 | pp->next = np->next; | |
287 | else if (!(p->st->l3.proc = np->next) && | |
475be4d8 | 288 | !test_bit(FLG_PTP, &p->st->l2.flag)) { |
1da177e4 LT |
289 | if (p->debug) |
290 | l3_debug(p->st, "release_l3_process: last process"); | |
b03efcfb | 291 | if (skb_queue_empty(&p->st->l3.squeue)) { |
1da177e4 LT |
292 | if (p->debug) |
293 | l3_debug(p->st, "release_l3_process: release link"); | |
294 | if (p->st->protocol != ISDN_PTYPE_NI1) | |
295 | FsmEvent(&p->st->l3.l3m, EV_RELEASE_REQ, NULL); | |
296 | else | |
297 | FsmEvent(&p->st->l3.l3m, EV_RELEASE_IND, NULL); | |
298 | } else { | |
299 | if (p->debug) | |
300 | l3_debug(p->st, "release_l3_process: not release link"); | |
301 | } | |
475be4d8 | 302 | } |
1da177e4 LT |
303 | kfree(p); |
304 | return; | |
305 | } | |
306 | pp = np; | |
307 | np = np->next; | |
308 | } | |
309 | printk(KERN_ERR "HiSax internal L3 error CR(%d) not in list\n", p->callref); | |
310 | l3_debug(p->st, "HiSax internal L3 error CR(%d) not in list", p->callref); | |
311 | }; | |
312 | ||
313 | static void | |
314 | l3ml3p(struct PStack *st, int pr) | |
315 | { | |
316 | struct l3_process *p = st->l3.proc; | |
317 | struct l3_process *np; | |
318 | ||
319 | while (p) { | |
320 | /* p might be kfreed under us, so we need to save where we want to go on */ | |
321 | np = p->next; | |
322 | st->l3.l3ml3(st, pr, p); | |
323 | p = np; | |
324 | } | |
325 | } | |
326 | ||
327 | void | |
328 | setstack_l3dc(struct PStack *st, struct Channel *chanp) | |
329 | { | |
330 | char tmp[64]; | |
331 | ||
332 | st->l3.proc = NULL; | |
333 | st->l3.global = NULL; | |
334 | skb_queue_head_init(&st->l3.squeue); | |
335 | st->l3.l3m.fsm = &l3fsm; | |
336 | st->l3.l3m.state = ST_L3_LC_REL; | |
337 | st->l3.l3m.debug = 1; | |
338 | st->l3.l3m.userdata = st; | |
339 | st->l3.l3m.userint = 0; | |
340 | st->l3.l3m.printdebug = l3m_debug; | |
475be4d8 | 341 | FsmInitTimer(&st->l3.l3m, &st->l3.l3m_timer); |
1da177e4 LT |
342 | strcpy(st->l3.debug_id, "L3DC "); |
343 | st->lli.l4l3_proto = no_l3_proto_spec; | |
344 | ||
475be4d8 | 345 | #ifdef CONFIG_HISAX_EURO |
1da177e4 LT |
346 | if (st->protocol == ISDN_PTYPE_EURO) { |
347 | setstack_dss1(st); | |
348 | } else | |
349 | #endif | |
475be4d8 JP |
350 | #ifdef CONFIG_HISAX_NI1 |
351 | if (st->protocol == ISDN_PTYPE_NI1) { | |
352 | setstack_ni1(st); | |
353 | } else | |
1da177e4 | 354 | #endif |
475be4d8 JP |
355 | #ifdef CONFIG_HISAX_1TR6 |
356 | if (st->protocol == ISDN_PTYPE_1TR6) { | |
357 | setstack_1tr6(st); | |
358 | } else | |
1da177e4 | 359 | #endif |
475be4d8 JP |
360 | if (st->protocol == ISDN_PTYPE_LEASED) { |
361 | st->lli.l4l3 = no_l3_proto; | |
362 | st->l2.l2l3 = no_l3_proto; | |
363 | st->l3.l3ml3 = no_l3_proto; | |
364 | printk(KERN_INFO "HiSax: Leased line mode\n"); | |
365 | } else { | |
366 | st->lli.l4l3 = no_l3_proto; | |
367 | st->l2.l2l3 = no_l3_proto; | |
368 | st->l3.l3ml3 = no_l3_proto; | |
369 | sprintf(tmp, "protocol %s not supported", | |
370 | (st->protocol == ISDN_PTYPE_1TR6) ? "1tr6" : | |
371 | (st->protocol == ISDN_PTYPE_EURO) ? "euro" : | |
372 | (st->protocol == ISDN_PTYPE_NI1) ? "ni1" : | |
373 | "unknown"); | |
374 | printk(KERN_WARNING "HiSax: %s\n", tmp); | |
375 | st->protocol = -1; | |
376 | } | |
1da177e4 LT |
377 | } |
378 | ||
672c3fd9 | 379 | static void |
1da177e4 LT |
380 | isdnl3_trans(struct PStack *st, int pr, void *arg) { |
381 | st->l3.l3l2(st, pr, arg); | |
382 | } | |
383 | ||
384 | void | |
385 | releasestack_isdnl3(struct PStack *st) | |
386 | { | |
387 | while (st->l3.proc) | |
388 | release_l3_process(st->l3.proc); | |
389 | if (st->l3.global) { | |
390 | StopAllL3Timer(st->l3.global); | |
391 | kfree(st->l3.global); | |
392 | st->l3.global = NULL; | |
393 | } | |
394 | FsmDelTimer(&st->l3.l3m_timer, 54); | |
395 | skb_queue_purge(&st->l3.squeue); | |
396 | } | |
397 | ||
398 | void | |
399 | setstack_l3bc(struct PStack *st, struct Channel *chanp) | |
400 | { | |
401 | ||
402 | st->l3.proc = NULL; | |
403 | st->l3.global = NULL; | |
404 | skb_queue_head_init(&st->l3.squeue); | |
405 | st->l3.l3m.fsm = &l3fsm; | |
406 | st->l3.l3m.state = ST_L3_LC_REL; | |
407 | st->l3.l3m.debug = 1; | |
408 | st->l3.l3m.userdata = st; | |
409 | st->l3.l3m.userint = 0; | |
410 | st->l3.l3m.printdebug = l3m_debug; | |
411 | strcpy(st->l3.debug_id, "L3BC "); | |
412 | st->lli.l4l3 = isdnl3_trans; | |
413 | } | |
414 | ||
415 | #define DREL_TIMER_VALUE 40000 | |
416 | ||
417 | static void | |
418 | lc_activate(struct FsmInst *fi, int event, void *arg) | |
419 | { | |
420 | struct PStack *st = fi->userdata; | |
421 | ||
422 | FsmChangeState(fi, ST_L3_LC_ESTAB_WAIT); | |
423 | st->l3.l3l2(st, DL_ESTABLISH | REQUEST, NULL); | |
424 | } | |
425 | ||
426 | static void | |
427 | lc_connect(struct FsmInst *fi, int event, void *arg) | |
428 | { | |
429 | struct PStack *st = fi->userdata; | |
430 | struct sk_buff *skb = arg; | |
431 | int dequeued = 0; | |
432 | ||
433 | FsmChangeState(fi, ST_L3_LC_ESTAB); | |
434 | while ((skb = skb_dequeue(&st->l3.squeue))) { | |
435 | st->l3.l3l2(st, DL_DATA | REQUEST, skb); | |
436 | dequeued++; | |
437 | } | |
438 | if ((!st->l3.proc) && dequeued) { | |
439 | if (st->l3.debug) | |
440 | l3_debug(st, "lc_connect: release link"); | |
441 | FsmEvent(&st->l3.l3m, EV_RELEASE_REQ, NULL); | |
442 | } else | |
443 | l3ml3p(st, DL_ESTABLISH | INDICATION); | |
444 | } | |
445 | ||
446 | static void | |
447 | lc_connected(struct FsmInst *fi, int event, void *arg) | |
448 | { | |
449 | struct PStack *st = fi->userdata; | |
450 | struct sk_buff *skb = arg; | |
451 | int dequeued = 0; | |
452 | ||
453 | FsmDelTimer(&st->l3.l3m_timer, 51); | |
454 | FsmChangeState(fi, ST_L3_LC_ESTAB); | |
455 | while ((skb = skb_dequeue(&st->l3.squeue))) { | |
456 | st->l3.l3l2(st, DL_DATA | REQUEST, skb); | |
457 | dequeued++; | |
458 | } | |
459 | if ((!st->l3.proc) && dequeued) { | |
460 | if (st->l3.debug) | |
461 | l3_debug(st, "lc_connected: release link"); | |
462 | FsmEvent(&st->l3.l3m, EV_RELEASE_REQ, NULL); | |
463 | } else | |
464 | l3ml3p(st, DL_ESTABLISH | CONFIRM); | |
465 | } | |
466 | ||
467 | static void | |
468 | lc_start_delay(struct FsmInst *fi, int event, void *arg) | |
469 | { | |
475be4d8 | 470 | struct PStack *st = fi->userdata; |
1da177e4 | 471 | |
475be4d8 JP |
472 | FsmChangeState(fi, ST_L3_LC_REL_DELAY); |
473 | FsmAddTimer(&st->l3.l3m_timer, DREL_TIMER_VALUE, EV_TIMEOUT, NULL, 50); | |
1da177e4 LT |
474 | } |
475 | ||
476 | static void | |
477 | lc_start_delay_check(struct FsmInst *fi, int event, void *arg) | |
478 | /* 20/09/00 - GE timer not user for NI-1 as layer 2 should stay up */ | |
479 | { | |
475be4d8 | 480 | struct PStack *st = fi->userdata; |
1da177e4 | 481 | |
475be4d8 JP |
482 | FsmChangeState(fi, ST_L3_LC_REL_DELAY); |
483 | /* 19/09/00 - GE timer not user for NI-1 */ | |
484 | if (st->protocol != ISDN_PTYPE_NI1) | |
485 | FsmAddTimer(&st->l3.l3m_timer, DREL_TIMER_VALUE, EV_TIMEOUT, NULL, 50); | |
1da177e4 LT |
486 | } |
487 | ||
488 | static void | |
489 | lc_release_req(struct FsmInst *fi, int event, void *arg) | |
490 | { | |
491 | struct PStack *st = fi->userdata; | |
492 | ||
493 | if (test_bit(FLG_L2BLOCK, &st->l2.flag)) { | |
494 | if (st->l3.debug) | |
495 | l3_debug(st, "lc_release_req: l2 blocked"); | |
496 | /* restart release timer */ | |
497 | FsmAddTimer(&st->l3.l3m_timer, DREL_TIMER_VALUE, EV_TIMEOUT, NULL, 51); | |
498 | } else { | |
499 | FsmChangeState(fi, ST_L3_LC_REL_WAIT); | |
500 | st->l3.l3l2(st, DL_RELEASE | REQUEST, NULL); | |
501 | } | |
502 | } | |
503 | ||
504 | static void | |
505 | lc_release_ind(struct FsmInst *fi, int event, void *arg) | |
506 | { | |
507 | struct PStack *st = fi->userdata; | |
508 | ||
509 | FsmDelTimer(&st->l3.l3m_timer, 52); | |
510 | FsmChangeState(fi, ST_L3_LC_REL); | |
511 | skb_queue_purge(&st->l3.squeue); | |
512 | l3ml3p(st, DL_RELEASE | INDICATION); | |
513 | } | |
514 | ||
515 | static void | |
516 | lc_release_cnf(struct FsmInst *fi, int event, void *arg) | |
517 | { | |
518 | struct PStack *st = fi->userdata; | |
519 | ||
520 | FsmChangeState(fi, ST_L3_LC_REL); | |
521 | skb_queue_purge(&st->l3.squeue); | |
522 | l3ml3p(st, DL_RELEASE | CONFIRM); | |
523 | } | |
524 | ||
525 | ||
526 | /* *INDENT-OFF* */ | |
527 | static struct FsmNode L3FnList[] __initdata = | |
528 | { | |
529 | {ST_L3_LC_REL, EV_ESTABLISH_REQ, lc_activate}, | |
530 | {ST_L3_LC_REL, EV_ESTABLISH_IND, lc_connect}, | |
531 | {ST_L3_LC_REL, EV_ESTABLISH_CNF, lc_connect}, | |
532 | {ST_L3_LC_ESTAB_WAIT, EV_ESTABLISH_CNF, lc_connected}, | |
533 | {ST_L3_LC_ESTAB_WAIT, EV_RELEASE_REQ, lc_start_delay}, | |
534 | {ST_L3_LC_ESTAB_WAIT, EV_RELEASE_IND, lc_release_ind}, | |
535 | {ST_L3_LC_ESTAB, EV_RELEASE_IND, lc_release_ind}, | |
536 | {ST_L3_LC_ESTAB, EV_RELEASE_REQ, lc_start_delay_check}, | |
475be4d8 JP |
537 | {ST_L3_LC_REL_DELAY, EV_RELEASE_IND, lc_release_ind}, |
538 | {ST_L3_LC_REL_DELAY, EV_ESTABLISH_REQ, lc_connected}, | |
539 | {ST_L3_LC_REL_DELAY, EV_TIMEOUT, lc_release_req}, | |
1da177e4 LT |
540 | {ST_L3_LC_REL_WAIT, EV_RELEASE_CNF, lc_release_cnf}, |
541 | {ST_L3_LC_REL_WAIT, EV_ESTABLISH_REQ, lc_activate}, | |
542 | }; | |
543 | /* *INDENT-ON* */ | |
544 | ||
1da177e4 LT |
545 | void |
546 | l3_msg(struct PStack *st, int pr, void *arg) | |
547 | { | |
548 | switch (pr) { | |
475be4d8 JP |
549 | case (DL_DATA | REQUEST): |
550 | if (st->l3.l3m.state == ST_L3_LC_ESTAB) { | |
551 | st->l3.l3l2(st, pr, arg); | |
552 | } else { | |
553 | struct sk_buff *skb = arg; | |
554 | ||
555 | skb_queue_tail(&st->l3.squeue, skb); | |
1da177e4 | 556 | FsmEvent(&st->l3.l3m, EV_ESTABLISH_REQ, NULL); |
475be4d8 JP |
557 | } |
558 | break; | |
559 | case (DL_ESTABLISH | REQUEST): | |
560 | FsmEvent(&st->l3.l3m, EV_ESTABLISH_REQ, NULL); | |
561 | break; | |
562 | case (DL_ESTABLISH | CONFIRM): | |
563 | FsmEvent(&st->l3.l3m, EV_ESTABLISH_CNF, NULL); | |
564 | break; | |
565 | case (DL_ESTABLISH | INDICATION): | |
566 | FsmEvent(&st->l3.l3m, EV_ESTABLISH_IND, NULL); | |
567 | break; | |
568 | case (DL_RELEASE | INDICATION): | |
569 | FsmEvent(&st->l3.l3m, EV_RELEASE_IND, NULL); | |
570 | break; | |
571 | case (DL_RELEASE | CONFIRM): | |
572 | FsmEvent(&st->l3.l3m, EV_RELEASE_CNF, NULL); | |
573 | break; | |
574 | case (DL_RELEASE | REQUEST): | |
575 | FsmEvent(&st->l3.l3m, EV_RELEASE_REQ, NULL); | |
576 | break; | |
1da177e4 LT |
577 | } |
578 | } | |
579 | ||
580 | int __init | |
581 | Isdnl3New(void) | |
582 | { | |
583 | l3fsm.state_count = L3_STATE_COUNT; | |
584 | l3fsm.event_count = L3_EVENT_COUNT; | |
585 | l3fsm.strEvent = strL3Event; | |
586 | l3fsm.strState = strL3State; | |
ba2d6ccb | 587 | return FsmNew(&l3fsm, L3FnList, ARRAY_SIZE(L3FnList)); |
1da177e4 LT |
588 | } |
589 | ||
590 | void | |
591 | Isdnl3Free(void) | |
592 | { | |
593 | FsmFree(&l3fsm); | |
594 | } |