diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/isdn/mISDN/Kconfig | 9 | ||||
-rw-r--r-- | drivers/isdn/mISDN/Makefile | 9 | ||||
-rw-r--r-- | drivers/isdn/mISDN/core.c | 244 | ||||
-rw-r--r-- | drivers/isdn/mISDN/core.h | 77 | ||||
-rw-r--r-- | drivers/isdn/mISDN/fsm.c | 183 | ||||
-rw-r--r-- | drivers/isdn/mISDN/fsm.h | 67 | ||||
-rw-r--r-- | drivers/isdn/mISDN/hwchannel.c | 365 | ||||
-rw-r--r-- | drivers/isdn/mISDN/layer1.c | 403 | ||||
-rw-r--r-- | drivers/isdn/mISDN/layer1.h | 26 | ||||
-rw-r--r-- | drivers/isdn/mISDN/layer2.c | 2216 | ||||
-rw-r--r-- | drivers/isdn/mISDN/layer2.h | 140 | ||||
-rw-r--r-- | drivers/isdn/mISDN/socket.c | 781 | ||||
-rw-r--r-- | drivers/isdn/mISDN/stack.c | 674 | ||||
-rw-r--r-- | drivers/isdn/mISDN/tei.c | 1340 | ||||
-rw-r--r-- | drivers/isdn/mISDN/timerdev.c | 301 |
15 files changed, 6835 insertions, 0 deletions
diff --git a/drivers/isdn/mISDN/Kconfig b/drivers/isdn/mISDN/Kconfig new file mode 100644 index 000000000000..231bd0d08316 --- /dev/null +++ b/drivers/isdn/mISDN/Kconfig | |||
@@ -0,0 +1,9 @@ | |||
1 | # | ||
2 | # modularer ISDN driver | ||
3 | # | ||
4 | |||
5 | menuconfig MISDN | ||
6 | tristate "Modular ISDN driver" | ||
7 | help | ||
8 | Enable support for the modular ISDN driver. | ||
9 | |||
diff --git a/drivers/isdn/mISDN/Makefile b/drivers/isdn/mISDN/Makefile new file mode 100644 index 000000000000..87c563d33612 --- /dev/null +++ b/drivers/isdn/mISDN/Makefile | |||
@@ -0,0 +1,9 @@ | |||
1 | # | ||
2 | # Makefile for the modular ISDN driver | ||
3 | # | ||
4 | |||
5 | obj-$(CONFIG_MISDN) += mISDN_core.o | ||
6 | |||
7 | # multi objects | ||
8 | |||
9 | mISDN_core-objs := core.o fsm.o socket.o hwchannel.o stack.o layer1.o layer2.o tei.o timerdev.o | ||
diff --git a/drivers/isdn/mISDN/core.c b/drivers/isdn/mISDN/core.c new file mode 100644 index 000000000000..33068177b7c9 --- /dev/null +++ b/drivers/isdn/mISDN/core.c | |||
@@ -0,0 +1,244 @@ | |||
1 | /* | ||
2 | * Copyright 2008 by Karsten Keil <kkeil@novell.com> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 as | ||
6 | * published by the Free Software Foundation. | ||
7 | * | ||
8 | * This program is distributed in the hope that it will be useful, | ||
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
11 | * GNU General Public License for more details. | ||
12 | * | ||
13 | */ | ||
14 | |||
15 | #include <linux/types.h> | ||
16 | #include <linux/stddef.h> | ||
17 | #include <linux/module.h> | ||
18 | #include <linux/spinlock.h> | ||
19 | #include <linux/mISDNif.h> | ||
20 | #include "core.h" | ||
21 | |||
22 | static u_int debug; | ||
23 | |||
24 | MODULE_AUTHOR("Karsten Keil"); | ||
25 | MODULE_LICENSE("GPL"); | ||
26 | module_param(debug, uint, S_IRUGO | S_IWUSR); | ||
27 | |||
28 | static LIST_HEAD(devices); | ||
29 | DEFINE_RWLOCK(device_lock); | ||
30 | static u64 device_ids; | ||
31 | #define MAX_DEVICE_ID 63 | ||
32 | |||
33 | static LIST_HEAD(Bprotocols); | ||
34 | DEFINE_RWLOCK(bp_lock); | ||
35 | |||
36 | struct mISDNdevice | ||
37 | *get_mdevice(u_int id) | ||
38 | { | ||
39 | struct mISDNdevice *dev; | ||
40 | |||
41 | read_lock(&device_lock); | ||
42 | list_for_each_entry(dev, &devices, D.list) | ||
43 | if (dev->id == id) { | ||
44 | read_unlock(&device_lock); | ||
45 | return dev; | ||
46 | } | ||
47 | read_unlock(&device_lock); | ||
48 | return NULL; | ||
49 | } | ||
50 | |||
51 | int | ||
52 | get_mdevice_count(void) | ||
53 | { | ||
54 | struct mISDNdevice *dev; | ||
55 | int cnt = 0; | ||
56 | |||
57 | read_lock(&device_lock); | ||
58 | list_for_each_entry(dev, &devices, D.list) | ||
59 | cnt++; | ||
60 | read_unlock(&device_lock); | ||
61 | return cnt; | ||
62 | } | ||
63 | |||
64 | static int | ||
65 | get_free_devid(void) | ||
66 | { | ||
67 | u_int i; | ||
68 | |||
69 | for (i = 0; i <= MAX_DEVICE_ID; i++) | ||
70 | if (!test_and_set_bit(i, (u_long *)&device_ids)) | ||
71 | return i; | ||
72 | return -1; | ||
73 | } | ||
74 | |||
75 | int | ||
76 | mISDN_register_device(struct mISDNdevice *dev, char *name) | ||
77 | { | ||
78 | u_long flags; | ||
79 | int err; | ||
80 | |||
81 | dev->id = get_free_devid(); | ||
82 | if (dev->id < 0) | ||
83 | return -EBUSY; | ||
84 | if (name && name[0]) | ||
85 | strcpy(dev->name, name); | ||
86 | else | ||
87 | sprintf(dev->name, "mISDN%d", dev->id); | ||
88 | if (debug & DEBUG_CORE) | ||
89 | printk(KERN_DEBUG "mISDN_register %s %d\n", | ||
90 | dev->name, dev->id); | ||
91 | err = create_stack(dev); | ||
92 | if (err) | ||
93 | return err; | ||
94 | write_lock_irqsave(&device_lock, flags); | ||
95 | list_add_tail(&dev->D.list, &devices); | ||
96 | write_unlock_irqrestore(&device_lock, flags); | ||
97 | return 0; | ||
98 | } | ||
99 | EXPORT_SYMBOL(mISDN_register_device); | ||
100 | |||
101 | void | ||
102 | mISDN_unregister_device(struct mISDNdevice *dev) { | ||
103 | u_long flags; | ||
104 | |||
105 | if (debug & DEBUG_CORE) | ||
106 | printk(KERN_DEBUG "mISDN_unregister %s %d\n", | ||
107 | dev->name, dev->id); | ||
108 | write_lock_irqsave(&device_lock, flags); | ||
109 | list_del(&dev->D.list); | ||
110 | write_unlock_irqrestore(&device_lock, flags); | ||
111 | test_and_clear_bit(dev->id, (u_long *)&device_ids); | ||
112 | delete_stack(dev); | ||
113 | } | ||
114 | EXPORT_SYMBOL(mISDN_unregister_device); | ||
115 | |||
116 | u_int | ||
117 | get_all_Bprotocols(void) | ||
118 | { | ||
119 | struct Bprotocol *bp; | ||
120 | u_int m = 0; | ||
121 | |||
122 | read_lock(&bp_lock); | ||
123 | list_for_each_entry(bp, &Bprotocols, list) | ||
124 | m |= bp->Bprotocols; | ||
125 | read_unlock(&bp_lock); | ||
126 | return m; | ||
127 | } | ||
128 | |||
129 | struct Bprotocol * | ||
130 | get_Bprotocol4mask(u_int m) | ||
131 | { | ||
132 | struct Bprotocol *bp; | ||
133 | |||
134 | read_lock(&bp_lock); | ||
135 | list_for_each_entry(bp, &Bprotocols, list) | ||
136 | if (bp->Bprotocols & m) { | ||
137 | read_unlock(&bp_lock); | ||
138 | return bp; | ||
139 | } | ||
140 | read_unlock(&bp_lock); | ||
141 | return NULL; | ||
142 | } | ||
143 | |||
144 | struct Bprotocol * | ||
145 | get_Bprotocol4id(u_int id) | ||
146 | { | ||
147 | u_int m; | ||
148 | |||
149 | if (id < ISDN_P_B_START || id > 63) { | ||
150 | printk(KERN_WARNING "%s id not in range %d\n", | ||
151 | __func__, id); | ||
152 | return NULL; | ||
153 | } | ||
154 | m = 1 << (id & ISDN_P_B_MASK); | ||
155 | return get_Bprotocol4mask(m); | ||
156 | } | ||
157 | |||
158 | int | ||
159 | mISDN_register_Bprotocol(struct Bprotocol *bp) | ||
160 | { | ||
161 | u_long flags; | ||
162 | struct Bprotocol *old; | ||
163 | |||
164 | if (debug & DEBUG_CORE) | ||
165 | printk(KERN_DEBUG "%s: %s/%x\n", __func__, | ||
166 | bp->name, bp->Bprotocols); | ||
167 | old = get_Bprotocol4mask(bp->Bprotocols); | ||
168 | if (old) { | ||
169 | printk(KERN_WARNING | ||
170 | "register duplicate protocol old %s/%x new %s/%x\n", | ||
171 | old->name, old->Bprotocols, bp->name, bp->Bprotocols); | ||
172 | return -EBUSY; | ||
173 | } | ||
174 | write_lock_irqsave(&bp_lock, flags); | ||
175 | list_add_tail(&bp->list, &Bprotocols); | ||
176 | write_unlock_irqrestore(&bp_lock, flags); | ||
177 | return 0; | ||
178 | } | ||
179 | EXPORT_SYMBOL(mISDN_register_Bprotocol); | ||
180 | |||
181 | void | ||
182 | mISDN_unregister_Bprotocol(struct Bprotocol *bp) | ||
183 | { | ||
184 | u_long flags; | ||
185 | |||
186 | if (debug & DEBUG_CORE) | ||
187 | printk(KERN_DEBUG "%s: %s/%x\n", __func__, bp->name, | ||
188 | bp->Bprotocols); | ||
189 | write_lock_irqsave(&bp_lock, flags); | ||
190 | list_del(&bp->list); | ||
191 | write_unlock_irqrestore(&bp_lock, flags); | ||
192 | } | ||
193 | EXPORT_SYMBOL(mISDN_unregister_Bprotocol); | ||
194 | |||
195 | int | ||
196 | mISDNInit(void) | ||
197 | { | ||
198 | int err; | ||
199 | |||
200 | printk(KERN_INFO "Modular ISDN core version %d.%d.%d\n", | ||
201 | MISDN_MAJOR_VERSION, MISDN_MINOR_VERSION, MISDN_RELEASE); | ||
202 | mISDN_initstack(&debug); | ||
203 | err = mISDN_inittimer(&debug); | ||
204 | if (err) | ||
205 | goto error; | ||
206 | err = l1_init(&debug); | ||
207 | if (err) { | ||
208 | mISDN_timer_cleanup(); | ||
209 | goto error; | ||
210 | } | ||
211 | err = Isdnl2_Init(&debug); | ||
212 | if (err) { | ||
213 | mISDN_timer_cleanup(); | ||
214 | l1_cleanup(); | ||
215 | goto error; | ||
216 | } | ||
217 | err = misdn_sock_init(&debug); | ||
218 | if (err) { | ||
219 | mISDN_timer_cleanup(); | ||
220 | l1_cleanup(); | ||
221 | Isdnl2_cleanup(); | ||
222 | } | ||
223 | error: | ||
224 | return err; | ||
225 | } | ||
226 | |||
227 | void mISDN_cleanup(void) | ||
228 | { | ||
229 | misdn_sock_cleanup(); | ||
230 | mISDN_timer_cleanup(); | ||
231 | l1_cleanup(); | ||
232 | Isdnl2_cleanup(); | ||
233 | |||
234 | if (!list_empty(&devices)) | ||
235 | printk(KERN_ERR "%s devices still registered\n", __func__); | ||
236 | |||
237 | if (!list_empty(&Bprotocols)) | ||
238 | printk(KERN_ERR "%s Bprotocols still registered\n", __func__); | ||
239 | printk(KERN_DEBUG "mISDNcore unloaded\n"); | ||
240 | } | ||
241 | |||
242 | module_init(mISDNInit); | ||
243 | module_exit(mISDN_cleanup); | ||
244 | |||
diff --git a/drivers/isdn/mISDN/core.h b/drivers/isdn/mISDN/core.h new file mode 100644 index 000000000000..7da7233b4c1a --- /dev/null +++ b/drivers/isdn/mISDN/core.h | |||
@@ -0,0 +1,77 @@ | |||
1 | /* | ||
2 | * Copyright 2008 by Karsten Keil <kkeil@novell.com> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 as | ||
6 | * published by the Free Software Foundation. | ||
7 | * | ||
8 | * This program is distributed in the hope that it will be useful, | ||
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
11 | * GNU General Public License for more details. | ||
12 | * | ||
13 | */ | ||
14 | |||
15 | #ifndef mISDN_CORE_H | ||
16 | #define mISDN_CORE_H | ||
17 | |||
18 | extern struct mISDNdevice *get_mdevice(u_int); | ||
19 | extern int get_mdevice_count(void); | ||
20 | |||
21 | /* stack status flag */ | ||
22 | #define mISDN_STACK_ACTION_MASK 0x0000ffff | ||
23 | #define mISDN_STACK_COMMAND_MASK 0x000f0000 | ||
24 | #define mISDN_STACK_STATUS_MASK 0xfff00000 | ||
25 | /* action bits 0-15 */ | ||
26 | #define mISDN_STACK_WORK 0 | ||
27 | #define mISDN_STACK_SETUP 1 | ||
28 | #define mISDN_STACK_CLEARING 2 | ||
29 | #define mISDN_STACK_RESTART 3 | ||
30 | #define mISDN_STACK_WAKEUP 4 | ||
31 | #define mISDN_STACK_ABORT 15 | ||
32 | /* command bits 16-19 */ | ||
33 | #define mISDN_STACK_STOPPED 16 | ||
34 | #define mISDN_STACK_INIT 17 | ||
35 | #define mISDN_STACK_THREADSTART 18 | ||
36 | /* status bits 20-31 */ | ||
37 | #define mISDN_STACK_BCHANNEL 20 | ||
38 | #define mISDN_STACK_ACTIVE 29 | ||
39 | #define mISDN_STACK_RUNNING 30 | ||
40 | #define mISDN_STACK_KILLED 31 | ||
41 | |||
42 | |||
43 | /* manager options */ | ||
44 | #define MGR_OPT_USER 24 | ||
45 | #define MGR_OPT_NETWORK 25 | ||
46 | |||
47 | extern int connect_Bstack(struct mISDNdevice *, struct mISDNchannel *, | ||
48 | u_int, struct sockaddr_mISDN *); | ||
49 | extern int connect_layer1(struct mISDNdevice *, struct mISDNchannel *, | ||
50 | u_int, struct sockaddr_mISDN *); | ||
51 | extern int create_l2entity(struct mISDNdevice *, struct mISDNchannel *, | ||
52 | u_int, struct sockaddr_mISDN *); | ||
53 | |||
54 | extern int create_stack(struct mISDNdevice *); | ||
55 | extern int create_teimanager(struct mISDNdevice *); | ||
56 | extern void delete_teimanager(struct mISDNchannel *); | ||
57 | extern void delete_channel(struct mISDNchannel *); | ||
58 | extern void delete_stack(struct mISDNdevice *); | ||
59 | extern void mISDN_initstack(u_int *); | ||
60 | extern int misdn_sock_init(u_int *); | ||
61 | extern void misdn_sock_cleanup(void); | ||
62 | extern void add_layer2(struct mISDNchannel *, struct mISDNstack *); | ||
63 | extern void __add_layer2(struct mISDNchannel *, struct mISDNstack *); | ||
64 | |||
65 | extern u_int get_all_Bprotocols(void); | ||
66 | struct Bprotocol *get_Bprotocol4mask(u_int); | ||
67 | struct Bprotocol *get_Bprotocol4id(u_int); | ||
68 | |||
69 | extern int mISDN_inittimer(u_int *); | ||
70 | extern void mISDN_timer_cleanup(void); | ||
71 | |||
72 | extern int l1_init(u_int *); | ||
73 | extern void l1_cleanup(void); | ||
74 | extern int Isdnl2_Init(u_int *); | ||
75 | extern void Isdnl2_cleanup(void); | ||
76 | |||
77 | #endif | ||
diff --git a/drivers/isdn/mISDN/fsm.c b/drivers/isdn/mISDN/fsm.c new file mode 100644 index 000000000000..b5d6553f2dc8 --- /dev/null +++ b/drivers/isdn/mISDN/fsm.c | |||
@@ -0,0 +1,183 @@ | |||
1 | /* | ||
2 | * finite state machine implementation | ||
3 | * | ||
4 | * Author Karsten Keil <kkeil@novell.com> | ||
5 | * | ||
6 | * Thanks to Jan den Ouden | ||
7 | * Fritz Elfert | ||
8 | * Copyright 2008 by Karsten Keil <kkeil@novell.com> | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License version 2 as | ||
12 | * published by the Free Software Foundation. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, | ||
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
17 | * GNU General Public License for more details. | ||
18 | * | ||
19 | */ | ||
20 | |||
21 | #include <linux/kernel.h> | ||
22 | #include <linux/slab.h> | ||
23 | #include <linux/module.h> | ||
24 | #include <linux/string.h> | ||
25 | #include "fsm.h" | ||
26 | |||
27 | #define FSM_TIMER_DEBUG 0 | ||
28 | |||
29 | void | ||
30 | mISDN_FsmNew(struct Fsm *fsm, | ||
31 | struct FsmNode *fnlist, int fncount) | ||
32 | { | ||
33 | int i; | ||
34 | |||
35 | fsm->jumpmatrix = kzalloc(sizeof(FSMFNPTR) * fsm->state_count * | ||
36 | fsm->event_count, GFP_KERNEL); | ||
37 | |||
38 | for (i = 0; i < fncount; i++) | ||
39 | if ((fnlist[i].state >= fsm->state_count) || | ||
40 | (fnlist[i].event >= fsm->event_count)) { | ||
41 | printk(KERN_ERR | ||
42 | "mISDN_FsmNew Error: %d st(%ld/%ld) ev(%ld/%ld)\n", | ||
43 | i, (long)fnlist[i].state, (long)fsm->state_count, | ||
44 | (long)fnlist[i].event, (long)fsm->event_count); | ||
45 | } else | ||
46 | fsm->jumpmatrix[fsm->state_count * fnlist[i].event + | ||
47 | fnlist[i].state] = (FSMFNPTR) fnlist[i].routine; | ||
48 | } | ||
49 | EXPORT_SYMBOL(mISDN_FsmNew); | ||
50 | |||
51 | void | ||
52 | mISDN_FsmFree(struct Fsm *fsm) | ||
53 | { | ||
54 | kfree((void *) fsm->jumpmatrix); | ||
55 | } | ||
56 | EXPORT_SYMBOL(mISDN_FsmFree); | ||
57 | |||
58 | int | ||
59 | mISDN_FsmEvent(struct FsmInst *fi, int event, void *arg) | ||
60 | { | ||
61 | FSMFNPTR r; | ||
62 | |||
63 | if ((fi->state >= fi->fsm->state_count) || | ||
64 | (event >= fi->fsm->event_count)) { | ||
65 | printk(KERN_ERR | ||
66 | "mISDN_FsmEvent Error st(%ld/%ld) ev(%d/%ld)\n", | ||
67 | (long)fi->state, (long)fi->fsm->state_count, event, | ||
68 | (long)fi->fsm->event_count); | ||
69 | return 1; | ||
70 | } | ||
71 | r = fi->fsm->jumpmatrix[fi->fsm->state_count * event + fi->state]; | ||
72 | if (r) { | ||
73 | if (fi->debug) | ||
74 | fi->printdebug(fi, "State %s Event %s", | ||
75 | fi->fsm->strState[fi->state], | ||
76 | fi->fsm->strEvent[event]); | ||
77 | r(fi, event, arg); | ||
78 | return 0; | ||
79 | } else { | ||
80 | if (fi->debug) | ||
81 | fi->printdebug(fi, "State %s Event %s no action", | ||
82 | fi->fsm->strState[fi->state], | ||
83 | fi->fsm->strEvent[event]); | ||
84 | return 1; | ||
85 | } | ||
86 | } | ||
87 | EXPORT_SYMBOL(mISDN_FsmEvent); | ||
88 | |||
89 | void | ||
90 | mISDN_FsmChangeState(struct FsmInst *fi, int newstate) | ||
91 | { | ||
92 | fi->state = newstate; | ||
93 | if (fi->debug) | ||
94 | fi->printdebug(fi, "ChangeState %s", | ||
95 | fi->fsm->strState[newstate]); | ||
96 | } | ||
97 | EXPORT_SYMBOL(mISDN_FsmChangeState); | ||
98 | |||
99 | static void | ||
100 | FsmExpireTimer(struct FsmTimer *ft) | ||
101 | { | ||
102 | #if FSM_TIMER_DEBUG | ||
103 | if (ft->fi->debug) | ||
104 | ft->fi->printdebug(ft->fi, "FsmExpireTimer %lx", (long) ft); | ||
105 | #endif | ||
106 | mISDN_FsmEvent(ft->fi, ft->event, ft->arg); | ||
107 | } | ||
108 | |||
109 | void | ||
110 | mISDN_FsmInitTimer(struct FsmInst *fi, struct FsmTimer *ft) | ||
111 | { | ||
112 | ft->fi = fi; | ||
113 | ft->tl.function = (void *) FsmExpireTimer; | ||
114 | ft->tl.data = (long) ft; | ||
115 | #if FSM_TIMER_DEBUG | ||
116 | if (ft->fi->debug) | ||
117 | ft->fi->printdebug(ft->fi, "mISDN_FsmInitTimer %lx", (long) ft); | ||
118 | #endif | ||
119 | init_timer(&ft->tl); | ||
120 | } | ||
121 | EXPORT_SYMBOL(mISDN_FsmInitTimer); | ||
122 | |||
123 | void | ||
124 | mISDN_FsmDelTimer(struct FsmTimer *ft, int where) | ||
125 | { | ||
126 | #if FSM_TIMER_DEBUG | ||
127 | if (ft->fi->debug) | ||
128 | ft->fi->printdebug(ft->fi, "mISDN_FsmDelTimer %lx %d", | ||
129 | (long) ft, where); | ||
130 | #endif | ||
131 | del_timer(&ft->tl); | ||
132 | } | ||
133 | EXPORT_SYMBOL(mISDN_FsmDelTimer); | ||
134 | |||
135 | int | ||
136 | mISDN_FsmAddTimer(struct FsmTimer *ft, | ||
137 | int millisec, int event, void *arg, int where) | ||
138 | { | ||
139 | |||
140 | #if FSM_TIMER_DEBUG | ||
141 | if (ft->fi->debug) | ||
142 | ft->fi->printdebug(ft->fi, "mISDN_FsmAddTimer %lx %d %d", | ||
143 | (long) ft, millisec, where); | ||
144 | #endif | ||
145 | |||
146 | if (timer_pending(&ft->tl)) { | ||
147 | if (ft->fi->debug) { | ||
148 | printk(KERN_WARNING | ||
149 | "mISDN_FsmAddTimer: timer already active!\n"); | ||
150 | ft->fi->printdebug(ft->fi, | ||
151 | "mISDN_FsmAddTimer already active!"); | ||
152 | } | ||
153 | return -1; | ||
154 | } | ||
155 | init_timer(&ft->tl); | ||
156 | ft->event = event; | ||
157 | ft->arg = arg; | ||
158 | ft->tl.expires = jiffies + (millisec * HZ) / 1000; | ||
159 | add_timer(&ft->tl); | ||
160 | return 0; | ||
161 | } | ||
162 | EXPORT_SYMBOL(mISDN_FsmAddTimer); | ||
163 | |||
164 | void | ||
165 | mISDN_FsmRestartTimer(struct FsmTimer *ft, | ||
166 | int millisec, int event, void *arg, int where) | ||
167 | { | ||
168 | |||
169 | #if FSM_TIMER_DEBUG | ||
170 | if (ft->fi->debug) | ||
171 | ft->fi->printdebug(ft->fi, "mISDN_FsmRestartTimer %lx %d %d", | ||
172 | (long) ft, millisec, where); | ||
173 | #endif | ||
174 | |||
175 | if (timer_pending(&ft->tl)) | ||
176 | del_timer(&ft->tl); | ||
177 | init_timer(&ft->tl); | ||
178 | ft->event = event; | ||
179 | ft->arg = arg; | ||
180 | ft->tl.expires = jiffies + (millisec * HZ) / 1000; | ||
181 | add_timer(&ft->tl); | ||
182 | } | ||
183 | EXPORT_SYMBOL(mISDN_FsmRestartTimer); | ||
diff --git a/drivers/isdn/mISDN/fsm.h b/drivers/isdn/mISDN/fsm.h new file mode 100644 index 000000000000..928f5be192c1 --- /dev/null +++ b/drivers/isdn/mISDN/fsm.h | |||
@@ -0,0 +1,67 @@ | |||
1 | /* | ||
2 | * | ||
3 | * Author Karsten Keil <kkeil@novell.com> | ||
4 | * | ||
5 | * Thanks to Jan den Ouden | ||
6 | * Fritz Elfert | ||
7 | * Copyright 2008 by Karsten Keil <kkeil@novell.com> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License version 2 as | ||
11 | * published by the Free Software Foundation. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | */ | ||
19 | |||
20 | #ifndef _MISDN_FSM_H | ||
21 | #define _MISDN_FSM_H | ||
22 | |||
23 | #include <linux/timer.h> | ||
24 | |||
25 | /* Statemachine */ | ||
26 | |||
27 | struct FsmInst; | ||
28 | |||
29 | typedef void (*FSMFNPTR)(struct FsmInst *, int, void *); | ||
30 | |||
31 | struct Fsm { | ||
32 | FSMFNPTR *jumpmatrix; | ||
33 | int state_count, event_count; | ||
34 | char **strEvent, **strState; | ||
35 | }; | ||
36 | |||
37 | struct FsmInst { | ||
38 | struct Fsm *fsm; | ||
39 | int state; | ||
40 | int debug; | ||
41 | void *userdata; | ||
42 | int userint; | ||
43 | void (*printdebug) (struct FsmInst *, char *, ...); | ||
44 | }; | ||
45 | |||
46 | struct FsmNode { | ||
47 | int state, event; | ||
48 | void (*routine) (struct FsmInst *, int, void *); | ||
49 | }; | ||
50 | |||
51 | struct FsmTimer { | ||
52 | struct FsmInst *fi; | ||
53 | struct timer_list tl; | ||
54 | int event; | ||
55 | void *arg; | ||
56 | }; | ||
57 | |||
58 | extern void mISDN_FsmNew(struct Fsm *, struct FsmNode *, int); | ||
59 | extern void mISDN_FsmFree(struct Fsm *); | ||
60 | extern int mISDN_FsmEvent(struct FsmInst *, int , void *); | ||
61 | extern void mISDN_FsmChangeState(struct FsmInst *, int); | ||
62 | extern void mISDN_FsmInitTimer(struct FsmInst *, struct FsmTimer *); | ||
63 | extern int mISDN_FsmAddTimer(struct FsmTimer *, int, int, void *, int); | ||
64 | extern void mISDN_FsmRestartTimer(struct FsmTimer *, int, int, void *, int); | ||
65 | extern void mISDN_FsmDelTimer(struct FsmTimer *, int); | ||
66 | |||
67 | #endif | ||
diff --git a/drivers/isdn/mISDN/hwchannel.c b/drivers/isdn/mISDN/hwchannel.c new file mode 100644 index 000000000000..2596fba4e614 --- /dev/null +++ b/drivers/isdn/mISDN/hwchannel.c | |||
@@ -0,0 +1,365 @@ | |||
1 | /* | ||
2 | * | ||
3 | * Author Karsten Keil <kkeil@novell.com> | ||
4 | * | ||
5 | * Copyright 2008 by Karsten Keil <kkeil@novell.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | */ | ||
17 | |||
18 | #include <linux/module.h> | ||
19 | #include <linux/mISDNhw.h> | ||
20 | |||
21 | static void | ||
22 | dchannel_bh(struct work_struct *ws) | ||
23 | { | ||
24 | struct dchannel *dch = container_of(ws, struct dchannel, workq); | ||
25 | struct sk_buff *skb; | ||
26 | int err; | ||
27 | |||
28 | if (test_and_clear_bit(FLG_RECVQUEUE, &dch->Flags)) { | ||
29 | while ((skb = skb_dequeue(&dch->rqueue))) { | ||
30 | if (likely(dch->dev.D.peer)) { | ||
31 | err = dch->dev.D.recv(dch->dev.D.peer, skb); | ||
32 | if (err) | ||
33 | dev_kfree_skb(skb); | ||
34 | } else | ||
35 | dev_kfree_skb(skb); | ||
36 | } | ||
37 | } | ||
38 | if (test_and_clear_bit(FLG_PHCHANGE, &dch->Flags)) { | ||
39 | if (dch->phfunc) | ||
40 | dch->phfunc(dch); | ||
41 | } | ||
42 | } | ||
43 | |||
44 | static void | ||
45 | bchannel_bh(struct work_struct *ws) | ||
46 | { | ||
47 | struct bchannel *bch = container_of(ws, struct bchannel, workq); | ||
48 | struct sk_buff *skb; | ||
49 | int err; | ||
50 | |||
51 | if (test_and_clear_bit(FLG_RECVQUEUE, &bch->Flags)) { | ||
52 | while ((skb = skb_dequeue(&bch->rqueue))) { | ||
53 | if (bch->rcount >= 64) | ||
54 | printk(KERN_WARNING "B-channel %p receive " | ||
55 | "queue if full, but empties...\n", bch); | ||
56 | bch->rcount--; | ||
57 | if (likely(bch->ch.peer)) { | ||
58 | err = bch->ch.recv(bch->ch.peer, skb); | ||
59 | if (err) | ||
60 | dev_kfree_skb(skb); | ||
61 | } else | ||
62 | dev_kfree_skb(skb); | ||
63 | } | ||
64 | } | ||
65 | } | ||
66 | |||
67 | int | ||
68 | mISDN_initdchannel(struct dchannel *ch, int maxlen, void *phf) | ||
69 | { | ||
70 | test_and_set_bit(FLG_HDLC, &ch->Flags); | ||
71 | ch->maxlen = maxlen; | ||
72 | ch->hw = NULL; | ||
73 | ch->rx_skb = NULL; | ||
74 | ch->tx_skb = NULL; | ||
75 | ch->tx_idx = 0; | ||
76 | ch->phfunc = phf; | ||
77 | skb_queue_head_init(&ch->squeue); | ||
78 | skb_queue_head_init(&ch->rqueue); | ||
79 | INIT_LIST_HEAD(&ch->dev.bchannels); | ||
80 | INIT_WORK(&ch->workq, dchannel_bh); | ||
81 | return 0; | ||
82 | } | ||
83 | EXPORT_SYMBOL(mISDN_initdchannel); | ||
84 | |||
85 | int | ||
86 | mISDN_initbchannel(struct bchannel *ch, int maxlen) | ||
87 | { | ||
88 | ch->Flags = 0; | ||
89 | ch->maxlen = maxlen; | ||
90 | ch->hw = NULL; | ||
91 | ch->rx_skb = NULL; | ||
92 | ch->tx_skb = NULL; | ||
93 | ch->tx_idx = 0; | ||
94 | skb_queue_head_init(&ch->rqueue); | ||
95 | ch->rcount = 0; | ||
96 | ch->next_skb = NULL; | ||
97 | INIT_WORK(&ch->workq, bchannel_bh); | ||
98 | return 0; | ||
99 | } | ||
100 | EXPORT_SYMBOL(mISDN_initbchannel); | ||
101 | |||
102 | int | ||
103 | mISDN_freedchannel(struct dchannel *ch) | ||
104 | { | ||
105 | if (ch->tx_skb) { | ||
106 | dev_kfree_skb(ch->tx_skb); | ||
107 | ch->tx_skb = NULL; | ||
108 | } | ||
109 | if (ch->rx_skb) { | ||
110 | dev_kfree_skb(ch->rx_skb); | ||
111 | ch->rx_skb = NULL; | ||
112 | } | ||
113 | skb_queue_purge(&ch->squeue); | ||
114 | skb_queue_purge(&ch->rqueue); | ||
115 | flush_scheduled_work(); | ||
116 | return 0; | ||
117 | } | ||
118 | EXPORT_SYMBOL(mISDN_freedchannel); | ||
119 | |||
120 | int | ||
121 | mISDN_freebchannel(struct bchannel *ch) | ||
122 | { | ||
123 | if (ch->tx_skb) { | ||
124 | dev_kfree_skb(ch->tx_skb); | ||
125 | ch->tx_skb = NULL; | ||
126 | } | ||
127 | if (ch->rx_skb) { | ||
128 | dev_kfree_skb(ch->rx_skb); | ||
129 | ch->rx_skb = NULL; | ||
130 | } | ||
131 | if (ch->next_skb) { | ||
132 | dev_kfree_skb(ch->next_skb); | ||
133 | ch->next_skb = NULL; | ||
134 | } | ||
135 | skb_queue_purge(&ch->rqueue); | ||
136 | ch->rcount = 0; | ||
137 | flush_scheduled_work(); | ||
138 | return 0; | ||
139 | } | ||
140 | EXPORT_SYMBOL(mISDN_freebchannel); | ||
141 | |||
142 | static inline u_int | ||
143 | get_sapi_tei(u_char *p) | ||
144 | { | ||
145 | u_int sapi, tei; | ||
146 | |||
147 | sapi = *p >> 2; | ||
148 | tei = p[1] >> 1; | ||
149 | return sapi | (tei << 8); | ||
150 | } | ||
151 | |||
152 | void | ||
153 | recv_Dchannel(struct dchannel *dch) | ||
154 | { | ||
155 | struct mISDNhead *hh; | ||
156 | |||
157 | if (dch->rx_skb->len < 2) { /* at least 2 for sapi / tei */ | ||
158 | dev_kfree_skb(dch->rx_skb); | ||
159 | dch->rx_skb = NULL; | ||
160 | return; | ||
161 | } | ||
162 | hh = mISDN_HEAD_P(dch->rx_skb); | ||
163 | hh->prim = PH_DATA_IND; | ||
164 | hh->id = get_sapi_tei(dch->rx_skb->data); | ||
165 | skb_queue_tail(&dch->rqueue, dch->rx_skb); | ||
166 | dch->rx_skb = NULL; | ||
167 | schedule_event(dch, FLG_RECVQUEUE); | ||
168 | } | ||
169 | EXPORT_SYMBOL(recv_Dchannel); | ||
170 | |||
171 | void | ||
172 | recv_Bchannel(struct bchannel *bch) | ||
173 | { | ||
174 | struct mISDNhead *hh; | ||
175 | |||
176 | hh = mISDN_HEAD_P(bch->rx_skb); | ||
177 | hh->prim = PH_DATA_IND; | ||
178 | hh->id = MISDN_ID_ANY; | ||
179 | if (bch->rcount >= 64) { | ||
180 | dev_kfree_skb(bch->rx_skb); | ||
181 | bch->rx_skb = NULL; | ||
182 | return; | ||
183 | } | ||
184 | bch->rcount++; | ||
185 | skb_queue_tail(&bch->rqueue, bch->rx_skb); | ||
186 | bch->rx_skb = NULL; | ||
187 | schedule_event(bch, FLG_RECVQUEUE); | ||
188 | } | ||
189 | EXPORT_SYMBOL(recv_Bchannel); | ||
190 | |||
191 | void | ||
192 | recv_Dchannel_skb(struct dchannel *dch, struct sk_buff *skb) | ||
193 | { | ||
194 | skb_queue_tail(&dch->rqueue, skb); | ||
195 | schedule_event(dch, FLG_RECVQUEUE); | ||
196 | } | ||
197 | EXPORT_SYMBOL(recv_Dchannel_skb); | ||
198 | |||
199 | void | ||
200 | recv_Bchannel_skb(struct bchannel *bch, struct sk_buff *skb) | ||
201 | { | ||
202 | if (bch->rcount >= 64) { | ||
203 | dev_kfree_skb(skb); | ||
204 | return; | ||
205 | } | ||
206 | bch->rcount++; | ||
207 | skb_queue_tail(&bch->rqueue, skb); | ||
208 | schedule_event(bch, FLG_RECVQUEUE); | ||
209 | } | ||
210 | EXPORT_SYMBOL(recv_Bchannel_skb); | ||
211 | |||
212 | static void | ||
213 | confirm_Dsend(struct dchannel *dch) | ||
214 | { | ||
215 | struct sk_buff *skb; | ||
216 | |||
217 | skb = _alloc_mISDN_skb(PH_DATA_CNF, mISDN_HEAD_ID(dch->tx_skb), | ||
218 | 0, NULL, GFP_ATOMIC); | ||
219 | if (!skb) { | ||
220 | printk(KERN_ERR "%s: no skb id %x\n", __func__, | ||
221 | mISDN_HEAD_ID(dch->tx_skb)); | ||
222 | return; | ||
223 | } | ||
224 | skb_queue_tail(&dch->rqueue, skb); | ||
225 | schedule_event(dch, FLG_RECVQUEUE); | ||
226 | } | ||
227 | |||
228 | int | ||
229 | get_next_dframe(struct dchannel *dch) | ||
230 | { | ||
231 | dch->tx_idx = 0; | ||
232 | dch->tx_skb = skb_dequeue(&dch->squeue); | ||
233 | if (dch->tx_skb) { | ||
234 | confirm_Dsend(dch); | ||
235 | return 1; | ||
236 | } | ||
237 | dch->tx_skb = NULL; | ||
238 | test_and_clear_bit(FLG_TX_BUSY, &dch->Flags); | ||
239 | return 0; | ||
240 | } | ||
241 | EXPORT_SYMBOL(get_next_dframe); | ||
242 | |||
243 | void | ||
244 | confirm_Bsend(struct bchannel *bch) | ||
245 | { | ||
246 | struct sk_buff *skb; | ||
247 | |||
248 | if (bch->rcount >= 64) | ||
249 | return; | ||
250 | skb = _alloc_mISDN_skb(PH_DATA_CNF, mISDN_HEAD_ID(bch->tx_skb), | ||
251 | 0, NULL, GFP_ATOMIC); | ||
252 | if (!skb) { | ||
253 | printk(KERN_ERR "%s: no skb id %x\n", __func__, | ||
254 | mISDN_HEAD_ID(bch->tx_skb)); | ||
255 | return; | ||
256 | } | ||
257 | bch->rcount++; | ||
258 | skb_queue_tail(&bch->rqueue, skb); | ||
259 | schedule_event(bch, FLG_RECVQUEUE); | ||
260 | } | ||
261 | EXPORT_SYMBOL(confirm_Bsend); | ||
262 | |||
263 | int | ||
264 | get_next_bframe(struct bchannel *bch) | ||
265 | { | ||
266 | bch->tx_idx = 0; | ||
267 | if (test_bit(FLG_TX_NEXT, &bch->Flags)) { | ||
268 | bch->tx_skb = bch->next_skb; | ||
269 | if (bch->tx_skb) { | ||
270 | bch->next_skb = NULL; | ||
271 | test_and_clear_bit(FLG_TX_NEXT, &bch->Flags); | ||
272 | if (!test_bit(FLG_TRANSPARENT, &bch->Flags)) | ||
273 | confirm_Bsend(bch); /* not for transparent */ | ||
274 | return 1; | ||
275 | } else { | ||
276 | test_and_clear_bit(FLG_TX_NEXT, &bch->Flags); | ||
277 | printk(KERN_WARNING "B TX_NEXT without skb\n"); | ||
278 | } | ||
279 | } | ||
280 | bch->tx_skb = NULL; | ||
281 | test_and_clear_bit(FLG_TX_BUSY, &bch->Flags); | ||
282 | return 0; | ||
283 | } | ||
284 | EXPORT_SYMBOL(get_next_bframe); | ||
285 | |||
286 | void | ||
287 | queue_ch_frame(struct mISDNchannel *ch, u_int pr, int id, struct sk_buff *skb) | ||
288 | { | ||
289 | struct mISDNhead *hh; | ||
290 | |||
291 | if (!skb) { | ||
292 | _queue_data(ch, pr, id, 0, NULL, GFP_ATOMIC); | ||
293 | } else { | ||
294 | if (ch->peer) { | ||
295 | hh = mISDN_HEAD_P(skb); | ||
296 | hh->prim = pr; | ||
297 | hh->id = id; | ||
298 | if (!ch->recv(ch->peer, skb)) | ||
299 | return; | ||
300 | } | ||
301 | dev_kfree_skb(skb); | ||
302 | } | ||
303 | } | ||
304 | EXPORT_SYMBOL(queue_ch_frame); | ||
305 | |||
306 | int | ||
307 | dchannel_senddata(struct dchannel *ch, struct sk_buff *skb) | ||
308 | { | ||
309 | /* check oversize */ | ||
310 | if (skb->len <= 0) { | ||
311 | printk(KERN_WARNING "%s: skb too small\n", __func__); | ||
312 | return -EINVAL; | ||
313 | } | ||
314 | if (skb->len > ch->maxlen) { | ||
315 | printk(KERN_WARNING "%s: skb too large(%d/%d)\n", | ||
316 | __func__, skb->len, ch->maxlen); | ||
317 | return -EINVAL; | ||
318 | } | ||
319 | /* HW lock must be obtained */ | ||
320 | if (test_and_set_bit(FLG_TX_BUSY, &ch->Flags)) { | ||
321 | skb_queue_tail(&ch->squeue, skb); | ||
322 | return 0; | ||
323 | } else { | ||
324 | /* write to fifo */ | ||
325 | ch->tx_skb = skb; | ||
326 | ch->tx_idx = 0; | ||
327 | return 1; | ||
328 | } | ||
329 | } | ||
330 | EXPORT_SYMBOL(dchannel_senddata); | ||
331 | |||
332 | int | ||
333 | bchannel_senddata(struct bchannel *ch, struct sk_buff *skb) | ||
334 | { | ||
335 | |||
336 | /* check oversize */ | ||
337 | if (skb->len <= 0) { | ||
338 | printk(KERN_WARNING "%s: skb too small\n", __func__); | ||
339 | return -EINVAL; | ||
340 | } | ||
341 | if (skb->len > ch->maxlen) { | ||
342 | printk(KERN_WARNING "%s: skb too large(%d/%d)\n", | ||
343 | __func__, skb->len, ch->maxlen); | ||
344 | return -EINVAL; | ||
345 | } | ||
346 | /* HW lock must be obtained */ | ||
347 | /* check for pending next_skb */ | ||
348 | if (ch->next_skb) { | ||
349 | printk(KERN_WARNING | ||
350 | "%s: next_skb exist ERROR (skb->len=%d next_skb->len=%d)\n", | ||
351 | __func__, skb->len, ch->next_skb->len); | ||
352 | return -EBUSY; | ||
353 | } | ||
354 | if (test_and_set_bit(FLG_TX_BUSY, &ch->Flags)) { | ||
355 | test_and_set_bit(FLG_TX_NEXT, &ch->Flags); | ||
356 | ch->next_skb = skb; | ||
357 | return 0; | ||
358 | } else { | ||
359 | /* write to fifo */ | ||
360 | ch->tx_skb = skb; | ||
361 | ch->tx_idx = 0; | ||
362 | return 1; | ||
363 | } | ||
364 | } | ||
365 | EXPORT_SYMBOL(bchannel_senddata); | ||
diff --git a/drivers/isdn/mISDN/layer1.c b/drivers/isdn/mISDN/layer1.c new file mode 100644 index 000000000000..fced1a2755f8 --- /dev/null +++ b/drivers/isdn/mISDN/layer1.c | |||
@@ -0,0 +1,403 @@ | |||
1 | /* | ||
2 | * | ||
3 | * Author Karsten Keil <kkeil@novell.com> | ||
4 | * | ||
5 | * Copyright 2008 by Karsten Keil <kkeil@novell.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | */ | ||
17 | |||
18 | |||
19 | #include <linux/module.h> | ||
20 | #include <linux/mISDNhw.h> | ||
21 | #include "layer1.h" | ||
22 | #include "fsm.h" | ||
23 | |||
24 | static int *debug; | ||
25 | |||
26 | struct layer1 { | ||
27 | u_long Flags; | ||
28 | struct FsmInst l1m; | ||
29 | struct FsmTimer timer; | ||
30 | int delay; | ||
31 | struct dchannel *dch; | ||
32 | dchannel_l1callback *dcb; | ||
33 | }; | ||
34 | |||
35 | #define TIMER3_VALUE 7000 | ||
36 | |||
37 | static | ||
38 | struct Fsm l1fsm_s = {NULL, 0, 0, NULL, NULL}; | ||
39 | |||
40 | enum { | ||
41 | ST_L1_F2, | ||
42 | ST_L1_F3, | ||
43 | ST_L1_F4, | ||
44 | ST_L1_F5, | ||
45 | ST_L1_F6, | ||
46 | ST_L1_F7, | ||
47 | ST_L1_F8, | ||
48 | }; | ||
49 | |||
50 | #define L1S_STATE_COUNT (ST_L1_F8+1) | ||
51 | |||
52 | static char *strL1SState[] = | ||
53 | { | ||
54 | "ST_L1_F2", | ||
55 | "ST_L1_F3", | ||
56 | "ST_L1_F4", | ||
57 | "ST_L1_F5", | ||
58 | "ST_L1_F6", | ||
59 | "ST_L1_F7", | ||
60 | "ST_L1_F8", | ||
61 | }; | ||
62 | |||
63 | enum { | ||
64 | EV_PH_ACTIVATE, | ||
65 | EV_PH_DEACTIVATE, | ||
66 | EV_RESET_IND, | ||
67 | EV_DEACT_CNF, | ||
68 | EV_DEACT_IND, | ||
69 | EV_POWER_UP, | ||
70 | EV_ANYSIG_IND, | ||
71 | EV_INFO2_IND, | ||
72 | EV_INFO4_IND, | ||
73 | EV_TIMER_DEACT, | ||
74 | EV_TIMER_ACT, | ||
75 | EV_TIMER3, | ||
76 | }; | ||
77 | |||
78 | #define L1_EVENT_COUNT (EV_TIMER3 + 1) | ||
79 | |||
80 | static char *strL1Event[] = | ||
81 | { | ||
82 | "EV_PH_ACTIVATE", | ||
83 | "EV_PH_DEACTIVATE", | ||
84 | "EV_RESET_IND", | ||
85 | "EV_DEACT_CNF", | ||
86 | "EV_DEACT_IND", | ||
87 | "EV_POWER_UP", | ||
88 | "EV_ANYSIG_IND", | ||
89 | "EV_INFO2_IND", | ||
90 | "EV_INFO4_IND", | ||
91 | "EV_TIMER_DEACT", | ||
92 | "EV_TIMER_ACT", | ||
93 | "EV_TIMER3", | ||
94 | }; | ||
95 | |||
96 | static void | ||
97 | l1m_debug(struct FsmInst *fi, char *fmt, ...) | ||
98 | { | ||
99 | struct layer1 *l1 = fi->userdata; | ||
100 | va_list va; | ||
101 | |||
102 | va_start(va, fmt); | ||
103 | printk(KERN_DEBUG "%s: ", l1->dch->dev.name); | ||
104 | vprintk(fmt, va); | ||
105 | printk("\n"); | ||
106 | va_end(va); | ||
107 | } | ||
108 | |||
109 | static void | ||
110 | l1_reset(struct FsmInst *fi, int event, void *arg) | ||
111 | { | ||
112 | mISDN_FsmChangeState(fi, ST_L1_F3); | ||
113 | } | ||
114 | |||
115 | static void | ||
116 | l1_deact_cnf(struct FsmInst *fi, int event, void *arg) | ||
117 | { | ||
118 | struct layer1 *l1 = fi->userdata; | ||
119 | |||
120 | mISDN_FsmChangeState(fi, ST_L1_F3); | ||
121 | if (test_bit(FLG_L1_ACTIVATING, &l1->Flags)) | ||
122 | l1->dcb(l1->dch, HW_POWERUP_REQ); | ||
123 | } | ||
124 | |||
125 | static void | ||
126 | l1_deact_req_s(struct FsmInst *fi, int event, void *arg) | ||
127 | { | ||
128 | struct layer1 *l1 = fi->userdata; | ||
129 | |||
130 | mISDN_FsmChangeState(fi, ST_L1_F3); | ||
131 | mISDN_FsmRestartTimer(&l1->timer, 550, EV_TIMER_DEACT, NULL, 2); | ||
132 | test_and_set_bit(FLG_L1_DEACTTIMER, &l1->Flags); | ||
133 | } | ||
134 | |||
135 | static void | ||
136 | l1_power_up_s(struct FsmInst *fi, int event, void *arg) | ||
137 | { | ||
138 | struct layer1 *l1 = fi->userdata; | ||
139 | |||
140 | if (test_bit(FLG_L1_ACTIVATING, &l1->Flags)) { | ||
141 | mISDN_FsmChangeState(fi, ST_L1_F4); | ||
142 | l1->dcb(l1->dch, INFO3_P8); | ||
143 | } else | ||
144 | mISDN_FsmChangeState(fi, ST_L1_F3); | ||
145 | } | ||
146 | |||
147 | static void | ||
148 | l1_go_F5(struct FsmInst *fi, int event, void *arg) | ||
149 | { | ||
150 | mISDN_FsmChangeState(fi, ST_L1_F5); | ||
151 | } | ||
152 | |||
153 | static void | ||
154 | l1_go_F8(struct FsmInst *fi, int event, void *arg) | ||
155 | { | ||
156 | mISDN_FsmChangeState(fi, ST_L1_F8); | ||
157 | } | ||
158 | |||
159 | static void | ||
160 | l1_info2_ind(struct FsmInst *fi, int event, void *arg) | ||
161 | { | ||
162 | struct layer1 *l1 = fi->userdata; | ||
163 | |||
164 | mISDN_FsmChangeState(fi, ST_L1_F6); | ||
165 | l1->dcb(l1->dch, INFO3_P8); | ||
166 | } | ||
167 | |||
168 | static void | ||
169 | l1_info4_ind(struct FsmInst *fi, int event, void *arg) | ||
170 | { | ||
171 | struct layer1 *l1 = fi->userdata; | ||
172 | |||
173 | mISDN_FsmChangeState(fi, ST_L1_F7); | ||
174 | l1->dcb(l1->dch, INFO3_P8); | ||
175 | if (test_and_clear_bit(FLG_L1_DEACTTIMER, &l1->Flags)) | ||
176 | mISDN_FsmDelTimer(&l1->timer, 4); | ||
177 | if (!test_bit(FLG_L1_ACTIVATED, &l1->Flags)) { | ||
178 | if (test_and_clear_bit(FLG_L1_T3RUN, &l1->Flags)) | ||
179 | mISDN_FsmDelTimer(&l1->timer, 3); | ||
180 | mISDN_FsmRestartTimer(&l1->timer, 110, EV_TIMER_ACT, NULL, 2); | ||
181 | test_and_set_bit(FLG_L1_ACTTIMER, &l1->Flags); | ||
182 | } | ||
183 | } | ||
184 | |||
185 | static void | ||
186 | l1_timer3(struct FsmInst *fi, int event, void *arg) | ||
187 | { | ||
188 | struct layer1 *l1 = fi->userdata; | ||
189 | |||
190 | test_and_clear_bit(FLG_L1_T3RUN, &l1->Flags); | ||
191 | if (test_and_clear_bit(FLG_L1_ACTIVATING, &l1->Flags)) { | ||
192 | if (test_and_clear_bit(FLG_L1_DBLOCKED, &l1->Flags)) | ||
193 | l1->dcb(l1->dch, HW_D_NOBLOCKED); | ||
194 | l1->dcb(l1->dch, PH_DEACTIVATE_IND); | ||
195 | } | ||
196 | if (l1->l1m.state != ST_L1_F6) { | ||
197 | mISDN_FsmChangeState(fi, ST_L1_F3); | ||
198 | l1->dcb(l1->dch, HW_POWERUP_REQ); | ||
199 | } | ||
200 | } | ||
201 | |||
202 | static void | ||
203 | l1_timer_act(struct FsmInst *fi, int event, void *arg) | ||
204 | { | ||
205 | struct layer1 *l1 = fi->userdata; | ||
206 | |||
207 | test_and_clear_bit(FLG_L1_ACTTIMER, &l1->Flags); | ||
208 | test_and_set_bit(FLG_L1_ACTIVATED, &l1->Flags); | ||
209 | l1->dcb(l1->dch, PH_ACTIVATE_IND); | ||
210 | } | ||
211 | |||
212 | static void | ||
213 | l1_timer_deact(struct FsmInst *fi, int event, void *arg) | ||
214 | { | ||
215 | struct layer1 *l1 = fi->userdata; | ||
216 | |||
217 | test_and_clear_bit(FLG_L1_DEACTTIMER, &l1->Flags); | ||
218 | test_and_clear_bit(FLG_L1_ACTIVATED, &l1->Flags); | ||
219 | if (test_and_clear_bit(FLG_L1_DBLOCKED, &l1->Flags)) | ||
220 | l1->dcb(l1->dch, HW_D_NOBLOCKED); | ||
221 | l1->dcb(l1->dch, PH_DEACTIVATE_IND); | ||
222 | l1->dcb(l1->dch, HW_DEACT_REQ); | ||
223 | } | ||
224 | |||
225 | static void | ||
226 | l1_activate_s(struct FsmInst *fi, int event, void *arg) | ||
227 | { | ||
228 | struct layer1 *l1 = fi->userdata; | ||
229 | |||
230 | mISDN_FsmRestartTimer(&l1->timer, TIMER3_VALUE, EV_TIMER3, NULL, 2); | ||
231 | test_and_set_bit(FLG_L1_T3RUN, &l1->Flags); | ||
232 | l1->dcb(l1->dch, HW_RESET_REQ); | ||
233 | } | ||
234 | |||
235 | static void | ||
236 | l1_activate_no(struct FsmInst *fi, int event, void *arg) | ||
237 | { | ||
238 | struct layer1 *l1 = fi->userdata; | ||
239 | |||
240 | if ((!test_bit(FLG_L1_DEACTTIMER, &l1->Flags)) && | ||
241 | (!test_bit(FLG_L1_T3RUN, &l1->Flags))) { | ||
242 | test_and_clear_bit(FLG_L1_ACTIVATING, &l1->Flags); | ||
243 | if (test_and_clear_bit(FLG_L1_DBLOCKED, &l1->Flags)) | ||
244 | l1->dcb(l1->dch, HW_D_NOBLOCKED); | ||
245 | l1->dcb(l1->dch, PH_DEACTIVATE_IND); | ||
246 | } | ||
247 | } | ||
248 | |||
249 | static struct FsmNode L1SFnList[] = | ||
250 | { | ||
251 | {ST_L1_F3, EV_PH_ACTIVATE, l1_activate_s}, | ||
252 | {ST_L1_F6, EV_PH_ACTIVATE, l1_activate_no}, | ||
253 | {ST_L1_F8, EV_PH_ACTIVATE, l1_activate_no}, | ||
254 | {ST_L1_F3, EV_RESET_IND, l1_reset}, | ||
255 | {ST_L1_F4, EV_RESET_IND, l1_reset}, | ||
256 | {ST_L1_F5, EV_RESET_IND, l1_reset}, | ||
257 | {ST_L1_F6, EV_RESET_IND, l1_reset}, | ||
258 | {ST_L1_F7, EV_RESET_IND, l1_reset}, | ||
259 | {ST_L1_F8, EV_RESET_IND, l1_reset}, | ||
260 | {ST_L1_F3, EV_DEACT_CNF, l1_deact_cnf}, | ||
261 | {ST_L1_F4, EV_DEACT_CNF, l1_deact_cnf}, | ||
262 | {ST_L1_F5, EV_DEACT_CNF, l1_deact_cnf}, | ||
263 | {ST_L1_F6, EV_DEACT_CNF, l1_deact_cnf}, | ||
264 | {ST_L1_F7, EV_DEACT_CNF, l1_deact_cnf}, | ||
265 | {ST_L1_F8, EV_DEACT_CNF, l1_deact_cnf}, | ||
266 | {ST_L1_F6, EV_DEACT_IND, l1_deact_req_s}, | ||
267 | {ST_L1_F7, EV_DEACT_IND, l1_deact_req_s}, | ||
268 | {ST_L1_F8, EV_DEACT_IND, l1_deact_req_s}, | ||
269 | {ST_L1_F3, EV_POWER_UP, l1_power_up_s}, | ||
270 | {ST_L1_F4, EV_ANYSIG_IND, l1_go_F5}, | ||
271 | {ST_L1_F6, EV_ANYSIG_IND, l1_go_F8}, | ||
272 | {ST_L1_F7, EV_ANYSIG_IND, l1_go_F8}, | ||
273 | {ST_L1_F3, EV_INFO2_IND, l1_info2_ind}, | ||
274 | {ST_L1_F4, EV_INFO2_IND, l1_info2_ind}, | ||
275 | {ST_L1_F5, EV_INFO2_IND, l1_info2_ind}, | ||
276 | {ST_L1_F7, EV_INFO2_IND, l1_info2_ind}, | ||
277 | {ST_L1_F8, EV_INFO2_IND, l1_info2_ind}, | ||
278 | {ST_L1_F3, EV_INFO4_IND, l1_info4_ind}, | ||
279 | {ST_L1_F4, EV_INFO4_IND, l1_info4_ind}, | ||
280 | {ST_L1_F5, EV_INFO4_IND, l1_info4_ind}, | ||
281 | {ST_L1_F6, EV_INFO4_IND, l1_info4_ind}, | ||
282 | {ST_L1_F8, EV_INFO4_IND, l1_info4_ind}, | ||
283 | {ST_L1_F3, EV_TIMER3, l1_timer3}, | ||
284 | {ST_L1_F4, EV_TIMER3, l1_timer3}, | ||
285 | {ST_L1_F5, EV_TIMER3, l1_timer3}, | ||
286 | {ST_L1_F6, EV_TIMER3, l1_timer3}, | ||
287 | {ST_L1_F8, EV_TIMER3, l1_timer3}, | ||
288 | {ST_L1_F7, EV_TIMER_ACT, l1_timer_act}, | ||
289 | {ST_L1_F3, EV_TIMER_DEACT, l1_timer_deact}, | ||
290 | {ST_L1_F4, EV_TIMER_DEACT, l1_timer_deact}, | ||
291 | {ST_L1_F5, EV_TIMER_DEACT, l1_timer_deact}, | ||
292 | {ST_L1_F6, EV_TIMER_DEACT, l1_timer_deact}, | ||
293 | {ST_L1_F7, EV_TIMER_DEACT, l1_timer_deact}, | ||
294 | {ST_L1_F8, EV_TIMER_DEACT, l1_timer_deact}, | ||
295 | }; | ||
296 | |||
297 | static void | ||
298 | release_l1(struct layer1 *l1) { | ||
299 | mISDN_FsmDelTimer(&l1->timer, 0); | ||
300 | if (l1->dch) | ||
301 | l1->dch->l1 = NULL; | ||
302 | module_put(THIS_MODULE); | ||
303 | kfree(l1); | ||
304 | } | ||
305 | |||
306 | int | ||
307 | l1_event(struct layer1 *l1, u_int event) | ||
308 | { | ||
309 | int err = 0; | ||
310 | |||
311 | if (!l1) | ||
312 | return -EINVAL; | ||
313 | switch (event) { | ||
314 | case HW_RESET_IND: | ||
315 | mISDN_FsmEvent(&l1->l1m, EV_RESET_IND, NULL); | ||
316 | break; | ||
317 | case HW_DEACT_IND: | ||
318 | mISDN_FsmEvent(&l1->l1m, EV_DEACT_IND, NULL); | ||
319 | break; | ||
320 | case HW_POWERUP_IND: | ||
321 | mISDN_FsmEvent(&l1->l1m, EV_POWER_UP, NULL); | ||
322 | break; | ||
323 | case HW_DEACT_CNF: | ||
324 | mISDN_FsmEvent(&l1->l1m, EV_DEACT_CNF, NULL); | ||
325 | break; | ||
326 | case ANYSIGNAL: | ||
327 | mISDN_FsmEvent(&l1->l1m, EV_ANYSIG_IND, NULL); | ||
328 | break; | ||
329 | case LOSTFRAMING: | ||
330 | mISDN_FsmEvent(&l1->l1m, EV_ANYSIG_IND, NULL); | ||
331 | break; | ||
332 | case INFO2: | ||
333 | mISDN_FsmEvent(&l1->l1m, EV_INFO2_IND, NULL); | ||
334 | break; | ||
335 | case INFO4_P8: | ||
336 | mISDN_FsmEvent(&l1->l1m, EV_INFO4_IND, NULL); | ||
337 | break; | ||
338 | case INFO4_P10: | ||
339 | mISDN_FsmEvent(&l1->l1m, EV_INFO4_IND, NULL); | ||
340 | break; | ||
341 | case PH_ACTIVATE_REQ: | ||
342 | if (test_bit(FLG_L1_ACTIVATED, &l1->Flags)) | ||
343 | l1->dcb(l1->dch, PH_ACTIVATE_IND); | ||
344 | else { | ||
345 | test_and_set_bit(FLG_L1_ACTIVATING, &l1->Flags); | ||
346 | mISDN_FsmEvent(&l1->l1m, EV_PH_ACTIVATE, NULL); | ||
347 | } | ||
348 | break; | ||
349 | case CLOSE_CHANNEL: | ||
350 | release_l1(l1); | ||
351 | break; | ||
352 | default: | ||
353 | if (*debug & DEBUG_L1) | ||
354 | printk(KERN_DEBUG "%s %x unhandled\n", | ||
355 | __func__, event); | ||
356 | err = -EINVAL; | ||
357 | } | ||
358 | return err; | ||
359 | } | ||
360 | EXPORT_SYMBOL(l1_event); | ||
361 | |||
362 | int | ||
363 | create_l1(struct dchannel *dch, dchannel_l1callback *dcb) { | ||
364 | struct layer1 *nl1; | ||
365 | |||
366 | nl1 = kzalloc(sizeof(struct layer1), GFP_ATOMIC); | ||
367 | if (!nl1) { | ||
368 | printk(KERN_ERR "kmalloc struct layer1 failed\n"); | ||
369 | return -ENOMEM; | ||
370 | } | ||
371 | nl1->l1m.fsm = &l1fsm_s; | ||
372 | nl1->l1m.state = ST_L1_F3; | ||
373 | nl1->Flags = 0; | ||
374 | nl1->l1m.debug = *debug & DEBUG_L1_FSM; | ||
375 | nl1->l1m.userdata = nl1; | ||
376 | nl1->l1m.userint = 0; | ||
377 | nl1->l1m.printdebug = l1m_debug; | ||
378 | nl1->dch = dch; | ||
379 | nl1->dcb = dcb; | ||
380 | mISDN_FsmInitTimer(&nl1->l1m, &nl1->timer); | ||
381 | __module_get(THIS_MODULE); | ||
382 | dch->l1 = nl1; | ||
383 | return 0; | ||
384 | } | ||
385 | EXPORT_SYMBOL(create_l1); | ||
386 | |||
387 | int | ||
388 | l1_init(u_int *deb) | ||
389 | { | ||
390 | debug = deb; | ||
391 | l1fsm_s.state_count = L1S_STATE_COUNT; | ||
392 | l1fsm_s.event_count = L1_EVENT_COUNT; | ||
393 | l1fsm_s.strEvent = strL1Event; | ||
394 | l1fsm_s.strState = strL1SState; | ||
395 | mISDN_FsmNew(&l1fsm_s, L1SFnList, ARRAY_SIZE(L1SFnList)); | ||
396 | return 0; | ||
397 | } | ||
398 | |||
399 | void | ||
400 | l1_cleanup(void) | ||
401 | { | ||
402 | mISDN_FsmFree(&l1fsm_s); | ||
403 | } | ||
diff --git a/drivers/isdn/mISDN/layer1.h b/drivers/isdn/mISDN/layer1.h new file mode 100644 index 000000000000..9c8125fd89af --- /dev/null +++ b/drivers/isdn/mISDN/layer1.h | |||
@@ -0,0 +1,26 @@ | |||
1 | /* | ||
2 | * | ||
3 | * Layer 1 defines | ||
4 | * | ||
5 | * Copyright 2008 by Karsten Keil <kkeil@novell.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | */ | ||
17 | |||
18 | #define FLG_L1_ACTIVATING 1 | ||
19 | #define FLG_L1_ACTIVATED 2 | ||
20 | #define FLG_L1_DEACTTIMER 3 | ||
21 | #define FLG_L1_ACTTIMER 4 | ||
22 | #define FLG_L1_T3RUN 5 | ||
23 | #define FLG_L1_PULL_REQ 6 | ||
24 | #define FLG_L1_UINT 7 | ||
25 | #define FLG_L1_DBLOCKED 8 | ||
26 | |||
diff --git a/drivers/isdn/mISDN/layer2.c b/drivers/isdn/mISDN/layer2.c new file mode 100644 index 000000000000..f5ad888ee71e --- /dev/null +++ b/drivers/isdn/mISDN/layer2.c | |||
@@ -0,0 +1,2216 @@ | |||
1 | /* | ||
2 | * | ||
3 | * Author Karsten Keil <kkeil@novell.com> | ||
4 | * | ||
5 | * Copyright 2008 by Karsten Keil <kkeil@novell.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | */ | ||
17 | |||
18 | #include "fsm.h" | ||
19 | #include "layer2.h" | ||
20 | |||
21 | static int *debug; | ||
22 | |||
23 | static | ||
24 | struct Fsm l2fsm = {NULL, 0, 0, NULL, NULL}; | ||
25 | |||
26 | static char *strL2State[] = | ||
27 | { | ||
28 | "ST_L2_1", | ||
29 | "ST_L2_2", | ||
30 | "ST_L2_3", | ||
31 | "ST_L2_4", | ||
32 | "ST_L2_5", | ||
33 | "ST_L2_6", | ||
34 | "ST_L2_7", | ||
35 | "ST_L2_8", | ||
36 | }; | ||
37 | |||
38 | enum { | ||
39 | EV_L2_UI, | ||
40 | EV_L2_SABME, | ||
41 | EV_L2_DISC, | ||
42 | EV_L2_DM, | ||
43 | EV_L2_UA, | ||
44 | EV_L2_FRMR, | ||
45 | EV_L2_SUPER, | ||
46 | EV_L2_I, | ||
47 | EV_L2_DL_DATA, | ||
48 | EV_L2_ACK_PULL, | ||
49 | EV_L2_DL_UNITDATA, | ||
50 | EV_L2_DL_ESTABLISH_REQ, | ||
51 | EV_L2_DL_RELEASE_REQ, | ||
52 | EV_L2_MDL_ASSIGN, | ||
53 | EV_L2_MDL_REMOVE, | ||
54 | EV_L2_MDL_ERROR, | ||
55 | EV_L1_DEACTIVATE, | ||
56 | EV_L2_T200, | ||
57 | EV_L2_T203, | ||
58 | EV_L2_SET_OWN_BUSY, | ||
59 | EV_L2_CLEAR_OWN_BUSY, | ||
60 | EV_L2_FRAME_ERROR, | ||
61 | }; | ||
62 | |||
63 | #define L2_EVENT_COUNT (EV_L2_FRAME_ERROR+1) | ||
64 | |||
65 | static char *strL2Event[] = | ||
66 | { | ||
67 | "EV_L2_UI", | ||
68 | "EV_L2_SABME", | ||
69 | "EV_L2_DISC", | ||
70 | "EV_L2_DM", | ||
71 | "EV_L2_UA", | ||
72 | "EV_L2_FRMR", | ||
73 | "EV_L2_SUPER", | ||
74 | "EV_L2_I", | ||
75 | "EV_L2_DL_DATA", | ||
76 | "EV_L2_ACK_PULL", | ||
77 | "EV_L2_DL_UNITDATA", | ||
78 | "EV_L2_DL_ESTABLISH_REQ", | ||
79 | "EV_L2_DL_RELEASE_REQ", | ||
80 | "EV_L2_MDL_ASSIGN", | ||
81 | "EV_L2_MDL_REMOVE", | ||
82 | "EV_L2_MDL_ERROR", | ||
83 | "EV_L1_DEACTIVATE", | ||
84 | "EV_L2_T200", | ||
85 | "EV_L2_T203", | ||
86 | "EV_L2_SET_OWN_BUSY", | ||
87 | "EV_L2_CLEAR_OWN_BUSY", | ||
88 | "EV_L2_FRAME_ERROR", | ||
89 | }; | ||
90 | |||
91 | static void | ||
92 | l2m_debug(struct FsmInst *fi, char *fmt, ...) | ||
93 | { | ||
94 | struct layer2 *l2 = fi->userdata; | ||
95 | va_list va; | ||
96 | |||
97 | if (!(*debug & DEBUG_L2_FSM)) | ||
98 | return; | ||
99 | va_start(va, fmt); | ||
100 | printk(KERN_DEBUG "l2 (tei %d): ", l2->tei); | ||
101 | vprintk(fmt, va); | ||
102 | printk("\n"); | ||
103 | va_end(va); | ||
104 | } | ||
105 | |||
106 | inline u_int | ||
107 | l2headersize(struct layer2 *l2, int ui) | ||
108 | { | ||
109 | return ((test_bit(FLG_MOD128, &l2->flag) && (!ui)) ? 2 : 1) + | ||
110 | (test_bit(FLG_LAPD, &l2->flag) ? 2 : 1); | ||
111 | } | ||
112 | |||
113 | inline u_int | ||
114 | l2addrsize(struct layer2 *l2) | ||
115 | { | ||
116 | return test_bit(FLG_LAPD, &l2->flag) ? 2 : 1; | ||
117 | } | ||
118 | |||
119 | static u_int | ||
120 | l2_newid(struct layer2 *l2) | ||
121 | { | ||
122 | u_int id; | ||
123 | |||
124 | id = l2->next_id++; | ||
125 | if (id == 0x7fff) | ||
126 | l2->next_id = 1; | ||
127 | id <<= 16; | ||
128 | id |= l2->tei << 8; | ||
129 | id |= l2->sapi; | ||
130 | return id; | ||
131 | } | ||
132 | |||
133 | static void | ||
134 | l2up(struct layer2 *l2, u_int prim, struct sk_buff *skb) | ||
135 | { | ||
136 | int err; | ||
137 | |||
138 | if (!l2->up) | ||
139 | return; | ||
140 | mISDN_HEAD_PRIM(skb) = prim; | ||
141 | mISDN_HEAD_ID(skb) = (l2->ch.nr << 16) | l2->ch.addr; | ||
142 | err = l2->up->send(l2->up, skb); | ||
143 | if (err) { | ||
144 | printk(KERN_WARNING "%s: err=%d\n", __func__, err); | ||
145 | dev_kfree_skb(skb); | ||
146 | } | ||
147 | } | ||
148 | |||
149 | static void | ||
150 | l2up_create(struct layer2 *l2, u_int prim, int len, void *arg) | ||
151 | { | ||
152 | struct sk_buff *skb; | ||
153 | struct mISDNhead *hh; | ||
154 | int err; | ||
155 | |||
156 | if (!l2->up) | ||
157 | return; | ||
158 | skb = mI_alloc_skb(len, GFP_ATOMIC); | ||
159 | if (!skb) | ||
160 | return; | ||
161 | hh = mISDN_HEAD_P(skb); | ||
162 | hh->prim = prim; | ||
163 | hh->id = (l2->ch.nr << 16) | l2->ch.addr; | ||
164 | if (len) | ||
165 | memcpy(skb_put(skb, len), arg, len); | ||
166 | err = l2->up->send(l2->up, skb); | ||
167 | if (err) { | ||
168 | printk(KERN_WARNING "%s: err=%d\n", __func__, err); | ||
169 | dev_kfree_skb(skb); | ||
170 | } | ||
171 | } | ||
172 | |||
173 | static int | ||
174 | l2down_skb(struct layer2 *l2, struct sk_buff *skb) { | ||
175 | int ret; | ||
176 | |||
177 | ret = l2->ch.recv(l2->ch.peer, skb); | ||
178 | if (ret && (*debug & DEBUG_L2_RECV)) | ||
179 | printk(KERN_DEBUG "l2down_skb: ret(%d)\n", ret); | ||
180 | return ret; | ||
181 | } | ||
182 | |||
183 | static int | ||
184 | l2down_raw(struct layer2 *l2, struct sk_buff *skb) | ||
185 | { | ||
186 | struct mISDNhead *hh = mISDN_HEAD_P(skb); | ||
187 | |||
188 | if (hh->prim == PH_DATA_REQ) { | ||
189 | if (test_and_set_bit(FLG_L1_NOTREADY, &l2->flag)) { | ||
190 | skb_queue_tail(&l2->down_queue, skb); | ||
191 | return 0; | ||
192 | } | ||
193 | l2->down_id = mISDN_HEAD_ID(skb); | ||
194 | } | ||
195 | return l2down_skb(l2, skb); | ||
196 | } | ||
197 | |||
198 | static int | ||
199 | l2down(struct layer2 *l2, u_int prim, u_int id, struct sk_buff *skb) | ||
200 | { | ||
201 | struct mISDNhead *hh = mISDN_HEAD_P(skb); | ||
202 | |||
203 | hh->prim = prim; | ||
204 | hh->id = id; | ||
205 | return l2down_raw(l2, skb); | ||
206 | } | ||
207 | |||
208 | static int | ||
209 | l2down_create(struct layer2 *l2, u_int prim, u_int id, int len, void *arg) | ||
210 | { | ||
211 | struct sk_buff *skb; | ||
212 | int err; | ||
213 | struct mISDNhead *hh; | ||
214 | |||
215 | skb = mI_alloc_skb(len, GFP_ATOMIC); | ||
216 | if (!skb) | ||
217 | return -ENOMEM; | ||
218 | hh = mISDN_HEAD_P(skb); | ||
219 | hh->prim = prim; | ||
220 | hh->id = id; | ||
221 | if (len) | ||
222 | memcpy(skb_put(skb, len), arg, len); | ||
223 | err = l2down_raw(l2, skb); | ||
224 | if (err) | ||
225 | dev_kfree_skb(skb); | ||
226 | return err; | ||
227 | } | ||
228 | |||
229 | static int | ||
230 | ph_data_confirm(struct layer2 *l2, struct mISDNhead *hh, struct sk_buff *skb) { | ||
231 | struct sk_buff *nskb = skb; | ||
232 | int ret = -EAGAIN; | ||
233 | |||
234 | if (test_bit(FLG_L1_NOTREADY, &l2->flag)) { | ||
235 | if (hh->id == l2->down_id) { | ||
236 | nskb = skb_dequeue(&l2->down_queue); | ||
237 | if (nskb) { | ||
238 | l2->down_id = mISDN_HEAD_ID(nskb); | ||
239 | if (l2down_skb(l2, nskb)) { | ||
240 | dev_kfree_skb(nskb); | ||
241 | l2->down_id = MISDN_ID_NONE; | ||
242 | } | ||
243 | } else | ||
244 | l2->down_id = MISDN_ID_NONE; | ||
245 | if (ret) { | ||
246 | dev_kfree_skb(skb); | ||
247 | ret = 0; | ||
248 | } | ||
249 | if (l2->down_id == MISDN_ID_NONE) { | ||
250 | test_and_clear_bit(FLG_L1_NOTREADY, &l2->flag); | ||
251 | mISDN_FsmEvent(&l2->l2m, EV_L2_ACK_PULL, NULL); | ||
252 | } | ||
253 | } | ||
254 | } | ||
255 | if (!test_and_set_bit(FLG_L1_NOTREADY, &l2->flag)) { | ||
256 | nskb = skb_dequeue(&l2->down_queue); | ||
257 | if (nskb) { | ||
258 | l2->down_id = mISDN_HEAD_ID(nskb); | ||
259 | if (l2down_skb(l2, nskb)) { | ||
260 | dev_kfree_skb(nskb); | ||
261 | l2->down_id = MISDN_ID_NONE; | ||
262 | test_and_clear_bit(FLG_L1_NOTREADY, &l2->flag); | ||
263 | } | ||
264 | } else | ||
265 | test_and_clear_bit(FLG_L1_NOTREADY, &l2->flag); | ||
266 | } | ||
267 | return ret; | ||
268 | } | ||
269 | |||
270 | static int | ||
271 | l2mgr(struct layer2 *l2, u_int prim, void *arg) { | ||
272 | long c = (long)arg; | ||
273 | |||
274 | printk(KERN_WARNING | ||
275 | "l2mgr: addr:%x prim %x %c\n", l2->id, prim, (char)c); | ||
276 | if (test_bit(FLG_LAPD, &l2->flag) && | ||
277 | !test_bit(FLG_FIXED_TEI, &l2->flag)) { | ||
278 | switch (c) { | ||
279 | case 'C': | ||
280 | case 'D': | ||
281 | case 'G': | ||
282 | case 'H': | ||
283 | l2_tei(l2, prim, (u_long)arg); | ||
284 | break; | ||
285 | } | ||
286 | } | ||
287 | return 0; | ||
288 | } | ||
289 | |||
290 | static void | ||
291 | set_peer_busy(struct layer2 *l2) { | ||
292 | test_and_set_bit(FLG_PEER_BUSY, &l2->flag); | ||
293 | if (skb_queue_len(&l2->i_queue) || skb_queue_len(&l2->ui_queue)) | ||
294 | test_and_set_bit(FLG_L2BLOCK, &l2->flag); | ||
295 | } | ||
296 | |||
297 | static void | ||
298 | clear_peer_busy(struct layer2 *l2) { | ||
299 | if (test_and_clear_bit(FLG_PEER_BUSY, &l2->flag)) | ||
300 | test_and_clear_bit(FLG_L2BLOCK, &l2->flag); | ||
301 | } | ||
302 | |||
303 | static void | ||
304 | InitWin(struct layer2 *l2) | ||
305 | { | ||
306 | int i; | ||
307 | |||
308 | for (i = 0; i < MAX_WINDOW; i++) | ||
309 | l2->windowar[i] = NULL; | ||
310 | } | ||
311 | |||
312 | static int | ||
313 | freewin(struct layer2 *l2) | ||
314 | { | ||
315 | int i, cnt = 0; | ||
316 | |||
317 | for (i = 0; i < MAX_WINDOW; i++) { | ||
318 | if (l2->windowar[i]) { | ||
319 | cnt++; | ||
320 | dev_kfree_skb(l2->windowar[i]); | ||
321 | l2->windowar[i] = NULL; | ||
322 | } | ||
323 | } | ||
324 | return cnt; | ||
325 | } | ||
326 | |||
327 | static void | ||
328 | ReleaseWin(struct layer2 *l2) | ||
329 | { | ||
330 | int cnt = freewin(l2); | ||
331 | |||
332 | if (cnt) | ||
333 | printk(KERN_WARNING | ||
334 | "isdnl2 freed %d skbuffs in release\n", cnt); | ||
335 | } | ||
336 | |||
337 | inline unsigned int | ||
338 | cansend(struct layer2 *l2) | ||
339 | { | ||
340 | unsigned int p1; | ||
341 | |||
342 | if (test_bit(FLG_MOD128, &l2->flag)) | ||
343 | p1 = (l2->vs - l2->va) % 128; | ||
344 | else | ||
345 | p1 = (l2->vs - l2->va) % 8; | ||
346 | return (p1 < l2->window) && !test_bit(FLG_PEER_BUSY, &l2->flag); | ||
347 | } | ||
348 | |||
349 | inline void | ||
350 | clear_exception(struct layer2 *l2) | ||
351 | { | ||
352 | test_and_clear_bit(FLG_ACK_PEND, &l2->flag); | ||
353 | test_and_clear_bit(FLG_REJEXC, &l2->flag); | ||
354 | test_and_clear_bit(FLG_OWN_BUSY, &l2->flag); | ||
355 | clear_peer_busy(l2); | ||
356 | } | ||
357 | |||
358 | static int | ||
359 | sethdraddr(struct layer2 *l2, u_char *header, int rsp) | ||
360 | { | ||
361 | u_char *ptr = header; | ||
362 | int crbit = rsp; | ||
363 | |||
364 | if (test_bit(FLG_LAPD, &l2->flag)) { | ||
365 | if (test_bit(FLG_LAPD_NET, &l2->flag)) | ||
366 | crbit = !crbit; | ||
367 | *ptr++ = (l2->sapi << 2) | (crbit ? 2 : 0); | ||
368 | *ptr++ = (l2->tei << 1) | 1; | ||
369 | return 2; | ||
370 | } else { | ||
371 | if (test_bit(FLG_ORIG, &l2->flag)) | ||
372 | crbit = !crbit; | ||
373 | if (crbit) | ||
374 | *ptr++ = l2->addr.B; | ||
375 | else | ||
376 | *ptr++ = l2->addr.A; | ||
377 | return 1; | ||
378 | } | ||
379 | } | ||
380 | |||
381 | static inline void | ||
382 | enqueue_super(struct layer2 *l2, struct sk_buff *skb) | ||
383 | { | ||
384 | if (l2down(l2, PH_DATA_REQ, l2_newid(l2), skb)) | ||
385 | dev_kfree_skb(skb); | ||
386 | } | ||
387 | |||
388 | static inline void | ||
389 | enqueue_ui(struct layer2 *l2, struct sk_buff *skb) | ||
390 | { | ||
391 | if (l2->tm) | ||
392 | l2_tei(l2, MDL_STATUS_UI_IND, 0); | ||
393 | if (l2down(l2, PH_DATA_REQ, l2_newid(l2), skb)) | ||
394 | dev_kfree_skb(skb); | ||
395 | } | ||
396 | |||
397 | inline int | ||
398 | IsUI(u_char *data) | ||
399 | { | ||
400 | return (data[0] & 0xef) == UI; | ||
401 | } | ||
402 | |||
403 | inline int | ||
404 | IsUA(u_char *data) | ||
405 | { | ||
406 | return (data[0] & 0xef) == UA; | ||
407 | } | ||
408 | |||
409 | inline int | ||
410 | IsDM(u_char *data) | ||
411 | { | ||
412 | return (data[0] & 0xef) == DM; | ||
413 | } | ||
414 | |||
415 | inline int | ||
416 | IsDISC(u_char *data) | ||
417 | { | ||
418 | return (data[0] & 0xef) == DISC; | ||
419 | } | ||
420 | |||
421 | inline int | ||
422 | IsRR(u_char *data, struct layer2 *l2) | ||
423 | { | ||
424 | if (test_bit(FLG_MOD128, &l2->flag)) | ||
425 | return data[0] == RR; | ||
426 | else | ||
427 | return (data[0] & 0xf) == 1; | ||
428 | } | ||
429 | |||
430 | inline int | ||
431 | IsSFrame(u_char *data, struct layer2 *l2) | ||
432 | { | ||
433 | register u_char d = *data; | ||
434 | |||
435 | if (!test_bit(FLG_MOD128, &l2->flag)) | ||
436 | d &= 0xf; | ||
437 | return ((d & 0xf3) == 1) && ((d & 0x0c) != 0x0c); | ||
438 | } | ||
439 | |||
440 | inline int | ||
441 | IsSABME(u_char *data, struct layer2 *l2) | ||
442 | { | ||
443 | u_char d = data[0] & ~0x10; | ||
444 | |||
445 | return test_bit(FLG_MOD128, &l2->flag) ? d == SABME : d == SABM; | ||
446 | } | ||
447 | |||
448 | inline int | ||
449 | IsREJ(u_char *data, struct layer2 *l2) | ||
450 | { | ||
451 | return test_bit(FLG_MOD128, &l2->flag) ? | ||
452 | data[0] == REJ : (data[0] & 0xf) == REJ; | ||
453 | } | ||
454 | |||
455 | inline int | ||
456 | IsFRMR(u_char *data) | ||
457 | { | ||
458 | return (data[0] & 0xef) == FRMR; | ||
459 | } | ||
460 | |||
461 | inline int | ||
462 | IsRNR(u_char *data, struct layer2 *l2) | ||
463 | { | ||
464 | return test_bit(FLG_MOD128, &l2->flag) ? | ||
465 | data[0] == RNR : (data[0] & 0xf) == RNR; | ||
466 | } | ||
467 | |||
468 | int | ||
469 | iframe_error(struct layer2 *l2, struct sk_buff *skb) | ||
470 | { | ||
471 | u_int i; | ||
472 | int rsp = *skb->data & 0x2; | ||
473 | |||
474 | i = l2addrsize(l2) + (test_bit(FLG_MOD128, &l2->flag) ? 2 : 1); | ||
475 | if (test_bit(FLG_ORIG, &l2->flag)) | ||
476 | rsp = !rsp; | ||
477 | if (rsp) | ||
478 | return 'L'; | ||
479 | if (skb->len < i) | ||
480 | return 'N'; | ||
481 | if ((skb->len - i) > l2->maxlen) | ||
482 | return 'O'; | ||
483 | return 0; | ||
484 | } | ||
485 | |||
486 | int | ||
487 | super_error(struct layer2 *l2, struct sk_buff *skb) | ||
488 | { | ||
489 | if (skb->len != l2addrsize(l2) + | ||
490 | (test_bit(FLG_MOD128, &l2->flag) ? 2 : 1)) | ||
491 | return 'N'; | ||
492 | return 0; | ||
493 | } | ||
494 | |||
495 | int | ||
496 | unnum_error(struct layer2 *l2, struct sk_buff *skb, int wantrsp) | ||
497 | { | ||
498 | int rsp = (*skb->data & 0x2) >> 1; | ||
499 | if (test_bit(FLG_ORIG, &l2->flag)) | ||
500 | rsp = !rsp; | ||
501 | if (rsp != wantrsp) | ||
502 | return 'L'; | ||
503 | if (skb->len != l2addrsize(l2) + 1) | ||
504 | return 'N'; | ||
505 | return 0; | ||
506 | } | ||
507 | |||
508 | int | ||
509 | UI_error(struct layer2 *l2, struct sk_buff *skb) | ||
510 | { | ||
511 | int rsp = *skb->data & 0x2; | ||
512 | if (test_bit(FLG_ORIG, &l2->flag)) | ||
513 | rsp = !rsp; | ||
514 | if (rsp) | ||
515 | return 'L'; | ||
516 | if (skb->len > l2->maxlen + l2addrsize(l2) + 1) | ||
517 | return 'O'; | ||
518 | return 0; | ||
519 | } | ||
520 | |||
521 | int | ||
522 | FRMR_error(struct layer2 *l2, struct sk_buff *skb) | ||
523 | { | ||
524 | u_int headers = l2addrsize(l2) + 1; | ||
525 | u_char *datap = skb->data + headers; | ||
526 | int rsp = *skb->data & 0x2; | ||
527 | |||
528 | if (test_bit(FLG_ORIG, &l2->flag)) | ||
529 | rsp = !rsp; | ||
530 | if (!rsp) | ||
531 | return 'L'; | ||
532 | if (test_bit(FLG_MOD128, &l2->flag)) { | ||
533 | if (skb->len < headers + 5) | ||
534 | return 'N'; | ||
535 | else if (*debug & DEBUG_L2) | ||
536 | l2m_debug(&l2->l2m, | ||
537 | "FRMR information %2x %2x %2x %2x %2x", | ||
538 | datap[0], datap[1], datap[2], datap[3], datap[4]); | ||
539 | } else { | ||
540 | if (skb->len < headers + 3) | ||
541 | return 'N'; | ||
542 | else if (*debug & DEBUG_L2) | ||
543 | l2m_debug(&l2->l2m, | ||
544 | "FRMR information %2x %2x %2x", | ||
545 | datap[0], datap[1], datap[2]); | ||
546 | } | ||
547 | return 0; | ||
548 | } | ||
549 | |||
550 | static unsigned int | ||
551 | legalnr(struct layer2 *l2, unsigned int nr) | ||
552 | { | ||
553 | if (test_bit(FLG_MOD128, &l2->flag)) | ||
554 | return ((nr - l2->va) % 128) <= ((l2->vs - l2->va) % 128); | ||
555 | else | ||
556 | return ((nr - l2->va) % 8) <= ((l2->vs - l2->va) % 8); | ||
557 | } | ||
558 | |||
559 | static void | ||
560 | setva(struct layer2 *l2, unsigned int nr) | ||
561 | { | ||
562 | struct sk_buff *skb; | ||
563 | |||
564 | while (l2->va != nr) { | ||
565 | l2->va++; | ||
566 | if (test_bit(FLG_MOD128, &l2->flag)) | ||
567 | l2->va %= 128; | ||
568 | else | ||
569 | l2->va %= 8; | ||
570 | if (l2->windowar[l2->sow]) { | ||
571 | skb_trim(l2->windowar[l2->sow], 0); | ||
572 | skb_queue_tail(&l2->tmp_queue, l2->windowar[l2->sow]); | ||
573 | l2->windowar[l2->sow] = NULL; | ||
574 | } | ||
575 | l2->sow = (l2->sow + 1) % l2->window; | ||
576 | } | ||
577 | skb = skb_dequeue(&l2->tmp_queue); | ||
578 | while (skb) { | ||
579 | dev_kfree_skb(skb); | ||
580 | skb = skb_dequeue(&l2->tmp_queue); | ||
581 | } | ||
582 | } | ||
583 | |||
584 | static void | ||
585 | send_uframe(struct layer2 *l2, struct sk_buff *skb, u_char cmd, u_char cr) | ||
586 | { | ||
587 | u_char tmp[MAX_L2HEADER_LEN]; | ||
588 | int i; | ||
589 | |||
590 | i = sethdraddr(l2, tmp, cr); | ||
591 | tmp[i++] = cmd; | ||
592 | if (skb) | ||
593 | skb_trim(skb, 0); | ||
594 | else { | ||
595 | skb = mI_alloc_skb(i, GFP_ATOMIC); | ||
596 | if (!skb) { | ||
597 | printk(KERN_WARNING "%s: can't alloc skbuff\n", | ||
598 | __func__); | ||
599 | return; | ||
600 | } | ||
601 | } | ||
602 | memcpy(skb_put(skb, i), tmp, i); | ||
603 | enqueue_super(l2, skb); | ||
604 | } | ||
605 | |||
606 | |||
607 | inline u_char | ||
608 | get_PollFlag(struct layer2 *l2, struct sk_buff *skb) | ||
609 | { | ||
610 | return skb->data[l2addrsize(l2)] & 0x10; | ||
611 | } | ||
612 | |||
613 | inline u_char | ||
614 | get_PollFlagFree(struct layer2 *l2, struct sk_buff *skb) | ||
615 | { | ||
616 | u_char PF; | ||
617 | |||
618 | PF = get_PollFlag(l2, skb); | ||
619 | dev_kfree_skb(skb); | ||
620 | return PF; | ||
621 | } | ||
622 | |||
623 | inline void | ||
624 | start_t200(struct layer2 *l2, int i) | ||
625 | { | ||
626 | mISDN_FsmAddTimer(&l2->t200, l2->T200, EV_L2_T200, NULL, i); | ||
627 | test_and_set_bit(FLG_T200_RUN, &l2->flag); | ||
628 | } | ||
629 | |||
630 | inline void | ||
631 | restart_t200(struct layer2 *l2, int i) | ||
632 | { | ||
633 | mISDN_FsmRestartTimer(&l2->t200, l2->T200, EV_L2_T200, NULL, i); | ||
634 | test_and_set_bit(FLG_T200_RUN, &l2->flag); | ||
635 | } | ||
636 | |||
637 | inline void | ||
638 | stop_t200(struct layer2 *l2, int i) | ||
639 | { | ||
640 | if (test_and_clear_bit(FLG_T200_RUN, &l2->flag)) | ||
641 | mISDN_FsmDelTimer(&l2->t200, i); | ||
642 | } | ||
643 | |||
644 | inline void | ||
645 | st5_dl_release_l2l3(struct layer2 *l2) | ||
646 | { | ||
647 | int pr; | ||
648 | |||
649 | if (test_and_clear_bit(FLG_PEND_REL, &l2->flag)) | ||
650 | pr = DL_RELEASE_CNF; | ||
651 | else | ||
652 | pr = DL_RELEASE_IND; | ||
653 | l2up_create(l2, pr, 0, NULL); | ||
654 | } | ||
655 | |||
656 | inline void | ||
657 | lapb_dl_release_l2l3(struct layer2 *l2, int f) | ||
658 | { | ||
659 | if (test_bit(FLG_LAPB, &l2->flag)) | ||
660 | l2down_create(l2, PH_DEACTIVATE_REQ, l2_newid(l2), 0, NULL); | ||
661 | l2up_create(l2, f, 0, NULL); | ||
662 | } | ||
663 | |||
664 | static void | ||
665 | establishlink(struct FsmInst *fi) | ||
666 | { | ||
667 | struct layer2 *l2 = fi->userdata; | ||
668 | u_char cmd; | ||
669 | |||
670 | clear_exception(l2); | ||
671 | l2->rc = 0; | ||
672 | cmd = (test_bit(FLG_MOD128, &l2->flag) ? SABME : SABM) | 0x10; | ||
673 | send_uframe(l2, NULL, cmd, CMD); | ||
674 | mISDN_FsmDelTimer(&l2->t203, 1); | ||
675 | restart_t200(l2, 1); | ||
676 | test_and_clear_bit(FLG_PEND_REL, &l2->flag); | ||
677 | freewin(l2); | ||
678 | mISDN_FsmChangeState(fi, ST_L2_5); | ||
679 | } | ||
680 | |||
681 | static void | ||
682 | l2_mdl_error_ua(struct FsmInst *fi, int event, void *arg) | ||
683 | { | ||
684 | struct sk_buff *skb = arg; | ||
685 | struct layer2 *l2 = fi->userdata; | ||
686 | |||
687 | if (get_PollFlagFree(l2, skb)) | ||
688 | l2mgr(l2, MDL_ERROR_IND, (void *) 'C'); | ||
689 | else | ||
690 | l2mgr(l2, MDL_ERROR_IND, (void *) 'D'); | ||
691 | |||
692 | } | ||
693 | |||
694 | static void | ||
695 | l2_mdl_error_dm(struct FsmInst *fi, int event, void *arg) | ||
696 | { | ||
697 | struct sk_buff *skb = arg; | ||
698 | struct layer2 *l2 = fi->userdata; | ||
699 | |||
700 | if (get_PollFlagFree(l2, skb)) | ||
701 | l2mgr(l2, MDL_ERROR_IND, (void *) 'B'); | ||
702 | else { | ||
703 | l2mgr(l2, MDL_ERROR_IND, (void *) 'E'); | ||
704 | establishlink(fi); | ||
705 | test_and_clear_bit(FLG_L3_INIT, &l2->flag); | ||
706 | } | ||
707 | } | ||
708 | |||
709 | static void | ||
710 | l2_st8_mdl_error_dm(struct FsmInst *fi, int event, void *arg) | ||
711 | { | ||
712 | struct sk_buff *skb = arg; | ||
713 | struct layer2 *l2 = fi->userdata; | ||
714 | |||
715 | if (get_PollFlagFree(l2, skb)) | ||
716 | l2mgr(l2, MDL_ERROR_IND, (void *) 'B'); | ||
717 | else | ||
718 | l2mgr(l2, MDL_ERROR_IND, (void *) 'E'); | ||
719 | establishlink(fi); | ||
720 | test_and_clear_bit(FLG_L3_INIT, &l2->flag); | ||
721 | } | ||
722 | |||
723 | static void | ||
724 | l2_go_st3(struct FsmInst *fi, int event, void *arg) | ||
725 | { | ||
726 | dev_kfree_skb((struct sk_buff *)arg); | ||
727 | mISDN_FsmChangeState(fi, ST_L2_3); | ||
728 | } | ||
729 | |||
730 | static void | ||
731 | l2_mdl_assign(struct FsmInst *fi, int event, void *arg) | ||
732 | { | ||
733 | struct layer2 *l2 = fi->userdata; | ||
734 | |||
735 | mISDN_FsmChangeState(fi, ST_L2_3); | ||
736 | dev_kfree_skb((struct sk_buff *)arg); | ||
737 | l2_tei(l2, MDL_ASSIGN_IND, 0); | ||
738 | } | ||
739 | |||
740 | static void | ||
741 | l2_queue_ui_assign(struct FsmInst *fi, int event, void *arg) | ||
742 | { | ||
743 | struct layer2 *l2 = fi->userdata; | ||
744 | struct sk_buff *skb = arg; | ||
745 | |||
746 | skb_queue_tail(&l2->ui_queue, skb); | ||
747 | mISDN_FsmChangeState(fi, ST_L2_2); | ||
748 | l2_tei(l2, MDL_ASSIGN_IND, 0); | ||
749 | } | ||
750 | |||
751 | static void | ||
752 | l2_queue_ui(struct FsmInst *fi, int event, void *arg) | ||
753 | { | ||
754 | struct layer2 *l2 = fi->userdata; | ||
755 | struct sk_buff *skb = arg; | ||
756 | |||
757 | skb_queue_tail(&l2->ui_queue, skb); | ||
758 | } | ||
759 | |||
760 | static void | ||
761 | tx_ui(struct layer2 *l2) | ||
762 | { | ||
763 | struct sk_buff *skb; | ||
764 | u_char header[MAX_L2HEADER_LEN]; | ||
765 | int i; | ||
766 | |||
767 | i = sethdraddr(l2, header, CMD); | ||
768 | if (test_bit(FLG_LAPD_NET, &l2->flag)) | ||
769 | header[1] = 0xff; /* tei 127 */ | ||
770 | header[i++] = UI; | ||
771 | while ((skb = skb_dequeue(&l2->ui_queue))) { | ||
772 | memcpy(skb_push(skb, i), header, i); | ||
773 | enqueue_ui(l2, skb); | ||
774 | } | ||
775 | } | ||
776 | |||
777 | static void | ||
778 | l2_send_ui(struct FsmInst *fi, int event, void *arg) | ||
779 | { | ||
780 | struct layer2 *l2 = fi->userdata; | ||
781 | struct sk_buff *skb = arg; | ||
782 | |||
783 | skb_queue_tail(&l2->ui_queue, skb); | ||
784 | tx_ui(l2); | ||
785 | } | ||
786 | |||
787 | static void | ||
788 | l2_got_ui(struct FsmInst *fi, int event, void *arg) | ||
789 | { | ||
790 | struct layer2 *l2 = fi->userdata; | ||
791 | struct sk_buff *skb = arg; | ||
792 | |||
793 | skb_pull(skb, l2headersize(l2, 1)); | ||
794 | /* | ||
795 | * in states 1-3 for broadcast | ||
796 | */ | ||
797 | |||
798 | if (l2->tm) | ||
799 | l2_tei(l2, MDL_STATUS_UI_IND, 0); | ||
800 | l2up(l2, DL_UNITDATA_IND, skb); | ||
801 | } | ||
802 | |||
803 | static void | ||
804 | l2_establish(struct FsmInst *fi, int event, void *arg) | ||
805 | { | ||
806 | struct sk_buff *skb = arg; | ||
807 | struct layer2 *l2 = fi->userdata; | ||
808 | |||
809 | establishlink(fi); | ||
810 | test_and_set_bit(FLG_L3_INIT, &l2->flag); | ||
811 | dev_kfree_skb(skb); | ||
812 | } | ||
813 | |||
814 | static void | ||
815 | l2_discard_i_setl3(struct FsmInst *fi, int event, void *arg) | ||
816 | { | ||
817 | struct sk_buff *skb = arg; | ||
818 | struct layer2 *l2 = fi->userdata; | ||
819 | |||
820 | skb_queue_purge(&l2->i_queue); | ||
821 | test_and_set_bit(FLG_L3_INIT, &l2->flag); | ||
822 | test_and_clear_bit(FLG_PEND_REL, &l2->flag); | ||
823 | dev_kfree_skb(skb); | ||
824 | } | ||
825 | |||
826 | static void | ||
827 | l2_l3_reestablish(struct FsmInst *fi, int event, void *arg) | ||
828 | { | ||
829 | struct sk_buff *skb = arg; | ||
830 | struct layer2 *l2 = fi->userdata; | ||
831 | |||
832 | skb_queue_purge(&l2->i_queue); | ||
833 | establishlink(fi); | ||
834 | test_and_set_bit(FLG_L3_INIT, &l2->flag); | ||
835 | dev_kfree_skb(skb); | ||
836 | } | ||
837 | |||
838 | static void | ||
839 | l2_release(struct FsmInst *fi, int event, void *arg) | ||
840 | { | ||
841 | struct layer2 *l2 = fi->userdata; | ||
842 | struct sk_buff *skb = arg; | ||
843 | |||
844 | skb_trim(skb, 0); | ||
845 | l2up(l2, DL_RELEASE_CNF, skb); | ||
846 | } | ||
847 | |||
848 | static void | ||
849 | l2_pend_rel(struct FsmInst *fi, int event, void *arg) | ||
850 | { | ||
851 | struct sk_buff *skb = arg; | ||
852 | struct layer2 *l2 = fi->userdata; | ||
853 | |||
854 | test_and_set_bit(FLG_PEND_REL, &l2->flag); | ||
855 | dev_kfree_skb(skb); | ||
856 | } | ||
857 | |||
858 | static void | ||
859 | l2_disconnect(struct FsmInst *fi, int event, void *arg) | ||
860 | { | ||
861 | struct layer2 *l2 = fi->userdata; | ||
862 | struct sk_buff *skb = arg; | ||
863 | |||
864 | skb_queue_purge(&l2->i_queue); | ||
865 | freewin(l2); | ||
866 | mISDN_FsmChangeState(fi, ST_L2_6); | ||
867 | l2->rc = 0; | ||
868 | send_uframe(l2, NULL, DISC | 0x10, CMD); | ||
869 | mISDN_FsmDelTimer(&l2->t203, 1); | ||
870 | restart_t200(l2, 2); | ||
871 | if (skb) | ||
872 | dev_kfree_skb(skb); | ||
873 | } | ||
874 | |||
875 | static void | ||
876 | l2_start_multi(struct FsmInst *fi, int event, void *arg) | ||
877 | { | ||
878 | struct layer2 *l2 = fi->userdata; | ||
879 | struct sk_buff *skb = arg; | ||
880 | |||
881 | l2->vs = 0; | ||
882 | l2->va = 0; | ||
883 | l2->vr = 0; | ||
884 | l2->sow = 0; | ||
885 | clear_exception(l2); | ||
886 | send_uframe(l2, NULL, UA | get_PollFlag(l2, skb), RSP); | ||
887 | mISDN_FsmChangeState(fi, ST_L2_7); | ||
888 | mISDN_FsmAddTimer(&l2->t203, l2->T203, EV_L2_T203, NULL, 3); | ||
889 | skb_trim(skb, 0); | ||
890 | l2up(l2, DL_ESTABLISH_IND, skb); | ||
891 | if (l2->tm) | ||
892 | l2_tei(l2, MDL_STATUS_UP_IND, 0); | ||
893 | } | ||
894 | |||
895 | static void | ||
896 | l2_send_UA(struct FsmInst *fi, int event, void *arg) | ||
897 | { | ||
898 | struct layer2 *l2 = fi->userdata; | ||
899 | struct sk_buff *skb = arg; | ||
900 | |||
901 | send_uframe(l2, skb, UA | get_PollFlag(l2, skb), RSP); | ||
902 | } | ||
903 | |||
904 | static void | ||
905 | l2_send_DM(struct FsmInst *fi, int event, void *arg) | ||
906 | { | ||
907 | struct layer2 *l2 = fi->userdata; | ||
908 | struct sk_buff *skb = arg; | ||
909 | |||
910 | send_uframe(l2, skb, DM | get_PollFlag(l2, skb), RSP); | ||
911 | } | ||
912 | |||
913 | static void | ||
914 | l2_restart_multi(struct FsmInst *fi, int event, void *arg) | ||
915 | { | ||
916 | struct layer2 *l2 = fi->userdata; | ||
917 | struct sk_buff *skb = arg; | ||
918 | int est = 0; | ||
919 | |||
920 | send_uframe(l2, skb, UA | get_PollFlag(l2, skb), RSP); | ||
921 | |||
922 | l2mgr(l2, MDL_ERROR_IND, (void *) 'F'); | ||
923 | |||
924 | if (l2->vs != l2->va) { | ||
925 | skb_queue_purge(&l2->i_queue); | ||
926 | est = 1; | ||
927 | } | ||
928 | |||
929 | clear_exception(l2); | ||
930 | l2->vs = 0; | ||
931 | l2->va = 0; | ||
932 | l2->vr = 0; | ||
933 | l2->sow = 0; | ||
934 | mISDN_FsmChangeState(fi, ST_L2_7); | ||
935 | stop_t200(l2, 3); | ||
936 | mISDN_FsmRestartTimer(&l2->t203, l2->T203, EV_L2_T203, NULL, 3); | ||
937 | |||
938 | if (est) | ||
939 | l2up_create(l2, DL_ESTABLISH_IND, 0, NULL); | ||
940 | /* mISDN_queue_data(&l2->inst, l2->inst.id | MSG_BROADCAST, | ||
941 | * MGR_SHORTSTATUS | INDICATION, SSTATUS_L2_ESTABLISHED, | ||
942 | * 0, NULL, 0); | ||
943 | */ | ||
944 | if (skb_queue_len(&l2->i_queue) && cansend(l2)) | ||
945 | mISDN_FsmEvent(fi, EV_L2_ACK_PULL, NULL); | ||
946 | } | ||
947 | |||
948 | static void | ||
949 | l2_stop_multi(struct FsmInst *fi, int event, void *arg) | ||
950 | { | ||
951 | struct layer2 *l2 = fi->userdata; | ||
952 | struct sk_buff *skb = arg; | ||
953 | |||
954 | mISDN_FsmChangeState(fi, ST_L2_4); | ||
955 | mISDN_FsmDelTimer(&l2->t203, 3); | ||
956 | stop_t200(l2, 4); | ||
957 | |||
958 | send_uframe(l2, skb, UA | get_PollFlag(l2, skb), RSP); | ||
959 | skb_queue_purge(&l2->i_queue); | ||
960 | freewin(l2); | ||
961 | lapb_dl_release_l2l3(l2, DL_RELEASE_IND); | ||
962 | if (l2->tm) | ||
963 | l2_tei(l2, MDL_STATUS_DOWN_IND, 0); | ||
964 | } | ||
965 | |||
966 | static void | ||
967 | l2_connected(struct FsmInst *fi, int event, void *arg) | ||
968 | { | ||
969 | struct layer2 *l2 = fi->userdata; | ||
970 | struct sk_buff *skb = arg; | ||
971 | int pr = -1; | ||
972 | |||
973 | if (!get_PollFlag(l2, skb)) { | ||
974 | l2_mdl_error_ua(fi, event, arg); | ||
975 | return; | ||
976 | } | ||
977 | dev_kfree_skb(skb); | ||
978 | if (test_and_clear_bit(FLG_PEND_REL, &l2->flag)) | ||
979 | l2_disconnect(fi, event, NULL); | ||
980 | if (test_and_clear_bit(FLG_L3_INIT, &l2->flag)) { | ||
981 | pr = DL_ESTABLISH_CNF; | ||
982 | } else if (l2->vs != l2->va) { | ||
983 | skb_queue_purge(&l2->i_queue); | ||
984 | pr = DL_ESTABLISH_IND; | ||
985 | } | ||
986 | stop_t200(l2, 5); | ||
987 | l2->vr = 0; | ||
988 | l2->vs = 0; | ||
989 | l2->va = 0; | ||
990 | l2->sow = 0; | ||
991 | mISDN_FsmChangeState(fi, ST_L2_7); | ||
992 | mISDN_FsmAddTimer(&l2->t203, l2->T203, EV_L2_T203, NULL, 4); | ||
993 | if (pr != -1) | ||
994 | l2up_create(l2, pr, 0, NULL); | ||
995 | |||
996 | if (skb_queue_len(&l2->i_queue) && cansend(l2)) | ||
997 | mISDN_FsmEvent(fi, EV_L2_ACK_PULL, NULL); | ||
998 | |||
999 | if (l2->tm) | ||
1000 | l2_tei(l2, MDL_STATUS_UP_IND, 0); | ||
1001 | } | ||
1002 | |||
1003 | static void | ||
1004 | l2_released(struct FsmInst *fi, int event, void *arg) | ||
1005 | { | ||
1006 | struct layer2 *l2 = fi->userdata; | ||
1007 | struct sk_buff *skb = arg; | ||
1008 | |||
1009 | if (!get_PollFlag(l2, skb)) { | ||
1010 | l2_mdl_error_ua(fi, event, arg); | ||
1011 | return; | ||
1012 | } | ||
1013 | dev_kfree_skb(skb); | ||
1014 | stop_t200(l2, 6); | ||
1015 | lapb_dl_release_l2l3(l2, DL_RELEASE_CNF); | ||
1016 | mISDN_FsmChangeState(fi, ST_L2_4); | ||
1017 | if (l2->tm) | ||
1018 | l2_tei(l2, MDL_STATUS_DOWN_IND, 0); | ||
1019 | } | ||
1020 | |||
1021 | static void | ||
1022 | l2_reestablish(struct FsmInst *fi, int event, void *arg) | ||
1023 | { | ||
1024 | struct layer2 *l2 = fi->userdata; | ||
1025 | struct sk_buff *skb = arg; | ||
1026 | |||
1027 | if (!get_PollFlagFree(l2, skb)) { | ||
1028 | establishlink(fi); | ||
1029 | test_and_set_bit(FLG_L3_INIT, &l2->flag); | ||
1030 | } | ||
1031 | } | ||
1032 | |||
1033 | static void | ||
1034 | l2_st5_dm_release(struct FsmInst *fi, int event, void *arg) | ||
1035 | { | ||
1036 | struct layer2 *l2 = fi->userdata; | ||
1037 | struct sk_buff *skb = arg; | ||
1038 | |||
1039 | if (get_PollFlagFree(l2, skb)) { | ||
1040 | stop_t200(l2, 7); | ||
1041 | if (!test_bit(FLG_L3_INIT, &l2->flag)) | ||
1042 | skb_queue_purge(&l2->i_queue); | ||
1043 | if (test_bit(FLG_LAPB, &l2->flag)) | ||
1044 | l2down_create(l2, PH_DEACTIVATE_REQ, | ||
1045 | l2_newid(l2), 0, NULL); | ||
1046 | st5_dl_release_l2l3(l2); | ||
1047 | mISDN_FsmChangeState(fi, ST_L2_4); | ||
1048 | if (l2->tm) | ||
1049 | l2_tei(l2, MDL_STATUS_DOWN_IND, 0); | ||
1050 | } | ||
1051 | } | ||
1052 | |||
1053 | static void | ||
1054 | l2_st6_dm_release(struct FsmInst *fi, int event, void *arg) | ||
1055 | { | ||
1056 | struct layer2 *l2 = fi->userdata; | ||
1057 | struct sk_buff *skb = arg; | ||
1058 | |||
1059 | if (get_PollFlagFree(l2, skb)) { | ||
1060 | stop_t200(l2, 8); | ||
1061 | lapb_dl_release_l2l3(l2, DL_RELEASE_CNF); | ||
1062 | mISDN_FsmChangeState(fi, ST_L2_4); | ||
1063 | if (l2->tm) | ||
1064 | l2_tei(l2, MDL_STATUS_DOWN_IND, 0); | ||
1065 | } | ||
1066 | } | ||
1067 | |||
1068 | void | ||
1069 | enquiry_cr(struct layer2 *l2, u_char typ, u_char cr, u_char pf) | ||
1070 | { | ||
1071 | struct sk_buff *skb; | ||
1072 | u_char tmp[MAX_L2HEADER_LEN]; | ||
1073 | int i; | ||
1074 | |||
1075 | i = sethdraddr(l2, tmp, cr); | ||
1076 | if (test_bit(FLG_MOD128, &l2->flag)) { | ||
1077 | tmp[i++] = typ; | ||
1078 | tmp[i++] = (l2->vr << 1) | (pf ? 1 : 0); | ||
1079 | } else | ||
1080 | tmp[i++] = (l2->vr << 5) | typ | (pf ? 0x10 : 0); | ||
1081 | skb = mI_alloc_skb(i, GFP_ATOMIC); | ||
1082 | if (!skb) { | ||
1083 | printk(KERN_WARNING | ||
1084 | "isdnl2 can't alloc sbbuff for enquiry_cr\n"); | ||
1085 | return; | ||
1086 | } | ||
1087 | memcpy(skb_put(skb, i), tmp, i); | ||
1088 | enqueue_super(l2, skb); | ||
1089 | } | ||
1090 | |||
1091 | inline void | ||
1092 | enquiry_response(struct layer2 *l2) | ||
1093 | { | ||
1094 | if (test_bit(FLG_OWN_BUSY, &l2->flag)) | ||
1095 | enquiry_cr(l2, RNR, RSP, 1); | ||
1096 | else | ||
1097 | enquiry_cr(l2, RR, RSP, 1); | ||
1098 | test_and_clear_bit(FLG_ACK_PEND, &l2->flag); | ||
1099 | } | ||
1100 | |||
1101 | inline void | ||
1102 | transmit_enquiry(struct layer2 *l2) | ||
1103 | { | ||
1104 | if (test_bit(FLG_OWN_BUSY, &l2->flag)) | ||
1105 | enquiry_cr(l2, RNR, CMD, 1); | ||
1106 | else | ||
1107 | enquiry_cr(l2, RR, CMD, 1); | ||
1108 | test_and_clear_bit(FLG_ACK_PEND, &l2->flag); | ||
1109 | start_t200(l2, 9); | ||
1110 | } | ||
1111 | |||
1112 | |||
1113 | static void | ||
1114 | nrerrorrecovery(struct FsmInst *fi) | ||
1115 | { | ||
1116 | struct layer2 *l2 = fi->userdata; | ||
1117 | |||
1118 | l2mgr(l2, MDL_ERROR_IND, (void *) 'J'); | ||
1119 | establishlink(fi); | ||
1120 | test_and_clear_bit(FLG_L3_INIT, &l2->flag); | ||
1121 | } | ||
1122 | |||
1123 | static void | ||
1124 | invoke_retransmission(struct layer2 *l2, unsigned int nr) | ||
1125 | { | ||
1126 | u_int p1; | ||
1127 | |||
1128 | if (l2->vs != nr) { | ||
1129 | while (l2->vs != nr) { | ||
1130 | (l2->vs)--; | ||
1131 | if (test_bit(FLG_MOD128, &l2->flag)) { | ||
1132 | l2->vs %= 128; | ||
1133 | p1 = (l2->vs - l2->va) % 128; | ||
1134 | } else { | ||
1135 | l2->vs %= 8; | ||
1136 | p1 = (l2->vs - l2->va) % 8; | ||
1137 | } | ||
1138 | p1 = (p1 + l2->sow) % l2->window; | ||
1139 | if (l2->windowar[p1]) | ||
1140 | skb_queue_head(&l2->i_queue, l2->windowar[p1]); | ||
1141 | else | ||
1142 | printk(KERN_WARNING | ||
1143 | "%s: windowar[%d] is NULL\n", | ||
1144 | __func__, p1); | ||
1145 | l2->windowar[p1] = NULL; | ||
1146 | } | ||
1147 | mISDN_FsmEvent(&l2->l2m, EV_L2_ACK_PULL, NULL); | ||
1148 | } | ||
1149 | } | ||
1150 | |||
1151 | static void | ||
1152 | l2_st7_got_super(struct FsmInst *fi, int event, void *arg) | ||
1153 | { | ||
1154 | struct layer2 *l2 = fi->userdata; | ||
1155 | struct sk_buff *skb = arg; | ||
1156 | int PollFlag, rsp, typ = RR; | ||
1157 | unsigned int nr; | ||
1158 | |||
1159 | rsp = *skb->data & 0x2; | ||
1160 | if (test_bit(FLG_ORIG, &l2->flag)) | ||
1161 | rsp = !rsp; | ||
1162 | |||
1163 | skb_pull(skb, l2addrsize(l2)); | ||
1164 | if (IsRNR(skb->data, l2)) { | ||
1165 | set_peer_busy(l2); | ||
1166 | typ = RNR; | ||
1167 | } else | ||
1168 | clear_peer_busy(l2); | ||
1169 | if (IsREJ(skb->data, l2)) | ||
1170 | typ = REJ; | ||
1171 | |||
1172 | if (test_bit(FLG_MOD128, &l2->flag)) { | ||
1173 | PollFlag = (skb->data[1] & 0x1) == 0x1; | ||
1174 | nr = skb->data[1] >> 1; | ||
1175 | } else { | ||
1176 | PollFlag = (skb->data[0] & 0x10); | ||
1177 | nr = (skb->data[0] >> 5) & 0x7; | ||
1178 | } | ||
1179 | dev_kfree_skb(skb); | ||
1180 | |||
1181 | if (PollFlag) { | ||
1182 | if (rsp) | ||
1183 | l2mgr(l2, MDL_ERROR_IND, (void *) 'A'); | ||
1184 | else | ||
1185 | enquiry_response(l2); | ||
1186 | } | ||
1187 | if (legalnr(l2, nr)) { | ||
1188 | if (typ == REJ) { | ||
1189 | setva(l2, nr); | ||
1190 | invoke_retransmission(l2, nr); | ||
1191 | stop_t200(l2, 10); | ||
1192 | if (mISDN_FsmAddTimer(&l2->t203, l2->T203, | ||
1193 | EV_L2_T203, NULL, 6)) | ||
1194 | l2m_debug(&l2->l2m, "Restart T203 ST7 REJ"); | ||
1195 | } else if ((nr == l2->vs) && (typ == RR)) { | ||
1196 | setva(l2, nr); | ||
1197 | stop_t200(l2, 11); | ||
1198 | mISDN_FsmRestartTimer(&l2->t203, l2->T203, | ||
1199 | EV_L2_T203, NULL, 7); | ||
1200 | } else if ((l2->va != nr) || (typ == RNR)) { | ||
1201 | setva(l2, nr); | ||
1202 | if (typ != RR) | ||
1203 | mISDN_FsmDelTimer(&l2->t203, 9); | ||
1204 | restart_t200(l2, 12); | ||
1205 | } | ||
1206 | if (skb_queue_len(&l2->i_queue) && (typ == RR)) | ||
1207 | mISDN_FsmEvent(fi, EV_L2_ACK_PULL, NULL); | ||
1208 | } else | ||
1209 | nrerrorrecovery(fi); | ||
1210 | } | ||
1211 | |||
1212 | static void | ||
1213 | l2_feed_i_if_reest(struct FsmInst *fi, int event, void *arg) | ||
1214 | { | ||
1215 | struct layer2 *l2 = fi->userdata; | ||
1216 | struct sk_buff *skb = arg; | ||
1217 | |||
1218 | if (!test_bit(FLG_L3_INIT, &l2->flag)) | ||
1219 | skb_queue_tail(&l2->i_queue, skb); | ||
1220 | else | ||
1221 | dev_kfree_skb(skb); | ||
1222 | } | ||
1223 | |||
1224 | static void | ||
1225 | l2_feed_i_pull(struct FsmInst *fi, int event, void *arg) | ||
1226 | { | ||
1227 | struct layer2 *l2 = fi->userdata; | ||
1228 | struct sk_buff *skb = arg; | ||
1229 | |||
1230 | skb_queue_tail(&l2->i_queue, skb); | ||
1231 | mISDN_FsmEvent(fi, EV_L2_ACK_PULL, NULL); | ||
1232 | } | ||
1233 | |||
1234 | static void | ||
1235 | l2_feed_iqueue(struct FsmInst *fi, int event, void *arg) | ||
1236 | { | ||
1237 | struct layer2 *l2 = fi->userdata; | ||
1238 | struct sk_buff *skb = arg; | ||
1239 | |||
1240 | skb_queue_tail(&l2->i_queue, skb); | ||
1241 | } | ||
1242 | |||
1243 | static void | ||
1244 | l2_got_iframe(struct FsmInst *fi, int event, void *arg) | ||
1245 | { | ||
1246 | struct layer2 *l2 = fi->userdata; | ||
1247 | struct sk_buff *skb = arg; | ||
1248 | int PollFlag, i; | ||
1249 | u_int ns, nr; | ||
1250 | |||
1251 | i = l2addrsize(l2); | ||
1252 | if (test_bit(FLG_MOD128, &l2->flag)) { | ||
1253 | PollFlag = ((skb->data[i + 1] & 0x1) == 0x1); | ||
1254 | ns = skb->data[i] >> 1; | ||
1255 | nr = (skb->data[i + 1] >> 1) & 0x7f; | ||
1256 | } else { | ||
1257 | PollFlag = (skb->data[i] & 0x10); | ||
1258 | ns = (skb->data[i] >> 1) & 0x7; | ||
1259 | nr = (skb->data[i] >> 5) & 0x7; | ||
1260 | } | ||
1261 | if (test_bit(FLG_OWN_BUSY, &l2->flag)) { | ||
1262 | dev_kfree_skb(skb); | ||
1263 | if (PollFlag) | ||
1264 | enquiry_response(l2); | ||
1265 | } else { | ||
1266 | if (l2->vr == ns) { | ||
1267 | l2->vr++; | ||
1268 | if (test_bit(FLG_MOD128, &l2->flag)) | ||
1269 | l2->vr %= 128; | ||
1270 | else | ||
1271 | l2->vr %= 8; | ||
1272 | test_and_clear_bit(FLG_REJEXC, &l2->flag); | ||
1273 | if (PollFlag) | ||
1274 | enquiry_response(l2); | ||
1275 | else | ||
1276 | test_and_set_bit(FLG_ACK_PEND, &l2->flag); | ||
1277 | skb_pull(skb, l2headersize(l2, 0)); | ||
1278 | l2up(l2, DL_DATA_IND, skb); | ||
1279 | } else { | ||
1280 | /* n(s)!=v(r) */ | ||
1281 | dev_kfree_skb(skb); | ||
1282 | if (test_and_set_bit(FLG_REJEXC, &l2->flag)) { | ||
1283 | if (PollFlag) | ||
1284 | enquiry_response(l2); | ||
1285 | } else { | ||
1286 | enquiry_cr(l2, REJ, RSP, PollFlag); | ||
1287 | test_and_clear_bit(FLG_ACK_PEND, &l2->flag); | ||
1288 | } | ||
1289 | } | ||
1290 | } | ||
1291 | if (legalnr(l2, nr)) { | ||
1292 | if (!test_bit(FLG_PEER_BUSY, &l2->flag) && | ||
1293 | (fi->state == ST_L2_7)) { | ||
1294 | if (nr == l2->vs) { | ||
1295 | stop_t200(l2, 13); | ||
1296 | mISDN_FsmRestartTimer(&l2->t203, l2->T203, | ||
1297 | EV_L2_T203, NULL, 7); | ||
1298 | } else if (nr != l2->va) | ||
1299 | restart_t200(l2, 14); | ||
1300 | } | ||
1301 | setva(l2, nr); | ||
1302 | } else { | ||
1303 | nrerrorrecovery(fi); | ||
1304 | return; | ||
1305 | } | ||
1306 | if (skb_queue_len(&l2->i_queue) && (fi->state == ST_L2_7)) | ||
1307 | mISDN_FsmEvent(fi, EV_L2_ACK_PULL, NULL); | ||
1308 | if (test_and_clear_bit(FLG_ACK_PEND, &l2->flag)) | ||
1309 | enquiry_cr(l2, RR, RSP, 0); | ||
1310 | } | ||
1311 | |||
1312 | static void | ||
1313 | l2_got_tei(struct FsmInst *fi, int event, void *arg) | ||
1314 | { | ||
1315 | struct layer2 *l2 = fi->userdata; | ||
1316 | u_int info; | ||
1317 | |||
1318 | l2->tei = (signed char)(long)arg; | ||
1319 | set_channel_address(&l2->ch, l2->sapi, l2->tei); | ||
1320 | info = DL_INFO_L2_CONNECT; | ||
1321 | l2up_create(l2, DL_INFORMATION_IND, sizeof(info), &info); | ||
1322 | if (fi->state == ST_L2_3) { | ||
1323 | establishlink(fi); | ||
1324 | test_and_set_bit(FLG_L3_INIT, &l2->flag); | ||
1325 | } else | ||
1326 | mISDN_FsmChangeState(fi, ST_L2_4); | ||
1327 | if (skb_queue_len(&l2->ui_queue)) | ||
1328 | tx_ui(l2); | ||
1329 | } | ||
1330 | |||
1331 | static void | ||
1332 | l2_st5_tout_200(struct FsmInst *fi, int event, void *arg) | ||
1333 | { | ||
1334 | struct layer2 *l2 = fi->userdata; | ||
1335 | |||
1336 | if (test_bit(FLG_LAPD, &l2->flag) && | ||
1337 | test_bit(FLG_DCHAN_BUSY, &l2->flag)) { | ||
1338 | mISDN_FsmAddTimer(&l2->t200, l2->T200, EV_L2_T200, NULL, 9); | ||
1339 | } else if (l2->rc == l2->N200) { | ||
1340 | mISDN_FsmChangeState(fi, ST_L2_4); | ||
1341 | test_and_clear_bit(FLG_T200_RUN, &l2->flag); | ||
1342 | skb_queue_purge(&l2->i_queue); | ||
1343 | l2mgr(l2, MDL_ERROR_IND, (void *) 'G'); | ||
1344 | if (test_bit(FLG_LAPB, &l2->flag)) | ||
1345 | l2down_create(l2, PH_DEACTIVATE_REQ, | ||
1346 | l2_newid(l2), 0, NULL); | ||
1347 | st5_dl_release_l2l3(l2); | ||
1348 | if (l2->tm) | ||
1349 | l2_tei(l2, MDL_STATUS_DOWN_IND, 0); | ||
1350 | } else { | ||
1351 | l2->rc++; | ||
1352 | mISDN_FsmAddTimer(&l2->t200, l2->T200, EV_L2_T200, NULL, 9); | ||
1353 | send_uframe(l2, NULL, (test_bit(FLG_MOD128, &l2->flag) ? | ||
1354 | SABME : SABM) | 0x10, CMD); | ||
1355 | } | ||
1356 | } | ||
1357 | |||
1358 | static void | ||
1359 | l2_st6_tout_200(struct FsmInst *fi, int event, void *arg) | ||
1360 | { | ||
1361 | struct layer2 *l2 = fi->userdata; | ||
1362 | |||
1363 | if (test_bit(FLG_LAPD, &l2->flag) && | ||
1364 | test_bit(FLG_DCHAN_BUSY, &l2->flag)) { | ||
1365 | mISDN_FsmAddTimer(&l2->t200, l2->T200, EV_L2_T200, NULL, 9); | ||
1366 | } else if (l2->rc == l2->N200) { | ||
1367 | mISDN_FsmChangeState(fi, ST_L2_4); | ||
1368 | test_and_clear_bit(FLG_T200_RUN, &l2->flag); | ||
1369 | l2mgr(l2, MDL_ERROR_IND, (void *) 'H'); | ||
1370 | lapb_dl_release_l2l3(l2, DL_RELEASE_CNF); | ||
1371 | if (l2->tm) | ||
1372 | l2_tei(l2, MDL_STATUS_DOWN_IND, 0); | ||
1373 | } else { | ||
1374 | l2->rc++; | ||
1375 | mISDN_FsmAddTimer(&l2->t200, l2->T200, EV_L2_T200, | ||
1376 | NULL, 9); | ||
1377 | send_uframe(l2, NULL, DISC | 0x10, CMD); | ||
1378 | } | ||
1379 | } | ||
1380 | |||
1381 | static void | ||
1382 | l2_st7_tout_200(struct FsmInst *fi, int event, void *arg) | ||
1383 | { | ||
1384 | struct layer2 *l2 = fi->userdata; | ||
1385 | |||
1386 | if (test_bit(FLG_LAPD, &l2->flag) && | ||
1387 | test_bit(FLG_DCHAN_BUSY, &l2->flag)) { | ||
1388 | mISDN_FsmAddTimer(&l2->t200, l2->T200, EV_L2_T200, NULL, 9); | ||
1389 | return; | ||
1390 | } | ||
1391 | test_and_clear_bit(FLG_T200_RUN, &l2->flag); | ||
1392 | l2->rc = 0; | ||
1393 | mISDN_FsmChangeState(fi, ST_L2_8); | ||
1394 | transmit_enquiry(l2); | ||
1395 | l2->rc++; | ||
1396 | } | ||
1397 | |||
1398 | static void | ||
1399 | l2_st8_tout_200(struct FsmInst *fi, int event, void *arg) | ||
1400 | { | ||
1401 | struct layer2 *l2 = fi->userdata; | ||
1402 | |||
1403 | if (test_bit(FLG_LAPD, &l2->flag) && | ||
1404 | test_bit(FLG_DCHAN_BUSY, &l2->flag)) { | ||
1405 | mISDN_FsmAddTimer(&l2->t200, l2->T200, EV_L2_T200, NULL, 9); | ||
1406 | return; | ||
1407 | } | ||
1408 | test_and_clear_bit(FLG_T200_RUN, &l2->flag); | ||
1409 | if (l2->rc == l2->N200) { | ||
1410 | l2mgr(l2, MDL_ERROR_IND, (void *) 'I'); | ||
1411 | establishlink(fi); | ||
1412 | test_and_clear_bit(FLG_L3_INIT, &l2->flag); | ||
1413 | } else { | ||
1414 | transmit_enquiry(l2); | ||
1415 | l2->rc++; | ||
1416 | } | ||
1417 | } | ||
1418 | |||
1419 | static void | ||
1420 | l2_st7_tout_203(struct FsmInst *fi, int event, void *arg) | ||
1421 | { | ||
1422 | struct layer2 *l2 = fi->userdata; | ||
1423 | |||
1424 | if (test_bit(FLG_LAPD, &l2->flag) && | ||
1425 | test_bit(FLG_DCHAN_BUSY, &l2->flag)) { | ||
1426 | mISDN_FsmAddTimer(&l2->t203, l2->T203, EV_L2_T203, NULL, 9); | ||
1427 | return; | ||
1428 | } | ||
1429 | mISDN_FsmChangeState(fi, ST_L2_8); | ||
1430 | transmit_enquiry(l2); | ||
1431 | l2->rc = 0; | ||
1432 | } | ||
1433 | |||
1434 | static void | ||
1435 | l2_pull_iqueue(struct FsmInst *fi, int event, void *arg) | ||
1436 | { | ||
1437 | struct layer2 *l2 = fi->userdata; | ||
1438 | struct sk_buff *skb, *nskb, *oskb; | ||
1439 | u_char header[MAX_L2HEADER_LEN]; | ||
1440 | u_int i, p1; | ||
1441 | |||
1442 | if (!cansend(l2)) | ||
1443 | return; | ||
1444 | |||
1445 | skb = skb_dequeue(&l2->i_queue); | ||
1446 | if (!skb) | ||
1447 | return; | ||
1448 | |||
1449 | if (test_bit(FLG_MOD128, &l2->flag)) | ||
1450 | p1 = (l2->vs - l2->va) % 128; | ||
1451 | else | ||
1452 | p1 = (l2->vs - l2->va) % 8; | ||
1453 | p1 = (p1 + l2->sow) % l2->window; | ||
1454 | if (l2->windowar[p1]) { | ||
1455 | printk(KERN_WARNING "isdnl2 try overwrite ack queue entry %d\n", | ||
1456 | p1); | ||
1457 | dev_kfree_skb(l2->windowar[p1]); | ||
1458 | } | ||
1459 | l2->windowar[p1] = skb; | ||
1460 | i = sethdraddr(l2, header, CMD); | ||
1461 | if (test_bit(FLG_MOD128, &l2->flag)) { | ||
1462 | header[i++] = l2->vs << 1; | ||
1463 | header[i++] = l2->vr << 1; | ||
1464 | l2->vs = (l2->vs + 1) % 128; | ||
1465 | } else { | ||
1466 | header[i++] = (l2->vr << 5) | (l2->vs << 1); | ||
1467 | l2->vs = (l2->vs + 1) % 8; | ||
1468 | } | ||
1469 | |||
1470 | nskb = skb_clone(skb, GFP_ATOMIC); | ||
1471 | p1 = skb_headroom(nskb); | ||
1472 | if (p1 >= i) | ||
1473 | memcpy(skb_push(nskb, i), header, i); | ||
1474 | else { | ||
1475 | printk(KERN_WARNING | ||
1476 | "isdnl2 pull_iqueue skb header(%d/%d) too short\n", i, p1); | ||
1477 | oskb = nskb; | ||
1478 | nskb = mI_alloc_skb(oskb->len + i, GFP_ATOMIC); | ||
1479 | if (!nskb) { | ||
1480 | dev_kfree_skb(oskb); | ||
1481 | printk(KERN_WARNING "%s: no skb mem\n", __func__); | ||
1482 | return; | ||
1483 | } | ||
1484 | memcpy(skb_put(nskb, i), header, i); | ||
1485 | memcpy(skb_put(nskb, oskb->len), oskb->data, oskb->len); | ||
1486 | dev_kfree_skb(oskb); | ||
1487 | } | ||
1488 | l2down(l2, PH_DATA_REQ, l2_newid(l2), nskb); | ||
1489 | test_and_clear_bit(FLG_ACK_PEND, &l2->flag); | ||
1490 | if (!test_and_set_bit(FLG_T200_RUN, &l2->flag)) { | ||
1491 | mISDN_FsmDelTimer(&l2->t203, 13); | ||
1492 | mISDN_FsmAddTimer(&l2->t200, l2->T200, EV_L2_T200, NULL, 11); | ||
1493 | } | ||
1494 | } | ||
1495 | |||
1496 | static void | ||
1497 | l2_st8_got_super(struct FsmInst *fi, int event, void *arg) | ||
1498 | { | ||
1499 | struct layer2 *l2 = fi->userdata; | ||
1500 | struct sk_buff *skb = arg; | ||
1501 | int PollFlag, rsp, rnr = 0; | ||
1502 | unsigned int nr; | ||
1503 | |||
1504 | rsp = *skb->data & 0x2; | ||
1505 | if (test_bit(FLG_ORIG, &l2->flag)) | ||
1506 | rsp = !rsp; | ||
1507 | |||
1508 | skb_pull(skb, l2addrsize(l2)); | ||
1509 | |||
1510 | if (IsRNR(skb->data, l2)) { | ||
1511 | set_peer_busy(l2); | ||
1512 | rnr = 1; | ||
1513 | } else | ||
1514 | clear_peer_busy(l2); | ||
1515 | |||
1516 | if (test_bit(FLG_MOD128, &l2->flag)) { | ||
1517 | PollFlag = (skb->data[1] & 0x1) == 0x1; | ||
1518 | nr = skb->data[1] >> 1; | ||
1519 | } else { | ||
1520 | PollFlag = (skb->data[0] & 0x10); | ||
1521 | nr = (skb->data[0] >> 5) & 0x7; | ||
1522 | } | ||
1523 | dev_kfree_skb(skb); | ||
1524 | if (rsp && PollFlag) { | ||
1525 | if (legalnr(l2, nr)) { | ||
1526 | if (rnr) { | ||
1527 | restart_t200(l2, 15); | ||
1528 | } else { | ||
1529 | stop_t200(l2, 16); | ||
1530 | mISDN_FsmAddTimer(&l2->t203, l2->T203, | ||
1531 | EV_L2_T203, NULL, 5); | ||
1532 | setva(l2, nr); | ||
1533 | } | ||
1534 | invoke_retransmission(l2, nr); | ||
1535 | mISDN_FsmChangeState(fi, ST_L2_7); | ||
1536 | if (skb_queue_len(&l2->i_queue) && cansend(l2)) | ||
1537 | mISDN_FsmEvent(fi, EV_L2_ACK_PULL, NULL); | ||
1538 | } else | ||
1539 | nrerrorrecovery(fi); | ||
1540 | } else { | ||
1541 | if (!rsp && PollFlag) | ||
1542 | enquiry_response(l2); | ||
1543 | if (legalnr(l2, nr)) | ||
1544 | setva(l2, nr); | ||
1545 | else | ||
1546 | nrerrorrecovery(fi); | ||
1547 | } | ||
1548 | } | ||
1549 | |||
1550 | static void | ||
1551 | l2_got_FRMR(struct FsmInst *fi, int event, void *arg) | ||
1552 | { | ||
1553 | struct layer2 *l2 = fi->userdata; | ||
1554 | struct sk_buff *skb = arg; | ||
1555 | |||
1556 | skb_pull(skb, l2addrsize(l2) + 1); | ||
1557 | |||
1558 | if (!(skb->data[0] & 1) || ((skb->data[0] & 3) == 1) || /* I or S */ | ||
1559 | (IsUA(skb->data) && (fi->state == ST_L2_7))) { | ||
1560 | l2mgr(l2, MDL_ERROR_IND, (void *) 'K'); | ||
1561 | establishlink(fi); | ||
1562 | test_and_clear_bit(FLG_L3_INIT, &l2->flag); | ||
1563 | } | ||
1564 | dev_kfree_skb(skb); | ||
1565 | } | ||
1566 | |||
1567 | static void | ||
1568 | l2_st24_tei_remove(struct FsmInst *fi, int event, void *arg) | ||
1569 | { | ||
1570 | struct layer2 *l2 = fi->userdata; | ||
1571 | |||
1572 | skb_queue_purge(&l2->ui_queue); | ||
1573 | l2->tei = GROUP_TEI; | ||
1574 | mISDN_FsmChangeState(fi, ST_L2_1); | ||
1575 | } | ||
1576 | |||
1577 | static void | ||
1578 | l2_st3_tei_remove(struct FsmInst *fi, int event, void *arg) | ||
1579 | { | ||
1580 | struct layer2 *l2 = fi->userdata; | ||
1581 | |||
1582 | skb_queue_purge(&l2->ui_queue); | ||
1583 | l2->tei = GROUP_TEI; | ||
1584 | l2up_create(l2, DL_RELEASE_IND, 0, NULL); | ||
1585 | mISDN_FsmChangeState(fi, ST_L2_1); | ||
1586 | } | ||
1587 | |||
1588 | static void | ||
1589 | l2_st5_tei_remove(struct FsmInst *fi, int event, void *arg) | ||
1590 | { | ||
1591 | struct layer2 *l2 = fi->userdata; | ||
1592 | |||
1593 | skb_queue_purge(&l2->i_queue); | ||
1594 | skb_queue_purge(&l2->ui_queue); | ||
1595 | freewin(l2); | ||
1596 | l2->tei = GROUP_TEI; | ||
1597 | stop_t200(l2, 17); | ||
1598 | st5_dl_release_l2l3(l2); | ||
1599 | mISDN_FsmChangeState(fi, ST_L2_1); | ||
1600 | } | ||
1601 | |||
1602 | static void | ||
1603 | l2_st6_tei_remove(struct FsmInst *fi, int event, void *arg) | ||
1604 | { | ||
1605 | struct layer2 *l2 = fi->userdata; | ||
1606 | |||
1607 | skb_queue_purge(&l2->ui_queue); | ||
1608 | l2->tei = GROUP_TEI; | ||
1609 | stop_t200(l2, 18); | ||
1610 | l2up_create(l2, DL_RELEASE_IND, 0, NULL); | ||
1611 | mISDN_FsmChangeState(fi, ST_L2_1); | ||
1612 | } | ||
1613 | |||
1614 | static void | ||
1615 | l2_tei_remove(struct FsmInst *fi, int event, void *arg) | ||
1616 | { | ||
1617 | struct layer2 *l2 = fi->userdata; | ||
1618 | |||
1619 | skb_queue_purge(&l2->i_queue); | ||
1620 | skb_queue_purge(&l2->ui_queue); | ||
1621 | freewin(l2); | ||
1622 | l2->tei = GROUP_TEI; | ||
1623 | stop_t200(l2, 17); | ||
1624 | mISDN_FsmDelTimer(&l2->t203, 19); | ||
1625 | l2up_create(l2, DL_RELEASE_IND, 0, NULL); | ||
1626 | /* mISDN_queue_data(&l2->inst, l2->inst.id | MSG_BROADCAST, | ||
1627 | * MGR_SHORTSTATUS_IND, SSTATUS_L2_RELEASED, | ||
1628 | * 0, NULL, 0); | ||
1629 | */ | ||
1630 | mISDN_FsmChangeState(fi, ST_L2_1); | ||
1631 | } | ||
1632 | |||
1633 | static void | ||
1634 | l2_st14_persistant_da(struct FsmInst *fi, int event, void *arg) | ||
1635 | { | ||
1636 | struct layer2 *l2 = fi->userdata; | ||
1637 | struct sk_buff *skb = arg; | ||
1638 | |||
1639 | skb_queue_purge(&l2->i_queue); | ||
1640 | skb_queue_purge(&l2->ui_queue); | ||
1641 | if (test_and_clear_bit(FLG_ESTAB_PEND, &l2->flag)) | ||
1642 | l2up(l2, DL_RELEASE_IND, skb); | ||
1643 | else | ||
1644 | dev_kfree_skb(skb); | ||
1645 | } | ||
1646 | |||
1647 | static void | ||
1648 | l2_st5_persistant_da(struct FsmInst *fi, int event, void *arg) | ||
1649 | { | ||
1650 | struct layer2 *l2 = fi->userdata; | ||
1651 | struct sk_buff *skb = arg; | ||
1652 | |||
1653 | skb_queue_purge(&l2->i_queue); | ||
1654 | skb_queue_purge(&l2->ui_queue); | ||
1655 | freewin(l2); | ||
1656 | stop_t200(l2, 19); | ||
1657 | st5_dl_release_l2l3(l2); | ||
1658 | mISDN_FsmChangeState(fi, ST_L2_4); | ||
1659 | if (l2->tm) | ||
1660 | l2_tei(l2, MDL_STATUS_DOWN_IND, 0); | ||
1661 | dev_kfree_skb(skb); | ||
1662 | } | ||
1663 | |||
1664 | static void | ||
1665 | l2_st6_persistant_da(struct FsmInst *fi, int event, void *arg) | ||
1666 | { | ||
1667 | struct layer2 *l2 = fi->userdata; | ||
1668 | struct sk_buff *skb = arg; | ||
1669 | |||
1670 | skb_queue_purge(&l2->ui_queue); | ||
1671 | stop_t200(l2, 20); | ||
1672 | l2up(l2, DL_RELEASE_CNF, skb); | ||
1673 | mISDN_FsmChangeState(fi, ST_L2_4); | ||
1674 | if (l2->tm) | ||
1675 | l2_tei(l2, MDL_STATUS_DOWN_IND, 0); | ||
1676 | } | ||
1677 | |||
1678 | static void | ||
1679 | l2_persistant_da(struct FsmInst *fi, int event, void *arg) | ||
1680 | { | ||
1681 | struct layer2 *l2 = fi->userdata; | ||
1682 | struct sk_buff *skb = arg; | ||
1683 | |||
1684 | skb_queue_purge(&l2->i_queue); | ||
1685 | skb_queue_purge(&l2->ui_queue); | ||
1686 | freewin(l2); | ||
1687 | stop_t200(l2, 19); | ||
1688 | mISDN_FsmDelTimer(&l2->t203, 19); | ||
1689 | l2up(l2, DL_RELEASE_IND, skb); | ||
1690 | mISDN_FsmChangeState(fi, ST_L2_4); | ||
1691 | if (l2->tm) | ||
1692 | l2_tei(l2, MDL_STATUS_DOWN_IND, 0); | ||
1693 | } | ||
1694 | |||
1695 | static void | ||
1696 | l2_set_own_busy(struct FsmInst *fi, int event, void *arg) | ||
1697 | { | ||
1698 | struct layer2 *l2 = fi->userdata; | ||
1699 | struct sk_buff *skb = arg; | ||
1700 | |||
1701 | if (!test_and_set_bit(FLG_OWN_BUSY, &l2->flag)) { | ||
1702 | enquiry_cr(l2, RNR, RSP, 0); | ||
1703 | test_and_clear_bit(FLG_ACK_PEND, &l2->flag); | ||
1704 | } | ||
1705 | if (skb) | ||
1706 | dev_kfree_skb(skb); | ||
1707 | } | ||
1708 | |||
1709 | static void | ||
1710 | l2_clear_own_busy(struct FsmInst *fi, int event, void *arg) | ||
1711 | { | ||
1712 | struct layer2 *l2 = fi->userdata; | ||
1713 | struct sk_buff *skb = arg; | ||
1714 | |||
1715 | if (!test_and_clear_bit(FLG_OWN_BUSY, &l2->flag)) { | ||
1716 | enquiry_cr(l2, RR, RSP, 0); | ||
1717 | test_and_clear_bit(FLG_ACK_PEND, &l2->flag); | ||
1718 | } | ||
1719 | if (skb) | ||
1720 | dev_kfree_skb(skb); | ||
1721 | } | ||
1722 | |||
1723 | static void | ||
1724 | l2_frame_error(struct FsmInst *fi, int event, void *arg) | ||
1725 | { | ||
1726 | struct layer2 *l2 = fi->userdata; | ||
1727 | |||
1728 | l2mgr(l2, MDL_ERROR_IND, arg); | ||
1729 | } | ||
1730 | |||
1731 | static void | ||
1732 | l2_frame_error_reest(struct FsmInst *fi, int event, void *arg) | ||
1733 | { | ||
1734 | struct layer2 *l2 = fi->userdata; | ||
1735 | |||
1736 | l2mgr(l2, MDL_ERROR_IND, arg); | ||
1737 | establishlink(fi); | ||
1738 | test_and_clear_bit(FLG_L3_INIT, &l2->flag); | ||
1739 | } | ||
1740 | |||
1741 | static struct FsmNode L2FnList[] = | ||
1742 | { | ||
1743 | {ST_L2_1, EV_L2_DL_ESTABLISH_REQ, l2_mdl_assign}, | ||
1744 | {ST_L2_2, EV_L2_DL_ESTABLISH_REQ, l2_go_st3}, | ||
1745 | {ST_L2_4, EV_L2_DL_ESTABLISH_REQ, l2_establish}, | ||
1746 | {ST_L2_5, EV_L2_DL_ESTABLISH_REQ, l2_discard_i_setl3}, | ||
1747 | {ST_L2_7, EV_L2_DL_ESTABLISH_REQ, l2_l3_reestablish}, | ||
1748 | {ST_L2_8, EV_L2_DL_ESTABLISH_REQ, l2_l3_reestablish}, | ||
1749 | {ST_L2_4, EV_L2_DL_RELEASE_REQ, l2_release}, | ||
1750 | {ST_L2_5, EV_L2_DL_RELEASE_REQ, l2_pend_rel}, | ||
1751 | {ST_L2_7, EV_L2_DL_RELEASE_REQ, l2_disconnect}, | ||
1752 | {ST_L2_8, EV_L2_DL_RELEASE_REQ, l2_disconnect}, | ||
1753 | {ST_L2_5, EV_L2_DL_DATA, l2_feed_i_if_reest}, | ||
1754 | {ST_L2_7, EV_L2_DL_DATA, l2_feed_i_pull}, | ||
1755 | {ST_L2_8, EV_L2_DL_DATA, l2_feed_iqueue}, | ||
1756 | {ST_L2_1, EV_L2_DL_UNITDATA, l2_queue_ui_assign}, | ||
1757 | {ST_L2_2, EV_L2_DL_UNITDATA, l2_queue_ui}, | ||
1758 | {ST_L2_3, EV_L2_DL_UNITDATA, l2_queue_ui}, | ||
1759 | {ST_L2_4, EV_L2_DL_UNITDATA, l2_send_ui}, | ||
1760 | {ST_L2_5, EV_L2_DL_UNITDATA, l2_send_ui}, | ||
1761 | {ST_L2_6, EV_L2_DL_UNITDATA, l2_send_ui}, | ||
1762 | {ST_L2_7, EV_L2_DL_UNITDATA, l2_send_ui}, | ||
1763 | {ST_L2_8, EV_L2_DL_UNITDATA, l2_send_ui}, | ||
1764 | {ST_L2_1, EV_L2_MDL_ASSIGN, l2_got_tei}, | ||
1765 | {ST_L2_2, EV_L2_MDL_ASSIGN, l2_got_tei}, | ||
1766 | {ST_L2_3, EV_L2_MDL_ASSIGN, l2_got_tei}, | ||
1767 | {ST_L2_2, EV_L2_MDL_ERROR, l2_st24_tei_remove}, | ||
1768 | {ST_L2_3, EV_L2_MDL_ERROR, l2_st3_tei_remove}, | ||
1769 | {ST_L2_4, EV_L2_MDL_REMOVE, l2_st24_tei_remove}, | ||
1770 | {ST_L2_5, EV_L2_MDL_REMOVE, l2_st5_tei_remove}, | ||
1771 | {ST_L2_6, EV_L2_MDL_REMOVE, l2_st6_tei_remove}, | ||
1772 | {ST_L2_7, EV_L2_MDL_REMOVE, l2_tei_remove}, | ||
1773 | {ST_L2_8, EV_L2_MDL_REMOVE, l2_tei_remove}, | ||
1774 | {ST_L2_4, EV_L2_SABME, l2_start_multi}, | ||
1775 | {ST_L2_5, EV_L2_SABME, l2_send_UA}, | ||
1776 | {ST_L2_6, EV_L2_SABME, l2_send_DM}, | ||
1777 | {ST_L2_7, EV_L2_SABME, l2_restart_multi}, | ||
1778 | {ST_L2_8, EV_L2_SABME, l2_restart_multi}, | ||
1779 | {ST_L2_4, EV_L2_DISC, l2_send_DM}, | ||
1780 | {ST_L2_5, EV_L2_DISC, l2_send_DM}, | ||
1781 | {ST_L2_6, EV_L2_DISC, l2_send_UA}, | ||
1782 | {ST_L2_7, EV_L2_DISC, l2_stop_multi}, | ||
1783 | {ST_L2_8, EV_L2_DISC, l2_stop_multi}, | ||
1784 | {ST_L2_4, EV_L2_UA, l2_mdl_error_ua}, | ||
1785 | {ST_L2_5, EV_L2_UA, l2_connected}, | ||
1786 | {ST_L2_6, EV_L2_UA, l2_released}, | ||
1787 | {ST_L2_7, EV_L2_UA, l2_mdl_error_ua}, | ||
1788 | {ST_L2_8, EV_L2_UA, l2_mdl_error_ua}, | ||
1789 | {ST_L2_4, EV_L2_DM, l2_reestablish}, | ||
1790 | {ST_L2_5, EV_L2_DM, l2_st5_dm_release}, | ||
1791 | {ST_L2_6, EV_L2_DM, l2_st6_dm_release}, | ||
1792 | {ST_L2_7, EV_L2_DM, l2_mdl_error_dm}, | ||
1793 | {ST_L2_8, EV_L2_DM, l2_st8_mdl_error_dm}, | ||
1794 | {ST_L2_1, EV_L2_UI, l2_got_ui}, | ||
1795 | {ST_L2_2, EV_L2_UI, l2_got_ui}, | ||
1796 | {ST_L2_3, EV_L2_UI, l2_got_ui}, | ||
1797 | {ST_L2_4, EV_L2_UI, l2_got_ui}, | ||
1798 | {ST_L2_5, EV_L2_UI, l2_got_ui}, | ||
1799 | {ST_L2_6, EV_L2_UI, l2_got_ui}, | ||
1800 | {ST_L2_7, EV_L2_UI, l2_got_ui}, | ||
1801 | {ST_L2_8, EV_L2_UI, l2_got_ui}, | ||
1802 | {ST_L2_7, EV_L2_FRMR, l2_got_FRMR}, | ||
1803 | {ST_L2_8, EV_L2_FRMR, l2_got_FRMR}, | ||
1804 | {ST_L2_7, EV_L2_SUPER, l2_st7_got_super}, | ||
1805 | {ST_L2_8, EV_L2_SUPER, l2_st8_got_super}, | ||
1806 | {ST_L2_7, EV_L2_I, l2_got_iframe}, | ||
1807 | {ST_L2_8, EV_L2_I, l2_got_iframe}, | ||
1808 | {ST_L2_5, EV_L2_T200, l2_st5_tout_200}, | ||
1809 | {ST_L2_6, EV_L2_T200, l2_st6_tout_200}, | ||
1810 | {ST_L2_7, EV_L2_T200, l2_st7_tout_200}, | ||
1811 | {ST_L2_8, EV_L2_T200, l2_st8_tout_200}, | ||
1812 | {ST_L2_7, EV_L2_T203, l2_st7_tout_203}, | ||
1813 | {ST_L2_7, EV_L2_ACK_PULL, l2_pull_iqueue}, | ||
1814 | {ST_L2_7, EV_L2_SET_OWN_BUSY, l2_set_own_busy}, | ||
1815 | {ST_L2_8, EV_L2_SET_OWN_BUSY, l2_set_own_busy}, | ||
1816 | {ST_L2_7, EV_L2_CLEAR_OWN_BUSY, l2_clear_own_busy}, | ||
1817 | {ST_L2_8, EV_L2_CLEAR_OWN_BUSY, l2_clear_own_busy}, | ||
1818 | {ST_L2_4, EV_L2_FRAME_ERROR, l2_frame_error}, | ||
1819 | {ST_L2_5, EV_L2_FRAME_ERROR, l2_frame_error}, | ||
1820 | {ST_L2_6, EV_L2_FRAME_ERROR, l2_frame_error}, | ||
1821 | {ST_L2_7, EV_L2_FRAME_ERROR, l2_frame_error_reest}, | ||
1822 | {ST_L2_8, EV_L2_FRAME_ERROR, l2_frame_error_reest}, | ||
1823 | {ST_L2_1, EV_L1_DEACTIVATE, l2_st14_persistant_da}, | ||
1824 | {ST_L2_2, EV_L1_DEACTIVATE, l2_st24_tei_remove}, | ||
1825 | {ST_L2_3, EV_L1_DEACTIVATE, l2_st3_tei_remove}, | ||
1826 | {ST_L2_4, EV_L1_DEACTIVATE, l2_st14_persistant_da}, | ||
1827 | {ST_L2_5, EV_L1_DEACTIVATE, l2_st5_persistant_da}, | ||
1828 | {ST_L2_6, EV_L1_DEACTIVATE, l2_st6_persistant_da}, | ||
1829 | {ST_L2_7, EV_L1_DEACTIVATE, l2_persistant_da}, | ||
1830 | {ST_L2_8, EV_L1_DEACTIVATE, l2_persistant_da}, | ||
1831 | }; | ||
1832 | |||
1833 | #define L2_FN_COUNT (sizeof(L2FnList)/sizeof(struct FsmNode)) | ||
1834 | |||
1835 | static int | ||
1836 | ph_data_indication(struct layer2 *l2, struct mISDNhead *hh, struct sk_buff *skb) | ||
1837 | { | ||
1838 | u_char *datap = skb->data; | ||
1839 | int ret = -EINVAL; | ||
1840 | int psapi, ptei; | ||
1841 | u_int l; | ||
1842 | int c = 0; | ||
1843 | |||
1844 | l = l2addrsize(l2); | ||
1845 | if (skb->len <= l) { | ||
1846 | mISDN_FsmEvent(&l2->l2m, EV_L2_FRAME_ERROR, (void *) 'N'); | ||
1847 | return ret; | ||
1848 | } | ||
1849 | if (test_bit(FLG_LAPD, &l2->flag)) { /* Maybe not needed */ | ||
1850 | psapi = *datap++; | ||
1851 | ptei = *datap++; | ||
1852 | if ((psapi & 1) || !(ptei & 1)) { | ||
1853 | printk(KERN_WARNING | ||
1854 | "l2 D-channel frame wrong EA0/EA1\n"); | ||
1855 | return ret; | ||
1856 | } | ||
1857 | psapi >>= 2; | ||
1858 | ptei >>= 1; | ||
1859 | if (psapi != l2->sapi) { | ||
1860 | /* not our bussiness | ||
1861 | * printk(KERN_DEBUG "%s: sapi %d/%d sapi mismatch\n", | ||
1862 | * __func__, | ||
1863 | * psapi, l2->sapi); | ||
1864 | */ | ||
1865 | dev_kfree_skb(skb); | ||
1866 | return 0; | ||
1867 | } | ||
1868 | if ((ptei != l2->tei) && (ptei != GROUP_TEI)) { | ||
1869 | /* not our bussiness | ||
1870 | * printk(KERN_DEBUG "%s: tei %d/%d sapi %d mismatch\n", | ||
1871 | * __func__, | ||
1872 | * ptei, l2->tei, psapi); | ||
1873 | */ | ||
1874 | dev_kfree_skb(skb); | ||
1875 | return 0; | ||
1876 | } | ||
1877 | } else | ||
1878 | datap += l; | ||
1879 | if (!(*datap & 1)) { /* I-Frame */ | ||
1880 | c = iframe_error(l2, skb); | ||
1881 | if (!c) | ||
1882 | ret = mISDN_FsmEvent(&l2->l2m, EV_L2_I, skb); | ||
1883 | } else if (IsSFrame(datap, l2)) { /* S-Frame */ | ||
1884 | c = super_error(l2, skb); | ||
1885 | if (!c) | ||
1886 | ret = mISDN_FsmEvent(&l2->l2m, EV_L2_SUPER, skb); | ||
1887 | } else if (IsUI(datap)) { | ||
1888 | c = UI_error(l2, skb); | ||
1889 | if (!c) | ||
1890 | ret = mISDN_FsmEvent(&l2->l2m, EV_L2_UI, skb); | ||
1891 | } else if (IsSABME(datap, l2)) { | ||
1892 | c = unnum_error(l2, skb, CMD); | ||
1893 | if (!c) | ||
1894 | ret = mISDN_FsmEvent(&l2->l2m, EV_L2_SABME, skb); | ||
1895 | } else if (IsUA(datap)) { | ||
1896 | c = unnum_error(l2, skb, RSP); | ||
1897 | if (!c) | ||
1898 | ret = mISDN_FsmEvent(&l2->l2m, EV_L2_UA, skb); | ||
1899 | } else if (IsDISC(datap)) { | ||
1900 | c = unnum_error(l2, skb, CMD); | ||
1901 | if (!c) | ||
1902 | ret = mISDN_FsmEvent(&l2->l2m, EV_L2_DISC, skb); | ||
1903 | } else if (IsDM(datap)) { | ||
1904 | c = unnum_error(l2, skb, RSP); | ||
1905 | if (!c) | ||
1906 | ret = mISDN_FsmEvent(&l2->l2m, EV_L2_DM, skb); | ||
1907 | } else if (IsFRMR(datap)) { | ||
1908 | c = FRMR_error(l2, skb); | ||
1909 | if (!c) | ||
1910 | ret = mISDN_FsmEvent(&l2->l2m, EV_L2_FRMR, skb); | ||
1911 | } else | ||
1912 | c = 'L'; | ||
1913 | if (c) { | ||
1914 | printk(KERN_WARNING "l2 D-channel frame error %c\n", c); | ||
1915 | mISDN_FsmEvent(&l2->l2m, EV_L2_FRAME_ERROR, (void *)(long)c); | ||
1916 | } | ||
1917 | return ret; | ||
1918 | } | ||
1919 | |||
1920 | static int | ||
1921 | l2_send(struct mISDNchannel *ch, struct sk_buff *skb) | ||
1922 | { | ||
1923 | struct layer2 *l2 = container_of(ch, struct layer2, ch); | ||
1924 | struct mISDNhead *hh = mISDN_HEAD_P(skb); | ||
1925 | int ret = -EINVAL; | ||
1926 | |||
1927 | if (*debug & DEBUG_L2_RECV) | ||
1928 | printk(KERN_DEBUG "%s: prim(%x) id(%x) tei(%d)\n", | ||
1929 | __func__, hh->prim, hh->id, l2->tei); | ||
1930 | switch (hh->prim) { | ||
1931 | case PH_DATA_IND: | ||
1932 | ret = ph_data_indication(l2, hh, skb); | ||
1933 | break; | ||
1934 | case PH_DATA_CNF: | ||
1935 | ret = ph_data_confirm(l2, hh, skb); | ||
1936 | break; | ||
1937 | case PH_ACTIVATE_IND: | ||
1938 | test_and_set_bit(FLG_L1_ACTIV, &l2->flag); | ||
1939 | l2up_create(l2, MPH_ACTIVATE_IND, 0, NULL); | ||
1940 | if (test_and_clear_bit(FLG_ESTAB_PEND, &l2->flag)) | ||
1941 | ret = mISDN_FsmEvent(&l2->l2m, | ||
1942 | EV_L2_DL_ESTABLISH_REQ, skb); | ||
1943 | break; | ||
1944 | case PH_DEACTIVATE_IND: | ||
1945 | test_and_clear_bit(FLG_L1_ACTIV, &l2->flag); | ||
1946 | l2up_create(l2, MPH_DEACTIVATE_IND, 0, NULL); | ||
1947 | ret = mISDN_FsmEvent(&l2->l2m, EV_L1_DEACTIVATE, skb); | ||
1948 | break; | ||
1949 | case MPH_INFORMATION_IND: | ||
1950 | if (!l2->up) | ||
1951 | break; | ||
1952 | ret = l2->up->send(l2->up, skb); | ||
1953 | break; | ||
1954 | case DL_DATA_REQ: | ||
1955 | ret = mISDN_FsmEvent(&l2->l2m, EV_L2_DL_DATA, skb); | ||
1956 | break; | ||
1957 | case DL_UNITDATA_REQ: | ||
1958 | ret = mISDN_FsmEvent(&l2->l2m, EV_L2_DL_UNITDATA, skb); | ||
1959 | break; | ||
1960 | case DL_ESTABLISH_REQ: | ||
1961 | if (test_bit(FLG_LAPB, &l2->flag)) | ||
1962 | test_and_set_bit(FLG_ORIG, &l2->flag); | ||
1963 | if (test_bit(FLG_L1_ACTIV, &l2->flag)) { | ||
1964 | if (test_bit(FLG_LAPD, &l2->flag) || | ||
1965 | test_bit(FLG_ORIG, &l2->flag)) | ||
1966 | ret = mISDN_FsmEvent(&l2->l2m, | ||
1967 | EV_L2_DL_ESTABLISH_REQ, skb); | ||
1968 | } else { | ||
1969 | if (test_bit(FLG_LAPD, &l2->flag) || | ||
1970 | test_bit(FLG_ORIG, &l2->flag)) { | ||
1971 | test_and_set_bit(FLG_ESTAB_PEND, | ||
1972 | &l2->flag); | ||
1973 | } | ||
1974 | ret = l2down(l2, PH_ACTIVATE_REQ, l2_newid(l2), | ||
1975 | skb); | ||
1976 | } | ||
1977 | break; | ||
1978 | case DL_RELEASE_REQ: | ||
1979 | if (test_bit(FLG_LAPB, &l2->flag)) | ||
1980 | l2down_create(l2, PH_DEACTIVATE_REQ, | ||
1981 | l2_newid(l2), 0, NULL); | ||
1982 | ret = mISDN_FsmEvent(&l2->l2m, EV_L2_DL_RELEASE_REQ, | ||
1983 | skb); | ||
1984 | break; | ||
1985 | default: | ||
1986 | if (*debug & DEBUG_L2) | ||
1987 | l2m_debug(&l2->l2m, "l2 unknown pr %04x", | ||
1988 | hh->prim); | ||
1989 | } | ||
1990 | if (ret) { | ||
1991 | dev_kfree_skb(skb); | ||
1992 | ret = 0; | ||
1993 | } | ||
1994 | return ret; | ||
1995 | } | ||
1996 | |||
1997 | int | ||
1998 | tei_l2(struct layer2 *l2, u_int cmd, u_long arg) | ||
1999 | { | ||
2000 | int ret = -EINVAL; | ||
2001 | |||
2002 | if (*debug & DEBUG_L2_TEI) | ||
2003 | printk(KERN_DEBUG "%s: cmd(%x)\n", __func__, cmd); | ||
2004 | switch (cmd) { | ||
2005 | case (MDL_ASSIGN_REQ): | ||
2006 | ret = mISDN_FsmEvent(&l2->l2m, EV_L2_MDL_ASSIGN, (void *)arg); | ||
2007 | break; | ||
2008 | case (MDL_REMOVE_REQ): | ||
2009 | ret = mISDN_FsmEvent(&l2->l2m, EV_L2_MDL_REMOVE, NULL); | ||
2010 | break; | ||
2011 | case (MDL_ERROR_IND): | ||
2012 | ret = mISDN_FsmEvent(&l2->l2m, EV_L2_MDL_ERROR, NULL); | ||
2013 | break; | ||
2014 | case (MDL_ERROR_RSP): | ||
2015 | /* ETS 300-125 5.3.2.1 Test: TC13010 */ | ||
2016 | printk(KERN_NOTICE "MDL_ERROR|REQ (tei_l2)\n"); | ||
2017 | ret = mISDN_FsmEvent(&l2->l2m, EV_L2_MDL_ERROR, NULL); | ||
2018 | break; | ||
2019 | } | ||
2020 | return ret; | ||
2021 | } | ||
2022 | |||
2023 | static void | ||
2024 | release_l2(struct layer2 *l2) | ||
2025 | { | ||
2026 | mISDN_FsmDelTimer(&l2->t200, 21); | ||
2027 | mISDN_FsmDelTimer(&l2->t203, 16); | ||
2028 | skb_queue_purge(&l2->i_queue); | ||
2029 | skb_queue_purge(&l2->ui_queue); | ||
2030 | skb_queue_purge(&l2->down_queue); | ||
2031 | ReleaseWin(l2); | ||
2032 | if (test_bit(FLG_LAPD, &l2->flag)) { | ||
2033 | release_tei(l2); | ||
2034 | if (l2->ch.st) | ||
2035 | l2->ch.st->dev->D.ctrl(&l2->ch.st->dev->D, | ||
2036 | CLOSE_CHANNEL, NULL); | ||
2037 | } | ||
2038 | kfree(l2); | ||
2039 | } | ||
2040 | |||
2041 | static int | ||
2042 | l2_ctrl(struct mISDNchannel *ch, u_int cmd, void *arg) | ||
2043 | { | ||
2044 | struct layer2 *l2 = container_of(ch, struct layer2, ch); | ||
2045 | u_int info; | ||
2046 | |||
2047 | if (*debug & DEBUG_L2_CTRL) | ||
2048 | printk(KERN_DEBUG "%s:(%x)\n", __func__, cmd); | ||
2049 | |||
2050 | switch (cmd) { | ||
2051 | case OPEN_CHANNEL: | ||
2052 | if (test_bit(FLG_LAPD, &l2->flag)) { | ||
2053 | set_channel_address(&l2->ch, l2->sapi, l2->tei); | ||
2054 | info = DL_INFO_L2_CONNECT; | ||
2055 | l2up_create(l2, DL_INFORMATION_IND, | ||
2056 | sizeof(info), &info); | ||
2057 | } | ||
2058 | break; | ||
2059 | case CLOSE_CHANNEL: | ||
2060 | if (l2->ch.peer) | ||
2061 | l2->ch.peer->ctrl(l2->ch.peer, CLOSE_CHANNEL, NULL); | ||
2062 | release_l2(l2); | ||
2063 | break; | ||
2064 | } | ||
2065 | return 0; | ||
2066 | } | ||
2067 | |||
2068 | struct layer2 * | ||
2069 | create_l2(struct mISDNchannel *ch, u_int protocol, u_long options, u_long arg) | ||
2070 | { | ||
2071 | struct layer2 *l2; | ||
2072 | struct channel_req rq; | ||
2073 | |||
2074 | l2 = kzalloc(sizeof(struct layer2), GFP_KERNEL); | ||
2075 | if (!l2) { | ||
2076 | printk(KERN_ERR "kzalloc layer2 failed\n"); | ||
2077 | return NULL; | ||
2078 | } | ||
2079 | l2->next_id = 1; | ||
2080 | l2->down_id = MISDN_ID_NONE; | ||
2081 | l2->up = ch; | ||
2082 | l2->ch.st = ch->st; | ||
2083 | l2->ch.send = l2_send; | ||
2084 | l2->ch.ctrl = l2_ctrl; | ||
2085 | switch (protocol) { | ||
2086 | case ISDN_P_LAPD_NT: | ||
2087 | test_and_set_bit(FLG_LAPD, &l2->flag); | ||
2088 | test_and_set_bit(FLG_LAPD_NET, &l2->flag); | ||
2089 | test_and_set_bit(FLG_MOD128, &l2->flag); | ||
2090 | l2->sapi = 0; | ||
2091 | l2->maxlen = MAX_DFRAME_LEN; | ||
2092 | if (test_bit(OPTION_L2_PMX, &options)) | ||
2093 | l2->window = 7; | ||
2094 | else | ||
2095 | l2->window = 1; | ||
2096 | if (test_bit(OPTION_L2_PTP, &options)) | ||
2097 | test_and_set_bit(FLG_PTP, &l2->flag); | ||
2098 | if (test_bit(OPTION_L2_FIXEDTEI, &options)) | ||
2099 | test_and_set_bit(FLG_FIXED_TEI, &l2->flag); | ||
2100 | l2->tei = (u_int)arg; | ||
2101 | l2->T200 = 1000; | ||
2102 | l2->N200 = 3; | ||
2103 | l2->T203 = 10000; | ||
2104 | if (test_bit(OPTION_L2_PMX, &options)) | ||
2105 | rq.protocol = ISDN_P_NT_E1; | ||
2106 | else | ||
2107 | rq.protocol = ISDN_P_NT_S0; | ||
2108 | rq.adr.channel = 0; | ||
2109 | l2->ch.st->dev->D.ctrl(&l2->ch.st->dev->D, OPEN_CHANNEL, &rq); | ||
2110 | break; | ||
2111 | case ISDN_P_LAPD_TE: | ||
2112 | test_and_set_bit(FLG_LAPD, &l2->flag); | ||
2113 | test_and_set_bit(FLG_MOD128, &l2->flag); | ||
2114 | test_and_set_bit(FLG_ORIG, &l2->flag); | ||
2115 | l2->sapi = 0; | ||
2116 | l2->maxlen = MAX_DFRAME_LEN; | ||
2117 | if (test_bit(OPTION_L2_PMX, &options)) | ||
2118 | l2->window = 7; | ||
2119 | else | ||
2120 | l2->window = 1; | ||
2121 | if (test_bit(OPTION_L2_PTP, &options)) | ||
2122 | test_and_set_bit(FLG_PTP, &l2->flag); | ||
2123 | if (test_bit(OPTION_L2_FIXEDTEI, &options)) | ||
2124 | test_and_set_bit(FLG_FIXED_TEI, &l2->flag); | ||
2125 | l2->tei = (u_int)arg; | ||
2126 | l2->T200 = 1000; | ||
2127 | l2->N200 = 3; | ||
2128 | l2->T203 = 10000; | ||
2129 | if (test_bit(OPTION_L2_PMX, &options)) | ||
2130 | rq.protocol = ISDN_P_TE_E1; | ||
2131 | else | ||
2132 | rq.protocol = ISDN_P_TE_S0; | ||
2133 | rq.adr.channel = 0; | ||
2134 | l2->ch.st->dev->D.ctrl(&l2->ch.st->dev->D, OPEN_CHANNEL, &rq); | ||
2135 | break; | ||
2136 | case ISDN_P_B_X75SLP: | ||
2137 | test_and_set_bit(FLG_LAPB, &l2->flag); | ||
2138 | l2->window = 7; | ||
2139 | l2->maxlen = MAX_DATA_SIZE; | ||
2140 | l2->T200 = 1000; | ||
2141 | l2->N200 = 4; | ||
2142 | l2->T203 = 5000; | ||
2143 | l2->addr.A = 3; | ||
2144 | l2->addr.B = 1; | ||
2145 | break; | ||
2146 | default: | ||
2147 | printk(KERN_ERR "layer2 create failed prt %x\n", | ||
2148 | protocol); | ||
2149 | kfree(l2); | ||
2150 | return NULL; | ||
2151 | } | ||
2152 | skb_queue_head_init(&l2->i_queue); | ||
2153 | skb_queue_head_init(&l2->ui_queue); | ||
2154 | skb_queue_head_init(&l2->down_queue); | ||
2155 | skb_queue_head_init(&l2->tmp_queue); | ||
2156 | InitWin(l2); | ||
2157 | l2->l2m.fsm = &l2fsm; | ||
2158 | if (test_bit(FLG_LAPB, &l2->flag) || | ||
2159 | test_bit(FLG_PTP, &l2->flag) || | ||
2160 | test_bit(FLG_LAPD_NET, &l2->flag)) | ||
2161 | l2->l2m.state = ST_L2_4; | ||
2162 | else | ||
2163 | l2->l2m.state = ST_L2_1; | ||
2164 | l2->l2m.debug = *debug; | ||
2165 | l2->l2m.userdata = l2; | ||
2166 | l2->l2m.userint = 0; | ||
2167 | l2->l2m.printdebug = l2m_debug; | ||
2168 | |||
2169 | mISDN_FsmInitTimer(&l2->l2m, &l2->t200); | ||
2170 | mISDN_FsmInitTimer(&l2->l2m, &l2->t203); | ||
2171 | return l2; | ||
2172 | } | ||
2173 | |||
2174 | static int | ||
2175 | x75create(struct channel_req *crq) | ||
2176 | { | ||
2177 | struct layer2 *l2; | ||
2178 | |||
2179 | if (crq->protocol != ISDN_P_B_X75SLP) | ||
2180 | return -EPROTONOSUPPORT; | ||
2181 | l2 = create_l2(crq->ch, crq->protocol, 0, 0); | ||
2182 | if (!l2) | ||
2183 | return -ENOMEM; | ||
2184 | crq->ch = &l2->ch; | ||
2185 | crq->protocol = ISDN_P_B_HDLC; | ||
2186 | return 0; | ||
2187 | } | ||
2188 | |||
2189 | static struct Bprotocol X75SLP = { | ||
2190 | .Bprotocols = (1 << (ISDN_P_B_X75SLP & ISDN_P_B_MASK)), | ||
2191 | .name = "X75SLP", | ||
2192 | .create = x75create | ||
2193 | }; | ||
2194 | |||
2195 | int | ||
2196 | Isdnl2_Init(u_int *deb) | ||
2197 | { | ||
2198 | debug = deb; | ||
2199 | mISDN_register_Bprotocol(&X75SLP); | ||
2200 | l2fsm.state_count = L2_STATE_COUNT; | ||
2201 | l2fsm.event_count = L2_EVENT_COUNT; | ||
2202 | l2fsm.strEvent = strL2Event; | ||
2203 | l2fsm.strState = strL2State; | ||
2204 | mISDN_FsmNew(&l2fsm, L2FnList, ARRAY_SIZE(L2FnList)); | ||
2205 | TEIInit(deb); | ||
2206 | return 0; | ||
2207 | } | ||
2208 | |||
2209 | void | ||
2210 | Isdnl2_cleanup(void) | ||
2211 | { | ||
2212 | mISDN_unregister_Bprotocol(&X75SLP); | ||
2213 | TEIFree(); | ||
2214 | mISDN_FsmFree(&l2fsm); | ||
2215 | } | ||
2216 | |||
diff --git a/drivers/isdn/mISDN/layer2.h b/drivers/isdn/mISDN/layer2.h new file mode 100644 index 000000000000..de2dd02056a3 --- /dev/null +++ b/drivers/isdn/mISDN/layer2.h | |||
@@ -0,0 +1,140 @@ | |||
1 | /* | ||
2 | * Layer 2 defines | ||
3 | * | ||
4 | * Copyright 2008 by Karsten Keil <kkeil@novell.com> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | */ | ||
16 | |||
17 | #include <linux/mISDNif.h> | ||
18 | #include <linux/skbuff.h> | ||
19 | #include "fsm.h" | ||
20 | |||
21 | #define MAX_WINDOW 8 | ||
22 | |||
23 | struct manager { | ||
24 | struct mISDNchannel ch; | ||
25 | struct mISDNchannel bcast; | ||
26 | u_long options; | ||
27 | struct list_head layer2; | ||
28 | rwlock_t lock; | ||
29 | struct FsmInst deact; | ||
30 | struct FsmTimer datimer; | ||
31 | struct sk_buff_head sendq; | ||
32 | struct mISDNchannel *up; | ||
33 | u_int nextid; | ||
34 | u_int lastid; | ||
35 | }; | ||
36 | |||
37 | struct teimgr { | ||
38 | int ri; | ||
39 | int rcnt; | ||
40 | struct FsmInst tei_m; | ||
41 | struct FsmTimer timer; | ||
42 | int tval, nval; | ||
43 | struct layer2 *l2; | ||
44 | struct manager *mgr; | ||
45 | }; | ||
46 | |||
47 | struct laddr { | ||
48 | u_char A; | ||
49 | u_char B; | ||
50 | }; | ||
51 | |||
52 | struct layer2 { | ||
53 | struct list_head list; | ||
54 | struct mISDNchannel ch; | ||
55 | u_long flag; | ||
56 | int id; | ||
57 | struct mISDNchannel *up; | ||
58 | signed char sapi; | ||
59 | signed char tei; | ||
60 | struct laddr addr; | ||
61 | u_int maxlen; | ||
62 | struct teimgr *tm; | ||
63 | u_int vs, va, vr; | ||
64 | int rc; | ||
65 | u_int window; | ||
66 | u_int sow; | ||
67 | struct FsmInst l2m; | ||
68 | struct FsmTimer t200, t203; | ||
69 | int T200, N200, T203; | ||
70 | u_int next_id; | ||
71 | u_int down_id; | ||
72 | struct sk_buff *windowar[MAX_WINDOW]; | ||
73 | struct sk_buff_head i_queue; | ||
74 | struct sk_buff_head ui_queue; | ||
75 | struct sk_buff_head down_queue; | ||
76 | struct sk_buff_head tmp_queue; | ||
77 | }; | ||
78 | |||
79 | enum { | ||
80 | ST_L2_1, | ||
81 | ST_L2_2, | ||
82 | ST_L2_3, | ||
83 | ST_L2_4, | ||
84 | ST_L2_5, | ||
85 | ST_L2_6, | ||
86 | ST_L2_7, | ||
87 | ST_L2_8, | ||
88 | }; | ||
89 | |||
90 | #define L2_STATE_COUNT (ST_L2_8+1) | ||
91 | |||
92 | extern struct layer2 *create_l2(struct mISDNchannel *, u_int, | ||
93 | u_long, u_long); | ||
94 | extern int tei_l2(struct layer2 *, u_int, u_long arg); | ||
95 | |||
96 | |||
97 | /* from tei.c */ | ||
98 | extern int l2_tei(struct layer2 *, u_int, u_long arg); | ||
99 | extern void release_tei(struct layer2 *); | ||
100 | extern int TEIInit(u_int *); | ||
101 | extern void TEIFree(void); | ||
102 | |||
103 | #define MAX_L2HEADER_LEN 4 | ||
104 | |||
105 | #define RR 0x01 | ||
106 | #define RNR 0x05 | ||
107 | #define REJ 0x09 | ||
108 | #define SABME 0x6f | ||
109 | #define SABM 0x2f | ||
110 | #define DM 0x0f | ||
111 | #define UI 0x03 | ||
112 | #define DISC 0x43 | ||
113 | #define UA 0x63 | ||
114 | #define FRMR 0x87 | ||
115 | #define XID 0xaf | ||
116 | |||
117 | #define CMD 0 | ||
118 | #define RSP 1 | ||
119 | |||
120 | #define LC_FLUSH_WAIT 1 | ||
121 | |||
122 | #define FLG_LAPB 0 | ||
123 | #define FLG_LAPD 1 | ||
124 | #define FLG_ORIG 2 | ||
125 | #define FLG_MOD128 3 | ||
126 | #define FLG_PEND_REL 4 | ||
127 | #define FLG_L3_INIT 5 | ||
128 | #define FLG_T200_RUN 6 | ||
129 | #define FLG_ACK_PEND 7 | ||
130 | #define FLG_REJEXC 8 | ||
131 | #define FLG_OWN_BUSY 9 | ||
132 | #define FLG_PEER_BUSY 10 | ||
133 | #define FLG_DCHAN_BUSY 11 | ||
134 | #define FLG_L1_ACTIV 12 | ||
135 | #define FLG_ESTAB_PEND 13 | ||
136 | #define FLG_PTP 14 | ||
137 | #define FLG_FIXED_TEI 15 | ||
138 | #define FLG_L2BLOCK 16 | ||
139 | #define FLG_L1_NOTREADY 17 | ||
140 | #define FLG_LAPD_NET 18 | ||
diff --git a/drivers/isdn/mISDN/socket.c b/drivers/isdn/mISDN/socket.c new file mode 100644 index 000000000000..4ba4cc364c9e --- /dev/null +++ b/drivers/isdn/mISDN/socket.c | |||
@@ -0,0 +1,781 @@ | |||
1 | /* | ||
2 | * | ||
3 | * Author Karsten Keil <kkeil@novell.com> | ||
4 | * | ||
5 | * Copyright 2008 by Karsten Keil <kkeil@novell.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | */ | ||
17 | |||
18 | #include <linux/mISDNif.h> | ||
19 | #include "core.h" | ||
20 | |||
21 | static int *debug; | ||
22 | |||
23 | static struct proto mISDN_proto = { | ||
24 | .name = "misdn", | ||
25 | .owner = THIS_MODULE, | ||
26 | .obj_size = sizeof(struct mISDN_sock) | ||
27 | }; | ||
28 | |||
29 | #define _pms(sk) ((struct mISDN_sock *)sk) | ||
30 | |||
31 | static struct mISDN_sock_list data_sockets = { | ||
32 | .lock = __RW_LOCK_UNLOCKED(data_sockets.lock) | ||
33 | }; | ||
34 | |||
35 | static struct mISDN_sock_list base_sockets = { | ||
36 | .lock = __RW_LOCK_UNLOCKED(base_sockets.lock) | ||
37 | }; | ||
38 | |||
39 | #define L2_HEADER_LEN 4 | ||
40 | |||
41 | static inline struct sk_buff * | ||
42 | _l2_alloc_skb(unsigned int len, gfp_t gfp_mask) | ||
43 | { | ||
44 | struct sk_buff *skb; | ||
45 | |||
46 | skb = alloc_skb(len + L2_HEADER_LEN, gfp_mask); | ||
47 | if (likely(skb)) | ||
48 | skb_reserve(skb, L2_HEADER_LEN); | ||
49 | return skb; | ||
50 | } | ||
51 | |||
52 | static void | ||
53 | mISDN_sock_link(struct mISDN_sock_list *l, struct sock *sk) | ||
54 | { | ||
55 | write_lock_bh(&l->lock); | ||
56 | sk_add_node(sk, &l->head); | ||
57 | write_unlock_bh(&l->lock); | ||
58 | } | ||
59 | |||
60 | static void mISDN_sock_unlink(struct mISDN_sock_list *l, struct sock *sk) | ||
61 | { | ||
62 | write_lock_bh(&l->lock); | ||
63 | sk_del_node_init(sk); | ||
64 | write_unlock_bh(&l->lock); | ||
65 | } | ||
66 | |||
67 | static int | ||
68 | mISDN_send(struct mISDNchannel *ch, struct sk_buff *skb) | ||
69 | { | ||
70 | struct mISDN_sock *msk; | ||
71 | int err; | ||
72 | |||
73 | msk = container_of(ch, struct mISDN_sock, ch); | ||
74 | if (*debug & DEBUG_SOCKET) | ||
75 | printk(KERN_DEBUG "%s len %d %p\n", __func__, skb->len, skb); | ||
76 | if (msk->sk.sk_state == MISDN_CLOSED) | ||
77 | return -EUNATCH; | ||
78 | __net_timestamp(skb); | ||
79 | err = sock_queue_rcv_skb(&msk->sk, skb); | ||
80 | if (err) | ||
81 | printk(KERN_WARNING "%s: error %d\n", __func__, err); | ||
82 | return err; | ||
83 | } | ||
84 | |||
85 | static int | ||
86 | mISDN_ctrl(struct mISDNchannel *ch, u_int cmd, void *arg) | ||
87 | { | ||
88 | struct mISDN_sock *msk; | ||
89 | |||
90 | msk = container_of(ch, struct mISDN_sock, ch); | ||
91 | if (*debug & DEBUG_SOCKET) | ||
92 | printk(KERN_DEBUG "%s(%p, %x, %p)\n", __func__, ch, cmd, arg); | ||
93 | switch (cmd) { | ||
94 | case CLOSE_CHANNEL: | ||
95 | msk->sk.sk_state = MISDN_CLOSED; | ||
96 | break; | ||
97 | } | ||
98 | return 0; | ||
99 | } | ||
100 | |||
101 | static inline void | ||
102 | mISDN_sock_cmsg(struct sock *sk, struct msghdr *msg, struct sk_buff *skb) | ||
103 | { | ||
104 | struct timeval tv; | ||
105 | |||
106 | if (_pms(sk)->cmask & MISDN_TIME_STAMP) { | ||
107 | skb_get_timestamp(skb, &tv); | ||
108 | put_cmsg(msg, SOL_MISDN, MISDN_TIME_STAMP, sizeof(tv), &tv); | ||
109 | } | ||
110 | } | ||
111 | |||
112 | static int | ||
113 | mISDN_sock_recvmsg(struct kiocb *iocb, struct socket *sock, | ||
114 | struct msghdr *msg, size_t len, int flags) | ||
115 | { | ||
116 | struct sk_buff *skb; | ||
117 | struct sock *sk = sock->sk; | ||
118 | struct sockaddr_mISDN *maddr; | ||
119 | |||
120 | int copied, err; | ||
121 | |||
122 | if (*debug & DEBUG_SOCKET) | ||
123 | printk(KERN_DEBUG "%s: len %d, flags %x ch.nr %d, proto %x\n", | ||
124 | __func__, (int)len, flags, _pms(sk)->ch.nr, | ||
125 | sk->sk_protocol); | ||
126 | if (flags & (MSG_OOB)) | ||
127 | return -EOPNOTSUPP; | ||
128 | |||
129 | if (sk->sk_state == MISDN_CLOSED) | ||
130 | return 0; | ||
131 | |||
132 | skb = skb_recv_datagram(sk, flags, flags & MSG_DONTWAIT, &err); | ||
133 | if (!skb) | ||
134 | return err; | ||
135 | |||
136 | if (msg->msg_namelen >= sizeof(struct sockaddr_mISDN)) { | ||
137 | msg->msg_namelen = sizeof(struct sockaddr_mISDN); | ||
138 | maddr = (struct sockaddr_mISDN *)msg->msg_name; | ||
139 | maddr->family = AF_ISDN; | ||
140 | maddr->dev = _pms(sk)->dev->id; | ||
141 | if ((sk->sk_protocol == ISDN_P_LAPD_TE) || | ||
142 | (sk->sk_protocol == ISDN_P_LAPD_NT)) { | ||
143 | maddr->channel = (mISDN_HEAD_ID(skb) >> 16) & 0xff; | ||
144 | maddr->tei = (mISDN_HEAD_ID(skb) >> 8) & 0xff; | ||
145 | maddr->sapi = mISDN_HEAD_ID(skb) & 0xff; | ||
146 | } else { | ||
147 | maddr->channel = _pms(sk)->ch.nr; | ||
148 | maddr->sapi = _pms(sk)->ch.addr & 0xFF; | ||
149 | maddr->tei = (_pms(sk)->ch.addr >> 8) & 0xFF; | ||
150 | } | ||
151 | } else { | ||
152 | if (msg->msg_namelen) | ||
153 | printk(KERN_WARNING "%s: too small namelen %d\n", | ||
154 | __func__, msg->msg_namelen); | ||
155 | msg->msg_namelen = 0; | ||
156 | } | ||
157 | |||
158 | copied = skb->len + MISDN_HEADER_LEN; | ||
159 | if (len < copied) { | ||
160 | if (flags & MSG_PEEK) | ||
161 | atomic_dec(&skb->users); | ||
162 | else | ||
163 | skb_queue_head(&sk->sk_receive_queue, skb); | ||
164 | return -ENOSPC; | ||
165 | } | ||
166 | memcpy(skb_push(skb, MISDN_HEADER_LEN), mISDN_HEAD_P(skb), | ||
167 | MISDN_HEADER_LEN); | ||
168 | |||
169 | err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied); | ||
170 | |||
171 | mISDN_sock_cmsg(sk, msg, skb); | ||
172 | |||
173 | skb_free_datagram(sk, skb); | ||
174 | |||
175 | return err ? : copied; | ||
176 | } | ||
177 | |||
178 | static int | ||
179 | mISDN_sock_sendmsg(struct kiocb *iocb, struct socket *sock, | ||
180 | struct msghdr *msg, size_t len) | ||
181 | { | ||
182 | struct sock *sk = sock->sk; | ||
183 | struct sk_buff *skb; | ||
184 | int err = -ENOMEM; | ||
185 | struct sockaddr_mISDN *maddr; | ||
186 | |||
187 | if (*debug & DEBUG_SOCKET) | ||
188 | printk(KERN_DEBUG "%s: len %d flags %x ch %d proto %x\n", | ||
189 | __func__, (int)len, msg->msg_flags, _pms(sk)->ch.nr, | ||
190 | sk->sk_protocol); | ||
191 | |||
192 | if (msg->msg_flags & MSG_OOB) | ||
193 | return -EOPNOTSUPP; | ||
194 | |||
195 | if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_NOSIGNAL|MSG_ERRQUEUE)) | ||
196 | return -EINVAL; | ||
197 | |||
198 | if (len < MISDN_HEADER_LEN) | ||
199 | return -EINVAL; | ||
200 | |||
201 | if (sk->sk_state != MISDN_BOUND) | ||
202 | return -EBADFD; | ||
203 | |||
204 | lock_sock(sk); | ||
205 | |||
206 | skb = _l2_alloc_skb(len, GFP_KERNEL); | ||
207 | if (!skb) | ||
208 | goto done; | ||
209 | |||
210 | if (memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len)) { | ||
211 | err = -EFAULT; | ||
212 | goto drop; | ||
213 | } | ||
214 | |||
215 | memcpy(mISDN_HEAD_P(skb), skb->data, MISDN_HEADER_LEN); | ||
216 | skb_pull(skb, MISDN_HEADER_LEN); | ||
217 | |||
218 | if (msg->msg_namelen >= sizeof(struct sockaddr_mISDN)) { | ||
219 | /* if we have a address, we use it */ | ||
220 | maddr = (struct sockaddr_mISDN *)msg->msg_name; | ||
221 | mISDN_HEAD_ID(skb) = maddr->channel; | ||
222 | } else { /* use default for L2 messages */ | ||
223 | if ((sk->sk_protocol == ISDN_P_LAPD_TE) || | ||
224 | (sk->sk_protocol == ISDN_P_LAPD_NT)) | ||
225 | mISDN_HEAD_ID(skb) = _pms(sk)->ch.nr; | ||
226 | } | ||
227 | |||
228 | if (*debug & DEBUG_SOCKET) | ||
229 | printk(KERN_DEBUG "%s: ID:%x\n", | ||
230 | __func__, mISDN_HEAD_ID(skb)); | ||
231 | |||
232 | err = -ENODEV; | ||
233 | if (!_pms(sk)->ch.peer || | ||
234 | (err = _pms(sk)->ch.recv(_pms(sk)->ch.peer, skb))) | ||
235 | goto drop; | ||
236 | |||
237 | err = len; | ||
238 | |||
239 | done: | ||
240 | release_sock(sk); | ||
241 | return err; | ||
242 | |||
243 | drop: | ||
244 | kfree_skb(skb); | ||
245 | goto done; | ||
246 | } | ||
247 | |||
248 | static int | ||
249 | data_sock_release(struct socket *sock) | ||
250 | { | ||
251 | struct sock *sk = sock->sk; | ||
252 | |||
253 | if (*debug & DEBUG_SOCKET) | ||
254 | printk(KERN_DEBUG "%s(%p) sk=%p\n", __func__, sock, sk); | ||
255 | if (!sk) | ||
256 | return 0; | ||
257 | switch (sk->sk_protocol) { | ||
258 | case ISDN_P_TE_S0: | ||
259 | case ISDN_P_NT_S0: | ||
260 | case ISDN_P_TE_E1: | ||
261 | case ISDN_P_NT_E1: | ||
262 | if (sk->sk_state == MISDN_BOUND) | ||
263 | delete_channel(&_pms(sk)->ch); | ||
264 | else | ||
265 | mISDN_sock_unlink(&data_sockets, sk); | ||
266 | break; | ||
267 | case ISDN_P_LAPD_TE: | ||
268 | case ISDN_P_LAPD_NT: | ||
269 | case ISDN_P_B_RAW: | ||
270 | case ISDN_P_B_HDLC: | ||
271 | case ISDN_P_B_X75SLP: | ||
272 | case ISDN_P_B_L2DTMF: | ||
273 | case ISDN_P_B_L2DSP: | ||
274 | case ISDN_P_B_L2DSPHDLC: | ||
275 | delete_channel(&_pms(sk)->ch); | ||
276 | mISDN_sock_unlink(&data_sockets, sk); | ||
277 | break; | ||
278 | } | ||
279 | |||
280 | lock_sock(sk); | ||
281 | |||
282 | sock_orphan(sk); | ||
283 | skb_queue_purge(&sk->sk_receive_queue); | ||
284 | |||
285 | release_sock(sk); | ||
286 | sock_put(sk); | ||
287 | |||
288 | return 0; | ||
289 | } | ||
290 | |||
291 | static int | ||
292 | data_sock_ioctl_bound(struct sock *sk, unsigned int cmd, void __user *p) | ||
293 | { | ||
294 | struct mISDN_ctrl_req cq; | ||
295 | int err = -EINVAL, val; | ||
296 | struct mISDNchannel *bchan, *next; | ||
297 | |||
298 | lock_sock(sk); | ||
299 | if (!_pms(sk)->dev) { | ||
300 | err = -ENODEV; | ||
301 | goto done; | ||
302 | } | ||
303 | switch (cmd) { | ||
304 | case IMCTRLREQ: | ||
305 | if (copy_from_user(&cq, p, sizeof(cq))) { | ||
306 | err = -EFAULT; | ||
307 | break; | ||
308 | } | ||
309 | if ((sk->sk_protocol & ~ISDN_P_B_MASK) == ISDN_P_B_START) { | ||
310 | list_for_each_entry_safe(bchan, next, | ||
311 | &_pms(sk)->dev->bchannels, list) { | ||
312 | if (bchan->nr == cq.channel) { | ||
313 | err = bchan->ctrl(bchan, | ||
314 | CONTROL_CHANNEL, &cq); | ||
315 | break; | ||
316 | } | ||
317 | } | ||
318 | } else | ||
319 | err = _pms(sk)->dev->D.ctrl(&_pms(sk)->dev->D, | ||
320 | CONTROL_CHANNEL, &cq); | ||
321 | if (err) | ||
322 | break; | ||
323 | if (copy_to_user(p, &cq, sizeof(cq))) | ||
324 | err = -EFAULT; | ||
325 | break; | ||
326 | case IMCLEAR_L2: | ||
327 | if (sk->sk_protocol != ISDN_P_LAPD_NT) { | ||
328 | err = -EINVAL; | ||
329 | break; | ||
330 | } | ||
331 | if (get_user(val, (int __user *)p)) { | ||
332 | err = -EFAULT; | ||
333 | break; | ||
334 | } | ||
335 | err = _pms(sk)->dev->teimgr->ctrl(_pms(sk)->dev->teimgr, | ||
336 | CONTROL_CHANNEL, &val); | ||
337 | break; | ||
338 | default: | ||
339 | err = -EINVAL; | ||
340 | break; | ||
341 | } | ||
342 | done: | ||
343 | release_sock(sk); | ||
344 | return err; | ||
345 | } | ||
346 | |||
347 | static int | ||
348 | data_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) | ||
349 | { | ||
350 | int err = 0, id; | ||
351 | struct sock *sk = sock->sk; | ||
352 | struct mISDNdevice *dev; | ||
353 | struct mISDNversion ver; | ||
354 | |||
355 | switch (cmd) { | ||
356 | case IMGETVERSION: | ||
357 | ver.major = MISDN_MAJOR_VERSION; | ||
358 | ver.minor = MISDN_MINOR_VERSION; | ||
359 | ver.release = MISDN_RELEASE; | ||
360 | if (copy_to_user((void __user *)arg, &ver, sizeof(ver))) | ||
361 | err = -EFAULT; | ||
362 | break; | ||
363 | case IMGETCOUNT: | ||
364 | id = get_mdevice_count(); | ||
365 | if (put_user(id, (int __user *)arg)) | ||
366 | err = -EFAULT; | ||
367 | break; | ||
368 | case IMGETDEVINFO: | ||
369 | if (get_user(id, (int __user *)arg)) { | ||
370 | err = -EFAULT; | ||
371 | break; | ||
372 | } | ||
373 | dev = get_mdevice(id); | ||
374 | if (dev) { | ||
375 | struct mISDN_devinfo di; | ||
376 | |||
377 | di.id = dev->id; | ||
378 | di.Dprotocols = dev->Dprotocols; | ||
379 | di.Bprotocols = dev->Bprotocols | get_all_Bprotocols(); | ||
380 | di.protocol = dev->D.protocol; | ||
381 | memcpy(di.channelmap, dev->channelmap, | ||
382 | MISDN_CHMAP_SIZE * 4); | ||
383 | di.nrbchan = dev->nrbchan; | ||
384 | strcpy(di.name, dev->name); | ||
385 | if (copy_to_user((void __user *)arg, &di, sizeof(di))) | ||
386 | err = -EFAULT; | ||
387 | } else | ||
388 | err = -ENODEV; | ||
389 | break; | ||
390 | default: | ||
391 | if (sk->sk_state == MISDN_BOUND) | ||
392 | err = data_sock_ioctl_bound(sk, cmd, | ||
393 | (void __user *)arg); | ||
394 | else | ||
395 | err = -ENOTCONN; | ||
396 | } | ||
397 | return err; | ||
398 | } | ||
399 | |||
400 | static int data_sock_setsockopt(struct socket *sock, int level, int optname, | ||
401 | char __user *optval, int len) | ||
402 | { | ||
403 | struct sock *sk = sock->sk; | ||
404 | int err = 0, opt = 0; | ||
405 | |||
406 | if (*debug & DEBUG_SOCKET) | ||
407 | printk(KERN_DEBUG "%s(%p, %d, %x, %p, %d)\n", __func__, sock, | ||
408 | level, optname, optval, len); | ||
409 | |||
410 | lock_sock(sk); | ||
411 | |||
412 | switch (optname) { | ||
413 | case MISDN_TIME_STAMP: | ||
414 | if (get_user(opt, (int __user *)optval)) { | ||
415 | err = -EFAULT; | ||
416 | break; | ||
417 | } | ||
418 | |||
419 | if (opt) | ||
420 | _pms(sk)->cmask |= MISDN_TIME_STAMP; | ||
421 | else | ||
422 | _pms(sk)->cmask &= ~MISDN_TIME_STAMP; | ||
423 | break; | ||
424 | default: | ||
425 | err = -ENOPROTOOPT; | ||
426 | break; | ||
427 | } | ||
428 | release_sock(sk); | ||
429 | return err; | ||
430 | } | ||
431 | |||
432 | static int data_sock_getsockopt(struct socket *sock, int level, int optname, | ||
433 | char __user *optval, int __user *optlen) | ||
434 | { | ||
435 | struct sock *sk = sock->sk; | ||
436 | int len, opt; | ||
437 | |||
438 | if (get_user(len, optlen)) | ||
439 | return -EFAULT; | ||
440 | |||
441 | switch (optname) { | ||
442 | case MISDN_TIME_STAMP: | ||
443 | if (_pms(sk)->cmask & MISDN_TIME_STAMP) | ||
444 | opt = 1; | ||
445 | else | ||
446 | opt = 0; | ||
447 | |||
448 | if (put_user(opt, optval)) | ||
449 | return -EFAULT; | ||
450 | break; | ||
451 | default: | ||
452 | return -ENOPROTOOPT; | ||
453 | } | ||
454 | |||
455 | return 0; | ||
456 | } | ||
457 | |||
458 | static int | ||
459 | data_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_len) | ||
460 | { | ||
461 | struct sockaddr_mISDN *maddr = (struct sockaddr_mISDN *) addr; | ||
462 | struct sock *sk = sock->sk; | ||
463 | int err = 0; | ||
464 | |||
465 | if (*debug & DEBUG_SOCKET) | ||
466 | printk(KERN_DEBUG "%s(%p) sk=%p\n", __func__, sock, sk); | ||
467 | if (addr_len != sizeof(struct sockaddr_mISDN)) | ||
468 | return -EINVAL; | ||
469 | if (!maddr || maddr->family != AF_ISDN) | ||
470 | return -EINVAL; | ||
471 | |||
472 | lock_sock(sk); | ||
473 | |||
474 | if (_pms(sk)->dev) { | ||
475 | err = -EALREADY; | ||
476 | goto done; | ||
477 | } | ||
478 | _pms(sk)->dev = get_mdevice(maddr->dev); | ||
479 | if (!_pms(sk)->dev) { | ||
480 | err = -ENODEV; | ||
481 | goto done; | ||
482 | } | ||
483 | _pms(sk)->ch.send = mISDN_send; | ||
484 | _pms(sk)->ch.ctrl = mISDN_ctrl; | ||
485 | |||
486 | switch (sk->sk_protocol) { | ||
487 | case ISDN_P_TE_S0: | ||
488 | case ISDN_P_NT_S0: | ||
489 | case ISDN_P_TE_E1: | ||
490 | case ISDN_P_NT_E1: | ||
491 | mISDN_sock_unlink(&data_sockets, sk); | ||
492 | err = connect_layer1(_pms(sk)->dev, &_pms(sk)->ch, | ||
493 | sk->sk_protocol, maddr); | ||
494 | if (err) | ||
495 | mISDN_sock_link(&data_sockets, sk); | ||
496 | break; | ||
497 | case ISDN_P_LAPD_TE: | ||
498 | case ISDN_P_LAPD_NT: | ||
499 | err = create_l2entity(_pms(sk)->dev, &_pms(sk)->ch, | ||
500 | sk->sk_protocol, maddr); | ||
501 | break; | ||
502 | case ISDN_P_B_RAW: | ||
503 | case ISDN_P_B_HDLC: | ||
504 | case ISDN_P_B_X75SLP: | ||
505 | case ISDN_P_B_L2DTMF: | ||
506 | case ISDN_P_B_L2DSP: | ||
507 | case ISDN_P_B_L2DSPHDLC: | ||
508 | err = connect_Bstack(_pms(sk)->dev, &_pms(sk)->ch, | ||
509 | sk->sk_protocol, maddr); | ||
510 | break; | ||
511 | default: | ||
512 | err = -EPROTONOSUPPORT; | ||
513 | } | ||
514 | if (err) | ||
515 | goto done; | ||
516 | sk->sk_state = MISDN_BOUND; | ||
517 | _pms(sk)->ch.protocol = sk->sk_protocol; | ||
518 | |||
519 | done: | ||
520 | release_sock(sk); | ||
521 | return err; | ||
522 | } | ||
523 | |||
524 | static int | ||
525 | data_sock_getname(struct socket *sock, struct sockaddr *addr, | ||
526 | int *addr_len, int peer) | ||
527 | { | ||
528 | struct sockaddr_mISDN *maddr = (struct sockaddr_mISDN *) addr; | ||
529 | struct sock *sk = sock->sk; | ||
530 | |||
531 | if (!_pms(sk)->dev) | ||
532 | return -EBADFD; | ||
533 | |||
534 | lock_sock(sk); | ||
535 | |||
536 | *addr_len = sizeof(*maddr); | ||
537 | maddr->dev = _pms(sk)->dev->id; | ||
538 | maddr->channel = _pms(sk)->ch.nr; | ||
539 | maddr->sapi = _pms(sk)->ch.addr & 0xff; | ||
540 | maddr->tei = (_pms(sk)->ch.addr >> 8) & 0xff; | ||
541 | release_sock(sk); | ||
542 | return 0; | ||
543 | } | ||
544 | |||
545 | static const struct proto_ops data_sock_ops = { | ||
546 | .family = PF_ISDN, | ||
547 | .owner = THIS_MODULE, | ||
548 | .release = data_sock_release, | ||
549 | .ioctl = data_sock_ioctl, | ||
550 | .bind = data_sock_bind, | ||
551 | .getname = data_sock_getname, | ||
552 | .sendmsg = mISDN_sock_sendmsg, | ||
553 | .recvmsg = mISDN_sock_recvmsg, | ||
554 | .poll = datagram_poll, | ||
555 | .listen = sock_no_listen, | ||
556 | .shutdown = sock_no_shutdown, | ||
557 | .setsockopt = data_sock_setsockopt, | ||
558 | .getsockopt = data_sock_getsockopt, | ||
559 | .connect = sock_no_connect, | ||
560 | .socketpair = sock_no_socketpair, | ||
561 | .accept = sock_no_accept, | ||
562 | .mmap = sock_no_mmap | ||
563 | }; | ||
564 | |||
565 | static int | ||
566 | data_sock_create(struct net *net, struct socket *sock, int protocol) | ||
567 | { | ||
568 | struct sock *sk; | ||
569 | |||
570 | if (sock->type != SOCK_DGRAM) | ||
571 | return -ESOCKTNOSUPPORT; | ||
572 | |||
573 | sk = sk_alloc(net, PF_ISDN, GFP_KERNEL, &mISDN_proto); | ||
574 | if (!sk) | ||
575 | return -ENOMEM; | ||
576 | |||
577 | sock_init_data(sock, sk); | ||
578 | |||
579 | sock->ops = &data_sock_ops; | ||
580 | sock->state = SS_UNCONNECTED; | ||
581 | sock_reset_flag(sk, SOCK_ZAPPED); | ||
582 | |||
583 | sk->sk_protocol = protocol; | ||
584 | sk->sk_state = MISDN_OPEN; | ||
585 | mISDN_sock_link(&data_sockets, sk); | ||
586 | |||
587 | return 0; | ||
588 | } | ||
589 | |||
590 | static int | ||
591 | base_sock_release(struct socket *sock) | ||
592 | { | ||
593 | struct sock *sk = sock->sk; | ||
594 | |||
595 | printk(KERN_DEBUG "%s(%p) sk=%p\n", __func__, sock, sk); | ||
596 | if (!sk) | ||
597 | return 0; | ||
598 | |||
599 | mISDN_sock_unlink(&base_sockets, sk); | ||
600 | sock_orphan(sk); | ||
601 | sock_put(sk); | ||
602 | |||
603 | return 0; | ||
604 | } | ||
605 | |||
606 | static int | ||
607 | base_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) | ||
608 | { | ||
609 | int err = 0, id; | ||
610 | struct mISDNdevice *dev; | ||
611 | struct mISDNversion ver; | ||
612 | |||
613 | switch (cmd) { | ||
614 | case IMGETVERSION: | ||
615 | ver.major = MISDN_MAJOR_VERSION; | ||
616 | ver.minor = MISDN_MINOR_VERSION; | ||
617 | ver.release = MISDN_RELEASE; | ||
618 | if (copy_to_user((void __user *)arg, &ver, sizeof(ver))) | ||
619 | err = -EFAULT; | ||
620 | break; | ||
621 | case IMGETCOUNT: | ||
622 | id = get_mdevice_count(); | ||
623 | if (put_user(id, (int __user *)arg)) | ||
624 | err = -EFAULT; | ||
625 | break; | ||
626 | case IMGETDEVINFO: | ||
627 | if (get_user(id, (int __user *)arg)) { | ||
628 | err = -EFAULT; | ||
629 | break; | ||
630 | } | ||
631 | dev = get_mdevice(id); | ||
632 | if (dev) { | ||
633 | struct mISDN_devinfo di; | ||
634 | |||
635 | di.id = dev->id; | ||
636 | di.Dprotocols = dev->Dprotocols; | ||
637 | di.Bprotocols = dev->Bprotocols | get_all_Bprotocols(); | ||
638 | di.protocol = dev->D.protocol; | ||
639 | memcpy(di.channelmap, dev->channelmap, | ||
640 | MISDN_CHMAP_SIZE * 4); | ||
641 | di.nrbchan = dev->nrbchan; | ||
642 | strcpy(di.name, dev->name); | ||
643 | if (copy_to_user((void __user *)arg, &di, sizeof(di))) | ||
644 | err = -EFAULT; | ||
645 | } else | ||
646 | err = -ENODEV; | ||
647 | break; | ||
648 | default: | ||
649 | err = -EINVAL; | ||
650 | } | ||
651 | return err; | ||
652 | } | ||
653 | |||
654 | static int | ||
655 | base_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_len) | ||
656 | { | ||
657 | struct sockaddr_mISDN *maddr = (struct sockaddr_mISDN *) addr; | ||
658 | struct sock *sk = sock->sk; | ||
659 | int err = 0; | ||
660 | |||
661 | if (!maddr || maddr->family != AF_ISDN) | ||
662 | return -EINVAL; | ||
663 | |||
664 | lock_sock(sk); | ||
665 | |||
666 | if (_pms(sk)->dev) { | ||
667 | err = -EALREADY; | ||
668 | goto done; | ||
669 | } | ||
670 | |||
671 | _pms(sk)->dev = get_mdevice(maddr->dev); | ||
672 | if (!_pms(sk)->dev) { | ||
673 | err = -ENODEV; | ||
674 | goto done; | ||
675 | } | ||
676 | sk->sk_state = MISDN_BOUND; | ||
677 | |||
678 | done: | ||
679 | release_sock(sk); | ||
680 | return err; | ||
681 | } | ||
682 | |||
683 | static const struct proto_ops base_sock_ops = { | ||
684 | .family = PF_ISDN, | ||
685 | .owner = THIS_MODULE, | ||
686 | .release = base_sock_release, | ||
687 | .ioctl = base_sock_ioctl, | ||
688 | .bind = base_sock_bind, | ||
689 | .getname = sock_no_getname, | ||
690 | .sendmsg = sock_no_sendmsg, | ||
691 | .recvmsg = sock_no_recvmsg, | ||
692 | .poll = sock_no_poll, | ||
693 | .listen = sock_no_listen, | ||
694 | .shutdown = sock_no_shutdown, | ||
695 | .setsockopt = sock_no_setsockopt, | ||
696 | .getsockopt = sock_no_getsockopt, | ||
697 | .connect = sock_no_connect, | ||
698 | .socketpair = sock_no_socketpair, | ||
699 | .accept = sock_no_accept, | ||
700 | .mmap = sock_no_mmap | ||
701 | }; | ||
702 | |||
703 | |||
704 | static int | ||
705 | base_sock_create(struct net *net, struct socket *sock, int protocol) | ||
706 | { | ||
707 | struct sock *sk; | ||
708 | |||
709 | if (sock->type != SOCK_RAW) | ||
710 | return -ESOCKTNOSUPPORT; | ||
711 | |||
712 | sk = sk_alloc(net, PF_ISDN, GFP_KERNEL, &mISDN_proto); | ||
713 | if (!sk) | ||
714 | return -ENOMEM; | ||
715 | |||
716 | sock_init_data(sock, sk); | ||
717 | sock->ops = &base_sock_ops; | ||
718 | sock->state = SS_UNCONNECTED; | ||
719 | sock_reset_flag(sk, SOCK_ZAPPED); | ||
720 | sk->sk_protocol = protocol; | ||
721 | sk->sk_state = MISDN_OPEN; | ||
722 | mISDN_sock_link(&base_sockets, sk); | ||
723 | |||
724 | return 0; | ||
725 | } | ||
726 | |||
727 | static int | ||
728 | mISDN_sock_create(struct net *net, struct socket *sock, int proto) | ||
729 | { | ||
730 | int err = -EPROTONOSUPPORT; | ||
731 | |||
732 | switch (proto) { | ||
733 | case ISDN_P_BASE: | ||
734 | err = base_sock_create(net, sock, proto); | ||
735 | break; | ||
736 | case ISDN_P_TE_S0: | ||
737 | case ISDN_P_NT_S0: | ||
738 | case ISDN_P_TE_E1: | ||
739 | case ISDN_P_NT_E1: | ||
740 | case ISDN_P_LAPD_TE: | ||
741 | case ISDN_P_LAPD_NT: | ||
742 | case ISDN_P_B_RAW: | ||
743 | case ISDN_P_B_HDLC: | ||
744 | case ISDN_P_B_X75SLP: | ||
745 | case ISDN_P_B_L2DTMF: | ||
746 | case ISDN_P_B_L2DSP: | ||
747 | case ISDN_P_B_L2DSPHDLC: | ||
748 | err = data_sock_create(net, sock, proto); | ||
749 | break; | ||
750 | default: | ||
751 | return err; | ||
752 | } | ||
753 | |||
754 | return err; | ||
755 | } | ||
756 | |||
757 | static struct | ||
758 | net_proto_family mISDN_sock_family_ops = { | ||
759 | .owner = THIS_MODULE, | ||
760 | .family = PF_ISDN, | ||
761 | .create = mISDN_sock_create, | ||
762 | }; | ||
763 | |||
764 | int | ||
765 | misdn_sock_init(u_int *deb) | ||
766 | { | ||
767 | int err; | ||
768 | |||
769 | debug = deb; | ||
770 | err = sock_register(&mISDN_sock_family_ops); | ||
771 | if (err) | ||
772 | printk(KERN_ERR "%s: error(%d)\n", __func__, err); | ||
773 | return err; | ||
774 | } | ||
775 | |||
776 | void | ||
777 | misdn_sock_cleanup(void) | ||
778 | { | ||
779 | sock_unregister(PF_ISDN); | ||
780 | } | ||
781 | |||
diff --git a/drivers/isdn/mISDN/stack.c b/drivers/isdn/mISDN/stack.c new file mode 100644 index 000000000000..54cfddcc4784 --- /dev/null +++ b/drivers/isdn/mISDN/stack.c | |||
@@ -0,0 +1,674 @@ | |||
1 | /* | ||
2 | * | ||
3 | * Author Karsten Keil <kkeil@novell.com> | ||
4 | * | ||
5 | * Copyright 2008 by Karsten Keil <kkeil@novell.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | */ | ||
17 | |||
18 | #include <linux/mISDNif.h> | ||
19 | #include <linux/kthread.h> | ||
20 | #include "core.h" | ||
21 | |||
22 | static u_int *debug; | ||
23 | |||
24 | static inline void | ||
25 | _queue_message(struct mISDNstack *st, struct sk_buff *skb) | ||
26 | { | ||
27 | struct mISDNhead *hh = mISDN_HEAD_P(skb); | ||
28 | |||
29 | if (*debug & DEBUG_QUEUE_FUNC) | ||
30 | printk(KERN_DEBUG "%s prim(%x) id(%x) %p\n", | ||
31 | __func__, hh->prim, hh->id, skb); | ||
32 | skb_queue_tail(&st->msgq, skb); | ||
33 | if (likely(!test_bit(mISDN_STACK_STOPPED, &st->status))) { | ||
34 | test_and_set_bit(mISDN_STACK_WORK, &st->status); | ||
35 | wake_up_interruptible(&st->workq); | ||
36 | } | ||
37 | } | ||
38 | |||
39 | int | ||
40 | mISDN_queue_message(struct mISDNchannel *ch, struct sk_buff *skb) | ||
41 | { | ||
42 | _queue_message(ch->st, skb); | ||
43 | return 0; | ||
44 | } | ||
45 | |||
46 | static struct mISDNchannel * | ||
47 | get_channel4id(struct mISDNstack *st, u_int id) | ||
48 | { | ||
49 | struct mISDNchannel *ch; | ||
50 | |||
51 | mutex_lock(&st->lmutex); | ||
52 | list_for_each_entry(ch, &st->layer2, list) { | ||
53 | if (id == ch->nr) | ||
54 | goto unlock; | ||
55 | } | ||
56 | ch = NULL; | ||
57 | unlock: | ||
58 | mutex_unlock(&st->lmutex); | ||
59 | return ch; | ||
60 | } | ||
61 | |||
62 | static void | ||
63 | send_socklist(struct mISDN_sock_list *sl, struct sk_buff *skb) | ||
64 | { | ||
65 | struct hlist_node *node; | ||
66 | struct sock *sk; | ||
67 | struct sk_buff *cskb = NULL; | ||
68 | |||
69 | read_lock(&sl->lock); | ||
70 | sk_for_each(sk, node, &sl->head) { | ||
71 | if (sk->sk_state != MISDN_BOUND) | ||
72 | continue; | ||
73 | if (!cskb) | ||
74 | cskb = skb_copy(skb, GFP_KERNEL); | ||
75 | if (!cskb) { | ||
76 | printk(KERN_WARNING "%s no skb\n", __func__); | ||
77 | break; | ||
78 | } | ||
79 | if (!sock_queue_rcv_skb(sk, cskb)) | ||
80 | cskb = NULL; | ||
81 | } | ||
82 | read_unlock(&sl->lock); | ||
83 | if (cskb) | ||
84 | dev_kfree_skb(cskb); | ||
85 | } | ||
86 | |||
87 | static void | ||
88 | send_layer2(struct mISDNstack *st, struct sk_buff *skb) | ||
89 | { | ||
90 | struct sk_buff *cskb; | ||
91 | struct mISDNhead *hh = mISDN_HEAD_P(skb); | ||
92 | struct mISDNchannel *ch; | ||
93 | int ret; | ||
94 | |||
95 | if (!st) | ||
96 | return; | ||
97 | mutex_lock(&st->lmutex); | ||
98 | if ((hh->id & MISDN_ID_ADDR_MASK) == MISDN_ID_ANY) { /* L2 for all */ | ||
99 | list_for_each_entry(ch, &st->layer2, list) { | ||
100 | if (list_is_last(&ch->list, &st->layer2)) { | ||
101 | cskb = skb; | ||
102 | skb = NULL; | ||
103 | } else { | ||
104 | cskb = skb_copy(skb, GFP_KERNEL); | ||
105 | } | ||
106 | if (cskb) { | ||
107 | ret = ch->send(ch, cskb); | ||
108 | if (ret) { | ||
109 | if (*debug & DEBUG_SEND_ERR) | ||
110 | printk(KERN_DEBUG | ||
111 | "%s ch%d prim(%x) addr(%x)" | ||
112 | " err %d\n", | ||
113 | __func__, ch->nr, | ||
114 | hh->prim, ch->addr, ret); | ||
115 | dev_kfree_skb(cskb); | ||
116 | } | ||
117 | } else { | ||
118 | printk(KERN_WARNING "%s ch%d addr %x no mem\n", | ||
119 | __func__, ch->nr, ch->addr); | ||
120 | goto out; | ||
121 | } | ||
122 | } | ||
123 | } else { | ||
124 | list_for_each_entry(ch, &st->layer2, list) { | ||
125 | if ((hh->id & MISDN_ID_ADDR_MASK) == ch->addr) { | ||
126 | ret = ch->send(ch, skb); | ||
127 | if (!ret) | ||
128 | skb = NULL; | ||
129 | goto out; | ||
130 | } | ||
131 | } | ||
132 | ret = st->dev->teimgr->ctrl(st->dev->teimgr, CHECK_DATA, skb); | ||
133 | if (!ret) | ||
134 | skb = NULL; | ||
135 | else if (*debug & DEBUG_SEND_ERR) | ||
136 | printk(KERN_DEBUG | ||
137 | "%s ch%d mgr prim(%x) addr(%x) err %d\n", | ||
138 | __func__, ch->nr, hh->prim, ch->addr, ret); | ||
139 | } | ||
140 | out: | ||
141 | mutex_unlock(&st->lmutex); | ||
142 | if (skb) | ||
143 | dev_kfree_skb(skb); | ||
144 | } | ||
145 | |||
146 | static inline int | ||
147 | send_msg_to_layer(struct mISDNstack *st, struct sk_buff *skb) | ||
148 | { | ||
149 | struct mISDNhead *hh = mISDN_HEAD_P(skb); | ||
150 | struct mISDNchannel *ch; | ||
151 | int lm; | ||
152 | |||
153 | lm = hh->prim & MISDN_LAYERMASK; | ||
154 | if (*debug & DEBUG_QUEUE_FUNC) | ||
155 | printk(KERN_DEBUG "%s prim(%x) id(%x) %p\n", | ||
156 | __func__, hh->prim, hh->id, skb); | ||
157 | if (lm == 0x1) { | ||
158 | if (!hlist_empty(&st->l1sock.head)) { | ||
159 | __net_timestamp(skb); | ||
160 | send_socklist(&st->l1sock, skb); | ||
161 | } | ||
162 | return st->layer1->send(st->layer1, skb); | ||
163 | } else if (lm == 0x2) { | ||
164 | if (!hlist_empty(&st->l1sock.head)) | ||
165 | send_socklist(&st->l1sock, skb); | ||
166 | send_layer2(st, skb); | ||
167 | return 0; | ||
168 | } else if (lm == 0x4) { | ||
169 | ch = get_channel4id(st, hh->id); | ||
170 | if (ch) | ||
171 | return ch->send(ch, skb); | ||
172 | else | ||
173 | printk(KERN_WARNING | ||
174 | "%s: dev(%s) prim(%x) id(%x) no channel\n", | ||
175 | __func__, st->dev->name, hh->prim, hh->id); | ||
176 | } else if (lm == 0x8) { | ||
177 | WARN_ON(lm == 0x8); | ||
178 | ch = get_channel4id(st, hh->id); | ||
179 | if (ch) | ||
180 | return ch->send(ch, skb); | ||
181 | else | ||
182 | printk(KERN_WARNING | ||
183 | "%s: dev(%s) prim(%x) id(%x) no channel\n", | ||
184 | __func__, st->dev->name, hh->prim, hh->id); | ||
185 | } else { | ||
186 | /* broadcast not handled yet */ | ||
187 | printk(KERN_WARNING "%s: dev(%s) prim %x not delivered\n", | ||
188 | __func__, st->dev->name, hh->prim); | ||
189 | } | ||
190 | return -ESRCH; | ||
191 | } | ||
192 | |||
193 | static void | ||
194 | do_clear_stack(struct mISDNstack *st) | ||
195 | { | ||
196 | } | ||
197 | |||
198 | static int | ||
199 | mISDNStackd(void *data) | ||
200 | { | ||
201 | struct mISDNstack *st = data; | ||
202 | int err = 0; | ||
203 | |||
204 | #ifdef CONFIG_SMP | ||
205 | lock_kernel(); | ||
206 | #endif | ||
207 | sigfillset(¤t->blocked); | ||
208 | #ifdef CONFIG_SMP | ||
209 | unlock_kernel(); | ||
210 | #endif | ||
211 | if (*debug & DEBUG_MSG_THREAD) | ||
212 | printk(KERN_DEBUG "mISDNStackd %s started\n", st->dev->name); | ||
213 | |||
214 | if (st->notify != NULL) { | ||
215 | complete(st->notify); | ||
216 | st->notify = NULL; | ||
217 | } | ||
218 | |||
219 | for (;;) { | ||
220 | struct sk_buff *skb; | ||
221 | |||
222 | if (unlikely(test_bit(mISDN_STACK_STOPPED, &st->status))) { | ||
223 | test_and_clear_bit(mISDN_STACK_WORK, &st->status); | ||
224 | test_and_clear_bit(mISDN_STACK_RUNNING, &st->status); | ||
225 | } else | ||
226 | test_and_set_bit(mISDN_STACK_RUNNING, &st->status); | ||
227 | while (test_bit(mISDN_STACK_WORK, &st->status)) { | ||
228 | skb = skb_dequeue(&st->msgq); | ||
229 | if (!skb) { | ||
230 | test_and_clear_bit(mISDN_STACK_WORK, | ||
231 | &st->status); | ||
232 | /* test if a race happens */ | ||
233 | skb = skb_dequeue(&st->msgq); | ||
234 | if (!skb) | ||
235 | continue; | ||
236 | test_and_set_bit(mISDN_STACK_WORK, | ||
237 | &st->status); | ||
238 | } | ||
239 | #ifdef MISDN_MSG_STATS | ||
240 | st->msg_cnt++; | ||
241 | #endif | ||
242 | err = send_msg_to_layer(st, skb); | ||
243 | if (unlikely(err)) { | ||
244 | if (*debug & DEBUG_SEND_ERR) | ||
245 | printk(KERN_DEBUG | ||
246 | "%s: %s prim(%x) id(%x) " | ||
247 | "send call(%d)\n", | ||
248 | __func__, st->dev->name, | ||
249 | mISDN_HEAD_PRIM(skb), | ||
250 | mISDN_HEAD_ID(skb), err); | ||
251 | dev_kfree_skb(skb); | ||
252 | continue; | ||
253 | } | ||
254 | if (unlikely(test_bit(mISDN_STACK_STOPPED, | ||
255 | &st->status))) { | ||
256 | test_and_clear_bit(mISDN_STACK_WORK, | ||
257 | &st->status); | ||
258 | test_and_clear_bit(mISDN_STACK_RUNNING, | ||
259 | &st->status); | ||
260 | break; | ||
261 | } | ||
262 | } | ||
263 | if (test_bit(mISDN_STACK_CLEARING, &st->status)) { | ||
264 | test_and_set_bit(mISDN_STACK_STOPPED, &st->status); | ||
265 | test_and_clear_bit(mISDN_STACK_RUNNING, &st->status); | ||
266 | do_clear_stack(st); | ||
267 | test_and_clear_bit(mISDN_STACK_CLEARING, &st->status); | ||
268 | test_and_set_bit(mISDN_STACK_RESTART, &st->status); | ||
269 | } | ||
270 | if (test_and_clear_bit(mISDN_STACK_RESTART, &st->status)) { | ||
271 | test_and_clear_bit(mISDN_STACK_STOPPED, &st->status); | ||
272 | test_and_set_bit(mISDN_STACK_RUNNING, &st->status); | ||
273 | if (!skb_queue_empty(&st->msgq)) | ||
274 | test_and_set_bit(mISDN_STACK_WORK, | ||
275 | &st->status); | ||
276 | } | ||
277 | if (test_bit(mISDN_STACK_ABORT, &st->status)) | ||
278 | break; | ||
279 | if (st->notify != NULL) { | ||
280 | complete(st->notify); | ||
281 | st->notify = NULL; | ||
282 | } | ||
283 | #ifdef MISDN_MSG_STATS | ||
284 | st->sleep_cnt++; | ||
285 | #endif | ||
286 | test_and_clear_bit(mISDN_STACK_ACTIVE, &st->status); | ||
287 | wait_event_interruptible(st->workq, (st->status & | ||
288 | mISDN_STACK_ACTION_MASK)); | ||
289 | if (*debug & DEBUG_MSG_THREAD) | ||
290 | printk(KERN_DEBUG "%s: %s wake status %08lx\n", | ||
291 | __func__, st->dev->name, st->status); | ||
292 | test_and_set_bit(mISDN_STACK_ACTIVE, &st->status); | ||
293 | |||
294 | test_and_clear_bit(mISDN_STACK_WAKEUP, &st->status); | ||
295 | |||
296 | if (test_bit(mISDN_STACK_STOPPED, &st->status)) { | ||
297 | test_and_clear_bit(mISDN_STACK_RUNNING, &st->status); | ||
298 | #ifdef MISDN_MSG_STATS | ||
299 | st->stopped_cnt++; | ||
300 | #endif | ||
301 | } | ||
302 | } | ||
303 | #ifdef MISDN_MSG_STATS | ||
304 | printk(KERN_DEBUG "mISDNStackd daemon for %s proceed %d " | ||
305 | "msg %d sleep %d stopped\n", | ||
306 | st->dev->name, st->msg_cnt, st->sleep_cnt, st->stopped_cnt); | ||
307 | printk(KERN_DEBUG | ||
308 | "mISDNStackd daemon for %s utime(%ld) stime(%ld)\n", | ||
309 | st->dev->name, st->thread->utime, st->thread->stime); | ||
310 | printk(KERN_DEBUG | ||
311 | "mISDNStackd daemon for %s nvcsw(%ld) nivcsw(%ld)\n", | ||
312 | st->dev->name, st->thread->nvcsw, st->thread->nivcsw); | ||
313 | printk(KERN_DEBUG "mISDNStackd daemon for %s killed now\n", | ||
314 | st->dev->name); | ||
315 | #endif | ||
316 | test_and_set_bit(mISDN_STACK_KILLED, &st->status); | ||
317 | test_and_clear_bit(mISDN_STACK_RUNNING, &st->status); | ||
318 | test_and_clear_bit(mISDN_STACK_ACTIVE, &st->status); | ||
319 | test_and_clear_bit(mISDN_STACK_ABORT, &st->status); | ||
320 | skb_queue_purge(&st->msgq); | ||
321 | st->thread = NULL; | ||
322 | if (st->notify != NULL) { | ||
323 | complete(st->notify); | ||
324 | st->notify = NULL; | ||
325 | } | ||
326 | return 0; | ||
327 | } | ||
328 | |||
329 | static int | ||
330 | l1_receive(struct mISDNchannel *ch, struct sk_buff *skb) | ||
331 | { | ||
332 | if (!ch->st) | ||
333 | return -ENODEV; | ||
334 | __net_timestamp(skb); | ||
335 | _queue_message(ch->st, skb); | ||
336 | return 0; | ||
337 | } | ||
338 | |||
339 | void | ||
340 | set_channel_address(struct mISDNchannel *ch, u_int sapi, u_int tei) | ||
341 | { | ||
342 | ch->addr = sapi | (tei << 8); | ||
343 | } | ||
344 | |||
345 | void | ||
346 | __add_layer2(struct mISDNchannel *ch, struct mISDNstack *st) | ||
347 | { | ||
348 | list_add_tail(&ch->list, &st->layer2); | ||
349 | } | ||
350 | |||
351 | void | ||
352 | add_layer2(struct mISDNchannel *ch, struct mISDNstack *st) | ||
353 | { | ||
354 | mutex_lock(&st->lmutex); | ||
355 | __add_layer2(ch, st); | ||
356 | mutex_unlock(&st->lmutex); | ||
357 | } | ||
358 | |||
359 | static int | ||
360 | st_own_ctrl(struct mISDNchannel *ch, u_int cmd, void *arg) | ||
361 | { | ||
362 | if (!ch->st || ch->st->layer1) | ||
363 | return -EINVAL; | ||
364 | return ch->st->layer1->ctrl(ch->st->layer1, cmd, arg); | ||
365 | } | ||
366 | |||
367 | int | ||
368 | create_stack(struct mISDNdevice *dev) | ||
369 | { | ||
370 | struct mISDNstack *newst; | ||
371 | int err; | ||
372 | DECLARE_COMPLETION_ONSTACK(done); | ||
373 | |||
374 | newst = kzalloc(sizeof(struct mISDNstack), GFP_KERNEL); | ||
375 | if (!newst) { | ||
376 | printk(KERN_ERR "kmalloc mISDN_stack failed\n"); | ||
377 | return -ENOMEM; | ||
378 | } | ||
379 | newst->dev = dev; | ||
380 | INIT_LIST_HEAD(&newst->layer2); | ||
381 | INIT_HLIST_HEAD(&newst->l1sock.head); | ||
382 | rwlock_init(&newst->l1sock.lock); | ||
383 | init_waitqueue_head(&newst->workq); | ||
384 | skb_queue_head_init(&newst->msgq); | ||
385 | mutex_init(&newst->lmutex); | ||
386 | dev->D.st = newst; | ||
387 | err = create_teimanager(dev); | ||
388 | if (err) { | ||
389 | printk(KERN_ERR "kmalloc teimanager failed\n"); | ||
390 | kfree(newst); | ||
391 | return err; | ||
392 | } | ||
393 | dev->teimgr->peer = &newst->own; | ||
394 | dev->teimgr->recv = mISDN_queue_message; | ||
395 | dev->teimgr->st = newst; | ||
396 | newst->layer1 = &dev->D; | ||
397 | dev->D.recv = l1_receive; | ||
398 | dev->D.peer = &newst->own; | ||
399 | newst->own.st = newst; | ||
400 | newst->own.ctrl = st_own_ctrl; | ||
401 | newst->own.send = mISDN_queue_message; | ||
402 | newst->own.recv = mISDN_queue_message; | ||
403 | if (*debug & DEBUG_CORE_FUNC) | ||
404 | printk(KERN_DEBUG "%s: st(%s)\n", __func__, newst->dev->name); | ||
405 | newst->notify = &done; | ||
406 | newst->thread = kthread_run(mISDNStackd, (void *)newst, "mISDN_%s", | ||
407 | newst->dev->name); | ||
408 | if (IS_ERR(newst->thread)) { | ||
409 | err = PTR_ERR(newst->thread); | ||
410 | printk(KERN_ERR | ||
411 | "mISDN:cannot create kernel thread for %s (%d)\n", | ||
412 | newst->dev->name, err); | ||
413 | delete_teimanager(dev->teimgr); | ||
414 | kfree(newst); | ||
415 | } else | ||
416 | wait_for_completion(&done); | ||
417 | return err; | ||
418 | } | ||
419 | |||
420 | int | ||
421 | connect_layer1(struct mISDNdevice *dev, struct mISDNchannel *ch, | ||
422 | u_int protocol, struct sockaddr_mISDN *adr) | ||
423 | { | ||
424 | struct mISDN_sock *msk = container_of(ch, struct mISDN_sock, ch); | ||
425 | struct channel_req rq; | ||
426 | int err; | ||
427 | |||
428 | |||
429 | if (*debug & DEBUG_CORE_FUNC) | ||
430 | printk(KERN_DEBUG "%s: %s proto(%x) adr(%d %d %d %d)\n", | ||
431 | __func__, dev->name, protocol, adr->dev, adr->channel, | ||
432 | adr->sapi, adr->tei); | ||
433 | switch (protocol) { | ||
434 | case ISDN_P_NT_S0: | ||
435 | case ISDN_P_NT_E1: | ||
436 | case ISDN_P_TE_S0: | ||
437 | case ISDN_P_TE_E1: | ||
438 | #ifdef PROTOCOL_CHECK | ||
439 | /* this should be enhanced */ | ||
440 | if (!list_empty(&dev->D.st->layer2) | ||
441 | && dev->D.protocol != protocol) | ||
442 | return -EBUSY; | ||
443 | if (!hlist_empty(&dev->D.st->l1sock.head) | ||
444 | && dev->D.protocol != protocol) | ||
445 | return -EBUSY; | ||
446 | #endif | ||
447 | ch->recv = mISDN_queue_message; | ||
448 | ch->peer = &dev->D.st->own; | ||
449 | ch->st = dev->D.st; | ||
450 | rq.protocol = protocol; | ||
451 | rq.adr.channel = 0; | ||
452 | err = dev->D.ctrl(&dev->D, OPEN_CHANNEL, &rq); | ||
453 | printk(KERN_DEBUG "%s: ret 1 %d\n", __func__, err); | ||
454 | if (err) | ||
455 | return err; | ||
456 | write_lock_bh(&dev->D.st->l1sock.lock); | ||
457 | sk_add_node(&msk->sk, &dev->D.st->l1sock.head); | ||
458 | write_unlock_bh(&dev->D.st->l1sock.lock); | ||
459 | break; | ||
460 | default: | ||
461 | return -ENOPROTOOPT; | ||
462 | } | ||
463 | return 0; | ||
464 | } | ||
465 | |||
466 | int | ||
467 | connect_Bstack(struct mISDNdevice *dev, struct mISDNchannel *ch, | ||
468 | u_int protocol, struct sockaddr_mISDN *adr) | ||
469 | { | ||
470 | struct channel_req rq, rq2; | ||
471 | int pmask, err; | ||
472 | struct Bprotocol *bp; | ||
473 | |||
474 | if (*debug & DEBUG_CORE_FUNC) | ||
475 | printk(KERN_DEBUG "%s: %s proto(%x) adr(%d %d %d %d)\n", | ||
476 | __func__, dev->name, protocol, | ||
477 | adr->dev, adr->channel, adr->sapi, | ||
478 | adr->tei); | ||
479 | ch->st = dev->D.st; | ||
480 | pmask = 1 << (protocol & ISDN_P_B_MASK); | ||
481 | if (pmask & dev->Bprotocols) { | ||
482 | rq.protocol = protocol; | ||
483 | rq.adr = *adr; | ||
484 | err = dev->D.ctrl(&dev->D, OPEN_CHANNEL, &rq); | ||
485 | if (err) | ||
486 | return err; | ||
487 | ch->recv = rq.ch->send; | ||
488 | ch->peer = rq.ch; | ||
489 | rq.ch->recv = ch->send; | ||
490 | rq.ch->peer = ch; | ||
491 | rq.ch->st = dev->D.st; | ||
492 | } else { | ||
493 | bp = get_Bprotocol4mask(pmask); | ||
494 | if (!bp) | ||
495 | return -ENOPROTOOPT; | ||
496 | rq2.protocol = protocol; | ||
497 | rq2.adr = *adr; | ||
498 | rq2.ch = ch; | ||
499 | err = bp->create(&rq2); | ||
500 | if (err) | ||
501 | return err; | ||
502 | ch->recv = rq2.ch->send; | ||
503 | ch->peer = rq2.ch; | ||
504 | rq2.ch->st = dev->D.st; | ||
505 | rq.protocol = rq2.protocol; | ||
506 | rq.adr = *adr; | ||
507 | err = dev->D.ctrl(&dev->D, OPEN_CHANNEL, &rq); | ||
508 | if (err) { | ||
509 | rq2.ch->ctrl(rq2.ch, CLOSE_CHANNEL, NULL); | ||
510 | return err; | ||
511 | } | ||
512 | rq2.ch->recv = rq.ch->send; | ||
513 | rq2.ch->peer = rq.ch; | ||
514 | rq.ch->recv = rq2.ch->send; | ||
515 | rq.ch->peer = rq2.ch; | ||
516 | rq.ch->st = dev->D.st; | ||
517 | } | ||
518 | ch->protocol = protocol; | ||
519 | ch->nr = rq.ch->nr; | ||
520 | return 0; | ||
521 | } | ||
522 | |||
523 | int | ||
524 | create_l2entity(struct mISDNdevice *dev, struct mISDNchannel *ch, | ||
525 | u_int protocol, struct sockaddr_mISDN *adr) | ||
526 | { | ||
527 | struct channel_req rq; | ||
528 | int err; | ||
529 | |||
530 | if (*debug & DEBUG_CORE_FUNC) | ||
531 | printk(KERN_DEBUG "%s: %s proto(%x) adr(%d %d %d %d)\n", | ||
532 | __func__, dev->name, protocol, | ||
533 | adr->dev, adr->channel, adr->sapi, | ||
534 | adr->tei); | ||
535 | rq.protocol = ISDN_P_TE_S0; | ||
536 | if (dev->Dprotocols & (1 << ISDN_P_TE_E1)) | ||
537 | rq.protocol = ISDN_P_TE_E1; | ||
538 | switch (protocol) { | ||
539 | case ISDN_P_LAPD_NT: | ||
540 | rq.protocol = ISDN_P_NT_S0; | ||
541 | if (dev->Dprotocols & (1 << ISDN_P_NT_E1)) | ||
542 | rq.protocol = ISDN_P_NT_E1; | ||
543 | case ISDN_P_LAPD_TE: | ||
544 | #ifdef PROTOCOL_CHECK | ||
545 | /* this should be enhanced */ | ||
546 | if (!list_empty(&dev->D.st->layer2) | ||
547 | && dev->D.protocol != protocol) | ||
548 | return -EBUSY; | ||
549 | if (!hlist_empty(&dev->D.st->l1sock.head) | ||
550 | && dev->D.protocol != protocol) | ||
551 | return -EBUSY; | ||
552 | #endif | ||
553 | ch->recv = mISDN_queue_message; | ||
554 | ch->peer = &dev->D.st->own; | ||
555 | ch->st = dev->D.st; | ||
556 | rq.adr.channel = 0; | ||
557 | err = dev->D.ctrl(&dev->D, OPEN_CHANNEL, &rq); | ||
558 | printk(KERN_DEBUG "%s: ret 1 %d\n", __func__, err); | ||
559 | if (err) | ||
560 | break; | ||
561 | rq.protocol = protocol; | ||
562 | rq.adr = *adr; | ||
563 | rq.ch = ch; | ||
564 | err = dev->teimgr->ctrl(dev->teimgr, OPEN_CHANNEL, &rq); | ||
565 | printk(KERN_DEBUG "%s: ret 2 %d\n", __func__, err); | ||
566 | if (!err) { | ||
567 | if ((protocol == ISDN_P_LAPD_NT) && !rq.ch) | ||
568 | break; | ||
569 | add_layer2(rq.ch, dev->D.st); | ||
570 | rq.ch->recv = mISDN_queue_message; | ||
571 | rq.ch->peer = &dev->D.st->own; | ||
572 | rq.ch->ctrl(rq.ch, OPEN_CHANNEL, NULL); /* can't fail */ | ||
573 | } | ||
574 | break; | ||
575 | default: | ||
576 | err = -EPROTONOSUPPORT; | ||
577 | } | ||
578 | return err; | ||
579 | } | ||
580 | |||
581 | void | ||
582 | delete_channel(struct mISDNchannel *ch) | ||
583 | { | ||
584 | struct mISDN_sock *msk = container_of(ch, struct mISDN_sock, ch); | ||
585 | struct mISDNchannel *pch; | ||
586 | |||
587 | if (!ch->st) { | ||
588 | printk(KERN_WARNING "%s: no stack\n", __func__); | ||
589 | return; | ||
590 | } | ||
591 | if (*debug & DEBUG_CORE_FUNC) | ||
592 | printk(KERN_DEBUG "%s: st(%s) protocol(%x)\n", __func__, | ||
593 | ch->st->dev->name, ch->protocol); | ||
594 | if (ch->protocol >= ISDN_P_B_START) { | ||
595 | if (ch->peer) { | ||
596 | ch->peer->ctrl(ch->peer, CLOSE_CHANNEL, NULL); | ||
597 | ch->peer = NULL; | ||
598 | } | ||
599 | return; | ||
600 | } | ||
601 | switch (ch->protocol) { | ||
602 | case ISDN_P_NT_S0: | ||
603 | case ISDN_P_TE_S0: | ||
604 | case ISDN_P_NT_E1: | ||
605 | case ISDN_P_TE_E1: | ||
606 | write_lock_bh(&ch->st->l1sock.lock); | ||
607 | sk_del_node_init(&msk->sk); | ||
608 | write_unlock_bh(&ch->st->l1sock.lock); | ||
609 | ch->st->dev->D.ctrl(&ch->st->dev->D, CLOSE_CHANNEL, NULL); | ||
610 | break; | ||
611 | case ISDN_P_LAPD_TE: | ||
612 | pch = get_channel4id(ch->st, ch->nr); | ||
613 | if (pch) { | ||
614 | mutex_lock(&ch->st->lmutex); | ||
615 | list_del(&pch->list); | ||
616 | mutex_unlock(&ch->st->lmutex); | ||
617 | pch->ctrl(pch, CLOSE_CHANNEL, NULL); | ||
618 | pch = ch->st->dev->teimgr; | ||
619 | pch->ctrl(pch, CLOSE_CHANNEL, NULL); | ||
620 | } else | ||
621 | printk(KERN_WARNING "%s: no l2 channel\n", | ||
622 | __func__); | ||
623 | break; | ||
624 | case ISDN_P_LAPD_NT: | ||
625 | pch = ch->st->dev->teimgr; | ||
626 | if (pch) { | ||
627 | pch->ctrl(pch, CLOSE_CHANNEL, NULL); | ||
628 | } else | ||
629 | printk(KERN_WARNING "%s: no l2 channel\n", | ||
630 | __func__); | ||
631 | break; | ||
632 | default: | ||
633 | break; | ||
634 | } | ||
635 | return; | ||
636 | } | ||
637 | |||
638 | void | ||
639 | delete_stack(struct mISDNdevice *dev) | ||
640 | { | ||
641 | struct mISDNstack *st = dev->D.st; | ||
642 | DECLARE_COMPLETION_ONSTACK(done); | ||
643 | |||
644 | if (*debug & DEBUG_CORE_FUNC) | ||
645 | printk(KERN_DEBUG "%s: st(%s)\n", __func__, | ||
646 | st->dev->name); | ||
647 | if (dev->teimgr) | ||
648 | delete_teimanager(dev->teimgr); | ||
649 | if (st->thread) { | ||
650 | if (st->notify) { | ||
651 | printk(KERN_WARNING "%s: notifier in use\n", | ||
652 | __func__); | ||
653 | complete(st->notify); | ||
654 | } | ||
655 | st->notify = &done; | ||
656 | test_and_set_bit(mISDN_STACK_ABORT, &st->status); | ||
657 | test_and_set_bit(mISDN_STACK_WAKEUP, &st->status); | ||
658 | wake_up_interruptible(&st->workq); | ||
659 | wait_for_completion(&done); | ||
660 | } | ||
661 | if (!list_empty(&st->layer2)) | ||
662 | printk(KERN_WARNING "%s: layer2 list not empty\n", | ||
663 | __func__); | ||
664 | if (!hlist_empty(&st->l1sock.head)) | ||
665 | printk(KERN_WARNING "%s: layer1 list not empty\n", | ||
666 | __func__); | ||
667 | kfree(st); | ||
668 | } | ||
669 | |||
670 | void | ||
671 | mISDN_initstack(u_int *dp) | ||
672 | { | ||
673 | debug = dp; | ||
674 | } | ||
diff --git a/drivers/isdn/mISDN/tei.c b/drivers/isdn/mISDN/tei.c new file mode 100644 index 000000000000..56a76a0ffddd --- /dev/null +++ b/drivers/isdn/mISDN/tei.c | |||
@@ -0,0 +1,1340 @@ | |||
1 | /* | ||
2 | * | ||
3 | * Author Karsten Keil <kkeil@novell.com> | ||
4 | * | ||
5 | * Copyright 2008 by Karsten Keil <kkeil@novell.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | */ | ||
17 | #include "layer2.h" | ||
18 | #include <linux/random.h> | ||
19 | #include "core.h" | ||
20 | |||
21 | #define ID_REQUEST 1 | ||
22 | #define ID_ASSIGNED 2 | ||
23 | #define ID_DENIED 3 | ||
24 | #define ID_CHK_REQ 4 | ||
25 | #define ID_CHK_RES 5 | ||
26 | #define ID_REMOVE 6 | ||
27 | #define ID_VERIFY 7 | ||
28 | |||
29 | #define TEI_ENTITY_ID 0xf | ||
30 | |||
31 | #define MGR_PH_ACTIVE 16 | ||
32 | #define MGR_PH_NOTREADY 17 | ||
33 | |||
34 | #define DATIMER_VAL 10000 | ||
35 | |||
36 | static u_int *debug; | ||
37 | |||
38 | static struct Fsm deactfsm = {NULL, 0, 0, NULL, NULL}; | ||
39 | static struct Fsm teifsmu = {NULL, 0, 0, NULL, NULL}; | ||
40 | static struct Fsm teifsmn = {NULL, 0, 0, NULL, NULL}; | ||
41 | |||
42 | enum { | ||
43 | ST_L1_DEACT, | ||
44 | ST_L1_DEACT_PENDING, | ||
45 | ST_L1_ACTIV, | ||
46 | }; | ||
47 | #define DEACT_STATE_COUNT (ST_L1_ACTIV+1) | ||
48 | |||
49 | static char *strDeactState[] = | ||
50 | { | ||
51 | "ST_L1_DEACT", | ||
52 | "ST_L1_DEACT_PENDING", | ||
53 | "ST_L1_ACTIV", | ||
54 | }; | ||
55 | |||
56 | enum { | ||
57 | EV_ACTIVATE, | ||
58 | EV_ACTIVATE_IND, | ||
59 | EV_DEACTIVATE, | ||
60 | EV_DEACTIVATE_IND, | ||
61 | EV_UI, | ||
62 | EV_DATIMER, | ||
63 | }; | ||
64 | |||
65 | #define DEACT_EVENT_COUNT (EV_DATIMER+1) | ||
66 | |||
67 | static char *strDeactEvent[] = | ||
68 | { | ||
69 | "EV_ACTIVATE", | ||
70 | "EV_ACTIVATE_IND", | ||
71 | "EV_DEACTIVATE", | ||
72 | "EV_DEACTIVATE_IND", | ||
73 | "EV_UI", | ||
74 | "EV_DATIMER", | ||
75 | }; | ||
76 | |||
77 | static void | ||
78 | da_debug(struct FsmInst *fi, char *fmt, ...) | ||
79 | { | ||
80 | struct manager *mgr = fi->userdata; | ||
81 | va_list va; | ||
82 | |||
83 | if (!(*debug & DEBUG_L2_TEIFSM)) | ||
84 | return; | ||
85 | va_start(va, fmt); | ||
86 | printk(KERN_DEBUG "mgr(%d): ", mgr->ch.st->dev->id); | ||
87 | vprintk(fmt, va); | ||
88 | printk("\n"); | ||
89 | va_end(va); | ||
90 | } | ||
91 | |||
92 | static void | ||
93 | da_activate(struct FsmInst *fi, int event, void *arg) | ||
94 | { | ||
95 | struct manager *mgr = fi->userdata; | ||
96 | |||
97 | if (fi->state == ST_L1_DEACT_PENDING) | ||
98 | mISDN_FsmDelTimer(&mgr->datimer, 1); | ||
99 | mISDN_FsmChangeState(fi, ST_L1_ACTIV); | ||
100 | } | ||
101 | |||
102 | static void | ||
103 | da_deactivate_ind(struct FsmInst *fi, int event, void *arg) | ||
104 | { | ||
105 | mISDN_FsmChangeState(fi, ST_L1_DEACT); | ||
106 | } | ||
107 | |||
108 | static void | ||
109 | da_deactivate(struct FsmInst *fi, int event, void *arg) | ||
110 | { | ||
111 | struct manager *mgr = fi->userdata; | ||
112 | struct layer2 *l2; | ||
113 | u_long flags; | ||
114 | |||
115 | read_lock_irqsave(&mgr->lock, flags); | ||
116 | list_for_each_entry(l2, &mgr->layer2, list) { | ||
117 | if (l2->l2m.state > ST_L2_4) { | ||
118 | /* have still activ TEI */ | ||
119 | read_unlock_irqrestore(&mgr->lock, flags); | ||
120 | return; | ||
121 | } | ||
122 | } | ||
123 | read_unlock_irqrestore(&mgr->lock, flags); | ||
124 | /* All TEI are inactiv */ | ||
125 | mISDN_FsmAddTimer(&mgr->datimer, DATIMER_VAL, EV_DATIMER, NULL, 1); | ||
126 | mISDN_FsmChangeState(fi, ST_L1_DEACT_PENDING); | ||
127 | } | ||
128 | |||
129 | static void | ||
130 | da_ui(struct FsmInst *fi, int event, void *arg) | ||
131 | { | ||
132 | struct manager *mgr = fi->userdata; | ||
133 | |||
134 | /* restart da timer */ | ||
135 | mISDN_FsmDelTimer(&mgr->datimer, 2); | ||
136 | mISDN_FsmAddTimer(&mgr->datimer, DATIMER_VAL, EV_DATIMER, NULL, 2); | ||
137 | |||
138 | } | ||
139 | |||
140 | static void | ||
141 | da_timer(struct FsmInst *fi, int event, void *arg) | ||
142 | { | ||
143 | struct manager *mgr = fi->userdata; | ||
144 | struct layer2 *l2; | ||
145 | u_long flags; | ||
146 | |||
147 | /* check again */ | ||
148 | read_lock_irqsave(&mgr->lock, flags); | ||
149 | list_for_each_entry(l2, &mgr->layer2, list) { | ||
150 | if (l2->l2m.state > ST_L2_4) { | ||
151 | /* have still activ TEI */ | ||
152 | read_unlock_irqrestore(&mgr->lock, flags); | ||
153 | mISDN_FsmChangeState(fi, ST_L1_ACTIV); | ||
154 | return; | ||
155 | } | ||
156 | } | ||
157 | read_unlock_irqrestore(&mgr->lock, flags); | ||
158 | /* All TEI are inactiv */ | ||
159 | mISDN_FsmChangeState(fi, ST_L1_DEACT); | ||
160 | _queue_data(&mgr->ch, PH_DEACTIVATE_REQ, MISDN_ID_ANY, 0, NULL, | ||
161 | GFP_ATOMIC); | ||
162 | } | ||
163 | |||
164 | static struct FsmNode DeactFnList[] = | ||
165 | { | ||
166 | {ST_L1_DEACT, EV_ACTIVATE_IND, da_activate}, | ||
167 | {ST_L1_ACTIV, EV_DEACTIVATE_IND, da_deactivate_ind}, | ||
168 | {ST_L1_ACTIV, EV_DEACTIVATE, da_deactivate}, | ||
169 | {ST_L1_DEACT_PENDING, EV_ACTIVATE, da_activate}, | ||
170 | {ST_L1_DEACT_PENDING, EV_UI, da_ui}, | ||
171 | {ST_L1_DEACT_PENDING, EV_DATIMER, da_timer}, | ||
172 | }; | ||
173 | |||
174 | enum { | ||
175 | ST_TEI_NOP, | ||
176 | ST_TEI_IDREQ, | ||
177 | ST_TEI_IDVERIFY, | ||
178 | }; | ||
179 | |||
180 | #define TEI_STATE_COUNT (ST_TEI_IDVERIFY+1) | ||
181 | |||
182 | static char *strTeiState[] = | ||
183 | { | ||
184 | "ST_TEI_NOP", | ||
185 | "ST_TEI_IDREQ", | ||
186 | "ST_TEI_IDVERIFY", | ||
187 | }; | ||
188 | |||
189 | enum { | ||
190 | EV_IDREQ, | ||
191 | EV_ASSIGN, | ||
192 | EV_ASSIGN_REQ, | ||
193 | EV_DENIED, | ||
194 | EV_CHKREQ, | ||
195 | EV_CHKRESP, | ||
196 | EV_REMOVE, | ||
197 | EV_VERIFY, | ||
198 | EV_TIMER, | ||
199 | }; | ||
200 | |||
201 | #define TEI_EVENT_COUNT (EV_TIMER+1) | ||
202 | |||
203 | static char *strTeiEvent[] = | ||
204 | { | ||
205 | "EV_IDREQ", | ||
206 | "EV_ASSIGN", | ||
207 | "EV_ASSIGN_REQ", | ||
208 | "EV_DENIED", | ||
209 | "EV_CHKREQ", | ||
210 | "EV_CHKRESP", | ||
211 | "EV_REMOVE", | ||
212 | "EV_VERIFY", | ||
213 | "EV_TIMER", | ||
214 | }; | ||
215 | |||
216 | static void | ||
217 | tei_debug(struct FsmInst *fi, char *fmt, ...) | ||
218 | { | ||
219 | struct teimgr *tm = fi->userdata; | ||
220 | va_list va; | ||
221 | |||
222 | if (!(*debug & DEBUG_L2_TEIFSM)) | ||
223 | return; | ||
224 | va_start(va, fmt); | ||
225 | printk(KERN_DEBUG "tei(%d): ", tm->l2->tei); | ||
226 | vprintk(fmt, va); | ||
227 | printk("\n"); | ||
228 | va_end(va); | ||
229 | } | ||
230 | |||
231 | |||
232 | |||
233 | static int | ||
234 | get_free_id(struct manager *mgr) | ||
235 | { | ||
236 | u64 ids = 0; | ||
237 | int i; | ||
238 | struct layer2 *l2; | ||
239 | |||
240 | list_for_each_entry(l2, &mgr->layer2, list) { | ||
241 | if (l2->ch.nr > 63) { | ||
242 | printk(KERN_WARNING | ||
243 | "%s: more as 63 layer2 for one device\n", | ||
244 | __func__); | ||
245 | return -EBUSY; | ||
246 | } | ||
247 | test_and_set_bit(l2->ch.nr, (u_long *)&ids); | ||
248 | } | ||
249 | for (i = 1; i < 64; i++) | ||
250 | if (!test_bit(i, (u_long *)&ids)) | ||
251 | return i; | ||
252 | printk(KERN_WARNING "%s: more as 63 layer2 for one device\n", | ||
253 | __func__); | ||
254 | return -EBUSY; | ||
255 | } | ||
256 | |||
257 | static int | ||
258 | get_free_tei(struct manager *mgr) | ||
259 | { | ||
260 | u64 ids = 0; | ||
261 | int i; | ||
262 | struct layer2 *l2; | ||
263 | |||
264 | list_for_each_entry(l2, &mgr->layer2, list) { | ||
265 | if (l2->ch.nr == 0) | ||
266 | continue; | ||
267 | if ((l2->ch.addr & 0xff) != 0) | ||
268 | continue; | ||
269 | i = l2->ch.addr >> 8; | ||
270 | if (i < 64) | ||
271 | continue; | ||
272 | i -= 64; | ||
273 | |||
274 | test_and_set_bit(i, (u_long *)&ids); | ||
275 | } | ||
276 | for (i = 0; i < 64; i++) | ||
277 | if (!test_bit(i, (u_long *)&ids)) | ||
278 | return i + 64; | ||
279 | printk(KERN_WARNING "%s: more as 63 dynamic tei for one device\n", | ||
280 | __func__); | ||
281 | return -1; | ||
282 | } | ||
283 | |||
284 | static void | ||
285 | teiup_create(struct manager *mgr, u_int prim, int len, void *arg) | ||
286 | { | ||
287 | struct sk_buff *skb; | ||
288 | struct mISDNhead *hh; | ||
289 | int err; | ||
290 | |||
291 | skb = mI_alloc_skb(len, GFP_ATOMIC); | ||
292 | if (!skb) | ||
293 | return; | ||
294 | hh = mISDN_HEAD_P(skb); | ||
295 | hh->prim = prim; | ||
296 | hh->id = (mgr->ch.nr << 16) | mgr->ch.addr; | ||
297 | if (len) | ||
298 | memcpy(skb_put(skb, len), arg, len); | ||
299 | err = mgr->up->send(mgr->up, skb); | ||
300 | if (err) { | ||
301 | printk(KERN_WARNING "%s: err=%d\n", __func__, err); | ||
302 | dev_kfree_skb(skb); | ||
303 | } | ||
304 | } | ||
305 | |||
306 | static u_int | ||
307 | new_id(struct manager *mgr) | ||
308 | { | ||
309 | u_int id; | ||
310 | |||
311 | id = mgr->nextid++; | ||
312 | if (id == 0x7fff) | ||
313 | mgr->nextid = 1; | ||
314 | id <<= 16; | ||
315 | id |= GROUP_TEI << 8; | ||
316 | id |= TEI_SAPI; | ||
317 | return id; | ||
318 | } | ||
319 | |||
320 | static void | ||
321 | do_send(struct manager *mgr) | ||
322 | { | ||
323 | if (!test_bit(MGR_PH_ACTIVE, &mgr->options)) | ||
324 | return; | ||
325 | |||
326 | if (!test_and_set_bit(MGR_PH_NOTREADY, &mgr->options)) { | ||
327 | struct sk_buff *skb = skb_dequeue(&mgr->sendq); | ||
328 | |||
329 | if (!skb) { | ||
330 | test_and_clear_bit(MGR_PH_NOTREADY, &mgr->options); | ||
331 | return; | ||
332 | } | ||
333 | mgr->lastid = mISDN_HEAD_ID(skb); | ||
334 | mISDN_FsmEvent(&mgr->deact, EV_UI, NULL); | ||
335 | if (mgr->ch.recv(mgr->ch.peer, skb)) { | ||
336 | dev_kfree_skb(skb); | ||
337 | test_and_clear_bit(MGR_PH_NOTREADY, &mgr->options); | ||
338 | mgr->lastid = MISDN_ID_NONE; | ||
339 | } | ||
340 | } | ||
341 | } | ||
342 | |||
343 | static void | ||
344 | do_ack(struct manager *mgr, u_int id) | ||
345 | { | ||
346 | if (test_bit(MGR_PH_NOTREADY, &mgr->options)) { | ||
347 | if (id == mgr->lastid) { | ||
348 | if (test_bit(MGR_PH_ACTIVE, &mgr->options)) { | ||
349 | struct sk_buff *skb; | ||
350 | |||
351 | skb = skb_dequeue(&mgr->sendq); | ||
352 | if (skb) { | ||
353 | mgr->lastid = mISDN_HEAD_ID(skb); | ||
354 | if (!mgr->ch.recv(mgr->ch.peer, skb)) | ||
355 | return; | ||
356 | dev_kfree_skb(skb); | ||
357 | } | ||
358 | } | ||
359 | mgr->lastid = MISDN_ID_NONE; | ||
360 | test_and_clear_bit(MGR_PH_NOTREADY, &mgr->options); | ||
361 | } | ||
362 | } | ||
363 | } | ||
364 | |||
365 | static void | ||
366 | mgr_send_down(struct manager *mgr, struct sk_buff *skb) | ||
367 | { | ||
368 | skb_queue_tail(&mgr->sendq, skb); | ||
369 | if (!test_bit(MGR_PH_ACTIVE, &mgr->options)) { | ||
370 | _queue_data(&mgr->ch, PH_ACTIVATE_REQ, MISDN_ID_ANY, 0, | ||
371 | NULL, GFP_KERNEL); | ||
372 | } else { | ||
373 | do_send(mgr); | ||
374 | } | ||
375 | } | ||
376 | |||
377 | static int | ||
378 | dl_unit_data(struct manager *mgr, struct sk_buff *skb) | ||
379 | { | ||
380 | if (!test_bit(MGR_OPT_NETWORK, &mgr->options)) /* only net send UI */ | ||
381 | return -EINVAL; | ||
382 | if (!test_bit(MGR_PH_ACTIVE, &mgr->options)) | ||
383 | _queue_data(&mgr->ch, PH_ACTIVATE_REQ, MISDN_ID_ANY, 0, | ||
384 | NULL, GFP_KERNEL); | ||
385 | skb_push(skb, 3); | ||
386 | skb->data[0] = 0x02; /* SAPI 0 C/R = 1 */ | ||
387 | skb->data[1] = 0xff; /* TEI 127 */ | ||
388 | skb->data[2] = UI; /* UI frame */ | ||
389 | mISDN_HEAD_PRIM(skb) = PH_DATA_REQ; | ||
390 | mISDN_HEAD_ID(skb) = new_id(mgr); | ||
391 | skb_queue_tail(&mgr->sendq, skb); | ||
392 | do_send(mgr); | ||
393 | return 0; | ||
394 | } | ||
395 | |||
396 | unsigned int | ||
397 | random_ri(void) | ||
398 | { | ||
399 | u16 x; | ||
400 | |||
401 | get_random_bytes(&x, sizeof(x)); | ||
402 | return x; | ||
403 | } | ||
404 | |||
405 | static struct layer2 * | ||
406 | findtei(struct manager *mgr, int tei) | ||
407 | { | ||
408 | struct layer2 *l2; | ||
409 | u_long flags; | ||
410 | |||
411 | read_lock_irqsave(&mgr->lock, flags); | ||
412 | list_for_each_entry(l2, &mgr->layer2, list) { | ||
413 | if ((l2->sapi == 0) && (l2->tei > 0) && | ||
414 | (l2->tei != GROUP_TEI) && (l2->tei == tei)) | ||
415 | goto done; | ||
416 | } | ||
417 | l2 = NULL; | ||
418 | done: | ||
419 | read_unlock_irqrestore(&mgr->lock, flags); | ||
420 | return l2; | ||
421 | } | ||
422 | |||
423 | static void | ||
424 | put_tei_msg(struct manager *mgr, u_char m_id, unsigned int ri, u_char tei) | ||
425 | { | ||
426 | struct sk_buff *skb; | ||
427 | u_char bp[8]; | ||
428 | |||
429 | bp[0] = (TEI_SAPI << 2); | ||
430 | if (test_bit(MGR_OPT_NETWORK, &mgr->options)) | ||
431 | bp[0] |= 2; /* CR:=1 for net command */ | ||
432 | bp[1] = (GROUP_TEI << 1) | 0x1; | ||
433 | bp[2] = UI; | ||
434 | bp[3] = TEI_ENTITY_ID; | ||
435 | bp[4] = ri >> 8; | ||
436 | bp[5] = ri & 0xff; | ||
437 | bp[6] = m_id; | ||
438 | bp[7] = (tei << 1) | 1; | ||
439 | skb = _alloc_mISDN_skb(PH_DATA_REQ, new_id(mgr), | ||
440 | 8, bp, GFP_ATOMIC); | ||
441 | if (!skb) { | ||
442 | printk(KERN_WARNING "%s: no skb for tei msg\n", __func__); | ||
443 | return; | ||
444 | } | ||
445 | mgr_send_down(mgr, skb); | ||
446 | } | ||
447 | |||
448 | static void | ||
449 | tei_id_request(struct FsmInst *fi, int event, void *arg) | ||
450 | { | ||
451 | struct teimgr *tm = fi->userdata; | ||
452 | |||
453 | if (tm->l2->tei != GROUP_TEI) { | ||
454 | tm->tei_m.printdebug(&tm->tei_m, | ||
455 | "assign request for allready assigned tei %d", | ||
456 | tm->l2->tei); | ||
457 | return; | ||
458 | } | ||
459 | tm->ri = random_ri(); | ||
460 | if (*debug & DEBUG_L2_TEI) | ||
461 | tm->tei_m.printdebug(&tm->tei_m, | ||
462 | "assign request ri %d", tm->ri); | ||
463 | put_tei_msg(tm->mgr, ID_REQUEST, tm->ri, GROUP_TEI); | ||
464 | mISDN_FsmChangeState(fi, ST_TEI_IDREQ); | ||
465 | mISDN_FsmAddTimer(&tm->timer, tm->tval, EV_TIMER, NULL, 1); | ||
466 | tm->nval = 3; | ||
467 | } | ||
468 | |||
469 | static void | ||
470 | tei_id_assign(struct FsmInst *fi, int event, void *arg) | ||
471 | { | ||
472 | struct teimgr *tm = fi->userdata; | ||
473 | struct layer2 *l2; | ||
474 | u_char *dp = arg; | ||
475 | int ri, tei; | ||
476 | |||
477 | ri = ((unsigned int) *dp++ << 8); | ||
478 | ri += *dp++; | ||
479 | dp++; | ||
480 | tei = *dp >> 1; | ||
481 | if (*debug & DEBUG_L2_TEI) | ||
482 | tm->tei_m.printdebug(fi, "identity assign ri %d tei %d", | ||
483 | ri, tei); | ||
484 | l2 = findtei(tm->mgr, tei); | ||
485 | if (l2) { /* same tei is in use */ | ||
486 | if (ri != l2->tm->ri) { | ||
487 | tm->tei_m.printdebug(fi, | ||
488 | "possible duplicate assignment tei %d", tei); | ||
489 | tei_l2(l2, MDL_ERROR_RSP, 0); | ||
490 | } | ||
491 | } else if (ri == tm->ri) { | ||
492 | mISDN_FsmDelTimer(&tm->timer, 1); | ||
493 | mISDN_FsmChangeState(fi, ST_TEI_NOP); | ||
494 | tei_l2(tm->l2, MDL_ASSIGN_REQ, tei); | ||
495 | } | ||
496 | } | ||
497 | |||
498 | static void | ||
499 | tei_id_test_dup(struct FsmInst *fi, int event, void *arg) | ||
500 | { | ||
501 | struct teimgr *tm = fi->userdata; | ||
502 | struct layer2 *l2; | ||
503 | u_char *dp = arg; | ||
504 | int tei, ri; | ||
505 | |||
506 | ri = ((unsigned int) *dp++ << 8); | ||
507 | ri += *dp++; | ||
508 | dp++; | ||
509 | tei = *dp >> 1; | ||
510 | if (*debug & DEBUG_L2_TEI) | ||
511 | tm->tei_m.printdebug(fi, "foreign identity assign ri %d tei %d", | ||
512 | ri, tei); | ||
513 | l2 = findtei(tm->mgr, tei); | ||
514 | if (l2) { /* same tei is in use */ | ||
515 | if (ri != l2->tm->ri) { /* and it wasn't our request */ | ||
516 | tm->tei_m.printdebug(fi, | ||
517 | "possible duplicate assignment tei %d", tei); | ||
518 | mISDN_FsmEvent(&l2->tm->tei_m, EV_VERIFY, NULL); | ||
519 | } | ||
520 | } | ||
521 | } | ||
522 | |||
523 | static void | ||
524 | tei_id_denied(struct FsmInst *fi, int event, void *arg) | ||
525 | { | ||
526 | struct teimgr *tm = fi->userdata; | ||
527 | u_char *dp = arg; | ||
528 | int ri, tei; | ||
529 | |||
530 | ri = ((unsigned int) *dp++ << 8); | ||
531 | ri += *dp++; | ||
532 | dp++; | ||
533 | tei = *dp >> 1; | ||
534 | if (*debug & DEBUG_L2_TEI) | ||
535 | tm->tei_m.printdebug(fi, "identity denied ri %d tei %d", | ||
536 | ri, tei); | ||
537 | } | ||
538 | |||
539 | static void | ||
540 | tei_id_chk_req(struct FsmInst *fi, int event, void *arg) | ||
541 | { | ||
542 | struct teimgr *tm = fi->userdata; | ||
543 | u_char *dp = arg; | ||
544 | int tei; | ||
545 | |||
546 | tei = *(dp+3) >> 1; | ||
547 | if (*debug & DEBUG_L2_TEI) | ||
548 | tm->tei_m.printdebug(fi, "identity check req tei %d", tei); | ||
549 | if ((tm->l2->tei != GROUP_TEI) && ((tei == GROUP_TEI) || | ||
550 | (tei == tm->l2->tei))) { | ||
551 | mISDN_FsmDelTimer(&tm->timer, 4); | ||
552 | mISDN_FsmChangeState(&tm->tei_m, ST_TEI_NOP); | ||
553 | put_tei_msg(tm->mgr, ID_CHK_RES, random_ri(), tm->l2->tei); | ||
554 | } | ||
555 | } | ||
556 | |||
557 | static void | ||
558 | tei_id_remove(struct FsmInst *fi, int event, void *arg) | ||
559 | { | ||
560 | struct teimgr *tm = fi->userdata; | ||
561 | u_char *dp = arg; | ||
562 | int tei; | ||
563 | |||
564 | tei = *(dp+3) >> 1; | ||
565 | if (*debug & DEBUG_L2_TEI) | ||
566 | tm->tei_m.printdebug(fi, "identity remove tei %d", tei); | ||
567 | if ((tm->l2->tei != GROUP_TEI) && | ||
568 | ((tei == GROUP_TEI) || (tei == tm->l2->tei))) { | ||
569 | mISDN_FsmDelTimer(&tm->timer, 5); | ||
570 | mISDN_FsmChangeState(&tm->tei_m, ST_TEI_NOP); | ||
571 | tei_l2(tm->l2, MDL_REMOVE_REQ, 0); | ||
572 | } | ||
573 | } | ||
574 | |||
575 | static void | ||
576 | tei_id_verify(struct FsmInst *fi, int event, void *arg) | ||
577 | { | ||
578 | struct teimgr *tm = fi->userdata; | ||
579 | |||
580 | if (*debug & DEBUG_L2_TEI) | ||
581 | tm->tei_m.printdebug(fi, "id verify request for tei %d", | ||
582 | tm->l2->tei); | ||
583 | put_tei_msg(tm->mgr, ID_VERIFY, 0, tm->l2->tei); | ||
584 | mISDN_FsmChangeState(&tm->tei_m, ST_TEI_IDVERIFY); | ||
585 | mISDN_FsmAddTimer(&tm->timer, tm->tval, EV_TIMER, NULL, 2); | ||
586 | tm->nval = 2; | ||
587 | } | ||
588 | |||
589 | static void | ||
590 | tei_id_req_tout(struct FsmInst *fi, int event, void *arg) | ||
591 | { | ||
592 | struct teimgr *tm = fi->userdata; | ||
593 | |||
594 | if (--tm->nval) { | ||
595 | tm->ri = random_ri(); | ||
596 | if (*debug & DEBUG_L2_TEI) | ||
597 | tm->tei_m.printdebug(fi, "assign req(%d) ri %d", | ||
598 | 4 - tm->nval, tm->ri); | ||
599 | put_tei_msg(tm->mgr, ID_REQUEST, tm->ri, GROUP_TEI); | ||
600 | mISDN_FsmAddTimer(&tm->timer, tm->tval, EV_TIMER, NULL, 3); | ||
601 | } else { | ||
602 | tm->tei_m.printdebug(fi, "assign req failed"); | ||
603 | tei_l2(tm->l2, MDL_ERROR_RSP, 0); | ||
604 | mISDN_FsmChangeState(fi, ST_TEI_NOP); | ||
605 | } | ||
606 | } | ||
607 | |||
608 | static void | ||
609 | tei_id_ver_tout(struct FsmInst *fi, int event, void *arg) | ||
610 | { | ||
611 | struct teimgr *tm = fi->userdata; | ||
612 | |||
613 | if (--tm->nval) { | ||
614 | if (*debug & DEBUG_L2_TEI) | ||
615 | tm->tei_m.printdebug(fi, | ||
616 | "id verify req(%d) for tei %d", | ||
617 | 3 - tm->nval, tm->l2->tei); | ||
618 | put_tei_msg(tm->mgr, ID_VERIFY, 0, tm->l2->tei); | ||
619 | mISDN_FsmAddTimer(&tm->timer, tm->tval, EV_TIMER, NULL, 4); | ||
620 | } else { | ||
621 | tm->tei_m.printdebug(fi, "verify req for tei %d failed", | ||
622 | tm->l2->tei); | ||
623 | tei_l2(tm->l2, MDL_REMOVE_REQ, 0); | ||
624 | mISDN_FsmChangeState(fi, ST_TEI_NOP); | ||
625 | } | ||
626 | } | ||
627 | |||
628 | static struct FsmNode TeiFnListUser[] = | ||
629 | { | ||
630 | {ST_TEI_NOP, EV_IDREQ, tei_id_request}, | ||
631 | {ST_TEI_NOP, EV_ASSIGN, tei_id_test_dup}, | ||
632 | {ST_TEI_NOP, EV_VERIFY, tei_id_verify}, | ||
633 | {ST_TEI_NOP, EV_REMOVE, tei_id_remove}, | ||
634 | {ST_TEI_NOP, EV_CHKREQ, tei_id_chk_req}, | ||
635 | {ST_TEI_IDREQ, EV_TIMER, tei_id_req_tout}, | ||
636 | {ST_TEI_IDREQ, EV_ASSIGN, tei_id_assign}, | ||
637 | {ST_TEI_IDREQ, EV_DENIED, tei_id_denied}, | ||
638 | {ST_TEI_IDVERIFY, EV_TIMER, tei_id_ver_tout}, | ||
639 | {ST_TEI_IDVERIFY, EV_REMOVE, tei_id_remove}, | ||
640 | {ST_TEI_IDVERIFY, EV_CHKREQ, tei_id_chk_req}, | ||
641 | }; | ||
642 | |||
643 | static void | ||
644 | tei_l2remove(struct layer2 *l2) | ||
645 | { | ||
646 | put_tei_msg(l2->tm->mgr, ID_REMOVE, 0, l2->tei); | ||
647 | tei_l2(l2, MDL_REMOVE_REQ, 0); | ||
648 | list_del(&l2->ch.list); | ||
649 | l2->ch.ctrl(&l2->ch, CLOSE_CHANNEL, NULL); | ||
650 | } | ||
651 | |||
652 | static void | ||
653 | tei_assign_req(struct FsmInst *fi, int event, void *arg) | ||
654 | { | ||
655 | struct teimgr *tm = fi->userdata; | ||
656 | u_char *dp = arg; | ||
657 | |||
658 | if (tm->l2->tei == GROUP_TEI) { | ||
659 | tm->tei_m.printdebug(&tm->tei_m, | ||
660 | "net tei assign request without tei"); | ||
661 | return; | ||
662 | } | ||
663 | tm->ri = ((unsigned int) *dp++ << 8); | ||
664 | tm->ri += *dp++; | ||
665 | if (*debug & DEBUG_L2_TEI) | ||
666 | tm->tei_m.printdebug(&tm->tei_m, | ||
667 | "net assign request ri %d teim %d", tm->ri, *dp); | ||
668 | put_tei_msg(tm->mgr, ID_ASSIGNED, tm->ri, tm->l2->tei); | ||
669 | mISDN_FsmChangeState(fi, ST_TEI_NOP); | ||
670 | } | ||
671 | |||
672 | static void | ||
673 | tei_id_chk_req_net(struct FsmInst *fi, int event, void *arg) | ||
674 | { | ||
675 | struct teimgr *tm = fi->userdata; | ||
676 | |||
677 | if (*debug & DEBUG_L2_TEI) | ||
678 | tm->tei_m.printdebug(fi, "id check request for tei %d", | ||
679 | tm->l2->tei); | ||
680 | tm->rcnt = 0; | ||
681 | put_tei_msg(tm->mgr, ID_CHK_REQ, 0, tm->l2->tei); | ||
682 | mISDN_FsmChangeState(&tm->tei_m, ST_TEI_IDVERIFY); | ||
683 | mISDN_FsmAddTimer(&tm->timer, tm->tval, EV_TIMER, NULL, 2); | ||
684 | tm->nval = 2; | ||
685 | } | ||
686 | |||
687 | static void | ||
688 | tei_id_chk_resp(struct FsmInst *fi, int event, void *arg) | ||
689 | { | ||
690 | struct teimgr *tm = fi->userdata; | ||
691 | u_char *dp = arg; | ||
692 | int tei; | ||
693 | |||
694 | tei = dp[3] >> 1; | ||
695 | if (*debug & DEBUG_L2_TEI) | ||
696 | tm->tei_m.printdebug(fi, "identity check resp tei %d", tei); | ||
697 | if (tei == tm->l2->tei) | ||
698 | tm->rcnt++; | ||
699 | } | ||
700 | |||
701 | static void | ||
702 | tei_id_verify_net(struct FsmInst *fi, int event, void *arg) | ||
703 | { | ||
704 | struct teimgr *tm = fi->userdata; | ||
705 | u_char *dp = arg; | ||
706 | int tei; | ||
707 | |||
708 | tei = dp[3] >> 1; | ||
709 | if (*debug & DEBUG_L2_TEI) | ||
710 | tm->tei_m.printdebug(fi, "identity verify req tei %d/%d", | ||
711 | tei, tm->l2->tei); | ||
712 | if (tei == tm->l2->tei) | ||
713 | tei_id_chk_req_net(fi, event, arg); | ||
714 | } | ||
715 | |||
716 | static void | ||
717 | tei_id_ver_tout_net(struct FsmInst *fi, int event, void *arg) | ||
718 | { | ||
719 | struct teimgr *tm = fi->userdata; | ||
720 | |||
721 | if (tm->rcnt == 1) { | ||
722 | if (*debug & DEBUG_L2_TEI) | ||
723 | tm->tei_m.printdebug(fi, | ||
724 | "check req for tei %d sucessful\n", tm->l2->tei); | ||
725 | mISDN_FsmChangeState(fi, ST_TEI_NOP); | ||
726 | } else if (tm->rcnt > 1) { | ||
727 | /* duplicate assignment; remove */ | ||
728 | tei_l2remove(tm->l2); | ||
729 | } else if (--tm->nval) { | ||
730 | if (*debug & DEBUG_L2_TEI) | ||
731 | tm->tei_m.printdebug(fi, | ||
732 | "id check req(%d) for tei %d", | ||
733 | 3 - tm->nval, tm->l2->tei); | ||
734 | put_tei_msg(tm->mgr, ID_CHK_REQ, 0, tm->l2->tei); | ||
735 | mISDN_FsmAddTimer(&tm->timer, tm->tval, EV_TIMER, NULL, 4); | ||
736 | } else { | ||
737 | tm->tei_m.printdebug(fi, "check req for tei %d failed", | ||
738 | tm->l2->tei); | ||
739 | mISDN_FsmChangeState(fi, ST_TEI_NOP); | ||
740 | tei_l2remove(tm->l2); | ||
741 | } | ||
742 | } | ||
743 | |||
744 | static struct FsmNode TeiFnListNet[] = | ||
745 | { | ||
746 | {ST_TEI_NOP, EV_ASSIGN_REQ, tei_assign_req}, | ||
747 | {ST_TEI_NOP, EV_VERIFY, tei_id_verify_net}, | ||
748 | {ST_TEI_NOP, EV_CHKREQ, tei_id_chk_req_net}, | ||
749 | {ST_TEI_IDVERIFY, EV_TIMER, tei_id_ver_tout_net}, | ||
750 | {ST_TEI_IDVERIFY, EV_CHKRESP, tei_id_chk_resp}, | ||
751 | }; | ||
752 | |||
753 | static void | ||
754 | tei_ph_data_ind(struct teimgr *tm, u_int mt, u_char *dp, int len) | ||
755 | { | ||
756 | if (test_bit(FLG_FIXED_TEI, &tm->l2->flag)) | ||
757 | return; | ||
758 | if (*debug & DEBUG_L2_TEI) | ||
759 | tm->tei_m.printdebug(&tm->tei_m, "tei handler mt %x", mt); | ||
760 | if (mt == ID_ASSIGNED) | ||
761 | mISDN_FsmEvent(&tm->tei_m, EV_ASSIGN, dp); | ||
762 | else if (mt == ID_DENIED) | ||
763 | mISDN_FsmEvent(&tm->tei_m, EV_DENIED, dp); | ||
764 | else if (mt == ID_CHK_REQ) | ||
765 | mISDN_FsmEvent(&tm->tei_m, EV_CHKREQ, dp); | ||
766 | else if (mt == ID_REMOVE) | ||
767 | mISDN_FsmEvent(&tm->tei_m, EV_REMOVE, dp); | ||
768 | else if (mt == ID_VERIFY) | ||
769 | mISDN_FsmEvent(&tm->tei_m, EV_VERIFY, dp); | ||
770 | else if (mt == ID_CHK_RES) | ||
771 | mISDN_FsmEvent(&tm->tei_m, EV_CHKRESP, dp); | ||
772 | } | ||
773 | |||
774 | static struct layer2 * | ||
775 | create_new_tei(struct manager *mgr, int tei) | ||
776 | { | ||
777 | u_long opt = 0; | ||
778 | u_long flags; | ||
779 | int id; | ||
780 | struct layer2 *l2; | ||
781 | |||
782 | if (!mgr->up) | ||
783 | return NULL; | ||
784 | if (tei < 64) | ||
785 | test_and_set_bit(OPTION_L2_FIXEDTEI, &opt); | ||
786 | if (mgr->ch.st->dev->Dprotocols | ||
787 | & ((1 << ISDN_P_TE_E1) | (1 << ISDN_P_NT_E1))) | ||
788 | test_and_set_bit(OPTION_L2_PMX, &opt); | ||
789 | l2 = create_l2(mgr->up, ISDN_P_LAPD_NT, (u_int)opt, (u_long)tei); | ||
790 | if (!l2) { | ||
791 | printk(KERN_WARNING "%s:no memory for layer2\n", __func__); | ||
792 | return NULL; | ||
793 | } | ||
794 | l2->tm = kzalloc(sizeof(struct teimgr), GFP_KERNEL); | ||
795 | if (!l2->tm) { | ||
796 | kfree(l2); | ||
797 | printk(KERN_WARNING "%s:no memory for teimgr\n", __func__); | ||
798 | return NULL; | ||
799 | } | ||
800 | l2->tm->mgr = mgr; | ||
801 | l2->tm->l2 = l2; | ||
802 | l2->tm->tei_m.debug = *debug & DEBUG_L2_TEIFSM; | ||
803 | l2->tm->tei_m.userdata = l2->tm; | ||
804 | l2->tm->tei_m.printdebug = tei_debug; | ||
805 | l2->tm->tei_m.fsm = &teifsmn; | ||
806 | l2->tm->tei_m.state = ST_TEI_NOP; | ||
807 | l2->tm->tval = 2000; /* T202 2 sec */ | ||
808 | mISDN_FsmInitTimer(&l2->tm->tei_m, &l2->tm->timer); | ||
809 | write_lock_irqsave(&mgr->lock, flags); | ||
810 | id = get_free_id(mgr); | ||
811 | list_add_tail(&l2->list, &mgr->layer2); | ||
812 | write_unlock_irqrestore(&mgr->lock, flags); | ||
813 | if (id < 0) { | ||
814 | l2->ch.ctrl(&l2->ch, CLOSE_CHANNEL, NULL); | ||
815 | printk(KERN_WARNING "%s:no free id\n", __func__); | ||
816 | return NULL; | ||
817 | } else { | ||
818 | l2->ch.nr = id; | ||
819 | __add_layer2(&l2->ch, mgr->ch.st); | ||
820 | l2->ch.recv = mgr->ch.recv; | ||
821 | l2->ch.peer = mgr->ch.peer; | ||
822 | l2->ch.ctrl(&l2->ch, OPEN_CHANNEL, NULL); | ||
823 | } | ||
824 | return l2; | ||
825 | } | ||
826 | |||
827 | static void | ||
828 | new_tei_req(struct manager *mgr, u_char *dp) | ||
829 | { | ||
830 | int tei, ri; | ||
831 | struct layer2 *l2; | ||
832 | |||
833 | ri = dp[0] << 8; | ||
834 | ri += dp[1]; | ||
835 | if (!mgr->up) | ||
836 | goto denied; | ||
837 | tei = get_free_tei(mgr); | ||
838 | if (tei < 0) { | ||
839 | printk(KERN_WARNING "%s:No free tei\n", __func__); | ||
840 | goto denied; | ||
841 | } | ||
842 | l2 = create_new_tei(mgr, tei); | ||
843 | if (!l2) | ||
844 | goto denied; | ||
845 | else | ||
846 | mISDN_FsmEvent(&l2->tm->tei_m, EV_ASSIGN_REQ, dp); | ||
847 | return; | ||
848 | denied: | ||
849 | put_tei_msg(mgr, ID_DENIED, ri, GROUP_TEI); | ||
850 | } | ||
851 | |||
852 | static int | ||
853 | ph_data_ind(struct manager *mgr, struct sk_buff *skb) | ||
854 | { | ||
855 | int ret = -EINVAL; | ||
856 | struct layer2 *l2; | ||
857 | u_long flags; | ||
858 | u_char mt; | ||
859 | |||
860 | if (skb->len < 8) { | ||
861 | if (*debug & DEBUG_L2_TEI) | ||
862 | printk(KERN_DEBUG "%s: short mgr frame %d/8\n", | ||
863 | __func__, skb->len); | ||
864 | goto done; | ||
865 | } | ||
866 | if (*debug & DEBUG_L2_TEI) | ||
867 | |||
868 | if ((skb->data[0] >> 2) != TEI_SAPI) /* not for us */ | ||
869 | goto done; | ||
870 | if (skb->data[0] & 1) /* EA0 formal error */ | ||
871 | goto done; | ||
872 | if (!(skb->data[1] & 1)) /* EA1 formal error */ | ||
873 | goto done; | ||
874 | if ((skb->data[1] >> 1) != GROUP_TEI) /* not for us */ | ||
875 | goto done; | ||
876 | if ((skb->data[2] & 0xef) != UI) /* not UI */ | ||
877 | goto done; | ||
878 | if (skb->data[3] != TEI_ENTITY_ID) /* not tei entity */ | ||
879 | goto done; | ||
880 | mt = skb->data[6]; | ||
881 | switch (mt) { | ||
882 | case ID_REQUEST: | ||
883 | case ID_CHK_RES: | ||
884 | case ID_VERIFY: | ||
885 | if (!test_bit(MGR_OPT_NETWORK, &mgr->options)) | ||
886 | goto done; | ||
887 | break; | ||
888 | case ID_ASSIGNED: | ||
889 | case ID_DENIED: | ||
890 | case ID_CHK_REQ: | ||
891 | case ID_REMOVE: | ||
892 | if (test_bit(MGR_OPT_NETWORK, &mgr->options)) | ||
893 | goto done; | ||
894 | break; | ||
895 | default: | ||
896 | goto done; | ||
897 | } | ||
898 | ret = 0; | ||
899 | if (mt == ID_REQUEST) { | ||
900 | new_tei_req(mgr, &skb->data[4]); | ||
901 | goto done; | ||
902 | } | ||
903 | read_lock_irqsave(&mgr->lock, flags); | ||
904 | list_for_each_entry(l2, &mgr->layer2, list) { | ||
905 | tei_ph_data_ind(l2->tm, mt, &skb->data[4], skb->len - 4); | ||
906 | } | ||
907 | read_unlock_irqrestore(&mgr->lock, flags); | ||
908 | done: | ||
909 | return ret; | ||
910 | } | ||
911 | |||
912 | int | ||
913 | l2_tei(struct layer2 *l2, u_int cmd, u_long arg) | ||
914 | { | ||
915 | struct teimgr *tm = l2->tm; | ||
916 | |||
917 | if (test_bit(FLG_FIXED_TEI, &l2->flag)) | ||
918 | return 0; | ||
919 | if (*debug & DEBUG_L2_TEI) | ||
920 | printk(KERN_DEBUG "%s: cmd(%x)\n", __func__, cmd); | ||
921 | switch (cmd) { | ||
922 | case MDL_ASSIGN_IND: | ||
923 | mISDN_FsmEvent(&tm->tei_m, EV_IDREQ, NULL); | ||
924 | break; | ||
925 | case MDL_ERROR_IND: | ||
926 | if (test_bit(MGR_OPT_NETWORK, &tm->mgr->options)) | ||
927 | mISDN_FsmEvent(&tm->tei_m, EV_CHKREQ, &l2->tei); | ||
928 | if (test_bit(MGR_OPT_USER, &tm->mgr->options)) | ||
929 | mISDN_FsmEvent(&tm->tei_m, EV_VERIFY, NULL); | ||
930 | break; | ||
931 | case MDL_STATUS_UP_IND: | ||
932 | if (test_bit(MGR_OPT_NETWORK, &tm->mgr->options)) | ||
933 | mISDN_FsmEvent(&tm->mgr->deact, EV_ACTIVATE, NULL); | ||
934 | break; | ||
935 | case MDL_STATUS_DOWN_IND: | ||
936 | if (test_bit(MGR_OPT_NETWORK, &tm->mgr->options)) | ||
937 | mISDN_FsmEvent(&tm->mgr->deact, EV_DEACTIVATE, NULL); | ||
938 | break; | ||
939 | case MDL_STATUS_UI_IND: | ||
940 | if (test_bit(MGR_OPT_NETWORK, &tm->mgr->options)) | ||
941 | mISDN_FsmEvent(&tm->mgr->deact, EV_UI, NULL); | ||
942 | break; | ||
943 | } | ||
944 | return 0; | ||
945 | } | ||
946 | |||
947 | void | ||
948 | release_tei(struct layer2 *l2) | ||
949 | { | ||
950 | struct teimgr *tm = l2->tm; | ||
951 | u_long flags; | ||
952 | |||
953 | mISDN_FsmDelTimer(&tm->timer, 1); | ||
954 | write_lock_irqsave(&tm->mgr->lock, flags); | ||
955 | list_del(&l2->list); | ||
956 | write_unlock_irqrestore(&tm->mgr->lock, flags); | ||
957 | l2->tm = NULL; | ||
958 | kfree(tm); | ||
959 | } | ||
960 | |||
961 | static int | ||
962 | create_teimgr(struct manager *mgr, struct channel_req *crq) | ||
963 | { | ||
964 | struct layer2 *l2; | ||
965 | u_long opt = 0; | ||
966 | u_long flags; | ||
967 | int id; | ||
968 | |||
969 | if (*debug & DEBUG_L2_TEI) | ||
970 | printk(KERN_DEBUG "%s: %s proto(%x) adr(%d %d %d %d)\n", | ||
971 | __func__, mgr->ch.st->dev->name, crq->protocol, | ||
972 | crq->adr.dev, crq->adr.channel, crq->adr.sapi, | ||
973 | crq->adr.tei); | ||
974 | if (crq->adr.sapi != 0) /* not supported yet */ | ||
975 | return -EINVAL; | ||
976 | if (crq->adr.tei > GROUP_TEI) | ||
977 | return -EINVAL; | ||
978 | if (crq->adr.tei < 64) | ||
979 | test_and_set_bit(OPTION_L2_FIXEDTEI, &opt); | ||
980 | if (crq->adr.tei == 0) | ||
981 | test_and_set_bit(OPTION_L2_PTP, &opt); | ||
982 | if (test_bit(MGR_OPT_NETWORK, &mgr->options)) { | ||
983 | if (crq->protocol == ISDN_P_LAPD_TE) | ||
984 | return -EPROTONOSUPPORT; | ||
985 | if ((crq->adr.tei != 0) && (crq->adr.tei != 127)) | ||
986 | return -EINVAL; | ||
987 | if (mgr->up) { | ||
988 | printk(KERN_WARNING | ||
989 | "%s: only one network manager is allowed\n", | ||
990 | __func__); | ||
991 | return -EBUSY; | ||
992 | } | ||
993 | } else if (test_bit(MGR_OPT_USER, &mgr->options)) { | ||
994 | if (crq->protocol == ISDN_P_LAPD_NT) | ||
995 | return -EPROTONOSUPPORT; | ||
996 | if ((crq->adr.tei >= 64) && (crq->adr.tei < GROUP_TEI)) | ||
997 | return -EINVAL; /* dyn tei */ | ||
998 | } else { | ||
999 | if (crq->protocol == ISDN_P_LAPD_NT) | ||
1000 | test_and_set_bit(MGR_OPT_NETWORK, &mgr->options); | ||
1001 | if (crq->protocol == ISDN_P_LAPD_TE) | ||
1002 | test_and_set_bit(MGR_OPT_USER, &mgr->options); | ||
1003 | } | ||
1004 | if (mgr->ch.st->dev->Dprotocols | ||
1005 | & ((1 << ISDN_P_TE_E1) | (1 << ISDN_P_NT_E1))) | ||
1006 | test_and_set_bit(OPTION_L2_PMX, &opt); | ||
1007 | if ((crq->protocol == ISDN_P_LAPD_NT) && (crq->adr.tei == 127)) { | ||
1008 | mgr->up = crq->ch; | ||
1009 | id = DL_INFO_L2_CONNECT; | ||
1010 | teiup_create(mgr, DL_INFORMATION_IND, sizeof(id), &id); | ||
1011 | crq->ch = NULL; | ||
1012 | if (!list_empty(&mgr->layer2)) { | ||
1013 | read_lock_irqsave(&mgr->lock, flags); | ||
1014 | list_for_each_entry(l2, &mgr->layer2, list) { | ||
1015 | l2->up = mgr->up; | ||
1016 | l2->ch.ctrl(&l2->ch, OPEN_CHANNEL, NULL); | ||
1017 | } | ||
1018 | read_unlock_irqrestore(&mgr->lock, flags); | ||
1019 | } | ||
1020 | return 0; | ||
1021 | } | ||
1022 | l2 = create_l2(crq->ch, crq->protocol, (u_int)opt, | ||
1023 | (u_long)crq->adr.tei); | ||
1024 | if (!l2) | ||
1025 | return -ENOMEM; | ||
1026 | l2->tm = kzalloc(sizeof(struct teimgr), GFP_KERNEL); | ||
1027 | if (!l2->tm) { | ||
1028 | kfree(l2); | ||
1029 | printk(KERN_ERR "kmalloc teimgr failed\n"); | ||
1030 | return -ENOMEM; | ||
1031 | } | ||
1032 | l2->tm->mgr = mgr; | ||
1033 | l2->tm->l2 = l2; | ||
1034 | l2->tm->tei_m.debug = *debug & DEBUG_L2_TEIFSM; | ||
1035 | l2->tm->tei_m.userdata = l2->tm; | ||
1036 | l2->tm->tei_m.printdebug = tei_debug; | ||
1037 | if (crq->protocol == ISDN_P_LAPD_TE) { | ||
1038 | l2->tm->tei_m.fsm = &teifsmu; | ||
1039 | l2->tm->tei_m.state = ST_TEI_NOP; | ||
1040 | l2->tm->tval = 1000; /* T201 1 sec */ | ||
1041 | } else { | ||
1042 | l2->tm->tei_m.fsm = &teifsmn; | ||
1043 | l2->tm->tei_m.state = ST_TEI_NOP; | ||
1044 | l2->tm->tval = 2000; /* T202 2 sec */ | ||
1045 | } | ||
1046 | mISDN_FsmInitTimer(&l2->tm->tei_m, &l2->tm->timer); | ||
1047 | write_lock_irqsave(&mgr->lock, flags); | ||
1048 | id = get_free_id(mgr); | ||
1049 | list_add_tail(&l2->list, &mgr->layer2); | ||
1050 | write_unlock_irqrestore(&mgr->lock, flags); | ||
1051 | if (id < 0) { | ||
1052 | l2->ch.ctrl(&l2->ch, CLOSE_CHANNEL, NULL); | ||
1053 | } else { | ||
1054 | l2->ch.nr = id; | ||
1055 | l2->up->nr = id; | ||
1056 | crq->ch = &l2->ch; | ||
1057 | id = 0; | ||
1058 | } | ||
1059 | return id; | ||
1060 | } | ||
1061 | |||
1062 | static int | ||
1063 | mgr_send(struct mISDNchannel *ch, struct sk_buff *skb) | ||
1064 | { | ||
1065 | struct manager *mgr; | ||
1066 | struct mISDNhead *hh = mISDN_HEAD_P(skb); | ||
1067 | int ret = -EINVAL; | ||
1068 | |||
1069 | mgr = container_of(ch, struct manager, ch); | ||
1070 | if (*debug & DEBUG_L2_RECV) | ||
1071 | printk(KERN_DEBUG "%s: prim(%x) id(%x)\n", | ||
1072 | __func__, hh->prim, hh->id); | ||
1073 | switch (hh->prim) { | ||
1074 | case PH_DATA_IND: | ||
1075 | mISDN_FsmEvent(&mgr->deact, EV_UI, NULL); | ||
1076 | ret = ph_data_ind(mgr, skb); | ||
1077 | break; | ||
1078 | case PH_DATA_CNF: | ||
1079 | do_ack(mgr, hh->id); | ||
1080 | ret = 0; | ||
1081 | break; | ||
1082 | case PH_ACTIVATE_IND: | ||
1083 | test_and_set_bit(MGR_PH_ACTIVE, &mgr->options); | ||
1084 | mISDN_FsmEvent(&mgr->deact, EV_ACTIVATE_IND, NULL); | ||
1085 | do_send(mgr); | ||
1086 | ret = 0; | ||
1087 | break; | ||
1088 | case PH_DEACTIVATE_IND: | ||
1089 | test_and_clear_bit(MGR_PH_ACTIVE, &mgr->options); | ||
1090 | mISDN_FsmEvent(&mgr->deact, EV_DEACTIVATE_IND, NULL); | ||
1091 | ret = 0; | ||
1092 | break; | ||
1093 | case DL_UNITDATA_REQ: | ||
1094 | return dl_unit_data(mgr, skb); | ||
1095 | } | ||
1096 | if (!ret) | ||
1097 | dev_kfree_skb(skb); | ||
1098 | return ret; | ||
1099 | } | ||
1100 | |||
1101 | static int | ||
1102 | free_teimanager(struct manager *mgr) | ||
1103 | { | ||
1104 | struct layer2 *l2, *nl2; | ||
1105 | |||
1106 | if (test_bit(MGR_OPT_NETWORK, &mgr->options)) { | ||
1107 | /* not locked lock is taken in release tei */ | ||
1108 | mgr->up = NULL; | ||
1109 | if (test_bit(OPTION_L2_CLEANUP, &mgr->options)) { | ||
1110 | list_for_each_entry_safe(l2, nl2, &mgr->layer2, list) { | ||
1111 | put_tei_msg(mgr, ID_REMOVE, 0, l2->tei); | ||
1112 | mutex_lock(&mgr->ch.st->lmutex); | ||
1113 | list_del(&l2->ch.list); | ||
1114 | mutex_unlock(&mgr->ch.st->lmutex); | ||
1115 | l2->ch.ctrl(&l2->ch, CLOSE_CHANNEL, NULL); | ||
1116 | } | ||
1117 | test_and_clear_bit(MGR_OPT_NETWORK, &mgr->options); | ||
1118 | } else { | ||
1119 | list_for_each_entry_safe(l2, nl2, &mgr->layer2, list) { | ||
1120 | l2->up = NULL; | ||
1121 | } | ||
1122 | } | ||
1123 | } | ||
1124 | if (test_bit(MGR_OPT_USER, &mgr->options)) { | ||
1125 | if (list_empty(&mgr->layer2)) | ||
1126 | test_and_clear_bit(MGR_OPT_USER, &mgr->options); | ||
1127 | } | ||
1128 | mgr->ch.st->dev->D.ctrl(&mgr->ch.st->dev->D, CLOSE_CHANNEL, NULL); | ||
1129 | return 0; | ||
1130 | } | ||
1131 | |||
1132 | static int | ||
1133 | ctrl_teimanager(struct manager *mgr, void *arg) | ||
1134 | { | ||
1135 | /* currently we only have one option */ | ||
1136 | int clean = *((int *)arg); | ||
1137 | |||
1138 | if (clean) | ||
1139 | test_and_set_bit(OPTION_L2_CLEANUP, &mgr->options); | ||
1140 | else | ||
1141 | test_and_clear_bit(OPTION_L2_CLEANUP, &mgr->options); | ||
1142 | return 0; | ||
1143 | } | ||
1144 | |||
1145 | /* This function does create a L2 for fixed TEI in NT Mode */ | ||
1146 | static int | ||
1147 | check_data(struct manager *mgr, struct sk_buff *skb) | ||
1148 | { | ||
1149 | struct mISDNhead *hh = mISDN_HEAD_P(skb); | ||
1150 | int ret, tei; | ||
1151 | struct layer2 *l2; | ||
1152 | |||
1153 | if (*debug & DEBUG_L2_CTRL) | ||
1154 | printk(KERN_DEBUG "%s: prim(%x) id(%x)\n", | ||
1155 | __func__, hh->prim, hh->id); | ||
1156 | if (test_bit(MGR_OPT_USER, &mgr->options)) | ||
1157 | return -ENOTCONN; | ||
1158 | if (hh->prim != PH_DATA_IND) | ||
1159 | return -ENOTCONN; | ||
1160 | if (skb->len != 3) | ||
1161 | return -ENOTCONN; | ||
1162 | if (skb->data[0] != 0) | ||
1163 | /* only SAPI 0 command */ | ||
1164 | return -ENOTCONN; | ||
1165 | if (!(skb->data[1] & 1)) /* invalid EA1 */ | ||
1166 | return -EINVAL; | ||
1167 | tei = skb->data[1] >> 0; | ||
1168 | if (tei > 63) /* not a fixed tei */ | ||
1169 | return -ENOTCONN; | ||
1170 | if ((skb->data[2] & ~0x10) != SABME) | ||
1171 | return -ENOTCONN; | ||
1172 | /* We got a SABME for a fixed TEI */ | ||
1173 | l2 = create_new_tei(mgr, tei); | ||
1174 | if (!l2) | ||
1175 | return -ENOMEM; | ||
1176 | ret = l2->ch.send(&l2->ch, skb); | ||
1177 | return ret; | ||
1178 | } | ||
1179 | |||
1180 | void | ||
1181 | delete_teimanager(struct mISDNchannel *ch) | ||
1182 | { | ||
1183 | struct manager *mgr; | ||
1184 | struct layer2 *l2, *nl2; | ||
1185 | |||
1186 | mgr = container_of(ch, struct manager, ch); | ||
1187 | /* not locked lock is taken in release tei */ | ||
1188 | list_for_each_entry_safe(l2, nl2, &mgr->layer2, list) { | ||
1189 | mutex_lock(&mgr->ch.st->lmutex); | ||
1190 | list_del(&l2->ch.list); | ||
1191 | mutex_unlock(&mgr->ch.st->lmutex); | ||
1192 | l2->ch.ctrl(&l2->ch, CLOSE_CHANNEL, NULL); | ||
1193 | } | ||
1194 | list_del(&mgr->ch.list); | ||
1195 | list_del(&mgr->bcast.list); | ||
1196 | skb_queue_purge(&mgr->sendq); | ||
1197 | kfree(mgr); | ||
1198 | } | ||
1199 | |||
1200 | static int | ||
1201 | mgr_ctrl(struct mISDNchannel *ch, u_int cmd, void *arg) | ||
1202 | { | ||
1203 | struct manager *mgr; | ||
1204 | int ret = -EINVAL; | ||
1205 | |||
1206 | mgr = container_of(ch, struct manager, ch); | ||
1207 | if (*debug & DEBUG_L2_CTRL) | ||
1208 | printk(KERN_DEBUG "%s(%x, %p)\n", __func__, cmd, arg); | ||
1209 | switch (cmd) { | ||
1210 | case OPEN_CHANNEL: | ||
1211 | ret = create_teimgr(mgr, arg); | ||
1212 | break; | ||
1213 | case CLOSE_CHANNEL: | ||
1214 | ret = free_teimanager(mgr); | ||
1215 | break; | ||
1216 | case CONTROL_CHANNEL: | ||
1217 | ret = ctrl_teimanager(mgr, arg); | ||
1218 | break; | ||
1219 | case CHECK_DATA: | ||
1220 | ret = check_data(mgr, arg); | ||
1221 | break; | ||
1222 | } | ||
1223 | return ret; | ||
1224 | } | ||
1225 | |||
1226 | static int | ||
1227 | mgr_bcast(struct mISDNchannel *ch, struct sk_buff *skb) | ||
1228 | { | ||
1229 | struct manager *mgr = container_of(ch, struct manager, bcast); | ||
1230 | struct mISDNhead *hh = mISDN_HEAD_P(skb); | ||
1231 | struct sk_buff *cskb = NULL; | ||
1232 | struct layer2 *l2; | ||
1233 | u_long flags; | ||
1234 | int ret; | ||
1235 | |||
1236 | read_lock_irqsave(&mgr->lock, flags); | ||
1237 | list_for_each_entry(l2, &mgr->layer2, list) { | ||
1238 | if ((hh->id & MISDN_ID_SAPI_MASK) == | ||
1239 | (l2->ch.addr & MISDN_ID_SAPI_MASK)) { | ||
1240 | if (list_is_last(&l2->list, &mgr->layer2)) { | ||
1241 | cskb = skb; | ||
1242 | skb = NULL; | ||
1243 | } else { | ||
1244 | if (!cskb) | ||
1245 | cskb = skb_copy(skb, GFP_KERNEL); | ||
1246 | } | ||
1247 | if (cskb) { | ||
1248 | ret = l2->ch.send(&l2->ch, cskb); | ||
1249 | if (ret) { | ||
1250 | if (*debug & DEBUG_SEND_ERR) | ||
1251 | printk(KERN_DEBUG | ||
1252 | "%s ch%d prim(%x) addr(%x)" | ||
1253 | " err %d\n", | ||
1254 | __func__, l2->ch.nr, | ||
1255 | hh->prim, l2->ch.addr, ret); | ||
1256 | } else | ||
1257 | cskb = NULL; | ||
1258 | } else { | ||
1259 | printk(KERN_WARNING "%s ch%d addr %x no mem\n", | ||
1260 | __func__, ch->nr, ch->addr); | ||
1261 | goto out; | ||
1262 | } | ||
1263 | } | ||
1264 | } | ||
1265 | out: | ||
1266 | read_unlock_irqrestore(&mgr->lock, flags); | ||
1267 | if (cskb) | ||
1268 | dev_kfree_skb(cskb); | ||
1269 | if (skb) | ||
1270 | dev_kfree_skb(skb); | ||
1271 | return 0; | ||
1272 | } | ||
1273 | |||
1274 | static int | ||
1275 | mgr_bcast_ctrl(struct mISDNchannel *ch, u_int cmd, void *arg) | ||
1276 | { | ||
1277 | |||
1278 | return -EINVAL; | ||
1279 | } | ||
1280 | |||
1281 | int | ||
1282 | create_teimanager(struct mISDNdevice *dev) | ||
1283 | { | ||
1284 | struct manager *mgr; | ||
1285 | |||
1286 | mgr = kzalloc(sizeof(struct manager), GFP_KERNEL); | ||
1287 | if (!mgr) | ||
1288 | return -ENOMEM; | ||
1289 | INIT_LIST_HEAD(&mgr->layer2); | ||
1290 | mgr->lock = __RW_LOCK_UNLOCKED(mgr->lock); | ||
1291 | skb_queue_head_init(&mgr->sendq); | ||
1292 | mgr->nextid = 1; | ||
1293 | mgr->lastid = MISDN_ID_NONE; | ||
1294 | mgr->ch.send = mgr_send; | ||
1295 | mgr->ch.ctrl = mgr_ctrl; | ||
1296 | mgr->ch.st = dev->D.st; | ||
1297 | set_channel_address(&mgr->ch, TEI_SAPI, GROUP_TEI); | ||
1298 | add_layer2(&mgr->ch, dev->D.st); | ||
1299 | mgr->bcast.send = mgr_bcast; | ||
1300 | mgr->bcast.ctrl = mgr_bcast_ctrl; | ||
1301 | mgr->bcast.st = dev->D.st; | ||
1302 | set_channel_address(&mgr->bcast, 0, GROUP_TEI); | ||
1303 | add_layer2(&mgr->bcast, dev->D.st); | ||
1304 | mgr->deact.debug = *debug & DEBUG_MANAGER; | ||
1305 | mgr->deact.userdata = mgr; | ||
1306 | mgr->deact.printdebug = da_debug; | ||
1307 | mgr->deact.fsm = &deactfsm; | ||
1308 | mgr->deact.state = ST_L1_DEACT; | ||
1309 | mISDN_FsmInitTimer(&mgr->deact, &mgr->datimer); | ||
1310 | dev->teimgr = &mgr->ch; | ||
1311 | return 0; | ||
1312 | } | ||
1313 | |||
1314 | int TEIInit(u_int *deb) | ||
1315 | { | ||
1316 | debug = deb; | ||
1317 | teifsmu.state_count = TEI_STATE_COUNT; | ||
1318 | teifsmu.event_count = TEI_EVENT_COUNT; | ||
1319 | teifsmu.strEvent = strTeiEvent; | ||
1320 | teifsmu.strState = strTeiState; | ||
1321 | mISDN_FsmNew(&teifsmu, TeiFnListUser, ARRAY_SIZE(TeiFnListUser)); | ||
1322 | teifsmn.state_count = TEI_STATE_COUNT; | ||
1323 | teifsmn.event_count = TEI_EVENT_COUNT; | ||
1324 | teifsmn.strEvent = strTeiEvent; | ||
1325 | teifsmn.strState = strTeiState; | ||
1326 | mISDN_FsmNew(&teifsmn, TeiFnListNet, ARRAY_SIZE(TeiFnListNet)); | ||
1327 | deactfsm.state_count = DEACT_STATE_COUNT; | ||
1328 | deactfsm.event_count = DEACT_EVENT_COUNT; | ||
1329 | deactfsm.strEvent = strDeactEvent; | ||
1330 | deactfsm.strState = strDeactState; | ||
1331 | mISDN_FsmNew(&deactfsm, DeactFnList, ARRAY_SIZE(DeactFnList)); | ||
1332 | return 0; | ||
1333 | } | ||
1334 | |||
1335 | void TEIFree(void) | ||
1336 | { | ||
1337 | mISDN_FsmFree(&teifsmu); | ||
1338 | mISDN_FsmFree(&teifsmn); | ||
1339 | mISDN_FsmFree(&deactfsm); | ||
1340 | } | ||
diff --git a/drivers/isdn/mISDN/timerdev.c b/drivers/isdn/mISDN/timerdev.c new file mode 100644 index 000000000000..b5fabc7019d8 --- /dev/null +++ b/drivers/isdn/mISDN/timerdev.c | |||
@@ -0,0 +1,301 @@ | |||
1 | /* | ||
2 | * | ||
3 | * general timer device for using in ISDN stacks | ||
4 | * | ||
5 | * Author Karsten Keil <kkeil@novell.com> | ||
6 | * | ||
7 | * Copyright 2008 by Karsten Keil <kkeil@novell.com> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License version 2 as | ||
11 | * published by the Free Software Foundation. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | */ | ||
19 | |||
20 | #include <linux/poll.h> | ||
21 | #include <linux/vmalloc.h> | ||
22 | #include <linux/timer.h> | ||
23 | #include <linux/miscdevice.h> | ||
24 | #include <linux/module.h> | ||
25 | #include <linux/mISDNif.h> | ||
26 | |||
27 | static int *debug; | ||
28 | |||
29 | |||
30 | struct mISDNtimerdev { | ||
31 | int next_id; | ||
32 | struct list_head pending; | ||
33 | struct list_head expired; | ||
34 | wait_queue_head_t wait; | ||
35 | u_int work; | ||
36 | spinlock_t lock; /* protect lists */ | ||
37 | }; | ||
38 | |||
39 | struct mISDNtimer { | ||
40 | struct list_head list; | ||
41 | struct mISDNtimerdev *dev; | ||
42 | struct timer_list tl; | ||
43 | int id; | ||
44 | }; | ||
45 | |||
46 | static int | ||
47 | mISDN_open(struct inode *ino, struct file *filep) | ||
48 | { | ||
49 | struct mISDNtimerdev *dev; | ||
50 | |||
51 | if (*debug & DEBUG_TIMER) | ||
52 | printk(KERN_DEBUG "%s(%p,%p)\n", __func__, ino, filep); | ||
53 | dev = kmalloc(sizeof(struct mISDNtimerdev) , GFP_KERNEL); | ||
54 | if (!dev) | ||
55 | return -ENOMEM; | ||
56 | dev->next_id = 1; | ||
57 | INIT_LIST_HEAD(&dev->pending); | ||
58 | INIT_LIST_HEAD(&dev->expired); | ||
59 | spin_lock_init(&dev->lock); | ||
60 | dev->work = 0; | ||
61 | init_waitqueue_head(&dev->wait); | ||
62 | filep->private_data = dev; | ||
63 | __module_get(THIS_MODULE); | ||
64 | return 0; | ||
65 | } | ||
66 | |||
67 | static int | ||
68 | mISDN_close(struct inode *ino, struct file *filep) | ||
69 | { | ||
70 | struct mISDNtimerdev *dev = filep->private_data; | ||
71 | struct mISDNtimer *timer, *next; | ||
72 | |||
73 | if (*debug & DEBUG_TIMER) | ||
74 | printk(KERN_DEBUG "%s(%p,%p)\n", __func__, ino, filep); | ||
75 | list_for_each_entry_safe(timer, next, &dev->pending, list) { | ||
76 | del_timer(&timer->tl); | ||
77 | kfree(timer); | ||
78 | } | ||
79 | list_for_each_entry_safe(timer, next, &dev->expired, list) { | ||
80 | kfree(timer); | ||
81 | } | ||
82 | kfree(dev); | ||
83 | module_put(THIS_MODULE); | ||
84 | return 0; | ||
85 | } | ||
86 | |||
87 | static ssize_t | ||
88 | mISDN_read(struct file *filep, char *buf, size_t count, loff_t *off) | ||
89 | { | ||
90 | struct mISDNtimerdev *dev = filep->private_data; | ||
91 | struct mISDNtimer *timer; | ||
92 | u_long flags; | ||
93 | int ret = 0; | ||
94 | |||
95 | if (*debug & DEBUG_TIMER) | ||
96 | printk(KERN_DEBUG "%s(%p, %p, %d, %p)\n", __func__, | ||
97 | filep, buf, (int)count, off); | ||
98 | if (*off != filep->f_pos) | ||
99 | return -ESPIPE; | ||
100 | |||
101 | if (list_empty(&dev->expired) && (dev->work == 0)) { | ||
102 | if (filep->f_flags & O_NONBLOCK) | ||
103 | return -EAGAIN; | ||
104 | wait_event_interruptible(dev->wait, (dev->work || | ||
105 | !list_empty(&dev->expired))); | ||
106 | if (signal_pending(current)) | ||
107 | return -ERESTARTSYS; | ||
108 | } | ||
109 | if (count < sizeof(int)) | ||
110 | return -ENOSPC; | ||
111 | if (dev->work) | ||
112 | dev->work = 0; | ||
113 | if (!list_empty(&dev->expired)) { | ||
114 | spin_lock_irqsave(&dev->lock, flags); | ||
115 | timer = (struct mISDNtimer *)dev->expired.next; | ||
116 | list_del(&timer->list); | ||
117 | spin_unlock_irqrestore(&dev->lock, flags); | ||
118 | if (put_user(timer->id, (int *)buf)) | ||
119 | ret = -EFAULT; | ||
120 | else | ||
121 | ret = sizeof(int); | ||
122 | kfree(timer); | ||
123 | } | ||
124 | return ret; | ||
125 | } | ||
126 | |||
127 | static loff_t | ||
128 | mISDN_llseek(struct file *filep, loff_t offset, int orig) | ||
129 | { | ||
130 | return -ESPIPE; | ||
131 | } | ||
132 | |||
133 | static ssize_t | ||
134 | mISDN_write(struct file *filep, const char *buf, size_t count, loff_t *off) | ||
135 | { | ||
136 | return -EOPNOTSUPP; | ||
137 | } | ||
138 | |||
139 | static unsigned int | ||
140 | mISDN_poll(struct file *filep, poll_table *wait) | ||
141 | { | ||
142 | struct mISDNtimerdev *dev = filep->private_data; | ||
143 | unsigned int mask = POLLERR; | ||
144 | |||
145 | if (*debug & DEBUG_TIMER) | ||
146 | printk(KERN_DEBUG "%s(%p, %p)\n", __func__, filep, wait); | ||
147 | if (dev) { | ||
148 | poll_wait(filep, &dev->wait, wait); | ||
149 | mask = 0; | ||
150 | if (dev->work || !list_empty(&dev->expired)) | ||
151 | mask |= (POLLIN | POLLRDNORM); | ||
152 | if (*debug & DEBUG_TIMER) | ||
153 | printk(KERN_DEBUG "%s work(%d) empty(%d)\n", __func__, | ||
154 | dev->work, list_empty(&dev->expired)); | ||
155 | } | ||
156 | return mask; | ||
157 | } | ||
158 | |||
159 | static void | ||
160 | dev_expire_timer(struct mISDNtimer *timer) | ||
161 | { | ||
162 | u_long flags; | ||
163 | |||
164 | spin_lock_irqsave(&timer->dev->lock, flags); | ||
165 | list_del(&timer->list); | ||
166 | list_add_tail(&timer->list, &timer->dev->expired); | ||
167 | spin_unlock_irqrestore(&timer->dev->lock, flags); | ||
168 | wake_up_interruptible(&timer->dev->wait); | ||
169 | } | ||
170 | |||
171 | static int | ||
172 | misdn_add_timer(struct mISDNtimerdev *dev, int timeout) | ||
173 | { | ||
174 | int id; | ||
175 | u_long flags; | ||
176 | struct mISDNtimer *timer; | ||
177 | |||
178 | if (!timeout) { | ||
179 | dev->work = 1; | ||
180 | wake_up_interruptible(&dev->wait); | ||
181 | id = 0; | ||
182 | } else { | ||
183 | timer = kzalloc(sizeof(struct mISDNtimer), GFP_KERNEL); | ||
184 | if (!timer) | ||
185 | return -ENOMEM; | ||
186 | spin_lock_irqsave(&dev->lock, flags); | ||
187 | timer->id = dev->next_id++; | ||
188 | if (dev->next_id < 0) | ||
189 | dev->next_id = 1; | ||
190 | list_add_tail(&timer->list, &dev->pending); | ||
191 | spin_unlock_irqrestore(&dev->lock, flags); | ||
192 | timer->dev = dev; | ||
193 | timer->tl.data = (long)timer; | ||
194 | timer->tl.function = (void *) dev_expire_timer; | ||
195 | init_timer(&timer->tl); | ||
196 | timer->tl.expires = jiffies + ((HZ * (u_long)timeout) / 1000); | ||
197 | add_timer(&timer->tl); | ||
198 | id = timer->id; | ||
199 | } | ||
200 | return id; | ||
201 | } | ||
202 | |||
203 | static int | ||
204 | misdn_del_timer(struct mISDNtimerdev *dev, int id) | ||
205 | { | ||
206 | u_long flags; | ||
207 | struct mISDNtimer *timer; | ||
208 | int ret = 0; | ||
209 | |||
210 | spin_lock_irqsave(&dev->lock, flags); | ||
211 | list_for_each_entry(timer, &dev->pending, list) { | ||
212 | if (timer->id == id) { | ||
213 | list_del_init(&timer->list); | ||
214 | del_timer(&timer->tl); | ||
215 | ret = timer->id; | ||
216 | kfree(timer); | ||
217 | goto unlock; | ||
218 | } | ||
219 | } | ||
220 | unlock: | ||
221 | spin_unlock_irqrestore(&dev->lock, flags); | ||
222 | return ret; | ||
223 | } | ||
224 | |||
225 | static int | ||
226 | mISDN_ioctl(struct inode *inode, struct file *filep, unsigned int cmd, | ||
227 | unsigned long arg) | ||
228 | { | ||
229 | struct mISDNtimerdev *dev = filep->private_data; | ||
230 | int id, tout, ret = 0; | ||
231 | |||
232 | |||
233 | if (*debug & DEBUG_TIMER) | ||
234 | printk(KERN_DEBUG "%s(%p, %x, %lx)\n", __func__, | ||
235 | filep, cmd, arg); | ||
236 | switch (cmd) { | ||
237 | case IMADDTIMER: | ||
238 | if (get_user(tout, (int __user *)arg)) { | ||
239 | ret = -EFAULT; | ||
240 | break; | ||
241 | } | ||
242 | id = misdn_add_timer(dev, tout); | ||
243 | if (*debug & DEBUG_TIMER) | ||
244 | printk(KERN_DEBUG "%s add %d id %d\n", __func__, | ||
245 | tout, id); | ||
246 | if (id < 0) { | ||
247 | ret = id; | ||
248 | break; | ||
249 | } | ||
250 | if (put_user(id, (int __user *)arg)) | ||
251 | ret = -EFAULT; | ||
252 | break; | ||
253 | case IMDELTIMER: | ||
254 | if (get_user(id, (int __user *)arg)) { | ||
255 | ret = -EFAULT; | ||
256 | break; | ||
257 | } | ||
258 | if (*debug & DEBUG_TIMER) | ||
259 | printk(KERN_DEBUG "%s del id %d\n", __func__, id); | ||
260 | id = misdn_del_timer(dev, id); | ||
261 | if (put_user(id, (int __user *)arg)) | ||
262 | ret = -EFAULT; | ||
263 | break; | ||
264 | default: | ||
265 | ret = -EINVAL; | ||
266 | } | ||
267 | return ret; | ||
268 | } | ||
269 | |||
270 | static struct file_operations mISDN_fops = { | ||
271 | .llseek = mISDN_llseek, | ||
272 | .read = mISDN_read, | ||
273 | .write = mISDN_write, | ||
274 | .poll = mISDN_poll, | ||
275 | .ioctl = mISDN_ioctl, | ||
276 | .open = mISDN_open, | ||
277 | .release = mISDN_close, | ||
278 | }; | ||
279 | |||
280 | static struct miscdevice mISDNtimer = { | ||
281 | .minor = MISC_DYNAMIC_MINOR, | ||
282 | .name = "mISDNtimer", | ||
283 | .fops = &mISDN_fops, | ||
284 | }; | ||
285 | |||
286 | int | ||
287 | mISDN_inittimer(int *deb) | ||
288 | { | ||
289 | int err; | ||
290 | |||
291 | debug = deb; | ||
292 | err = misc_register(&mISDNtimer); | ||
293 | if (err) | ||
294 | printk(KERN_WARNING "mISDN: Could not register timer device\n"); | ||
295 | return err; | ||
296 | } | ||
297 | |||
298 | void mISDN_timer_cleanup(void) | ||
299 | { | ||
300 | misc_deregister(&mISDNtimer); | ||
301 | } | ||