diff options
Diffstat (limited to 'drivers/isdn/mISDN/tei.c')
-rw-r--r-- | drivers/isdn/mISDN/tei.c | 1340 |
1 files changed, 1340 insertions, 0 deletions
diff --git a/drivers/isdn/mISDN/tei.c b/drivers/isdn/mISDN/tei.c new file mode 100644 index 000000000000..56a76a0ffddd --- /dev/null +++ b/drivers/isdn/mISDN/tei.c | |||
@@ -0,0 +1,1340 @@ | |||
1 | /* | ||
2 | * | ||
3 | * Author Karsten Keil <kkeil@novell.com> | ||
4 | * | ||
5 | * Copyright 2008 by Karsten Keil <kkeil@novell.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | */ | ||
17 | #include "layer2.h" | ||
18 | #include <linux/random.h> | ||
19 | #include "core.h" | ||
20 | |||
21 | #define ID_REQUEST 1 | ||
22 | #define ID_ASSIGNED 2 | ||
23 | #define ID_DENIED 3 | ||
24 | #define ID_CHK_REQ 4 | ||
25 | #define ID_CHK_RES 5 | ||
26 | #define ID_REMOVE 6 | ||
27 | #define ID_VERIFY 7 | ||
28 | |||
29 | #define TEI_ENTITY_ID 0xf | ||
30 | |||
31 | #define MGR_PH_ACTIVE 16 | ||
32 | #define MGR_PH_NOTREADY 17 | ||
33 | |||
34 | #define DATIMER_VAL 10000 | ||
35 | |||
36 | static u_int *debug; | ||
37 | |||
38 | static struct Fsm deactfsm = {NULL, 0, 0, NULL, NULL}; | ||
39 | static struct Fsm teifsmu = {NULL, 0, 0, NULL, NULL}; | ||
40 | static struct Fsm teifsmn = {NULL, 0, 0, NULL, NULL}; | ||
41 | |||
42 | enum { | ||
43 | ST_L1_DEACT, | ||
44 | ST_L1_DEACT_PENDING, | ||
45 | ST_L1_ACTIV, | ||
46 | }; | ||
47 | #define DEACT_STATE_COUNT (ST_L1_ACTIV+1) | ||
48 | |||
49 | static char *strDeactState[] = | ||
50 | { | ||
51 | "ST_L1_DEACT", | ||
52 | "ST_L1_DEACT_PENDING", | ||
53 | "ST_L1_ACTIV", | ||
54 | }; | ||
55 | |||
56 | enum { | ||
57 | EV_ACTIVATE, | ||
58 | EV_ACTIVATE_IND, | ||
59 | EV_DEACTIVATE, | ||
60 | EV_DEACTIVATE_IND, | ||
61 | EV_UI, | ||
62 | EV_DATIMER, | ||
63 | }; | ||
64 | |||
65 | #define DEACT_EVENT_COUNT (EV_DATIMER+1) | ||
66 | |||
67 | static char *strDeactEvent[] = | ||
68 | { | ||
69 | "EV_ACTIVATE", | ||
70 | "EV_ACTIVATE_IND", | ||
71 | "EV_DEACTIVATE", | ||
72 | "EV_DEACTIVATE_IND", | ||
73 | "EV_UI", | ||
74 | "EV_DATIMER", | ||
75 | }; | ||
76 | |||
77 | static void | ||
78 | da_debug(struct FsmInst *fi, char *fmt, ...) | ||
79 | { | ||
80 | struct manager *mgr = fi->userdata; | ||
81 | va_list va; | ||
82 | |||
83 | if (!(*debug & DEBUG_L2_TEIFSM)) | ||
84 | return; | ||
85 | va_start(va, fmt); | ||
86 | printk(KERN_DEBUG "mgr(%d): ", mgr->ch.st->dev->id); | ||
87 | vprintk(fmt, va); | ||
88 | printk("\n"); | ||
89 | va_end(va); | ||
90 | } | ||
91 | |||
92 | static void | ||
93 | da_activate(struct FsmInst *fi, int event, void *arg) | ||
94 | { | ||
95 | struct manager *mgr = fi->userdata; | ||
96 | |||
97 | if (fi->state == ST_L1_DEACT_PENDING) | ||
98 | mISDN_FsmDelTimer(&mgr->datimer, 1); | ||
99 | mISDN_FsmChangeState(fi, ST_L1_ACTIV); | ||
100 | } | ||
101 | |||
102 | static void | ||
103 | da_deactivate_ind(struct FsmInst *fi, int event, void *arg) | ||
104 | { | ||
105 | mISDN_FsmChangeState(fi, ST_L1_DEACT); | ||
106 | } | ||
107 | |||
108 | static void | ||
109 | da_deactivate(struct FsmInst *fi, int event, void *arg) | ||
110 | { | ||
111 | struct manager *mgr = fi->userdata; | ||
112 | struct layer2 *l2; | ||
113 | u_long flags; | ||
114 | |||
115 | read_lock_irqsave(&mgr->lock, flags); | ||
116 | list_for_each_entry(l2, &mgr->layer2, list) { | ||
117 | if (l2->l2m.state > ST_L2_4) { | ||
118 | /* have still activ TEI */ | ||
119 | read_unlock_irqrestore(&mgr->lock, flags); | ||
120 | return; | ||
121 | } | ||
122 | } | ||
123 | read_unlock_irqrestore(&mgr->lock, flags); | ||
124 | /* All TEI are inactiv */ | ||
125 | mISDN_FsmAddTimer(&mgr->datimer, DATIMER_VAL, EV_DATIMER, NULL, 1); | ||
126 | mISDN_FsmChangeState(fi, ST_L1_DEACT_PENDING); | ||
127 | } | ||
128 | |||
129 | static void | ||
130 | da_ui(struct FsmInst *fi, int event, void *arg) | ||
131 | { | ||
132 | struct manager *mgr = fi->userdata; | ||
133 | |||
134 | /* restart da timer */ | ||
135 | mISDN_FsmDelTimer(&mgr->datimer, 2); | ||
136 | mISDN_FsmAddTimer(&mgr->datimer, DATIMER_VAL, EV_DATIMER, NULL, 2); | ||
137 | |||
138 | } | ||
139 | |||
140 | static void | ||
141 | da_timer(struct FsmInst *fi, int event, void *arg) | ||
142 | { | ||
143 | struct manager *mgr = fi->userdata; | ||
144 | struct layer2 *l2; | ||
145 | u_long flags; | ||
146 | |||
147 | /* check again */ | ||
148 | read_lock_irqsave(&mgr->lock, flags); | ||
149 | list_for_each_entry(l2, &mgr->layer2, list) { | ||
150 | if (l2->l2m.state > ST_L2_4) { | ||
151 | /* have still activ TEI */ | ||
152 | read_unlock_irqrestore(&mgr->lock, flags); | ||
153 | mISDN_FsmChangeState(fi, ST_L1_ACTIV); | ||
154 | return; | ||
155 | } | ||
156 | } | ||
157 | read_unlock_irqrestore(&mgr->lock, flags); | ||
158 | /* All TEI are inactiv */ | ||
159 | mISDN_FsmChangeState(fi, ST_L1_DEACT); | ||
160 | _queue_data(&mgr->ch, PH_DEACTIVATE_REQ, MISDN_ID_ANY, 0, NULL, | ||
161 | GFP_ATOMIC); | ||
162 | } | ||
163 | |||
164 | static struct FsmNode DeactFnList[] = | ||
165 | { | ||
166 | {ST_L1_DEACT, EV_ACTIVATE_IND, da_activate}, | ||
167 | {ST_L1_ACTIV, EV_DEACTIVATE_IND, da_deactivate_ind}, | ||
168 | {ST_L1_ACTIV, EV_DEACTIVATE, da_deactivate}, | ||
169 | {ST_L1_DEACT_PENDING, EV_ACTIVATE, da_activate}, | ||
170 | {ST_L1_DEACT_PENDING, EV_UI, da_ui}, | ||
171 | {ST_L1_DEACT_PENDING, EV_DATIMER, da_timer}, | ||
172 | }; | ||
173 | |||
174 | enum { | ||
175 | ST_TEI_NOP, | ||
176 | ST_TEI_IDREQ, | ||
177 | ST_TEI_IDVERIFY, | ||
178 | }; | ||
179 | |||
180 | #define TEI_STATE_COUNT (ST_TEI_IDVERIFY+1) | ||
181 | |||
182 | static char *strTeiState[] = | ||
183 | { | ||
184 | "ST_TEI_NOP", | ||
185 | "ST_TEI_IDREQ", | ||
186 | "ST_TEI_IDVERIFY", | ||
187 | }; | ||
188 | |||
189 | enum { | ||
190 | EV_IDREQ, | ||
191 | EV_ASSIGN, | ||
192 | EV_ASSIGN_REQ, | ||
193 | EV_DENIED, | ||
194 | EV_CHKREQ, | ||
195 | EV_CHKRESP, | ||
196 | EV_REMOVE, | ||
197 | EV_VERIFY, | ||
198 | EV_TIMER, | ||
199 | }; | ||
200 | |||
201 | #define TEI_EVENT_COUNT (EV_TIMER+1) | ||
202 | |||
203 | static char *strTeiEvent[] = | ||
204 | { | ||
205 | "EV_IDREQ", | ||
206 | "EV_ASSIGN", | ||
207 | "EV_ASSIGN_REQ", | ||
208 | "EV_DENIED", | ||
209 | "EV_CHKREQ", | ||
210 | "EV_CHKRESP", | ||
211 | "EV_REMOVE", | ||
212 | "EV_VERIFY", | ||
213 | "EV_TIMER", | ||
214 | }; | ||
215 | |||
216 | static void | ||
217 | tei_debug(struct FsmInst *fi, char *fmt, ...) | ||
218 | { | ||
219 | struct teimgr *tm = fi->userdata; | ||
220 | va_list va; | ||
221 | |||
222 | if (!(*debug & DEBUG_L2_TEIFSM)) | ||
223 | return; | ||
224 | va_start(va, fmt); | ||
225 | printk(KERN_DEBUG "tei(%d): ", tm->l2->tei); | ||
226 | vprintk(fmt, va); | ||
227 | printk("\n"); | ||
228 | va_end(va); | ||
229 | } | ||
230 | |||
231 | |||
232 | |||
233 | static int | ||
234 | get_free_id(struct manager *mgr) | ||
235 | { | ||
236 | u64 ids = 0; | ||
237 | int i; | ||
238 | struct layer2 *l2; | ||
239 | |||
240 | list_for_each_entry(l2, &mgr->layer2, list) { | ||
241 | if (l2->ch.nr > 63) { | ||
242 | printk(KERN_WARNING | ||
243 | "%s: more as 63 layer2 for one device\n", | ||
244 | __func__); | ||
245 | return -EBUSY; | ||
246 | } | ||
247 | test_and_set_bit(l2->ch.nr, (u_long *)&ids); | ||
248 | } | ||
249 | for (i = 1; i < 64; i++) | ||
250 | if (!test_bit(i, (u_long *)&ids)) | ||
251 | return i; | ||
252 | printk(KERN_WARNING "%s: more as 63 layer2 for one device\n", | ||
253 | __func__); | ||
254 | return -EBUSY; | ||
255 | } | ||
256 | |||
257 | static int | ||
258 | get_free_tei(struct manager *mgr) | ||
259 | { | ||
260 | u64 ids = 0; | ||
261 | int i; | ||
262 | struct layer2 *l2; | ||
263 | |||
264 | list_for_each_entry(l2, &mgr->layer2, list) { | ||
265 | if (l2->ch.nr == 0) | ||
266 | continue; | ||
267 | if ((l2->ch.addr & 0xff) != 0) | ||
268 | continue; | ||
269 | i = l2->ch.addr >> 8; | ||
270 | if (i < 64) | ||
271 | continue; | ||
272 | i -= 64; | ||
273 | |||
274 | test_and_set_bit(i, (u_long *)&ids); | ||
275 | } | ||
276 | for (i = 0; i < 64; i++) | ||
277 | if (!test_bit(i, (u_long *)&ids)) | ||
278 | return i + 64; | ||
279 | printk(KERN_WARNING "%s: more as 63 dynamic tei for one device\n", | ||
280 | __func__); | ||
281 | return -1; | ||
282 | } | ||
283 | |||
284 | static void | ||
285 | teiup_create(struct manager *mgr, u_int prim, int len, void *arg) | ||
286 | { | ||
287 | struct sk_buff *skb; | ||
288 | struct mISDNhead *hh; | ||
289 | int err; | ||
290 | |||
291 | skb = mI_alloc_skb(len, GFP_ATOMIC); | ||
292 | if (!skb) | ||
293 | return; | ||
294 | hh = mISDN_HEAD_P(skb); | ||
295 | hh->prim = prim; | ||
296 | hh->id = (mgr->ch.nr << 16) | mgr->ch.addr; | ||
297 | if (len) | ||
298 | memcpy(skb_put(skb, len), arg, len); | ||
299 | err = mgr->up->send(mgr->up, skb); | ||
300 | if (err) { | ||
301 | printk(KERN_WARNING "%s: err=%d\n", __func__, err); | ||
302 | dev_kfree_skb(skb); | ||
303 | } | ||
304 | } | ||
305 | |||
306 | static u_int | ||
307 | new_id(struct manager *mgr) | ||
308 | { | ||
309 | u_int id; | ||
310 | |||
311 | id = mgr->nextid++; | ||
312 | if (id == 0x7fff) | ||
313 | mgr->nextid = 1; | ||
314 | id <<= 16; | ||
315 | id |= GROUP_TEI << 8; | ||
316 | id |= TEI_SAPI; | ||
317 | return id; | ||
318 | } | ||
319 | |||
320 | static void | ||
321 | do_send(struct manager *mgr) | ||
322 | { | ||
323 | if (!test_bit(MGR_PH_ACTIVE, &mgr->options)) | ||
324 | return; | ||
325 | |||
326 | if (!test_and_set_bit(MGR_PH_NOTREADY, &mgr->options)) { | ||
327 | struct sk_buff *skb = skb_dequeue(&mgr->sendq); | ||
328 | |||
329 | if (!skb) { | ||
330 | test_and_clear_bit(MGR_PH_NOTREADY, &mgr->options); | ||
331 | return; | ||
332 | } | ||
333 | mgr->lastid = mISDN_HEAD_ID(skb); | ||
334 | mISDN_FsmEvent(&mgr->deact, EV_UI, NULL); | ||
335 | if (mgr->ch.recv(mgr->ch.peer, skb)) { | ||
336 | dev_kfree_skb(skb); | ||
337 | test_and_clear_bit(MGR_PH_NOTREADY, &mgr->options); | ||
338 | mgr->lastid = MISDN_ID_NONE; | ||
339 | } | ||
340 | } | ||
341 | } | ||
342 | |||
343 | static void | ||
344 | do_ack(struct manager *mgr, u_int id) | ||
345 | { | ||
346 | if (test_bit(MGR_PH_NOTREADY, &mgr->options)) { | ||
347 | if (id == mgr->lastid) { | ||
348 | if (test_bit(MGR_PH_ACTIVE, &mgr->options)) { | ||
349 | struct sk_buff *skb; | ||
350 | |||
351 | skb = skb_dequeue(&mgr->sendq); | ||
352 | if (skb) { | ||
353 | mgr->lastid = mISDN_HEAD_ID(skb); | ||
354 | if (!mgr->ch.recv(mgr->ch.peer, skb)) | ||
355 | return; | ||
356 | dev_kfree_skb(skb); | ||
357 | } | ||
358 | } | ||
359 | mgr->lastid = MISDN_ID_NONE; | ||
360 | test_and_clear_bit(MGR_PH_NOTREADY, &mgr->options); | ||
361 | } | ||
362 | } | ||
363 | } | ||
364 | |||
365 | static void | ||
366 | mgr_send_down(struct manager *mgr, struct sk_buff *skb) | ||
367 | { | ||
368 | skb_queue_tail(&mgr->sendq, skb); | ||
369 | if (!test_bit(MGR_PH_ACTIVE, &mgr->options)) { | ||
370 | _queue_data(&mgr->ch, PH_ACTIVATE_REQ, MISDN_ID_ANY, 0, | ||
371 | NULL, GFP_KERNEL); | ||
372 | } else { | ||
373 | do_send(mgr); | ||
374 | } | ||
375 | } | ||
376 | |||
377 | static int | ||
378 | dl_unit_data(struct manager *mgr, struct sk_buff *skb) | ||
379 | { | ||
380 | if (!test_bit(MGR_OPT_NETWORK, &mgr->options)) /* only net send UI */ | ||
381 | return -EINVAL; | ||
382 | if (!test_bit(MGR_PH_ACTIVE, &mgr->options)) | ||
383 | _queue_data(&mgr->ch, PH_ACTIVATE_REQ, MISDN_ID_ANY, 0, | ||
384 | NULL, GFP_KERNEL); | ||
385 | skb_push(skb, 3); | ||
386 | skb->data[0] = 0x02; /* SAPI 0 C/R = 1 */ | ||
387 | skb->data[1] = 0xff; /* TEI 127 */ | ||
388 | skb->data[2] = UI; /* UI frame */ | ||
389 | mISDN_HEAD_PRIM(skb) = PH_DATA_REQ; | ||
390 | mISDN_HEAD_ID(skb) = new_id(mgr); | ||
391 | skb_queue_tail(&mgr->sendq, skb); | ||
392 | do_send(mgr); | ||
393 | return 0; | ||
394 | } | ||
395 | |||
396 | unsigned int | ||
397 | random_ri(void) | ||
398 | { | ||
399 | u16 x; | ||
400 | |||
401 | get_random_bytes(&x, sizeof(x)); | ||
402 | return x; | ||
403 | } | ||
404 | |||
405 | static struct layer2 * | ||
406 | findtei(struct manager *mgr, int tei) | ||
407 | { | ||
408 | struct layer2 *l2; | ||
409 | u_long flags; | ||
410 | |||
411 | read_lock_irqsave(&mgr->lock, flags); | ||
412 | list_for_each_entry(l2, &mgr->layer2, list) { | ||
413 | if ((l2->sapi == 0) && (l2->tei > 0) && | ||
414 | (l2->tei != GROUP_TEI) && (l2->tei == tei)) | ||
415 | goto done; | ||
416 | } | ||
417 | l2 = NULL; | ||
418 | done: | ||
419 | read_unlock_irqrestore(&mgr->lock, flags); | ||
420 | return l2; | ||
421 | } | ||
422 | |||
423 | static void | ||
424 | put_tei_msg(struct manager *mgr, u_char m_id, unsigned int ri, u_char tei) | ||
425 | { | ||
426 | struct sk_buff *skb; | ||
427 | u_char bp[8]; | ||
428 | |||
429 | bp[0] = (TEI_SAPI << 2); | ||
430 | if (test_bit(MGR_OPT_NETWORK, &mgr->options)) | ||
431 | bp[0] |= 2; /* CR:=1 for net command */ | ||
432 | bp[1] = (GROUP_TEI << 1) | 0x1; | ||
433 | bp[2] = UI; | ||
434 | bp[3] = TEI_ENTITY_ID; | ||
435 | bp[4] = ri >> 8; | ||
436 | bp[5] = ri & 0xff; | ||
437 | bp[6] = m_id; | ||
438 | bp[7] = (tei << 1) | 1; | ||
439 | skb = _alloc_mISDN_skb(PH_DATA_REQ, new_id(mgr), | ||
440 | 8, bp, GFP_ATOMIC); | ||
441 | if (!skb) { | ||
442 | printk(KERN_WARNING "%s: no skb for tei msg\n", __func__); | ||
443 | return; | ||
444 | } | ||
445 | mgr_send_down(mgr, skb); | ||
446 | } | ||
447 | |||
448 | static void | ||
449 | tei_id_request(struct FsmInst *fi, int event, void *arg) | ||
450 | { | ||
451 | struct teimgr *tm = fi->userdata; | ||
452 | |||
453 | if (tm->l2->tei != GROUP_TEI) { | ||
454 | tm->tei_m.printdebug(&tm->tei_m, | ||
455 | "assign request for allready assigned tei %d", | ||
456 | tm->l2->tei); | ||
457 | return; | ||
458 | } | ||
459 | tm->ri = random_ri(); | ||
460 | if (*debug & DEBUG_L2_TEI) | ||
461 | tm->tei_m.printdebug(&tm->tei_m, | ||
462 | "assign request ri %d", tm->ri); | ||
463 | put_tei_msg(tm->mgr, ID_REQUEST, tm->ri, GROUP_TEI); | ||
464 | mISDN_FsmChangeState(fi, ST_TEI_IDREQ); | ||
465 | mISDN_FsmAddTimer(&tm->timer, tm->tval, EV_TIMER, NULL, 1); | ||
466 | tm->nval = 3; | ||
467 | } | ||
468 | |||
469 | static void | ||
470 | tei_id_assign(struct FsmInst *fi, int event, void *arg) | ||
471 | { | ||
472 | struct teimgr *tm = fi->userdata; | ||
473 | struct layer2 *l2; | ||
474 | u_char *dp = arg; | ||
475 | int ri, tei; | ||
476 | |||
477 | ri = ((unsigned int) *dp++ << 8); | ||
478 | ri += *dp++; | ||
479 | dp++; | ||
480 | tei = *dp >> 1; | ||
481 | if (*debug & DEBUG_L2_TEI) | ||
482 | tm->tei_m.printdebug(fi, "identity assign ri %d tei %d", | ||
483 | ri, tei); | ||
484 | l2 = findtei(tm->mgr, tei); | ||
485 | if (l2) { /* same tei is in use */ | ||
486 | if (ri != l2->tm->ri) { | ||
487 | tm->tei_m.printdebug(fi, | ||
488 | "possible duplicate assignment tei %d", tei); | ||
489 | tei_l2(l2, MDL_ERROR_RSP, 0); | ||
490 | } | ||
491 | } else if (ri == tm->ri) { | ||
492 | mISDN_FsmDelTimer(&tm->timer, 1); | ||
493 | mISDN_FsmChangeState(fi, ST_TEI_NOP); | ||
494 | tei_l2(tm->l2, MDL_ASSIGN_REQ, tei); | ||
495 | } | ||
496 | } | ||
497 | |||
498 | static void | ||
499 | tei_id_test_dup(struct FsmInst *fi, int event, void *arg) | ||
500 | { | ||
501 | struct teimgr *tm = fi->userdata; | ||
502 | struct layer2 *l2; | ||
503 | u_char *dp = arg; | ||
504 | int tei, ri; | ||
505 | |||
506 | ri = ((unsigned int) *dp++ << 8); | ||
507 | ri += *dp++; | ||
508 | dp++; | ||
509 | tei = *dp >> 1; | ||
510 | if (*debug & DEBUG_L2_TEI) | ||
511 | tm->tei_m.printdebug(fi, "foreign identity assign ri %d tei %d", | ||
512 | ri, tei); | ||
513 | l2 = findtei(tm->mgr, tei); | ||
514 | if (l2) { /* same tei is in use */ | ||
515 | if (ri != l2->tm->ri) { /* and it wasn't our request */ | ||
516 | tm->tei_m.printdebug(fi, | ||
517 | "possible duplicate assignment tei %d", tei); | ||
518 | mISDN_FsmEvent(&l2->tm->tei_m, EV_VERIFY, NULL); | ||
519 | } | ||
520 | } | ||
521 | } | ||
522 | |||
523 | static void | ||
524 | tei_id_denied(struct FsmInst *fi, int event, void *arg) | ||
525 | { | ||
526 | struct teimgr *tm = fi->userdata; | ||
527 | u_char *dp = arg; | ||
528 | int ri, tei; | ||
529 | |||
530 | ri = ((unsigned int) *dp++ << 8); | ||
531 | ri += *dp++; | ||
532 | dp++; | ||
533 | tei = *dp >> 1; | ||
534 | if (*debug & DEBUG_L2_TEI) | ||
535 | tm->tei_m.printdebug(fi, "identity denied ri %d tei %d", | ||
536 | ri, tei); | ||
537 | } | ||
538 | |||
539 | static void | ||
540 | tei_id_chk_req(struct FsmInst *fi, int event, void *arg) | ||
541 | { | ||
542 | struct teimgr *tm = fi->userdata; | ||
543 | u_char *dp = arg; | ||
544 | int tei; | ||
545 | |||
546 | tei = *(dp+3) >> 1; | ||
547 | if (*debug & DEBUG_L2_TEI) | ||
548 | tm->tei_m.printdebug(fi, "identity check req tei %d", tei); | ||
549 | if ((tm->l2->tei != GROUP_TEI) && ((tei == GROUP_TEI) || | ||
550 | (tei == tm->l2->tei))) { | ||
551 | mISDN_FsmDelTimer(&tm->timer, 4); | ||
552 | mISDN_FsmChangeState(&tm->tei_m, ST_TEI_NOP); | ||
553 | put_tei_msg(tm->mgr, ID_CHK_RES, random_ri(), tm->l2->tei); | ||
554 | } | ||
555 | } | ||
556 | |||
557 | static void | ||
558 | tei_id_remove(struct FsmInst *fi, int event, void *arg) | ||
559 | { | ||
560 | struct teimgr *tm = fi->userdata; | ||
561 | u_char *dp = arg; | ||
562 | int tei; | ||
563 | |||
564 | tei = *(dp+3) >> 1; | ||
565 | if (*debug & DEBUG_L2_TEI) | ||
566 | tm->tei_m.printdebug(fi, "identity remove tei %d", tei); | ||
567 | if ((tm->l2->tei != GROUP_TEI) && | ||
568 | ((tei == GROUP_TEI) || (tei == tm->l2->tei))) { | ||
569 | mISDN_FsmDelTimer(&tm->timer, 5); | ||
570 | mISDN_FsmChangeState(&tm->tei_m, ST_TEI_NOP); | ||
571 | tei_l2(tm->l2, MDL_REMOVE_REQ, 0); | ||
572 | } | ||
573 | } | ||
574 | |||
575 | static void | ||
576 | tei_id_verify(struct FsmInst *fi, int event, void *arg) | ||
577 | { | ||
578 | struct teimgr *tm = fi->userdata; | ||
579 | |||
580 | if (*debug & DEBUG_L2_TEI) | ||
581 | tm->tei_m.printdebug(fi, "id verify request for tei %d", | ||
582 | tm->l2->tei); | ||
583 | put_tei_msg(tm->mgr, ID_VERIFY, 0, tm->l2->tei); | ||
584 | mISDN_FsmChangeState(&tm->tei_m, ST_TEI_IDVERIFY); | ||
585 | mISDN_FsmAddTimer(&tm->timer, tm->tval, EV_TIMER, NULL, 2); | ||
586 | tm->nval = 2; | ||
587 | } | ||
588 | |||
589 | static void | ||
590 | tei_id_req_tout(struct FsmInst *fi, int event, void *arg) | ||
591 | { | ||
592 | struct teimgr *tm = fi->userdata; | ||
593 | |||
594 | if (--tm->nval) { | ||
595 | tm->ri = random_ri(); | ||
596 | if (*debug & DEBUG_L2_TEI) | ||
597 | tm->tei_m.printdebug(fi, "assign req(%d) ri %d", | ||
598 | 4 - tm->nval, tm->ri); | ||
599 | put_tei_msg(tm->mgr, ID_REQUEST, tm->ri, GROUP_TEI); | ||
600 | mISDN_FsmAddTimer(&tm->timer, tm->tval, EV_TIMER, NULL, 3); | ||
601 | } else { | ||
602 | tm->tei_m.printdebug(fi, "assign req failed"); | ||
603 | tei_l2(tm->l2, MDL_ERROR_RSP, 0); | ||
604 | mISDN_FsmChangeState(fi, ST_TEI_NOP); | ||
605 | } | ||
606 | } | ||
607 | |||
608 | static void | ||
609 | tei_id_ver_tout(struct FsmInst *fi, int event, void *arg) | ||
610 | { | ||
611 | struct teimgr *tm = fi->userdata; | ||
612 | |||
613 | if (--tm->nval) { | ||
614 | if (*debug & DEBUG_L2_TEI) | ||
615 | tm->tei_m.printdebug(fi, | ||
616 | "id verify req(%d) for tei %d", | ||
617 | 3 - tm->nval, tm->l2->tei); | ||
618 | put_tei_msg(tm->mgr, ID_VERIFY, 0, tm->l2->tei); | ||
619 | mISDN_FsmAddTimer(&tm->timer, tm->tval, EV_TIMER, NULL, 4); | ||
620 | } else { | ||
621 | tm->tei_m.printdebug(fi, "verify req for tei %d failed", | ||
622 | tm->l2->tei); | ||
623 | tei_l2(tm->l2, MDL_REMOVE_REQ, 0); | ||
624 | mISDN_FsmChangeState(fi, ST_TEI_NOP); | ||
625 | } | ||
626 | } | ||
627 | |||
628 | static struct FsmNode TeiFnListUser[] = | ||
629 | { | ||
630 | {ST_TEI_NOP, EV_IDREQ, tei_id_request}, | ||
631 | {ST_TEI_NOP, EV_ASSIGN, tei_id_test_dup}, | ||
632 | {ST_TEI_NOP, EV_VERIFY, tei_id_verify}, | ||
633 | {ST_TEI_NOP, EV_REMOVE, tei_id_remove}, | ||
634 | {ST_TEI_NOP, EV_CHKREQ, tei_id_chk_req}, | ||
635 | {ST_TEI_IDREQ, EV_TIMER, tei_id_req_tout}, | ||
636 | {ST_TEI_IDREQ, EV_ASSIGN, tei_id_assign}, | ||
637 | {ST_TEI_IDREQ, EV_DENIED, tei_id_denied}, | ||
638 | {ST_TEI_IDVERIFY, EV_TIMER, tei_id_ver_tout}, | ||
639 | {ST_TEI_IDVERIFY, EV_REMOVE, tei_id_remove}, | ||
640 | {ST_TEI_IDVERIFY, EV_CHKREQ, tei_id_chk_req}, | ||
641 | }; | ||
642 | |||
643 | static void | ||
644 | tei_l2remove(struct layer2 *l2) | ||
645 | { | ||
646 | put_tei_msg(l2->tm->mgr, ID_REMOVE, 0, l2->tei); | ||
647 | tei_l2(l2, MDL_REMOVE_REQ, 0); | ||
648 | list_del(&l2->ch.list); | ||
649 | l2->ch.ctrl(&l2->ch, CLOSE_CHANNEL, NULL); | ||
650 | } | ||
651 | |||
652 | static void | ||
653 | tei_assign_req(struct FsmInst *fi, int event, void *arg) | ||
654 | { | ||
655 | struct teimgr *tm = fi->userdata; | ||
656 | u_char *dp = arg; | ||
657 | |||
658 | if (tm->l2->tei == GROUP_TEI) { | ||
659 | tm->tei_m.printdebug(&tm->tei_m, | ||
660 | "net tei assign request without tei"); | ||
661 | return; | ||
662 | } | ||
663 | tm->ri = ((unsigned int) *dp++ << 8); | ||
664 | tm->ri += *dp++; | ||
665 | if (*debug & DEBUG_L2_TEI) | ||
666 | tm->tei_m.printdebug(&tm->tei_m, | ||
667 | "net assign request ri %d teim %d", tm->ri, *dp); | ||
668 | put_tei_msg(tm->mgr, ID_ASSIGNED, tm->ri, tm->l2->tei); | ||
669 | mISDN_FsmChangeState(fi, ST_TEI_NOP); | ||
670 | } | ||
671 | |||
672 | static void | ||
673 | tei_id_chk_req_net(struct FsmInst *fi, int event, void *arg) | ||
674 | { | ||
675 | struct teimgr *tm = fi->userdata; | ||
676 | |||
677 | if (*debug & DEBUG_L2_TEI) | ||
678 | tm->tei_m.printdebug(fi, "id check request for tei %d", | ||
679 | tm->l2->tei); | ||
680 | tm->rcnt = 0; | ||
681 | put_tei_msg(tm->mgr, ID_CHK_REQ, 0, tm->l2->tei); | ||
682 | mISDN_FsmChangeState(&tm->tei_m, ST_TEI_IDVERIFY); | ||
683 | mISDN_FsmAddTimer(&tm->timer, tm->tval, EV_TIMER, NULL, 2); | ||
684 | tm->nval = 2; | ||
685 | } | ||
686 | |||
687 | static void | ||
688 | tei_id_chk_resp(struct FsmInst *fi, int event, void *arg) | ||
689 | { | ||
690 | struct teimgr *tm = fi->userdata; | ||
691 | u_char *dp = arg; | ||
692 | int tei; | ||
693 | |||
694 | tei = dp[3] >> 1; | ||
695 | if (*debug & DEBUG_L2_TEI) | ||
696 | tm->tei_m.printdebug(fi, "identity check resp tei %d", tei); | ||
697 | if (tei == tm->l2->tei) | ||
698 | tm->rcnt++; | ||
699 | } | ||
700 | |||
701 | static void | ||
702 | tei_id_verify_net(struct FsmInst *fi, int event, void *arg) | ||
703 | { | ||
704 | struct teimgr *tm = fi->userdata; | ||
705 | u_char *dp = arg; | ||
706 | int tei; | ||
707 | |||
708 | tei = dp[3] >> 1; | ||
709 | if (*debug & DEBUG_L2_TEI) | ||
710 | tm->tei_m.printdebug(fi, "identity verify req tei %d/%d", | ||
711 | tei, tm->l2->tei); | ||
712 | if (tei == tm->l2->tei) | ||
713 | tei_id_chk_req_net(fi, event, arg); | ||
714 | } | ||
715 | |||
716 | static void | ||
717 | tei_id_ver_tout_net(struct FsmInst *fi, int event, void *arg) | ||
718 | { | ||
719 | struct teimgr *tm = fi->userdata; | ||
720 | |||
721 | if (tm->rcnt == 1) { | ||
722 | if (*debug & DEBUG_L2_TEI) | ||
723 | tm->tei_m.printdebug(fi, | ||
724 | "check req for tei %d sucessful\n", tm->l2->tei); | ||
725 | mISDN_FsmChangeState(fi, ST_TEI_NOP); | ||
726 | } else if (tm->rcnt > 1) { | ||
727 | /* duplicate assignment; remove */ | ||
728 | tei_l2remove(tm->l2); | ||
729 | } else if (--tm->nval) { | ||
730 | if (*debug & DEBUG_L2_TEI) | ||
731 | tm->tei_m.printdebug(fi, | ||
732 | "id check req(%d) for tei %d", | ||
733 | 3 - tm->nval, tm->l2->tei); | ||
734 | put_tei_msg(tm->mgr, ID_CHK_REQ, 0, tm->l2->tei); | ||
735 | mISDN_FsmAddTimer(&tm->timer, tm->tval, EV_TIMER, NULL, 4); | ||
736 | } else { | ||
737 | tm->tei_m.printdebug(fi, "check req for tei %d failed", | ||
738 | tm->l2->tei); | ||
739 | mISDN_FsmChangeState(fi, ST_TEI_NOP); | ||
740 | tei_l2remove(tm->l2); | ||
741 | } | ||
742 | } | ||
743 | |||
744 | static struct FsmNode TeiFnListNet[] = | ||
745 | { | ||
746 | {ST_TEI_NOP, EV_ASSIGN_REQ, tei_assign_req}, | ||
747 | {ST_TEI_NOP, EV_VERIFY, tei_id_verify_net}, | ||
748 | {ST_TEI_NOP, EV_CHKREQ, tei_id_chk_req_net}, | ||
749 | {ST_TEI_IDVERIFY, EV_TIMER, tei_id_ver_tout_net}, | ||
750 | {ST_TEI_IDVERIFY, EV_CHKRESP, tei_id_chk_resp}, | ||
751 | }; | ||
752 | |||
753 | static void | ||
754 | tei_ph_data_ind(struct teimgr *tm, u_int mt, u_char *dp, int len) | ||
755 | { | ||
756 | if (test_bit(FLG_FIXED_TEI, &tm->l2->flag)) | ||
757 | return; | ||
758 | if (*debug & DEBUG_L2_TEI) | ||
759 | tm->tei_m.printdebug(&tm->tei_m, "tei handler mt %x", mt); | ||
760 | if (mt == ID_ASSIGNED) | ||
761 | mISDN_FsmEvent(&tm->tei_m, EV_ASSIGN, dp); | ||
762 | else if (mt == ID_DENIED) | ||
763 | mISDN_FsmEvent(&tm->tei_m, EV_DENIED, dp); | ||
764 | else if (mt == ID_CHK_REQ) | ||
765 | mISDN_FsmEvent(&tm->tei_m, EV_CHKREQ, dp); | ||
766 | else if (mt == ID_REMOVE) | ||
767 | mISDN_FsmEvent(&tm->tei_m, EV_REMOVE, dp); | ||
768 | else if (mt == ID_VERIFY) | ||
769 | mISDN_FsmEvent(&tm->tei_m, EV_VERIFY, dp); | ||
770 | else if (mt == ID_CHK_RES) | ||
771 | mISDN_FsmEvent(&tm->tei_m, EV_CHKRESP, dp); | ||
772 | } | ||
773 | |||
774 | static struct layer2 * | ||
775 | create_new_tei(struct manager *mgr, int tei) | ||
776 | { | ||
777 | u_long opt = 0; | ||
778 | u_long flags; | ||
779 | int id; | ||
780 | struct layer2 *l2; | ||
781 | |||
782 | if (!mgr->up) | ||
783 | return NULL; | ||
784 | if (tei < 64) | ||
785 | test_and_set_bit(OPTION_L2_FIXEDTEI, &opt); | ||
786 | if (mgr->ch.st->dev->Dprotocols | ||
787 | & ((1 << ISDN_P_TE_E1) | (1 << ISDN_P_NT_E1))) | ||
788 | test_and_set_bit(OPTION_L2_PMX, &opt); | ||
789 | l2 = create_l2(mgr->up, ISDN_P_LAPD_NT, (u_int)opt, (u_long)tei); | ||
790 | if (!l2) { | ||
791 | printk(KERN_WARNING "%s:no memory for layer2\n", __func__); | ||
792 | return NULL; | ||
793 | } | ||
794 | l2->tm = kzalloc(sizeof(struct teimgr), GFP_KERNEL); | ||
795 | if (!l2->tm) { | ||
796 | kfree(l2); | ||
797 | printk(KERN_WARNING "%s:no memory for teimgr\n", __func__); | ||
798 | return NULL; | ||
799 | } | ||
800 | l2->tm->mgr = mgr; | ||
801 | l2->tm->l2 = l2; | ||
802 | l2->tm->tei_m.debug = *debug & DEBUG_L2_TEIFSM; | ||
803 | l2->tm->tei_m.userdata = l2->tm; | ||
804 | l2->tm->tei_m.printdebug = tei_debug; | ||
805 | l2->tm->tei_m.fsm = &teifsmn; | ||
806 | l2->tm->tei_m.state = ST_TEI_NOP; | ||
807 | l2->tm->tval = 2000; /* T202 2 sec */ | ||
808 | mISDN_FsmInitTimer(&l2->tm->tei_m, &l2->tm->timer); | ||
809 | write_lock_irqsave(&mgr->lock, flags); | ||
810 | id = get_free_id(mgr); | ||
811 | list_add_tail(&l2->list, &mgr->layer2); | ||
812 | write_unlock_irqrestore(&mgr->lock, flags); | ||
813 | if (id < 0) { | ||
814 | l2->ch.ctrl(&l2->ch, CLOSE_CHANNEL, NULL); | ||
815 | printk(KERN_WARNING "%s:no free id\n", __func__); | ||
816 | return NULL; | ||
817 | } else { | ||
818 | l2->ch.nr = id; | ||
819 | __add_layer2(&l2->ch, mgr->ch.st); | ||
820 | l2->ch.recv = mgr->ch.recv; | ||
821 | l2->ch.peer = mgr->ch.peer; | ||
822 | l2->ch.ctrl(&l2->ch, OPEN_CHANNEL, NULL); | ||
823 | } | ||
824 | return l2; | ||
825 | } | ||
826 | |||
827 | static void | ||
828 | new_tei_req(struct manager *mgr, u_char *dp) | ||
829 | { | ||
830 | int tei, ri; | ||
831 | struct layer2 *l2; | ||
832 | |||
833 | ri = dp[0] << 8; | ||
834 | ri += dp[1]; | ||
835 | if (!mgr->up) | ||
836 | goto denied; | ||
837 | tei = get_free_tei(mgr); | ||
838 | if (tei < 0) { | ||
839 | printk(KERN_WARNING "%s:No free tei\n", __func__); | ||
840 | goto denied; | ||
841 | } | ||
842 | l2 = create_new_tei(mgr, tei); | ||
843 | if (!l2) | ||
844 | goto denied; | ||
845 | else | ||
846 | mISDN_FsmEvent(&l2->tm->tei_m, EV_ASSIGN_REQ, dp); | ||
847 | return; | ||
848 | denied: | ||
849 | put_tei_msg(mgr, ID_DENIED, ri, GROUP_TEI); | ||
850 | } | ||
851 | |||
852 | static int | ||
853 | ph_data_ind(struct manager *mgr, struct sk_buff *skb) | ||
854 | { | ||
855 | int ret = -EINVAL; | ||
856 | struct layer2 *l2; | ||
857 | u_long flags; | ||
858 | u_char mt; | ||
859 | |||
860 | if (skb->len < 8) { | ||
861 | if (*debug & DEBUG_L2_TEI) | ||
862 | printk(KERN_DEBUG "%s: short mgr frame %d/8\n", | ||
863 | __func__, skb->len); | ||
864 | goto done; | ||
865 | } | ||
866 | if (*debug & DEBUG_L2_TEI) | ||
867 | |||
868 | if ((skb->data[0] >> 2) != TEI_SAPI) /* not for us */ | ||
869 | goto done; | ||
870 | if (skb->data[0] & 1) /* EA0 formal error */ | ||
871 | goto done; | ||
872 | if (!(skb->data[1] & 1)) /* EA1 formal error */ | ||
873 | goto done; | ||
874 | if ((skb->data[1] >> 1) != GROUP_TEI) /* not for us */ | ||
875 | goto done; | ||
876 | if ((skb->data[2] & 0xef) != UI) /* not UI */ | ||
877 | goto done; | ||
878 | if (skb->data[3] != TEI_ENTITY_ID) /* not tei entity */ | ||
879 | goto done; | ||
880 | mt = skb->data[6]; | ||
881 | switch (mt) { | ||
882 | case ID_REQUEST: | ||
883 | case ID_CHK_RES: | ||
884 | case ID_VERIFY: | ||
885 | if (!test_bit(MGR_OPT_NETWORK, &mgr->options)) | ||
886 | goto done; | ||
887 | break; | ||
888 | case ID_ASSIGNED: | ||
889 | case ID_DENIED: | ||
890 | case ID_CHK_REQ: | ||
891 | case ID_REMOVE: | ||
892 | if (test_bit(MGR_OPT_NETWORK, &mgr->options)) | ||
893 | goto done; | ||
894 | break; | ||
895 | default: | ||
896 | goto done; | ||
897 | } | ||
898 | ret = 0; | ||
899 | if (mt == ID_REQUEST) { | ||
900 | new_tei_req(mgr, &skb->data[4]); | ||
901 | goto done; | ||
902 | } | ||
903 | read_lock_irqsave(&mgr->lock, flags); | ||
904 | list_for_each_entry(l2, &mgr->layer2, list) { | ||
905 | tei_ph_data_ind(l2->tm, mt, &skb->data[4], skb->len - 4); | ||
906 | } | ||
907 | read_unlock_irqrestore(&mgr->lock, flags); | ||
908 | done: | ||
909 | return ret; | ||
910 | } | ||
911 | |||
912 | int | ||
913 | l2_tei(struct layer2 *l2, u_int cmd, u_long arg) | ||
914 | { | ||
915 | struct teimgr *tm = l2->tm; | ||
916 | |||
917 | if (test_bit(FLG_FIXED_TEI, &l2->flag)) | ||
918 | return 0; | ||
919 | if (*debug & DEBUG_L2_TEI) | ||
920 | printk(KERN_DEBUG "%s: cmd(%x)\n", __func__, cmd); | ||
921 | switch (cmd) { | ||
922 | case MDL_ASSIGN_IND: | ||
923 | mISDN_FsmEvent(&tm->tei_m, EV_IDREQ, NULL); | ||
924 | break; | ||
925 | case MDL_ERROR_IND: | ||
926 | if (test_bit(MGR_OPT_NETWORK, &tm->mgr->options)) | ||
927 | mISDN_FsmEvent(&tm->tei_m, EV_CHKREQ, &l2->tei); | ||
928 | if (test_bit(MGR_OPT_USER, &tm->mgr->options)) | ||
929 | mISDN_FsmEvent(&tm->tei_m, EV_VERIFY, NULL); | ||
930 | break; | ||
931 | case MDL_STATUS_UP_IND: | ||
932 | if (test_bit(MGR_OPT_NETWORK, &tm->mgr->options)) | ||
933 | mISDN_FsmEvent(&tm->mgr->deact, EV_ACTIVATE, NULL); | ||
934 | break; | ||
935 | case MDL_STATUS_DOWN_IND: | ||
936 | if (test_bit(MGR_OPT_NETWORK, &tm->mgr->options)) | ||
937 | mISDN_FsmEvent(&tm->mgr->deact, EV_DEACTIVATE, NULL); | ||
938 | break; | ||
939 | case MDL_STATUS_UI_IND: | ||
940 | if (test_bit(MGR_OPT_NETWORK, &tm->mgr->options)) | ||
941 | mISDN_FsmEvent(&tm->mgr->deact, EV_UI, NULL); | ||
942 | break; | ||
943 | } | ||
944 | return 0; | ||
945 | } | ||
946 | |||
947 | void | ||
948 | release_tei(struct layer2 *l2) | ||
949 | { | ||
950 | struct teimgr *tm = l2->tm; | ||
951 | u_long flags; | ||
952 | |||
953 | mISDN_FsmDelTimer(&tm->timer, 1); | ||
954 | write_lock_irqsave(&tm->mgr->lock, flags); | ||
955 | list_del(&l2->list); | ||
956 | write_unlock_irqrestore(&tm->mgr->lock, flags); | ||
957 | l2->tm = NULL; | ||
958 | kfree(tm); | ||
959 | } | ||
960 | |||
961 | static int | ||
962 | create_teimgr(struct manager *mgr, struct channel_req *crq) | ||
963 | { | ||
964 | struct layer2 *l2; | ||
965 | u_long opt = 0; | ||
966 | u_long flags; | ||
967 | int id; | ||
968 | |||
969 | if (*debug & DEBUG_L2_TEI) | ||
970 | printk(KERN_DEBUG "%s: %s proto(%x) adr(%d %d %d %d)\n", | ||
971 | __func__, mgr->ch.st->dev->name, crq->protocol, | ||
972 | crq->adr.dev, crq->adr.channel, crq->adr.sapi, | ||
973 | crq->adr.tei); | ||
974 | if (crq->adr.sapi != 0) /* not supported yet */ | ||
975 | return -EINVAL; | ||
976 | if (crq->adr.tei > GROUP_TEI) | ||
977 | return -EINVAL; | ||
978 | if (crq->adr.tei < 64) | ||
979 | test_and_set_bit(OPTION_L2_FIXEDTEI, &opt); | ||
980 | if (crq->adr.tei == 0) | ||
981 | test_and_set_bit(OPTION_L2_PTP, &opt); | ||
982 | if (test_bit(MGR_OPT_NETWORK, &mgr->options)) { | ||
983 | if (crq->protocol == ISDN_P_LAPD_TE) | ||
984 | return -EPROTONOSUPPORT; | ||
985 | if ((crq->adr.tei != 0) && (crq->adr.tei != 127)) | ||
986 | return -EINVAL; | ||
987 | if (mgr->up) { | ||
988 | printk(KERN_WARNING | ||
989 | "%s: only one network manager is allowed\n", | ||
990 | __func__); | ||
991 | return -EBUSY; | ||
992 | } | ||
993 | } else if (test_bit(MGR_OPT_USER, &mgr->options)) { | ||
994 | if (crq->protocol == ISDN_P_LAPD_NT) | ||
995 | return -EPROTONOSUPPORT; | ||
996 | if ((crq->adr.tei >= 64) && (crq->adr.tei < GROUP_TEI)) | ||
997 | return -EINVAL; /* dyn tei */ | ||
998 | } else { | ||
999 | if (crq->protocol == ISDN_P_LAPD_NT) | ||
1000 | test_and_set_bit(MGR_OPT_NETWORK, &mgr->options); | ||
1001 | if (crq->protocol == ISDN_P_LAPD_TE) | ||
1002 | test_and_set_bit(MGR_OPT_USER, &mgr->options); | ||
1003 | } | ||
1004 | if (mgr->ch.st->dev->Dprotocols | ||
1005 | & ((1 << ISDN_P_TE_E1) | (1 << ISDN_P_NT_E1))) | ||
1006 | test_and_set_bit(OPTION_L2_PMX, &opt); | ||
1007 | if ((crq->protocol == ISDN_P_LAPD_NT) && (crq->adr.tei == 127)) { | ||
1008 | mgr->up = crq->ch; | ||
1009 | id = DL_INFO_L2_CONNECT; | ||
1010 | teiup_create(mgr, DL_INFORMATION_IND, sizeof(id), &id); | ||
1011 | crq->ch = NULL; | ||
1012 | if (!list_empty(&mgr->layer2)) { | ||
1013 | read_lock_irqsave(&mgr->lock, flags); | ||
1014 | list_for_each_entry(l2, &mgr->layer2, list) { | ||
1015 | l2->up = mgr->up; | ||
1016 | l2->ch.ctrl(&l2->ch, OPEN_CHANNEL, NULL); | ||
1017 | } | ||
1018 | read_unlock_irqrestore(&mgr->lock, flags); | ||
1019 | } | ||
1020 | return 0; | ||
1021 | } | ||
1022 | l2 = create_l2(crq->ch, crq->protocol, (u_int)opt, | ||
1023 | (u_long)crq->adr.tei); | ||
1024 | if (!l2) | ||
1025 | return -ENOMEM; | ||
1026 | l2->tm = kzalloc(sizeof(struct teimgr), GFP_KERNEL); | ||
1027 | if (!l2->tm) { | ||
1028 | kfree(l2); | ||
1029 | printk(KERN_ERR "kmalloc teimgr failed\n"); | ||
1030 | return -ENOMEM; | ||
1031 | } | ||
1032 | l2->tm->mgr = mgr; | ||
1033 | l2->tm->l2 = l2; | ||
1034 | l2->tm->tei_m.debug = *debug & DEBUG_L2_TEIFSM; | ||
1035 | l2->tm->tei_m.userdata = l2->tm; | ||
1036 | l2->tm->tei_m.printdebug = tei_debug; | ||
1037 | if (crq->protocol == ISDN_P_LAPD_TE) { | ||
1038 | l2->tm->tei_m.fsm = &teifsmu; | ||
1039 | l2->tm->tei_m.state = ST_TEI_NOP; | ||
1040 | l2->tm->tval = 1000; /* T201 1 sec */ | ||
1041 | } else { | ||
1042 | l2->tm->tei_m.fsm = &teifsmn; | ||
1043 | l2->tm->tei_m.state = ST_TEI_NOP; | ||
1044 | l2->tm->tval = 2000; /* T202 2 sec */ | ||
1045 | } | ||
1046 | mISDN_FsmInitTimer(&l2->tm->tei_m, &l2->tm->timer); | ||
1047 | write_lock_irqsave(&mgr->lock, flags); | ||
1048 | id = get_free_id(mgr); | ||
1049 | list_add_tail(&l2->list, &mgr->layer2); | ||
1050 | write_unlock_irqrestore(&mgr->lock, flags); | ||
1051 | if (id < 0) { | ||
1052 | l2->ch.ctrl(&l2->ch, CLOSE_CHANNEL, NULL); | ||
1053 | } else { | ||
1054 | l2->ch.nr = id; | ||
1055 | l2->up->nr = id; | ||
1056 | crq->ch = &l2->ch; | ||
1057 | id = 0; | ||
1058 | } | ||
1059 | return id; | ||
1060 | } | ||
1061 | |||
1062 | static int | ||
1063 | mgr_send(struct mISDNchannel *ch, struct sk_buff *skb) | ||
1064 | { | ||
1065 | struct manager *mgr; | ||
1066 | struct mISDNhead *hh = mISDN_HEAD_P(skb); | ||
1067 | int ret = -EINVAL; | ||
1068 | |||
1069 | mgr = container_of(ch, struct manager, ch); | ||
1070 | if (*debug & DEBUG_L2_RECV) | ||
1071 | printk(KERN_DEBUG "%s: prim(%x) id(%x)\n", | ||
1072 | __func__, hh->prim, hh->id); | ||
1073 | switch (hh->prim) { | ||
1074 | case PH_DATA_IND: | ||
1075 | mISDN_FsmEvent(&mgr->deact, EV_UI, NULL); | ||
1076 | ret = ph_data_ind(mgr, skb); | ||
1077 | break; | ||
1078 | case PH_DATA_CNF: | ||
1079 | do_ack(mgr, hh->id); | ||
1080 | ret = 0; | ||
1081 | break; | ||
1082 | case PH_ACTIVATE_IND: | ||
1083 | test_and_set_bit(MGR_PH_ACTIVE, &mgr->options); | ||
1084 | mISDN_FsmEvent(&mgr->deact, EV_ACTIVATE_IND, NULL); | ||
1085 | do_send(mgr); | ||
1086 | ret = 0; | ||
1087 | break; | ||
1088 | case PH_DEACTIVATE_IND: | ||
1089 | test_and_clear_bit(MGR_PH_ACTIVE, &mgr->options); | ||
1090 | mISDN_FsmEvent(&mgr->deact, EV_DEACTIVATE_IND, NULL); | ||
1091 | ret = 0; | ||
1092 | break; | ||
1093 | case DL_UNITDATA_REQ: | ||
1094 | return dl_unit_data(mgr, skb); | ||
1095 | } | ||
1096 | if (!ret) | ||
1097 | dev_kfree_skb(skb); | ||
1098 | return ret; | ||
1099 | } | ||
1100 | |||
1101 | static int | ||
1102 | free_teimanager(struct manager *mgr) | ||
1103 | { | ||
1104 | struct layer2 *l2, *nl2; | ||
1105 | |||
1106 | if (test_bit(MGR_OPT_NETWORK, &mgr->options)) { | ||
1107 | /* not locked lock is taken in release tei */ | ||
1108 | mgr->up = NULL; | ||
1109 | if (test_bit(OPTION_L2_CLEANUP, &mgr->options)) { | ||
1110 | list_for_each_entry_safe(l2, nl2, &mgr->layer2, list) { | ||
1111 | put_tei_msg(mgr, ID_REMOVE, 0, l2->tei); | ||
1112 | mutex_lock(&mgr->ch.st->lmutex); | ||
1113 | list_del(&l2->ch.list); | ||
1114 | mutex_unlock(&mgr->ch.st->lmutex); | ||
1115 | l2->ch.ctrl(&l2->ch, CLOSE_CHANNEL, NULL); | ||
1116 | } | ||
1117 | test_and_clear_bit(MGR_OPT_NETWORK, &mgr->options); | ||
1118 | } else { | ||
1119 | list_for_each_entry_safe(l2, nl2, &mgr->layer2, list) { | ||
1120 | l2->up = NULL; | ||
1121 | } | ||
1122 | } | ||
1123 | } | ||
1124 | if (test_bit(MGR_OPT_USER, &mgr->options)) { | ||
1125 | if (list_empty(&mgr->layer2)) | ||
1126 | test_and_clear_bit(MGR_OPT_USER, &mgr->options); | ||
1127 | } | ||
1128 | mgr->ch.st->dev->D.ctrl(&mgr->ch.st->dev->D, CLOSE_CHANNEL, NULL); | ||
1129 | return 0; | ||
1130 | } | ||
1131 | |||
1132 | static int | ||
1133 | ctrl_teimanager(struct manager *mgr, void *arg) | ||
1134 | { | ||
1135 | /* currently we only have one option */ | ||
1136 | int clean = *((int *)arg); | ||
1137 | |||
1138 | if (clean) | ||
1139 | test_and_set_bit(OPTION_L2_CLEANUP, &mgr->options); | ||
1140 | else | ||
1141 | test_and_clear_bit(OPTION_L2_CLEANUP, &mgr->options); | ||
1142 | return 0; | ||
1143 | } | ||
1144 | |||
1145 | /* This function does create a L2 for fixed TEI in NT Mode */ | ||
1146 | static int | ||
1147 | check_data(struct manager *mgr, struct sk_buff *skb) | ||
1148 | { | ||
1149 | struct mISDNhead *hh = mISDN_HEAD_P(skb); | ||
1150 | int ret, tei; | ||
1151 | struct layer2 *l2; | ||
1152 | |||
1153 | if (*debug & DEBUG_L2_CTRL) | ||
1154 | printk(KERN_DEBUG "%s: prim(%x) id(%x)\n", | ||
1155 | __func__, hh->prim, hh->id); | ||
1156 | if (test_bit(MGR_OPT_USER, &mgr->options)) | ||
1157 | return -ENOTCONN; | ||
1158 | if (hh->prim != PH_DATA_IND) | ||
1159 | return -ENOTCONN; | ||
1160 | if (skb->len != 3) | ||
1161 | return -ENOTCONN; | ||
1162 | if (skb->data[0] != 0) | ||
1163 | /* only SAPI 0 command */ | ||
1164 | return -ENOTCONN; | ||
1165 | if (!(skb->data[1] & 1)) /* invalid EA1 */ | ||
1166 | return -EINVAL; | ||
1167 | tei = skb->data[1] >> 0; | ||
1168 | if (tei > 63) /* not a fixed tei */ | ||
1169 | return -ENOTCONN; | ||
1170 | if ((skb->data[2] & ~0x10) != SABME) | ||
1171 | return -ENOTCONN; | ||
1172 | /* We got a SABME for a fixed TEI */ | ||
1173 | l2 = create_new_tei(mgr, tei); | ||
1174 | if (!l2) | ||
1175 | return -ENOMEM; | ||
1176 | ret = l2->ch.send(&l2->ch, skb); | ||
1177 | return ret; | ||
1178 | } | ||
1179 | |||
1180 | void | ||
1181 | delete_teimanager(struct mISDNchannel *ch) | ||
1182 | { | ||
1183 | struct manager *mgr; | ||
1184 | struct layer2 *l2, *nl2; | ||
1185 | |||
1186 | mgr = container_of(ch, struct manager, ch); | ||
1187 | /* not locked lock is taken in release tei */ | ||
1188 | list_for_each_entry_safe(l2, nl2, &mgr->layer2, list) { | ||
1189 | mutex_lock(&mgr->ch.st->lmutex); | ||
1190 | list_del(&l2->ch.list); | ||
1191 | mutex_unlock(&mgr->ch.st->lmutex); | ||
1192 | l2->ch.ctrl(&l2->ch, CLOSE_CHANNEL, NULL); | ||
1193 | } | ||
1194 | list_del(&mgr->ch.list); | ||
1195 | list_del(&mgr->bcast.list); | ||
1196 | skb_queue_purge(&mgr->sendq); | ||
1197 | kfree(mgr); | ||
1198 | } | ||
1199 | |||
1200 | static int | ||
1201 | mgr_ctrl(struct mISDNchannel *ch, u_int cmd, void *arg) | ||
1202 | { | ||
1203 | struct manager *mgr; | ||
1204 | int ret = -EINVAL; | ||
1205 | |||
1206 | mgr = container_of(ch, struct manager, ch); | ||
1207 | if (*debug & DEBUG_L2_CTRL) | ||
1208 | printk(KERN_DEBUG "%s(%x, %p)\n", __func__, cmd, arg); | ||
1209 | switch (cmd) { | ||
1210 | case OPEN_CHANNEL: | ||
1211 | ret = create_teimgr(mgr, arg); | ||
1212 | break; | ||
1213 | case CLOSE_CHANNEL: | ||
1214 | ret = free_teimanager(mgr); | ||
1215 | break; | ||
1216 | case CONTROL_CHANNEL: | ||
1217 | ret = ctrl_teimanager(mgr, arg); | ||
1218 | break; | ||
1219 | case CHECK_DATA: | ||
1220 | ret = check_data(mgr, arg); | ||
1221 | break; | ||
1222 | } | ||
1223 | return ret; | ||
1224 | } | ||
1225 | |||
1226 | static int | ||
1227 | mgr_bcast(struct mISDNchannel *ch, struct sk_buff *skb) | ||
1228 | { | ||
1229 | struct manager *mgr = container_of(ch, struct manager, bcast); | ||
1230 | struct mISDNhead *hh = mISDN_HEAD_P(skb); | ||
1231 | struct sk_buff *cskb = NULL; | ||
1232 | struct layer2 *l2; | ||
1233 | u_long flags; | ||
1234 | int ret; | ||
1235 | |||
1236 | read_lock_irqsave(&mgr->lock, flags); | ||
1237 | list_for_each_entry(l2, &mgr->layer2, list) { | ||
1238 | if ((hh->id & MISDN_ID_SAPI_MASK) == | ||
1239 | (l2->ch.addr & MISDN_ID_SAPI_MASK)) { | ||
1240 | if (list_is_last(&l2->list, &mgr->layer2)) { | ||
1241 | cskb = skb; | ||
1242 | skb = NULL; | ||
1243 | } else { | ||
1244 | if (!cskb) | ||
1245 | cskb = skb_copy(skb, GFP_KERNEL); | ||
1246 | } | ||
1247 | if (cskb) { | ||
1248 | ret = l2->ch.send(&l2->ch, cskb); | ||
1249 | if (ret) { | ||
1250 | if (*debug & DEBUG_SEND_ERR) | ||
1251 | printk(KERN_DEBUG | ||
1252 | "%s ch%d prim(%x) addr(%x)" | ||
1253 | " err %d\n", | ||
1254 | __func__, l2->ch.nr, | ||
1255 | hh->prim, l2->ch.addr, ret); | ||
1256 | } else | ||
1257 | cskb = NULL; | ||
1258 | } else { | ||
1259 | printk(KERN_WARNING "%s ch%d addr %x no mem\n", | ||
1260 | __func__, ch->nr, ch->addr); | ||
1261 | goto out; | ||
1262 | } | ||
1263 | } | ||
1264 | } | ||
1265 | out: | ||
1266 | read_unlock_irqrestore(&mgr->lock, flags); | ||
1267 | if (cskb) | ||
1268 | dev_kfree_skb(cskb); | ||
1269 | if (skb) | ||
1270 | dev_kfree_skb(skb); | ||
1271 | return 0; | ||
1272 | } | ||
1273 | |||
1274 | static int | ||
1275 | mgr_bcast_ctrl(struct mISDNchannel *ch, u_int cmd, void *arg) | ||
1276 | { | ||
1277 | |||
1278 | return -EINVAL; | ||
1279 | } | ||
1280 | |||
1281 | int | ||
1282 | create_teimanager(struct mISDNdevice *dev) | ||
1283 | { | ||
1284 | struct manager *mgr; | ||
1285 | |||
1286 | mgr = kzalloc(sizeof(struct manager), GFP_KERNEL); | ||
1287 | if (!mgr) | ||
1288 | return -ENOMEM; | ||
1289 | INIT_LIST_HEAD(&mgr->layer2); | ||
1290 | mgr->lock = __RW_LOCK_UNLOCKED(mgr->lock); | ||
1291 | skb_queue_head_init(&mgr->sendq); | ||
1292 | mgr->nextid = 1; | ||
1293 | mgr->lastid = MISDN_ID_NONE; | ||
1294 | mgr->ch.send = mgr_send; | ||
1295 | mgr->ch.ctrl = mgr_ctrl; | ||
1296 | mgr->ch.st = dev->D.st; | ||
1297 | set_channel_address(&mgr->ch, TEI_SAPI, GROUP_TEI); | ||
1298 | add_layer2(&mgr->ch, dev->D.st); | ||
1299 | mgr->bcast.send = mgr_bcast; | ||
1300 | mgr->bcast.ctrl = mgr_bcast_ctrl; | ||
1301 | mgr->bcast.st = dev->D.st; | ||
1302 | set_channel_address(&mgr->bcast, 0, GROUP_TEI); | ||
1303 | add_layer2(&mgr->bcast, dev->D.st); | ||
1304 | mgr->deact.debug = *debug & DEBUG_MANAGER; | ||
1305 | mgr->deact.userdata = mgr; | ||
1306 | mgr->deact.printdebug = da_debug; | ||
1307 | mgr->deact.fsm = &deactfsm; | ||
1308 | mgr->deact.state = ST_L1_DEACT; | ||
1309 | mISDN_FsmInitTimer(&mgr->deact, &mgr->datimer); | ||
1310 | dev->teimgr = &mgr->ch; | ||
1311 | return 0; | ||
1312 | } | ||
1313 | |||
1314 | int TEIInit(u_int *deb) | ||
1315 | { | ||
1316 | debug = deb; | ||
1317 | teifsmu.state_count = TEI_STATE_COUNT; | ||
1318 | teifsmu.event_count = TEI_EVENT_COUNT; | ||
1319 | teifsmu.strEvent = strTeiEvent; | ||
1320 | teifsmu.strState = strTeiState; | ||
1321 | mISDN_FsmNew(&teifsmu, TeiFnListUser, ARRAY_SIZE(TeiFnListUser)); | ||
1322 | teifsmn.state_count = TEI_STATE_COUNT; | ||
1323 | teifsmn.event_count = TEI_EVENT_COUNT; | ||
1324 | teifsmn.strEvent = strTeiEvent; | ||
1325 | teifsmn.strState = strTeiState; | ||
1326 | mISDN_FsmNew(&teifsmn, TeiFnListNet, ARRAY_SIZE(TeiFnListNet)); | ||
1327 | deactfsm.state_count = DEACT_STATE_COUNT; | ||
1328 | deactfsm.event_count = DEACT_EVENT_COUNT; | ||
1329 | deactfsm.strEvent = strDeactEvent; | ||
1330 | deactfsm.strState = strDeactState; | ||
1331 | mISDN_FsmNew(&deactfsm, DeactFnList, ARRAY_SIZE(DeactFnList)); | ||
1332 | return 0; | ||
1333 | } | ||
1334 | |||
1335 | void TEIFree(void) | ||
1336 | { | ||
1337 | mISDN_FsmFree(&teifsmu); | ||
1338 | mISDN_FsmFree(&teifsmn); | ||
1339 | mISDN_FsmFree(&deactfsm); | ||
1340 | } | ||