1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun *
4*4882a593Smuzhiyun * Author Karsten Keil <kkeil@novell.com>
5*4882a593Smuzhiyun *
6*4882a593Smuzhiyun * Copyright 2008 by Karsten Keil <kkeil@novell.com>
7*4882a593Smuzhiyun */
8*4882a593Smuzhiyun #include "layer2.h"
9*4882a593Smuzhiyun #include <linux/random.h>
10*4882a593Smuzhiyun #include <linux/slab.h>
11*4882a593Smuzhiyun #include "core.h"
12*4882a593Smuzhiyun
13*4882a593Smuzhiyun #define ID_REQUEST 1
14*4882a593Smuzhiyun #define ID_ASSIGNED 2
15*4882a593Smuzhiyun #define ID_DENIED 3
16*4882a593Smuzhiyun #define ID_CHK_REQ 4
17*4882a593Smuzhiyun #define ID_CHK_RES 5
18*4882a593Smuzhiyun #define ID_REMOVE 6
19*4882a593Smuzhiyun #define ID_VERIFY 7
20*4882a593Smuzhiyun
21*4882a593Smuzhiyun #define TEI_ENTITY_ID 0xf
22*4882a593Smuzhiyun
23*4882a593Smuzhiyun #define MGR_PH_ACTIVE 16
24*4882a593Smuzhiyun #define MGR_PH_NOTREADY 17
25*4882a593Smuzhiyun
26*4882a593Smuzhiyun #define DATIMER_VAL 10000
27*4882a593Smuzhiyun
28*4882a593Smuzhiyun static u_int *debug;
29*4882a593Smuzhiyun
30*4882a593Smuzhiyun static struct Fsm deactfsm = {NULL, 0, 0, NULL, NULL};
31*4882a593Smuzhiyun static struct Fsm teifsmu = {NULL, 0, 0, NULL, NULL};
32*4882a593Smuzhiyun static struct Fsm teifsmn = {NULL, 0, 0, NULL, NULL};
33*4882a593Smuzhiyun
34*4882a593Smuzhiyun enum {
35*4882a593Smuzhiyun ST_L1_DEACT,
36*4882a593Smuzhiyun ST_L1_DEACT_PENDING,
37*4882a593Smuzhiyun ST_L1_ACTIV,
38*4882a593Smuzhiyun };
39*4882a593Smuzhiyun #define DEACT_STATE_COUNT (ST_L1_ACTIV + 1)
40*4882a593Smuzhiyun
41*4882a593Smuzhiyun static char *strDeactState[] =
42*4882a593Smuzhiyun {
43*4882a593Smuzhiyun "ST_L1_DEACT",
44*4882a593Smuzhiyun "ST_L1_DEACT_PENDING",
45*4882a593Smuzhiyun "ST_L1_ACTIV",
46*4882a593Smuzhiyun };
47*4882a593Smuzhiyun
48*4882a593Smuzhiyun enum {
49*4882a593Smuzhiyun EV_ACTIVATE,
50*4882a593Smuzhiyun EV_ACTIVATE_IND,
51*4882a593Smuzhiyun EV_DEACTIVATE,
52*4882a593Smuzhiyun EV_DEACTIVATE_IND,
53*4882a593Smuzhiyun EV_UI,
54*4882a593Smuzhiyun EV_DATIMER,
55*4882a593Smuzhiyun };
56*4882a593Smuzhiyun
57*4882a593Smuzhiyun #define DEACT_EVENT_COUNT (EV_DATIMER + 1)
58*4882a593Smuzhiyun
59*4882a593Smuzhiyun static char *strDeactEvent[] =
60*4882a593Smuzhiyun {
61*4882a593Smuzhiyun "EV_ACTIVATE",
62*4882a593Smuzhiyun "EV_ACTIVATE_IND",
63*4882a593Smuzhiyun "EV_DEACTIVATE",
64*4882a593Smuzhiyun "EV_DEACTIVATE_IND",
65*4882a593Smuzhiyun "EV_UI",
66*4882a593Smuzhiyun "EV_DATIMER",
67*4882a593Smuzhiyun };
68*4882a593Smuzhiyun
69*4882a593Smuzhiyun static void
da_debug(struct FsmInst * fi,char * fmt,...)70*4882a593Smuzhiyun da_debug(struct FsmInst *fi, char *fmt, ...)
71*4882a593Smuzhiyun {
72*4882a593Smuzhiyun struct manager *mgr = fi->userdata;
73*4882a593Smuzhiyun struct va_format vaf;
74*4882a593Smuzhiyun va_list va;
75*4882a593Smuzhiyun
76*4882a593Smuzhiyun if (!(*debug & DEBUG_L2_TEIFSM))
77*4882a593Smuzhiyun return;
78*4882a593Smuzhiyun
79*4882a593Smuzhiyun va_start(va, fmt);
80*4882a593Smuzhiyun
81*4882a593Smuzhiyun vaf.fmt = fmt;
82*4882a593Smuzhiyun vaf.va = &va;
83*4882a593Smuzhiyun
84*4882a593Smuzhiyun printk(KERN_DEBUG "mgr(%d): %pV\n", mgr->ch.st->dev->id, &vaf);
85*4882a593Smuzhiyun
86*4882a593Smuzhiyun va_end(va);
87*4882a593Smuzhiyun }
88*4882a593Smuzhiyun
89*4882a593Smuzhiyun static void
da_activate(struct FsmInst * fi,int event,void * arg)90*4882a593Smuzhiyun da_activate(struct FsmInst *fi, int event, void *arg)
91*4882a593Smuzhiyun {
92*4882a593Smuzhiyun struct manager *mgr = fi->userdata;
93*4882a593Smuzhiyun
94*4882a593Smuzhiyun if (fi->state == ST_L1_DEACT_PENDING)
95*4882a593Smuzhiyun mISDN_FsmDelTimer(&mgr->datimer, 1);
96*4882a593Smuzhiyun mISDN_FsmChangeState(fi, ST_L1_ACTIV);
97*4882a593Smuzhiyun }
98*4882a593Smuzhiyun
99*4882a593Smuzhiyun static void
da_deactivate_ind(struct FsmInst * fi,int event,void * arg)100*4882a593Smuzhiyun da_deactivate_ind(struct FsmInst *fi, int event, void *arg)
101*4882a593Smuzhiyun {
102*4882a593Smuzhiyun mISDN_FsmChangeState(fi, ST_L1_DEACT);
103*4882a593Smuzhiyun }
104*4882a593Smuzhiyun
105*4882a593Smuzhiyun static void
da_deactivate(struct FsmInst * fi,int event,void * arg)106*4882a593Smuzhiyun da_deactivate(struct FsmInst *fi, int event, void *arg)
107*4882a593Smuzhiyun {
108*4882a593Smuzhiyun struct manager *mgr = fi->userdata;
109*4882a593Smuzhiyun struct layer2 *l2;
110*4882a593Smuzhiyun u_long flags;
111*4882a593Smuzhiyun
112*4882a593Smuzhiyun read_lock_irqsave(&mgr->lock, flags);
113*4882a593Smuzhiyun list_for_each_entry(l2, &mgr->layer2, list) {
114*4882a593Smuzhiyun if (l2->l2m.state > ST_L2_4) {
115*4882a593Smuzhiyun /* have still activ TEI */
116*4882a593Smuzhiyun read_unlock_irqrestore(&mgr->lock, flags);
117*4882a593Smuzhiyun return;
118*4882a593Smuzhiyun }
119*4882a593Smuzhiyun }
120*4882a593Smuzhiyun read_unlock_irqrestore(&mgr->lock, flags);
121*4882a593Smuzhiyun /* All TEI are inactiv */
122*4882a593Smuzhiyun if (!test_bit(OPTION_L1_HOLD, &mgr->options)) {
123*4882a593Smuzhiyun mISDN_FsmAddTimer(&mgr->datimer, DATIMER_VAL, EV_DATIMER,
124*4882a593Smuzhiyun NULL, 1);
125*4882a593Smuzhiyun mISDN_FsmChangeState(fi, ST_L1_DEACT_PENDING);
126*4882a593Smuzhiyun }
127*4882a593Smuzhiyun }
128*4882a593Smuzhiyun
129*4882a593Smuzhiyun static void
da_ui(struct FsmInst * fi,int event,void * arg)130*4882a593Smuzhiyun da_ui(struct FsmInst *fi, int event, void *arg)
131*4882a593Smuzhiyun {
132*4882a593Smuzhiyun struct manager *mgr = fi->userdata;
133*4882a593Smuzhiyun
134*4882a593Smuzhiyun /* restart da timer */
135*4882a593Smuzhiyun if (!test_bit(OPTION_L1_HOLD, &mgr->options)) {
136*4882a593Smuzhiyun mISDN_FsmDelTimer(&mgr->datimer, 2);
137*4882a593Smuzhiyun mISDN_FsmAddTimer(&mgr->datimer, DATIMER_VAL, EV_DATIMER,
138*4882a593Smuzhiyun NULL, 2);
139*4882a593Smuzhiyun }
140*4882a593Smuzhiyun }
141*4882a593Smuzhiyun
142*4882a593Smuzhiyun static void
da_timer(struct FsmInst * fi,int event,void * arg)143*4882a593Smuzhiyun da_timer(struct FsmInst *fi, int event, void *arg)
144*4882a593Smuzhiyun {
145*4882a593Smuzhiyun struct manager *mgr = fi->userdata;
146*4882a593Smuzhiyun struct layer2 *l2;
147*4882a593Smuzhiyun u_long flags;
148*4882a593Smuzhiyun
149*4882a593Smuzhiyun /* check again */
150*4882a593Smuzhiyun read_lock_irqsave(&mgr->lock, flags);
151*4882a593Smuzhiyun list_for_each_entry(l2, &mgr->layer2, list) {
152*4882a593Smuzhiyun if (l2->l2m.state > ST_L2_4) {
153*4882a593Smuzhiyun /* have still activ TEI */
154*4882a593Smuzhiyun read_unlock_irqrestore(&mgr->lock, flags);
155*4882a593Smuzhiyun mISDN_FsmChangeState(fi, ST_L1_ACTIV);
156*4882a593Smuzhiyun return;
157*4882a593Smuzhiyun }
158*4882a593Smuzhiyun }
159*4882a593Smuzhiyun read_unlock_irqrestore(&mgr->lock, flags);
160*4882a593Smuzhiyun /* All TEI are inactiv */
161*4882a593Smuzhiyun mISDN_FsmChangeState(fi, ST_L1_DEACT);
162*4882a593Smuzhiyun _queue_data(&mgr->ch, PH_DEACTIVATE_REQ, MISDN_ID_ANY, 0, NULL,
163*4882a593Smuzhiyun GFP_ATOMIC);
164*4882a593Smuzhiyun }
165*4882a593Smuzhiyun
166*4882a593Smuzhiyun static struct FsmNode DeactFnList[] =
167*4882a593Smuzhiyun {
168*4882a593Smuzhiyun {ST_L1_DEACT, EV_ACTIVATE_IND, da_activate},
169*4882a593Smuzhiyun {ST_L1_ACTIV, EV_DEACTIVATE_IND, da_deactivate_ind},
170*4882a593Smuzhiyun {ST_L1_ACTIV, EV_DEACTIVATE, da_deactivate},
171*4882a593Smuzhiyun {ST_L1_DEACT_PENDING, EV_ACTIVATE, da_activate},
172*4882a593Smuzhiyun {ST_L1_DEACT_PENDING, EV_UI, da_ui},
173*4882a593Smuzhiyun {ST_L1_DEACT_PENDING, EV_DATIMER, da_timer},
174*4882a593Smuzhiyun };
175*4882a593Smuzhiyun
176*4882a593Smuzhiyun enum {
177*4882a593Smuzhiyun ST_TEI_NOP,
178*4882a593Smuzhiyun ST_TEI_IDREQ,
179*4882a593Smuzhiyun ST_TEI_IDVERIFY,
180*4882a593Smuzhiyun };
181*4882a593Smuzhiyun
182*4882a593Smuzhiyun #define TEI_STATE_COUNT (ST_TEI_IDVERIFY + 1)
183*4882a593Smuzhiyun
184*4882a593Smuzhiyun static char *strTeiState[] =
185*4882a593Smuzhiyun {
186*4882a593Smuzhiyun "ST_TEI_NOP",
187*4882a593Smuzhiyun "ST_TEI_IDREQ",
188*4882a593Smuzhiyun "ST_TEI_IDVERIFY",
189*4882a593Smuzhiyun };
190*4882a593Smuzhiyun
191*4882a593Smuzhiyun enum {
192*4882a593Smuzhiyun EV_IDREQ,
193*4882a593Smuzhiyun EV_ASSIGN,
194*4882a593Smuzhiyun EV_ASSIGN_REQ,
195*4882a593Smuzhiyun EV_DENIED,
196*4882a593Smuzhiyun EV_CHKREQ,
197*4882a593Smuzhiyun EV_CHKRESP,
198*4882a593Smuzhiyun EV_REMOVE,
199*4882a593Smuzhiyun EV_VERIFY,
200*4882a593Smuzhiyun EV_TIMER,
201*4882a593Smuzhiyun };
202*4882a593Smuzhiyun
203*4882a593Smuzhiyun #define TEI_EVENT_COUNT (EV_TIMER + 1)
204*4882a593Smuzhiyun
205*4882a593Smuzhiyun static char *strTeiEvent[] =
206*4882a593Smuzhiyun {
207*4882a593Smuzhiyun "EV_IDREQ",
208*4882a593Smuzhiyun "EV_ASSIGN",
209*4882a593Smuzhiyun "EV_ASSIGN_REQ",
210*4882a593Smuzhiyun "EV_DENIED",
211*4882a593Smuzhiyun "EV_CHKREQ",
212*4882a593Smuzhiyun "EV_CHKRESP",
213*4882a593Smuzhiyun "EV_REMOVE",
214*4882a593Smuzhiyun "EV_VERIFY",
215*4882a593Smuzhiyun "EV_TIMER",
216*4882a593Smuzhiyun };
217*4882a593Smuzhiyun
218*4882a593Smuzhiyun static void
tei_debug(struct FsmInst * fi,char * fmt,...)219*4882a593Smuzhiyun tei_debug(struct FsmInst *fi, char *fmt, ...)
220*4882a593Smuzhiyun {
221*4882a593Smuzhiyun struct teimgr *tm = fi->userdata;
222*4882a593Smuzhiyun struct va_format vaf;
223*4882a593Smuzhiyun va_list va;
224*4882a593Smuzhiyun
225*4882a593Smuzhiyun if (!(*debug & DEBUG_L2_TEIFSM))
226*4882a593Smuzhiyun return;
227*4882a593Smuzhiyun
228*4882a593Smuzhiyun va_start(va, fmt);
229*4882a593Smuzhiyun
230*4882a593Smuzhiyun vaf.fmt = fmt;
231*4882a593Smuzhiyun vaf.va = &va;
232*4882a593Smuzhiyun
233*4882a593Smuzhiyun printk(KERN_DEBUG "sapi(%d) tei(%d): %pV\n",
234*4882a593Smuzhiyun tm->l2->sapi, tm->l2->tei, &vaf);
235*4882a593Smuzhiyun
236*4882a593Smuzhiyun va_end(va);
237*4882a593Smuzhiyun }
238*4882a593Smuzhiyun
239*4882a593Smuzhiyun
240*4882a593Smuzhiyun
241*4882a593Smuzhiyun static int
get_free_id(struct manager * mgr)242*4882a593Smuzhiyun get_free_id(struct manager *mgr)
243*4882a593Smuzhiyun {
244*4882a593Smuzhiyun DECLARE_BITMAP(ids, 64) = { [0 ... BITS_TO_LONGS(64) - 1] = 0 };
245*4882a593Smuzhiyun int i;
246*4882a593Smuzhiyun struct layer2 *l2;
247*4882a593Smuzhiyun
248*4882a593Smuzhiyun list_for_each_entry(l2, &mgr->layer2, list) {
249*4882a593Smuzhiyun if (l2->ch.nr > 63) {
250*4882a593Smuzhiyun printk(KERN_WARNING
251*4882a593Smuzhiyun "%s: more as 63 layer2 for one device\n",
252*4882a593Smuzhiyun __func__);
253*4882a593Smuzhiyun return -EBUSY;
254*4882a593Smuzhiyun }
255*4882a593Smuzhiyun __set_bit(l2->ch.nr, ids);
256*4882a593Smuzhiyun }
257*4882a593Smuzhiyun i = find_next_zero_bit(ids, 64, 1);
258*4882a593Smuzhiyun if (i < 64)
259*4882a593Smuzhiyun return i;
260*4882a593Smuzhiyun printk(KERN_WARNING "%s: more as 63 layer2 for one device\n",
261*4882a593Smuzhiyun __func__);
262*4882a593Smuzhiyun return -EBUSY;
263*4882a593Smuzhiyun }
264*4882a593Smuzhiyun
265*4882a593Smuzhiyun static int
get_free_tei(struct manager * mgr)266*4882a593Smuzhiyun get_free_tei(struct manager *mgr)
267*4882a593Smuzhiyun {
268*4882a593Smuzhiyun DECLARE_BITMAP(ids, 64) = { [0 ... BITS_TO_LONGS(64) - 1] = 0 };
269*4882a593Smuzhiyun int i;
270*4882a593Smuzhiyun struct layer2 *l2;
271*4882a593Smuzhiyun
272*4882a593Smuzhiyun list_for_each_entry(l2, &mgr->layer2, list) {
273*4882a593Smuzhiyun if (l2->ch.nr == 0)
274*4882a593Smuzhiyun continue;
275*4882a593Smuzhiyun if ((l2->ch.addr & 0xff) != 0)
276*4882a593Smuzhiyun continue;
277*4882a593Smuzhiyun i = l2->ch.addr >> 8;
278*4882a593Smuzhiyun if (i < 64)
279*4882a593Smuzhiyun continue;
280*4882a593Smuzhiyun i -= 64;
281*4882a593Smuzhiyun
282*4882a593Smuzhiyun __set_bit(i, ids);
283*4882a593Smuzhiyun }
284*4882a593Smuzhiyun i = find_first_zero_bit(ids, 64);
285*4882a593Smuzhiyun if (i < 64)
286*4882a593Smuzhiyun return i + 64;
287*4882a593Smuzhiyun printk(KERN_WARNING "%s: more as 63 dynamic tei for one device\n",
288*4882a593Smuzhiyun __func__);
289*4882a593Smuzhiyun return -1;
290*4882a593Smuzhiyun }
291*4882a593Smuzhiyun
292*4882a593Smuzhiyun static void
teiup_create(struct manager * mgr,u_int prim,int len,void * arg)293*4882a593Smuzhiyun teiup_create(struct manager *mgr, u_int prim, int len, void *arg)
294*4882a593Smuzhiyun {
295*4882a593Smuzhiyun struct sk_buff *skb;
296*4882a593Smuzhiyun struct mISDNhead *hh;
297*4882a593Smuzhiyun int err;
298*4882a593Smuzhiyun
299*4882a593Smuzhiyun skb = mI_alloc_skb(len, GFP_ATOMIC);
300*4882a593Smuzhiyun if (!skb)
301*4882a593Smuzhiyun return;
302*4882a593Smuzhiyun hh = mISDN_HEAD_P(skb);
303*4882a593Smuzhiyun hh->prim = prim;
304*4882a593Smuzhiyun hh->id = (mgr->ch.nr << 16) | mgr->ch.addr;
305*4882a593Smuzhiyun if (len)
306*4882a593Smuzhiyun skb_put_data(skb, arg, len);
307*4882a593Smuzhiyun err = mgr->up->send(mgr->up, skb);
308*4882a593Smuzhiyun if (err) {
309*4882a593Smuzhiyun printk(KERN_WARNING "%s: err=%d\n", __func__, err);
310*4882a593Smuzhiyun dev_kfree_skb(skb);
311*4882a593Smuzhiyun }
312*4882a593Smuzhiyun }
313*4882a593Smuzhiyun
314*4882a593Smuzhiyun static u_int
new_id(struct manager * mgr)315*4882a593Smuzhiyun new_id(struct manager *mgr)
316*4882a593Smuzhiyun {
317*4882a593Smuzhiyun u_int id;
318*4882a593Smuzhiyun
319*4882a593Smuzhiyun id = mgr->nextid++;
320*4882a593Smuzhiyun if (id == 0x7fff)
321*4882a593Smuzhiyun mgr->nextid = 1;
322*4882a593Smuzhiyun id <<= 16;
323*4882a593Smuzhiyun id |= GROUP_TEI << 8;
324*4882a593Smuzhiyun id |= TEI_SAPI;
325*4882a593Smuzhiyun return id;
326*4882a593Smuzhiyun }
327*4882a593Smuzhiyun
328*4882a593Smuzhiyun static void
do_send(struct manager * mgr)329*4882a593Smuzhiyun do_send(struct manager *mgr)
330*4882a593Smuzhiyun {
331*4882a593Smuzhiyun if (!test_bit(MGR_PH_ACTIVE, &mgr->options))
332*4882a593Smuzhiyun return;
333*4882a593Smuzhiyun
334*4882a593Smuzhiyun if (!test_and_set_bit(MGR_PH_NOTREADY, &mgr->options)) {
335*4882a593Smuzhiyun struct sk_buff *skb = skb_dequeue(&mgr->sendq);
336*4882a593Smuzhiyun
337*4882a593Smuzhiyun if (!skb) {
338*4882a593Smuzhiyun test_and_clear_bit(MGR_PH_NOTREADY, &mgr->options);
339*4882a593Smuzhiyun return;
340*4882a593Smuzhiyun }
341*4882a593Smuzhiyun mgr->lastid = mISDN_HEAD_ID(skb);
342*4882a593Smuzhiyun mISDN_FsmEvent(&mgr->deact, EV_UI, NULL);
343*4882a593Smuzhiyun if (mgr->ch.recv(mgr->ch.peer, skb)) {
344*4882a593Smuzhiyun dev_kfree_skb(skb);
345*4882a593Smuzhiyun test_and_clear_bit(MGR_PH_NOTREADY, &mgr->options);
346*4882a593Smuzhiyun mgr->lastid = MISDN_ID_NONE;
347*4882a593Smuzhiyun }
348*4882a593Smuzhiyun }
349*4882a593Smuzhiyun }
350*4882a593Smuzhiyun
351*4882a593Smuzhiyun static void
do_ack(struct manager * mgr,u_int id)352*4882a593Smuzhiyun do_ack(struct manager *mgr, u_int id)
353*4882a593Smuzhiyun {
354*4882a593Smuzhiyun if (test_bit(MGR_PH_NOTREADY, &mgr->options)) {
355*4882a593Smuzhiyun if (id == mgr->lastid) {
356*4882a593Smuzhiyun if (test_bit(MGR_PH_ACTIVE, &mgr->options)) {
357*4882a593Smuzhiyun struct sk_buff *skb;
358*4882a593Smuzhiyun
359*4882a593Smuzhiyun skb = skb_dequeue(&mgr->sendq);
360*4882a593Smuzhiyun if (skb) {
361*4882a593Smuzhiyun mgr->lastid = mISDN_HEAD_ID(skb);
362*4882a593Smuzhiyun if (!mgr->ch.recv(mgr->ch.peer, skb))
363*4882a593Smuzhiyun return;
364*4882a593Smuzhiyun dev_kfree_skb(skb);
365*4882a593Smuzhiyun }
366*4882a593Smuzhiyun }
367*4882a593Smuzhiyun mgr->lastid = MISDN_ID_NONE;
368*4882a593Smuzhiyun test_and_clear_bit(MGR_PH_NOTREADY, &mgr->options);
369*4882a593Smuzhiyun }
370*4882a593Smuzhiyun }
371*4882a593Smuzhiyun }
372*4882a593Smuzhiyun
373*4882a593Smuzhiyun static void
mgr_send_down(struct manager * mgr,struct sk_buff * skb)374*4882a593Smuzhiyun mgr_send_down(struct manager *mgr, struct sk_buff *skb)
375*4882a593Smuzhiyun {
376*4882a593Smuzhiyun skb_queue_tail(&mgr->sendq, skb);
377*4882a593Smuzhiyun if (!test_bit(MGR_PH_ACTIVE, &mgr->options)) {
378*4882a593Smuzhiyun _queue_data(&mgr->ch, PH_ACTIVATE_REQ, MISDN_ID_ANY, 0,
379*4882a593Smuzhiyun NULL, GFP_KERNEL);
380*4882a593Smuzhiyun } else {
381*4882a593Smuzhiyun do_send(mgr);
382*4882a593Smuzhiyun }
383*4882a593Smuzhiyun }
384*4882a593Smuzhiyun
385*4882a593Smuzhiyun static int
dl_unit_data(struct manager * mgr,struct sk_buff * skb)386*4882a593Smuzhiyun dl_unit_data(struct manager *mgr, struct sk_buff *skb)
387*4882a593Smuzhiyun {
388*4882a593Smuzhiyun if (!test_bit(MGR_OPT_NETWORK, &mgr->options)) /* only net send UI */
389*4882a593Smuzhiyun return -EINVAL;
390*4882a593Smuzhiyun if (!test_bit(MGR_PH_ACTIVE, &mgr->options))
391*4882a593Smuzhiyun _queue_data(&mgr->ch, PH_ACTIVATE_REQ, MISDN_ID_ANY, 0,
392*4882a593Smuzhiyun NULL, GFP_KERNEL);
393*4882a593Smuzhiyun skb_push(skb, 3);
394*4882a593Smuzhiyun skb->data[0] = 0x02; /* SAPI 0 C/R = 1 */
395*4882a593Smuzhiyun skb->data[1] = 0xff; /* TEI 127 */
396*4882a593Smuzhiyun skb->data[2] = UI; /* UI frame */
397*4882a593Smuzhiyun mISDN_HEAD_PRIM(skb) = PH_DATA_REQ;
398*4882a593Smuzhiyun mISDN_HEAD_ID(skb) = new_id(mgr);
399*4882a593Smuzhiyun skb_queue_tail(&mgr->sendq, skb);
400*4882a593Smuzhiyun do_send(mgr);
401*4882a593Smuzhiyun return 0;
402*4882a593Smuzhiyun }
403*4882a593Smuzhiyun
404*4882a593Smuzhiyun static unsigned int
random_ri(void)405*4882a593Smuzhiyun random_ri(void)
406*4882a593Smuzhiyun {
407*4882a593Smuzhiyun u16 x;
408*4882a593Smuzhiyun
409*4882a593Smuzhiyun get_random_bytes(&x, sizeof(x));
410*4882a593Smuzhiyun return x;
411*4882a593Smuzhiyun }
412*4882a593Smuzhiyun
413*4882a593Smuzhiyun static struct layer2 *
findtei(struct manager * mgr,int tei)414*4882a593Smuzhiyun findtei(struct manager *mgr, int tei)
415*4882a593Smuzhiyun {
416*4882a593Smuzhiyun struct layer2 *l2;
417*4882a593Smuzhiyun u_long flags;
418*4882a593Smuzhiyun
419*4882a593Smuzhiyun read_lock_irqsave(&mgr->lock, flags);
420*4882a593Smuzhiyun list_for_each_entry(l2, &mgr->layer2, list) {
421*4882a593Smuzhiyun if ((l2->sapi == 0) && (l2->tei > 0) &&
422*4882a593Smuzhiyun (l2->tei != GROUP_TEI) && (l2->tei == tei))
423*4882a593Smuzhiyun goto done;
424*4882a593Smuzhiyun }
425*4882a593Smuzhiyun l2 = NULL;
426*4882a593Smuzhiyun done:
427*4882a593Smuzhiyun read_unlock_irqrestore(&mgr->lock, flags);
428*4882a593Smuzhiyun return l2;
429*4882a593Smuzhiyun }
430*4882a593Smuzhiyun
431*4882a593Smuzhiyun static void
put_tei_msg(struct manager * mgr,u_char m_id,unsigned int ri,int tei)432*4882a593Smuzhiyun put_tei_msg(struct manager *mgr, u_char m_id, unsigned int ri, int tei)
433*4882a593Smuzhiyun {
434*4882a593Smuzhiyun struct sk_buff *skb;
435*4882a593Smuzhiyun u_char bp[8];
436*4882a593Smuzhiyun
437*4882a593Smuzhiyun bp[0] = (TEI_SAPI << 2);
438*4882a593Smuzhiyun if (test_bit(MGR_OPT_NETWORK, &mgr->options))
439*4882a593Smuzhiyun bp[0] |= 2; /* CR:=1 for net command */
440*4882a593Smuzhiyun bp[1] = (GROUP_TEI << 1) | 0x1;
441*4882a593Smuzhiyun bp[2] = UI;
442*4882a593Smuzhiyun bp[3] = TEI_ENTITY_ID;
443*4882a593Smuzhiyun bp[4] = ri >> 8;
444*4882a593Smuzhiyun bp[5] = ri & 0xff;
445*4882a593Smuzhiyun bp[6] = m_id;
446*4882a593Smuzhiyun bp[7] = ((tei << 1) & 0xff) | 1;
447*4882a593Smuzhiyun skb = _alloc_mISDN_skb(PH_DATA_REQ, new_id(mgr), 8, bp, GFP_ATOMIC);
448*4882a593Smuzhiyun if (!skb) {
449*4882a593Smuzhiyun printk(KERN_WARNING "%s: no skb for tei msg\n", __func__);
450*4882a593Smuzhiyun return;
451*4882a593Smuzhiyun }
452*4882a593Smuzhiyun mgr_send_down(mgr, skb);
453*4882a593Smuzhiyun }
454*4882a593Smuzhiyun
455*4882a593Smuzhiyun static void
tei_id_request(struct FsmInst * fi,int event,void * arg)456*4882a593Smuzhiyun tei_id_request(struct FsmInst *fi, int event, void *arg)
457*4882a593Smuzhiyun {
458*4882a593Smuzhiyun struct teimgr *tm = fi->userdata;
459*4882a593Smuzhiyun
460*4882a593Smuzhiyun if (tm->l2->tei != GROUP_TEI) {
461*4882a593Smuzhiyun tm->tei_m.printdebug(&tm->tei_m,
462*4882a593Smuzhiyun "assign request for already assigned tei %d",
463*4882a593Smuzhiyun tm->l2->tei);
464*4882a593Smuzhiyun return;
465*4882a593Smuzhiyun }
466*4882a593Smuzhiyun tm->ri = random_ri();
467*4882a593Smuzhiyun if (*debug & DEBUG_L2_TEI)
468*4882a593Smuzhiyun tm->tei_m.printdebug(&tm->tei_m,
469*4882a593Smuzhiyun "assign request ri %d", tm->ri);
470*4882a593Smuzhiyun put_tei_msg(tm->mgr, ID_REQUEST, tm->ri, GROUP_TEI);
471*4882a593Smuzhiyun mISDN_FsmChangeState(fi, ST_TEI_IDREQ);
472*4882a593Smuzhiyun mISDN_FsmAddTimer(&tm->timer, tm->tval, EV_TIMER, NULL, 1);
473*4882a593Smuzhiyun tm->nval = 3;
474*4882a593Smuzhiyun }
475*4882a593Smuzhiyun
476*4882a593Smuzhiyun static void
tei_id_assign(struct FsmInst * fi,int event,void * arg)477*4882a593Smuzhiyun tei_id_assign(struct FsmInst *fi, int event, void *arg)
478*4882a593Smuzhiyun {
479*4882a593Smuzhiyun struct teimgr *tm = fi->userdata;
480*4882a593Smuzhiyun struct layer2 *l2;
481*4882a593Smuzhiyun u_char *dp = arg;
482*4882a593Smuzhiyun int ri, tei;
483*4882a593Smuzhiyun
484*4882a593Smuzhiyun ri = ((unsigned int) *dp++ << 8);
485*4882a593Smuzhiyun ri += *dp++;
486*4882a593Smuzhiyun dp++;
487*4882a593Smuzhiyun tei = *dp >> 1;
488*4882a593Smuzhiyun if (*debug & DEBUG_L2_TEI)
489*4882a593Smuzhiyun tm->tei_m.printdebug(fi, "identity assign ri %d tei %d",
490*4882a593Smuzhiyun ri, tei);
491*4882a593Smuzhiyun l2 = findtei(tm->mgr, tei);
492*4882a593Smuzhiyun if (l2) { /* same tei is in use */
493*4882a593Smuzhiyun if (ri != l2->tm->ri) {
494*4882a593Smuzhiyun tm->tei_m.printdebug(fi,
495*4882a593Smuzhiyun "possible duplicate assignment tei %d", tei);
496*4882a593Smuzhiyun tei_l2(l2, MDL_ERROR_RSP, 0);
497*4882a593Smuzhiyun }
498*4882a593Smuzhiyun } else if (ri == tm->ri) {
499*4882a593Smuzhiyun mISDN_FsmDelTimer(&tm->timer, 1);
500*4882a593Smuzhiyun mISDN_FsmChangeState(fi, ST_TEI_NOP);
501*4882a593Smuzhiyun tei_l2(tm->l2, MDL_ASSIGN_REQ, tei);
502*4882a593Smuzhiyun }
503*4882a593Smuzhiyun }
504*4882a593Smuzhiyun
505*4882a593Smuzhiyun static void
tei_id_test_dup(struct FsmInst * fi,int event,void * arg)506*4882a593Smuzhiyun tei_id_test_dup(struct FsmInst *fi, int event, void *arg)
507*4882a593Smuzhiyun {
508*4882a593Smuzhiyun struct teimgr *tm = fi->userdata;
509*4882a593Smuzhiyun struct layer2 *l2;
510*4882a593Smuzhiyun u_char *dp = arg;
511*4882a593Smuzhiyun int tei, ri;
512*4882a593Smuzhiyun
513*4882a593Smuzhiyun ri = ((unsigned int) *dp++ << 8);
514*4882a593Smuzhiyun ri += *dp++;
515*4882a593Smuzhiyun dp++;
516*4882a593Smuzhiyun tei = *dp >> 1;
517*4882a593Smuzhiyun if (*debug & DEBUG_L2_TEI)
518*4882a593Smuzhiyun tm->tei_m.printdebug(fi, "foreign identity assign ri %d tei %d",
519*4882a593Smuzhiyun ri, tei);
520*4882a593Smuzhiyun l2 = findtei(tm->mgr, tei);
521*4882a593Smuzhiyun if (l2) { /* same tei is in use */
522*4882a593Smuzhiyun if (ri != l2->tm->ri) { /* and it wasn't our request */
523*4882a593Smuzhiyun tm->tei_m.printdebug(fi,
524*4882a593Smuzhiyun "possible duplicate assignment tei %d", tei);
525*4882a593Smuzhiyun mISDN_FsmEvent(&l2->tm->tei_m, EV_VERIFY, NULL);
526*4882a593Smuzhiyun }
527*4882a593Smuzhiyun }
528*4882a593Smuzhiyun }
529*4882a593Smuzhiyun
530*4882a593Smuzhiyun static void
tei_id_denied(struct FsmInst * fi,int event,void * arg)531*4882a593Smuzhiyun tei_id_denied(struct FsmInst *fi, int event, void *arg)
532*4882a593Smuzhiyun {
533*4882a593Smuzhiyun struct teimgr *tm = fi->userdata;
534*4882a593Smuzhiyun u_char *dp = arg;
535*4882a593Smuzhiyun int ri, tei;
536*4882a593Smuzhiyun
537*4882a593Smuzhiyun ri = ((unsigned int) *dp++ << 8);
538*4882a593Smuzhiyun ri += *dp++;
539*4882a593Smuzhiyun dp++;
540*4882a593Smuzhiyun tei = *dp >> 1;
541*4882a593Smuzhiyun if (*debug & DEBUG_L2_TEI)
542*4882a593Smuzhiyun tm->tei_m.printdebug(fi, "identity denied ri %d tei %d",
543*4882a593Smuzhiyun ri, tei);
544*4882a593Smuzhiyun }
545*4882a593Smuzhiyun
546*4882a593Smuzhiyun static void
tei_id_chk_req(struct FsmInst * fi,int event,void * arg)547*4882a593Smuzhiyun tei_id_chk_req(struct FsmInst *fi, int event, void *arg)
548*4882a593Smuzhiyun {
549*4882a593Smuzhiyun struct teimgr *tm = fi->userdata;
550*4882a593Smuzhiyun u_char *dp = arg;
551*4882a593Smuzhiyun int tei;
552*4882a593Smuzhiyun
553*4882a593Smuzhiyun tei = *(dp + 3) >> 1;
554*4882a593Smuzhiyun if (*debug & DEBUG_L2_TEI)
555*4882a593Smuzhiyun tm->tei_m.printdebug(fi, "identity check req tei %d", tei);
556*4882a593Smuzhiyun if ((tm->l2->tei != GROUP_TEI) && ((tei == GROUP_TEI) ||
557*4882a593Smuzhiyun (tei == tm->l2->tei))) {
558*4882a593Smuzhiyun mISDN_FsmDelTimer(&tm->timer, 4);
559*4882a593Smuzhiyun mISDN_FsmChangeState(&tm->tei_m, ST_TEI_NOP);
560*4882a593Smuzhiyun put_tei_msg(tm->mgr, ID_CHK_RES, random_ri(), tm->l2->tei);
561*4882a593Smuzhiyun }
562*4882a593Smuzhiyun }
563*4882a593Smuzhiyun
564*4882a593Smuzhiyun static void
tei_id_remove(struct FsmInst * fi,int event,void * arg)565*4882a593Smuzhiyun tei_id_remove(struct FsmInst *fi, int event, void *arg)
566*4882a593Smuzhiyun {
567*4882a593Smuzhiyun struct teimgr *tm = fi->userdata;
568*4882a593Smuzhiyun u_char *dp = arg;
569*4882a593Smuzhiyun int tei;
570*4882a593Smuzhiyun
571*4882a593Smuzhiyun tei = *(dp + 3) >> 1;
572*4882a593Smuzhiyun if (*debug & DEBUG_L2_TEI)
573*4882a593Smuzhiyun tm->tei_m.printdebug(fi, "identity remove tei %d", tei);
574*4882a593Smuzhiyun if ((tm->l2->tei != GROUP_TEI) &&
575*4882a593Smuzhiyun ((tei == GROUP_TEI) || (tei == tm->l2->tei))) {
576*4882a593Smuzhiyun mISDN_FsmDelTimer(&tm->timer, 5);
577*4882a593Smuzhiyun mISDN_FsmChangeState(&tm->tei_m, ST_TEI_NOP);
578*4882a593Smuzhiyun tei_l2(tm->l2, MDL_REMOVE_REQ, 0);
579*4882a593Smuzhiyun }
580*4882a593Smuzhiyun }
581*4882a593Smuzhiyun
582*4882a593Smuzhiyun static void
tei_id_verify(struct FsmInst * fi,int event,void * arg)583*4882a593Smuzhiyun tei_id_verify(struct FsmInst *fi, int event, void *arg)
584*4882a593Smuzhiyun {
585*4882a593Smuzhiyun struct teimgr *tm = fi->userdata;
586*4882a593Smuzhiyun
587*4882a593Smuzhiyun if (*debug & DEBUG_L2_TEI)
588*4882a593Smuzhiyun tm->tei_m.printdebug(fi, "id verify request for tei %d",
589*4882a593Smuzhiyun tm->l2->tei);
590*4882a593Smuzhiyun put_tei_msg(tm->mgr, ID_VERIFY, 0, tm->l2->tei);
591*4882a593Smuzhiyun mISDN_FsmChangeState(&tm->tei_m, ST_TEI_IDVERIFY);
592*4882a593Smuzhiyun mISDN_FsmAddTimer(&tm->timer, tm->tval, EV_TIMER, NULL, 2);
593*4882a593Smuzhiyun tm->nval = 2;
594*4882a593Smuzhiyun }
595*4882a593Smuzhiyun
596*4882a593Smuzhiyun static void
tei_id_req_tout(struct FsmInst * fi,int event,void * arg)597*4882a593Smuzhiyun tei_id_req_tout(struct FsmInst *fi, int event, void *arg)
598*4882a593Smuzhiyun {
599*4882a593Smuzhiyun struct teimgr *tm = fi->userdata;
600*4882a593Smuzhiyun
601*4882a593Smuzhiyun if (--tm->nval) {
602*4882a593Smuzhiyun tm->ri = random_ri();
603*4882a593Smuzhiyun if (*debug & DEBUG_L2_TEI)
604*4882a593Smuzhiyun tm->tei_m.printdebug(fi, "assign req(%d) ri %d",
605*4882a593Smuzhiyun 4 - tm->nval, tm->ri);
606*4882a593Smuzhiyun put_tei_msg(tm->mgr, ID_REQUEST, tm->ri, GROUP_TEI);
607*4882a593Smuzhiyun mISDN_FsmAddTimer(&tm->timer, tm->tval, EV_TIMER, NULL, 3);
608*4882a593Smuzhiyun } else {
609*4882a593Smuzhiyun tm->tei_m.printdebug(fi, "assign req failed");
610*4882a593Smuzhiyun tei_l2(tm->l2, MDL_ERROR_RSP, 0);
611*4882a593Smuzhiyun mISDN_FsmChangeState(fi, ST_TEI_NOP);
612*4882a593Smuzhiyun }
613*4882a593Smuzhiyun }
614*4882a593Smuzhiyun
615*4882a593Smuzhiyun static void
tei_id_ver_tout(struct FsmInst * fi,int event,void * arg)616*4882a593Smuzhiyun tei_id_ver_tout(struct FsmInst *fi, int event, void *arg)
617*4882a593Smuzhiyun {
618*4882a593Smuzhiyun struct teimgr *tm = fi->userdata;
619*4882a593Smuzhiyun
620*4882a593Smuzhiyun if (--tm->nval) {
621*4882a593Smuzhiyun if (*debug & DEBUG_L2_TEI)
622*4882a593Smuzhiyun tm->tei_m.printdebug(fi,
623*4882a593Smuzhiyun "id verify req(%d) for tei %d",
624*4882a593Smuzhiyun 3 - tm->nval, tm->l2->tei);
625*4882a593Smuzhiyun put_tei_msg(tm->mgr, ID_VERIFY, 0, tm->l2->tei);
626*4882a593Smuzhiyun mISDN_FsmAddTimer(&tm->timer, tm->tval, EV_TIMER, NULL, 4);
627*4882a593Smuzhiyun } else {
628*4882a593Smuzhiyun tm->tei_m.printdebug(fi, "verify req for tei %d failed",
629*4882a593Smuzhiyun tm->l2->tei);
630*4882a593Smuzhiyun tei_l2(tm->l2, MDL_REMOVE_REQ, 0);
631*4882a593Smuzhiyun mISDN_FsmChangeState(fi, ST_TEI_NOP);
632*4882a593Smuzhiyun }
633*4882a593Smuzhiyun }
634*4882a593Smuzhiyun
635*4882a593Smuzhiyun static struct FsmNode TeiFnListUser[] =
636*4882a593Smuzhiyun {
637*4882a593Smuzhiyun {ST_TEI_NOP, EV_IDREQ, tei_id_request},
638*4882a593Smuzhiyun {ST_TEI_NOP, EV_ASSIGN, tei_id_test_dup},
639*4882a593Smuzhiyun {ST_TEI_NOP, EV_VERIFY, tei_id_verify},
640*4882a593Smuzhiyun {ST_TEI_NOP, EV_REMOVE, tei_id_remove},
641*4882a593Smuzhiyun {ST_TEI_NOP, EV_CHKREQ, tei_id_chk_req},
642*4882a593Smuzhiyun {ST_TEI_IDREQ, EV_TIMER, tei_id_req_tout},
643*4882a593Smuzhiyun {ST_TEI_IDREQ, EV_ASSIGN, tei_id_assign},
644*4882a593Smuzhiyun {ST_TEI_IDREQ, EV_DENIED, tei_id_denied},
645*4882a593Smuzhiyun {ST_TEI_IDVERIFY, EV_TIMER, tei_id_ver_tout},
646*4882a593Smuzhiyun {ST_TEI_IDVERIFY, EV_REMOVE, tei_id_remove},
647*4882a593Smuzhiyun {ST_TEI_IDVERIFY, EV_CHKREQ, tei_id_chk_req},
648*4882a593Smuzhiyun };
649*4882a593Smuzhiyun
650*4882a593Smuzhiyun static void
tei_l2remove(struct layer2 * l2)651*4882a593Smuzhiyun tei_l2remove(struct layer2 *l2)
652*4882a593Smuzhiyun {
653*4882a593Smuzhiyun put_tei_msg(l2->tm->mgr, ID_REMOVE, 0, l2->tei);
654*4882a593Smuzhiyun tei_l2(l2, MDL_REMOVE_REQ, 0);
655*4882a593Smuzhiyun list_del(&l2->ch.list);
656*4882a593Smuzhiyun l2->ch.ctrl(&l2->ch, CLOSE_CHANNEL, NULL);
657*4882a593Smuzhiyun }
658*4882a593Smuzhiyun
659*4882a593Smuzhiyun static void
tei_assign_req(struct FsmInst * fi,int event,void * arg)660*4882a593Smuzhiyun tei_assign_req(struct FsmInst *fi, int event, void *arg)
661*4882a593Smuzhiyun {
662*4882a593Smuzhiyun struct teimgr *tm = fi->userdata;
663*4882a593Smuzhiyun u_char *dp = arg;
664*4882a593Smuzhiyun
665*4882a593Smuzhiyun if (tm->l2->tei == GROUP_TEI) {
666*4882a593Smuzhiyun tm->tei_m.printdebug(&tm->tei_m,
667*4882a593Smuzhiyun "net tei assign request without tei");
668*4882a593Smuzhiyun return;
669*4882a593Smuzhiyun }
670*4882a593Smuzhiyun tm->ri = ((unsigned int) *dp++ << 8);
671*4882a593Smuzhiyun tm->ri += *dp++;
672*4882a593Smuzhiyun if (*debug & DEBUG_L2_TEI)
673*4882a593Smuzhiyun tm->tei_m.printdebug(&tm->tei_m,
674*4882a593Smuzhiyun "net assign request ri %d teim %d", tm->ri, *dp);
675*4882a593Smuzhiyun put_tei_msg(tm->mgr, ID_ASSIGNED, tm->ri, tm->l2->tei);
676*4882a593Smuzhiyun mISDN_FsmChangeState(fi, ST_TEI_NOP);
677*4882a593Smuzhiyun }
678*4882a593Smuzhiyun
679*4882a593Smuzhiyun static void
tei_id_chk_req_net(struct FsmInst * fi,int event,void * arg)680*4882a593Smuzhiyun tei_id_chk_req_net(struct FsmInst *fi, int event, void *arg)
681*4882a593Smuzhiyun {
682*4882a593Smuzhiyun struct teimgr *tm = fi->userdata;
683*4882a593Smuzhiyun
684*4882a593Smuzhiyun if (*debug & DEBUG_L2_TEI)
685*4882a593Smuzhiyun tm->tei_m.printdebug(fi, "id check request for tei %d",
686*4882a593Smuzhiyun tm->l2->tei);
687*4882a593Smuzhiyun tm->rcnt = 0;
688*4882a593Smuzhiyun put_tei_msg(tm->mgr, ID_CHK_REQ, 0, tm->l2->tei);
689*4882a593Smuzhiyun mISDN_FsmChangeState(&tm->tei_m, ST_TEI_IDVERIFY);
690*4882a593Smuzhiyun mISDN_FsmAddTimer(&tm->timer, tm->tval, EV_TIMER, NULL, 2);
691*4882a593Smuzhiyun tm->nval = 2;
692*4882a593Smuzhiyun }
693*4882a593Smuzhiyun
694*4882a593Smuzhiyun static void
tei_id_chk_resp(struct FsmInst * fi,int event,void * arg)695*4882a593Smuzhiyun tei_id_chk_resp(struct FsmInst *fi, int event, void *arg)
696*4882a593Smuzhiyun {
697*4882a593Smuzhiyun struct teimgr *tm = fi->userdata;
698*4882a593Smuzhiyun u_char *dp = arg;
699*4882a593Smuzhiyun int tei;
700*4882a593Smuzhiyun
701*4882a593Smuzhiyun tei = dp[3] >> 1;
702*4882a593Smuzhiyun if (*debug & DEBUG_L2_TEI)
703*4882a593Smuzhiyun tm->tei_m.printdebug(fi, "identity check resp tei %d", tei);
704*4882a593Smuzhiyun if (tei == tm->l2->tei)
705*4882a593Smuzhiyun tm->rcnt++;
706*4882a593Smuzhiyun }
707*4882a593Smuzhiyun
708*4882a593Smuzhiyun static void
tei_id_verify_net(struct FsmInst * fi,int event,void * arg)709*4882a593Smuzhiyun tei_id_verify_net(struct FsmInst *fi, int event, void *arg)
710*4882a593Smuzhiyun {
711*4882a593Smuzhiyun struct teimgr *tm = fi->userdata;
712*4882a593Smuzhiyun u_char *dp = arg;
713*4882a593Smuzhiyun int tei;
714*4882a593Smuzhiyun
715*4882a593Smuzhiyun tei = dp[3] >> 1;
716*4882a593Smuzhiyun if (*debug & DEBUG_L2_TEI)
717*4882a593Smuzhiyun tm->tei_m.printdebug(fi, "identity verify req tei %d/%d",
718*4882a593Smuzhiyun tei, tm->l2->tei);
719*4882a593Smuzhiyun if (tei == tm->l2->tei)
720*4882a593Smuzhiyun tei_id_chk_req_net(fi, event, arg);
721*4882a593Smuzhiyun }
722*4882a593Smuzhiyun
723*4882a593Smuzhiyun static void
tei_id_ver_tout_net(struct FsmInst * fi,int event,void * arg)724*4882a593Smuzhiyun tei_id_ver_tout_net(struct FsmInst *fi, int event, void *arg)
725*4882a593Smuzhiyun {
726*4882a593Smuzhiyun struct teimgr *tm = fi->userdata;
727*4882a593Smuzhiyun
728*4882a593Smuzhiyun if (tm->rcnt == 1) {
729*4882a593Smuzhiyun if (*debug & DEBUG_L2_TEI)
730*4882a593Smuzhiyun tm->tei_m.printdebug(fi,
731*4882a593Smuzhiyun "check req for tei %d successful\n", tm->l2->tei);
732*4882a593Smuzhiyun mISDN_FsmChangeState(fi, ST_TEI_NOP);
733*4882a593Smuzhiyun } else if (tm->rcnt > 1) {
734*4882a593Smuzhiyun /* duplicate assignment; remove */
735*4882a593Smuzhiyun tei_l2remove(tm->l2);
736*4882a593Smuzhiyun } else if (--tm->nval) {
737*4882a593Smuzhiyun if (*debug & DEBUG_L2_TEI)
738*4882a593Smuzhiyun tm->tei_m.printdebug(fi,
739*4882a593Smuzhiyun "id check req(%d) for tei %d",
740*4882a593Smuzhiyun 3 - tm->nval, tm->l2->tei);
741*4882a593Smuzhiyun put_tei_msg(tm->mgr, ID_CHK_REQ, 0, tm->l2->tei);
742*4882a593Smuzhiyun mISDN_FsmAddTimer(&tm->timer, tm->tval, EV_TIMER, NULL, 4);
743*4882a593Smuzhiyun } else {
744*4882a593Smuzhiyun tm->tei_m.printdebug(fi, "check req for tei %d failed",
745*4882a593Smuzhiyun tm->l2->tei);
746*4882a593Smuzhiyun mISDN_FsmChangeState(fi, ST_TEI_NOP);
747*4882a593Smuzhiyun tei_l2remove(tm->l2);
748*4882a593Smuzhiyun }
749*4882a593Smuzhiyun }
750*4882a593Smuzhiyun
751*4882a593Smuzhiyun static struct FsmNode TeiFnListNet[] =
752*4882a593Smuzhiyun {
753*4882a593Smuzhiyun {ST_TEI_NOP, EV_ASSIGN_REQ, tei_assign_req},
754*4882a593Smuzhiyun {ST_TEI_NOP, EV_VERIFY, tei_id_verify_net},
755*4882a593Smuzhiyun {ST_TEI_NOP, EV_CHKREQ, tei_id_chk_req_net},
756*4882a593Smuzhiyun {ST_TEI_IDVERIFY, EV_TIMER, tei_id_ver_tout_net},
757*4882a593Smuzhiyun {ST_TEI_IDVERIFY, EV_CHKRESP, tei_id_chk_resp},
758*4882a593Smuzhiyun };
759*4882a593Smuzhiyun
760*4882a593Smuzhiyun static void
tei_ph_data_ind(struct teimgr * tm,u_int mt,u_char * dp,int len)761*4882a593Smuzhiyun tei_ph_data_ind(struct teimgr *tm, u_int mt, u_char *dp, int len)
762*4882a593Smuzhiyun {
763*4882a593Smuzhiyun if (test_bit(FLG_FIXED_TEI, &tm->l2->flag))
764*4882a593Smuzhiyun return;
765*4882a593Smuzhiyun if (*debug & DEBUG_L2_TEI)
766*4882a593Smuzhiyun tm->tei_m.printdebug(&tm->tei_m, "tei handler mt %x", mt);
767*4882a593Smuzhiyun if (mt == ID_ASSIGNED)
768*4882a593Smuzhiyun mISDN_FsmEvent(&tm->tei_m, EV_ASSIGN, dp);
769*4882a593Smuzhiyun else if (mt == ID_DENIED)
770*4882a593Smuzhiyun mISDN_FsmEvent(&tm->tei_m, EV_DENIED, dp);
771*4882a593Smuzhiyun else if (mt == ID_CHK_REQ)
772*4882a593Smuzhiyun mISDN_FsmEvent(&tm->tei_m, EV_CHKREQ, dp);
773*4882a593Smuzhiyun else if (mt == ID_REMOVE)
774*4882a593Smuzhiyun mISDN_FsmEvent(&tm->tei_m, EV_REMOVE, dp);
775*4882a593Smuzhiyun else if (mt == ID_VERIFY)
776*4882a593Smuzhiyun mISDN_FsmEvent(&tm->tei_m, EV_VERIFY, dp);
777*4882a593Smuzhiyun else if (mt == ID_CHK_RES)
778*4882a593Smuzhiyun mISDN_FsmEvent(&tm->tei_m, EV_CHKRESP, dp);
779*4882a593Smuzhiyun }
780*4882a593Smuzhiyun
781*4882a593Smuzhiyun static struct layer2 *
create_new_tei(struct manager * mgr,int tei,int sapi)782*4882a593Smuzhiyun create_new_tei(struct manager *mgr, int tei, int sapi)
783*4882a593Smuzhiyun {
784*4882a593Smuzhiyun unsigned long opt = 0;
785*4882a593Smuzhiyun unsigned long flags;
786*4882a593Smuzhiyun int id;
787*4882a593Smuzhiyun struct layer2 *l2;
788*4882a593Smuzhiyun struct channel_req rq;
789*4882a593Smuzhiyun
790*4882a593Smuzhiyun if (!mgr->up)
791*4882a593Smuzhiyun return NULL;
792*4882a593Smuzhiyun if ((tei >= 0) && (tei < 64))
793*4882a593Smuzhiyun test_and_set_bit(OPTION_L2_FIXEDTEI, &opt);
794*4882a593Smuzhiyun if (mgr->ch.st->dev->Dprotocols & ((1 << ISDN_P_TE_E1) |
795*4882a593Smuzhiyun (1 << ISDN_P_NT_E1))) {
796*4882a593Smuzhiyun test_and_set_bit(OPTION_L2_PMX, &opt);
797*4882a593Smuzhiyun rq.protocol = ISDN_P_NT_E1;
798*4882a593Smuzhiyun } else {
799*4882a593Smuzhiyun rq.protocol = ISDN_P_NT_S0;
800*4882a593Smuzhiyun }
801*4882a593Smuzhiyun l2 = create_l2(mgr->up, ISDN_P_LAPD_NT, opt, tei, sapi);
802*4882a593Smuzhiyun if (!l2) {
803*4882a593Smuzhiyun printk(KERN_WARNING "%s:no memory for layer2\n", __func__);
804*4882a593Smuzhiyun return NULL;
805*4882a593Smuzhiyun }
806*4882a593Smuzhiyun l2->tm = kzalloc(sizeof(struct teimgr), GFP_KERNEL);
807*4882a593Smuzhiyun if (!l2->tm) {
808*4882a593Smuzhiyun kfree(l2);
809*4882a593Smuzhiyun printk(KERN_WARNING "%s:no memory for teimgr\n", __func__);
810*4882a593Smuzhiyun return NULL;
811*4882a593Smuzhiyun }
812*4882a593Smuzhiyun l2->tm->mgr = mgr;
813*4882a593Smuzhiyun l2->tm->l2 = l2;
814*4882a593Smuzhiyun l2->tm->tei_m.debug = *debug & DEBUG_L2_TEIFSM;
815*4882a593Smuzhiyun l2->tm->tei_m.userdata = l2->tm;
816*4882a593Smuzhiyun l2->tm->tei_m.printdebug = tei_debug;
817*4882a593Smuzhiyun l2->tm->tei_m.fsm = &teifsmn;
818*4882a593Smuzhiyun l2->tm->tei_m.state = ST_TEI_NOP;
819*4882a593Smuzhiyun l2->tm->tval = 2000; /* T202 2 sec */
820*4882a593Smuzhiyun mISDN_FsmInitTimer(&l2->tm->tei_m, &l2->tm->timer);
821*4882a593Smuzhiyun write_lock_irqsave(&mgr->lock, flags);
822*4882a593Smuzhiyun id = get_free_id(mgr);
823*4882a593Smuzhiyun list_add_tail(&l2->list, &mgr->layer2);
824*4882a593Smuzhiyun write_unlock_irqrestore(&mgr->lock, flags);
825*4882a593Smuzhiyun if (id < 0) {
826*4882a593Smuzhiyun l2->ch.ctrl(&l2->ch, CLOSE_CHANNEL, NULL);
827*4882a593Smuzhiyun printk(KERN_WARNING "%s:no free id\n", __func__);
828*4882a593Smuzhiyun return NULL;
829*4882a593Smuzhiyun } else {
830*4882a593Smuzhiyun l2->ch.nr = id;
831*4882a593Smuzhiyun __add_layer2(&l2->ch, mgr->ch.st);
832*4882a593Smuzhiyun l2->ch.recv = mgr->ch.recv;
833*4882a593Smuzhiyun l2->ch.peer = mgr->ch.peer;
834*4882a593Smuzhiyun l2->ch.ctrl(&l2->ch, OPEN_CHANNEL, NULL);
835*4882a593Smuzhiyun /* We need open here L1 for the manager as well (refcounting) */
836*4882a593Smuzhiyun rq.adr.dev = mgr->ch.st->dev->id;
837*4882a593Smuzhiyun id = mgr->ch.st->own.ctrl(&mgr->ch.st->own, OPEN_CHANNEL, &rq);
838*4882a593Smuzhiyun if (id < 0) {
839*4882a593Smuzhiyun printk(KERN_WARNING "%s: cannot open L1\n", __func__);
840*4882a593Smuzhiyun l2->ch.ctrl(&l2->ch, CLOSE_CHANNEL, NULL);
841*4882a593Smuzhiyun l2 = NULL;
842*4882a593Smuzhiyun }
843*4882a593Smuzhiyun }
844*4882a593Smuzhiyun return l2;
845*4882a593Smuzhiyun }
846*4882a593Smuzhiyun
847*4882a593Smuzhiyun static void
new_tei_req(struct manager * mgr,u_char * dp)848*4882a593Smuzhiyun new_tei_req(struct manager *mgr, u_char *dp)
849*4882a593Smuzhiyun {
850*4882a593Smuzhiyun int tei, ri;
851*4882a593Smuzhiyun struct layer2 *l2;
852*4882a593Smuzhiyun
853*4882a593Smuzhiyun ri = dp[0] << 8;
854*4882a593Smuzhiyun ri += dp[1];
855*4882a593Smuzhiyun if (!mgr->up)
856*4882a593Smuzhiyun goto denied;
857*4882a593Smuzhiyun if (!(dp[3] & 1)) /* Extension bit != 1 */
858*4882a593Smuzhiyun goto denied;
859*4882a593Smuzhiyun if (dp[3] != 0xff)
860*4882a593Smuzhiyun tei = dp[3] >> 1; /* 3GPP TS 08.56 6.1.11.2 */
861*4882a593Smuzhiyun else
862*4882a593Smuzhiyun tei = get_free_tei(mgr);
863*4882a593Smuzhiyun if (tei < 0) {
864*4882a593Smuzhiyun printk(KERN_WARNING "%s:No free tei\n", __func__);
865*4882a593Smuzhiyun goto denied;
866*4882a593Smuzhiyun }
867*4882a593Smuzhiyun l2 = create_new_tei(mgr, tei, CTRL_SAPI);
868*4882a593Smuzhiyun if (!l2)
869*4882a593Smuzhiyun goto denied;
870*4882a593Smuzhiyun else
871*4882a593Smuzhiyun mISDN_FsmEvent(&l2->tm->tei_m, EV_ASSIGN_REQ, dp);
872*4882a593Smuzhiyun return;
873*4882a593Smuzhiyun denied:
874*4882a593Smuzhiyun put_tei_msg(mgr, ID_DENIED, ri, GROUP_TEI);
875*4882a593Smuzhiyun }
876*4882a593Smuzhiyun
877*4882a593Smuzhiyun static int
ph_data_ind(struct manager * mgr,struct sk_buff * skb)878*4882a593Smuzhiyun ph_data_ind(struct manager *mgr, struct sk_buff *skb)
879*4882a593Smuzhiyun {
880*4882a593Smuzhiyun int ret = -EINVAL;
881*4882a593Smuzhiyun struct layer2 *l2, *nl2;
882*4882a593Smuzhiyun u_char mt;
883*4882a593Smuzhiyun
884*4882a593Smuzhiyun if (skb->len < 8) {
885*4882a593Smuzhiyun if (*debug & DEBUG_L2_TEI)
886*4882a593Smuzhiyun printk(KERN_DEBUG "%s: short mgr frame %d/8\n",
887*4882a593Smuzhiyun __func__, skb->len);
888*4882a593Smuzhiyun goto done;
889*4882a593Smuzhiyun }
890*4882a593Smuzhiyun
891*4882a593Smuzhiyun if ((skb->data[0] >> 2) != TEI_SAPI) /* not for us */
892*4882a593Smuzhiyun goto done;
893*4882a593Smuzhiyun if (skb->data[0] & 1) /* EA0 formal error */
894*4882a593Smuzhiyun goto done;
895*4882a593Smuzhiyun if (!(skb->data[1] & 1)) /* EA1 formal error */
896*4882a593Smuzhiyun goto done;
897*4882a593Smuzhiyun if ((skb->data[1] >> 1) != GROUP_TEI) /* not for us */
898*4882a593Smuzhiyun goto done;
899*4882a593Smuzhiyun if ((skb->data[2] & 0xef) != UI) /* not UI */
900*4882a593Smuzhiyun goto done;
901*4882a593Smuzhiyun if (skb->data[3] != TEI_ENTITY_ID) /* not tei entity */
902*4882a593Smuzhiyun goto done;
903*4882a593Smuzhiyun mt = skb->data[6];
904*4882a593Smuzhiyun switch (mt) {
905*4882a593Smuzhiyun case ID_REQUEST:
906*4882a593Smuzhiyun case ID_CHK_RES:
907*4882a593Smuzhiyun case ID_VERIFY:
908*4882a593Smuzhiyun if (!test_bit(MGR_OPT_NETWORK, &mgr->options))
909*4882a593Smuzhiyun goto done;
910*4882a593Smuzhiyun break;
911*4882a593Smuzhiyun case ID_ASSIGNED:
912*4882a593Smuzhiyun case ID_DENIED:
913*4882a593Smuzhiyun case ID_CHK_REQ:
914*4882a593Smuzhiyun case ID_REMOVE:
915*4882a593Smuzhiyun if (test_bit(MGR_OPT_NETWORK, &mgr->options))
916*4882a593Smuzhiyun goto done;
917*4882a593Smuzhiyun break;
918*4882a593Smuzhiyun default:
919*4882a593Smuzhiyun goto done;
920*4882a593Smuzhiyun }
921*4882a593Smuzhiyun ret = 0;
922*4882a593Smuzhiyun if (mt == ID_REQUEST) {
923*4882a593Smuzhiyun new_tei_req(mgr, &skb->data[4]);
924*4882a593Smuzhiyun goto done;
925*4882a593Smuzhiyun }
926*4882a593Smuzhiyun list_for_each_entry_safe(l2, nl2, &mgr->layer2, list) {
927*4882a593Smuzhiyun tei_ph_data_ind(l2->tm, mt, &skb->data[4], skb->len - 4);
928*4882a593Smuzhiyun }
929*4882a593Smuzhiyun done:
930*4882a593Smuzhiyun return ret;
931*4882a593Smuzhiyun }
932*4882a593Smuzhiyun
933*4882a593Smuzhiyun int
l2_tei(struct layer2 * l2,u_int cmd,u_long arg)934*4882a593Smuzhiyun l2_tei(struct layer2 *l2, u_int cmd, u_long arg)
935*4882a593Smuzhiyun {
936*4882a593Smuzhiyun struct teimgr *tm = l2->tm;
937*4882a593Smuzhiyun
938*4882a593Smuzhiyun if (test_bit(FLG_FIXED_TEI, &l2->flag))
939*4882a593Smuzhiyun return 0;
940*4882a593Smuzhiyun if (*debug & DEBUG_L2_TEI)
941*4882a593Smuzhiyun printk(KERN_DEBUG "%s: cmd(%x)\n", __func__, cmd);
942*4882a593Smuzhiyun switch (cmd) {
943*4882a593Smuzhiyun case MDL_ASSIGN_IND:
944*4882a593Smuzhiyun mISDN_FsmEvent(&tm->tei_m, EV_IDREQ, NULL);
945*4882a593Smuzhiyun break;
946*4882a593Smuzhiyun case MDL_ERROR_IND:
947*4882a593Smuzhiyun if (test_bit(MGR_OPT_NETWORK, &tm->mgr->options))
948*4882a593Smuzhiyun mISDN_FsmEvent(&tm->tei_m, EV_CHKREQ, &l2->tei);
949*4882a593Smuzhiyun if (test_bit(MGR_OPT_USER, &tm->mgr->options))
950*4882a593Smuzhiyun mISDN_FsmEvent(&tm->tei_m, EV_VERIFY, NULL);
951*4882a593Smuzhiyun break;
952*4882a593Smuzhiyun case MDL_STATUS_UP_IND:
953*4882a593Smuzhiyun if (test_bit(MGR_OPT_NETWORK, &tm->mgr->options))
954*4882a593Smuzhiyun mISDN_FsmEvent(&tm->mgr->deact, EV_ACTIVATE, NULL);
955*4882a593Smuzhiyun break;
956*4882a593Smuzhiyun case MDL_STATUS_DOWN_IND:
957*4882a593Smuzhiyun if (test_bit(MGR_OPT_NETWORK, &tm->mgr->options))
958*4882a593Smuzhiyun mISDN_FsmEvent(&tm->mgr->deact, EV_DEACTIVATE, NULL);
959*4882a593Smuzhiyun break;
960*4882a593Smuzhiyun case MDL_STATUS_UI_IND:
961*4882a593Smuzhiyun if (test_bit(MGR_OPT_NETWORK, &tm->mgr->options))
962*4882a593Smuzhiyun mISDN_FsmEvent(&tm->mgr->deact, EV_UI, NULL);
963*4882a593Smuzhiyun break;
964*4882a593Smuzhiyun }
965*4882a593Smuzhiyun return 0;
966*4882a593Smuzhiyun }
967*4882a593Smuzhiyun
968*4882a593Smuzhiyun void
TEIrelease(struct layer2 * l2)969*4882a593Smuzhiyun TEIrelease(struct layer2 *l2)
970*4882a593Smuzhiyun {
971*4882a593Smuzhiyun struct teimgr *tm = l2->tm;
972*4882a593Smuzhiyun u_long flags;
973*4882a593Smuzhiyun
974*4882a593Smuzhiyun mISDN_FsmDelTimer(&tm->timer, 1);
975*4882a593Smuzhiyun write_lock_irqsave(&tm->mgr->lock, flags);
976*4882a593Smuzhiyun list_del(&l2->list);
977*4882a593Smuzhiyun write_unlock_irqrestore(&tm->mgr->lock, flags);
978*4882a593Smuzhiyun l2->tm = NULL;
979*4882a593Smuzhiyun kfree(tm);
980*4882a593Smuzhiyun }
981*4882a593Smuzhiyun
982*4882a593Smuzhiyun static int
create_teimgr(struct manager * mgr,struct channel_req * crq)983*4882a593Smuzhiyun create_teimgr(struct manager *mgr, struct channel_req *crq)
984*4882a593Smuzhiyun {
985*4882a593Smuzhiyun struct layer2 *l2;
986*4882a593Smuzhiyun unsigned long opt = 0;
987*4882a593Smuzhiyun unsigned long flags;
988*4882a593Smuzhiyun int id;
989*4882a593Smuzhiyun struct channel_req l1rq;
990*4882a593Smuzhiyun
991*4882a593Smuzhiyun if (*debug & DEBUG_L2_TEI)
992*4882a593Smuzhiyun printk(KERN_DEBUG "%s: %s proto(%x) adr(%d %d %d %d)\n",
993*4882a593Smuzhiyun __func__, dev_name(&mgr->ch.st->dev->dev),
994*4882a593Smuzhiyun crq->protocol, crq->adr.dev, crq->adr.channel,
995*4882a593Smuzhiyun crq->adr.sapi, crq->adr.tei);
996*4882a593Smuzhiyun if (crq->adr.tei > GROUP_TEI)
997*4882a593Smuzhiyun return -EINVAL;
998*4882a593Smuzhiyun if (crq->adr.tei < 64)
999*4882a593Smuzhiyun test_and_set_bit(OPTION_L2_FIXEDTEI, &opt);
1000*4882a593Smuzhiyun if (crq->adr.tei == 0)
1001*4882a593Smuzhiyun test_and_set_bit(OPTION_L2_PTP, &opt);
1002*4882a593Smuzhiyun if (test_bit(MGR_OPT_NETWORK, &mgr->options)) {
1003*4882a593Smuzhiyun if (crq->protocol == ISDN_P_LAPD_TE)
1004*4882a593Smuzhiyun return -EPROTONOSUPPORT;
1005*4882a593Smuzhiyun if ((crq->adr.tei != 0) && (crq->adr.tei != 127))
1006*4882a593Smuzhiyun return -EINVAL;
1007*4882a593Smuzhiyun if (mgr->up) {
1008*4882a593Smuzhiyun printk(KERN_WARNING
1009*4882a593Smuzhiyun "%s: only one network manager is allowed\n",
1010*4882a593Smuzhiyun __func__);
1011*4882a593Smuzhiyun return -EBUSY;
1012*4882a593Smuzhiyun }
1013*4882a593Smuzhiyun } else if (test_bit(MGR_OPT_USER, &mgr->options)) {
1014*4882a593Smuzhiyun if (crq->protocol == ISDN_P_LAPD_NT)
1015*4882a593Smuzhiyun return -EPROTONOSUPPORT;
1016*4882a593Smuzhiyun if ((crq->adr.tei >= 64) && (crq->adr.tei < GROUP_TEI))
1017*4882a593Smuzhiyun return -EINVAL; /* dyn tei */
1018*4882a593Smuzhiyun } else {
1019*4882a593Smuzhiyun if (crq->protocol == ISDN_P_LAPD_NT)
1020*4882a593Smuzhiyun test_and_set_bit(MGR_OPT_NETWORK, &mgr->options);
1021*4882a593Smuzhiyun if (crq->protocol == ISDN_P_LAPD_TE)
1022*4882a593Smuzhiyun test_and_set_bit(MGR_OPT_USER, &mgr->options);
1023*4882a593Smuzhiyun }
1024*4882a593Smuzhiyun l1rq.adr = crq->adr;
1025*4882a593Smuzhiyun if (mgr->ch.st->dev->Dprotocols
1026*4882a593Smuzhiyun & ((1 << ISDN_P_TE_E1) | (1 << ISDN_P_NT_E1)))
1027*4882a593Smuzhiyun test_and_set_bit(OPTION_L2_PMX, &opt);
1028*4882a593Smuzhiyun if ((crq->protocol == ISDN_P_LAPD_NT) && (crq->adr.tei == 127)) {
1029*4882a593Smuzhiyun mgr->up = crq->ch;
1030*4882a593Smuzhiyun id = DL_INFO_L2_CONNECT;
1031*4882a593Smuzhiyun teiup_create(mgr, DL_INFORMATION_IND, sizeof(id), &id);
1032*4882a593Smuzhiyun if (test_bit(MGR_PH_ACTIVE, &mgr->options))
1033*4882a593Smuzhiyun teiup_create(mgr, PH_ACTIVATE_IND, 0, NULL);
1034*4882a593Smuzhiyun crq->ch = NULL;
1035*4882a593Smuzhiyun if (!list_empty(&mgr->layer2)) {
1036*4882a593Smuzhiyun read_lock_irqsave(&mgr->lock, flags);
1037*4882a593Smuzhiyun list_for_each_entry(l2, &mgr->layer2, list) {
1038*4882a593Smuzhiyun l2->up = mgr->up;
1039*4882a593Smuzhiyun l2->ch.ctrl(&l2->ch, OPEN_CHANNEL, NULL);
1040*4882a593Smuzhiyun }
1041*4882a593Smuzhiyun read_unlock_irqrestore(&mgr->lock, flags);
1042*4882a593Smuzhiyun }
1043*4882a593Smuzhiyun return 0;
1044*4882a593Smuzhiyun }
1045*4882a593Smuzhiyun l2 = create_l2(crq->ch, crq->protocol, opt,
1046*4882a593Smuzhiyun crq->adr.tei, crq->adr.sapi);
1047*4882a593Smuzhiyun if (!l2)
1048*4882a593Smuzhiyun return -ENOMEM;
1049*4882a593Smuzhiyun l2->tm = kzalloc(sizeof(struct teimgr), GFP_KERNEL);
1050*4882a593Smuzhiyun if (!l2->tm) {
1051*4882a593Smuzhiyun kfree(l2);
1052*4882a593Smuzhiyun printk(KERN_ERR "kmalloc teimgr failed\n");
1053*4882a593Smuzhiyun return -ENOMEM;
1054*4882a593Smuzhiyun }
1055*4882a593Smuzhiyun l2->tm->mgr = mgr;
1056*4882a593Smuzhiyun l2->tm->l2 = l2;
1057*4882a593Smuzhiyun l2->tm->tei_m.debug = *debug & DEBUG_L2_TEIFSM;
1058*4882a593Smuzhiyun l2->tm->tei_m.userdata = l2->tm;
1059*4882a593Smuzhiyun l2->tm->tei_m.printdebug = tei_debug;
1060*4882a593Smuzhiyun if (crq->protocol == ISDN_P_LAPD_TE) {
1061*4882a593Smuzhiyun l2->tm->tei_m.fsm = &teifsmu;
1062*4882a593Smuzhiyun l2->tm->tei_m.state = ST_TEI_NOP;
1063*4882a593Smuzhiyun l2->tm->tval = 1000; /* T201 1 sec */
1064*4882a593Smuzhiyun if (test_bit(OPTION_L2_PMX, &opt))
1065*4882a593Smuzhiyun l1rq.protocol = ISDN_P_TE_E1;
1066*4882a593Smuzhiyun else
1067*4882a593Smuzhiyun l1rq.protocol = ISDN_P_TE_S0;
1068*4882a593Smuzhiyun } else {
1069*4882a593Smuzhiyun l2->tm->tei_m.fsm = &teifsmn;
1070*4882a593Smuzhiyun l2->tm->tei_m.state = ST_TEI_NOP;
1071*4882a593Smuzhiyun l2->tm->tval = 2000; /* T202 2 sec */
1072*4882a593Smuzhiyun if (test_bit(OPTION_L2_PMX, &opt))
1073*4882a593Smuzhiyun l1rq.protocol = ISDN_P_NT_E1;
1074*4882a593Smuzhiyun else
1075*4882a593Smuzhiyun l1rq.protocol = ISDN_P_NT_S0;
1076*4882a593Smuzhiyun }
1077*4882a593Smuzhiyun mISDN_FsmInitTimer(&l2->tm->tei_m, &l2->tm->timer);
1078*4882a593Smuzhiyun write_lock_irqsave(&mgr->lock, flags);
1079*4882a593Smuzhiyun id = get_free_id(mgr);
1080*4882a593Smuzhiyun list_add_tail(&l2->list, &mgr->layer2);
1081*4882a593Smuzhiyun write_unlock_irqrestore(&mgr->lock, flags);
1082*4882a593Smuzhiyun if (id >= 0) {
1083*4882a593Smuzhiyun l2->ch.nr = id;
1084*4882a593Smuzhiyun l2->up->nr = id;
1085*4882a593Smuzhiyun crq->ch = &l2->ch;
1086*4882a593Smuzhiyun /* We need open here L1 for the manager as well (refcounting) */
1087*4882a593Smuzhiyun id = mgr->ch.st->own.ctrl(&mgr->ch.st->own, OPEN_CHANNEL,
1088*4882a593Smuzhiyun &l1rq);
1089*4882a593Smuzhiyun }
1090*4882a593Smuzhiyun if (id < 0)
1091*4882a593Smuzhiyun l2->ch.ctrl(&l2->ch, CLOSE_CHANNEL, NULL);
1092*4882a593Smuzhiyun return id;
1093*4882a593Smuzhiyun }
1094*4882a593Smuzhiyun
1095*4882a593Smuzhiyun static int
mgr_send(struct mISDNchannel * ch,struct sk_buff * skb)1096*4882a593Smuzhiyun mgr_send(struct mISDNchannel *ch, struct sk_buff *skb)
1097*4882a593Smuzhiyun {
1098*4882a593Smuzhiyun struct manager *mgr;
1099*4882a593Smuzhiyun struct mISDNhead *hh = mISDN_HEAD_P(skb);
1100*4882a593Smuzhiyun int ret = -EINVAL;
1101*4882a593Smuzhiyun
1102*4882a593Smuzhiyun mgr = container_of(ch, struct manager, ch);
1103*4882a593Smuzhiyun if (*debug & DEBUG_L2_RECV)
1104*4882a593Smuzhiyun printk(KERN_DEBUG "%s: prim(%x) id(%x)\n",
1105*4882a593Smuzhiyun __func__, hh->prim, hh->id);
1106*4882a593Smuzhiyun switch (hh->prim) {
1107*4882a593Smuzhiyun case PH_DATA_IND:
1108*4882a593Smuzhiyun mISDN_FsmEvent(&mgr->deact, EV_UI, NULL);
1109*4882a593Smuzhiyun ret = ph_data_ind(mgr, skb);
1110*4882a593Smuzhiyun break;
1111*4882a593Smuzhiyun case PH_DATA_CNF:
1112*4882a593Smuzhiyun do_ack(mgr, hh->id);
1113*4882a593Smuzhiyun ret = 0;
1114*4882a593Smuzhiyun break;
1115*4882a593Smuzhiyun case PH_ACTIVATE_IND:
1116*4882a593Smuzhiyun test_and_set_bit(MGR_PH_ACTIVE, &mgr->options);
1117*4882a593Smuzhiyun if (mgr->up)
1118*4882a593Smuzhiyun teiup_create(mgr, PH_ACTIVATE_IND, 0, NULL);
1119*4882a593Smuzhiyun mISDN_FsmEvent(&mgr->deact, EV_ACTIVATE_IND, NULL);
1120*4882a593Smuzhiyun do_send(mgr);
1121*4882a593Smuzhiyun ret = 0;
1122*4882a593Smuzhiyun break;
1123*4882a593Smuzhiyun case PH_DEACTIVATE_IND:
1124*4882a593Smuzhiyun test_and_clear_bit(MGR_PH_ACTIVE, &mgr->options);
1125*4882a593Smuzhiyun if (mgr->up)
1126*4882a593Smuzhiyun teiup_create(mgr, PH_DEACTIVATE_IND, 0, NULL);
1127*4882a593Smuzhiyun mISDN_FsmEvent(&mgr->deact, EV_DEACTIVATE_IND, NULL);
1128*4882a593Smuzhiyun ret = 0;
1129*4882a593Smuzhiyun break;
1130*4882a593Smuzhiyun case DL_UNITDATA_REQ:
1131*4882a593Smuzhiyun return dl_unit_data(mgr, skb);
1132*4882a593Smuzhiyun }
1133*4882a593Smuzhiyun if (!ret)
1134*4882a593Smuzhiyun dev_kfree_skb(skb);
1135*4882a593Smuzhiyun return ret;
1136*4882a593Smuzhiyun }
1137*4882a593Smuzhiyun
1138*4882a593Smuzhiyun static int
free_teimanager(struct manager * mgr)1139*4882a593Smuzhiyun free_teimanager(struct manager *mgr)
1140*4882a593Smuzhiyun {
1141*4882a593Smuzhiyun struct layer2 *l2, *nl2;
1142*4882a593Smuzhiyun
1143*4882a593Smuzhiyun test_and_clear_bit(OPTION_L1_HOLD, &mgr->options);
1144*4882a593Smuzhiyun if (test_bit(MGR_OPT_NETWORK, &mgr->options)) {
1145*4882a593Smuzhiyun /* not locked lock is taken in release tei */
1146*4882a593Smuzhiyun mgr->up = NULL;
1147*4882a593Smuzhiyun if (test_bit(OPTION_L2_CLEANUP, &mgr->options)) {
1148*4882a593Smuzhiyun list_for_each_entry_safe(l2, nl2, &mgr->layer2, list) {
1149*4882a593Smuzhiyun put_tei_msg(mgr, ID_REMOVE, 0, l2->tei);
1150*4882a593Smuzhiyun mutex_lock(&mgr->ch.st->lmutex);
1151*4882a593Smuzhiyun list_del(&l2->ch.list);
1152*4882a593Smuzhiyun mutex_unlock(&mgr->ch.st->lmutex);
1153*4882a593Smuzhiyun l2->ch.ctrl(&l2->ch, CLOSE_CHANNEL, NULL);
1154*4882a593Smuzhiyun }
1155*4882a593Smuzhiyun test_and_clear_bit(MGR_OPT_NETWORK, &mgr->options);
1156*4882a593Smuzhiyun } else {
1157*4882a593Smuzhiyun list_for_each_entry_safe(l2, nl2, &mgr->layer2, list) {
1158*4882a593Smuzhiyun l2->up = NULL;
1159*4882a593Smuzhiyun }
1160*4882a593Smuzhiyun }
1161*4882a593Smuzhiyun }
1162*4882a593Smuzhiyun if (test_bit(MGR_OPT_USER, &mgr->options)) {
1163*4882a593Smuzhiyun if (list_empty(&mgr->layer2))
1164*4882a593Smuzhiyun test_and_clear_bit(MGR_OPT_USER, &mgr->options);
1165*4882a593Smuzhiyun }
1166*4882a593Smuzhiyun mgr->ch.st->dev->D.ctrl(&mgr->ch.st->dev->D, CLOSE_CHANNEL, NULL);
1167*4882a593Smuzhiyun return 0;
1168*4882a593Smuzhiyun }
1169*4882a593Smuzhiyun
1170*4882a593Smuzhiyun static int
ctrl_teimanager(struct manager * mgr,void * arg)1171*4882a593Smuzhiyun ctrl_teimanager(struct manager *mgr, void *arg)
1172*4882a593Smuzhiyun {
1173*4882a593Smuzhiyun /* currently we only have one option */
1174*4882a593Smuzhiyun unsigned int *val = (unsigned int *)arg;
1175*4882a593Smuzhiyun
1176*4882a593Smuzhiyun switch (val[0]) {
1177*4882a593Smuzhiyun case IMCLEAR_L2:
1178*4882a593Smuzhiyun if (val[1])
1179*4882a593Smuzhiyun test_and_set_bit(OPTION_L2_CLEANUP, &mgr->options);
1180*4882a593Smuzhiyun else
1181*4882a593Smuzhiyun test_and_clear_bit(OPTION_L2_CLEANUP, &mgr->options);
1182*4882a593Smuzhiyun break;
1183*4882a593Smuzhiyun case IMHOLD_L1:
1184*4882a593Smuzhiyun if (val[1])
1185*4882a593Smuzhiyun test_and_set_bit(OPTION_L1_HOLD, &mgr->options);
1186*4882a593Smuzhiyun else
1187*4882a593Smuzhiyun test_and_clear_bit(OPTION_L1_HOLD, &mgr->options);
1188*4882a593Smuzhiyun break;
1189*4882a593Smuzhiyun default:
1190*4882a593Smuzhiyun return -EINVAL;
1191*4882a593Smuzhiyun }
1192*4882a593Smuzhiyun return 0;
1193*4882a593Smuzhiyun }
1194*4882a593Smuzhiyun
1195*4882a593Smuzhiyun /* This function does create a L2 for fixed TEI in NT Mode */
1196*4882a593Smuzhiyun static int
check_data(struct manager * mgr,struct sk_buff * skb)1197*4882a593Smuzhiyun check_data(struct manager *mgr, struct sk_buff *skb)
1198*4882a593Smuzhiyun {
1199*4882a593Smuzhiyun struct mISDNhead *hh = mISDN_HEAD_P(skb);
1200*4882a593Smuzhiyun int ret, tei, sapi;
1201*4882a593Smuzhiyun struct layer2 *l2;
1202*4882a593Smuzhiyun
1203*4882a593Smuzhiyun if (*debug & DEBUG_L2_CTRL)
1204*4882a593Smuzhiyun printk(KERN_DEBUG "%s: prim(%x) id(%x)\n",
1205*4882a593Smuzhiyun __func__, hh->prim, hh->id);
1206*4882a593Smuzhiyun if (test_bit(MGR_OPT_USER, &mgr->options))
1207*4882a593Smuzhiyun return -ENOTCONN;
1208*4882a593Smuzhiyun if (hh->prim != PH_DATA_IND)
1209*4882a593Smuzhiyun return -ENOTCONN;
1210*4882a593Smuzhiyun if (skb->len != 3)
1211*4882a593Smuzhiyun return -ENOTCONN;
1212*4882a593Smuzhiyun if (skb->data[0] & 3) /* EA0 and CR must be 0 */
1213*4882a593Smuzhiyun return -EINVAL;
1214*4882a593Smuzhiyun sapi = skb->data[0] >> 2;
1215*4882a593Smuzhiyun if (!(skb->data[1] & 1)) /* invalid EA1 */
1216*4882a593Smuzhiyun return -EINVAL;
1217*4882a593Smuzhiyun tei = skb->data[1] >> 1;
1218*4882a593Smuzhiyun if (tei > 63) /* not a fixed tei */
1219*4882a593Smuzhiyun return -ENOTCONN;
1220*4882a593Smuzhiyun if ((skb->data[2] & ~0x10) != SABME)
1221*4882a593Smuzhiyun return -ENOTCONN;
1222*4882a593Smuzhiyun /* We got a SABME for a fixed TEI */
1223*4882a593Smuzhiyun if (*debug & DEBUG_L2_CTRL)
1224*4882a593Smuzhiyun printk(KERN_DEBUG "%s: SABME sapi(%d) tei(%d)\n",
1225*4882a593Smuzhiyun __func__, sapi, tei);
1226*4882a593Smuzhiyun l2 = create_new_tei(mgr, tei, sapi);
1227*4882a593Smuzhiyun if (!l2) {
1228*4882a593Smuzhiyun if (*debug & DEBUG_L2_CTRL)
1229*4882a593Smuzhiyun printk(KERN_DEBUG "%s: failed to create new tei\n",
1230*4882a593Smuzhiyun __func__);
1231*4882a593Smuzhiyun return -ENOMEM;
1232*4882a593Smuzhiyun }
1233*4882a593Smuzhiyun ret = l2->ch.send(&l2->ch, skb);
1234*4882a593Smuzhiyun return ret;
1235*4882a593Smuzhiyun }
1236*4882a593Smuzhiyun
1237*4882a593Smuzhiyun void
delete_teimanager(struct mISDNchannel * ch)1238*4882a593Smuzhiyun delete_teimanager(struct mISDNchannel *ch)
1239*4882a593Smuzhiyun {
1240*4882a593Smuzhiyun struct manager *mgr;
1241*4882a593Smuzhiyun struct layer2 *l2, *nl2;
1242*4882a593Smuzhiyun
1243*4882a593Smuzhiyun mgr = container_of(ch, struct manager, ch);
1244*4882a593Smuzhiyun /* not locked lock is taken in release tei */
1245*4882a593Smuzhiyun list_for_each_entry_safe(l2, nl2, &mgr->layer2, list) {
1246*4882a593Smuzhiyun mutex_lock(&mgr->ch.st->lmutex);
1247*4882a593Smuzhiyun list_del(&l2->ch.list);
1248*4882a593Smuzhiyun mutex_unlock(&mgr->ch.st->lmutex);
1249*4882a593Smuzhiyun l2->ch.ctrl(&l2->ch, CLOSE_CHANNEL, NULL);
1250*4882a593Smuzhiyun }
1251*4882a593Smuzhiyun list_del(&mgr->ch.list);
1252*4882a593Smuzhiyun list_del(&mgr->bcast.list);
1253*4882a593Smuzhiyun skb_queue_purge(&mgr->sendq);
1254*4882a593Smuzhiyun kfree(mgr);
1255*4882a593Smuzhiyun }
1256*4882a593Smuzhiyun
1257*4882a593Smuzhiyun static int
mgr_ctrl(struct mISDNchannel * ch,u_int cmd,void * arg)1258*4882a593Smuzhiyun mgr_ctrl(struct mISDNchannel *ch, u_int cmd, void *arg)
1259*4882a593Smuzhiyun {
1260*4882a593Smuzhiyun struct manager *mgr;
1261*4882a593Smuzhiyun int ret = -EINVAL;
1262*4882a593Smuzhiyun
1263*4882a593Smuzhiyun mgr = container_of(ch, struct manager, ch);
1264*4882a593Smuzhiyun if (*debug & DEBUG_L2_CTRL)
1265*4882a593Smuzhiyun printk(KERN_DEBUG "%s(%x, %p)\n", __func__, cmd, arg);
1266*4882a593Smuzhiyun switch (cmd) {
1267*4882a593Smuzhiyun case OPEN_CHANNEL:
1268*4882a593Smuzhiyun ret = create_teimgr(mgr, arg);
1269*4882a593Smuzhiyun break;
1270*4882a593Smuzhiyun case CLOSE_CHANNEL:
1271*4882a593Smuzhiyun ret = free_teimanager(mgr);
1272*4882a593Smuzhiyun break;
1273*4882a593Smuzhiyun case CONTROL_CHANNEL:
1274*4882a593Smuzhiyun ret = ctrl_teimanager(mgr, arg);
1275*4882a593Smuzhiyun break;
1276*4882a593Smuzhiyun case CHECK_DATA:
1277*4882a593Smuzhiyun ret = check_data(mgr, arg);
1278*4882a593Smuzhiyun break;
1279*4882a593Smuzhiyun }
1280*4882a593Smuzhiyun return ret;
1281*4882a593Smuzhiyun }
1282*4882a593Smuzhiyun
1283*4882a593Smuzhiyun static int
mgr_bcast(struct mISDNchannel * ch,struct sk_buff * skb)1284*4882a593Smuzhiyun mgr_bcast(struct mISDNchannel *ch, struct sk_buff *skb)
1285*4882a593Smuzhiyun {
1286*4882a593Smuzhiyun struct manager *mgr = container_of(ch, struct manager, bcast);
1287*4882a593Smuzhiyun struct mISDNhead *hhc, *hh = mISDN_HEAD_P(skb);
1288*4882a593Smuzhiyun struct sk_buff *cskb = NULL;
1289*4882a593Smuzhiyun struct layer2 *l2;
1290*4882a593Smuzhiyun u_long flags;
1291*4882a593Smuzhiyun int ret;
1292*4882a593Smuzhiyun
1293*4882a593Smuzhiyun read_lock_irqsave(&mgr->lock, flags);
1294*4882a593Smuzhiyun list_for_each_entry(l2, &mgr->layer2, list) {
1295*4882a593Smuzhiyun if ((hh->id & MISDN_ID_SAPI_MASK) ==
1296*4882a593Smuzhiyun (l2->ch.addr & MISDN_ID_SAPI_MASK)) {
1297*4882a593Smuzhiyun if (list_is_last(&l2->list, &mgr->layer2)) {
1298*4882a593Smuzhiyun cskb = skb;
1299*4882a593Smuzhiyun skb = NULL;
1300*4882a593Smuzhiyun } else {
1301*4882a593Smuzhiyun if (!cskb)
1302*4882a593Smuzhiyun cskb = skb_copy(skb, GFP_ATOMIC);
1303*4882a593Smuzhiyun }
1304*4882a593Smuzhiyun if (cskb) {
1305*4882a593Smuzhiyun hhc = mISDN_HEAD_P(cskb);
1306*4882a593Smuzhiyun /* save original header behind normal header */
1307*4882a593Smuzhiyun hhc++;
1308*4882a593Smuzhiyun *hhc = *hh;
1309*4882a593Smuzhiyun hhc--;
1310*4882a593Smuzhiyun hhc->prim = DL_INTERN_MSG;
1311*4882a593Smuzhiyun hhc->id = l2->ch.nr;
1312*4882a593Smuzhiyun ret = ch->st->own.recv(&ch->st->own, cskb);
1313*4882a593Smuzhiyun if (ret) {
1314*4882a593Smuzhiyun if (*debug & DEBUG_SEND_ERR)
1315*4882a593Smuzhiyun printk(KERN_DEBUG
1316*4882a593Smuzhiyun "%s ch%d prim(%x) addr(%x)"
1317*4882a593Smuzhiyun " err %d\n",
1318*4882a593Smuzhiyun __func__, l2->ch.nr,
1319*4882a593Smuzhiyun hh->prim, l2->ch.addr, ret);
1320*4882a593Smuzhiyun } else
1321*4882a593Smuzhiyun cskb = NULL;
1322*4882a593Smuzhiyun } else {
1323*4882a593Smuzhiyun printk(KERN_WARNING "%s ch%d addr %x no mem\n",
1324*4882a593Smuzhiyun __func__, ch->nr, ch->addr);
1325*4882a593Smuzhiyun goto out;
1326*4882a593Smuzhiyun }
1327*4882a593Smuzhiyun }
1328*4882a593Smuzhiyun }
1329*4882a593Smuzhiyun out:
1330*4882a593Smuzhiyun read_unlock_irqrestore(&mgr->lock, flags);
1331*4882a593Smuzhiyun dev_kfree_skb(cskb);
1332*4882a593Smuzhiyun dev_kfree_skb(skb);
1333*4882a593Smuzhiyun return 0;
1334*4882a593Smuzhiyun }
1335*4882a593Smuzhiyun
1336*4882a593Smuzhiyun static int
mgr_bcast_ctrl(struct mISDNchannel * ch,u_int cmd,void * arg)1337*4882a593Smuzhiyun mgr_bcast_ctrl(struct mISDNchannel *ch, u_int cmd, void *arg)
1338*4882a593Smuzhiyun {
1339*4882a593Smuzhiyun
1340*4882a593Smuzhiyun return -EINVAL;
1341*4882a593Smuzhiyun }
1342*4882a593Smuzhiyun
1343*4882a593Smuzhiyun int
create_teimanager(struct mISDNdevice * dev)1344*4882a593Smuzhiyun create_teimanager(struct mISDNdevice *dev)
1345*4882a593Smuzhiyun {
1346*4882a593Smuzhiyun struct manager *mgr;
1347*4882a593Smuzhiyun
1348*4882a593Smuzhiyun mgr = kzalloc(sizeof(struct manager), GFP_KERNEL);
1349*4882a593Smuzhiyun if (!mgr)
1350*4882a593Smuzhiyun return -ENOMEM;
1351*4882a593Smuzhiyun INIT_LIST_HEAD(&mgr->layer2);
1352*4882a593Smuzhiyun rwlock_init(&mgr->lock);
1353*4882a593Smuzhiyun skb_queue_head_init(&mgr->sendq);
1354*4882a593Smuzhiyun mgr->nextid = 1;
1355*4882a593Smuzhiyun mgr->lastid = MISDN_ID_NONE;
1356*4882a593Smuzhiyun mgr->ch.send = mgr_send;
1357*4882a593Smuzhiyun mgr->ch.ctrl = mgr_ctrl;
1358*4882a593Smuzhiyun mgr->ch.st = dev->D.st;
1359*4882a593Smuzhiyun set_channel_address(&mgr->ch, TEI_SAPI, GROUP_TEI);
1360*4882a593Smuzhiyun add_layer2(&mgr->ch, dev->D.st);
1361*4882a593Smuzhiyun mgr->bcast.send = mgr_bcast;
1362*4882a593Smuzhiyun mgr->bcast.ctrl = mgr_bcast_ctrl;
1363*4882a593Smuzhiyun mgr->bcast.st = dev->D.st;
1364*4882a593Smuzhiyun set_channel_address(&mgr->bcast, 0, GROUP_TEI);
1365*4882a593Smuzhiyun add_layer2(&mgr->bcast, dev->D.st);
1366*4882a593Smuzhiyun mgr->deact.debug = *debug & DEBUG_MANAGER;
1367*4882a593Smuzhiyun mgr->deact.userdata = mgr;
1368*4882a593Smuzhiyun mgr->deact.printdebug = da_debug;
1369*4882a593Smuzhiyun mgr->deact.fsm = &deactfsm;
1370*4882a593Smuzhiyun mgr->deact.state = ST_L1_DEACT;
1371*4882a593Smuzhiyun mISDN_FsmInitTimer(&mgr->deact, &mgr->datimer);
1372*4882a593Smuzhiyun dev->teimgr = &mgr->ch;
1373*4882a593Smuzhiyun return 0;
1374*4882a593Smuzhiyun }
1375*4882a593Smuzhiyun
TEIInit(u_int * deb)1376*4882a593Smuzhiyun int TEIInit(u_int *deb)
1377*4882a593Smuzhiyun {
1378*4882a593Smuzhiyun int res;
1379*4882a593Smuzhiyun debug = deb;
1380*4882a593Smuzhiyun teifsmu.state_count = TEI_STATE_COUNT;
1381*4882a593Smuzhiyun teifsmu.event_count = TEI_EVENT_COUNT;
1382*4882a593Smuzhiyun teifsmu.strEvent = strTeiEvent;
1383*4882a593Smuzhiyun teifsmu.strState = strTeiState;
1384*4882a593Smuzhiyun res = mISDN_FsmNew(&teifsmu, TeiFnListUser, ARRAY_SIZE(TeiFnListUser));
1385*4882a593Smuzhiyun if (res)
1386*4882a593Smuzhiyun goto error;
1387*4882a593Smuzhiyun teifsmn.state_count = TEI_STATE_COUNT;
1388*4882a593Smuzhiyun teifsmn.event_count = TEI_EVENT_COUNT;
1389*4882a593Smuzhiyun teifsmn.strEvent = strTeiEvent;
1390*4882a593Smuzhiyun teifsmn.strState = strTeiState;
1391*4882a593Smuzhiyun res = mISDN_FsmNew(&teifsmn, TeiFnListNet, ARRAY_SIZE(TeiFnListNet));
1392*4882a593Smuzhiyun if (res)
1393*4882a593Smuzhiyun goto error_smn;
1394*4882a593Smuzhiyun deactfsm.state_count = DEACT_STATE_COUNT;
1395*4882a593Smuzhiyun deactfsm.event_count = DEACT_EVENT_COUNT;
1396*4882a593Smuzhiyun deactfsm.strEvent = strDeactEvent;
1397*4882a593Smuzhiyun deactfsm.strState = strDeactState;
1398*4882a593Smuzhiyun res = mISDN_FsmNew(&deactfsm, DeactFnList, ARRAY_SIZE(DeactFnList));
1399*4882a593Smuzhiyun if (res)
1400*4882a593Smuzhiyun goto error_deact;
1401*4882a593Smuzhiyun return 0;
1402*4882a593Smuzhiyun
1403*4882a593Smuzhiyun error_deact:
1404*4882a593Smuzhiyun mISDN_FsmFree(&teifsmn);
1405*4882a593Smuzhiyun error_smn:
1406*4882a593Smuzhiyun mISDN_FsmFree(&teifsmu);
1407*4882a593Smuzhiyun error:
1408*4882a593Smuzhiyun return res;
1409*4882a593Smuzhiyun }
1410*4882a593Smuzhiyun
TEIFree(void)1411*4882a593Smuzhiyun void TEIFree(void)
1412*4882a593Smuzhiyun {
1413*4882a593Smuzhiyun mISDN_FsmFree(&teifsmu);
1414*4882a593Smuzhiyun mISDN_FsmFree(&teifsmn);
1415*4882a593Smuzhiyun mISDN_FsmFree(&deactfsm);
1416*4882a593Smuzhiyun }
1417