1*1802d0beSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
21b2b03f8SKarsten Keil /*
31b2b03f8SKarsten Keil *
41b2b03f8SKarsten Keil * Author Karsten Keil <kkeil@novell.com>
51b2b03f8SKarsten Keil *
61b2b03f8SKarsten Keil * Copyright 2008 by Karsten Keil <kkeil@novell.com>
71b2b03f8SKarsten Keil */
81b2b03f8SKarsten Keil #include "layer2.h"
91b2b03f8SKarsten Keil #include <linux/random.h>
105a0e3ad6STejun Heo #include <linux/slab.h>
111b2b03f8SKarsten Keil #include "core.h"
121b2b03f8SKarsten Keil
131b2b03f8SKarsten Keil #define ID_REQUEST 1
141b2b03f8SKarsten Keil #define ID_ASSIGNED 2
151b2b03f8SKarsten Keil #define ID_DENIED 3
161b2b03f8SKarsten Keil #define ID_CHK_REQ 4
171b2b03f8SKarsten Keil #define ID_CHK_RES 5
181b2b03f8SKarsten Keil #define ID_REMOVE 6
191b2b03f8SKarsten Keil #define ID_VERIFY 7
201b2b03f8SKarsten Keil
211b2b03f8SKarsten Keil #define TEI_ENTITY_ID 0xf
221b2b03f8SKarsten Keil
231b2b03f8SKarsten Keil #define MGR_PH_ACTIVE 16
241b2b03f8SKarsten Keil #define MGR_PH_NOTREADY 17
251b2b03f8SKarsten Keil
261b2b03f8SKarsten Keil #define DATIMER_VAL 10000
271b2b03f8SKarsten Keil
281b2b03f8SKarsten Keil static u_int *debug;
291b2b03f8SKarsten Keil
301b2b03f8SKarsten Keil static struct Fsm deactfsm = {NULL, 0, 0, NULL, NULL};
311b2b03f8SKarsten Keil static struct Fsm teifsmu = {NULL, 0, 0, NULL, NULL};
321b2b03f8SKarsten Keil static struct Fsm teifsmn = {NULL, 0, 0, NULL, NULL};
331b2b03f8SKarsten Keil
341b2b03f8SKarsten Keil enum {
351b2b03f8SKarsten Keil ST_L1_DEACT,
361b2b03f8SKarsten Keil ST_L1_DEACT_PENDING,
371b2b03f8SKarsten Keil ST_L1_ACTIV,
381b2b03f8SKarsten Keil };
391b2b03f8SKarsten Keil #define DEACT_STATE_COUNT (ST_L1_ACTIV + 1)
401b2b03f8SKarsten Keil
411b2b03f8SKarsten Keil static char *strDeactState[] =
421b2b03f8SKarsten Keil {
431b2b03f8SKarsten Keil "ST_L1_DEACT",
441b2b03f8SKarsten Keil "ST_L1_DEACT_PENDING",
451b2b03f8SKarsten Keil "ST_L1_ACTIV",
461b2b03f8SKarsten Keil };
471b2b03f8SKarsten Keil
481b2b03f8SKarsten Keil enum {
491b2b03f8SKarsten Keil EV_ACTIVATE,
501b2b03f8SKarsten Keil EV_ACTIVATE_IND,
511b2b03f8SKarsten Keil EV_DEACTIVATE,
521b2b03f8SKarsten Keil EV_DEACTIVATE_IND,
531b2b03f8SKarsten Keil EV_UI,
541b2b03f8SKarsten Keil EV_DATIMER,
551b2b03f8SKarsten Keil };
561b2b03f8SKarsten Keil
571b2b03f8SKarsten Keil #define DEACT_EVENT_COUNT (EV_DATIMER + 1)
581b2b03f8SKarsten Keil
591b2b03f8SKarsten Keil static char *strDeactEvent[] =
601b2b03f8SKarsten Keil {
611b2b03f8SKarsten Keil "EV_ACTIVATE",
621b2b03f8SKarsten Keil "EV_ACTIVATE_IND",
631b2b03f8SKarsten Keil "EV_DEACTIVATE",
641b2b03f8SKarsten Keil "EV_DEACTIVATE_IND",
651b2b03f8SKarsten Keil "EV_UI",
661b2b03f8SKarsten Keil "EV_DATIMER",
671b2b03f8SKarsten Keil };
681b2b03f8SKarsten Keil
691b2b03f8SKarsten Keil static void
da_debug(struct FsmInst * fi,char * fmt,...)701b2b03f8SKarsten Keil da_debug(struct FsmInst *fi, char *fmt, ...)
711b2b03f8SKarsten Keil {
721b2b03f8SKarsten Keil struct manager *mgr = fi->userdata;
73020f01ebSJoe Perches struct va_format vaf;
741b2b03f8SKarsten Keil va_list va;
751b2b03f8SKarsten Keil
761b2b03f8SKarsten Keil if (!(*debug & DEBUG_L2_TEIFSM))
771b2b03f8SKarsten Keil return;
78020f01ebSJoe Perches
791b2b03f8SKarsten Keil va_start(va, fmt);
80020f01ebSJoe Perches
81020f01ebSJoe Perches vaf.fmt = fmt;
82020f01ebSJoe Perches vaf.va = &va;
83020f01ebSJoe Perches
84020f01ebSJoe Perches printk(KERN_DEBUG "mgr(%d): %pV\n", mgr->ch.st->dev->id, &vaf);
85020f01ebSJoe Perches
861b2b03f8SKarsten Keil va_end(va);
871b2b03f8SKarsten Keil }
881b2b03f8SKarsten Keil
891b2b03f8SKarsten Keil static void
da_activate(struct FsmInst * fi,int event,void * arg)901b2b03f8SKarsten Keil da_activate(struct FsmInst *fi, int event, void *arg)
911b2b03f8SKarsten Keil {
921b2b03f8SKarsten Keil struct manager *mgr = fi->userdata;
931b2b03f8SKarsten Keil
941b2b03f8SKarsten Keil if (fi->state == ST_L1_DEACT_PENDING)
951b2b03f8SKarsten Keil mISDN_FsmDelTimer(&mgr->datimer, 1);
961b2b03f8SKarsten Keil mISDN_FsmChangeState(fi, ST_L1_ACTIV);
971b2b03f8SKarsten Keil }
981b2b03f8SKarsten Keil
991b2b03f8SKarsten Keil static void
da_deactivate_ind(struct FsmInst * fi,int event,void * arg)1001b2b03f8SKarsten Keil da_deactivate_ind(struct FsmInst *fi, int event, void *arg)
1011b2b03f8SKarsten Keil {
1021b2b03f8SKarsten Keil mISDN_FsmChangeState(fi, ST_L1_DEACT);
1031b2b03f8SKarsten Keil }
1041b2b03f8SKarsten Keil
1051b2b03f8SKarsten Keil static void
da_deactivate(struct FsmInst * fi,int event,void * arg)1061b2b03f8SKarsten Keil da_deactivate(struct FsmInst *fi, int event, void *arg)
1071b2b03f8SKarsten Keil {
1081b2b03f8SKarsten Keil struct manager *mgr = fi->userdata;
1091b2b03f8SKarsten Keil struct layer2 *l2;
1101b2b03f8SKarsten Keil u_long flags;
1111b2b03f8SKarsten Keil
1121b2b03f8SKarsten Keil read_lock_irqsave(&mgr->lock, flags);
1131b2b03f8SKarsten Keil list_for_each_entry(l2, &mgr->layer2, list) {
1141b2b03f8SKarsten Keil if (l2->l2m.state > ST_L2_4) {
1151b2b03f8SKarsten Keil /* have still activ TEI */
1161b2b03f8SKarsten Keil read_unlock_irqrestore(&mgr->lock, flags);
1171b2b03f8SKarsten Keil return;
1181b2b03f8SKarsten Keil }
1191b2b03f8SKarsten Keil }
1201b2b03f8SKarsten Keil read_unlock_irqrestore(&mgr->lock, flags);
1211b2b03f8SKarsten Keil /* All TEI are inactiv */
122e73f6b22SAndreas Eversberg if (!test_bit(OPTION_L1_HOLD, &mgr->options)) {
123e73f6b22SAndreas Eversberg mISDN_FsmAddTimer(&mgr->datimer, DATIMER_VAL, EV_DATIMER,
124e73f6b22SAndreas Eversberg NULL, 1);
1251b2b03f8SKarsten Keil mISDN_FsmChangeState(fi, ST_L1_DEACT_PENDING);
1261b2b03f8SKarsten Keil }
127e73f6b22SAndreas Eversberg }
1281b2b03f8SKarsten Keil
1291b2b03f8SKarsten Keil static void
da_ui(struct FsmInst * fi,int event,void * arg)1301b2b03f8SKarsten Keil da_ui(struct FsmInst *fi, int event, void *arg)
1311b2b03f8SKarsten Keil {
1321b2b03f8SKarsten Keil struct manager *mgr = fi->userdata;
1331b2b03f8SKarsten Keil
1341b2b03f8SKarsten Keil /* restart da timer */
135e73f6b22SAndreas Eversberg if (!test_bit(OPTION_L1_HOLD, &mgr->options)) {
1361b2b03f8SKarsten Keil mISDN_FsmDelTimer(&mgr->datimer, 2);
137e73f6b22SAndreas Eversberg mISDN_FsmAddTimer(&mgr->datimer, DATIMER_VAL, EV_DATIMER,
138e73f6b22SAndreas Eversberg NULL, 2);
139e73f6b22SAndreas Eversberg }
1401b2b03f8SKarsten Keil }
1411b2b03f8SKarsten Keil
1421b2b03f8SKarsten Keil static void
da_timer(struct FsmInst * fi,int event,void * arg)1431b2b03f8SKarsten Keil da_timer(struct FsmInst *fi, int event, void *arg)
1441b2b03f8SKarsten Keil {
1451b2b03f8SKarsten Keil struct manager *mgr = fi->userdata;
1461b2b03f8SKarsten Keil struct layer2 *l2;
1471b2b03f8SKarsten Keil u_long flags;
1481b2b03f8SKarsten Keil
1491b2b03f8SKarsten Keil /* check again */
1501b2b03f8SKarsten Keil read_lock_irqsave(&mgr->lock, flags);
1511b2b03f8SKarsten Keil list_for_each_entry(l2, &mgr->layer2, list) {
1521b2b03f8SKarsten Keil if (l2->l2m.state > ST_L2_4) {
1531b2b03f8SKarsten Keil /* have still activ TEI */
1541b2b03f8SKarsten Keil read_unlock_irqrestore(&mgr->lock, flags);
1551b2b03f8SKarsten Keil mISDN_FsmChangeState(fi, ST_L1_ACTIV);
1561b2b03f8SKarsten Keil return;
1571b2b03f8SKarsten Keil }
1581b2b03f8SKarsten Keil }
1591b2b03f8SKarsten Keil read_unlock_irqrestore(&mgr->lock, flags);
1601b2b03f8SKarsten Keil /* All TEI are inactiv */
1611b2b03f8SKarsten Keil mISDN_FsmChangeState(fi, ST_L1_DEACT);
1621b2b03f8SKarsten Keil _queue_data(&mgr->ch, PH_DEACTIVATE_REQ, MISDN_ID_ANY, 0, NULL,
1631b2b03f8SKarsten Keil GFP_ATOMIC);
1641b2b03f8SKarsten Keil }
1651b2b03f8SKarsten Keil
1661b2b03f8SKarsten Keil static struct FsmNode DeactFnList[] =
1671b2b03f8SKarsten Keil {
1681b2b03f8SKarsten Keil {ST_L1_DEACT, EV_ACTIVATE_IND, da_activate},
1691b2b03f8SKarsten Keil {ST_L1_ACTIV, EV_DEACTIVATE_IND, da_deactivate_ind},
1701b2b03f8SKarsten Keil {ST_L1_ACTIV, EV_DEACTIVATE, da_deactivate},
1711b2b03f8SKarsten Keil {ST_L1_DEACT_PENDING, EV_ACTIVATE, da_activate},
1721b2b03f8SKarsten Keil {ST_L1_DEACT_PENDING, EV_UI, da_ui},
1731b2b03f8SKarsten Keil {ST_L1_DEACT_PENDING, EV_DATIMER, da_timer},
1741b2b03f8SKarsten Keil };
1751b2b03f8SKarsten Keil
1761b2b03f8SKarsten Keil enum {
1771b2b03f8SKarsten Keil ST_TEI_NOP,
1781b2b03f8SKarsten Keil ST_TEI_IDREQ,
1791b2b03f8SKarsten Keil ST_TEI_IDVERIFY,
1801b2b03f8SKarsten Keil };
1811b2b03f8SKarsten Keil
1821b2b03f8SKarsten Keil #define TEI_STATE_COUNT (ST_TEI_IDVERIFY + 1)
1831b2b03f8SKarsten Keil
1841b2b03f8SKarsten Keil static char *strTeiState[] =
1851b2b03f8SKarsten Keil {
1861b2b03f8SKarsten Keil "ST_TEI_NOP",
1871b2b03f8SKarsten Keil "ST_TEI_IDREQ",
1881b2b03f8SKarsten Keil "ST_TEI_IDVERIFY",
1891b2b03f8SKarsten Keil };
1901b2b03f8SKarsten Keil
1911b2b03f8SKarsten Keil enum {
1921b2b03f8SKarsten Keil EV_IDREQ,
1931b2b03f8SKarsten Keil EV_ASSIGN,
1941b2b03f8SKarsten Keil EV_ASSIGN_REQ,
1951b2b03f8SKarsten Keil EV_DENIED,
1961b2b03f8SKarsten Keil EV_CHKREQ,
1971b2b03f8SKarsten Keil EV_CHKRESP,
1981b2b03f8SKarsten Keil EV_REMOVE,
1991b2b03f8SKarsten Keil EV_VERIFY,
2001b2b03f8SKarsten Keil EV_TIMER,
2011b2b03f8SKarsten Keil };
2021b2b03f8SKarsten Keil
2031b2b03f8SKarsten Keil #define TEI_EVENT_COUNT (EV_TIMER + 1)
2041b2b03f8SKarsten Keil
2051b2b03f8SKarsten Keil static char *strTeiEvent[] =
2061b2b03f8SKarsten Keil {
2071b2b03f8SKarsten Keil "EV_IDREQ",
2081b2b03f8SKarsten Keil "EV_ASSIGN",
2091b2b03f8SKarsten Keil "EV_ASSIGN_REQ",
2101b2b03f8SKarsten Keil "EV_DENIED",
2111b2b03f8SKarsten Keil "EV_CHKREQ",
2121b2b03f8SKarsten Keil "EV_CHKRESP",
2131b2b03f8SKarsten Keil "EV_REMOVE",
2141b2b03f8SKarsten Keil "EV_VERIFY",
2151b2b03f8SKarsten Keil "EV_TIMER",
2161b2b03f8SKarsten Keil };
2171b2b03f8SKarsten Keil
2181b2b03f8SKarsten Keil static void
tei_debug(struct FsmInst * fi,char * fmt,...)2191b2b03f8SKarsten Keil tei_debug(struct FsmInst *fi, char *fmt, ...)
2201b2b03f8SKarsten Keil {
2211b2b03f8SKarsten Keil struct teimgr *tm = fi->userdata;
222020f01ebSJoe Perches struct va_format vaf;
2231b2b03f8SKarsten Keil va_list va;
2241b2b03f8SKarsten Keil
2251b2b03f8SKarsten Keil if (!(*debug & DEBUG_L2_TEIFSM))
2261b2b03f8SKarsten Keil return;
227020f01ebSJoe Perches
2281b2b03f8SKarsten Keil va_start(va, fmt);
229020f01ebSJoe Perches
230020f01ebSJoe Perches vaf.fmt = fmt;
231020f01ebSJoe Perches vaf.va = &va;
232020f01ebSJoe Perches
233020f01ebSJoe Perches printk(KERN_DEBUG "sapi(%d) tei(%d): %pV\n",
234020f01ebSJoe Perches tm->l2->sapi, tm->l2->tei, &vaf);
235020f01ebSJoe Perches
2361b2b03f8SKarsten Keil va_end(va);
2371b2b03f8SKarsten Keil }
2381b2b03f8SKarsten Keil
2391b2b03f8SKarsten Keil
2401b2b03f8SKarsten Keil
2411b2b03f8SKarsten Keil static int
get_free_id(struct manager * mgr)2421b2b03f8SKarsten Keil get_free_id(struct manager *mgr)
2431b2b03f8SKarsten Keil {
244481af03bSAkinobu Mita DECLARE_BITMAP(ids, 64) = { [0 ... BITS_TO_LONGS(64) - 1] = 0 };
2451b2b03f8SKarsten Keil int i;
2461b2b03f8SKarsten Keil struct layer2 *l2;
2471b2b03f8SKarsten Keil
2481b2b03f8SKarsten Keil list_for_each_entry(l2, &mgr->layer2, list) {
2491b2b03f8SKarsten Keil if (l2->ch.nr > 63) {
2501b2b03f8SKarsten Keil printk(KERN_WARNING
2511b2b03f8SKarsten Keil "%s: more as 63 layer2 for one device\n",
2521b2b03f8SKarsten Keil __func__);
2531b2b03f8SKarsten Keil return -EBUSY;
2541b2b03f8SKarsten Keil }
255481af03bSAkinobu Mita __set_bit(l2->ch.nr, ids);
2561b2b03f8SKarsten Keil }
257481af03bSAkinobu Mita i = find_next_zero_bit(ids, 64, 1);
258481af03bSAkinobu Mita if (i < 64)
2591b2b03f8SKarsten Keil return i;
2601b2b03f8SKarsten Keil printk(KERN_WARNING "%s: more as 63 layer2 for one device\n",
2611b2b03f8SKarsten Keil __func__);
2621b2b03f8SKarsten Keil return -EBUSY;
2631b2b03f8SKarsten Keil }
2641b2b03f8SKarsten Keil
2651b2b03f8SKarsten Keil static int
get_free_tei(struct manager * mgr)2661b2b03f8SKarsten Keil get_free_tei(struct manager *mgr)
2671b2b03f8SKarsten Keil {
268481af03bSAkinobu Mita DECLARE_BITMAP(ids, 64) = { [0 ... BITS_TO_LONGS(64) - 1] = 0 };
2691b2b03f8SKarsten Keil int i;
2701b2b03f8SKarsten Keil struct layer2 *l2;
2711b2b03f8SKarsten Keil
2721b2b03f8SKarsten Keil list_for_each_entry(l2, &mgr->layer2, list) {
2731b2b03f8SKarsten Keil if (l2->ch.nr == 0)
2741b2b03f8SKarsten Keil continue;
2751b2b03f8SKarsten Keil if ((l2->ch.addr & 0xff) != 0)
2761b2b03f8SKarsten Keil continue;
2771b2b03f8SKarsten Keil i = l2->ch.addr >> 8;
2781b2b03f8SKarsten Keil if (i < 64)
2791b2b03f8SKarsten Keil continue;
2801b2b03f8SKarsten Keil i -= 64;
2811b2b03f8SKarsten Keil
282481af03bSAkinobu Mita __set_bit(i, ids);
2831b2b03f8SKarsten Keil }
284481af03bSAkinobu Mita i = find_first_zero_bit(ids, 64);
285481af03bSAkinobu Mita if (i < 64)
2861b2b03f8SKarsten Keil return i + 64;
2871b2b03f8SKarsten Keil printk(KERN_WARNING "%s: more as 63 dynamic tei for one device\n",
2881b2b03f8SKarsten Keil __func__);
2891b2b03f8SKarsten Keil return -1;
2901b2b03f8SKarsten Keil }
2911b2b03f8SKarsten Keil
2921b2b03f8SKarsten Keil static void
teiup_create(struct manager * mgr,u_int prim,int len,void * arg)2931b2b03f8SKarsten Keil teiup_create(struct manager *mgr, u_int prim, int len, void *arg)
2941b2b03f8SKarsten Keil {
2951b2b03f8SKarsten Keil struct sk_buff *skb;
2961b2b03f8SKarsten Keil struct mISDNhead *hh;
2971b2b03f8SKarsten Keil int err;
2981b2b03f8SKarsten Keil
2991b2b03f8SKarsten Keil skb = mI_alloc_skb(len, GFP_ATOMIC);
3001b2b03f8SKarsten Keil if (!skb)
3011b2b03f8SKarsten Keil return;
3021b2b03f8SKarsten Keil hh = mISDN_HEAD_P(skb);
3031b2b03f8SKarsten Keil hh->prim = prim;
3041b2b03f8SKarsten Keil hh->id = (mgr->ch.nr << 16) | mgr->ch.addr;
3051b2b03f8SKarsten Keil if (len)
30659ae1d12SJohannes Berg skb_put_data(skb, arg, len);
3071b2b03f8SKarsten Keil err = mgr->up->send(mgr->up, skb);
3081b2b03f8SKarsten Keil if (err) {
3091b2b03f8SKarsten Keil printk(KERN_WARNING "%s: err=%d\n", __func__, err);
3101b2b03f8SKarsten Keil dev_kfree_skb(skb);
3111b2b03f8SKarsten Keil }
3121b2b03f8SKarsten Keil }
3131b2b03f8SKarsten Keil
3141b2b03f8SKarsten Keil static u_int
new_id(struct manager * mgr)3151b2b03f8SKarsten Keil new_id(struct manager *mgr)
3161b2b03f8SKarsten Keil {
3171b2b03f8SKarsten Keil u_int id;
3181b2b03f8SKarsten Keil
3191b2b03f8SKarsten Keil id = mgr->nextid++;
3201b2b03f8SKarsten Keil if (id == 0x7fff)
3211b2b03f8SKarsten Keil mgr->nextid = 1;
3221b2b03f8SKarsten Keil id <<= 16;
3231b2b03f8SKarsten Keil id |= GROUP_TEI << 8;
3241b2b03f8SKarsten Keil id |= TEI_SAPI;
3251b2b03f8SKarsten Keil return id;
3261b2b03f8SKarsten Keil }
3271b2b03f8SKarsten Keil
3281b2b03f8SKarsten Keil static void
do_send(struct manager * mgr)3291b2b03f8SKarsten Keil do_send(struct manager *mgr)
3301b2b03f8SKarsten Keil {
3311b2b03f8SKarsten Keil if (!test_bit(MGR_PH_ACTIVE, &mgr->options))
3321b2b03f8SKarsten Keil return;
3331b2b03f8SKarsten Keil
3341b2b03f8SKarsten Keil if (!test_and_set_bit(MGR_PH_NOTREADY, &mgr->options)) {
3351b2b03f8SKarsten Keil struct sk_buff *skb = skb_dequeue(&mgr->sendq);
3361b2b03f8SKarsten Keil
3371b2b03f8SKarsten Keil if (!skb) {
3381b2b03f8SKarsten Keil test_and_clear_bit(MGR_PH_NOTREADY, &mgr->options);
3391b2b03f8SKarsten Keil return;
3401b2b03f8SKarsten Keil }
3411b2b03f8SKarsten Keil mgr->lastid = mISDN_HEAD_ID(skb);
3421b2b03f8SKarsten Keil mISDN_FsmEvent(&mgr->deact, EV_UI, NULL);
3431b2b03f8SKarsten Keil if (mgr->ch.recv(mgr->ch.peer, skb)) {
3441b2b03f8SKarsten Keil dev_kfree_skb(skb);
3451b2b03f8SKarsten Keil test_and_clear_bit(MGR_PH_NOTREADY, &mgr->options);
3461b2b03f8SKarsten Keil mgr->lastid = MISDN_ID_NONE;
3471b2b03f8SKarsten Keil }
3481b2b03f8SKarsten Keil }
3491b2b03f8SKarsten Keil }
3501b2b03f8SKarsten Keil
3511b2b03f8SKarsten Keil static void
do_ack(struct manager * mgr,u_int id)3521b2b03f8SKarsten Keil do_ack(struct manager *mgr, u_int id)
3531b2b03f8SKarsten Keil {
3541b2b03f8SKarsten Keil if (test_bit(MGR_PH_NOTREADY, &mgr->options)) {
3551b2b03f8SKarsten Keil if (id == mgr->lastid) {
3561b2b03f8SKarsten Keil if (test_bit(MGR_PH_ACTIVE, &mgr->options)) {
3571b2b03f8SKarsten Keil struct sk_buff *skb;
3581b2b03f8SKarsten Keil
3591b2b03f8SKarsten Keil skb = skb_dequeue(&mgr->sendq);
3601b2b03f8SKarsten Keil if (skb) {
3611b2b03f8SKarsten Keil mgr->lastid = mISDN_HEAD_ID(skb);
3621b2b03f8SKarsten Keil if (!mgr->ch.recv(mgr->ch.peer, skb))
3631b2b03f8SKarsten Keil return;
3641b2b03f8SKarsten Keil dev_kfree_skb(skb);
3651b2b03f8SKarsten Keil }
3661b2b03f8SKarsten Keil }
3671b2b03f8SKarsten Keil mgr->lastid = MISDN_ID_NONE;
3681b2b03f8SKarsten Keil test_and_clear_bit(MGR_PH_NOTREADY, &mgr->options);
3691b2b03f8SKarsten Keil }
3701b2b03f8SKarsten Keil }
3711b2b03f8SKarsten Keil }
3721b2b03f8SKarsten Keil
3731b2b03f8SKarsten Keil static void
mgr_send_down(struct manager * mgr,struct sk_buff * skb)3741b2b03f8SKarsten Keil mgr_send_down(struct manager *mgr, struct sk_buff *skb)
3751b2b03f8SKarsten Keil {
3761b2b03f8SKarsten Keil skb_queue_tail(&mgr->sendq, skb);
3771b2b03f8SKarsten Keil if (!test_bit(MGR_PH_ACTIVE, &mgr->options)) {
3781b2b03f8SKarsten Keil _queue_data(&mgr->ch, PH_ACTIVATE_REQ, MISDN_ID_ANY, 0,
3791b2b03f8SKarsten Keil NULL, GFP_KERNEL);
3801b2b03f8SKarsten Keil } else {
3811b2b03f8SKarsten Keil do_send(mgr);
3821b2b03f8SKarsten Keil }
3831b2b03f8SKarsten Keil }
3841b2b03f8SKarsten Keil
3851b2b03f8SKarsten Keil static int
dl_unit_data(struct manager * mgr,struct sk_buff * skb)3861b2b03f8SKarsten Keil dl_unit_data(struct manager *mgr, struct sk_buff *skb)
3871b2b03f8SKarsten Keil {
3881b2b03f8SKarsten Keil if (!test_bit(MGR_OPT_NETWORK, &mgr->options)) /* only net send UI */
3891b2b03f8SKarsten Keil return -EINVAL;
3901b2b03f8SKarsten Keil if (!test_bit(MGR_PH_ACTIVE, &mgr->options))
3911b2b03f8SKarsten Keil _queue_data(&mgr->ch, PH_ACTIVATE_REQ, MISDN_ID_ANY, 0,
3921b2b03f8SKarsten Keil NULL, GFP_KERNEL);
3931b2b03f8SKarsten Keil skb_push(skb, 3);
3941b2b03f8SKarsten Keil skb->data[0] = 0x02; /* SAPI 0 C/R = 1 */
3951b2b03f8SKarsten Keil skb->data[1] = 0xff; /* TEI 127 */
3961b2b03f8SKarsten Keil skb->data[2] = UI; /* UI frame */
3971b2b03f8SKarsten Keil mISDN_HEAD_PRIM(skb) = PH_DATA_REQ;
3981b2b03f8SKarsten Keil mISDN_HEAD_ID(skb) = new_id(mgr);
3991b2b03f8SKarsten Keil skb_queue_tail(&mgr->sendq, skb);
4001b2b03f8SKarsten Keil do_send(mgr);
4011b2b03f8SKarsten Keil return 0;
4021b2b03f8SKarsten Keil }
4031b2b03f8SKarsten Keil
4045b834354SHannes Eder static unsigned int
random_ri(void)4051b2b03f8SKarsten Keil random_ri(void)
4061b2b03f8SKarsten Keil {
4071b2b03f8SKarsten Keil u16 x;
4081b2b03f8SKarsten Keil
4091b2b03f8SKarsten Keil get_random_bytes(&x, sizeof(x));
4101b2b03f8SKarsten Keil return x;
4111b2b03f8SKarsten Keil }
4121b2b03f8SKarsten Keil
4131b2b03f8SKarsten Keil static struct layer2 *
findtei(struct manager * mgr,int tei)4141b2b03f8SKarsten Keil findtei(struct manager *mgr, int tei)
4151b2b03f8SKarsten Keil {
4161b2b03f8SKarsten Keil struct layer2 *l2;
4171b2b03f8SKarsten Keil u_long flags;
4181b2b03f8SKarsten Keil
4191b2b03f8SKarsten Keil read_lock_irqsave(&mgr->lock, flags);
4201b2b03f8SKarsten Keil list_for_each_entry(l2, &mgr->layer2, list) {
4211b2b03f8SKarsten Keil if ((l2->sapi == 0) && (l2->tei > 0) &&
4221b2b03f8SKarsten Keil (l2->tei != GROUP_TEI) && (l2->tei == tei))
4231b2b03f8SKarsten Keil goto done;
4241b2b03f8SKarsten Keil }
4251b2b03f8SKarsten Keil l2 = NULL;
4261b2b03f8SKarsten Keil done:
4271b2b03f8SKarsten Keil read_unlock_irqrestore(&mgr->lock, flags);
4281b2b03f8SKarsten Keil return l2;
4291b2b03f8SKarsten Keil }
4301b2b03f8SKarsten Keil
4311b2b03f8SKarsten Keil static void
put_tei_msg(struct manager * mgr,u_char m_id,unsigned int ri,int tei)4325b277b86SAndreas Eversberg put_tei_msg(struct manager *mgr, u_char m_id, unsigned int ri, int tei)
4331b2b03f8SKarsten Keil {
4341b2b03f8SKarsten Keil struct sk_buff *skb;
4351b2b03f8SKarsten Keil u_char bp[8];
4361b2b03f8SKarsten Keil
4371b2b03f8SKarsten Keil bp[0] = (TEI_SAPI << 2);
4381b2b03f8SKarsten Keil if (test_bit(MGR_OPT_NETWORK, &mgr->options))
4391b2b03f8SKarsten Keil bp[0] |= 2; /* CR:=1 for net command */
4401b2b03f8SKarsten Keil bp[1] = (GROUP_TEI << 1) | 0x1;
4411b2b03f8SKarsten Keil bp[2] = UI;
4421b2b03f8SKarsten Keil bp[3] = TEI_ENTITY_ID;
4431b2b03f8SKarsten Keil bp[4] = ri >> 8;
4441b2b03f8SKarsten Keil bp[5] = ri & 0xff;
4451b2b03f8SKarsten Keil bp[6] = m_id;
4465b277b86SAndreas Eversberg bp[7] = ((tei << 1) & 0xff) | 1;
4475b277b86SAndreas Eversberg skb = _alloc_mISDN_skb(PH_DATA_REQ, new_id(mgr), 8, bp, GFP_ATOMIC);
4481b2b03f8SKarsten Keil if (!skb) {
4491b2b03f8SKarsten Keil printk(KERN_WARNING "%s: no skb for tei msg\n", __func__);
4501b2b03f8SKarsten Keil return;
4511b2b03f8SKarsten Keil }
4521b2b03f8SKarsten Keil mgr_send_down(mgr, skb);
4531b2b03f8SKarsten Keil }
4541b2b03f8SKarsten Keil
4551b2b03f8SKarsten Keil static void
tei_id_request(struct FsmInst * fi,int event,void * arg)4561b2b03f8SKarsten Keil tei_id_request(struct FsmInst *fi, int event, void *arg)
4571b2b03f8SKarsten Keil {
4581b2b03f8SKarsten Keil struct teimgr *tm = fi->userdata;
4591b2b03f8SKarsten Keil
4601b2b03f8SKarsten Keil if (tm->l2->tei != GROUP_TEI) {
4611b2b03f8SKarsten Keil tm->tei_m.printdebug(&tm->tei_m,
462698f9315SUwe Kleine-König "assign request for already assigned tei %d",
4631b2b03f8SKarsten Keil tm->l2->tei);
4641b2b03f8SKarsten Keil return;
4651b2b03f8SKarsten Keil }
4661b2b03f8SKarsten Keil tm->ri = random_ri();
4671b2b03f8SKarsten Keil if (*debug & DEBUG_L2_TEI)
4681b2b03f8SKarsten Keil tm->tei_m.printdebug(&tm->tei_m,
4691b2b03f8SKarsten Keil "assign request ri %d", tm->ri);
4701b2b03f8SKarsten Keil put_tei_msg(tm->mgr, ID_REQUEST, tm->ri, GROUP_TEI);
4711b2b03f8SKarsten Keil mISDN_FsmChangeState(fi, ST_TEI_IDREQ);
4721b2b03f8SKarsten Keil mISDN_FsmAddTimer(&tm->timer, tm->tval, EV_TIMER, NULL, 1);
4731b2b03f8SKarsten Keil tm->nval = 3;
4741b2b03f8SKarsten Keil }
4751b2b03f8SKarsten Keil
4761b2b03f8SKarsten Keil static void
tei_id_assign(struct FsmInst * fi,int event,void * arg)4771b2b03f8SKarsten Keil tei_id_assign(struct FsmInst *fi, int event, void *arg)
4781b2b03f8SKarsten Keil {
4791b2b03f8SKarsten Keil struct teimgr *tm = fi->userdata;
4801b2b03f8SKarsten Keil struct layer2 *l2;
4811b2b03f8SKarsten Keil u_char *dp = arg;
4821b2b03f8SKarsten Keil int ri, tei;
4831b2b03f8SKarsten Keil
4841b2b03f8SKarsten Keil ri = ((unsigned int) *dp++ << 8);
4851b2b03f8SKarsten Keil ri += *dp++;
4861b2b03f8SKarsten Keil dp++;
4871b2b03f8SKarsten Keil tei = *dp >> 1;
4881b2b03f8SKarsten Keil if (*debug & DEBUG_L2_TEI)
4891b2b03f8SKarsten Keil tm->tei_m.printdebug(fi, "identity assign ri %d tei %d",
4901b2b03f8SKarsten Keil ri, tei);
4911b2b03f8SKarsten Keil l2 = findtei(tm->mgr, tei);
4921b2b03f8SKarsten Keil if (l2) { /* same tei is in use */
4931b2b03f8SKarsten Keil if (ri != l2->tm->ri) {
4941b2b03f8SKarsten Keil tm->tei_m.printdebug(fi,
4951b2b03f8SKarsten Keil "possible duplicate assignment tei %d", tei);
4961b2b03f8SKarsten Keil tei_l2(l2, MDL_ERROR_RSP, 0);
4971b2b03f8SKarsten Keil }
4981b2b03f8SKarsten Keil } else if (ri == tm->ri) {
4991b2b03f8SKarsten Keil mISDN_FsmDelTimer(&tm->timer, 1);
5001b2b03f8SKarsten Keil mISDN_FsmChangeState(fi, ST_TEI_NOP);
5011b2b03f8SKarsten Keil tei_l2(tm->l2, MDL_ASSIGN_REQ, tei);
5021b2b03f8SKarsten Keil }
5031b2b03f8SKarsten Keil }
5041b2b03f8SKarsten Keil
5051b2b03f8SKarsten Keil static void
tei_id_test_dup(struct FsmInst * fi,int event,void * arg)5061b2b03f8SKarsten Keil tei_id_test_dup(struct FsmInst *fi, int event, void *arg)
5071b2b03f8SKarsten Keil {
5081b2b03f8SKarsten Keil struct teimgr *tm = fi->userdata;
5091b2b03f8SKarsten Keil struct layer2 *l2;
5101b2b03f8SKarsten Keil u_char *dp = arg;
5111b2b03f8SKarsten Keil int tei, ri;
5121b2b03f8SKarsten Keil
5131b2b03f8SKarsten Keil ri = ((unsigned int) *dp++ << 8);
5141b2b03f8SKarsten Keil ri += *dp++;
5151b2b03f8SKarsten Keil dp++;
5161b2b03f8SKarsten Keil tei = *dp >> 1;
5171b2b03f8SKarsten Keil if (*debug & DEBUG_L2_TEI)
5181b2b03f8SKarsten Keil tm->tei_m.printdebug(fi, "foreign identity assign ri %d tei %d",
5191b2b03f8SKarsten Keil ri, tei);
5201b2b03f8SKarsten Keil l2 = findtei(tm->mgr, tei);
5211b2b03f8SKarsten Keil if (l2) { /* same tei is in use */
5221b2b03f8SKarsten Keil if (ri != l2->tm->ri) { /* and it wasn't our request */
5231b2b03f8SKarsten Keil tm->tei_m.printdebug(fi,
5241b2b03f8SKarsten Keil "possible duplicate assignment tei %d", tei);
5251b2b03f8SKarsten Keil mISDN_FsmEvent(&l2->tm->tei_m, EV_VERIFY, NULL);
5261b2b03f8SKarsten Keil }
5271b2b03f8SKarsten Keil }
5281b2b03f8SKarsten Keil }
5291b2b03f8SKarsten Keil
5301b2b03f8SKarsten Keil static void
tei_id_denied(struct FsmInst * fi,int event,void * arg)5311b2b03f8SKarsten Keil tei_id_denied(struct FsmInst *fi, int event, void *arg)
5321b2b03f8SKarsten Keil {
5331b2b03f8SKarsten Keil struct teimgr *tm = fi->userdata;
5341b2b03f8SKarsten Keil u_char *dp = arg;
5351b2b03f8SKarsten Keil int ri, tei;
5361b2b03f8SKarsten Keil
5371b2b03f8SKarsten Keil ri = ((unsigned int) *dp++ << 8);
5381b2b03f8SKarsten Keil ri += *dp++;
5391b2b03f8SKarsten Keil dp++;
5401b2b03f8SKarsten Keil tei = *dp >> 1;
5411b2b03f8SKarsten Keil if (*debug & DEBUG_L2_TEI)
5421b2b03f8SKarsten Keil tm->tei_m.printdebug(fi, "identity denied ri %d tei %d",
5431b2b03f8SKarsten Keil ri, tei);
5441b2b03f8SKarsten Keil }
5451b2b03f8SKarsten Keil
5461b2b03f8SKarsten Keil static void
tei_id_chk_req(struct FsmInst * fi,int event,void * arg)5471b2b03f8SKarsten Keil tei_id_chk_req(struct FsmInst *fi, int event, void *arg)
5481b2b03f8SKarsten Keil {
5491b2b03f8SKarsten Keil struct teimgr *tm = fi->userdata;
5501b2b03f8SKarsten Keil u_char *dp = arg;
5511b2b03f8SKarsten Keil int tei;
5521b2b03f8SKarsten Keil
5531b2b03f8SKarsten Keil tei = *(dp + 3) >> 1;
5541b2b03f8SKarsten Keil if (*debug & DEBUG_L2_TEI)
5551b2b03f8SKarsten Keil tm->tei_m.printdebug(fi, "identity check req tei %d", tei);
5561b2b03f8SKarsten Keil if ((tm->l2->tei != GROUP_TEI) && ((tei == GROUP_TEI) ||
5571b2b03f8SKarsten Keil (tei == tm->l2->tei))) {
5581b2b03f8SKarsten Keil mISDN_FsmDelTimer(&tm->timer, 4);
5591b2b03f8SKarsten Keil mISDN_FsmChangeState(&tm->tei_m, ST_TEI_NOP);
5601b2b03f8SKarsten Keil put_tei_msg(tm->mgr, ID_CHK_RES, random_ri(), tm->l2->tei);
5611b2b03f8SKarsten Keil }
5621b2b03f8SKarsten Keil }
5631b2b03f8SKarsten Keil
5641b2b03f8SKarsten Keil static void
tei_id_remove(struct FsmInst * fi,int event,void * arg)5651b2b03f8SKarsten Keil tei_id_remove(struct FsmInst *fi, int event, void *arg)
5661b2b03f8SKarsten Keil {
5671b2b03f8SKarsten Keil struct teimgr *tm = fi->userdata;
5681b2b03f8SKarsten Keil u_char *dp = arg;
5691b2b03f8SKarsten Keil int tei;
5701b2b03f8SKarsten Keil
5711b2b03f8SKarsten Keil tei = *(dp + 3) >> 1;
5721b2b03f8SKarsten Keil if (*debug & DEBUG_L2_TEI)
5731b2b03f8SKarsten Keil tm->tei_m.printdebug(fi, "identity remove tei %d", tei);
5741b2b03f8SKarsten Keil if ((tm->l2->tei != GROUP_TEI) &&
5751b2b03f8SKarsten Keil ((tei == GROUP_TEI) || (tei == tm->l2->tei))) {
5761b2b03f8SKarsten Keil mISDN_FsmDelTimer(&tm->timer, 5);
5771b2b03f8SKarsten Keil mISDN_FsmChangeState(&tm->tei_m, ST_TEI_NOP);
5781b2b03f8SKarsten Keil tei_l2(tm->l2, MDL_REMOVE_REQ, 0);
5791b2b03f8SKarsten Keil }
5801b2b03f8SKarsten Keil }
5811b2b03f8SKarsten Keil
5821b2b03f8SKarsten Keil static void
tei_id_verify(struct FsmInst * fi,int event,void * arg)5831b2b03f8SKarsten Keil tei_id_verify(struct FsmInst *fi, int event, void *arg)
5841b2b03f8SKarsten Keil {
5851b2b03f8SKarsten Keil struct teimgr *tm = fi->userdata;
5861b2b03f8SKarsten Keil
5871b2b03f8SKarsten Keil if (*debug & DEBUG_L2_TEI)
5881b2b03f8SKarsten Keil tm->tei_m.printdebug(fi, "id verify request for tei %d",
5891b2b03f8SKarsten Keil tm->l2->tei);
5901b2b03f8SKarsten Keil put_tei_msg(tm->mgr, ID_VERIFY, 0, tm->l2->tei);
5911b2b03f8SKarsten Keil mISDN_FsmChangeState(&tm->tei_m, ST_TEI_IDVERIFY);
5921b2b03f8SKarsten Keil mISDN_FsmAddTimer(&tm->timer, tm->tval, EV_TIMER, NULL, 2);
5931b2b03f8SKarsten Keil tm->nval = 2;
5941b2b03f8SKarsten Keil }
5951b2b03f8SKarsten Keil
5961b2b03f8SKarsten Keil static void
tei_id_req_tout(struct FsmInst * fi,int event,void * arg)5971b2b03f8SKarsten Keil tei_id_req_tout(struct FsmInst *fi, int event, void *arg)
5981b2b03f8SKarsten Keil {
5991b2b03f8SKarsten Keil struct teimgr *tm = fi->userdata;
6001b2b03f8SKarsten Keil
6011b2b03f8SKarsten Keil if (--tm->nval) {
6021b2b03f8SKarsten Keil tm->ri = random_ri();
6031b2b03f8SKarsten Keil if (*debug & DEBUG_L2_TEI)
6041b2b03f8SKarsten Keil tm->tei_m.printdebug(fi, "assign req(%d) ri %d",
6051b2b03f8SKarsten Keil 4 - tm->nval, tm->ri);
6061b2b03f8SKarsten Keil put_tei_msg(tm->mgr, ID_REQUEST, tm->ri, GROUP_TEI);
6071b2b03f8SKarsten Keil mISDN_FsmAddTimer(&tm->timer, tm->tval, EV_TIMER, NULL, 3);
6081b2b03f8SKarsten Keil } else {
6091b2b03f8SKarsten Keil tm->tei_m.printdebug(fi, "assign req failed");
6101b2b03f8SKarsten Keil tei_l2(tm->l2, MDL_ERROR_RSP, 0);
6111b2b03f8SKarsten Keil mISDN_FsmChangeState(fi, ST_TEI_NOP);
6121b2b03f8SKarsten Keil }
6131b2b03f8SKarsten Keil }
6141b2b03f8SKarsten Keil
6151b2b03f8SKarsten Keil static void
tei_id_ver_tout(struct FsmInst * fi,int event,void * arg)6161b2b03f8SKarsten Keil tei_id_ver_tout(struct FsmInst *fi, int event, void *arg)
6171b2b03f8SKarsten Keil {
6181b2b03f8SKarsten Keil struct teimgr *tm = fi->userdata;
6191b2b03f8SKarsten Keil
6201b2b03f8SKarsten Keil if (--tm->nval) {
6211b2b03f8SKarsten Keil if (*debug & DEBUG_L2_TEI)
6221b2b03f8SKarsten Keil tm->tei_m.printdebug(fi,
6231b2b03f8SKarsten Keil "id verify req(%d) for tei %d",
6241b2b03f8SKarsten Keil 3 - tm->nval, tm->l2->tei);
6251b2b03f8SKarsten Keil put_tei_msg(tm->mgr, ID_VERIFY, 0, tm->l2->tei);
6261b2b03f8SKarsten Keil mISDN_FsmAddTimer(&tm->timer, tm->tval, EV_TIMER, NULL, 4);
6271b2b03f8SKarsten Keil } else {
6281b2b03f8SKarsten Keil tm->tei_m.printdebug(fi, "verify req for tei %d failed",
6291b2b03f8SKarsten Keil tm->l2->tei);
6301b2b03f8SKarsten Keil tei_l2(tm->l2, MDL_REMOVE_REQ, 0);
6311b2b03f8SKarsten Keil mISDN_FsmChangeState(fi, ST_TEI_NOP);
6321b2b03f8SKarsten Keil }
6331b2b03f8SKarsten Keil }
6341b2b03f8SKarsten Keil
6351b2b03f8SKarsten Keil static struct FsmNode TeiFnListUser[] =
6361b2b03f8SKarsten Keil {
6371b2b03f8SKarsten Keil {ST_TEI_NOP, EV_IDREQ, tei_id_request},
6381b2b03f8SKarsten Keil {ST_TEI_NOP, EV_ASSIGN, tei_id_test_dup},
6391b2b03f8SKarsten Keil {ST_TEI_NOP, EV_VERIFY, tei_id_verify},
6401b2b03f8SKarsten Keil {ST_TEI_NOP, EV_REMOVE, tei_id_remove},
6411b2b03f8SKarsten Keil {ST_TEI_NOP, EV_CHKREQ, tei_id_chk_req},
6421b2b03f8SKarsten Keil {ST_TEI_IDREQ, EV_TIMER, tei_id_req_tout},
6431b2b03f8SKarsten Keil {ST_TEI_IDREQ, EV_ASSIGN, tei_id_assign},
6441b2b03f8SKarsten Keil {ST_TEI_IDREQ, EV_DENIED, tei_id_denied},
6451b2b03f8SKarsten Keil {ST_TEI_IDVERIFY, EV_TIMER, tei_id_ver_tout},
6461b2b03f8SKarsten Keil {ST_TEI_IDVERIFY, EV_REMOVE, tei_id_remove},
6471b2b03f8SKarsten Keil {ST_TEI_IDVERIFY, EV_CHKREQ, tei_id_chk_req},
6481b2b03f8SKarsten Keil };
6491b2b03f8SKarsten Keil
6501b2b03f8SKarsten Keil static void
tei_l2remove(struct layer2 * l2)6511b2b03f8SKarsten Keil tei_l2remove(struct layer2 *l2)
6521b2b03f8SKarsten Keil {
6531b2b03f8SKarsten Keil put_tei_msg(l2->tm->mgr, ID_REMOVE, 0, l2->tei);
6541b2b03f8SKarsten Keil tei_l2(l2, MDL_REMOVE_REQ, 0);
6551b2b03f8SKarsten Keil list_del(&l2->ch.list);
6561b2b03f8SKarsten Keil l2->ch.ctrl(&l2->ch, CLOSE_CHANNEL, NULL);
6571b2b03f8SKarsten Keil }
6581b2b03f8SKarsten Keil
6591b2b03f8SKarsten Keil static void
tei_assign_req(struct FsmInst * fi,int event,void * arg)6601b2b03f8SKarsten Keil tei_assign_req(struct FsmInst *fi, int event, void *arg)
6611b2b03f8SKarsten Keil {
6621b2b03f8SKarsten Keil struct teimgr *tm = fi->userdata;
6631b2b03f8SKarsten Keil u_char *dp = arg;
6641b2b03f8SKarsten Keil
6651b2b03f8SKarsten Keil if (tm->l2->tei == GROUP_TEI) {
6661b2b03f8SKarsten Keil tm->tei_m.printdebug(&tm->tei_m,
6671b2b03f8SKarsten Keil "net tei assign request without tei");
6681b2b03f8SKarsten Keil return;
6691b2b03f8SKarsten Keil }
6701b2b03f8SKarsten Keil tm->ri = ((unsigned int) *dp++ << 8);
6711b2b03f8SKarsten Keil tm->ri += *dp++;
6721b2b03f8SKarsten Keil if (*debug & DEBUG_L2_TEI)
6731b2b03f8SKarsten Keil tm->tei_m.printdebug(&tm->tei_m,
6741b2b03f8SKarsten Keil "net assign request ri %d teim %d", tm->ri, *dp);
6751b2b03f8SKarsten Keil put_tei_msg(tm->mgr, ID_ASSIGNED, tm->ri, tm->l2->tei);
6761b2b03f8SKarsten Keil mISDN_FsmChangeState(fi, ST_TEI_NOP);
6771b2b03f8SKarsten Keil }
6781b2b03f8SKarsten Keil
6791b2b03f8SKarsten Keil static void
tei_id_chk_req_net(struct FsmInst * fi,int event,void * arg)6801b2b03f8SKarsten Keil tei_id_chk_req_net(struct FsmInst *fi, int event, void *arg)
6811b2b03f8SKarsten Keil {
6821b2b03f8SKarsten Keil struct teimgr *tm = fi->userdata;
6831b2b03f8SKarsten Keil
6841b2b03f8SKarsten Keil if (*debug & DEBUG_L2_TEI)
6851b2b03f8SKarsten Keil tm->tei_m.printdebug(fi, "id check request for tei %d",
6861b2b03f8SKarsten Keil tm->l2->tei);
6871b2b03f8SKarsten Keil tm->rcnt = 0;
6881b2b03f8SKarsten Keil put_tei_msg(tm->mgr, ID_CHK_REQ, 0, tm->l2->tei);
6891b2b03f8SKarsten Keil mISDN_FsmChangeState(&tm->tei_m, ST_TEI_IDVERIFY);
6901b2b03f8SKarsten Keil mISDN_FsmAddTimer(&tm->timer, tm->tval, EV_TIMER, NULL, 2);
6911b2b03f8SKarsten Keil tm->nval = 2;
6921b2b03f8SKarsten Keil }
6931b2b03f8SKarsten Keil
6941b2b03f8SKarsten Keil static void
tei_id_chk_resp(struct FsmInst * fi,int event,void * arg)6951b2b03f8SKarsten Keil tei_id_chk_resp(struct FsmInst *fi, int event, void *arg)
6961b2b03f8SKarsten Keil {
6971b2b03f8SKarsten Keil struct teimgr *tm = fi->userdata;
6981b2b03f8SKarsten Keil u_char *dp = arg;
6991b2b03f8SKarsten Keil int tei;
7001b2b03f8SKarsten Keil
7011b2b03f8SKarsten Keil tei = dp[3] >> 1;
7021b2b03f8SKarsten Keil if (*debug & DEBUG_L2_TEI)
7031b2b03f8SKarsten Keil tm->tei_m.printdebug(fi, "identity check resp tei %d", tei);
7041b2b03f8SKarsten Keil if (tei == tm->l2->tei)
7051b2b03f8SKarsten Keil tm->rcnt++;
7061b2b03f8SKarsten Keil }
7071b2b03f8SKarsten Keil
7081b2b03f8SKarsten Keil static void
tei_id_verify_net(struct FsmInst * fi,int event,void * arg)7091b2b03f8SKarsten Keil tei_id_verify_net(struct FsmInst *fi, int event, void *arg)
7101b2b03f8SKarsten Keil {
7111b2b03f8SKarsten Keil struct teimgr *tm = fi->userdata;
7121b2b03f8SKarsten Keil u_char *dp = arg;
7131b2b03f8SKarsten Keil int tei;
7141b2b03f8SKarsten Keil
7151b2b03f8SKarsten Keil tei = dp[3] >> 1;
7161b2b03f8SKarsten Keil if (*debug & DEBUG_L2_TEI)
7171b2b03f8SKarsten Keil tm->tei_m.printdebug(fi, "identity verify req tei %d/%d",
7181b2b03f8SKarsten Keil tei, tm->l2->tei);
7191b2b03f8SKarsten Keil if (tei == tm->l2->tei)
7201b2b03f8SKarsten Keil tei_id_chk_req_net(fi, event, arg);
7211b2b03f8SKarsten Keil }
7221b2b03f8SKarsten Keil
7231b2b03f8SKarsten Keil static void
tei_id_ver_tout_net(struct FsmInst * fi,int event,void * arg)7241b2b03f8SKarsten Keil tei_id_ver_tout_net(struct FsmInst *fi, int event, void *arg)
7251b2b03f8SKarsten Keil {
7261b2b03f8SKarsten Keil struct teimgr *tm = fi->userdata;
7271b2b03f8SKarsten Keil
7281b2b03f8SKarsten Keil if (tm->rcnt == 1) {
7291b2b03f8SKarsten Keil if (*debug & DEBUG_L2_TEI)
7301b2b03f8SKarsten Keil tm->tei_m.printdebug(fi,
731af901ca1SAndré Goddard Rosa "check req for tei %d successful\n", tm->l2->tei);
7321b2b03f8SKarsten Keil mISDN_FsmChangeState(fi, ST_TEI_NOP);
7331b2b03f8SKarsten Keil } else if (tm->rcnt > 1) {
7341b2b03f8SKarsten Keil /* duplicate assignment; remove */
7351b2b03f8SKarsten Keil tei_l2remove(tm->l2);
7361b2b03f8SKarsten Keil } else if (--tm->nval) {
7371b2b03f8SKarsten Keil if (*debug & DEBUG_L2_TEI)
7381b2b03f8SKarsten Keil tm->tei_m.printdebug(fi,
7391b2b03f8SKarsten Keil "id check req(%d) for tei %d",
7401b2b03f8SKarsten Keil 3 - tm->nval, tm->l2->tei);
7411b2b03f8SKarsten Keil put_tei_msg(tm->mgr, ID_CHK_REQ, 0, tm->l2->tei);
7421b2b03f8SKarsten Keil mISDN_FsmAddTimer(&tm->timer, tm->tval, EV_TIMER, NULL, 4);
7431b2b03f8SKarsten Keil } else {
7441b2b03f8SKarsten Keil tm->tei_m.printdebug(fi, "check req for tei %d failed",
7451b2b03f8SKarsten Keil tm->l2->tei);
7461b2b03f8SKarsten Keil mISDN_FsmChangeState(fi, ST_TEI_NOP);
7471b2b03f8SKarsten Keil tei_l2remove(tm->l2);
7481b2b03f8SKarsten Keil }
7491b2b03f8SKarsten Keil }
7501b2b03f8SKarsten Keil
7511b2b03f8SKarsten Keil static struct FsmNode TeiFnListNet[] =
7521b2b03f8SKarsten Keil {
7531b2b03f8SKarsten Keil {ST_TEI_NOP, EV_ASSIGN_REQ, tei_assign_req},
7541b2b03f8SKarsten Keil {ST_TEI_NOP, EV_VERIFY, tei_id_verify_net},
7551b2b03f8SKarsten Keil {ST_TEI_NOP, EV_CHKREQ, tei_id_chk_req_net},
7561b2b03f8SKarsten Keil {ST_TEI_IDVERIFY, EV_TIMER, tei_id_ver_tout_net},
7571b2b03f8SKarsten Keil {ST_TEI_IDVERIFY, EV_CHKRESP, tei_id_chk_resp},
7581b2b03f8SKarsten Keil };
7591b2b03f8SKarsten Keil
7601b2b03f8SKarsten Keil static void
tei_ph_data_ind(struct teimgr * tm,u_int mt,u_char * dp,int len)7611b2b03f8SKarsten Keil tei_ph_data_ind(struct teimgr *tm, u_int mt, u_char *dp, int len)
7621b2b03f8SKarsten Keil {
7631b2b03f8SKarsten Keil if (test_bit(FLG_FIXED_TEI, &tm->l2->flag))
7641b2b03f8SKarsten Keil return;
7651b2b03f8SKarsten Keil if (*debug & DEBUG_L2_TEI)
7661b2b03f8SKarsten Keil tm->tei_m.printdebug(&tm->tei_m, "tei handler mt %x", mt);
7671b2b03f8SKarsten Keil if (mt == ID_ASSIGNED)
7681b2b03f8SKarsten Keil mISDN_FsmEvent(&tm->tei_m, EV_ASSIGN, dp);
7691b2b03f8SKarsten Keil else if (mt == ID_DENIED)
7701b2b03f8SKarsten Keil mISDN_FsmEvent(&tm->tei_m, EV_DENIED, dp);
7711b2b03f8SKarsten Keil else if (mt == ID_CHK_REQ)
7721b2b03f8SKarsten Keil mISDN_FsmEvent(&tm->tei_m, EV_CHKREQ, dp);
7731b2b03f8SKarsten Keil else if (mt == ID_REMOVE)
7741b2b03f8SKarsten Keil mISDN_FsmEvent(&tm->tei_m, EV_REMOVE, dp);
7751b2b03f8SKarsten Keil else if (mt == ID_VERIFY)
7761b2b03f8SKarsten Keil mISDN_FsmEvent(&tm->tei_m, EV_VERIFY, dp);
7771b2b03f8SKarsten Keil else if (mt == ID_CHK_RES)
7781b2b03f8SKarsten Keil mISDN_FsmEvent(&tm->tei_m, EV_CHKRESP, dp);
7791b2b03f8SKarsten Keil }
7801b2b03f8SKarsten Keil
7811b2b03f8SKarsten Keil static struct layer2 *
create_new_tei(struct manager * mgr,int tei,int sapi)7825b277b86SAndreas Eversberg create_new_tei(struct manager *mgr, int tei, int sapi)
7831b2b03f8SKarsten Keil {
7847ed80fe4SKarsten Keil unsigned long opt = 0;
7857ed80fe4SKarsten Keil unsigned long flags;
7861b2b03f8SKarsten Keil int id;
7871b2b03f8SKarsten Keil struct layer2 *l2;
7887ed80fe4SKarsten Keil struct channel_req rq;
7891b2b03f8SKarsten Keil
7901b2b03f8SKarsten Keil if (!mgr->up)
7911b2b03f8SKarsten Keil return NULL;
7925b277b86SAndreas Eversberg if ((tei >= 0) && (tei < 64))
7931b2b03f8SKarsten Keil test_and_set_bit(OPTION_L2_FIXEDTEI, &opt);
7947ed80fe4SKarsten Keil if (mgr->ch.st->dev->Dprotocols & ((1 << ISDN_P_TE_E1) |
7957ed80fe4SKarsten Keil (1 << ISDN_P_NT_E1))) {
7961b2b03f8SKarsten Keil test_and_set_bit(OPTION_L2_PMX, &opt);
7977ed80fe4SKarsten Keil rq.protocol = ISDN_P_NT_E1;
7987ed80fe4SKarsten Keil } else {
7997ed80fe4SKarsten Keil rq.protocol = ISDN_P_NT_S0;
8007ed80fe4SKarsten Keil }
8015b277b86SAndreas Eversberg l2 = create_l2(mgr->up, ISDN_P_LAPD_NT, opt, tei, sapi);
8021b2b03f8SKarsten Keil if (!l2) {
8031b2b03f8SKarsten Keil printk(KERN_WARNING "%s:no memory for layer2\n", __func__);
8041b2b03f8SKarsten Keil return NULL;
8051b2b03f8SKarsten Keil }
8061b2b03f8SKarsten Keil l2->tm = kzalloc(sizeof(struct teimgr), GFP_KERNEL);
8071b2b03f8SKarsten Keil if (!l2->tm) {
8081b2b03f8SKarsten Keil kfree(l2);
8091b2b03f8SKarsten Keil printk(KERN_WARNING "%s:no memory for teimgr\n", __func__);
8101b2b03f8SKarsten Keil return NULL;
8111b2b03f8SKarsten Keil }
8121b2b03f8SKarsten Keil l2->tm->mgr = mgr;
8131b2b03f8SKarsten Keil l2->tm->l2 = l2;
8141b2b03f8SKarsten Keil l2->tm->tei_m.debug = *debug & DEBUG_L2_TEIFSM;
8151b2b03f8SKarsten Keil l2->tm->tei_m.userdata = l2->tm;
8161b2b03f8SKarsten Keil l2->tm->tei_m.printdebug = tei_debug;
8171b2b03f8SKarsten Keil l2->tm->tei_m.fsm = &teifsmn;
8181b2b03f8SKarsten Keil l2->tm->tei_m.state = ST_TEI_NOP;
8191b2b03f8SKarsten Keil l2->tm->tval = 2000; /* T202 2 sec */
8201b2b03f8SKarsten Keil mISDN_FsmInitTimer(&l2->tm->tei_m, &l2->tm->timer);
8211b2b03f8SKarsten Keil write_lock_irqsave(&mgr->lock, flags);
8221b2b03f8SKarsten Keil id = get_free_id(mgr);
8231b2b03f8SKarsten Keil list_add_tail(&l2->list, &mgr->layer2);
8241b2b03f8SKarsten Keil write_unlock_irqrestore(&mgr->lock, flags);
8251b2b03f8SKarsten Keil if (id < 0) {
8261b2b03f8SKarsten Keil l2->ch.ctrl(&l2->ch, CLOSE_CHANNEL, NULL);
8271b2b03f8SKarsten Keil printk(KERN_WARNING "%s:no free id\n", __func__);
8281b2b03f8SKarsten Keil return NULL;
8291b2b03f8SKarsten Keil } else {
8301b2b03f8SKarsten Keil l2->ch.nr = id;
8311b2b03f8SKarsten Keil __add_layer2(&l2->ch, mgr->ch.st);
8321b2b03f8SKarsten Keil l2->ch.recv = mgr->ch.recv;
8331b2b03f8SKarsten Keil l2->ch.peer = mgr->ch.peer;
8341b2b03f8SKarsten Keil l2->ch.ctrl(&l2->ch, OPEN_CHANNEL, NULL);
8357ed80fe4SKarsten Keil /* We need open here L1 for the manager as well (refcounting) */
8367ed80fe4SKarsten Keil rq.adr.dev = mgr->ch.st->dev->id;
8377ed80fe4SKarsten Keil id = mgr->ch.st->own.ctrl(&mgr->ch.st->own, OPEN_CHANNEL, &rq);
8387ed80fe4SKarsten Keil if (id < 0) {
8397ed80fe4SKarsten Keil printk(KERN_WARNING "%s: cannot open L1\n", __func__);
8407ed80fe4SKarsten Keil l2->ch.ctrl(&l2->ch, CLOSE_CHANNEL, NULL);
8417ed80fe4SKarsten Keil l2 = NULL;
8427ed80fe4SKarsten Keil }
8431b2b03f8SKarsten Keil }
8441b2b03f8SKarsten Keil return l2;
8451b2b03f8SKarsten Keil }
8461b2b03f8SKarsten Keil
8471b2b03f8SKarsten Keil static void
new_tei_req(struct manager * mgr,u_char * dp)8481b2b03f8SKarsten Keil new_tei_req(struct manager *mgr, u_char *dp)
8491b2b03f8SKarsten Keil {
8501b2b03f8SKarsten Keil int tei, ri;
8511b2b03f8SKarsten Keil struct layer2 *l2;
8521b2b03f8SKarsten Keil
8531b2b03f8SKarsten Keil ri = dp[0] << 8;
8541b2b03f8SKarsten Keil ri += dp[1];
8551b2b03f8SKarsten Keil if (!mgr->up)
8561b2b03f8SKarsten Keil goto denied;
8575b277b86SAndreas Eversberg if (!(dp[3] & 1)) /* Extension bit != 1 */
8585b277b86SAndreas Eversberg goto denied;
8595b277b86SAndreas Eversberg if (dp[3] != 0xff)
8605b277b86SAndreas Eversberg tei = dp[3] >> 1; /* 3GPP TS 08.56 6.1.11.2 */
8615b277b86SAndreas Eversberg else
8621b2b03f8SKarsten Keil tei = get_free_tei(mgr);
8631b2b03f8SKarsten Keil if (tei < 0) {
8641b2b03f8SKarsten Keil printk(KERN_WARNING "%s:No free tei\n", __func__);
8651b2b03f8SKarsten Keil goto denied;
8661b2b03f8SKarsten Keil }
8675b277b86SAndreas Eversberg l2 = create_new_tei(mgr, tei, CTRL_SAPI);
8681b2b03f8SKarsten Keil if (!l2)
8691b2b03f8SKarsten Keil goto denied;
8701b2b03f8SKarsten Keil else
8711b2b03f8SKarsten Keil mISDN_FsmEvent(&l2->tm->tei_m, EV_ASSIGN_REQ, dp);
8721b2b03f8SKarsten Keil return;
8731b2b03f8SKarsten Keil denied:
8741b2b03f8SKarsten Keil put_tei_msg(mgr, ID_DENIED, ri, GROUP_TEI);
8751b2b03f8SKarsten Keil }
8761b2b03f8SKarsten Keil
8771b2b03f8SKarsten Keil static int
ph_data_ind(struct manager * mgr,struct sk_buff * skb)8781b2b03f8SKarsten Keil ph_data_ind(struct manager *mgr, struct sk_buff *skb)
8791b2b03f8SKarsten Keil {
8801b2b03f8SKarsten Keil int ret = -EINVAL;
8818164491dSKarsten Keil struct layer2 *l2, *nl2;
8821b2b03f8SKarsten Keil u_char mt;
8831b2b03f8SKarsten Keil
8841b2b03f8SKarsten Keil if (skb->len < 8) {
8851b2b03f8SKarsten Keil if (*debug & DEBUG_L2_TEI)
8861b2b03f8SKarsten Keil printk(KERN_DEBUG "%s: short mgr frame %d/8\n",
8871b2b03f8SKarsten Keil __func__, skb->len);
8881b2b03f8SKarsten Keil goto done;
8891b2b03f8SKarsten Keil }
8901b2b03f8SKarsten Keil
8911b2b03f8SKarsten Keil if ((skb->data[0] >> 2) != TEI_SAPI) /* not for us */
8921b2b03f8SKarsten Keil goto done;
8931b2b03f8SKarsten Keil if (skb->data[0] & 1) /* EA0 formal error */
8941b2b03f8SKarsten Keil goto done;
8951b2b03f8SKarsten Keil if (!(skb->data[1] & 1)) /* EA1 formal error */
8961b2b03f8SKarsten Keil goto done;
8971b2b03f8SKarsten Keil if ((skb->data[1] >> 1) != GROUP_TEI) /* not for us */
8981b2b03f8SKarsten Keil goto done;
8991b2b03f8SKarsten Keil if ((skb->data[2] & 0xef) != UI) /* not UI */
9001b2b03f8SKarsten Keil goto done;
9011b2b03f8SKarsten Keil if (skb->data[3] != TEI_ENTITY_ID) /* not tei entity */
9021b2b03f8SKarsten Keil goto done;
9031b2b03f8SKarsten Keil mt = skb->data[6];
9041b2b03f8SKarsten Keil switch (mt) {
9051b2b03f8SKarsten Keil case ID_REQUEST:
9061b2b03f8SKarsten Keil case ID_CHK_RES:
9071b2b03f8SKarsten Keil case ID_VERIFY:
9081b2b03f8SKarsten Keil if (!test_bit(MGR_OPT_NETWORK, &mgr->options))
9091b2b03f8SKarsten Keil goto done;
9101b2b03f8SKarsten Keil break;
9111b2b03f8SKarsten Keil case ID_ASSIGNED:
9121b2b03f8SKarsten Keil case ID_DENIED:
9131b2b03f8SKarsten Keil case ID_CHK_REQ:
9141b2b03f8SKarsten Keil case ID_REMOVE:
9151b2b03f8SKarsten Keil if (test_bit(MGR_OPT_NETWORK, &mgr->options))
9161b2b03f8SKarsten Keil goto done;
9171b2b03f8SKarsten Keil break;
9181b2b03f8SKarsten Keil default:
9191b2b03f8SKarsten Keil goto done;
9201b2b03f8SKarsten Keil }
9211b2b03f8SKarsten Keil ret = 0;
9221b2b03f8SKarsten Keil if (mt == ID_REQUEST) {
9231b2b03f8SKarsten Keil new_tei_req(mgr, &skb->data[4]);
9241b2b03f8SKarsten Keil goto done;
9251b2b03f8SKarsten Keil }
9268164491dSKarsten Keil list_for_each_entry_safe(l2, nl2, &mgr->layer2, list) {
9271b2b03f8SKarsten Keil tei_ph_data_ind(l2->tm, mt, &skb->data[4], skb->len - 4);
9281b2b03f8SKarsten Keil }
9291b2b03f8SKarsten Keil done:
9301b2b03f8SKarsten Keil return ret;
9311b2b03f8SKarsten Keil }
9321b2b03f8SKarsten Keil
9331b2b03f8SKarsten Keil int
l2_tei(struct layer2 * l2,u_int cmd,u_long arg)9341b2b03f8SKarsten Keil l2_tei(struct layer2 *l2, u_int cmd, u_long arg)
9351b2b03f8SKarsten Keil {
9361b2b03f8SKarsten Keil struct teimgr *tm = l2->tm;
9371b2b03f8SKarsten Keil
9381b2b03f8SKarsten Keil if (test_bit(FLG_FIXED_TEI, &l2->flag))
9391b2b03f8SKarsten Keil return 0;
9401b2b03f8SKarsten Keil if (*debug & DEBUG_L2_TEI)
9411b2b03f8SKarsten Keil printk(KERN_DEBUG "%s: cmd(%x)\n", __func__, cmd);
9421b2b03f8SKarsten Keil switch (cmd) {
9431b2b03f8SKarsten Keil case MDL_ASSIGN_IND:
9441b2b03f8SKarsten Keil mISDN_FsmEvent(&tm->tei_m, EV_IDREQ, NULL);
9451b2b03f8SKarsten Keil break;
9461b2b03f8SKarsten Keil case MDL_ERROR_IND:
9471b2b03f8SKarsten Keil if (test_bit(MGR_OPT_NETWORK, &tm->mgr->options))
9481b2b03f8SKarsten Keil mISDN_FsmEvent(&tm->tei_m, EV_CHKREQ, &l2->tei);
9491b2b03f8SKarsten Keil if (test_bit(MGR_OPT_USER, &tm->mgr->options))
9501b2b03f8SKarsten Keil mISDN_FsmEvent(&tm->tei_m, EV_VERIFY, NULL);
9511b2b03f8SKarsten Keil break;
9521b2b03f8SKarsten Keil case MDL_STATUS_UP_IND:
9531b2b03f8SKarsten Keil if (test_bit(MGR_OPT_NETWORK, &tm->mgr->options))
9541b2b03f8SKarsten Keil mISDN_FsmEvent(&tm->mgr->deact, EV_ACTIVATE, NULL);
9551b2b03f8SKarsten Keil break;
9561b2b03f8SKarsten Keil case MDL_STATUS_DOWN_IND:
9571b2b03f8SKarsten Keil if (test_bit(MGR_OPT_NETWORK, &tm->mgr->options))
9581b2b03f8SKarsten Keil mISDN_FsmEvent(&tm->mgr->deact, EV_DEACTIVATE, NULL);
9591b2b03f8SKarsten Keil break;
9601b2b03f8SKarsten Keil case MDL_STATUS_UI_IND:
9611b2b03f8SKarsten Keil if (test_bit(MGR_OPT_NETWORK, &tm->mgr->options))
9621b2b03f8SKarsten Keil mISDN_FsmEvent(&tm->mgr->deact, EV_UI, NULL);
9631b2b03f8SKarsten Keil break;
9641b2b03f8SKarsten Keil }
9651b2b03f8SKarsten Keil return 0;
9661b2b03f8SKarsten Keil }
9671b2b03f8SKarsten Keil
9681b2b03f8SKarsten Keil void
TEIrelease(struct layer2 * l2)969c5b61d59SKarsten Keil TEIrelease(struct layer2 *l2)
9701b2b03f8SKarsten Keil {
9711b2b03f8SKarsten Keil struct teimgr *tm = l2->tm;
9721b2b03f8SKarsten Keil u_long flags;
9731b2b03f8SKarsten Keil
9741b2b03f8SKarsten Keil mISDN_FsmDelTimer(&tm->timer, 1);
9751b2b03f8SKarsten Keil write_lock_irqsave(&tm->mgr->lock, flags);
9761b2b03f8SKarsten Keil list_del(&l2->list);
9771b2b03f8SKarsten Keil write_unlock_irqrestore(&tm->mgr->lock, flags);
9781b2b03f8SKarsten Keil l2->tm = NULL;
9791b2b03f8SKarsten Keil kfree(tm);
9801b2b03f8SKarsten Keil }
9811b2b03f8SKarsten Keil
9821b2b03f8SKarsten Keil static int
create_teimgr(struct manager * mgr,struct channel_req * crq)9831b2b03f8SKarsten Keil create_teimgr(struct manager *mgr, struct channel_req *crq)
9841b2b03f8SKarsten Keil {
9851b2b03f8SKarsten Keil struct layer2 *l2;
9867ed80fe4SKarsten Keil unsigned long opt = 0;
9877ed80fe4SKarsten Keil unsigned long flags;
9881b2b03f8SKarsten Keil int id;
9897ed80fe4SKarsten Keil struct channel_req l1rq;
9901b2b03f8SKarsten Keil
9911b2b03f8SKarsten Keil if (*debug & DEBUG_L2_TEI)
9921b2b03f8SKarsten Keil printk(KERN_DEBUG "%s: %s proto(%x) adr(%d %d %d %d)\n",
993837468d1SMatthias Urlichs __func__, dev_name(&mgr->ch.st->dev->dev),
994837468d1SMatthias Urlichs crq->protocol, crq->adr.dev, crq->adr.channel,
995837468d1SMatthias Urlichs crq->adr.sapi, crq->adr.tei);
9961b2b03f8SKarsten Keil if (crq->adr.tei > GROUP_TEI)
9971b2b03f8SKarsten Keil return -EINVAL;
9981b2b03f8SKarsten Keil if (crq->adr.tei < 64)
9991b2b03f8SKarsten Keil test_and_set_bit(OPTION_L2_FIXEDTEI, &opt);
10001b2b03f8SKarsten Keil if (crq->adr.tei == 0)
10011b2b03f8SKarsten Keil test_and_set_bit(OPTION_L2_PTP, &opt);
10021b2b03f8SKarsten Keil if (test_bit(MGR_OPT_NETWORK, &mgr->options)) {
10031b2b03f8SKarsten Keil if (crq->protocol == ISDN_P_LAPD_TE)
10041b2b03f8SKarsten Keil return -EPROTONOSUPPORT;
10051b2b03f8SKarsten Keil if ((crq->adr.tei != 0) && (crq->adr.tei != 127))
10061b2b03f8SKarsten Keil return -EINVAL;
10071b2b03f8SKarsten Keil if (mgr->up) {
10081b2b03f8SKarsten Keil printk(KERN_WARNING
10091b2b03f8SKarsten Keil "%s: only one network manager is allowed\n",
10101b2b03f8SKarsten Keil __func__);
10111b2b03f8SKarsten Keil return -EBUSY;
10121b2b03f8SKarsten Keil }
10131b2b03f8SKarsten Keil } else if (test_bit(MGR_OPT_USER, &mgr->options)) {
10141b2b03f8SKarsten Keil if (crq->protocol == ISDN_P_LAPD_NT)
10151b2b03f8SKarsten Keil return -EPROTONOSUPPORT;
10161b2b03f8SKarsten Keil if ((crq->adr.tei >= 64) && (crq->adr.tei < GROUP_TEI))
10171b2b03f8SKarsten Keil return -EINVAL; /* dyn tei */
10181b2b03f8SKarsten Keil } else {
10191b2b03f8SKarsten Keil if (crq->protocol == ISDN_P_LAPD_NT)
10201b2b03f8SKarsten Keil test_and_set_bit(MGR_OPT_NETWORK, &mgr->options);
10211b2b03f8SKarsten Keil if (crq->protocol == ISDN_P_LAPD_TE)
10221b2b03f8SKarsten Keil test_and_set_bit(MGR_OPT_USER, &mgr->options);
10231b2b03f8SKarsten Keil }
10247ed80fe4SKarsten Keil l1rq.adr = crq->adr;
10251b2b03f8SKarsten Keil if (mgr->ch.st->dev->Dprotocols
10261b2b03f8SKarsten Keil & ((1 << ISDN_P_TE_E1) | (1 << ISDN_P_NT_E1)))
10271b2b03f8SKarsten Keil test_and_set_bit(OPTION_L2_PMX, &opt);
10281b2b03f8SKarsten Keil if ((crq->protocol == ISDN_P_LAPD_NT) && (crq->adr.tei == 127)) {
10291b2b03f8SKarsten Keil mgr->up = crq->ch;
10301b2b03f8SKarsten Keil id = DL_INFO_L2_CONNECT;
10311b2b03f8SKarsten Keil teiup_create(mgr, DL_INFORMATION_IND, sizeof(id), &id);
103282107b73SAndreas Eversberg if (test_bit(MGR_PH_ACTIVE, &mgr->options))
103382107b73SAndreas Eversberg teiup_create(mgr, PH_ACTIVATE_IND, 0, NULL);
10341b2b03f8SKarsten Keil crq->ch = NULL;
10351b2b03f8SKarsten Keil if (!list_empty(&mgr->layer2)) {
10361b2b03f8SKarsten Keil read_lock_irqsave(&mgr->lock, flags);
10371b2b03f8SKarsten Keil list_for_each_entry(l2, &mgr->layer2, list) {
10381b2b03f8SKarsten Keil l2->up = mgr->up;
10391b2b03f8SKarsten Keil l2->ch.ctrl(&l2->ch, OPEN_CHANNEL, NULL);
10401b2b03f8SKarsten Keil }
10411b2b03f8SKarsten Keil read_unlock_irqrestore(&mgr->lock, flags);
10421b2b03f8SKarsten Keil }
10431b2b03f8SKarsten Keil return 0;
10441b2b03f8SKarsten Keil }
10455b277b86SAndreas Eversberg l2 = create_l2(crq->ch, crq->protocol, opt,
10465b277b86SAndreas Eversberg crq->adr.tei, crq->adr.sapi);
10471b2b03f8SKarsten Keil if (!l2)
10481b2b03f8SKarsten Keil return -ENOMEM;
10491b2b03f8SKarsten Keil l2->tm = kzalloc(sizeof(struct teimgr), GFP_KERNEL);
10501b2b03f8SKarsten Keil if (!l2->tm) {
10511b2b03f8SKarsten Keil kfree(l2);
10521b2b03f8SKarsten Keil printk(KERN_ERR "kmalloc teimgr failed\n");
10531b2b03f8SKarsten Keil return -ENOMEM;
10541b2b03f8SKarsten Keil }
10551b2b03f8SKarsten Keil l2->tm->mgr = mgr;
10561b2b03f8SKarsten Keil l2->tm->l2 = l2;
10571b2b03f8SKarsten Keil l2->tm->tei_m.debug = *debug & DEBUG_L2_TEIFSM;
10581b2b03f8SKarsten Keil l2->tm->tei_m.userdata = l2->tm;
10591b2b03f8SKarsten Keil l2->tm->tei_m.printdebug = tei_debug;
10601b2b03f8SKarsten Keil if (crq->protocol == ISDN_P_LAPD_TE) {
10611b2b03f8SKarsten Keil l2->tm->tei_m.fsm = &teifsmu;
10621b2b03f8SKarsten Keil l2->tm->tei_m.state = ST_TEI_NOP;
10631b2b03f8SKarsten Keil l2->tm->tval = 1000; /* T201 1 sec */
10647ed80fe4SKarsten Keil if (test_bit(OPTION_L2_PMX, &opt))
10657ed80fe4SKarsten Keil l1rq.protocol = ISDN_P_TE_E1;
10667ed80fe4SKarsten Keil else
10677ed80fe4SKarsten Keil l1rq.protocol = ISDN_P_TE_S0;
10681b2b03f8SKarsten Keil } else {
10691b2b03f8SKarsten Keil l2->tm->tei_m.fsm = &teifsmn;
10701b2b03f8SKarsten Keil l2->tm->tei_m.state = ST_TEI_NOP;
10711b2b03f8SKarsten Keil l2->tm->tval = 2000; /* T202 2 sec */
10727ed80fe4SKarsten Keil if (test_bit(OPTION_L2_PMX, &opt))
10737ed80fe4SKarsten Keil l1rq.protocol = ISDN_P_NT_E1;
10747ed80fe4SKarsten Keil else
10757ed80fe4SKarsten Keil l1rq.protocol = ISDN_P_NT_S0;
10761b2b03f8SKarsten Keil }
10771b2b03f8SKarsten Keil mISDN_FsmInitTimer(&l2->tm->tei_m, &l2->tm->timer);
10781b2b03f8SKarsten Keil write_lock_irqsave(&mgr->lock, flags);
10791b2b03f8SKarsten Keil id = get_free_id(mgr);
10801b2b03f8SKarsten Keil list_add_tail(&l2->list, &mgr->layer2);
10811b2b03f8SKarsten Keil write_unlock_irqrestore(&mgr->lock, flags);
10827ed80fe4SKarsten Keil if (id >= 0) {
10831b2b03f8SKarsten Keil l2->ch.nr = id;
10841b2b03f8SKarsten Keil l2->up->nr = id;
10851b2b03f8SKarsten Keil crq->ch = &l2->ch;
10867ed80fe4SKarsten Keil /* We need open here L1 for the manager as well (refcounting) */
10877ed80fe4SKarsten Keil id = mgr->ch.st->own.ctrl(&mgr->ch.st->own, OPEN_CHANNEL,
10887ed80fe4SKarsten Keil &l1rq);
10891b2b03f8SKarsten Keil }
10907ed80fe4SKarsten Keil if (id < 0)
10917ed80fe4SKarsten Keil l2->ch.ctrl(&l2->ch, CLOSE_CHANNEL, NULL);
10921b2b03f8SKarsten Keil return id;
10931b2b03f8SKarsten Keil }
10941b2b03f8SKarsten Keil
10951b2b03f8SKarsten Keil static int
mgr_send(struct mISDNchannel * ch,struct sk_buff * skb)10961b2b03f8SKarsten Keil mgr_send(struct mISDNchannel *ch, struct sk_buff *skb)
10971b2b03f8SKarsten Keil {
10981b2b03f8SKarsten Keil struct manager *mgr;
10991b2b03f8SKarsten Keil struct mISDNhead *hh = mISDN_HEAD_P(skb);
11001b2b03f8SKarsten Keil int ret = -EINVAL;
11011b2b03f8SKarsten Keil
11021b2b03f8SKarsten Keil mgr = container_of(ch, struct manager, ch);
11031b2b03f8SKarsten Keil if (*debug & DEBUG_L2_RECV)
11041b2b03f8SKarsten Keil printk(KERN_DEBUG "%s: prim(%x) id(%x)\n",
11051b2b03f8SKarsten Keil __func__, hh->prim, hh->id);
11061b2b03f8SKarsten Keil switch (hh->prim) {
11071b2b03f8SKarsten Keil case PH_DATA_IND:
11081b2b03f8SKarsten Keil mISDN_FsmEvent(&mgr->deact, EV_UI, NULL);
11091b2b03f8SKarsten Keil ret = ph_data_ind(mgr, skb);
11101b2b03f8SKarsten Keil break;
11111b2b03f8SKarsten Keil case PH_DATA_CNF:
11121b2b03f8SKarsten Keil do_ack(mgr, hh->id);
11131b2b03f8SKarsten Keil ret = 0;
11141b2b03f8SKarsten Keil break;
11151b2b03f8SKarsten Keil case PH_ACTIVATE_IND:
11161b2b03f8SKarsten Keil test_and_set_bit(MGR_PH_ACTIVE, &mgr->options);
111782107b73SAndreas Eversberg if (mgr->up)
111882107b73SAndreas Eversberg teiup_create(mgr, PH_ACTIVATE_IND, 0, NULL);
11191b2b03f8SKarsten Keil mISDN_FsmEvent(&mgr->deact, EV_ACTIVATE_IND, NULL);
11201b2b03f8SKarsten Keil do_send(mgr);
11211b2b03f8SKarsten Keil ret = 0;
11221b2b03f8SKarsten Keil break;
11231b2b03f8SKarsten Keil case PH_DEACTIVATE_IND:
11241b2b03f8SKarsten Keil test_and_clear_bit(MGR_PH_ACTIVE, &mgr->options);
112582107b73SAndreas Eversberg if (mgr->up)
112682107b73SAndreas Eversberg teiup_create(mgr, PH_DEACTIVATE_IND, 0, NULL);
11271b2b03f8SKarsten Keil mISDN_FsmEvent(&mgr->deact, EV_DEACTIVATE_IND, NULL);
11281b2b03f8SKarsten Keil ret = 0;
11291b2b03f8SKarsten Keil break;
11301b2b03f8SKarsten Keil case DL_UNITDATA_REQ:
11311b2b03f8SKarsten Keil return dl_unit_data(mgr, skb);
11321b2b03f8SKarsten Keil }
11331b2b03f8SKarsten Keil if (!ret)
11341b2b03f8SKarsten Keil dev_kfree_skb(skb);
11351b2b03f8SKarsten Keil return ret;
11361b2b03f8SKarsten Keil }
11371b2b03f8SKarsten Keil
11381b2b03f8SKarsten Keil static int
free_teimanager(struct manager * mgr)11391b2b03f8SKarsten Keil free_teimanager(struct manager *mgr)
11401b2b03f8SKarsten Keil {
11411b2b03f8SKarsten Keil struct layer2 *l2, *nl2;
11421b2b03f8SKarsten Keil
1143e73f6b22SAndreas Eversberg test_and_clear_bit(OPTION_L1_HOLD, &mgr->options);
11441b2b03f8SKarsten Keil if (test_bit(MGR_OPT_NETWORK, &mgr->options)) {
11451b2b03f8SKarsten Keil /* not locked lock is taken in release tei */
11461b2b03f8SKarsten Keil mgr->up = NULL;
11471b2b03f8SKarsten Keil if (test_bit(OPTION_L2_CLEANUP, &mgr->options)) {
11481b2b03f8SKarsten Keil list_for_each_entry_safe(l2, nl2, &mgr->layer2, list) {
11491b2b03f8SKarsten Keil put_tei_msg(mgr, ID_REMOVE, 0, l2->tei);
11501b2b03f8SKarsten Keil mutex_lock(&mgr->ch.st->lmutex);
11511b2b03f8SKarsten Keil list_del(&l2->ch.list);
11521b2b03f8SKarsten Keil mutex_unlock(&mgr->ch.st->lmutex);
11531b2b03f8SKarsten Keil l2->ch.ctrl(&l2->ch, CLOSE_CHANNEL, NULL);
11541b2b03f8SKarsten Keil }
11551b2b03f8SKarsten Keil test_and_clear_bit(MGR_OPT_NETWORK, &mgr->options);
11561b2b03f8SKarsten Keil } else {
11571b2b03f8SKarsten Keil list_for_each_entry_safe(l2, nl2, &mgr->layer2, list) {
11581b2b03f8SKarsten Keil l2->up = NULL;
11591b2b03f8SKarsten Keil }
11601b2b03f8SKarsten Keil }
11611b2b03f8SKarsten Keil }
11621b2b03f8SKarsten Keil if (test_bit(MGR_OPT_USER, &mgr->options)) {
11631b2b03f8SKarsten Keil if (list_empty(&mgr->layer2))
11641b2b03f8SKarsten Keil test_and_clear_bit(MGR_OPT_USER, &mgr->options);
11651b2b03f8SKarsten Keil }
11661b2b03f8SKarsten Keil mgr->ch.st->dev->D.ctrl(&mgr->ch.st->dev->D, CLOSE_CHANNEL, NULL);
11671b2b03f8SKarsten Keil return 0;
11681b2b03f8SKarsten Keil }
11691b2b03f8SKarsten Keil
11701b2b03f8SKarsten Keil static int
ctrl_teimanager(struct manager * mgr,void * arg)11711b2b03f8SKarsten Keil ctrl_teimanager(struct manager *mgr, void *arg)
11721b2b03f8SKarsten Keil {
11731b2b03f8SKarsten Keil /* currently we only have one option */
1174aeb5e02aSNathan Chancellor unsigned int *val = (unsigned int *)arg;
11751b2b03f8SKarsten Keil
1176e73f6b22SAndreas Eversberg switch (val[0]) {
1177e73f6b22SAndreas Eversberg case IMCLEAR_L2:
1178e73f6b22SAndreas Eversberg if (val[1])
11791b2b03f8SKarsten Keil test_and_set_bit(OPTION_L2_CLEANUP, &mgr->options);
11801b2b03f8SKarsten Keil else
11811b2b03f8SKarsten Keil test_and_clear_bit(OPTION_L2_CLEANUP, &mgr->options);
1182e73f6b22SAndreas Eversberg break;
1183e73f6b22SAndreas Eversberg case IMHOLD_L1:
1184e73f6b22SAndreas Eversberg if (val[1])
1185e73f6b22SAndreas Eversberg test_and_set_bit(OPTION_L1_HOLD, &mgr->options);
1186e73f6b22SAndreas Eversberg else
1187e73f6b22SAndreas Eversberg test_and_clear_bit(OPTION_L1_HOLD, &mgr->options);
1188e73f6b22SAndreas Eversberg break;
1189e73f6b22SAndreas Eversberg default:
1190aeb5e02aSNathan Chancellor return -EINVAL;
1191e73f6b22SAndreas Eversberg }
1192aeb5e02aSNathan Chancellor return 0;
11931b2b03f8SKarsten Keil }
11941b2b03f8SKarsten Keil
11951b2b03f8SKarsten Keil /* This function does create a L2 for fixed TEI in NT Mode */
11961b2b03f8SKarsten Keil static int
check_data(struct manager * mgr,struct sk_buff * skb)11971b2b03f8SKarsten Keil check_data(struct manager *mgr, struct sk_buff *skb)
11981b2b03f8SKarsten Keil {
11991b2b03f8SKarsten Keil struct mISDNhead *hh = mISDN_HEAD_P(skb);
12005b277b86SAndreas Eversberg int ret, tei, sapi;
12011b2b03f8SKarsten Keil struct layer2 *l2;
12021b2b03f8SKarsten Keil
12031b2b03f8SKarsten Keil if (*debug & DEBUG_L2_CTRL)
12041b2b03f8SKarsten Keil printk(KERN_DEBUG "%s: prim(%x) id(%x)\n",
12051b2b03f8SKarsten Keil __func__, hh->prim, hh->id);
12061b2b03f8SKarsten Keil if (test_bit(MGR_OPT_USER, &mgr->options))
12071b2b03f8SKarsten Keil return -ENOTCONN;
12081b2b03f8SKarsten Keil if (hh->prim != PH_DATA_IND)
12091b2b03f8SKarsten Keil return -ENOTCONN;
12101b2b03f8SKarsten Keil if (skb->len != 3)
12111b2b03f8SKarsten Keil return -ENOTCONN;
12125b277b86SAndreas Eversberg if (skb->data[0] & 3) /* EA0 and CR must be 0 */
12135b277b86SAndreas Eversberg return -EINVAL;
12145b277b86SAndreas Eversberg sapi = skb->data[0] >> 2;
12151b2b03f8SKarsten Keil if (!(skb->data[1] & 1)) /* invalid EA1 */
12161b2b03f8SKarsten Keil return -EINVAL;
12175b277b86SAndreas Eversberg tei = skb->data[1] >> 1;
12181b2b03f8SKarsten Keil if (tei > 63) /* not a fixed tei */
12191b2b03f8SKarsten Keil return -ENOTCONN;
12201b2b03f8SKarsten Keil if ((skb->data[2] & ~0x10) != SABME)
12211b2b03f8SKarsten Keil return -ENOTCONN;
12221b2b03f8SKarsten Keil /* We got a SABME for a fixed TEI */
1223d796509aSAndreas Eversberg if (*debug & DEBUG_L2_CTRL)
1224d796509aSAndreas Eversberg printk(KERN_DEBUG "%s: SABME sapi(%d) tei(%d)\n",
1225d796509aSAndreas Eversberg __func__, sapi, tei);
12265b277b86SAndreas Eversberg l2 = create_new_tei(mgr, tei, sapi);
1227d796509aSAndreas Eversberg if (!l2) {
1228d796509aSAndreas Eversberg if (*debug & DEBUG_L2_CTRL)
1229d796509aSAndreas Eversberg printk(KERN_DEBUG "%s: failed to create new tei\n",
1230d796509aSAndreas Eversberg __func__);
12311b2b03f8SKarsten Keil return -ENOMEM;
1232d796509aSAndreas Eversberg }
12331b2b03f8SKarsten Keil ret = l2->ch.send(&l2->ch, skb);
12341b2b03f8SKarsten Keil return ret;
12351b2b03f8SKarsten Keil }
12361b2b03f8SKarsten Keil
12371b2b03f8SKarsten Keil void
delete_teimanager(struct mISDNchannel * ch)12381b2b03f8SKarsten Keil delete_teimanager(struct mISDNchannel *ch)
12391b2b03f8SKarsten Keil {
12401b2b03f8SKarsten Keil struct manager *mgr;
12411b2b03f8SKarsten Keil struct layer2 *l2, *nl2;
12421b2b03f8SKarsten Keil
12431b2b03f8SKarsten Keil mgr = container_of(ch, struct manager, ch);
12441b2b03f8SKarsten Keil /* not locked lock is taken in release tei */
12451b2b03f8SKarsten Keil list_for_each_entry_safe(l2, nl2, &mgr->layer2, list) {
12461b2b03f8SKarsten Keil mutex_lock(&mgr->ch.st->lmutex);
12471b2b03f8SKarsten Keil list_del(&l2->ch.list);
12481b2b03f8SKarsten Keil mutex_unlock(&mgr->ch.st->lmutex);
12491b2b03f8SKarsten Keil l2->ch.ctrl(&l2->ch, CLOSE_CHANNEL, NULL);
12501b2b03f8SKarsten Keil }
12511b2b03f8SKarsten Keil list_del(&mgr->ch.list);
12521b2b03f8SKarsten Keil list_del(&mgr->bcast.list);
12531b2b03f8SKarsten Keil skb_queue_purge(&mgr->sendq);
12541b2b03f8SKarsten Keil kfree(mgr);
12551b2b03f8SKarsten Keil }
12561b2b03f8SKarsten Keil
12571b2b03f8SKarsten Keil static int
mgr_ctrl(struct mISDNchannel * ch,u_int cmd,void * arg)12581b2b03f8SKarsten Keil mgr_ctrl(struct mISDNchannel *ch, u_int cmd, void *arg)
12591b2b03f8SKarsten Keil {
12601b2b03f8SKarsten Keil struct manager *mgr;
12611b2b03f8SKarsten Keil int ret = -EINVAL;
12621b2b03f8SKarsten Keil
12631b2b03f8SKarsten Keil mgr = container_of(ch, struct manager, ch);
12641b2b03f8SKarsten Keil if (*debug & DEBUG_L2_CTRL)
12651b2b03f8SKarsten Keil printk(KERN_DEBUG "%s(%x, %p)\n", __func__, cmd, arg);
12661b2b03f8SKarsten Keil switch (cmd) {
12671b2b03f8SKarsten Keil case OPEN_CHANNEL:
12681b2b03f8SKarsten Keil ret = create_teimgr(mgr, arg);
12691b2b03f8SKarsten Keil break;
12701b2b03f8SKarsten Keil case CLOSE_CHANNEL:
12711b2b03f8SKarsten Keil ret = free_teimanager(mgr);
12721b2b03f8SKarsten Keil break;
12731b2b03f8SKarsten Keil case CONTROL_CHANNEL:
12741b2b03f8SKarsten Keil ret = ctrl_teimanager(mgr, arg);
12751b2b03f8SKarsten Keil break;
12761b2b03f8SKarsten Keil case CHECK_DATA:
12771b2b03f8SKarsten Keil ret = check_data(mgr, arg);
12781b2b03f8SKarsten Keil break;
12791b2b03f8SKarsten Keil }
12801b2b03f8SKarsten Keil return ret;
12811b2b03f8SKarsten Keil }
12821b2b03f8SKarsten Keil
12831b2b03f8SKarsten Keil static int
mgr_bcast(struct mISDNchannel * ch,struct sk_buff * skb)12841b2b03f8SKarsten Keil mgr_bcast(struct mISDNchannel *ch, struct sk_buff *skb)
12851b2b03f8SKarsten Keil {
12861b2b03f8SKarsten Keil struct manager *mgr = container_of(ch, struct manager, bcast);
12878423e6b2SKarsten Keil struct mISDNhead *hhc, *hh = mISDN_HEAD_P(skb);
12881b2b03f8SKarsten Keil struct sk_buff *cskb = NULL;
12891b2b03f8SKarsten Keil struct layer2 *l2;
12901b2b03f8SKarsten Keil u_long flags;
12911b2b03f8SKarsten Keil int ret;
12921b2b03f8SKarsten Keil
12931b2b03f8SKarsten Keil read_lock_irqsave(&mgr->lock, flags);
12941b2b03f8SKarsten Keil list_for_each_entry(l2, &mgr->layer2, list) {
12951b2b03f8SKarsten Keil if ((hh->id & MISDN_ID_SAPI_MASK) ==
12961b2b03f8SKarsten Keil (l2->ch.addr & MISDN_ID_SAPI_MASK)) {
12971b2b03f8SKarsten Keil if (list_is_last(&l2->list, &mgr->layer2)) {
12981b2b03f8SKarsten Keil cskb = skb;
12991b2b03f8SKarsten Keil skb = NULL;
13001b2b03f8SKarsten Keil } else {
13011b2b03f8SKarsten Keil if (!cskb)
13028423e6b2SKarsten Keil cskb = skb_copy(skb, GFP_ATOMIC);
13031b2b03f8SKarsten Keil }
13041b2b03f8SKarsten Keil if (cskb) {
13058423e6b2SKarsten Keil hhc = mISDN_HEAD_P(cskb);
13068423e6b2SKarsten Keil /* save original header behind normal header */
13078423e6b2SKarsten Keil hhc++;
13088423e6b2SKarsten Keil *hhc = *hh;
13098423e6b2SKarsten Keil hhc--;
13108423e6b2SKarsten Keil hhc->prim = DL_INTERN_MSG;
13118423e6b2SKarsten Keil hhc->id = l2->ch.nr;
13128423e6b2SKarsten Keil ret = ch->st->own.recv(&ch->st->own, cskb);
13131b2b03f8SKarsten Keil if (ret) {
13141b2b03f8SKarsten Keil if (*debug & DEBUG_SEND_ERR)
13151b2b03f8SKarsten Keil printk(KERN_DEBUG
13161b2b03f8SKarsten Keil "%s ch%d prim(%x) addr(%x)"
13171b2b03f8SKarsten Keil " err %d\n",
13181b2b03f8SKarsten Keil __func__, l2->ch.nr,
13191b2b03f8SKarsten Keil hh->prim, l2->ch.addr, ret);
13201b2b03f8SKarsten Keil } else
13211b2b03f8SKarsten Keil cskb = NULL;
13221b2b03f8SKarsten Keil } else {
13231b2b03f8SKarsten Keil printk(KERN_WARNING "%s ch%d addr %x no mem\n",
13241b2b03f8SKarsten Keil __func__, ch->nr, ch->addr);
13251b2b03f8SKarsten Keil goto out;
13261b2b03f8SKarsten Keil }
13271b2b03f8SKarsten Keil }
13281b2b03f8SKarsten Keil }
13291b2b03f8SKarsten Keil out:
13301b2b03f8SKarsten Keil read_unlock_irqrestore(&mgr->lock, flags);
13311b2b03f8SKarsten Keil dev_kfree_skb(cskb);
13321b2b03f8SKarsten Keil dev_kfree_skb(skb);
13331b2b03f8SKarsten Keil return 0;
13341b2b03f8SKarsten Keil }
13351b2b03f8SKarsten Keil
13361b2b03f8SKarsten Keil static int
mgr_bcast_ctrl(struct mISDNchannel * ch,u_int cmd,void * arg)13371b2b03f8SKarsten Keil mgr_bcast_ctrl(struct mISDNchannel *ch, u_int cmd, void *arg)
13381b2b03f8SKarsten Keil {
13391b2b03f8SKarsten Keil
13401b2b03f8SKarsten Keil return -EINVAL;
13411b2b03f8SKarsten Keil }
13421b2b03f8SKarsten Keil
13431b2b03f8SKarsten Keil int
create_teimanager(struct mISDNdevice * dev)13441b2b03f8SKarsten Keil create_teimanager(struct mISDNdevice *dev)
13451b2b03f8SKarsten Keil {
13461b2b03f8SKarsten Keil struct manager *mgr;
13471b2b03f8SKarsten Keil
13481b2b03f8SKarsten Keil mgr = kzalloc(sizeof(struct manager), GFP_KERNEL);
13491b2b03f8SKarsten Keil if (!mgr)
13501b2b03f8SKarsten Keil return -ENOMEM;
13511b2b03f8SKarsten Keil INIT_LIST_HEAD(&mgr->layer2);
1352702c7904SKarsten Keil rwlock_init(&mgr->lock);
13531b2b03f8SKarsten Keil skb_queue_head_init(&mgr->sendq);
13541b2b03f8SKarsten Keil mgr->nextid = 1;
13551b2b03f8SKarsten Keil mgr->lastid = MISDN_ID_NONE;
13561b2b03f8SKarsten Keil mgr->ch.send = mgr_send;
13571b2b03f8SKarsten Keil mgr->ch.ctrl = mgr_ctrl;
13581b2b03f8SKarsten Keil mgr->ch.st = dev->D.st;
13591b2b03f8SKarsten Keil set_channel_address(&mgr->ch, TEI_SAPI, GROUP_TEI);
13601b2b03f8SKarsten Keil add_layer2(&mgr->ch, dev->D.st);
13611b2b03f8SKarsten Keil mgr->bcast.send = mgr_bcast;
13621b2b03f8SKarsten Keil mgr->bcast.ctrl = mgr_bcast_ctrl;
13631b2b03f8SKarsten Keil mgr->bcast.st = dev->D.st;
13641b2b03f8SKarsten Keil set_channel_address(&mgr->bcast, 0, GROUP_TEI);
13651b2b03f8SKarsten Keil add_layer2(&mgr->bcast, dev->D.st);
13661b2b03f8SKarsten Keil mgr->deact.debug = *debug & DEBUG_MANAGER;
13671b2b03f8SKarsten Keil mgr->deact.userdata = mgr;
13681b2b03f8SKarsten Keil mgr->deact.printdebug = da_debug;
13691b2b03f8SKarsten Keil mgr->deact.fsm = &deactfsm;
13701b2b03f8SKarsten Keil mgr->deact.state = ST_L1_DEACT;
13711b2b03f8SKarsten Keil mISDN_FsmInitTimer(&mgr->deact, &mgr->datimer);
13721b2b03f8SKarsten Keil dev->teimgr = &mgr->ch;
13731b2b03f8SKarsten Keil return 0;
13741b2b03f8SKarsten Keil }
13751b2b03f8SKarsten Keil
TEIInit(u_int * deb)13761b2b03f8SKarsten Keil int TEIInit(u_int *deb)
13771b2b03f8SKarsten Keil {
137854a6a043SAnton Vasilyev int res;
13791b2b03f8SKarsten Keil debug = deb;
13801b2b03f8SKarsten Keil teifsmu.state_count = TEI_STATE_COUNT;
13811b2b03f8SKarsten Keil teifsmu.event_count = TEI_EVENT_COUNT;
13821b2b03f8SKarsten Keil teifsmu.strEvent = strTeiEvent;
13831b2b03f8SKarsten Keil teifsmu.strState = strTeiState;
138454a6a043SAnton Vasilyev res = mISDN_FsmNew(&teifsmu, TeiFnListUser, ARRAY_SIZE(TeiFnListUser));
138554a6a043SAnton Vasilyev if (res)
138654a6a043SAnton Vasilyev goto error;
13871b2b03f8SKarsten Keil teifsmn.state_count = TEI_STATE_COUNT;
13881b2b03f8SKarsten Keil teifsmn.event_count = TEI_EVENT_COUNT;
13891b2b03f8SKarsten Keil teifsmn.strEvent = strTeiEvent;
13901b2b03f8SKarsten Keil teifsmn.strState = strTeiState;
139154a6a043SAnton Vasilyev res = mISDN_FsmNew(&teifsmn, TeiFnListNet, ARRAY_SIZE(TeiFnListNet));
139254a6a043SAnton Vasilyev if (res)
139354a6a043SAnton Vasilyev goto error_smn;
13941b2b03f8SKarsten Keil deactfsm.state_count = DEACT_STATE_COUNT;
13951b2b03f8SKarsten Keil deactfsm.event_count = DEACT_EVENT_COUNT;
13961b2b03f8SKarsten Keil deactfsm.strEvent = strDeactEvent;
13971b2b03f8SKarsten Keil deactfsm.strState = strDeactState;
139854a6a043SAnton Vasilyev res = mISDN_FsmNew(&deactfsm, DeactFnList, ARRAY_SIZE(DeactFnList));
139954a6a043SAnton Vasilyev if (res)
140054a6a043SAnton Vasilyev goto error_deact;
14011b2b03f8SKarsten Keil return 0;
140254a6a043SAnton Vasilyev
140354a6a043SAnton Vasilyev error_deact:
140454a6a043SAnton Vasilyev mISDN_FsmFree(&teifsmn);
140554a6a043SAnton Vasilyev error_smn:
140654a6a043SAnton Vasilyev mISDN_FsmFree(&teifsmu);
140754a6a043SAnton Vasilyev error:
140854a6a043SAnton Vasilyev return res;
14091b2b03f8SKarsten Keil }
14101b2b03f8SKarsten Keil
TEIFree(void)14111b2b03f8SKarsten Keil void TEIFree(void)
14121b2b03f8SKarsten Keil {
14131b2b03f8SKarsten Keil mISDN_FsmFree(&teifsmu);
14141b2b03f8SKarsten Keil mISDN_FsmFree(&teifsmn);
14151b2b03f8SKarsten Keil mISDN_FsmFree(&deactfsm);
14161b2b03f8SKarsten Keil }
1417