]>
Commit | Line | Data |
---|---|---|
1da177e4 LT |
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" | |
5a0e3ad6 | 20 | #include <linux/gfp.h> |
1da177e4 LT |
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 | ||
672c3fd9 | 78 | static unsigned int |
1da177e4 LT |
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 allready asigned 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 | ||
1da177e4 LT |
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; | |
ba2d6ccb | 458 | return FsmNew(&teifsm, TeiFnList, ARRAY_SIZE(TeiFnList)); |
1da177e4 LT |
459 | } |
460 | ||
461 | void | |
462 | TeiFree(void) | |
463 | { | |
464 | FsmFree(&teifsm); | |
465 | } |