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