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
24const 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
36static struct Fsm teifsm;
37
38void tei_handler(struct PStack *st, u_char pr, struct sk_buff *skb);
39
40enum {
41	ST_TEI_NOP,
42	ST_TEI_IDREQ,
43	ST_TEI_IDVERIFY,
44};
45
46#define TEI_STATE_COUNT (ST_TEI_IDVERIFY + 1)
47
48static char *strTeiState[] =
49{
50	"ST_TEI_NOP",
51	"ST_TEI_IDREQ",
52	"ST_TEI_IDVERIFY",
53};
54
55enum {
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
67static 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
78static unsigned int
79random_ri(void)
80{
81	unsigned int x;
82
83	get_random_bytes(&x, sizeof(x));
84	return (x & 0xffff);
85}
86
87static struct PStack *
88findtei(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
103static void
104put_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
126static void
127tei_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
147static void
148tei_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
175static void
176tei_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
196static void
197tei_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
210static void
211tei_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
228static void
229tei_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
249static void
250tei_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
263static void
264tei_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
286static void
287tei_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
309static void
310tei_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
365static void
366tei_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
393static void
394tei_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
404void
405setstack_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
420void
421init_tei(struct IsdnCardState *cs, int protocol)
422{
423}
424
425void
426release_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
436static 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
451int __init
452TeiNew(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
461void
462TeiFree(void)
463{
464	FsmFree(&teifsm);
465}
466