/home/lenb/src/to-akpm branch 'acpi-2.6.12'
[linux-2.6] / drivers / isdn / hisax / tei.c
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 static 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 }