diff options
| -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 | ||||
| -rw-r--r-- | include/linux/mISDNhw.h | 193 | ||||
| -rw-r--r-- | include/linux/mISDNif.h | 487 |
17 files changed, 7515 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 | } | ||
diff --git a/include/linux/mISDNhw.h b/include/linux/mISDNhw.h new file mode 100644 index 000000000000..e794dfb87504 --- /dev/null +++ b/include/linux/mISDNhw.h | |||
| @@ -0,0 +1,193 @@ | |||
| 1 | /* | ||
| 2 | * | ||
| 3 | * Author Karsten Keil <kkeil@novell.com> | ||
| 4 | * | ||
| 5 | * Basic declarations for the mISDN HW channels | ||
| 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 | #ifndef MISDNHW_H | ||
| 21 | #define MISDNHW_H | ||
| 22 | #include <linux/mISDNif.h> | ||
| 23 | #include <linux/timer.h> | ||
| 24 | |||
| 25 | /* | ||
| 26 | * HW DEBUG 0xHHHHGGGG | ||
| 27 | * H - hardware driver specific bits | ||
| 28 | * G - for all drivers | ||
| 29 | */ | ||
| 30 | |||
| 31 | #define DEBUG_HW 0x00000001 | ||
| 32 | #define DEBUG_HW_OPEN 0x00000002 | ||
| 33 | #define DEBUG_HW_DCHANNEL 0x00000100 | ||
| 34 | #define DEBUG_HW_DFIFO 0x00000200 | ||
| 35 | #define DEBUG_HW_BCHANNEL 0x00001000 | ||
| 36 | #define DEBUG_HW_BFIFO 0x00002000 | ||
| 37 | |||
| 38 | #define MAX_DFRAME_LEN_L1 300 | ||
| 39 | #define MAX_MON_FRAME 32 | ||
| 40 | #define MAX_LOG_SPACE 2048 | ||
| 41 | #define MISDN_COPY_SIZE 32 | ||
| 42 | |||
| 43 | /* channel->Flags bit field */ | ||
| 44 | #define FLG_TX_BUSY 0 /* tx_buf in use */ | ||
| 45 | #define FLG_TX_NEXT 1 /* next_skb in use */ | ||
| 46 | #define FLG_L1_BUSY 2 /* L1 is permanent busy */ | ||
| 47 | #define FLG_L2_ACTIVATED 3 /* activated from L2 */ | ||
| 48 | #define FLG_OPEN 5 /* channel is in use */ | ||
| 49 | #define FLG_ACTIVE 6 /* channel is activated */ | ||
| 50 | #define FLG_BUSY_TIMER 7 | ||
| 51 | /* channel type */ | ||
| 52 | #define FLG_DCHANNEL 8 /* channel is D-channel */ | ||
| 53 | #define FLG_BCHANNEL 9 /* channel is B-channel */ | ||
| 54 | #define FLG_ECHANNEL 10 /* channel is E-channel */ | ||
| 55 | #define FLG_TRANSPARENT 12 /* channel use transparent data */ | ||
| 56 | #define FLG_HDLC 13 /* channel use hdlc data */ | ||
| 57 | #define FLG_L2DATA 14 /* channel use L2 DATA primitivs */ | ||
| 58 | #define FLG_ORIGIN 15 /* channel is on origin site */ | ||
| 59 | /* channel specific stuff */ | ||
| 60 | /* arcofi specific */ | ||
| 61 | #define FLG_ARCOFI_TIMER 16 | ||
| 62 | #define FLG_ARCOFI_ERROR 17 | ||
| 63 | /* isar specific */ | ||
| 64 | #define FLG_INITIALIZED 16 | ||
| 65 | #define FLG_DLEETX 17 | ||
| 66 | #define FLG_LASTDLE 18 | ||
| 67 | #define FLG_FIRST 19 | ||
| 68 | #define FLG_LASTDATA 20 | ||
| 69 | #define FLG_NMD_DATA 21 | ||
| 70 | #define FLG_FTI_RUN 22 | ||
| 71 | #define FLG_LL_OK 23 | ||
| 72 | #define FLG_LL_CONN 24 | ||
| 73 | #define FLG_DTMFSEND 25 | ||
| 74 | |||
| 75 | /* workq events */ | ||
| 76 | #define FLG_RECVQUEUE 30 | ||
| 77 | #define FLG_PHCHANGE 31 | ||
| 78 | |||
| 79 | #define schedule_event(s, ev) do { \ | ||
| 80 | test_and_set_bit(ev, &((s)->Flags)); \ | ||
| 81 | schedule_work(&((s)->workq)); \ | ||
| 82 | } while (0) | ||
| 83 | |||
| 84 | struct dchannel { | ||
| 85 | struct mISDNdevice dev; | ||
| 86 | u_long Flags; | ||
| 87 | struct work_struct workq; | ||
| 88 | void (*phfunc) (struct dchannel *); | ||
| 89 | u_int state; | ||
| 90 | void *l1; | ||
| 91 | /* HW access */ | ||
| 92 | u_char (*read_reg) (void *, u_char); | ||
| 93 | void (*write_reg) (void *, u_char, u_char); | ||
| 94 | void (*read_fifo) (void *, u_char *, int); | ||
| 95 | void (*write_fifo) (void *, u_char *, int); | ||
| 96 | void *hw; | ||
| 97 | int slot; /* multiport card channel slot */ | ||
| 98 | struct timer_list timer; | ||
| 99 | /* receive data */ | ||
| 100 | struct sk_buff *rx_skb; | ||
| 101 | int maxlen; | ||
| 102 | /* send data */ | ||
| 103 | struct sk_buff_head squeue; | ||
| 104 | struct sk_buff_head rqueue; | ||
| 105 | struct sk_buff *tx_skb; | ||
| 106 | int tx_idx; | ||
| 107 | int debug; | ||
| 108 | /* statistics */ | ||
| 109 | int err_crc; | ||
| 110 | int err_tx; | ||
| 111 | int err_rx; | ||
| 112 | }; | ||
| 113 | |||
| 114 | typedef int (dchannel_l1callback)(struct dchannel *, u_int); | ||
| 115 | extern int create_l1(struct dchannel *, dchannel_l1callback *); | ||
| 116 | |||
| 117 | /* private L1 commands */ | ||
| 118 | #define INFO0 0x8002 | ||
| 119 | #define INFO1 0x8102 | ||
| 120 | #define INFO2 0x8202 | ||
| 121 | #define INFO3_P8 0x8302 | ||
| 122 | #define INFO3_P10 0x8402 | ||
| 123 | #define INFO4_P8 0x8502 | ||
| 124 | #define INFO4_P10 0x8602 | ||
| 125 | #define LOSTFRAMING 0x8702 | ||
| 126 | #define ANYSIGNAL 0x8802 | ||
| 127 | #define HW_POWERDOWN 0x8902 | ||
| 128 | #define HW_RESET_REQ 0x8a02 | ||
| 129 | #define HW_POWERUP_REQ 0x8b02 | ||
| 130 | #define HW_DEACT_REQ 0x8c02 | ||
| 131 | #define HW_ACTIVATE_REQ 0x8e02 | ||
| 132 | #define HW_D_NOBLOCKED 0x8f02 | ||
| 133 | #define HW_RESET_IND 0x9002 | ||
| 134 | #define HW_POWERUP_IND 0x9102 | ||
| 135 | #define HW_DEACT_IND 0x9202 | ||
| 136 | #define HW_ACTIVATE_IND 0x9302 | ||
| 137 | #define HW_DEACT_CNF 0x9402 | ||
| 138 | #define HW_TESTLOOP 0x9502 | ||
| 139 | #define HW_TESTRX_RAW 0x9602 | ||
| 140 | #define HW_TESTRX_HDLC 0x9702 | ||
| 141 | #define HW_TESTRX_OFF 0x9802 | ||
| 142 | |||
| 143 | struct layer1; | ||
| 144 | extern int l1_event(struct layer1 *, u_int); | ||
| 145 | |||
| 146 | |||
| 147 | struct bchannel { | ||
| 148 | struct mISDNchannel ch; | ||
| 149 | int nr; | ||
| 150 | u_long Flags; | ||
| 151 | struct work_struct workq; | ||
| 152 | u_int state; | ||
| 153 | /* HW access */ | ||
| 154 | u_char (*read_reg) (void *, u_char); | ||
| 155 | void (*write_reg) (void *, u_char, u_char); | ||
| 156 | void (*read_fifo) (void *, u_char *, int); | ||
| 157 | void (*write_fifo) (void *, u_char *, int); | ||
| 158 | void *hw; | ||
| 159 | int slot; /* multiport card channel slot */ | ||
| 160 | struct timer_list timer; | ||
| 161 | /* receive data */ | ||
| 162 | struct sk_buff *rx_skb; | ||
| 163 | int maxlen; | ||
| 164 | /* send data */ | ||
| 165 | struct sk_buff *next_skb; | ||
| 166 | struct sk_buff *tx_skb; | ||
| 167 | struct sk_buff_head rqueue; | ||
| 168 | int rcount; | ||
| 169 | int tx_idx; | ||
| 170 | int debug; | ||
| 171 | /* statistics */ | ||
| 172 | int err_crc; | ||
| 173 | int err_tx; | ||
| 174 | int err_rx; | ||
| 175 | }; | ||
| 176 | |||
| 177 | extern int mISDN_initdchannel(struct dchannel *, int, void *); | ||
| 178 | extern int mISDN_initbchannel(struct bchannel *, int); | ||
| 179 | extern int mISDN_freedchannel(struct dchannel *); | ||
| 180 | extern int mISDN_freebchannel(struct bchannel *); | ||
| 181 | extern void queue_ch_frame(struct mISDNchannel *, u_int, | ||
| 182 | int, struct sk_buff *); | ||
| 183 | extern int dchannel_senddata(struct dchannel *, struct sk_buff *); | ||
| 184 | extern int bchannel_senddata(struct bchannel *, struct sk_buff *); | ||
| 185 | extern void recv_Dchannel(struct dchannel *); | ||
| 186 | extern void recv_Bchannel(struct bchannel *); | ||
| 187 | extern void recv_Dchannel_skb(struct dchannel *, struct sk_buff *); | ||
| 188 | extern void recv_Bchannel_skb(struct bchannel *, struct sk_buff *); | ||
| 189 | extern void confirm_Bsend(struct bchannel *bch); | ||
| 190 | extern int get_next_bframe(struct bchannel *); | ||
| 191 | extern int get_next_dframe(struct dchannel *); | ||
| 192 | |||
| 193 | #endif | ||
diff --git a/include/linux/mISDNif.h b/include/linux/mISDNif.h new file mode 100644 index 000000000000..5c948f337817 --- /dev/null +++ b/include/linux/mISDNif.h | |||
| @@ -0,0 +1,487 @@ | |||
| 1 | /* | ||
| 2 | * | ||
| 3 | * Author Karsten Keil <kkeil@novell.com> | ||
| 4 | * | ||
| 5 | * Copyright 2008 by Karsten Keil <kkeil@novell.com> | ||
| 6 | * | ||
| 7 | * This code is free software; you can redistribute it and/or modify | ||
| 8 | * it under the terms of the GNU LESSER GENERAL PUBLIC LICENSE | ||
| 9 | * version 2.1 as published by the Free Software Foundation. | ||
| 10 | * | ||
| 11 | * This code 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 LESSER GENERAL PUBLIC LICENSE for more details. | ||
| 15 | * | ||
| 16 | */ | ||
| 17 | |||
| 18 | #ifndef mISDNIF_H | ||
| 19 | #define mISDNIF_H | ||
| 20 | |||
| 21 | #include <stdarg.h> | ||
| 22 | #include <linux/types.h> | ||
| 23 | #include <linux/errno.h> | ||
| 24 | #include <linux/socket.h> | ||
| 25 | |||
| 26 | /* | ||
| 27 | * ABI Version 32 bit | ||
| 28 | * | ||
| 29 | * <8 bit> Major version | ||
| 30 | * - changed if any interface become backwards incompatible | ||
| 31 | * | ||
| 32 | * <8 bit> Minor version | ||
| 33 | * - changed if any interface is extended but backwards compatible | ||
| 34 | * | ||
| 35 | * <16 bit> Release number | ||
| 36 | * - should be incremented on every checkin | ||
| 37 | */ | ||
| 38 | #define MISDN_MAJOR_VERSION 1 | ||
| 39 | #define MISDN_MINOR_VERSION 0 | ||
| 40 | #define MISDN_RELEASE 18 | ||
| 41 | |||
| 42 | /* primitives for information exchange | ||
| 43 | * generell format | ||
| 44 | * <16 bit 0 > | ||
| 45 | * <8 bit command> | ||
| 46 | * BIT 8 = 1 LAYER private | ||
| 47 | * BIT 7 = 1 answer | ||
| 48 | * BIT 6 = 1 DATA | ||
| 49 | * <8 bit target layer mask> | ||
| 50 | * | ||
| 51 | * Layer = 00 is reserved for general commands | ||
| 52 | Layer = 01 L2 -> HW | ||
| 53 | Layer = 02 HW -> L2 | ||
| 54 | Layer = 04 L3 -> L2 | ||
| 55 | Layer = 08 L2 -> L3 | ||
| 56 | * Layer = FF is reserved for broadcast commands | ||
| 57 | */ | ||
| 58 | |||
| 59 | #define MISDN_CMDMASK 0xff00 | ||
| 60 | #define MISDN_LAYERMASK 0x00ff | ||
| 61 | |||
| 62 | /* generell commands */ | ||
| 63 | #define OPEN_CHANNEL 0x0100 | ||
| 64 | #define CLOSE_CHANNEL 0x0200 | ||
| 65 | #define CONTROL_CHANNEL 0x0300 | ||
| 66 | #define CHECK_DATA 0x0400 | ||
| 67 | |||
| 68 | /* layer 2 -> layer 1 */ | ||
| 69 | #define PH_ACTIVATE_REQ 0x0101 | ||
| 70 | #define PH_DEACTIVATE_REQ 0x0201 | ||
| 71 | #define PH_DATA_REQ 0x2001 | ||
| 72 | #define MPH_ACTIVATE_REQ 0x0501 | ||
| 73 | #define MPH_DEACTIVATE_REQ 0x0601 | ||
| 74 | #define MPH_INFORMATION_REQ 0x0701 | ||
| 75 | #define PH_CONTROL_REQ 0x0801 | ||
| 76 | |||
| 77 | /* layer 1 -> layer 2 */ | ||
| 78 | #define PH_ACTIVATE_IND 0x0102 | ||
| 79 | #define PH_ACTIVATE_CNF 0x4102 | ||
| 80 | #define PH_DEACTIVATE_IND 0x0202 | ||
| 81 | #define PH_DEACTIVATE_CNF 0x4202 | ||
| 82 | #define PH_DATA_IND 0x2002 | ||
| 83 | #define MPH_ACTIVATE_IND 0x0502 | ||
| 84 | #define MPH_DEACTIVATE_IND 0x0602 | ||
| 85 | #define MPH_INFORMATION_IND 0x0702 | ||
| 86 | #define PH_DATA_CNF 0x6002 | ||
| 87 | #define PH_CONTROL_IND 0x0802 | ||
| 88 | #define PH_CONTROL_CNF 0x4802 | ||
| 89 | |||
| 90 | /* layer 3 -> layer 2 */ | ||
| 91 | #define DL_ESTABLISH_REQ 0x1004 | ||
| 92 | #define DL_RELEASE_REQ 0x1104 | ||
| 93 | #define DL_DATA_REQ 0x3004 | ||
| 94 | #define DL_UNITDATA_REQ 0x3104 | ||
| 95 | #define DL_INFORMATION_REQ 0x0004 | ||
| 96 | |||
| 97 | /* layer 2 -> layer 3 */ | ||
| 98 | #define DL_ESTABLISH_IND 0x1008 | ||
| 99 | #define DL_ESTABLISH_CNF 0x5008 | ||
| 100 | #define DL_RELEASE_IND 0x1108 | ||
| 101 | #define DL_RELEASE_CNF 0x5108 | ||
| 102 | #define DL_DATA_IND 0x3008 | ||
| 103 | #define DL_UNITDATA_IND 0x3108 | ||
| 104 | #define DL_INFORMATION_IND 0x0008 | ||
| 105 | |||
| 106 | /* intern layer 2 managment */ | ||
| 107 | #define MDL_ASSIGN_REQ 0x1804 | ||
| 108 | #define MDL_ASSIGN_IND 0x1904 | ||
| 109 | #define MDL_REMOVE_REQ 0x1A04 | ||
| 110 | #define MDL_REMOVE_IND 0x1B04 | ||
| 111 | #define MDL_STATUS_UP_IND 0x1C04 | ||
| 112 | #define MDL_STATUS_DOWN_IND 0x1D04 | ||
| 113 | #define MDL_STATUS_UI_IND 0x1E04 | ||
| 114 | #define MDL_ERROR_IND 0x1F04 | ||
| 115 | #define MDL_ERROR_RSP 0x5F04 | ||
| 116 | |||
| 117 | /* DL_INFORMATION_IND types */ | ||
| 118 | #define DL_INFO_L2_CONNECT 0x0001 | ||
| 119 | #define DL_INFO_L2_REMOVED 0x0002 | ||
| 120 | |||
| 121 | /* PH_CONTROL types */ | ||
| 122 | /* TOUCH TONE IS 0x20XX XX "0"..."9", "A","B","C","D","*","#" */ | ||
| 123 | #define DTMF_TONE_VAL 0x2000 | ||
| 124 | #define DTMF_TONE_MASK 0x007F | ||
| 125 | #define DTMF_TONE_START 0x2100 | ||
| 126 | #define DTMF_TONE_STOP 0x2200 | ||
| 127 | #define DTMF_HFC_COEF 0x4000 | ||
| 128 | #define DSP_CONF_JOIN 0x2403 | ||
| 129 | #define DSP_CONF_SPLIT 0x2404 | ||
| 130 | #define DSP_RECEIVE_OFF 0x2405 | ||
| 131 | #define DSP_RECEIVE_ON 0x2406 | ||
| 132 | #define DSP_ECHO_ON 0x2407 | ||
| 133 | #define DSP_ECHO_OFF 0x2408 | ||
| 134 | #define DSP_MIX_ON 0x2409 | ||
| 135 | #define DSP_MIX_OFF 0x240a | ||
| 136 | #define DSP_DELAY 0x240b | ||
| 137 | #define DSP_JITTER 0x240c | ||
| 138 | #define DSP_TXDATA_ON 0x240d | ||
| 139 | #define DSP_TXDATA_OFF 0x240e | ||
| 140 | #define DSP_TX_DEJITTER 0x240f | ||
| 141 | #define DSP_TX_DEJ_OFF 0x2410 | ||
| 142 | #define DSP_TONE_PATT_ON 0x2411 | ||
| 143 | #define DSP_TONE_PATT_OFF 0x2412 | ||
| 144 | #define DSP_VOL_CHANGE_TX 0x2413 | ||
| 145 | #define DSP_VOL_CHANGE_RX 0x2414 | ||
| 146 | #define DSP_BF_ENABLE_KEY 0x2415 | ||
| 147 | #define DSP_BF_DISABLE 0x2416 | ||
| 148 | #define DSP_BF_ACCEPT 0x2416 | ||
| 149 | #define DSP_BF_REJECT 0x2417 | ||
| 150 | #define DSP_PIPELINE_CFG 0x2418 | ||
| 151 | #define HFC_VOL_CHANGE_TX 0x2601 | ||
| 152 | #define HFC_VOL_CHANGE_RX 0x2602 | ||
| 153 | #define HFC_SPL_LOOP_ON 0x2603 | ||
| 154 | #define HFC_SPL_LOOP_OFF 0x2604 | ||
| 155 | |||
| 156 | /* DSP_TONE_PATT_ON parameter */ | ||
| 157 | #define TONE_OFF 0x0000 | ||
| 158 | #define TONE_GERMAN_DIALTONE 0x0001 | ||
| 159 | #define TONE_GERMAN_OLDDIALTONE 0x0002 | ||
| 160 | #define TONE_AMERICAN_DIALTONE 0x0003 | ||
| 161 | #define TONE_GERMAN_DIALPBX 0x0004 | ||
| 162 | #define TONE_GERMAN_OLDDIALPBX 0x0005 | ||
| 163 | #define TONE_AMERICAN_DIALPBX 0x0006 | ||
| 164 | #define TONE_GERMAN_RINGING 0x0007 | ||
| 165 | #define TONE_GERMAN_OLDRINGING 0x0008 | ||
| 166 | #define TONE_AMERICAN_RINGPBX 0x000b | ||
| 167 | #define TONE_GERMAN_RINGPBX 0x000c | ||
| 168 | #define TONE_GERMAN_OLDRINGPBX 0x000d | ||
| 169 | #define TONE_AMERICAN_RINGING 0x000e | ||
| 170 | #define TONE_GERMAN_BUSY 0x000f | ||
| 171 | #define TONE_GERMAN_OLDBUSY 0x0010 | ||
| 172 | #define TONE_AMERICAN_BUSY 0x0011 | ||
| 173 | #define TONE_GERMAN_HANGUP 0x0012 | ||
| 174 | #define TONE_GERMAN_OLDHANGUP 0x0013 | ||
| 175 | #define TONE_AMERICAN_HANGUP 0x0014 | ||
| 176 | #define TONE_SPECIAL_INFO 0x0015 | ||
| 177 | #define TONE_GERMAN_GASSENBESETZT 0x0016 | ||
| 178 | #define TONE_GERMAN_AUFSCHALTTON 0x0016 | ||
| 179 | |||
| 180 | /* MPH_INFORMATION_IND */ | ||
| 181 | #define L1_SIGNAL_LOS_OFF 0x0010 | ||
| 182 | #define L1_SIGNAL_LOS_ON 0x0011 | ||
| 183 | #define L1_SIGNAL_AIS_OFF 0x0012 | ||
| 184 | #define L1_SIGNAL_AIS_ON 0x0013 | ||
| 185 | #define L1_SIGNAL_RDI_OFF 0x0014 | ||
| 186 | #define L1_SIGNAL_RDI_ON 0x0015 | ||
| 187 | #define L1_SIGNAL_SLIP_RX 0x0020 | ||
| 188 | #define L1_SIGNAL_SLIP_TX 0x0021 | ||
| 189 | |||
| 190 | /* | ||
| 191 | * protocol ids | ||
| 192 | * D channel 1-31 | ||
| 193 | * B channel 33 - 63 | ||
| 194 | */ | ||
| 195 | |||
| 196 | #define ISDN_P_NONE 0 | ||
| 197 | #define ISDN_P_BASE 0 | ||
| 198 | #define ISDN_P_TE_S0 0x01 | ||
| 199 | #define ISDN_P_NT_S0 0x02 | ||
| 200 | #define ISDN_P_TE_E1 0x03 | ||
| 201 | #define ISDN_P_NT_E1 0x04 | ||
| 202 | #define ISDN_P_LAPD_TE 0x10 | ||
| 203 | #define ISDN_P_LAPD_NT 0x11 | ||
| 204 | |||
| 205 | #define ISDN_P_B_MASK 0x1f | ||
| 206 | #define ISDN_P_B_START 0x20 | ||
| 207 | |||
| 208 | #define ISDN_P_B_RAW 0x21 | ||
| 209 | #define ISDN_P_B_HDLC 0x22 | ||
| 210 | #define ISDN_P_B_X75SLP 0x23 | ||
| 211 | #define ISDN_P_B_L2DTMF 0x24 | ||
| 212 | #define ISDN_P_B_L2DSP 0x25 | ||
| 213 | #define ISDN_P_B_L2DSPHDLC 0x26 | ||
| 214 | |||
| 215 | #define OPTION_L2_PMX 1 | ||
| 216 | #define OPTION_L2_PTP 2 | ||
| 217 | #define OPTION_L2_FIXEDTEI 3 | ||
| 218 | #define OPTION_L2_CLEANUP 4 | ||
| 219 | |||
| 220 | /* should be in sync with linux/kobject.h:KOBJ_NAME_LEN */ | ||
| 221 | #define MISDN_MAX_IDLEN 20 | ||
| 222 | |||
| 223 | struct mISDNhead { | ||
| 224 | unsigned int prim; | ||
| 225 | unsigned int id; | ||
| 226 | } __attribute__((packed)); | ||
| 227 | |||
| 228 | #define MISDN_HEADER_LEN sizeof(struct mISDNhead) | ||
| 229 | #define MAX_DATA_SIZE 2048 | ||
| 230 | #define MAX_DATA_MEM (MAX_DATA_SIZE + MISDN_HEADER_LEN) | ||
| 231 | #define MAX_DFRAME_LEN 260 | ||
| 232 | |||
| 233 | #define MISDN_ID_ADDR_MASK 0xFFFF | ||
| 234 | #define MISDN_ID_TEI_MASK 0xFF00 | ||
| 235 | #define MISDN_ID_SAPI_MASK 0x00FF | ||
| 236 | #define MISDN_ID_TEI_ANY 0x7F00 | ||
| 237 | |||
| 238 | #define MISDN_ID_ANY 0xFFFF | ||
| 239 | #define MISDN_ID_NONE 0xFFFE | ||
| 240 | |||
| 241 | #define GROUP_TEI 127 | ||
| 242 | #define TEI_SAPI 63 | ||
| 243 | #define CTRL_SAPI 0 | ||
| 244 | |||
| 245 | #define MISDN_CHMAP_SIZE 4 | ||
| 246 | |||
| 247 | #define SOL_MISDN 0 | ||
| 248 | |||
| 249 | struct sockaddr_mISDN { | ||
| 250 | sa_family_t family; | ||
| 251 | unsigned char dev; | ||
| 252 | unsigned char channel; | ||
| 253 | unsigned char sapi; | ||
| 254 | unsigned char tei; | ||
| 255 | }; | ||
| 256 | |||
| 257 | /* timer device ioctl */ | ||
| 258 | #define IMADDTIMER _IOR('I', 64, int) | ||
| 259 | #define IMDELTIMER _IOR('I', 65, int) | ||
| 260 | /* socket ioctls */ | ||
| 261 | #define IMGETVERSION _IOR('I', 66, int) | ||
| 262 | #define IMGETCOUNT _IOR('I', 67, int) | ||
| 263 | #define IMGETDEVINFO _IOR('I', 68, int) | ||
| 264 | #define IMCTRLREQ _IOR('I', 69, int) | ||
| 265 | #define IMCLEAR_L2 _IOR('I', 70, int) | ||
| 266 | |||
| 267 | struct mISDNversion { | ||
| 268 | unsigned char major; | ||
| 269 | unsigned char minor; | ||
| 270 | unsigned short release; | ||
| 271 | }; | ||
| 272 | |||
| 273 | struct mISDN_devinfo { | ||
| 274 | u_int id; | ||
| 275 | u_int Dprotocols; | ||
| 276 | u_int Bprotocols; | ||
| 277 | u_int protocol; | ||
| 278 | u_long channelmap[MISDN_CHMAP_SIZE]; | ||
| 279 | u_int nrbchan; | ||
| 280 | char name[MISDN_MAX_IDLEN]; | ||
| 281 | }; | ||
| 282 | |||
| 283 | /* CONTROL_CHANNEL parameters */ | ||
| 284 | #define MISDN_CTRL_GETOP 0x0000 | ||
| 285 | #define MISDN_CTRL_LOOP 0x0001 | ||
| 286 | #define MISDN_CTRL_CONNECT 0x0002 | ||
| 287 | #define MISDN_CTRL_DISCONNECT 0x0004 | ||
| 288 | #define MISDN_CTRL_PCMCONNECT 0x0010 | ||
| 289 | #define MISDN_CTRL_PCMDISCONNECT 0x0020 | ||
| 290 | #define MISDN_CTRL_SETPEER 0x0040 | ||
| 291 | #define MISDN_CTRL_UNSETPEER 0x0080 | ||
| 292 | #define MISDN_CTRL_RX_OFF 0x0100 | ||
| 293 | #define MISDN_CTRL_HW_FEATURES_OP 0x2000 | ||
| 294 | #define MISDN_CTRL_HW_FEATURES 0x2001 | ||
| 295 | #define MISDN_CTRL_HFC_OP 0x4000 | ||
| 296 | #define MISDN_CTRL_HFC_PCM_CONN 0x4001 | ||
| 297 | #define MISDN_CTRL_HFC_PCM_DISC 0x4002 | ||
| 298 | #define MISDN_CTRL_HFC_CONF_JOIN 0x4003 | ||
| 299 | #define MISDN_CTRL_HFC_CONF_SPLIT 0x4004 | ||
| 300 | #define MISDN_CTRL_HFC_RECEIVE_OFF 0x4005 | ||
| 301 | #define MISDN_CTRL_HFC_RECEIVE_ON 0x4006 | ||
| 302 | #define MISDN_CTRL_HFC_ECHOCAN_ON 0x4007 | ||
| 303 | #define MISDN_CTRL_HFC_ECHOCAN_OFF 0x4008 | ||
| 304 | |||
| 305 | |||
| 306 | /* socket options */ | ||
| 307 | #define MISDN_TIME_STAMP 0x0001 | ||
| 308 | |||
| 309 | struct mISDN_ctrl_req { | ||
| 310 | int op; | ||
| 311 | int channel; | ||
| 312 | int p1; | ||
| 313 | int p2; | ||
| 314 | }; | ||
| 315 | |||
| 316 | /* muxer options */ | ||
| 317 | #define MISDN_OPT_ALL 1 | ||
| 318 | #define MISDN_OPT_TEIMGR 2 | ||
| 319 | |||
| 320 | #ifdef __KERNEL__ | ||
| 321 | #include <linux/list.h> | ||
| 322 | #include <linux/skbuff.h> | ||
| 323 | #include <linux/net.h> | ||
| 324 | #include <net/sock.h> | ||
| 325 | #include <linux/completion.h> | ||
| 326 | |||
| 327 | #define DEBUG_CORE 0x000000ff | ||
| 328 | #define DEBUG_CORE_FUNC 0x00000002 | ||
| 329 | #define DEBUG_SOCKET 0x00000004 | ||
| 330 | #define DEBUG_MANAGER 0x00000008 | ||
| 331 | #define DEBUG_SEND_ERR 0x00000010 | ||
| 332 | #define DEBUG_MSG_THREAD 0x00000020 | ||
| 333 | #define DEBUG_QUEUE_FUNC 0x00000040 | ||
| 334 | #define DEBUG_L1 0x0000ff00 | ||
| 335 | #define DEBUG_L1_FSM 0x00000200 | ||
| 336 | #define DEBUG_L2 0x00ff0000 | ||
| 337 | #define DEBUG_L2_FSM 0x00020000 | ||
| 338 | #define DEBUG_L2_CTRL 0x00040000 | ||
| 339 | #define DEBUG_L2_RECV 0x00080000 | ||
| 340 | #define DEBUG_L2_TEI 0x00100000 | ||
| 341 | #define DEBUG_L2_TEIFSM 0x00200000 | ||
| 342 | #define DEBUG_TIMER 0x01000000 | ||
| 343 | |||
| 344 | #define mISDN_HEAD_P(s) ((struct mISDNhead *)&s->cb[0]) | ||
| 345 | #define mISDN_HEAD_PRIM(s) (((struct mISDNhead *)&s->cb[0])->prim) | ||
| 346 | #define mISDN_HEAD_ID(s) (((struct mISDNhead *)&s->cb[0])->id) | ||
| 347 | |||
| 348 | /* socket states */ | ||
| 349 | #define MISDN_OPEN 1 | ||
| 350 | #define MISDN_BOUND 2 | ||
| 351 | #define MISDN_CLOSED 3 | ||
| 352 | |||
| 353 | struct mISDNchannel; | ||
| 354 | struct mISDNdevice; | ||
| 355 | struct mISDNstack; | ||
| 356 | |||
| 357 | struct channel_req { | ||
| 358 | u_int protocol; | ||
| 359 | struct sockaddr_mISDN adr; | ||
| 360 | struct mISDNchannel *ch; | ||
| 361 | }; | ||
| 362 | |||
| 363 | typedef int (ctrl_func_t)(struct mISDNchannel *, u_int, void *); | ||
| 364 | typedef int (send_func_t)(struct mISDNchannel *, struct sk_buff *); | ||
| 365 | typedef int (create_func_t)(struct channel_req *); | ||
| 366 | |||
| 367 | struct Bprotocol { | ||
| 368 | struct list_head list; | ||
| 369 | char *name; | ||
| 370 | u_int Bprotocols; | ||
| 371 | create_func_t *create; | ||
| 372 | }; | ||
| 373 | |||
| 374 | struct mISDNchannel { | ||
| 375 | struct list_head list; | ||
| 376 | u_int protocol; | ||
| 377 | u_int nr; | ||
| 378 | u_long opt; | ||
| 379 | u_int addr; | ||
| 380 | struct mISDNstack *st; | ||
| 381 | struct mISDNchannel *peer; | ||
| 382 | send_func_t *send; | ||
| 383 | send_func_t *recv; | ||
| 384 | ctrl_func_t *ctrl; | ||
| 385 | }; | ||
| 386 | |||
| 387 | struct mISDN_sock_list { | ||
| 388 | struct hlist_head head; | ||
| 389 | rwlock_t lock; | ||
| 390 | }; | ||
| 391 | |||
| 392 | struct mISDN_sock { | ||
| 393 | struct sock sk; | ||
| 394 | struct mISDNchannel ch; | ||
| 395 | u_int cmask; | ||
| 396 | struct mISDNdevice *dev; | ||
| 397 | }; | ||
| 398 | |||
| 399 | |||
| 400 | |||
| 401 | struct mISDNdevice { | ||
| 402 | struct mISDNchannel D; | ||
| 403 | u_int id; | ||
| 404 | char name[MISDN_MAX_IDLEN]; | ||
| 405 | u_int Dprotocols; | ||
| 406 | u_int Bprotocols; | ||
| 407 | u_int nrbchan; | ||
| 408 | u_long channelmap[MISDN_CHMAP_SIZE]; | ||
| 409 | struct list_head bchannels; | ||
| 410 | struct mISDNchannel *teimgr; | ||
| 411 | struct device dev; | ||
| 412 | }; | ||
| 413 | |||
| 414 | struct mISDNstack { | ||
| 415 | u_long status; | ||
| 416 | struct mISDNdevice *dev; | ||
| 417 | struct task_struct *thread; | ||
| 418 | struct completion *notify; | ||
| 419 | wait_queue_head_t workq; | ||
| 420 | struct sk_buff_head msgq; | ||
| 421 | struct list_head layer2; | ||
| 422 | struct mISDNchannel *layer1; | ||
| 423 | struct mISDNchannel own; | ||
| 424 | struct mutex lmutex; /* protect lists */ | ||
| 425 | struct mISDN_sock_list l1sock; | ||
| 426 | #ifdef MISDN_MSG_STATS | ||
| 427 | u_int msg_cnt; | ||
| 428 | u_int sleep_cnt; | ||
| 429 | u_int stopped_cnt; | ||
| 430 | #endif | ||
| 431 | }; | ||
| 432 | |||
| 433 | /* global alloc/queue dunctions */ | ||
| 434 | |||
| 435 | static inline struct sk_buff * | ||
| 436 | mI_alloc_skb(unsigned int len, gfp_t gfp_mask) | ||
| 437 | { | ||
| 438 | struct sk_buff *skb; | ||
| 439 | |||
| 440 | skb = alloc_skb(len + MISDN_HEADER_LEN, gfp_mask); | ||
| 441 | if (likely(skb)) | ||
| 442 | skb_reserve(skb, MISDN_HEADER_LEN); | ||
| 443 | return skb; | ||
| 444 | } | ||
| 445 | |||
| 446 | static inline struct sk_buff * | ||
| 447 | _alloc_mISDN_skb(u_int prim, u_int id, u_int len, void *dp, gfp_t gfp_mask) | ||
| 448 | { | ||
| 449 | struct sk_buff *skb = mI_alloc_skb(len, gfp_mask); | ||
| 450 | struct mISDNhead *hh; | ||
| 451 | |||
| 452 | if (!skb) | ||
| 453 | return NULL; | ||
| 454 | if (len) | ||
| 455 | memcpy(skb_put(skb, len), dp, len); | ||
| 456 | hh = mISDN_HEAD_P(skb); | ||
| 457 | hh->prim = prim; | ||
| 458 | hh->id = id; | ||
| 459 | return skb; | ||
| 460 | } | ||
| 461 | |||
| 462 | static inline void | ||
| 463 | _queue_data(struct mISDNchannel *ch, u_int prim, | ||
| 464 | u_int id, u_int len, void *dp, gfp_t gfp_mask) | ||
| 465 | { | ||
| 466 | struct sk_buff *skb; | ||
| 467 | |||
| 468 | if (!ch->peer) | ||
| 469 | return; | ||
| 470 | skb = _alloc_mISDN_skb(prim, id, len, dp, gfp_mask); | ||
| 471 | if (!skb) | ||
| 472 | return; | ||
| 473 | if (ch->recv(ch->peer, skb)) | ||
| 474 | dev_kfree_skb(skb); | ||
| 475 | } | ||
| 476 | |||
| 477 | /* global register/unregister functions */ | ||
| 478 | |||
| 479 | extern int mISDN_register_device(struct mISDNdevice *, char *name); | ||
| 480 | extern void mISDN_unregister_device(struct mISDNdevice *); | ||
| 481 | extern int mISDN_register_Bprotocol(struct Bprotocol *); | ||
| 482 | extern void mISDN_unregister_Bprotocol(struct Bprotocol *); | ||
| 483 | |||
| 484 | extern void set_channel_address(struct mISDNchannel *, u_int, u_int); | ||
| 485 | |||
| 486 | #endif /* __KERNEL__ */ | ||
| 487 | #endif /* mISDNIF_H */ | ||
