1/* $Id: tei.c,v 1.1.1.1 2007/08/03 18:52:36 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
23const char *tei_revision = "$Revision: 1.1.1.1 $";
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
35static struct Fsm teifsm;
36
37void tei_handler(struct PStack *st, u_char pr, struct sk_buff *skb);
38
39enum {
40	ST_TEI_NOP,
41	ST_TEI_IDREQ,
42	ST_TEI_IDVERIFY,
43};
44
45#define TEI_STATE_COUNT (ST_TEI_IDVERIFY+1)
46
47static char *strTeiState[] =
48{
49	"ST_TEI_NOP",
50	"ST_TEI_IDREQ",
51	"ST_TEI_IDVERIFY",
52};
53
54enum {
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
66static 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
77static unsigned int
78random_ri(void)
79{
80	unsigned int x;
81
82	get_random_bytes(&x, sizeof(x));
83	return (x & 0xffff);
84}
85
86static struct PStack *
87findtei(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
102static void
103put_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
125static void
126tei_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
146static void
147tei_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
174static void
175tei_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
195static void
196tei_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
209static void
210tei_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
227static void
228tei_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
248static void
249tei_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
262static void
263tei_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
285static void
286tei_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
308static void
309tei_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
364static void
365tei_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
392static void
393tei_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
403void
404setstack_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
419void
420init_tei(struct IsdnCardState *cs, int protocol)
421{
422}
423
424void
425release_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
435static 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
452int __init
453TeiNew(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
462void
463TeiFree(void)
464{
465	FsmFree(&teifsm);
466}
467