diff options
Diffstat (limited to 'drivers/isdn/hisax/tei.c')
-rw-r--r-- | drivers/isdn/hisax/tei.c | 466 |
1 files changed, 466 insertions, 0 deletions
diff --git a/drivers/isdn/hisax/tei.c b/drivers/isdn/hisax/tei.c new file mode 100644 index 000000000000..082726db3985 --- /dev/null +++ b/drivers/isdn/hisax/tei.c | |||
@@ -0,0 +1,466 @@ | |||
1 | /* $Id: tei.c,v 2.20.2.3 2004/01/13 14:31:26 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> | ||
6 | * | ||
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 "hisax.h" | ||
19 | #include "isdnl2.h" | ||
20 | #include <linux/init.h> | ||
21 | #include <linux/random.h> | ||
22 | |||
23 | const char *tei_revision = "$Revision: 2.20.2.3 $"; | ||
24 | |||
25 | #define ID_REQUEST 1 | ||
26 | #define ID_ASSIGNED 2 | ||
27 | #define ID_DENIED 3 | ||
28 | #define ID_CHK_REQ 4 | ||
29 | #define ID_CHK_RES 5 | ||
30 | #define ID_REMOVE 6 | ||
31 | #define ID_VERIFY 7 | ||
32 | |||
33 | #define TEI_ENTITY_ID 0xf | ||
34 | |||
35 | static struct Fsm teifsm; | ||
36 | |||
37 | void tei_handler(struct PStack *st, u_char pr, struct sk_buff *skb); | ||
38 | |||
39 | enum { | ||
40 | ST_TEI_NOP, | ||
41 | ST_TEI_IDREQ, | ||
42 | ST_TEI_IDVERIFY, | ||
43 | }; | ||
44 | |||
45 | #define TEI_STATE_COUNT (ST_TEI_IDVERIFY+1) | ||
46 | |||
47 | static char *strTeiState[] = | ||
48 | { | ||
49 | "ST_TEI_NOP", | ||
50 | "ST_TEI_IDREQ", | ||
51 | "ST_TEI_IDVERIFY", | ||
52 | }; | ||
53 | |||
54 | enum { | ||
55 | EV_IDREQ, | ||
56 | EV_ASSIGN, | ||
57 | EV_DENIED, | ||
58 | EV_CHKREQ, | ||
59 | EV_REMOVE, | ||
60 | EV_VERIFY, | ||
61 | EV_T202, | ||
62 | }; | ||
63 | |||
64 | #define TEI_EVENT_COUNT (EV_T202+1) | ||
65 | |||
66 | static char *strTeiEvent[] = | ||
67 | { | ||
68 | "EV_IDREQ", | ||
69 | "EV_ASSIGN", | ||
70 | "EV_DENIED", | ||
71 | "EV_CHKREQ", | ||
72 | "EV_REMOVE", | ||
73 | "EV_VERIFY", | ||
74 | "EV_T202", | ||
75 | }; | ||
76 | |||
77 | unsigned int | ||
78 | random_ri(void) | ||
79 | { | ||
80 | unsigned int x; | ||
81 | |||
82 | get_random_bytes(&x, sizeof(x)); | ||
83 | return (x & 0xffff); | ||
84 | } | ||
85 | |||
86 | static struct PStack * | ||
87 | findtei(struct PStack *st, int tei) | ||
88 | { | ||
89 | struct PStack *ptr = *(st->l1.stlistp); | ||
90 | |||
91 | if (tei == 127) | ||
92 | return (NULL); | ||
93 | |||
94 | while (ptr) | ||
95 | if (ptr->l2.tei == tei) | ||
96 | return (ptr); | ||
97 | else | ||
98 | ptr = ptr->next; | ||
99 | return (NULL); | ||
100 | } | ||
101 | |||
102 | static void | ||
103 | put_tei_msg(struct PStack *st, u_char m_id, unsigned int ri, u_char tei) | ||
104 | { | ||
105 | struct sk_buff *skb; | ||
106 | u_char *bp; | ||
107 | |||
108 | if (!(skb = alloc_skb(8, GFP_ATOMIC))) { | ||
109 | printk(KERN_WARNING "HiSax: No skb for TEI manager\n"); | ||
110 | return; | ||
111 | } | ||
112 | bp = skb_put(skb, 3); | ||
113 | bp[0] = (TEI_SAPI << 2); | ||
114 | bp[1] = (GROUP_TEI << 1) | 0x1; | ||
115 | bp[2] = UI; | ||
116 | bp = skb_put(skb, 5); | ||
117 | bp[0] = TEI_ENTITY_ID; | ||
118 | bp[1] = ri >> 8; | ||
119 | bp[2] = ri & 0xff; | ||
120 | bp[3] = m_id; | ||
121 | bp[4] = (tei << 1) | 1; | ||
122 | st->l2.l2l1(st, PH_DATA | REQUEST, skb); | ||
123 | } | ||
124 | |||
125 | static void | ||
126 | tei_id_request(struct FsmInst *fi, int event, void *arg) | ||
127 | { | ||
128 | struct PStack *st = fi->userdata; | ||
129 | |||
130 | if (st->l2.tei != -1) { | ||
131 | st->ma.tei_m.printdebug(&st->ma.tei_m, | ||
132 | "assign request for allready asigned tei %d", | ||
133 | st->l2.tei); | ||
134 | return; | ||
135 | } | ||
136 | st->ma.ri = random_ri(); | ||
137 | if (st->ma.debug) | ||
138 | st->ma.tei_m.printdebug(&st->ma.tei_m, | ||
139 | "assign request ri %d", st->ma.ri); | ||
140 | put_tei_msg(st, ID_REQUEST, st->ma.ri, 127); | ||
141 | FsmChangeState(&st->ma.tei_m, ST_TEI_IDREQ); | ||
142 | FsmAddTimer(&st->ma.t202, st->ma.T202, EV_T202, NULL, 1); | ||
143 | st->ma.N202 = 3; | ||
144 | } | ||
145 | |||
146 | static void | ||
147 | tei_id_assign(struct FsmInst *fi, int event, void *arg) | ||
148 | { | ||
149 | struct PStack *ost, *st = fi->userdata; | ||
150 | struct sk_buff *skb = arg; | ||
151 | struct IsdnCardState *cs; | ||
152 | int ri, tei; | ||
153 | |||
154 | ri = ((unsigned int) skb->data[1] << 8) + skb->data[2]; | ||
155 | tei = skb->data[4] >> 1; | ||
156 | if (st->ma.debug) | ||
157 | st->ma.tei_m.printdebug(&st->ma.tei_m, | ||
158 | "identity assign ri %d tei %d", ri, tei); | ||
159 | if ((ost = findtei(st, tei))) { /* same tei is in use */ | ||
160 | if (ri != ost->ma.ri) { | ||
161 | st->ma.tei_m.printdebug(&st->ma.tei_m, | ||
162 | "possible duplicate assignment tei %d", tei); | ||
163 | ost->l2.l2tei(ost, MDL_ERROR | RESPONSE, NULL); | ||
164 | } | ||
165 | } else if (ri == st->ma.ri) { | ||
166 | FsmDelTimer(&st->ma.t202, 1); | ||
167 | FsmChangeState(&st->ma.tei_m, ST_TEI_NOP); | ||
168 | st->l3.l3l2(st, MDL_ASSIGN | REQUEST, (void *) (long) tei); | ||
169 | cs = (struct IsdnCardState *) st->l1.hardware; | ||
170 | cs->cardmsg(cs, MDL_ASSIGN | REQUEST, NULL); | ||
171 | } | ||
172 | } | ||
173 | |||
174 | static void | ||
175 | tei_id_test_dup(struct FsmInst *fi, int event, void *arg) | ||
176 | { | ||
177 | struct PStack *ost, *st = fi->userdata; | ||
178 | struct sk_buff *skb = arg; | ||
179 | int tei, ri; | ||
180 | |||
181 | ri = ((unsigned int) skb->data[1] << 8) + skb->data[2]; | ||
182 | tei = skb->data[4] >> 1; | ||
183 | if (st->ma.debug) | ||
184 | st->ma.tei_m.printdebug(&st->ma.tei_m, | ||
185 | "foreign identity assign ri %d tei %d", ri, tei); | ||
186 | if ((ost = findtei(st, tei))) { /* same tei is in use */ | ||
187 | if (ri != ost->ma.ri) { /* and it wasn't our request */ | ||
188 | st->ma.tei_m.printdebug(&st->ma.tei_m, | ||
189 | "possible duplicate assignment tei %d", tei); | ||
190 | FsmEvent(&ost->ma.tei_m, EV_VERIFY, NULL); | ||
191 | } | ||
192 | } | ||
193 | } | ||
194 | |||
195 | static void | ||
196 | tei_id_denied(struct FsmInst *fi, int event, void *arg) | ||
197 | { | ||
198 | struct PStack *st = fi->userdata; | ||
199 | struct sk_buff *skb = arg; | ||
200 | int ri, tei; | ||
201 | |||
202 | ri = ((unsigned int) skb->data[1] << 8) + skb->data[2]; | ||
203 | tei = skb->data[4] >> 1; | ||
204 | if (st->ma.debug) | ||
205 | st->ma.tei_m.printdebug(&st->ma.tei_m, | ||
206 | "identity denied ri %d tei %d", ri, tei); | ||
207 | } | ||
208 | |||
209 | static void | ||
210 | tei_id_chk_req(struct FsmInst *fi, int event, void *arg) | ||
211 | { | ||
212 | struct PStack *st = fi->userdata; | ||
213 | struct sk_buff *skb = arg; | ||
214 | int tei; | ||
215 | |||
216 | tei = skb->data[4] >> 1; | ||
217 | if (st->ma.debug) | ||
218 | st->ma.tei_m.printdebug(&st->ma.tei_m, | ||
219 | "identity check req tei %d", tei); | ||
220 | if ((st->l2.tei != -1) && ((tei == GROUP_TEI) || (tei == st->l2.tei))) { | ||
221 | FsmDelTimer(&st->ma.t202, 4); | ||
222 | FsmChangeState(&st->ma.tei_m, ST_TEI_NOP); | ||
223 | put_tei_msg(st, ID_CHK_RES, random_ri(), st->l2.tei); | ||
224 | } | ||
225 | } | ||
226 | |||
227 | static void | ||
228 | tei_id_remove(struct FsmInst *fi, int event, void *arg) | ||
229 | { | ||
230 | struct PStack *st = fi->userdata; | ||
231 | struct sk_buff *skb = arg; | ||
232 | struct IsdnCardState *cs; | ||
233 | int tei; | ||
234 | |||
235 | tei = skb->data[4] >> 1; | ||
236 | if (st->ma.debug) | ||
237 | st->ma.tei_m.printdebug(&st->ma.tei_m, | ||
238 | "identity remove tei %d", tei); | ||
239 | if ((st->l2.tei != -1) && ((tei == GROUP_TEI) || (tei == st->l2.tei))) { | ||
240 | FsmDelTimer(&st->ma.t202, 5); | ||
241 | FsmChangeState(&st->ma.tei_m, ST_TEI_NOP); | ||
242 | st->l3.l3l2(st, MDL_REMOVE | REQUEST, NULL); | ||
243 | cs = (struct IsdnCardState *) st->l1.hardware; | ||
244 | cs->cardmsg(cs, MDL_REMOVE | REQUEST, NULL); | ||
245 | } | ||
246 | } | ||
247 | |||
248 | static void | ||
249 | tei_id_verify(struct FsmInst *fi, int event, void *arg) | ||
250 | { | ||
251 | struct PStack *st = fi->userdata; | ||
252 | |||
253 | if (st->ma.debug) | ||
254 | st->ma.tei_m.printdebug(&st->ma.tei_m, | ||
255 | "id verify request for tei %d", st->l2.tei); | ||
256 | put_tei_msg(st, ID_VERIFY, 0, st->l2.tei); | ||
257 | FsmChangeState(&st->ma.tei_m, ST_TEI_IDVERIFY); | ||
258 | FsmAddTimer(&st->ma.t202, st->ma.T202, EV_T202, NULL, 2); | ||
259 | st->ma.N202 = 2; | ||
260 | } | ||
261 | |||
262 | static void | ||
263 | tei_id_req_tout(struct FsmInst *fi, int event, void *arg) | ||
264 | { | ||
265 | struct PStack *st = fi->userdata; | ||
266 | struct IsdnCardState *cs; | ||
267 | |||
268 | if (--st->ma.N202) { | ||
269 | st->ma.ri = random_ri(); | ||
270 | if (st->ma.debug) | ||
271 | st->ma.tei_m.printdebug(&st->ma.tei_m, | ||
272 | "assign req(%d) ri %d", 4 - st->ma.N202, | ||
273 | st->ma.ri); | ||
274 | put_tei_msg(st, ID_REQUEST, st->ma.ri, 127); | ||
275 | FsmAddTimer(&st->ma.t202, st->ma.T202, EV_T202, NULL, 3); | ||
276 | } else { | ||
277 | st->ma.tei_m.printdebug(&st->ma.tei_m, "assign req failed"); | ||
278 | st->l3.l3l2(st, MDL_ERROR | RESPONSE, NULL); | ||
279 | cs = (struct IsdnCardState *) st->l1.hardware; | ||
280 | cs->cardmsg(cs, MDL_REMOVE | REQUEST, NULL); | ||
281 | FsmChangeState(fi, ST_TEI_NOP); | ||
282 | } | ||
283 | } | ||
284 | |||
285 | static void | ||
286 | tei_id_ver_tout(struct FsmInst *fi, int event, void *arg) | ||
287 | { | ||
288 | struct PStack *st = fi->userdata; | ||
289 | struct IsdnCardState *cs; | ||
290 | |||
291 | if (--st->ma.N202) { | ||
292 | if (st->ma.debug) | ||
293 | st->ma.tei_m.printdebug(&st->ma.tei_m, | ||
294 | "id verify req(%d) for tei %d", | ||
295 | 3 - st->ma.N202, st->l2.tei); | ||
296 | put_tei_msg(st, ID_VERIFY, 0, st->l2.tei); | ||
297 | FsmAddTimer(&st->ma.t202, st->ma.T202, EV_T202, NULL, 4); | ||
298 | } else { | ||
299 | st->ma.tei_m.printdebug(&st->ma.tei_m, | ||
300 | "verify req for tei %d failed", st->l2.tei); | ||
301 | st->l3.l3l2(st, MDL_REMOVE | REQUEST, NULL); | ||
302 | cs = (struct IsdnCardState *) st->l1.hardware; | ||
303 | cs->cardmsg(cs, MDL_REMOVE | REQUEST, NULL); | ||
304 | FsmChangeState(fi, ST_TEI_NOP); | ||
305 | } | ||
306 | } | ||
307 | |||
308 | static void | ||
309 | tei_l1l2(struct PStack *st, int pr, void *arg) | ||
310 | { | ||
311 | struct sk_buff *skb = arg; | ||
312 | int mt; | ||
313 | |||
314 | if (test_bit(FLG_FIXED_TEI, &st->l2.flag)) { | ||
315 | dev_kfree_skb(skb); | ||
316 | return; | ||
317 | } | ||
318 | |||
319 | if (pr == (PH_DATA | INDICATION)) { | ||
320 | if (skb->len < 3) { | ||
321 | st->ma.tei_m.printdebug(&st->ma.tei_m, | ||
322 | "short mgr frame %ld/3", skb->len); | ||
323 | } else if ((skb->data[0] != ((TEI_SAPI << 2) | 2)) || | ||
324 | (skb->data[1] != ((GROUP_TEI << 1) | 1))) { | ||
325 | st->ma.tei_m.printdebug(&st->ma.tei_m, | ||
326 | "wrong mgr sapi/tei %x/%x", | ||
327 | skb->data[0], skb->data[1]); | ||
328 | } else if ((skb->data[2] & 0xef) != UI) { | ||
329 | st->ma.tei_m.printdebug(&st->ma.tei_m, | ||
330 | "mgr frame is not ui %x", skb->data[2]); | ||
331 | } else { | ||
332 | skb_pull(skb, 3); | ||
333 | if (skb->len < 5) { | ||
334 | st->ma.tei_m.printdebug(&st->ma.tei_m, | ||
335 | "short mgr frame %ld/5", skb->len); | ||
336 | } else if (skb->data[0] != TEI_ENTITY_ID) { | ||
337 | /* wrong management entity identifier, ignore */ | ||
338 | st->ma.tei_m.printdebug(&st->ma.tei_m, | ||
339 | "tei handler wrong entity id %x", | ||
340 | skb->data[0]); | ||
341 | } else { | ||
342 | mt = skb->data[3]; | ||
343 | if (mt == ID_ASSIGNED) | ||
344 | FsmEvent(&st->ma.tei_m, EV_ASSIGN, skb); | ||
345 | else if (mt == ID_DENIED) | ||
346 | FsmEvent(&st->ma.tei_m, EV_DENIED, skb); | ||
347 | else if (mt == ID_CHK_REQ) | ||
348 | FsmEvent(&st->ma.tei_m, EV_CHKREQ, skb); | ||
349 | else if (mt == ID_REMOVE) | ||
350 | FsmEvent(&st->ma.tei_m, EV_REMOVE, skb); | ||
351 | else { | ||
352 | st->ma.tei_m.printdebug(&st->ma.tei_m, | ||
353 | "tei handler wrong mt %x\n", mt); | ||
354 | } | ||
355 | } | ||
356 | } | ||
357 | } else { | ||
358 | st->ma.tei_m.printdebug(&st->ma.tei_m, | ||
359 | "tei handler wrong pr %x\n", pr); | ||
360 | } | ||
361 | dev_kfree_skb(skb); | ||
362 | } | ||
363 | |||
364 | static void | ||
365 | tei_l2tei(struct PStack *st, int pr, void *arg) | ||
366 | { | ||
367 | struct IsdnCardState *cs; | ||
368 | |||
369 | if (test_bit(FLG_FIXED_TEI, &st->l2.flag)) { | ||
370 | if (pr == (MDL_ASSIGN | INDICATION)) { | ||
371 | if (st->ma.debug) | ||
372 | st->ma.tei_m.printdebug(&st->ma.tei_m, | ||
373 | "fixed assign tei %d", st->l2.tei); | ||
374 | st->l3.l3l2(st, MDL_ASSIGN | REQUEST, (void *) (long) st->l2.tei); | ||
375 | cs = (struct IsdnCardState *) st->l1.hardware; | ||
376 | cs->cardmsg(cs, MDL_ASSIGN | REQUEST, NULL); | ||
377 | } | ||
378 | return; | ||
379 | } | ||
380 | switch (pr) { | ||
381 | case (MDL_ASSIGN | INDICATION): | ||
382 | FsmEvent(&st->ma.tei_m, EV_IDREQ, arg); | ||
383 | break; | ||
384 | case (MDL_ERROR | REQUEST): | ||
385 | FsmEvent(&st->ma.tei_m, EV_VERIFY, arg); | ||
386 | break; | ||
387 | default: | ||
388 | break; | ||
389 | } | ||
390 | } | ||
391 | |||
392 | static void | ||
393 | tei_debug(struct FsmInst *fi, char *fmt, ...) | ||
394 | { | ||
395 | va_list args; | ||
396 | struct PStack *st = fi->userdata; | ||
397 | |||
398 | va_start(args, fmt); | ||
399 | VHiSax_putstatus(st->l1.hardware, "tei ", fmt, args); | ||
400 | va_end(args); | ||
401 | } | ||
402 | |||
403 | void | ||
404 | setstack_tei(struct PStack *st) | ||
405 | { | ||
406 | st->l2.l2tei = tei_l2tei; | ||
407 | st->ma.T202 = 2000; /* T202 2000 milliseconds */ | ||
408 | st->l1.l1tei = tei_l1l2; | ||
409 | st->ma.debug = 1; | ||
410 | st->ma.tei_m.fsm = &teifsm; | ||
411 | st->ma.tei_m.state = ST_TEI_NOP; | ||
412 | st->ma.tei_m.debug = 1; | ||
413 | st->ma.tei_m.userdata = st; | ||
414 | st->ma.tei_m.userint = 0; | ||
415 | st->ma.tei_m.printdebug = tei_debug; | ||
416 | FsmInitTimer(&st->ma.tei_m, &st->ma.t202); | ||
417 | } | ||
418 | |||
419 | void | ||
420 | init_tei(struct IsdnCardState *cs, int protocol) | ||
421 | { | ||
422 | } | ||
423 | |||
424 | void | ||
425 | release_tei(struct IsdnCardState *cs) | ||
426 | { | ||
427 | struct PStack *st = cs->stlist; | ||
428 | |||
429 | while (st) { | ||
430 | FsmDelTimer(&st->ma.t202, 1); | ||
431 | st = st->next; | ||
432 | } | ||
433 | } | ||
434 | |||
435 | static struct FsmNode TeiFnList[] __initdata = | ||
436 | { | ||
437 | {ST_TEI_NOP, EV_IDREQ, tei_id_request}, | ||
438 | {ST_TEI_NOP, EV_ASSIGN, tei_id_test_dup}, | ||
439 | {ST_TEI_NOP, EV_VERIFY, tei_id_verify}, | ||
440 | {ST_TEI_NOP, EV_REMOVE, tei_id_remove}, | ||
441 | {ST_TEI_NOP, EV_CHKREQ, tei_id_chk_req}, | ||
442 | {ST_TEI_IDREQ, EV_T202, tei_id_req_tout}, | ||
443 | {ST_TEI_IDREQ, EV_ASSIGN, tei_id_assign}, | ||
444 | {ST_TEI_IDREQ, EV_DENIED, tei_id_denied}, | ||
445 | {ST_TEI_IDVERIFY, EV_T202, tei_id_ver_tout}, | ||
446 | {ST_TEI_IDVERIFY, EV_REMOVE, tei_id_remove}, | ||
447 | {ST_TEI_IDVERIFY, EV_CHKREQ, tei_id_chk_req}, | ||
448 | }; | ||
449 | |||
450 | #define TEI_FN_COUNT (sizeof(TeiFnList)/sizeof(struct FsmNode)) | ||
451 | |||
452 | int __init | ||
453 | TeiNew(void) | ||
454 | { | ||
455 | teifsm.state_count = TEI_STATE_COUNT; | ||
456 | teifsm.event_count = TEI_EVENT_COUNT; | ||
457 | teifsm.strEvent = strTeiEvent; | ||
458 | teifsm.strState = strTeiState; | ||
459 | return FsmNew(&teifsm, TeiFnList, TEI_FN_COUNT); | ||
460 | } | ||
461 | |||
462 | void | ||
463 | TeiFree(void) | ||
464 | { | ||
465 | FsmFree(&teifsm); | ||
466 | } | ||