diff options
-rw-r--r-- | drivers/net/wan/cycx_drv.c | 569 | ||||
-rw-r--r-- | drivers/net/wan/cycx_main.c | 346 | ||||
-rw-r--r-- | drivers/net/wan/cycx_x25.c | 1602 | ||||
-rw-r--r-- | include/linux/cyclomx.h | 77 | ||||
-rw-r--r-- | include/linux/cycx_drv.h | 64 | ||||
-rw-r--r-- | include/linux/wanrouter.h | 127 | ||||
-rw-r--r-- | include/uapi/linux/wanrouter.h | 443 | ||||
-rw-r--r-- | net/wanrouter/Kconfig | 27 | ||||
-rw-r--r-- | net/wanrouter/Makefile | 7 | ||||
-rw-r--r-- | net/wanrouter/patchlevel | 1 | ||||
-rw-r--r-- | net/wanrouter/wanmain.c | 782 | ||||
-rw-r--r-- | net/wanrouter/wanproc.c | 380 |
12 files changed, 8 insertions, 4417 deletions
diff --git a/drivers/net/wan/cycx_drv.c b/drivers/net/wan/cycx_drv.c deleted file mode 100644 index 2a3ecae67a90..000000000000 --- a/drivers/net/wan/cycx_drv.c +++ /dev/null | |||
@@ -1,569 +0,0 @@ | |||
1 | /* | ||
2 | * cycx_drv.c Cyclom 2X Support Module. | ||
3 | * | ||
4 | * This module is a library of common hardware specific | ||
5 | * functions used by the Cyclades Cyclom 2X sync card. | ||
6 | * | ||
7 | * Author: Arnaldo Carvalho de Melo <acme@conectiva.com.br> | ||
8 | * | ||
9 | * Copyright: (c) 1998-2003 Arnaldo Carvalho de Melo | ||
10 | * | ||
11 | * Based on sdladrv.c by Gene Kozin <genek@compuserve.com> | ||
12 | * | ||
13 | * This program is free software; you can redistribute it and/or | ||
14 | * modify it under the terms of the GNU General Public License | ||
15 | * as published by the Free Software Foundation; either version | ||
16 | * 2 of the License, or (at your option) any later version. | ||
17 | * ============================================================================ | ||
18 | * 1999/11/11 acme set_current_state(TASK_INTERRUPTIBLE), code | ||
19 | * cleanup | ||
20 | * 1999/11/08 acme init_cyc2x deleted, doing nothing | ||
21 | * 1999/11/06 acme back to read[bw], write[bw] and memcpy_to and | ||
22 | * fromio to use dpmbase ioremaped | ||
23 | * 1999/10/26 acme use isa_read[bw], isa_write[bw] & isa_memcpy_to | ||
24 | * & fromio | ||
25 | * 1999/10/23 acme cleanup to only supports cyclom2x: all the other | ||
26 | * boards are no longer manufactured by cyclades, | ||
27 | * if someone wants to support them... be my guest! | ||
28 | * 1999/05/28 acme cycx_intack & cycx_intde gone for good | ||
29 | * 1999/05/18 acme lots of unlogged work, submitting to Linus... | ||
30 | * 1999/01/03 acme more judicious use of data types | ||
31 | * 1999/01/03 acme judicious use of data types :> | ||
32 | * cycx_inten trying to reset pending interrupts | ||
33 | * from cyclom 2x - I think this isn't the way to | ||
34 | * go, but for now... | ||
35 | * 1999/01/02 acme cycx_intack ok, I think there's nothing to do | ||
36 | * to ack an int in cycx_drv.c, only handle it in | ||
37 | * cyx_isr (or in the other protocols: cyp_isr, | ||
38 | * cyf_isr, when they get implemented. | ||
39 | * Dec 31, 1998 acme cycx_data_boot & cycx_code_boot fixed, crossing | ||
40 | * fingers to see x25_configure in cycx_x25.c | ||
41 | * work... :) | ||
42 | * Dec 26, 1998 acme load implementation fixed, seems to work! :) | ||
43 | * cycx_2x_dpmbase_options with all the possible | ||
44 | * DPM addresses (20). | ||
45 | * cycx_intr implemented (test this!) | ||
46 | * general code cleanup | ||
47 | * Dec 8, 1998 Ivan Passos Cyclom-2X firmware load implementation. | ||
48 | * Aug 8, 1998 acme Initial version. | ||
49 | */ | ||
50 | |||
51 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
52 | |||
53 | #include <linux/init.h> /* __init */ | ||
54 | #include <linux/module.h> | ||
55 | #include <linux/kernel.h> /* printk(), and other useful stuff */ | ||
56 | #include <linux/stddef.h> /* offsetof(), etc. */ | ||
57 | #include <linux/errno.h> /* return codes */ | ||
58 | #include <linux/cycx_drv.h> /* API definitions */ | ||
59 | #include <linux/cycx_cfm.h> /* CYCX firmware module definitions */ | ||
60 | #include <linux/delay.h> /* udelay, msleep_interruptible */ | ||
61 | #include <asm/io.h> /* read[wl], write[wl], ioremap, iounmap */ | ||
62 | |||
63 | #define MOD_VERSION 0 | ||
64 | #define MOD_RELEASE 6 | ||
65 | |||
66 | MODULE_AUTHOR("Arnaldo Carvalho de Melo"); | ||
67 | MODULE_DESCRIPTION("Cyclom 2x Sync Card Driver"); | ||
68 | MODULE_LICENSE("GPL"); | ||
69 | |||
70 | /* Hardware-specific functions */ | ||
71 | static int load_cyc2x(struct cycx_hw *hw, struct cycx_firmware *cfm, u32 len); | ||
72 | static void cycx_bootcfg(struct cycx_hw *hw); | ||
73 | |||
74 | static int reset_cyc2x(void __iomem *addr); | ||
75 | static int detect_cyc2x(void __iomem *addr); | ||
76 | |||
77 | /* Miscellaneous functions */ | ||
78 | static int get_option_index(const long *optlist, long optval); | ||
79 | static u16 checksum(u8 *buf, u32 len); | ||
80 | |||
81 | #define wait_cyc(addr) cycx_exec(addr + CMD_OFFSET) | ||
82 | |||
83 | /* Global Data */ | ||
84 | |||
85 | /* private data */ | ||
86 | static const char fullname[] = "Cyclom 2X Support Module"; | ||
87 | static const char copyright[] = | ||
88 | "(c) 1998-2003 Arnaldo Carvalho de Melo <acme@conectiva.com.br>"; | ||
89 | |||
90 | /* Hardware configuration options. | ||
91 | * These are arrays of configuration options used by verification routines. | ||
92 | * The first element of each array is its size (i.e. number of options). | ||
93 | */ | ||
94 | static const long cyc2x_dpmbase_options[] = { | ||
95 | 20, | ||
96 | 0xA0000, 0xA4000, 0xA8000, 0xAC000, 0xB0000, 0xB4000, 0xB8000, | ||
97 | 0xBC000, 0xC0000, 0xC4000, 0xC8000, 0xCC000, 0xD0000, 0xD4000, | ||
98 | 0xD8000, 0xDC000, 0xE0000, 0xE4000, 0xE8000, 0xEC000 | ||
99 | }; | ||
100 | |||
101 | static const long cycx_2x_irq_options[] = { 7, 3, 5, 9, 10, 11, 12, 15 }; | ||
102 | |||
103 | /* Kernel Loadable Module Entry Points */ | ||
104 | /* Module 'insert' entry point. | ||
105 | * o print announcement | ||
106 | * o initialize static data | ||
107 | * | ||
108 | * Return: 0 Ok | ||
109 | * < 0 error. | ||
110 | * Context: process */ | ||
111 | |||
112 | static int __init cycx_drv_init(void) | ||
113 | { | ||
114 | pr_info("%s v%u.%u %s\n", | ||
115 | fullname, MOD_VERSION, MOD_RELEASE, copyright); | ||
116 | |||
117 | return 0; | ||
118 | } | ||
119 | |||
120 | /* Module 'remove' entry point. | ||
121 | * o release all remaining system resources */ | ||
122 | static void cycx_drv_cleanup(void) | ||
123 | { | ||
124 | } | ||
125 | |||
126 | /* Kernel APIs */ | ||
127 | /* Set up adapter. | ||
128 | * o detect adapter type | ||
129 | * o verify hardware configuration options | ||
130 | * o check for hardware conflicts | ||
131 | * o set up adapter shared memory | ||
132 | * o test adapter memory | ||
133 | * o load firmware | ||
134 | * Return: 0 ok. | ||
135 | * < 0 error */ | ||
136 | EXPORT_SYMBOL(cycx_setup); | ||
137 | int cycx_setup(struct cycx_hw *hw, void *cfm, u32 len, unsigned long dpmbase) | ||
138 | { | ||
139 | int err; | ||
140 | |||
141 | /* Verify IRQ configuration options */ | ||
142 | if (!get_option_index(cycx_2x_irq_options, hw->irq)) { | ||
143 | pr_err("IRQ %d is invalid!\n", hw->irq); | ||
144 | return -EINVAL; | ||
145 | } | ||
146 | |||
147 | /* Setup adapter dual-port memory window and test memory */ | ||
148 | if (!dpmbase) { | ||
149 | pr_err("you must specify the dpm address!\n"); | ||
150 | return -EINVAL; | ||
151 | } else if (!get_option_index(cyc2x_dpmbase_options, dpmbase)) { | ||
152 | pr_err("memory address 0x%lX is invalid!\n", dpmbase); | ||
153 | return -EINVAL; | ||
154 | } | ||
155 | |||
156 | hw->dpmbase = ioremap(dpmbase, CYCX_WINDOWSIZE); | ||
157 | hw->dpmsize = CYCX_WINDOWSIZE; | ||
158 | |||
159 | if (!detect_cyc2x(hw->dpmbase)) { | ||
160 | pr_err("adapter Cyclom 2X not found at address 0x%lX!\n", | ||
161 | dpmbase); | ||
162 | return -EINVAL; | ||
163 | } | ||
164 | |||
165 | pr_info("found Cyclom 2X card at address 0x%lX\n", dpmbase); | ||
166 | |||
167 | /* Load firmware. If loader fails then shut down adapter */ | ||
168 | err = load_cyc2x(hw, cfm, len); | ||
169 | |||
170 | if (err) | ||
171 | cycx_down(hw); /* shutdown adapter */ | ||
172 | |||
173 | return err; | ||
174 | } | ||
175 | |||
176 | EXPORT_SYMBOL(cycx_down); | ||
177 | int cycx_down(struct cycx_hw *hw) | ||
178 | { | ||
179 | iounmap(hw->dpmbase); | ||
180 | return 0; | ||
181 | } | ||
182 | |||
183 | /* Enable interrupt generation. */ | ||
184 | static void cycx_inten(struct cycx_hw *hw) | ||
185 | { | ||
186 | writeb(0, hw->dpmbase); | ||
187 | } | ||
188 | |||
189 | /* Generate an interrupt to adapter's CPU. */ | ||
190 | EXPORT_SYMBOL(cycx_intr); | ||
191 | void cycx_intr(struct cycx_hw *hw) | ||
192 | { | ||
193 | writew(0, hw->dpmbase + GEN_CYCX_INTR); | ||
194 | } | ||
195 | |||
196 | /* Execute Adapter Command. | ||
197 | * o Set exec flag. | ||
198 | * o Busy-wait until flag is reset. */ | ||
199 | EXPORT_SYMBOL(cycx_exec); | ||
200 | int cycx_exec(void __iomem *addr) | ||
201 | { | ||
202 | u16 i = 0; | ||
203 | /* wait till addr content is zeroed */ | ||
204 | |||
205 | while (readw(addr)) { | ||
206 | udelay(1000); | ||
207 | |||
208 | if (++i > 50) | ||
209 | return -1; | ||
210 | } | ||
211 | |||
212 | return 0; | ||
213 | } | ||
214 | |||
215 | /* Read absolute adapter memory. | ||
216 | * Transfer data from adapter's memory to data buffer. */ | ||
217 | EXPORT_SYMBOL(cycx_peek); | ||
218 | int cycx_peek(struct cycx_hw *hw, u32 addr, void *buf, u32 len) | ||
219 | { | ||
220 | if (len == 1) | ||
221 | *(u8*)buf = readb(hw->dpmbase + addr); | ||
222 | else | ||
223 | memcpy_fromio(buf, hw->dpmbase + addr, len); | ||
224 | |||
225 | return 0; | ||
226 | } | ||
227 | |||
228 | /* Write Absolute Adapter Memory. | ||
229 | * Transfer data from data buffer to adapter's memory. */ | ||
230 | EXPORT_SYMBOL(cycx_poke); | ||
231 | int cycx_poke(struct cycx_hw *hw, u32 addr, void *buf, u32 len) | ||
232 | { | ||
233 | if (len == 1) | ||
234 | writeb(*(u8*)buf, hw->dpmbase + addr); | ||
235 | else | ||
236 | memcpy_toio(hw->dpmbase + addr, buf, len); | ||
237 | |||
238 | return 0; | ||
239 | } | ||
240 | |||
241 | /* Hardware-Specific Functions */ | ||
242 | |||
243 | /* Load Aux Routines */ | ||
244 | /* Reset board hardware. | ||
245 | return 1 if memory exists at addr and 0 if not. */ | ||
246 | static int memory_exists(void __iomem *addr) | ||
247 | { | ||
248 | int tries = 0; | ||
249 | |||
250 | for (; tries < 3 ; tries++) { | ||
251 | writew(TEST_PATTERN, addr + 0x10); | ||
252 | |||
253 | if (readw(addr + 0x10) == TEST_PATTERN) | ||
254 | if (readw(addr + 0x10) == TEST_PATTERN) | ||
255 | return 1; | ||
256 | |||
257 | msleep_interruptible(1 * 1000); | ||
258 | } | ||
259 | |||
260 | return 0; | ||
261 | } | ||
262 | |||
263 | /* Load reset code. */ | ||
264 | static void reset_load(void __iomem *addr, u8 *buffer, u32 cnt) | ||
265 | { | ||
266 | void __iomem *pt_code = addr + RESET_OFFSET; | ||
267 | u16 i; /*, j; */ | ||
268 | |||
269 | for (i = 0 ; i < cnt ; i++) { | ||
270 | /* for (j = 0 ; j < 50 ; j++); Delay - FIXME busy waiting... */ | ||
271 | writeb(*buffer++, pt_code++); | ||
272 | } | ||
273 | } | ||
274 | |||
275 | /* Load buffer using boot interface. | ||
276 | * o copy data from buffer to Cyclom-X memory | ||
277 | * o wait for reset code to copy it to right portion of memory */ | ||
278 | static int buffer_load(void __iomem *addr, u8 *buffer, u32 cnt) | ||
279 | { | ||
280 | memcpy_toio(addr + DATA_OFFSET, buffer, cnt); | ||
281 | writew(GEN_BOOT_DAT, addr + CMD_OFFSET); | ||
282 | |||
283 | return wait_cyc(addr); | ||
284 | } | ||
285 | |||
286 | /* Set up entry point and kick start Cyclom-X CPU. */ | ||
287 | static void cycx_start(void __iomem *addr) | ||
288 | { | ||
289 | /* put in 0x30 offset the jump instruction to the code entry point */ | ||
290 | writeb(0xea, addr + 0x30); | ||
291 | writeb(0x00, addr + 0x31); | ||
292 | writeb(0xc4, addr + 0x32); | ||
293 | writeb(0x00, addr + 0x33); | ||
294 | writeb(0x00, addr + 0x34); | ||
295 | |||
296 | /* cmd to start executing code */ | ||
297 | writew(GEN_START, addr + CMD_OFFSET); | ||
298 | } | ||
299 | |||
300 | /* Load and boot reset code. */ | ||
301 | static void cycx_reset_boot(void __iomem *addr, u8 *code, u32 len) | ||
302 | { | ||
303 | void __iomem *pt_start = addr + START_OFFSET; | ||
304 | |||
305 | writeb(0xea, pt_start++); /* jmp to f000:3f00 */ | ||
306 | writeb(0x00, pt_start++); | ||
307 | writeb(0xfc, pt_start++); | ||
308 | writeb(0x00, pt_start++); | ||
309 | writeb(0xf0, pt_start); | ||
310 | reset_load(addr, code, len); | ||
311 | |||
312 | /* 80186 was in hold, go */ | ||
313 | writeb(0, addr + START_CPU); | ||
314 | msleep_interruptible(1 * 1000); | ||
315 | } | ||
316 | |||
317 | /* Load data.bin file through boot (reset) interface. */ | ||
318 | static int cycx_data_boot(void __iomem *addr, u8 *code, u32 len) | ||
319 | { | ||
320 | void __iomem *pt_boot_cmd = addr + CMD_OFFSET; | ||
321 | u32 i; | ||
322 | |||
323 | /* boot buffer length */ | ||
324 | writew(CFM_LOAD_BUFSZ, pt_boot_cmd + sizeof(u16)); | ||
325 | writew(GEN_DEFPAR, pt_boot_cmd); | ||
326 | |||
327 | if (wait_cyc(addr) < 0) | ||
328 | return -1; | ||
329 | |||
330 | writew(0, pt_boot_cmd + sizeof(u16)); | ||
331 | writew(0x4000, pt_boot_cmd + 2 * sizeof(u16)); | ||
332 | writew(GEN_SET_SEG, pt_boot_cmd); | ||
333 | |||
334 | if (wait_cyc(addr) < 0) | ||
335 | return -1; | ||
336 | |||
337 | for (i = 0 ; i < len ; i += CFM_LOAD_BUFSZ) | ||
338 | if (buffer_load(addr, code + i, | ||
339 | min_t(u32, CFM_LOAD_BUFSZ, (len - i))) < 0) { | ||
340 | pr_err("Error !!\n"); | ||
341 | return -1; | ||
342 | } | ||
343 | |||
344 | return 0; | ||
345 | } | ||
346 | |||
347 | |||
348 | /* Load code.bin file through boot (reset) interface. */ | ||
349 | static int cycx_code_boot(void __iomem *addr, u8 *code, u32 len) | ||
350 | { | ||
351 | void __iomem *pt_boot_cmd = addr + CMD_OFFSET; | ||
352 | u32 i; | ||
353 | |||
354 | /* boot buffer length */ | ||
355 | writew(CFM_LOAD_BUFSZ, pt_boot_cmd + sizeof(u16)); | ||
356 | writew(GEN_DEFPAR, pt_boot_cmd); | ||
357 | |||
358 | if (wait_cyc(addr) < 0) | ||
359 | return -1; | ||
360 | |||
361 | writew(0x0000, pt_boot_cmd + sizeof(u16)); | ||
362 | writew(0xc400, pt_boot_cmd + 2 * sizeof(u16)); | ||
363 | writew(GEN_SET_SEG, pt_boot_cmd); | ||
364 | |||
365 | if (wait_cyc(addr) < 0) | ||
366 | return -1; | ||
367 | |||
368 | for (i = 0 ; i < len ; i += CFM_LOAD_BUFSZ) | ||
369 | if (buffer_load(addr, code + i, | ||
370 | min_t(u32, CFM_LOAD_BUFSZ, (len - i)))) { | ||
371 | pr_err("Error !!\n"); | ||
372 | return -1; | ||
373 | } | ||
374 | |||
375 | return 0; | ||
376 | } | ||
377 | |||
378 | /* Load adapter from the memory image of the CYCX firmware module. | ||
379 | * o verify firmware integrity and compatibility | ||
380 | * o start adapter up */ | ||
381 | static int load_cyc2x(struct cycx_hw *hw, struct cycx_firmware *cfm, u32 len) | ||
382 | { | ||
383 | int i, j; | ||
384 | struct cycx_fw_header *img_hdr; | ||
385 | u8 *reset_image, | ||
386 | *data_image, | ||
387 | *code_image; | ||
388 | void __iomem *pt_cycld = hw->dpmbase + 0x400; | ||
389 | u16 cksum; | ||
390 | |||
391 | /* Announce */ | ||
392 | pr_info("firmware signature=\"%s\"\n", cfm->signature); | ||
393 | |||
394 | /* Verify firmware signature */ | ||
395 | if (strcmp(cfm->signature, CFM_SIGNATURE)) { | ||
396 | pr_err("load_cyc2x: not Cyclom-2X firmware!\n"); | ||
397 | return -EINVAL; | ||
398 | } | ||
399 | |||
400 | pr_info("firmware version=%u\n", cfm->version); | ||
401 | |||
402 | /* Verify firmware module format version */ | ||
403 | if (cfm->version != CFM_VERSION) { | ||
404 | pr_err("%s: firmware format %u rejected! Expecting %u.\n", | ||
405 | __func__, cfm->version, CFM_VERSION); | ||
406 | return -EINVAL; | ||
407 | } | ||
408 | |||
409 | /* Verify firmware module length and checksum */ | ||
410 | cksum = checksum((u8*)&cfm->info, sizeof(struct cycx_fw_info) + | ||
411 | cfm->info.codesize); | ||
412 | /* | ||
413 | FIXME cfm->info.codesize is off by 2 | ||
414 | if (((len - sizeof(struct cycx_firmware) - 1) != cfm->info.codesize) || | ||
415 | */ | ||
416 | if (cksum != cfm->checksum) { | ||
417 | pr_err("%s: firmware corrupted!\n", __func__); | ||
418 | pr_err(" cdsize = 0x%x (expected 0x%lx)\n", | ||
419 | len - (int)sizeof(struct cycx_firmware) - 1, | ||
420 | cfm->info.codesize); | ||
421 | pr_err(" chksum = 0x%x (expected 0x%x)\n", | ||
422 | cksum, cfm->checksum); | ||
423 | return -EINVAL; | ||
424 | } | ||
425 | |||
426 | /* If everything is ok, set reset, data and code pointers */ | ||
427 | img_hdr = (struct cycx_fw_header *)&cfm->image; | ||
428 | #ifdef FIRMWARE_DEBUG | ||
429 | pr_info("%s: image sizes\n", __func__); | ||
430 | pr_info(" reset=%lu\n", img_hdr->reset_size); | ||
431 | pr_info(" data=%lu\n", img_hdr->data_size); | ||
432 | pr_info(" code=%lu\n", img_hdr->code_size); | ||
433 | #endif | ||
434 | reset_image = ((u8 *)img_hdr) + sizeof(struct cycx_fw_header); | ||
435 | data_image = reset_image + img_hdr->reset_size; | ||
436 | code_image = data_image + img_hdr->data_size; | ||
437 | |||
438 | /*---- Start load ----*/ | ||
439 | /* Announce */ | ||
440 | pr_info("loading firmware %s (ID=%u)...\n", | ||
441 | cfm->descr[0] ? cfm->descr : "unknown firmware", | ||
442 | cfm->info.codeid); | ||
443 | |||
444 | for (i = 0 ; i < 5 ; i++) { | ||
445 | /* Reset Cyclom hardware */ | ||
446 | if (!reset_cyc2x(hw->dpmbase)) { | ||
447 | pr_err("dpm problem or board not found\n"); | ||
448 | return -EINVAL; | ||
449 | } | ||
450 | |||
451 | /* Load reset.bin */ | ||
452 | cycx_reset_boot(hw->dpmbase, reset_image, img_hdr->reset_size); | ||
453 | /* reset is waiting for boot */ | ||
454 | writew(GEN_POWER_ON, pt_cycld); | ||
455 | msleep_interruptible(1 * 1000); | ||
456 | |||
457 | for (j = 0 ; j < 3 ; j++) | ||
458 | if (!readw(pt_cycld)) | ||
459 | goto reset_loaded; | ||
460 | else | ||
461 | msleep_interruptible(1 * 1000); | ||
462 | } | ||
463 | |||
464 | pr_err("reset not started\n"); | ||
465 | return -EINVAL; | ||
466 | |||
467 | reset_loaded: | ||
468 | /* Load data.bin */ | ||
469 | if (cycx_data_boot(hw->dpmbase, data_image, img_hdr->data_size)) { | ||
470 | pr_err("cannot load data file\n"); | ||
471 | return -EINVAL; | ||
472 | } | ||
473 | |||
474 | /* Load code.bin */ | ||
475 | if (cycx_code_boot(hw->dpmbase, code_image, img_hdr->code_size)) { | ||
476 | pr_err("cannot load code file\n"); | ||
477 | return -EINVAL; | ||
478 | } | ||
479 | |||
480 | /* Prepare boot-time configuration data */ | ||
481 | cycx_bootcfg(hw); | ||
482 | |||
483 | /* kick-off CPU */ | ||
484 | cycx_start(hw->dpmbase); | ||
485 | |||
486 | /* Arthur Ganzert's tip: wait a while after the firmware loading... | ||
487 | seg abr 26 17:17:12 EST 1999 - acme */ | ||
488 | msleep_interruptible(7 * 1000); | ||
489 | pr_info("firmware loaded!\n"); | ||
490 | |||
491 | /* enable interrupts */ | ||
492 | cycx_inten(hw); | ||
493 | |||
494 | return 0; | ||
495 | } | ||
496 | |||
497 | /* Prepare boot-time firmware configuration data. | ||
498 | * o initialize configuration data area | ||
499 | From async.doc - V_3.4.0 - 07/18/1994 | ||
500 | - As of now, only static buffers are available to the user. | ||
501 | So, the bit VD_RXDIRC must be set in 'valid'. That means that user | ||
502 | wants to use the static transmission and reception buffers. */ | ||
503 | static void cycx_bootcfg(struct cycx_hw *hw) | ||
504 | { | ||
505 | /* use fixed buffers */ | ||
506 | writeb(FIXED_BUFFERS, hw->dpmbase + CONF_OFFSET); | ||
507 | } | ||
508 | |||
509 | /* Detect Cyclom 2x adapter. | ||
510 | * Following tests are used to detect Cyclom 2x adapter: | ||
511 | * to be completed based on the tests done below | ||
512 | * Return 1 if detected o.k. or 0 if failed. | ||
513 | * Note: This test is destructive! Adapter will be left in shutdown | ||
514 | * state after the test. */ | ||
515 | static int detect_cyc2x(void __iomem *addr) | ||
516 | { | ||
517 | reset_cyc2x(addr); | ||
518 | |||
519 | return memory_exists(addr); | ||
520 | } | ||
521 | |||
522 | /* Miscellaneous */ | ||
523 | /* Get option's index into the options list. | ||
524 | * Return option's index (1 .. N) or zero if option is invalid. */ | ||
525 | static int get_option_index(const long *optlist, long optval) | ||
526 | { | ||
527 | int i = 1; | ||
528 | |||
529 | for (; i <= optlist[0]; ++i) | ||
530 | if (optlist[i] == optval) | ||
531 | return i; | ||
532 | |||
533 | return 0; | ||
534 | } | ||
535 | |||
536 | /* Reset adapter's CPU. */ | ||
537 | static int reset_cyc2x(void __iomem *addr) | ||
538 | { | ||
539 | writeb(0, addr + RST_ENABLE); | ||
540 | msleep_interruptible(2 * 1000); | ||
541 | writeb(0, addr + RST_DISABLE); | ||
542 | msleep_interruptible(2 * 1000); | ||
543 | |||
544 | return memory_exists(addr); | ||
545 | } | ||
546 | |||
547 | /* Calculate 16-bit CRC using CCITT polynomial. */ | ||
548 | static u16 checksum(u8 *buf, u32 len) | ||
549 | { | ||
550 | u16 crc = 0; | ||
551 | u16 mask, flag; | ||
552 | |||
553 | for (; len; --len, ++buf) | ||
554 | for (mask = 0x80; mask; mask >>= 1) { | ||
555 | flag = (crc & 0x8000); | ||
556 | crc <<= 1; | ||
557 | crc |= ((*buf & mask) ? 1 : 0); | ||
558 | |||
559 | if (flag) | ||
560 | crc ^= 0x1021; | ||
561 | } | ||
562 | |||
563 | return crc; | ||
564 | } | ||
565 | |||
566 | module_init(cycx_drv_init); | ||
567 | module_exit(cycx_drv_cleanup); | ||
568 | |||
569 | /* End */ | ||
diff --git a/drivers/net/wan/cycx_main.c b/drivers/net/wan/cycx_main.c deleted file mode 100644 index 81fbbad406be..000000000000 --- a/drivers/net/wan/cycx_main.c +++ /dev/null | |||
@@ -1,346 +0,0 @@ | |||
1 | /* | ||
2 | * cycx_main.c Cyclades Cyclom 2X WAN Link Driver. Main module. | ||
3 | * | ||
4 | * Author: Arnaldo Carvalho de Melo <acme@conectiva.com.br> | ||
5 | * | ||
6 | * Copyright: (c) 1998-2003 Arnaldo Carvalho de Melo | ||
7 | * | ||
8 | * Based on sdlamain.c by Gene Kozin <genek@compuserve.com> & | ||
9 | * Jaspreet Singh <jaspreet@sangoma.com> | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or | ||
12 | * modify it under the terms of the GNU General Public License | ||
13 | * as published by the Free Software Foundation; either version | ||
14 | * 2 of the License, or (at your option) any later version. | ||
15 | * ============================================================================ | ||
16 | * Please look at the bitkeeper changelog (or any other scm tool that ends up | ||
17 | * importing bitkeeper changelog or that replaces bitkeeper in the future as | ||
18 | * main tool for linux development). | ||
19 | * | ||
20 | * 2001/05/09 acme Fix MODULE_DESC for debug, .bss nitpicks, | ||
21 | * some cleanups | ||
22 | * 2000/07/13 acme remove useless #ifdef MODULE and crap | ||
23 | * #if KERNEL_VERSION > blah | ||
24 | * 2000/07/06 acme __exit at cyclomx_cleanup | ||
25 | * 2000/04/02 acme dprintk and cycx_debug | ||
26 | * module_init/module_exit | ||
27 | * 2000/01/21 acme rename cyclomx_open to cyclomx_mod_inc_use_count | ||
28 | * and cyclomx_close to cyclomx_mod_dec_use_count | ||
29 | * 2000/01/08 acme cleanup | ||
30 | * 1999/11/06 acme cycx_down back to life (it needs to be | ||
31 | * called to iounmap the dpmbase) | ||
32 | * 1999/08/09 acme removed references to enable_tx_int | ||
33 | * use spinlocks instead of cli/sti in | ||
34 | * cyclomx_set_state | ||
35 | * 1999/05/19 acme works directly linked into the kernel | ||
36 | * init_waitqueue_head for 2.3.* kernel | ||
37 | * 1999/05/18 acme major cleanup (polling not needed), etc | ||
38 | * 1998/08/28 acme minor cleanup (ioctls for firmware deleted) | ||
39 | * queue_task activated | ||
40 | * 1998/08/08 acme Initial version. | ||
41 | */ | ||
42 | |||
43 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
44 | |||
45 | #include <linux/stddef.h> /* offsetof(), etc. */ | ||
46 | #include <linux/errno.h> /* return codes */ | ||
47 | #include <linux/string.h> /* inline memset(), etc. */ | ||
48 | #include <linux/slab.h> /* kmalloc(), kfree() */ | ||
49 | #include <linux/kernel.h> /* printk(), and other useful stuff */ | ||
50 | #include <linux/module.h> /* support for loadable modules */ | ||
51 | #include <linux/ioport.h> /* request_region(), release_region() */ | ||
52 | #include <linux/wanrouter.h> /* WAN router definitions */ | ||
53 | #include <linux/cyclomx.h> /* cyclomx common user API definitions */ | ||
54 | #include <linux/init.h> /* __init (when not using as a module) */ | ||
55 | #include <linux/interrupt.h> | ||
56 | |||
57 | unsigned int cycx_debug; | ||
58 | |||
59 | MODULE_AUTHOR("Arnaldo Carvalho de Melo"); | ||
60 | MODULE_DESCRIPTION("Cyclom 2X Sync Card Driver."); | ||
61 | MODULE_LICENSE("GPL"); | ||
62 | module_param(cycx_debug, int, 0); | ||
63 | MODULE_PARM_DESC(cycx_debug, "cyclomx debug level"); | ||
64 | |||
65 | /* Defines & Macros */ | ||
66 | |||
67 | #define CYCX_DRV_VERSION 0 /* version number */ | ||
68 | #define CYCX_DRV_RELEASE 11 /* release (minor version) number */ | ||
69 | #define CYCX_MAX_CARDS 1 /* max number of adapters */ | ||
70 | |||
71 | #define CONFIG_CYCX_CARDS 1 | ||
72 | |||
73 | /* Function Prototypes */ | ||
74 | |||
75 | /* WAN link driver entry points */ | ||
76 | static int cycx_wan_setup(struct wan_device *wandev, wandev_conf_t *conf); | ||
77 | static int cycx_wan_shutdown(struct wan_device *wandev); | ||
78 | |||
79 | /* Miscellaneous functions */ | ||
80 | static irqreturn_t cycx_isr(int irq, void *dev_id); | ||
81 | |||
82 | /* Global Data | ||
83 | * Note: All data must be explicitly initialized!!! | ||
84 | */ | ||
85 | |||
86 | /* private data */ | ||
87 | static const char cycx_drvname[] = "cyclomx"; | ||
88 | static const char cycx_fullname[] = "CYCLOM 2X(tm) Sync Card Driver"; | ||
89 | static const char cycx_copyright[] = "(c) 1998-2003 Arnaldo Carvalho de Melo " | ||
90 | "<acme@conectiva.com.br>"; | ||
91 | static int cycx_ncards = CONFIG_CYCX_CARDS; | ||
92 | static struct cycx_device *cycx_card_array; /* adapter data space */ | ||
93 | |||
94 | /* Kernel Loadable Module Entry Points */ | ||
95 | |||
96 | /* | ||
97 | * Module 'insert' entry point. | ||
98 | * o print announcement | ||
99 | * o allocate adapter data space | ||
100 | * o initialize static data | ||
101 | * o register all cards with WAN router | ||
102 | * o calibrate Cyclom 2X shared memory access delay. | ||
103 | * | ||
104 | * Return: 0 Ok | ||
105 | * < 0 error. | ||
106 | * Context: process | ||
107 | */ | ||
108 | static int __init cycx_init(void) | ||
109 | { | ||
110 | int cnt, err = -ENOMEM; | ||
111 | |||
112 | pr_info("%s v%u.%u %s\n", | ||
113 | cycx_fullname, CYCX_DRV_VERSION, CYCX_DRV_RELEASE, | ||
114 | cycx_copyright); | ||
115 | |||
116 | /* Verify number of cards and allocate adapter data space */ | ||
117 | cycx_ncards = min_t(int, cycx_ncards, CYCX_MAX_CARDS); | ||
118 | cycx_ncards = max_t(int, cycx_ncards, 1); | ||
119 | cycx_card_array = kcalloc(cycx_ncards, sizeof(struct cycx_device), GFP_KERNEL); | ||
120 | if (!cycx_card_array) | ||
121 | goto out; | ||
122 | |||
123 | |||
124 | /* Register adapters with WAN router */ | ||
125 | for (cnt = 0; cnt < cycx_ncards; ++cnt) { | ||
126 | struct cycx_device *card = &cycx_card_array[cnt]; | ||
127 | struct wan_device *wandev = &card->wandev; | ||
128 | |||
129 | sprintf(card->devname, "%s%d", cycx_drvname, cnt + 1); | ||
130 | wandev->magic = ROUTER_MAGIC; | ||
131 | wandev->name = card->devname; | ||
132 | wandev->private = card; | ||
133 | wandev->setup = cycx_wan_setup; | ||
134 | wandev->shutdown = cycx_wan_shutdown; | ||
135 | err = register_wan_device(wandev); | ||
136 | |||
137 | if (err) { | ||
138 | pr_err("%s registration failed with error %d!\n", | ||
139 | card->devname, err); | ||
140 | break; | ||
141 | } | ||
142 | } | ||
143 | |||
144 | err = -ENODEV; | ||
145 | if (!cnt) { | ||
146 | kfree(cycx_card_array); | ||
147 | goto out; | ||
148 | } | ||
149 | err = 0; | ||
150 | cycx_ncards = cnt; /* adjust actual number of cards */ | ||
151 | out: return err; | ||
152 | } | ||
153 | |||
154 | /* | ||
155 | * Module 'remove' entry point. | ||
156 | * o unregister all adapters from the WAN router | ||
157 | * o release all remaining system resources | ||
158 | */ | ||
159 | static void __exit cycx_exit(void) | ||
160 | { | ||
161 | int i = 0; | ||
162 | |||
163 | for (; i < cycx_ncards; ++i) { | ||
164 | struct cycx_device *card = &cycx_card_array[i]; | ||
165 | unregister_wan_device(card->devname); | ||
166 | } | ||
167 | |||
168 | kfree(cycx_card_array); | ||
169 | } | ||
170 | |||
171 | /* WAN Device Driver Entry Points */ | ||
172 | /* | ||
173 | * Setup/configure WAN link driver. | ||
174 | * o check adapter state | ||
175 | * o make sure firmware is present in configuration | ||
176 | * o allocate interrupt vector | ||
177 | * o setup Cyclom 2X hardware | ||
178 | * o call appropriate routine to perform protocol-specific initialization | ||
179 | * | ||
180 | * This function is called when router handles ROUTER_SETUP IOCTL. The | ||
181 | * configuration structure is in kernel memory (including extended data, if | ||
182 | * any). | ||
183 | */ | ||
184 | static int cycx_wan_setup(struct wan_device *wandev, wandev_conf_t *conf) | ||
185 | { | ||
186 | int rc = -EFAULT; | ||
187 | struct cycx_device *card; | ||
188 | int irq; | ||
189 | |||
190 | /* Sanity checks */ | ||
191 | |||
192 | if (!wandev || !wandev->private || !conf) | ||
193 | goto out; | ||
194 | |||
195 | card = wandev->private; | ||
196 | rc = -EBUSY; | ||
197 | if (wandev->state != WAN_UNCONFIGURED) | ||
198 | goto out; | ||
199 | |||
200 | rc = -EINVAL; | ||
201 | if (!conf->data_size || !conf->data) { | ||
202 | pr_err("%s: firmware not found in configuration data!\n", | ||
203 | wandev->name); | ||
204 | goto out; | ||
205 | } | ||
206 | |||
207 | if (conf->irq <= 0) { | ||
208 | pr_err("%s: can't configure without IRQ!\n", wandev->name); | ||
209 | goto out; | ||
210 | } | ||
211 | |||
212 | /* Allocate IRQ */ | ||
213 | irq = conf->irq == 2 ? 9 : conf->irq; /* IRQ2 -> IRQ9 */ | ||
214 | |||
215 | if (request_irq(irq, cycx_isr, 0, wandev->name, card)) { | ||
216 | pr_err("%s: can't reserve IRQ %d!\n", wandev->name, irq); | ||
217 | goto out; | ||
218 | } | ||
219 | |||
220 | /* Configure hardware, load firmware, etc. */ | ||
221 | memset(&card->hw, 0, sizeof(card->hw)); | ||
222 | card->hw.irq = irq; | ||
223 | card->hw.dpmsize = CYCX_WINDOWSIZE; | ||
224 | card->hw.fwid = CFID_X25_2X; | ||
225 | spin_lock_init(&card->lock); | ||
226 | init_waitqueue_head(&card->wait_stats); | ||
227 | |||
228 | rc = cycx_setup(&card->hw, conf->data, conf->data_size, conf->maddr); | ||
229 | if (rc) | ||
230 | goto out_irq; | ||
231 | |||
232 | /* Initialize WAN device data space */ | ||
233 | wandev->irq = irq; | ||
234 | wandev->dma = wandev->ioport = 0; | ||
235 | wandev->maddr = (unsigned long)card->hw.dpmbase; | ||
236 | wandev->msize = card->hw.dpmsize; | ||
237 | wandev->hw_opt[2] = 0; | ||
238 | wandev->hw_opt[3] = card->hw.fwid; | ||
239 | |||
240 | /* Protocol-specific initialization */ | ||
241 | switch (card->hw.fwid) { | ||
242 | #ifdef CONFIG_CYCLOMX_X25 | ||
243 | case CFID_X25_2X: | ||
244 | rc = cycx_x25_wan_init(card, conf); | ||
245 | break; | ||
246 | #endif | ||
247 | default: | ||
248 | pr_err("%s: this firmware is not supported!\n", wandev->name); | ||
249 | rc = -EINVAL; | ||
250 | } | ||
251 | |||
252 | if (rc) { | ||
253 | cycx_down(&card->hw); | ||
254 | goto out_irq; | ||
255 | } | ||
256 | |||
257 | rc = 0; | ||
258 | out: | ||
259 | return rc; | ||
260 | out_irq: | ||
261 | free_irq(irq, card); | ||
262 | goto out; | ||
263 | } | ||
264 | |||
265 | /* | ||
266 | * Shut down WAN link driver. | ||
267 | * o shut down adapter hardware | ||
268 | * o release system resources. | ||
269 | * | ||
270 | * This function is called by the router when device is being unregistered or | ||
271 | * when it handles ROUTER_DOWN IOCTL. | ||
272 | */ | ||
273 | static int cycx_wan_shutdown(struct wan_device *wandev) | ||
274 | { | ||
275 | int ret = -EFAULT; | ||
276 | struct cycx_device *card; | ||
277 | |||
278 | /* sanity checks */ | ||
279 | if (!wandev || !wandev->private) | ||
280 | goto out; | ||
281 | |||
282 | ret = 0; | ||
283 | if (wandev->state == WAN_UNCONFIGURED) | ||
284 | goto out; | ||
285 | |||
286 | card = wandev->private; | ||
287 | wandev->state = WAN_UNCONFIGURED; | ||
288 | cycx_down(&card->hw); | ||
289 | pr_info("%s: irq %d being freed!\n", wandev->name, wandev->irq); | ||
290 | free_irq(wandev->irq, card); | ||
291 | out: return ret; | ||
292 | } | ||
293 | |||
294 | /* Miscellaneous */ | ||
295 | /* | ||
296 | * Cyclom 2X Interrupt Service Routine. | ||
297 | * o acknowledge Cyclom 2X hardware interrupt. | ||
298 | * o call protocol-specific interrupt service routine, if any. | ||
299 | */ | ||
300 | static irqreturn_t cycx_isr(int irq, void *dev_id) | ||
301 | { | ||
302 | struct cycx_device *card = dev_id; | ||
303 | |||
304 | if (card->wandev.state == WAN_UNCONFIGURED) | ||
305 | goto out; | ||
306 | |||
307 | if (card->in_isr) { | ||
308 | pr_warn("%s: interrupt re-entrancy on IRQ %d!\n", | ||
309 | card->devname, card->wandev.irq); | ||
310 | goto out; | ||
311 | } | ||
312 | |||
313 | if (card->isr) | ||
314 | card->isr(card); | ||
315 | return IRQ_HANDLED; | ||
316 | out: | ||
317 | return IRQ_NONE; | ||
318 | } | ||
319 | |||
320 | /* Set WAN device state. */ | ||
321 | void cycx_set_state(struct cycx_device *card, int state) | ||
322 | { | ||
323 | unsigned long flags; | ||
324 | char *string_state = NULL; | ||
325 | |||
326 | spin_lock_irqsave(&card->lock, flags); | ||
327 | |||
328 | if (card->wandev.state != state) { | ||
329 | switch (state) { | ||
330 | case WAN_CONNECTED: | ||
331 | string_state = "connected!"; | ||
332 | break; | ||
333 | case WAN_DISCONNECTED: | ||
334 | string_state = "disconnected!"; | ||
335 | break; | ||
336 | } | ||
337 | pr_info("%s: link %s\n", card->devname, string_state); | ||
338 | card->wandev.state = state; | ||
339 | } | ||
340 | |||
341 | card->state_tick = jiffies; | ||
342 | spin_unlock_irqrestore(&card->lock, flags); | ||
343 | } | ||
344 | |||
345 | module_init(cycx_init); | ||
346 | module_exit(cycx_exit); | ||
diff --git a/drivers/net/wan/cycx_x25.c b/drivers/net/wan/cycx_x25.c deleted file mode 100644 index 06f3f6309e4b..000000000000 --- a/drivers/net/wan/cycx_x25.c +++ /dev/null | |||
@@ -1,1602 +0,0 @@ | |||
1 | /* | ||
2 | * cycx_x25.c Cyclom 2X WAN Link Driver. X.25 module. | ||
3 | * | ||
4 | * Author: Arnaldo Carvalho de Melo <acme@conectiva.com.br> | ||
5 | * | ||
6 | * Copyright: (c) 1998-2003 Arnaldo Carvalho de Melo | ||
7 | * | ||
8 | * Based on sdla_x25.c by Gene Kozin <genek@compuserve.com> | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or | ||
11 | * modify it under the terms of the GNU General Public License | ||
12 | * as published by the Free Software Foundation; either version | ||
13 | * 2 of the License, or (at your option) any later version. | ||
14 | * ============================================================================ | ||
15 | * 2001/01/12 acme use dev_kfree_skb_irq on interrupt context | ||
16 | * 2000/04/02 acme dprintk, cycx_debug | ||
17 | * fixed the bug introduced in get_dev_by_lcn and | ||
18 | * get_dev_by_dte_addr by the anonymous hacker | ||
19 | * that converted this driver to softnet | ||
20 | * 2000/01/08 acme cleanup | ||
21 | * 1999/10/27 acme use ARPHRD_HWX25 so that the X.25 stack know | ||
22 | * that we have a X.25 stack implemented in | ||
23 | * firmware onboard | ||
24 | * 1999/10/18 acme support for X.25 sockets in if_send, | ||
25 | * beware: socket(AF_X25...) IS WORK IN PROGRESS, | ||
26 | * TCP/IP over X.25 via wanrouter not affected, | ||
27 | * working. | ||
28 | * 1999/10/09 acme chan_disc renamed to chan_disconnect, | ||
29 | * began adding support for X.25 sockets: | ||
30 | * conf->protocol in new_if | ||
31 | * 1999/10/05 acme fixed return E... to return -E... | ||
32 | * 1999/08/10 acme serialized access to the card thru a spinlock | ||
33 | * in x25_exec | ||
34 | * 1999/08/09 acme removed per channel spinlocks | ||
35 | * removed references to enable_tx_int | ||
36 | * 1999/05/28 acme fixed nibble_to_byte, ackvc now properly treated | ||
37 | * if_send simplified | ||
38 | * 1999/05/25 acme fixed t1, t2, t21 & t23 configuration | ||
39 | * use spinlocks instead of cli/sti in some points | ||
40 | * 1999/05/24 acme finished the x25_get_stat function | ||
41 | * 1999/05/23 acme dev->type = ARPHRD_X25 (tcpdump only works, | ||
42 | * AFAIT, with ARPHRD_ETHER). This seems to be | ||
43 | * needed to use socket(AF_X25)... | ||
44 | * Now the config file must specify a peer media | ||
45 | * address for svc channels over a crossover cable. | ||
46 | * Removed hold_timeout from x25_channel_t, | ||
47 | * not used. | ||
48 | * A little enhancement in the DEBUG processing | ||
49 | * 1999/05/22 acme go to DISCONNECTED in disconnect_confirm_intr, | ||
50 | * instead of chan_disc. | ||
51 | * 1999/05/16 marcelo fixed timer initialization in SVCs | ||
52 | * 1999/01/05 acme x25_configure now get (most of) all | ||
53 | * parameters... | ||
54 | * 1999/01/05 acme pktlen now (correctly) uses log2 (value | ||
55 | * configured) | ||
56 | * 1999/01/03 acme judicious use of data types (u8, u16, u32, etc) | ||
57 | * 1999/01/03 acme cyx_isr: reset dpmbase to acknowledge | ||
58 | * indication (interrupt from cyclom 2x) | ||
59 | * 1999/01/02 acme cyx_isr: first hackings... | ||
60 | * 1999/01/0203 acme when initializing an array don't give less | ||
61 | * elements than declared... | ||
62 | * example: char send_cmd[6] = "?\xFF\x10"; | ||
63 | * you'll gonna lose a couple hours, 'cause your | ||
64 | * brain won't admit that there's an error in the | ||
65 | * above declaration... the side effect is that | ||
66 | * memset is put into the unresolved symbols | ||
67 | * instead of using the inline memset functions... | ||
68 | * 1999/01/02 acme began chan_connect, chan_send, x25_send | ||
69 | * 1998/12/31 acme x25_configure | ||
70 | * this code can be compiled as non module | ||
71 | * 1998/12/27 acme code cleanup | ||
72 | * IPX code wiped out! let's decrease code | ||
73 | * complexity for now, remember: I'm learning! :) | ||
74 | * bps_to_speed_code OK | ||
75 | * 1998/12/26 acme Minimal debug code cleanup | ||
76 | * 1998/08/08 acme Initial version. | ||
77 | */ | ||
78 | |||
79 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
80 | |||
81 | #define CYCLOMX_X25_DEBUG 1 | ||
82 | |||
83 | #include <linux/ctype.h> /* isdigit() */ | ||
84 | #include <linux/errno.h> /* return codes */ | ||
85 | #include <linux/if_arp.h> /* ARPHRD_HWX25 */ | ||
86 | #include <linux/kernel.h> /* printk(), and other useful stuff */ | ||
87 | #include <linux/module.h> | ||
88 | #include <linux/string.h> /* inline memset(), etc. */ | ||
89 | #include <linux/sched.h> | ||
90 | #include <linux/slab.h> /* kmalloc(), kfree() */ | ||
91 | #include <linux/stddef.h> /* offsetof(), etc. */ | ||
92 | #include <linux/wanrouter.h> /* WAN router definitions */ | ||
93 | |||
94 | #include <asm/byteorder.h> /* htons(), etc. */ | ||
95 | |||
96 | #include <linux/cyclomx.h> /* Cyclom 2X common user API definitions */ | ||
97 | #include <linux/cycx_x25.h> /* X.25 firmware API definitions */ | ||
98 | |||
99 | #include <net/x25device.h> | ||
100 | |||
101 | /* Defines & Macros */ | ||
102 | #define CYCX_X25_MAX_CMD_RETRY 5 | ||
103 | #define CYCX_X25_CHAN_MTU 2048 /* unfragmented logical channel MTU */ | ||
104 | |||
105 | /* Data Structures */ | ||
106 | /* This is an extension of the 'struct net_device' we create for each network | ||
107 | interface to keep the rest of X.25 channel-specific data. */ | ||
108 | struct cycx_x25_channel { | ||
109 | /* This member must be first. */ | ||
110 | struct net_device *slave; /* WAN slave */ | ||
111 | |||
112 | char name[WAN_IFNAME_SZ+1]; /* interface name, ASCIIZ */ | ||
113 | char addr[WAN_ADDRESS_SZ+1]; /* media address, ASCIIZ */ | ||
114 | char *local_addr; /* local media address, ASCIIZ - | ||
115 | svc thru crossover cable */ | ||
116 | s16 lcn; /* logical channel number/conn.req.key*/ | ||
117 | u8 link; | ||
118 | struct timer_list timer; /* timer used for svc channel disc. */ | ||
119 | u16 protocol; /* ethertype, 0 - multiplexed */ | ||
120 | u8 svc; /* 0 - permanent, 1 - switched */ | ||
121 | u8 state; /* channel state */ | ||
122 | u8 drop_sequence; /* mark sequence for dropping */ | ||
123 | u32 idle_tmout; /* sec, before disconnecting */ | ||
124 | struct sk_buff *rx_skb; /* receive socket buffer */ | ||
125 | struct cycx_device *card; /* -> owner */ | ||
126 | struct net_device_stats ifstats;/* interface statistics */ | ||
127 | }; | ||
128 | |||
129 | /* Function Prototypes */ | ||
130 | /* WAN link driver entry points. These are called by the WAN router module. */ | ||
131 | static int cycx_wan_update(struct wan_device *wandev), | ||
132 | cycx_wan_new_if(struct wan_device *wandev, struct net_device *dev, | ||
133 | wanif_conf_t *conf), | ||
134 | cycx_wan_del_if(struct wan_device *wandev, struct net_device *dev); | ||
135 | |||
136 | /* Network device interface */ | ||
137 | static int cycx_netdevice_init(struct net_device *dev); | ||
138 | static int cycx_netdevice_open(struct net_device *dev); | ||
139 | static int cycx_netdevice_stop(struct net_device *dev); | ||
140 | static int cycx_netdevice_hard_header(struct sk_buff *skb, | ||
141 | struct net_device *dev, u16 type, | ||
142 | const void *daddr, const void *saddr, | ||
143 | unsigned len); | ||
144 | static int cycx_netdevice_rebuild_header(struct sk_buff *skb); | ||
145 | static netdev_tx_t cycx_netdevice_hard_start_xmit(struct sk_buff *skb, | ||
146 | struct net_device *dev); | ||
147 | |||
148 | static struct net_device_stats * | ||
149 | cycx_netdevice_get_stats(struct net_device *dev); | ||
150 | |||
151 | /* Interrupt handlers */ | ||
152 | static void cycx_x25_irq_handler(struct cycx_device *card), | ||
153 | cycx_x25_irq_tx(struct cycx_device *card, struct cycx_x25_cmd *cmd), | ||
154 | cycx_x25_irq_rx(struct cycx_device *card, struct cycx_x25_cmd *cmd), | ||
155 | cycx_x25_irq_log(struct cycx_device *card, | ||
156 | struct cycx_x25_cmd *cmd), | ||
157 | cycx_x25_irq_stat(struct cycx_device *card, | ||
158 | struct cycx_x25_cmd *cmd), | ||
159 | cycx_x25_irq_connect_confirm(struct cycx_device *card, | ||
160 | struct cycx_x25_cmd *cmd), | ||
161 | cycx_x25_irq_disconnect_confirm(struct cycx_device *card, | ||
162 | struct cycx_x25_cmd *cmd), | ||
163 | cycx_x25_irq_connect(struct cycx_device *card, | ||
164 | struct cycx_x25_cmd *cmd), | ||
165 | cycx_x25_irq_disconnect(struct cycx_device *card, | ||
166 | struct cycx_x25_cmd *cmd), | ||
167 | cycx_x25_irq_spurious(struct cycx_device *card, | ||
168 | struct cycx_x25_cmd *cmd); | ||
169 | |||
170 | /* X.25 firmware interface functions */ | ||
171 | static int cycx_x25_configure(struct cycx_device *card, | ||
172 | struct cycx_x25_config *conf), | ||
173 | cycx_x25_get_stats(struct cycx_device *card), | ||
174 | cycx_x25_send(struct cycx_device *card, u8 link, u8 lcn, u8 bitm, | ||
175 | int len, void *buf), | ||
176 | cycx_x25_connect_response(struct cycx_device *card, | ||
177 | struct cycx_x25_channel *chan), | ||
178 | cycx_x25_disconnect_response(struct cycx_device *card, u8 link, | ||
179 | u8 lcn); | ||
180 | |||
181 | /* channel functions */ | ||
182 | static int cycx_x25_chan_connect(struct net_device *dev), | ||
183 | cycx_x25_chan_send(struct net_device *dev, struct sk_buff *skb); | ||
184 | |||
185 | static void cycx_x25_chan_disconnect(struct net_device *dev), | ||
186 | cycx_x25_chan_send_event(struct net_device *dev, u8 event); | ||
187 | |||
188 | /* Miscellaneous functions */ | ||
189 | static void cycx_x25_set_chan_state(struct net_device *dev, u8 state), | ||
190 | cycx_x25_chan_timer(unsigned long d); | ||
191 | |||
192 | static void nibble_to_byte(u8 *s, u8 *d, u8 len, u8 nibble), | ||
193 | reset_timer(struct net_device *dev); | ||
194 | |||
195 | static u8 bps_to_speed_code(u32 bps); | ||
196 | static u8 cycx_log2(u32 n); | ||
197 | |||
198 | static unsigned dec_to_uint(u8 *str, int len); | ||
199 | |||
200 | static struct net_device *cycx_x25_get_dev_by_lcn(struct wan_device *wandev, | ||
201 | s16 lcn); | ||
202 | static struct net_device * | ||
203 | cycx_x25_get_dev_by_dte_addr(struct wan_device *wandev, char *dte); | ||
204 | |||
205 | static void cycx_x25_chan_setup(struct net_device *dev); | ||
206 | |||
207 | #ifdef CYCLOMX_X25_DEBUG | ||
208 | static void hex_dump(char *msg, unsigned char *p, int len); | ||
209 | static void cycx_x25_dump_config(struct cycx_x25_config *conf); | ||
210 | static void cycx_x25_dump_stats(struct cycx_x25_stats *stats); | ||
211 | static void cycx_x25_dump_devs(struct wan_device *wandev); | ||
212 | #else | ||
213 | #define hex_dump(msg, p, len) | ||
214 | #define cycx_x25_dump_config(conf) | ||
215 | #define cycx_x25_dump_stats(stats) | ||
216 | #define cycx_x25_dump_devs(wandev) | ||
217 | #endif | ||
218 | /* Public Functions */ | ||
219 | |||
220 | /* X.25 Protocol Initialization routine. | ||
221 | * | ||
222 | * This routine is called by the main Cyclom 2X module during setup. At this | ||
223 | * point adapter is completely initialized and X.25 firmware is running. | ||
224 | * o configure adapter | ||
225 | * o initialize protocol-specific fields of the adapter data space. | ||
226 | * | ||
227 | * Return: 0 o.k. | ||
228 | * < 0 failure. */ | ||
229 | int cycx_x25_wan_init(struct cycx_device *card, wandev_conf_t *conf) | ||
230 | { | ||
231 | struct cycx_x25_config cfg; | ||
232 | |||
233 | /* Verify configuration ID */ | ||
234 | if (conf->config_id != WANCONFIG_X25) { | ||
235 | pr_info("%s: invalid configuration ID %u!\n", | ||
236 | card->devname, conf->config_id); | ||
237 | return -EINVAL; | ||
238 | } | ||
239 | |||
240 | /* Initialize protocol-specific fields */ | ||
241 | card->mbox = card->hw.dpmbase + X25_MBOX_OFFS; | ||
242 | card->u.x.connection_keys = 0; | ||
243 | spin_lock_init(&card->u.x.lock); | ||
244 | |||
245 | /* Configure adapter. Here we set reasonable defaults, then parse | ||
246 | * device configuration structure and set configuration options. | ||
247 | * Most configuration options are verified and corrected (if | ||
248 | * necessary) since we can't rely on the adapter to do so and don't | ||
249 | * want it to fail either. */ | ||
250 | memset(&cfg, 0, sizeof(cfg)); | ||
251 | cfg.link = 0; | ||
252 | cfg.clock = conf->clocking == WANOPT_EXTERNAL ? 8 : 55; | ||
253 | cfg.speed = bps_to_speed_code(conf->bps); | ||
254 | cfg.n3win = 7; | ||
255 | cfg.n2win = 2; | ||
256 | cfg.n2 = 5; | ||
257 | cfg.nvc = 1; | ||
258 | cfg.npvc = 1; | ||
259 | cfg.flags = 0x02; /* default = V35 */ | ||
260 | cfg.t1 = 10; /* line carrier timeout */ | ||
261 | cfg.t2 = 29; /* tx timeout */ | ||
262 | cfg.t21 = 180; /* CALL timeout */ | ||
263 | cfg.t23 = 180; /* CLEAR timeout */ | ||
264 | |||
265 | /* adjust MTU */ | ||
266 | if (!conf->mtu || conf->mtu >= 512) | ||
267 | card->wandev.mtu = 512; | ||
268 | else if (conf->mtu >= 256) | ||
269 | card->wandev.mtu = 256; | ||
270 | else if (conf->mtu >= 128) | ||
271 | card->wandev.mtu = 128; | ||
272 | else | ||
273 | card->wandev.mtu = 64; | ||
274 | |||
275 | cfg.pktlen = cycx_log2(card->wandev.mtu); | ||
276 | |||
277 | if (conf->station == WANOPT_DTE) { | ||
278 | cfg.locaddr = 3; /* DTE */ | ||
279 | cfg.remaddr = 1; /* DCE */ | ||
280 | } else { | ||
281 | cfg.locaddr = 1; /* DCE */ | ||
282 | cfg.remaddr = 3; /* DTE */ | ||
283 | } | ||
284 | |||
285 | if (conf->interface == WANOPT_RS232) | ||
286 | cfg.flags = 0; /* FIXME just reset the 2nd bit */ | ||
287 | |||
288 | if (conf->u.x25.hi_pvc) { | ||
289 | card->u.x.hi_pvc = min_t(unsigned int, conf->u.x25.hi_pvc, 4095); | ||
290 | card->u.x.lo_pvc = min_t(unsigned int, conf->u.x25.lo_pvc, card->u.x.hi_pvc); | ||
291 | } | ||
292 | |||
293 | if (conf->u.x25.hi_svc) { | ||
294 | card->u.x.hi_svc = min_t(unsigned int, conf->u.x25.hi_svc, 4095); | ||
295 | card->u.x.lo_svc = min_t(unsigned int, conf->u.x25.lo_svc, card->u.x.hi_svc); | ||
296 | } | ||
297 | |||
298 | if (card->u.x.lo_pvc == 255) | ||
299 | cfg.npvc = 0; | ||
300 | else | ||
301 | cfg.npvc = card->u.x.hi_pvc - card->u.x.lo_pvc + 1; | ||
302 | |||
303 | cfg.nvc = card->u.x.hi_svc - card->u.x.lo_svc + 1 + cfg.npvc; | ||
304 | |||
305 | if (conf->u.x25.hdlc_window) | ||
306 | cfg.n2win = min_t(unsigned int, conf->u.x25.hdlc_window, 7); | ||
307 | |||
308 | if (conf->u.x25.pkt_window) | ||
309 | cfg.n3win = min_t(unsigned int, conf->u.x25.pkt_window, 7); | ||
310 | |||
311 | if (conf->u.x25.t1) | ||
312 | cfg.t1 = min_t(unsigned int, conf->u.x25.t1, 30); | ||
313 | |||
314 | if (conf->u.x25.t2) | ||
315 | cfg.t2 = min_t(unsigned int, conf->u.x25.t2, 30); | ||
316 | |||
317 | if (conf->u.x25.t11_t21) | ||
318 | cfg.t21 = min_t(unsigned int, conf->u.x25.t11_t21, 30); | ||
319 | |||
320 | if (conf->u.x25.t13_t23) | ||
321 | cfg.t23 = min_t(unsigned int, conf->u.x25.t13_t23, 30); | ||
322 | |||
323 | if (conf->u.x25.n2) | ||
324 | cfg.n2 = min_t(unsigned int, conf->u.x25.n2, 30); | ||
325 | |||
326 | /* initialize adapter */ | ||
327 | if (cycx_x25_configure(card, &cfg)) | ||
328 | return -EIO; | ||
329 | |||
330 | /* Initialize protocol-specific fields of adapter data space */ | ||
331 | card->wandev.bps = conf->bps; | ||
332 | card->wandev.interface = conf->interface; | ||
333 | card->wandev.clocking = conf->clocking; | ||
334 | card->wandev.station = conf->station; | ||
335 | card->isr = cycx_x25_irq_handler; | ||
336 | card->exec = NULL; | ||
337 | card->wandev.update = cycx_wan_update; | ||
338 | card->wandev.new_if = cycx_wan_new_if; | ||
339 | card->wandev.del_if = cycx_wan_del_if; | ||
340 | card->wandev.state = WAN_DISCONNECTED; | ||
341 | |||
342 | return 0; | ||
343 | } | ||
344 | |||
345 | /* WAN Device Driver Entry Points */ | ||
346 | /* Update device status & statistics. */ | ||
347 | static int cycx_wan_update(struct wan_device *wandev) | ||
348 | { | ||
349 | /* sanity checks */ | ||
350 | if (!wandev || !wandev->private) | ||
351 | return -EFAULT; | ||
352 | |||
353 | if (wandev->state == WAN_UNCONFIGURED) | ||
354 | return -ENODEV; | ||
355 | |||
356 | cycx_x25_get_stats(wandev->private); | ||
357 | |||
358 | return 0; | ||
359 | } | ||
360 | |||
361 | /* Create new logical channel. | ||
362 | * This routine is called by the router when ROUTER_IFNEW IOCTL is being | ||
363 | * handled. | ||
364 | * o parse media- and hardware-specific configuration | ||
365 | * o make sure that a new channel can be created | ||
366 | * o allocate resources, if necessary | ||
367 | * o prepare network device structure for registration. | ||
368 | * | ||
369 | * Return: 0 o.k. | ||
370 | * < 0 failure (channel will not be created) */ | ||
371 | static int cycx_wan_new_if(struct wan_device *wandev, struct net_device *dev, | ||
372 | wanif_conf_t *conf) | ||
373 | { | ||
374 | struct cycx_device *card = wandev->private; | ||
375 | struct cycx_x25_channel *chan; | ||
376 | int err = 0; | ||
377 | |||
378 | if (!conf->name[0] || strlen(conf->name) > WAN_IFNAME_SZ) { | ||
379 | pr_info("%s: invalid interface name!\n", card->devname); | ||
380 | return -EINVAL; | ||
381 | } | ||
382 | |||
383 | dev = alloc_netdev(sizeof(struct cycx_x25_channel), conf->name, | ||
384 | cycx_x25_chan_setup); | ||
385 | if (!dev) | ||
386 | return -ENOMEM; | ||
387 | |||
388 | chan = netdev_priv(dev); | ||
389 | strcpy(chan->name, conf->name); | ||
390 | chan->card = card; | ||
391 | chan->link = conf->port; | ||
392 | chan->protocol = conf->protocol ? ETH_P_X25 : ETH_P_IP; | ||
393 | chan->rx_skb = NULL; | ||
394 | /* only used in svc connected thru crossover cable */ | ||
395 | chan->local_addr = NULL; | ||
396 | |||
397 | if (conf->addr[0] == '@') { /* SVC */ | ||
398 | int len = strlen(conf->local_addr); | ||
399 | |||
400 | if (len) { | ||
401 | if (len > WAN_ADDRESS_SZ) { | ||
402 | pr_err("%s: %s local addr too long!\n", | ||
403 | wandev->name, chan->name); | ||
404 | err = -EINVAL; | ||
405 | goto error; | ||
406 | } else { | ||
407 | chan->local_addr = kmalloc(len + 1, GFP_KERNEL); | ||
408 | |||
409 | if (!chan->local_addr) { | ||
410 | err = -ENOMEM; | ||
411 | goto error; | ||
412 | } | ||
413 | } | ||
414 | |||
415 | strncpy(chan->local_addr, conf->local_addr, | ||
416 | WAN_ADDRESS_SZ); | ||
417 | } | ||
418 | |||
419 | chan->svc = 1; | ||
420 | strncpy(chan->addr, &conf->addr[1], WAN_ADDRESS_SZ); | ||
421 | init_timer(&chan->timer); | ||
422 | chan->timer.function = cycx_x25_chan_timer; | ||
423 | chan->timer.data = (unsigned long)dev; | ||
424 | |||
425 | /* Set channel timeouts (default if not specified) */ | ||
426 | chan->idle_tmout = conf->idle_timeout ? conf->idle_timeout : 90; | ||
427 | } else if (isdigit(conf->addr[0])) { /* PVC */ | ||
428 | s16 lcn = dec_to_uint(conf->addr, 0); | ||
429 | |||
430 | if (lcn >= card->u.x.lo_pvc && lcn <= card->u.x.hi_pvc) | ||
431 | chan->lcn = lcn; | ||
432 | else { | ||
433 | pr_err("%s: PVC %u is out of range on interface %s!\n", | ||
434 | wandev->name, lcn, chan->name); | ||
435 | err = -EINVAL; | ||
436 | goto error; | ||
437 | } | ||
438 | } else { | ||
439 | pr_err("%s: invalid media address on interface %s!\n", | ||
440 | wandev->name, chan->name); | ||
441 | err = -EINVAL; | ||
442 | goto error; | ||
443 | } | ||
444 | |||
445 | return 0; | ||
446 | |||
447 | error: | ||
448 | free_netdev(dev); | ||
449 | return err; | ||
450 | } | ||
451 | |||
452 | /* Delete logical channel. */ | ||
453 | static int cycx_wan_del_if(struct wan_device *wandev, struct net_device *dev) | ||
454 | { | ||
455 | struct cycx_x25_channel *chan = netdev_priv(dev); | ||
456 | |||
457 | if (chan->svc) { | ||
458 | kfree(chan->local_addr); | ||
459 | if (chan->state == WAN_CONNECTED) | ||
460 | del_timer(&chan->timer); | ||
461 | } | ||
462 | |||
463 | return 0; | ||
464 | } | ||
465 | |||
466 | |||
467 | /* Network Device Interface */ | ||
468 | |||
469 | static const struct header_ops cycx_header_ops = { | ||
470 | .create = cycx_netdevice_hard_header, | ||
471 | .rebuild = cycx_netdevice_rebuild_header, | ||
472 | }; | ||
473 | |||
474 | static const struct net_device_ops cycx_netdev_ops = { | ||
475 | .ndo_init = cycx_netdevice_init, | ||
476 | .ndo_open = cycx_netdevice_open, | ||
477 | .ndo_stop = cycx_netdevice_stop, | ||
478 | .ndo_start_xmit = cycx_netdevice_hard_start_xmit, | ||
479 | .ndo_get_stats = cycx_netdevice_get_stats, | ||
480 | }; | ||
481 | |||
482 | static void cycx_x25_chan_setup(struct net_device *dev) | ||
483 | { | ||
484 | /* Initialize device driver entry points */ | ||
485 | dev->netdev_ops = &cycx_netdev_ops; | ||
486 | dev->header_ops = &cycx_header_ops; | ||
487 | |||
488 | /* Initialize media-specific parameters */ | ||
489 | dev->mtu = CYCX_X25_CHAN_MTU; | ||
490 | dev->type = ARPHRD_HWX25; /* ARP h/w type */ | ||
491 | dev->hard_header_len = 0; /* media header length */ | ||
492 | dev->addr_len = 0; /* hardware address length */ | ||
493 | } | ||
494 | |||
495 | /* Initialize Linux network interface. | ||
496 | * | ||
497 | * This routine is called only once for each interface, during Linux network | ||
498 | * interface registration. Returning anything but zero will fail interface | ||
499 | * registration. */ | ||
500 | static int cycx_netdevice_init(struct net_device *dev) | ||
501 | { | ||
502 | struct cycx_x25_channel *chan = netdev_priv(dev); | ||
503 | struct cycx_device *card = chan->card; | ||
504 | struct wan_device *wandev = &card->wandev; | ||
505 | |||
506 | if (!chan->svc) | ||
507 | *(__be16*)dev->dev_addr = htons(chan->lcn); | ||
508 | |||
509 | /* Initialize hardware parameters (just for reference) */ | ||
510 | dev->irq = wandev->irq; | ||
511 | dev->dma = wandev->dma; | ||
512 | dev->base_addr = wandev->ioport; | ||
513 | dev->mem_start = (unsigned long)wandev->maddr; | ||
514 | dev->mem_end = (unsigned long)(wandev->maddr + | ||
515 | wandev->msize - 1); | ||
516 | dev->flags |= IFF_NOARP; | ||
517 | |||
518 | /* Set transmit buffer queue length */ | ||
519 | dev->tx_queue_len = 10; | ||
520 | |||
521 | /* Initialize socket buffers */ | ||
522 | cycx_x25_set_chan_state(dev, WAN_DISCONNECTED); | ||
523 | |||
524 | return 0; | ||
525 | } | ||
526 | |||
527 | /* Open network interface. | ||
528 | * o prevent module from unloading by incrementing use count | ||
529 | * o if link is disconnected then initiate connection | ||
530 | * | ||
531 | * Return 0 if O.k. or errno. */ | ||
532 | static int cycx_netdevice_open(struct net_device *dev) | ||
533 | { | ||
534 | if (netif_running(dev)) | ||
535 | return -EBUSY; /* only one open is allowed */ | ||
536 | |||
537 | netif_start_queue(dev); | ||
538 | return 0; | ||
539 | } | ||
540 | |||
541 | /* Close network interface. | ||
542 | * o reset flags. | ||
543 | * o if there's no more open channels then disconnect physical link. */ | ||
544 | static int cycx_netdevice_stop(struct net_device *dev) | ||
545 | { | ||
546 | struct cycx_x25_channel *chan = netdev_priv(dev); | ||
547 | |||
548 | netif_stop_queue(dev); | ||
549 | |||
550 | if (chan->state == WAN_CONNECTED || chan->state == WAN_CONNECTING) | ||
551 | cycx_x25_chan_disconnect(dev); | ||
552 | |||
553 | return 0; | ||
554 | } | ||
555 | |||
556 | /* Build media header. | ||
557 | * o encapsulate packet according to encapsulation type. | ||
558 | * | ||
559 | * The trick here is to put packet type (Ethertype) into 'protocol' field of | ||
560 | * the socket buffer, so that we don't forget it. If encapsulation fails, | ||
561 | * set skb->protocol to 0 and discard packet later. | ||
562 | * | ||
563 | * Return: media header length. */ | ||
564 | static int cycx_netdevice_hard_header(struct sk_buff *skb, | ||
565 | struct net_device *dev, u16 type, | ||
566 | const void *daddr, const void *saddr, | ||
567 | unsigned len) | ||
568 | { | ||
569 | skb->protocol = htons(type); | ||
570 | |||
571 | return dev->hard_header_len; | ||
572 | } | ||
573 | |||
574 | /* * Re-build media header. | ||
575 | * Return: 1 physical address resolved. | ||
576 | * 0 physical address not resolved */ | ||
577 | static int cycx_netdevice_rebuild_header(struct sk_buff *skb) | ||
578 | { | ||
579 | return 1; | ||
580 | } | ||
581 | |||
582 | /* Send a packet on a network interface. | ||
583 | * o set busy flag (marks start of the transmission). | ||
584 | * o check link state. If link is not up, then drop the packet. | ||
585 | * o check channel status. If it's down then initiate a call. | ||
586 | * o pass a packet to corresponding WAN device. | ||
587 | * o free socket buffer | ||
588 | * | ||
589 | * Return: 0 complete (socket buffer must be freed) | ||
590 | * non-0 packet may be re-transmitted (tbusy must be set) | ||
591 | * | ||
592 | * Notes: | ||
593 | * 1. This routine is called either by the protocol stack or by the "net | ||
594 | * bottom half" (with interrupts enabled). | ||
595 | * 2. Setting tbusy flag will inhibit further transmit requests from the | ||
596 | * protocol stack and can be used for flow control with protocol layer. */ | ||
597 | static netdev_tx_t cycx_netdevice_hard_start_xmit(struct sk_buff *skb, | ||
598 | struct net_device *dev) | ||
599 | { | ||
600 | struct cycx_x25_channel *chan = netdev_priv(dev); | ||
601 | struct cycx_device *card = chan->card; | ||
602 | |||
603 | if (!chan->svc) | ||
604 | chan->protocol = ntohs(skb->protocol); | ||
605 | |||
606 | if (card->wandev.state != WAN_CONNECTED) | ||
607 | ++chan->ifstats.tx_dropped; | ||
608 | else if (chan->svc && chan->protocol && | ||
609 | chan->protocol != ntohs(skb->protocol)) { | ||
610 | pr_info("%s: unsupported Ethertype 0x%04X on interface %s!\n", | ||
611 | card->devname, ntohs(skb->protocol), dev->name); | ||
612 | ++chan->ifstats.tx_errors; | ||
613 | } else if (chan->protocol == ETH_P_IP) { | ||
614 | switch (chan->state) { | ||
615 | case WAN_DISCONNECTED: | ||
616 | if (cycx_x25_chan_connect(dev)) { | ||
617 | netif_stop_queue(dev); | ||
618 | return NETDEV_TX_BUSY; | ||
619 | } | ||
620 | /* fall thru */ | ||
621 | case WAN_CONNECTED: | ||
622 | reset_timer(dev); | ||
623 | dev->trans_start = jiffies; | ||
624 | netif_stop_queue(dev); | ||
625 | |||
626 | if (cycx_x25_chan_send(dev, skb)) | ||
627 | return NETDEV_TX_BUSY; | ||
628 | |||
629 | break; | ||
630 | default: | ||
631 | ++chan->ifstats.tx_dropped; | ||
632 | ++card->wandev.stats.tx_dropped; | ||
633 | } | ||
634 | } else { /* chan->protocol == ETH_P_X25 */ | ||
635 | switch (skb->data[0]) { | ||
636 | case X25_IFACE_DATA: | ||
637 | break; | ||
638 | case X25_IFACE_CONNECT: | ||
639 | cycx_x25_chan_connect(dev); | ||
640 | goto free_packet; | ||
641 | case X25_IFACE_DISCONNECT: | ||
642 | cycx_x25_chan_disconnect(dev); | ||
643 | goto free_packet; | ||
644 | default: | ||
645 | pr_info("%s: unknown %d x25-iface request on %s!\n", | ||
646 | card->devname, skb->data[0], dev->name); | ||
647 | ++chan->ifstats.tx_errors; | ||
648 | goto free_packet; | ||
649 | } | ||
650 | |||
651 | skb_pull(skb, 1); /* Remove control byte */ | ||
652 | reset_timer(dev); | ||
653 | dev->trans_start = jiffies; | ||
654 | netif_stop_queue(dev); | ||
655 | |||
656 | if (cycx_x25_chan_send(dev, skb)) { | ||
657 | /* prepare for future retransmissions */ | ||
658 | skb_push(skb, 1); | ||
659 | return NETDEV_TX_BUSY; | ||
660 | } | ||
661 | } | ||
662 | |||
663 | free_packet: | ||
664 | dev_kfree_skb(skb); | ||
665 | |||
666 | return NETDEV_TX_OK; | ||
667 | } | ||
668 | |||
669 | /* Get Ethernet-style interface statistics. | ||
670 | * Return a pointer to struct net_device_stats */ | ||
671 | static struct net_device_stats *cycx_netdevice_get_stats(struct net_device *dev) | ||
672 | { | ||
673 | struct cycx_x25_channel *chan = netdev_priv(dev); | ||
674 | |||
675 | return chan ? &chan->ifstats : NULL; | ||
676 | } | ||
677 | |||
678 | /* Interrupt Handlers */ | ||
679 | /* X.25 Interrupt Service Routine. */ | ||
680 | static void cycx_x25_irq_handler(struct cycx_device *card) | ||
681 | { | ||
682 | struct cycx_x25_cmd cmd; | ||
683 | u16 z = 0; | ||
684 | |||
685 | card->in_isr = 1; | ||
686 | card->buff_int_mode_unbusy = 0; | ||
687 | cycx_peek(&card->hw, X25_RXMBOX_OFFS, &cmd, sizeof(cmd)); | ||
688 | |||
689 | switch (cmd.command) { | ||
690 | case X25_DATA_INDICATION: | ||
691 | cycx_x25_irq_rx(card, &cmd); | ||
692 | break; | ||
693 | case X25_ACK_FROM_VC: | ||
694 | cycx_x25_irq_tx(card, &cmd); | ||
695 | break; | ||
696 | case X25_LOG: | ||
697 | cycx_x25_irq_log(card, &cmd); | ||
698 | break; | ||
699 | case X25_STATISTIC: | ||
700 | cycx_x25_irq_stat(card, &cmd); | ||
701 | break; | ||
702 | case X25_CONNECT_CONFIRM: | ||
703 | cycx_x25_irq_connect_confirm(card, &cmd); | ||
704 | break; | ||
705 | case X25_CONNECT_INDICATION: | ||
706 | cycx_x25_irq_connect(card, &cmd); | ||
707 | break; | ||
708 | case X25_DISCONNECT_INDICATION: | ||
709 | cycx_x25_irq_disconnect(card, &cmd); | ||
710 | break; | ||
711 | case X25_DISCONNECT_CONFIRM: | ||
712 | cycx_x25_irq_disconnect_confirm(card, &cmd); | ||
713 | break; | ||
714 | case X25_LINE_ON: | ||
715 | cycx_set_state(card, WAN_CONNECTED); | ||
716 | break; | ||
717 | case X25_LINE_OFF: | ||
718 | cycx_set_state(card, WAN_DISCONNECTED); | ||
719 | break; | ||
720 | default: | ||
721 | cycx_x25_irq_spurious(card, &cmd); | ||
722 | break; | ||
723 | } | ||
724 | |||
725 | cycx_poke(&card->hw, 0, &z, sizeof(z)); | ||
726 | cycx_poke(&card->hw, X25_RXMBOX_OFFS, &z, sizeof(z)); | ||
727 | card->in_isr = 0; | ||
728 | } | ||
729 | |||
730 | /* Transmit interrupt handler. | ||
731 | * o Release socket buffer | ||
732 | * o Clear 'tbusy' flag */ | ||
733 | static void cycx_x25_irq_tx(struct cycx_device *card, struct cycx_x25_cmd *cmd) | ||
734 | { | ||
735 | struct net_device *dev; | ||
736 | struct wan_device *wandev = &card->wandev; | ||
737 | u8 lcn; | ||
738 | |||
739 | cycx_peek(&card->hw, cmd->buf, &lcn, sizeof(lcn)); | ||
740 | |||
741 | /* unbusy device and then dev_tint(); */ | ||
742 | dev = cycx_x25_get_dev_by_lcn(wandev, lcn); | ||
743 | if (dev) { | ||
744 | card->buff_int_mode_unbusy = 1; | ||
745 | netif_wake_queue(dev); | ||
746 | } else | ||
747 | pr_err("%s:ackvc for inexistent lcn %d\n", card->devname, lcn); | ||
748 | } | ||
749 | |||
750 | /* Receive interrupt handler. | ||
751 | * This routine handles fragmented IP packets using M-bit according to the | ||
752 | * RFC1356. | ||
753 | * o map logical channel number to network interface. | ||
754 | * o allocate socket buffer or append received packet to the existing one. | ||
755 | * o if M-bit is reset (i.e. it's the last packet in a sequence) then | ||
756 | * decapsulate packet and pass socket buffer to the protocol stack. | ||
757 | * | ||
758 | * Notes: | ||
759 | * 1. When allocating a socket buffer, if M-bit is set then more data is | ||
760 | * coming and we have to allocate buffer for the maximum IP packet size | ||
761 | * expected on this channel. | ||
762 | * 2. If something goes wrong and X.25 packet has to be dropped (e.g. no | ||
763 | * socket buffers available) the whole packet sequence must be discarded. */ | ||
764 | static void cycx_x25_irq_rx(struct cycx_device *card, struct cycx_x25_cmd *cmd) | ||
765 | { | ||
766 | struct wan_device *wandev = &card->wandev; | ||
767 | struct net_device *dev; | ||
768 | struct cycx_x25_channel *chan; | ||
769 | struct sk_buff *skb; | ||
770 | u8 bitm, lcn; | ||
771 | int pktlen = cmd->len - 5; | ||
772 | |||
773 | cycx_peek(&card->hw, cmd->buf, &lcn, sizeof(lcn)); | ||
774 | cycx_peek(&card->hw, cmd->buf + 4, &bitm, sizeof(bitm)); | ||
775 | bitm &= 0x10; | ||
776 | |||
777 | dev = cycx_x25_get_dev_by_lcn(wandev, lcn); | ||
778 | if (!dev) { | ||
779 | /* Invalid channel, discard packet */ | ||
780 | pr_info("%s: receiving on orphaned LCN %d!\n", | ||
781 | card->devname, lcn); | ||
782 | return; | ||
783 | } | ||
784 | |||
785 | chan = netdev_priv(dev); | ||
786 | reset_timer(dev); | ||
787 | |||
788 | if (chan->drop_sequence) { | ||
789 | if (!bitm) | ||
790 | chan->drop_sequence = 0; | ||
791 | else | ||
792 | return; | ||
793 | } | ||
794 | |||
795 | if ((skb = chan->rx_skb) == NULL) { | ||
796 | /* Allocate new socket buffer */ | ||
797 | int bufsize = bitm ? dev->mtu : pktlen; | ||
798 | |||
799 | if ((skb = dev_alloc_skb((chan->protocol == ETH_P_X25 ? 1 : 0) + | ||
800 | bufsize + | ||
801 | dev->hard_header_len)) == NULL) { | ||
802 | pr_info("%s: no socket buffers available!\n", | ||
803 | card->devname); | ||
804 | chan->drop_sequence = 1; | ||
805 | ++chan->ifstats.rx_dropped; | ||
806 | return; | ||
807 | } | ||
808 | |||
809 | if (chan->protocol == ETH_P_X25) /* X.25 socket layer control */ | ||
810 | /* 0 = data packet (dev_alloc_skb zeroed skb->data) */ | ||
811 | skb_put(skb, 1); | ||
812 | |||
813 | skb->dev = dev; | ||
814 | skb->protocol = htons(chan->protocol); | ||
815 | chan->rx_skb = skb; | ||
816 | } | ||
817 | |||
818 | if (skb_tailroom(skb) < pktlen) { | ||
819 | /* No room for the packet. Call off the whole thing! */ | ||
820 | dev_kfree_skb_irq(skb); | ||
821 | chan->rx_skb = NULL; | ||
822 | |||
823 | if (bitm) | ||
824 | chan->drop_sequence = 1; | ||
825 | |||
826 | pr_info("%s: unexpectedly long packet sequence on interface %s!\n", | ||
827 | card->devname, dev->name); | ||
828 | ++chan->ifstats.rx_length_errors; | ||
829 | return; | ||
830 | } | ||
831 | |||
832 | /* Append packet to the socket buffer */ | ||
833 | cycx_peek(&card->hw, cmd->buf + 5, skb_put(skb, pktlen), pktlen); | ||
834 | |||
835 | if (bitm) | ||
836 | return; /* more data is coming */ | ||
837 | |||
838 | chan->rx_skb = NULL; /* dequeue packet */ | ||
839 | |||
840 | ++chan->ifstats.rx_packets; | ||
841 | chan->ifstats.rx_bytes += pktlen; | ||
842 | |||
843 | skb_reset_mac_header(skb); | ||
844 | netif_rx(skb); | ||
845 | } | ||
846 | |||
847 | /* Connect interrupt handler. */ | ||
848 | static void cycx_x25_irq_connect(struct cycx_device *card, | ||
849 | struct cycx_x25_cmd *cmd) | ||
850 | { | ||
851 | struct wan_device *wandev = &card->wandev; | ||
852 | struct net_device *dev = NULL; | ||
853 | struct cycx_x25_channel *chan; | ||
854 | u8 d[32], | ||
855 | loc[24], | ||
856 | rem[24]; | ||
857 | u8 lcn, sizeloc, sizerem; | ||
858 | |||
859 | cycx_peek(&card->hw, cmd->buf, &lcn, sizeof(lcn)); | ||
860 | cycx_peek(&card->hw, cmd->buf + 5, &sizeloc, sizeof(sizeloc)); | ||
861 | cycx_peek(&card->hw, cmd->buf + 6, d, cmd->len - 6); | ||
862 | |||
863 | sizerem = sizeloc >> 4; | ||
864 | sizeloc &= 0x0F; | ||
865 | |||
866 | loc[0] = rem[0] = '\0'; | ||
867 | |||
868 | if (sizeloc) | ||
869 | nibble_to_byte(d, loc, sizeloc, 0); | ||
870 | |||
871 | if (sizerem) | ||
872 | nibble_to_byte(d + (sizeloc >> 1), rem, sizerem, sizeloc & 1); | ||
873 | |||
874 | dprintk(1, KERN_INFO "%s:lcn=%d, local=%s, remote=%s\n", | ||
875 | __func__, lcn, loc, rem); | ||
876 | |||
877 | dev = cycx_x25_get_dev_by_dte_addr(wandev, rem); | ||
878 | if (!dev) { | ||
879 | /* Invalid channel, discard packet */ | ||
880 | pr_info("%s: connect not expected: remote %s!\n", | ||
881 | card->devname, rem); | ||
882 | return; | ||
883 | } | ||
884 | |||
885 | chan = netdev_priv(dev); | ||
886 | chan->lcn = lcn; | ||
887 | cycx_x25_connect_response(card, chan); | ||
888 | cycx_x25_set_chan_state(dev, WAN_CONNECTED); | ||
889 | } | ||
890 | |||
891 | /* Connect confirm interrupt handler. */ | ||
892 | static void cycx_x25_irq_connect_confirm(struct cycx_device *card, | ||
893 | struct cycx_x25_cmd *cmd) | ||
894 | { | ||
895 | struct wan_device *wandev = &card->wandev; | ||
896 | struct net_device *dev; | ||
897 | struct cycx_x25_channel *chan; | ||
898 | u8 lcn, key; | ||
899 | |||
900 | cycx_peek(&card->hw, cmd->buf, &lcn, sizeof(lcn)); | ||
901 | cycx_peek(&card->hw, cmd->buf + 1, &key, sizeof(key)); | ||
902 | dprintk(1, KERN_INFO "%s: %s:lcn=%d, key=%d\n", | ||
903 | card->devname, __func__, lcn, key); | ||
904 | |||
905 | dev = cycx_x25_get_dev_by_lcn(wandev, -key); | ||
906 | if (!dev) { | ||
907 | /* Invalid channel, discard packet */ | ||
908 | clear_bit(--key, (void*)&card->u.x.connection_keys); | ||
909 | pr_info("%s: connect confirm not expected: lcn %d, key=%d!\n", | ||
910 | card->devname, lcn, key); | ||
911 | return; | ||
912 | } | ||
913 | |||
914 | clear_bit(--key, (void*)&card->u.x.connection_keys); | ||
915 | chan = netdev_priv(dev); | ||
916 | chan->lcn = lcn; | ||
917 | cycx_x25_set_chan_state(dev, WAN_CONNECTED); | ||
918 | } | ||
919 | |||
920 | /* Disconnect confirm interrupt handler. */ | ||
921 | static void cycx_x25_irq_disconnect_confirm(struct cycx_device *card, | ||
922 | struct cycx_x25_cmd *cmd) | ||
923 | { | ||
924 | struct wan_device *wandev = &card->wandev; | ||
925 | struct net_device *dev; | ||
926 | u8 lcn; | ||
927 | |||
928 | cycx_peek(&card->hw, cmd->buf, &lcn, sizeof(lcn)); | ||
929 | dprintk(1, KERN_INFO "%s: %s:lcn=%d\n", | ||
930 | card->devname, __func__, lcn); | ||
931 | dev = cycx_x25_get_dev_by_lcn(wandev, lcn); | ||
932 | if (!dev) { | ||
933 | /* Invalid channel, discard packet */ | ||
934 | pr_info("%s:disconnect confirm not expected!:lcn %d\n", | ||
935 | card->devname, lcn); | ||
936 | return; | ||
937 | } | ||
938 | |||
939 | cycx_x25_set_chan_state(dev, WAN_DISCONNECTED); | ||
940 | } | ||
941 | |||
942 | /* disconnect interrupt handler. */ | ||
943 | static void cycx_x25_irq_disconnect(struct cycx_device *card, | ||
944 | struct cycx_x25_cmd *cmd) | ||
945 | { | ||
946 | struct wan_device *wandev = &card->wandev; | ||
947 | struct net_device *dev; | ||
948 | u8 lcn; | ||
949 | |||
950 | cycx_peek(&card->hw, cmd->buf, &lcn, sizeof(lcn)); | ||
951 | dprintk(1, KERN_INFO "%s:lcn=%d\n", __func__, lcn); | ||
952 | |||
953 | dev = cycx_x25_get_dev_by_lcn(wandev, lcn); | ||
954 | if (dev) { | ||
955 | struct cycx_x25_channel *chan = netdev_priv(dev); | ||
956 | |||
957 | cycx_x25_disconnect_response(card, chan->link, lcn); | ||
958 | cycx_x25_set_chan_state(dev, WAN_DISCONNECTED); | ||
959 | } else | ||
960 | cycx_x25_disconnect_response(card, 0, lcn); | ||
961 | } | ||
962 | |||
963 | /* LOG interrupt handler. */ | ||
964 | static void cycx_x25_irq_log(struct cycx_device *card, struct cycx_x25_cmd *cmd) | ||
965 | { | ||
966 | #if CYCLOMX_X25_DEBUG | ||
967 | char bf[20]; | ||
968 | u16 size, toread, link, msg_code; | ||
969 | u8 code, routine; | ||
970 | |||
971 | cycx_peek(&card->hw, cmd->buf, &msg_code, sizeof(msg_code)); | ||
972 | cycx_peek(&card->hw, cmd->buf + 2, &link, sizeof(link)); | ||
973 | cycx_peek(&card->hw, cmd->buf + 4, &size, sizeof(size)); | ||
974 | /* at most 20 bytes are available... thanks to Daniela :) */ | ||
975 | toread = size < 20 ? size : 20; | ||
976 | cycx_peek(&card->hw, cmd->buf + 10, &bf, toread); | ||
977 | cycx_peek(&card->hw, cmd->buf + 10 + toread, &code, 1); | ||
978 | cycx_peek(&card->hw, cmd->buf + 10 + toread + 1, &routine, 1); | ||
979 | |||
980 | pr_info("cycx_x25_irq_handler: X25_LOG (0x4500) indic.:\n"); | ||
981 | pr_info("cmd->buf=0x%X\n", cmd->buf); | ||
982 | pr_info("Log message code=0x%X\n", msg_code); | ||
983 | pr_info("Link=%d\n", link); | ||
984 | pr_info("log code=0x%X\n", code); | ||
985 | pr_info("log routine=0x%X\n", routine); | ||
986 | pr_info("Message size=%d\n", size); | ||
987 | hex_dump("Message", bf, toread); | ||
988 | #endif | ||
989 | } | ||
990 | |||
991 | /* STATISTIC interrupt handler. */ | ||
992 | static void cycx_x25_irq_stat(struct cycx_device *card, | ||
993 | struct cycx_x25_cmd *cmd) | ||
994 | { | ||
995 | cycx_peek(&card->hw, cmd->buf, &card->u.x.stats, | ||
996 | sizeof(card->u.x.stats)); | ||
997 | hex_dump("cycx_x25_irq_stat", (unsigned char*)&card->u.x.stats, | ||
998 | sizeof(card->u.x.stats)); | ||
999 | cycx_x25_dump_stats(&card->u.x.stats); | ||
1000 | wake_up_interruptible(&card->wait_stats); | ||
1001 | } | ||
1002 | |||
1003 | /* Spurious interrupt handler. | ||
1004 | * o print a warning | ||
1005 | * If number of spurious interrupts exceeded some limit, then ??? */ | ||
1006 | static void cycx_x25_irq_spurious(struct cycx_device *card, | ||
1007 | struct cycx_x25_cmd *cmd) | ||
1008 | { | ||
1009 | pr_info("%s: spurious interrupt (0x%X)!\n", | ||
1010 | card->devname, cmd->command); | ||
1011 | } | ||
1012 | #ifdef CYCLOMX_X25_DEBUG | ||
1013 | static void hex_dump(char *msg, unsigned char *p, int len) | ||
1014 | { | ||
1015 | print_hex_dump(KERN_INFO, msg, DUMP_PREFIX_OFFSET, 16, 1, | ||
1016 | p, len, true); | ||
1017 | } | ||
1018 | #endif | ||
1019 | |||
1020 | /* Cyclom 2X Firmware-Specific Functions */ | ||
1021 | /* Exec X.25 command. */ | ||
1022 | static int x25_exec(struct cycx_device *card, int command, int link, | ||
1023 | void *d1, int len1, void *d2, int len2) | ||
1024 | { | ||
1025 | struct cycx_x25_cmd c; | ||
1026 | unsigned long flags; | ||
1027 | u32 addr = 0x1200 + 0x2E0 * link + 0x1E2; | ||
1028 | u8 retry = CYCX_X25_MAX_CMD_RETRY; | ||
1029 | int err = 0; | ||
1030 | |||
1031 | c.command = command; | ||
1032 | c.link = link; | ||
1033 | c.len = len1 + len2; | ||
1034 | |||
1035 | spin_lock_irqsave(&card->u.x.lock, flags); | ||
1036 | |||
1037 | /* write command */ | ||
1038 | cycx_poke(&card->hw, X25_MBOX_OFFS, &c, sizeof(c) - sizeof(c.buf)); | ||
1039 | |||
1040 | /* write X.25 data */ | ||
1041 | if (d1) { | ||
1042 | cycx_poke(&card->hw, addr, d1, len1); | ||
1043 | |||
1044 | if (d2) { | ||
1045 | if (len2 > 254) { | ||
1046 | u32 addr1 = 0xA00 + 0x400 * link; | ||
1047 | |||
1048 | cycx_poke(&card->hw, addr + len1, d2, 249); | ||
1049 | cycx_poke(&card->hw, addr1, ((u8*)d2) + 249, | ||
1050 | len2 - 249); | ||
1051 | } else | ||
1052 | cycx_poke(&card->hw, addr + len1, d2, len2); | ||
1053 | } | ||
1054 | } | ||
1055 | |||
1056 | /* generate interruption, executing command */ | ||
1057 | cycx_intr(&card->hw); | ||
1058 | |||
1059 | /* wait till card->mbox == 0 */ | ||
1060 | do { | ||
1061 | err = cycx_exec(card->mbox); | ||
1062 | } while (retry-- && err); | ||
1063 | |||
1064 | spin_unlock_irqrestore(&card->u.x.lock, flags); | ||
1065 | |||
1066 | return err; | ||
1067 | } | ||
1068 | |||
1069 | /* Configure adapter. */ | ||
1070 | static int cycx_x25_configure(struct cycx_device *card, | ||
1071 | struct cycx_x25_config *conf) | ||
1072 | { | ||
1073 | struct { | ||
1074 | u16 nlinks; | ||
1075 | struct cycx_x25_config conf[2]; | ||
1076 | } x25_cmd_conf; | ||
1077 | |||
1078 | memset(&x25_cmd_conf, 0, sizeof(x25_cmd_conf)); | ||
1079 | x25_cmd_conf.nlinks = 2; | ||
1080 | x25_cmd_conf.conf[0] = *conf; | ||
1081 | /* FIXME: we need to find a way in the wanrouter framework | ||
1082 | to configure the second link, for now lets use it | ||
1083 | with the same config from the first link, fixing | ||
1084 | the interface type to RS232, the speed in 38400 and | ||
1085 | the clock to external */ | ||
1086 | x25_cmd_conf.conf[1] = *conf; | ||
1087 | x25_cmd_conf.conf[1].link = 1; | ||
1088 | x25_cmd_conf.conf[1].speed = 5; /* 38400 */ | ||
1089 | x25_cmd_conf.conf[1].clock = 8; | ||
1090 | x25_cmd_conf.conf[1].flags = 0; /* default = RS232 */ | ||
1091 | |||
1092 | cycx_x25_dump_config(&x25_cmd_conf.conf[0]); | ||
1093 | cycx_x25_dump_config(&x25_cmd_conf.conf[1]); | ||
1094 | |||
1095 | return x25_exec(card, X25_CONFIG, 0, | ||
1096 | &x25_cmd_conf, sizeof(x25_cmd_conf), NULL, 0); | ||
1097 | } | ||
1098 | |||
1099 | /* Get protocol statistics. */ | ||
1100 | static int cycx_x25_get_stats(struct cycx_device *card) | ||
1101 | { | ||
1102 | /* the firmware expects 20 in the size field!!! | ||
1103 | thanks to Daniela */ | ||
1104 | int err = x25_exec(card, X25_STATISTIC, 0, NULL, 20, NULL, 0); | ||
1105 | |||
1106 | if (err) | ||
1107 | return err; | ||
1108 | |||
1109 | interruptible_sleep_on(&card->wait_stats); | ||
1110 | |||
1111 | if (signal_pending(current)) | ||
1112 | return -EINTR; | ||
1113 | |||
1114 | card->wandev.stats.rx_packets = card->u.x.stats.n2_rx_frames; | ||
1115 | card->wandev.stats.rx_over_errors = card->u.x.stats.rx_over_errors; | ||
1116 | card->wandev.stats.rx_crc_errors = card->u.x.stats.rx_crc_errors; | ||
1117 | card->wandev.stats.rx_length_errors = 0; /* not available from fw */ | ||
1118 | card->wandev.stats.rx_frame_errors = 0; /* not available from fw */ | ||
1119 | card->wandev.stats.rx_missed_errors = card->u.x.stats.rx_aborts; | ||
1120 | card->wandev.stats.rx_dropped = 0; /* not available from fw */ | ||
1121 | card->wandev.stats.rx_errors = 0; /* not available from fw */ | ||
1122 | card->wandev.stats.tx_packets = card->u.x.stats.n2_tx_frames; | ||
1123 | card->wandev.stats.tx_aborted_errors = card->u.x.stats.tx_aborts; | ||
1124 | card->wandev.stats.tx_dropped = 0; /* not available from fw */ | ||
1125 | card->wandev.stats.collisions = 0; /* not available from fw */ | ||
1126 | card->wandev.stats.tx_errors = 0; /* not available from fw */ | ||
1127 | |||
1128 | cycx_x25_dump_devs(&card->wandev); | ||
1129 | |||
1130 | return 0; | ||
1131 | } | ||
1132 | |||
1133 | /* return the number of nibbles */ | ||
1134 | static int byte_to_nibble(u8 *s, u8 *d, char *nibble) | ||
1135 | { | ||
1136 | int i = 0; | ||
1137 | |||
1138 | if (*nibble && *s) { | ||
1139 | d[i] |= *s++ - '0'; | ||
1140 | *nibble = 0; | ||
1141 | ++i; | ||
1142 | } | ||
1143 | |||
1144 | while (*s) { | ||
1145 | d[i] = (*s - '0') << 4; | ||
1146 | if (*(s + 1)) | ||
1147 | d[i] |= *(s + 1) - '0'; | ||
1148 | else { | ||
1149 | *nibble = 1; | ||
1150 | break; | ||
1151 | } | ||
1152 | ++i; | ||
1153 | s += 2; | ||
1154 | } | ||
1155 | |||
1156 | return i; | ||
1157 | } | ||
1158 | |||
1159 | static void nibble_to_byte(u8 *s, u8 *d, u8 len, u8 nibble) | ||
1160 | { | ||
1161 | if (nibble) { | ||
1162 | *d++ = '0' + (*s++ & 0x0F); | ||
1163 | --len; | ||
1164 | } | ||
1165 | |||
1166 | while (len) { | ||
1167 | *d++ = '0' + (*s >> 4); | ||
1168 | |||
1169 | if (--len) { | ||
1170 | *d++ = '0' + (*s & 0x0F); | ||
1171 | --len; | ||
1172 | } else break; | ||
1173 | |||
1174 | ++s; | ||
1175 | } | ||
1176 | |||
1177 | *d = '\0'; | ||
1178 | } | ||
1179 | |||
1180 | /* Place X.25 call. */ | ||
1181 | static int x25_place_call(struct cycx_device *card, | ||
1182 | struct cycx_x25_channel *chan) | ||
1183 | { | ||
1184 | int err = 0, | ||
1185 | len; | ||
1186 | char d[64], | ||
1187 | nibble = 0, | ||
1188 | mylen = chan->local_addr ? strlen(chan->local_addr) : 0, | ||
1189 | remotelen = strlen(chan->addr); | ||
1190 | u8 key; | ||
1191 | |||
1192 | if (card->u.x.connection_keys == ~0U) { | ||
1193 | pr_info("%s: too many simultaneous connection requests!\n", | ||
1194 | card->devname); | ||
1195 | return -EAGAIN; | ||
1196 | } | ||
1197 | |||
1198 | key = ffz(card->u.x.connection_keys); | ||
1199 | set_bit(key, (void*)&card->u.x.connection_keys); | ||
1200 | ++key; | ||
1201 | dprintk(1, KERN_INFO "%s:x25_place_call:key=%d\n", card->devname, key); | ||
1202 | memset(d, 0, sizeof(d)); | ||
1203 | d[1] = key; /* user key */ | ||
1204 | d[2] = 0x10; | ||
1205 | d[4] = 0x0B; | ||
1206 | |||
1207 | len = byte_to_nibble(chan->addr, d + 6, &nibble); | ||
1208 | |||
1209 | if (chan->local_addr) | ||
1210 | len += byte_to_nibble(chan->local_addr, d + 6 + len, &nibble); | ||
1211 | |||
1212 | if (nibble) | ||
1213 | ++len; | ||
1214 | |||
1215 | d[5] = mylen << 4 | remotelen; | ||
1216 | d[6 + len + 1] = 0xCC; /* TCP/IP over X.25, thanks to Daniela :) */ | ||
1217 | |||
1218 | if ((err = x25_exec(card, X25_CONNECT_REQUEST, chan->link, | ||
1219 | &d, 7 + len + 1, NULL, 0)) != 0) | ||
1220 | clear_bit(--key, (void*)&card->u.x.connection_keys); | ||
1221 | else | ||
1222 | chan->lcn = -key; | ||
1223 | |||
1224 | return err; | ||
1225 | } | ||
1226 | |||
1227 | /* Place X.25 CONNECT RESPONSE. */ | ||
1228 | static int cycx_x25_connect_response(struct cycx_device *card, | ||
1229 | struct cycx_x25_channel *chan) | ||
1230 | { | ||
1231 | u8 d[8]; | ||
1232 | |||
1233 | memset(d, 0, sizeof(d)); | ||
1234 | d[0] = d[3] = chan->lcn; | ||
1235 | d[2] = 0x10; | ||
1236 | d[4] = 0x0F; | ||
1237 | d[7] = 0xCC; /* TCP/IP over X.25, thanks Daniela */ | ||
1238 | |||
1239 | return x25_exec(card, X25_CONNECT_RESPONSE, chan->link, &d, 8, NULL, 0); | ||
1240 | } | ||
1241 | |||
1242 | /* Place X.25 DISCONNECT RESPONSE. */ | ||
1243 | static int cycx_x25_disconnect_response(struct cycx_device *card, u8 link, | ||
1244 | u8 lcn) | ||
1245 | { | ||
1246 | char d[5]; | ||
1247 | |||
1248 | memset(d, 0, sizeof(d)); | ||
1249 | d[0] = d[3] = lcn; | ||
1250 | d[2] = 0x10; | ||
1251 | d[4] = 0x17; | ||
1252 | |||
1253 | return x25_exec(card, X25_DISCONNECT_RESPONSE, link, &d, 5, NULL, 0); | ||
1254 | } | ||
1255 | |||
1256 | /* Clear X.25 call. */ | ||
1257 | static int x25_clear_call(struct cycx_device *card, u8 link, u8 lcn, u8 cause, | ||
1258 | u8 diagn) | ||
1259 | { | ||
1260 | u8 d[7]; | ||
1261 | |||
1262 | memset(d, 0, sizeof(d)); | ||
1263 | d[0] = d[3] = lcn; | ||
1264 | d[2] = 0x10; | ||
1265 | d[4] = 0x13; | ||
1266 | d[5] = cause; | ||
1267 | d[6] = diagn; | ||
1268 | |||
1269 | return x25_exec(card, X25_DISCONNECT_REQUEST, link, d, 7, NULL, 0); | ||
1270 | } | ||
1271 | |||
1272 | /* Send X.25 data packet. */ | ||
1273 | static int cycx_x25_send(struct cycx_device *card, u8 link, u8 lcn, u8 bitm, | ||
1274 | int len, void *buf) | ||
1275 | { | ||
1276 | u8 d[] = "?\xFF\x10??"; | ||
1277 | |||
1278 | d[0] = d[3] = lcn; | ||
1279 | d[4] = bitm; | ||
1280 | |||
1281 | return x25_exec(card, X25_DATA_REQUEST, link, &d, 5, buf, len); | ||
1282 | } | ||
1283 | |||
1284 | /* Miscellaneous */ | ||
1285 | /* Find network device by its channel number. */ | ||
1286 | static struct net_device *cycx_x25_get_dev_by_lcn(struct wan_device *wandev, | ||
1287 | s16 lcn) | ||
1288 | { | ||
1289 | struct net_device *dev = wandev->dev; | ||
1290 | struct cycx_x25_channel *chan; | ||
1291 | |||
1292 | while (dev) { | ||
1293 | chan = netdev_priv(dev); | ||
1294 | |||
1295 | if (chan->lcn == lcn) | ||
1296 | break; | ||
1297 | dev = chan->slave; | ||
1298 | } | ||
1299 | return dev; | ||
1300 | } | ||
1301 | |||
1302 | /* Find network device by its remote dte address. */ | ||
1303 | static struct net_device * | ||
1304 | cycx_x25_get_dev_by_dte_addr(struct wan_device *wandev, char *dte) | ||
1305 | { | ||
1306 | struct net_device *dev = wandev->dev; | ||
1307 | struct cycx_x25_channel *chan; | ||
1308 | |||
1309 | while (dev) { | ||
1310 | chan = netdev_priv(dev); | ||
1311 | |||
1312 | if (!strcmp(chan->addr, dte)) | ||
1313 | break; | ||
1314 | dev = chan->slave; | ||
1315 | } | ||
1316 | return dev; | ||
1317 | } | ||
1318 | |||
1319 | /* Initiate connection on the logical channel. | ||
1320 | * o for PVC we just get channel configuration | ||
1321 | * o for SVCs place an X.25 call | ||
1322 | * | ||
1323 | * Return: 0 connected | ||
1324 | * >0 connection in progress | ||
1325 | * <0 failure */ | ||
1326 | static int cycx_x25_chan_connect(struct net_device *dev) | ||
1327 | { | ||
1328 | struct cycx_x25_channel *chan = netdev_priv(dev); | ||
1329 | struct cycx_device *card = chan->card; | ||
1330 | |||
1331 | if (chan->svc) { | ||
1332 | if (!chan->addr[0]) | ||
1333 | return -EINVAL; /* no destination address */ | ||
1334 | |||
1335 | dprintk(1, KERN_INFO "%s: placing X.25 call to %s...\n", | ||
1336 | card->devname, chan->addr); | ||
1337 | |||
1338 | if (x25_place_call(card, chan)) | ||
1339 | return -EIO; | ||
1340 | |||
1341 | cycx_x25_set_chan_state(dev, WAN_CONNECTING); | ||
1342 | return 1; | ||
1343 | } else | ||
1344 | cycx_x25_set_chan_state(dev, WAN_CONNECTED); | ||
1345 | |||
1346 | return 0; | ||
1347 | } | ||
1348 | |||
1349 | /* Disconnect logical channel. | ||
1350 | * o if SVC then clear X.25 call */ | ||
1351 | static void cycx_x25_chan_disconnect(struct net_device *dev) | ||
1352 | { | ||
1353 | struct cycx_x25_channel *chan = netdev_priv(dev); | ||
1354 | |||
1355 | if (chan->svc) { | ||
1356 | x25_clear_call(chan->card, chan->link, chan->lcn, 0, 0); | ||
1357 | cycx_x25_set_chan_state(dev, WAN_DISCONNECTING); | ||
1358 | } else | ||
1359 | cycx_x25_set_chan_state(dev, WAN_DISCONNECTED); | ||
1360 | } | ||
1361 | |||
1362 | /* Called by kernel timer */ | ||
1363 | static void cycx_x25_chan_timer(unsigned long d) | ||
1364 | { | ||
1365 | struct net_device *dev = (struct net_device *)d; | ||
1366 | struct cycx_x25_channel *chan = netdev_priv(dev); | ||
1367 | |||
1368 | if (chan->state == WAN_CONNECTED) | ||
1369 | cycx_x25_chan_disconnect(dev); | ||
1370 | else | ||
1371 | pr_err("%s: %s for svc (%s) not connected!\n", | ||
1372 | chan->card->devname, __func__, dev->name); | ||
1373 | } | ||
1374 | |||
1375 | /* Set logical channel state. */ | ||
1376 | static void cycx_x25_set_chan_state(struct net_device *dev, u8 state) | ||
1377 | { | ||
1378 | struct cycx_x25_channel *chan = netdev_priv(dev); | ||
1379 | struct cycx_device *card = chan->card; | ||
1380 | unsigned long flags; | ||
1381 | char *string_state = NULL; | ||
1382 | |||
1383 | spin_lock_irqsave(&card->lock, flags); | ||
1384 | |||
1385 | if (chan->state != state) { | ||
1386 | if (chan->svc && chan->state == WAN_CONNECTED) | ||
1387 | del_timer(&chan->timer); | ||
1388 | |||
1389 | switch (state) { | ||
1390 | case WAN_CONNECTED: | ||
1391 | string_state = "connected!"; | ||
1392 | *(__be16*)dev->dev_addr = htons(chan->lcn); | ||
1393 | netif_wake_queue(dev); | ||
1394 | reset_timer(dev); | ||
1395 | |||
1396 | if (chan->protocol == ETH_P_X25) | ||
1397 | cycx_x25_chan_send_event(dev, | ||
1398 | X25_IFACE_CONNECT); | ||
1399 | |||
1400 | break; | ||
1401 | case WAN_CONNECTING: | ||
1402 | string_state = "connecting..."; | ||
1403 | break; | ||
1404 | case WAN_DISCONNECTING: | ||
1405 | string_state = "disconnecting..."; | ||
1406 | break; | ||
1407 | case WAN_DISCONNECTED: | ||
1408 | string_state = "disconnected!"; | ||
1409 | |||
1410 | if (chan->svc) { | ||
1411 | *(unsigned short*)dev->dev_addr = 0; | ||
1412 | chan->lcn = 0; | ||
1413 | } | ||
1414 | |||
1415 | if (chan->protocol == ETH_P_X25) | ||
1416 | cycx_x25_chan_send_event(dev, | ||
1417 | X25_IFACE_DISCONNECT); | ||
1418 | |||
1419 | netif_wake_queue(dev); | ||
1420 | break; | ||
1421 | } | ||
1422 | |||
1423 | pr_info("%s: interface %s %s\n", | ||
1424 | card->devname, dev->name, string_state); | ||
1425 | chan->state = state; | ||
1426 | } | ||
1427 | |||
1428 | spin_unlock_irqrestore(&card->lock, flags); | ||
1429 | } | ||
1430 | |||
1431 | /* Send packet on a logical channel. | ||
1432 | * When this function is called, tx_skb field of the channel data space | ||
1433 | * points to the transmit socket buffer. When transmission is complete, | ||
1434 | * release socket buffer and reset 'tbusy' flag. | ||
1435 | * | ||
1436 | * Return: 0 - transmission complete | ||
1437 | * 1 - busy | ||
1438 | * | ||
1439 | * Notes: | ||
1440 | * 1. If packet length is greater than MTU for this channel, we'll fragment | ||
1441 | * the packet into 'complete sequence' using M-bit. | ||
1442 | * 2. When transmission is complete, an event notification should be issued | ||
1443 | * to the router. */ | ||
1444 | static int cycx_x25_chan_send(struct net_device *dev, struct sk_buff *skb) | ||
1445 | { | ||
1446 | struct cycx_x25_channel *chan = netdev_priv(dev); | ||
1447 | struct cycx_device *card = chan->card; | ||
1448 | int bitm = 0; /* final packet */ | ||
1449 | unsigned len = skb->len; | ||
1450 | |||
1451 | if (skb->len > card->wandev.mtu) { | ||
1452 | len = card->wandev.mtu; | ||
1453 | bitm = 0x10; /* set M-bit (more data) */ | ||
1454 | } | ||
1455 | |||
1456 | if (cycx_x25_send(card, chan->link, chan->lcn, bitm, len, skb->data)) | ||
1457 | return 1; | ||
1458 | |||
1459 | if (bitm) { | ||
1460 | skb_pull(skb, len); | ||
1461 | return 1; | ||
1462 | } | ||
1463 | |||
1464 | ++chan->ifstats.tx_packets; | ||
1465 | chan->ifstats.tx_bytes += len; | ||
1466 | |||
1467 | return 0; | ||
1468 | } | ||
1469 | |||
1470 | /* Send event (connection, disconnection, etc) to X.25 socket layer */ | ||
1471 | |||
1472 | static void cycx_x25_chan_send_event(struct net_device *dev, u8 event) | ||
1473 | { | ||
1474 | struct sk_buff *skb; | ||
1475 | unsigned char *ptr; | ||
1476 | |||
1477 | if ((skb = dev_alloc_skb(1)) == NULL) { | ||
1478 | pr_err("%s: out of memory\n", __func__); | ||
1479 | return; | ||
1480 | } | ||
1481 | |||
1482 | ptr = skb_put(skb, 1); | ||
1483 | *ptr = event; | ||
1484 | |||
1485 | skb->protocol = x25_type_trans(skb, dev); | ||
1486 | netif_rx(skb); | ||
1487 | } | ||
1488 | |||
1489 | /* Convert line speed in bps to a number used by cyclom 2x code. */ | ||
1490 | static u8 bps_to_speed_code(u32 bps) | ||
1491 | { | ||
1492 | u8 number = 0; /* defaults to the lowest (1200) speed ;> */ | ||
1493 | |||
1494 | if (bps >= 512000) number = 8; | ||
1495 | else if (bps >= 256000) number = 7; | ||
1496 | else if (bps >= 64000) number = 6; | ||
1497 | else if (bps >= 38400) number = 5; | ||
1498 | else if (bps >= 19200) number = 4; | ||
1499 | else if (bps >= 9600) number = 3; | ||
1500 | else if (bps >= 4800) number = 2; | ||
1501 | else if (bps >= 2400) number = 1; | ||
1502 | |||
1503 | return number; | ||
1504 | } | ||
1505 | |||
1506 | /* log base 2 */ | ||
1507 | static u8 cycx_log2(u32 n) | ||
1508 | { | ||
1509 | u8 log = 0; | ||
1510 | |||
1511 | if (!n) | ||
1512 | return 0; | ||
1513 | |||
1514 | while (n > 1) { | ||
1515 | n >>= 1; | ||
1516 | ++log; | ||
1517 | } | ||
1518 | |||
1519 | return log; | ||
1520 | } | ||
1521 | |||
1522 | /* Convert decimal string to unsigned integer. | ||
1523 | * If len != 0 then only 'len' characters of the string are converted. */ | ||
1524 | static unsigned dec_to_uint(u8 *str, int len) | ||
1525 | { | ||
1526 | unsigned val = 0; | ||
1527 | |||
1528 | if (!len) | ||
1529 | len = strlen(str); | ||
1530 | |||
1531 | for (; len && isdigit(*str); ++str, --len) | ||
1532 | val = (val * 10) + (*str - (unsigned) '0'); | ||
1533 | |||
1534 | return val; | ||
1535 | } | ||
1536 | |||
1537 | static void reset_timer(struct net_device *dev) | ||
1538 | { | ||
1539 | struct cycx_x25_channel *chan = netdev_priv(dev); | ||
1540 | |||
1541 | if (chan->svc) | ||
1542 | mod_timer(&chan->timer, jiffies+chan->idle_tmout*HZ); | ||
1543 | } | ||
1544 | #ifdef CYCLOMX_X25_DEBUG | ||
1545 | static void cycx_x25_dump_config(struct cycx_x25_config *conf) | ||
1546 | { | ||
1547 | pr_info("X.25 configuration\n"); | ||
1548 | pr_info("-----------------\n"); | ||
1549 | pr_info("link number=%d\n", conf->link); | ||
1550 | pr_info("line speed=%d\n", conf->speed); | ||
1551 | pr_info("clock=%sternal\n", conf->clock == 8 ? "Ex" : "In"); | ||
1552 | pr_info("# level 2 retransm.=%d\n", conf->n2); | ||
1553 | pr_info("level 2 window=%d\n", conf->n2win); | ||
1554 | pr_info("level 3 window=%d\n", conf->n3win); | ||
1555 | pr_info("# logical channels=%d\n", conf->nvc); | ||
1556 | pr_info("level 3 pkt len=%d\n", conf->pktlen); | ||
1557 | pr_info("my address=%d\n", conf->locaddr); | ||
1558 | pr_info("remote address=%d\n", conf->remaddr); | ||
1559 | pr_info("t1=%d seconds\n", conf->t1); | ||
1560 | pr_info("t2=%d seconds\n", conf->t2); | ||
1561 | pr_info("t21=%d seconds\n", conf->t21); | ||
1562 | pr_info("# PVCs=%d\n", conf->npvc); | ||
1563 | pr_info("t23=%d seconds\n", conf->t23); | ||
1564 | pr_info("flags=0x%x\n", conf->flags); | ||
1565 | } | ||
1566 | |||
1567 | static void cycx_x25_dump_stats(struct cycx_x25_stats *stats) | ||
1568 | { | ||
1569 | pr_info("X.25 statistics\n"); | ||
1570 | pr_info("--------------\n"); | ||
1571 | pr_info("rx_crc_errors=%d\n", stats->rx_crc_errors); | ||
1572 | pr_info("rx_over_errors=%d\n", stats->rx_over_errors); | ||
1573 | pr_info("n2_tx_frames=%d\n", stats->n2_tx_frames); | ||
1574 | pr_info("n2_rx_frames=%d\n", stats->n2_rx_frames); | ||
1575 | pr_info("tx_timeouts=%d\n", stats->tx_timeouts); | ||
1576 | pr_info("rx_timeouts=%d\n", stats->rx_timeouts); | ||
1577 | pr_info("n3_tx_packets=%d\n", stats->n3_tx_packets); | ||
1578 | pr_info("n3_rx_packets=%d\n", stats->n3_rx_packets); | ||
1579 | pr_info("tx_aborts=%d\n", stats->tx_aborts); | ||
1580 | pr_info("rx_aborts=%d\n", stats->rx_aborts); | ||
1581 | } | ||
1582 | |||
1583 | static void cycx_x25_dump_devs(struct wan_device *wandev) | ||
1584 | { | ||
1585 | struct net_device *dev = wandev->dev; | ||
1586 | |||
1587 | pr_info("X.25 dev states\n"); | ||
1588 | pr_info("name: addr: txoff: protocol:\n"); | ||
1589 | pr_info("---------------------------------------\n"); | ||
1590 | |||
1591 | while(dev) { | ||
1592 | struct cycx_x25_channel *chan = netdev_priv(dev); | ||
1593 | |||
1594 | pr_info("%-5.5s %-15.15s %d ETH_P_%s\n", | ||
1595 | chan->name, chan->addr, netif_queue_stopped(dev), | ||
1596 | chan->protocol == ETH_P_IP ? "IP" : "X25"); | ||
1597 | dev = chan->slave; | ||
1598 | } | ||
1599 | } | ||
1600 | |||
1601 | #endif /* CYCLOMX_X25_DEBUG */ | ||
1602 | /* End */ | ||
diff --git a/include/linux/cyclomx.h b/include/linux/cyclomx.h deleted file mode 100644 index b88f7f428e58..000000000000 --- a/include/linux/cyclomx.h +++ /dev/null | |||
@@ -1,77 +0,0 @@ | |||
1 | #ifndef _CYCLOMX_H | ||
2 | #define _CYCLOMX_H | ||
3 | /* | ||
4 | * cyclomx.h Cyclom 2X WAN Link Driver. | ||
5 | * User-level API definitions. | ||
6 | * | ||
7 | * Author: Arnaldo Carvalho de Melo <acme@conectiva.com.br> | ||
8 | * | ||
9 | * Copyright: (c) 1998-2003 Arnaldo Carvalho de Melo | ||
10 | * | ||
11 | * Based on wanpipe.h by Gene Kozin <genek@compuserve.com> | ||
12 | * | ||
13 | * This program is free software; you can redistribute it and/or | ||
14 | * modify it under the terms of the GNU General Public License | ||
15 | * as published by the Free Software Foundation; either version | ||
16 | * 2 of the License, or (at your option) any later version. | ||
17 | * ============================================================================ | ||
18 | * 2000/07/13 acme remove crap #if KERNEL_VERSION > blah | ||
19 | * 2000/01/21 acme rename cyclomx_open to cyclomx_mod_inc_use_count | ||
20 | * and cyclomx_close to cyclomx_mod_dec_use_count | ||
21 | * 1999/05/19 acme wait_queue_head_t wait_stats(support for 2.3.*) | ||
22 | * 1999/01/03 acme judicious use of data types | ||
23 | * 1998/12/27 acme cleanup: PACKED not needed | ||
24 | * 1998/08/08 acme Version 0.0.1 | ||
25 | */ | ||
26 | |||
27 | #include <linux/wanrouter.h> | ||
28 | #include <linux/spinlock.h> | ||
29 | |||
30 | #ifdef __KERNEL__ | ||
31 | /* Kernel Interface */ | ||
32 | |||
33 | #include <linux/cycx_drv.h> /* Cyclom 2X support module API definitions */ | ||
34 | #include <linux/cycx_cfm.h> /* Cyclom 2X firmware module definitions */ | ||
35 | #ifdef CONFIG_CYCLOMX_X25 | ||
36 | #include <linux/cycx_x25.h> | ||
37 | #endif | ||
38 | |||
39 | /* Adapter Data Space. | ||
40 | * This structure is needed because we handle multiple cards, otherwise | ||
41 | * static data would do it. | ||
42 | */ | ||
43 | struct cycx_device { | ||
44 | char devname[WAN_DRVNAME_SZ + 1];/* card name */ | ||
45 | struct cycx_hw hw; /* hardware configuration */ | ||
46 | struct wan_device wandev; /* WAN device data space */ | ||
47 | u32 state_tick; /* link state timestamp */ | ||
48 | spinlock_t lock; | ||
49 | char in_isr; /* interrupt-in-service flag */ | ||
50 | char buff_int_mode_unbusy; /* flag for carrying out dev_tint */ | ||
51 | wait_queue_head_t wait_stats; /* to wait for the STATS indication */ | ||
52 | void __iomem *mbox; /* -> mailbox */ | ||
53 | void (*isr)(struct cycx_device* card); /* interrupt service routine */ | ||
54 | int (*exec)(struct cycx_device* card, void* u_cmd, void* u_data); | ||
55 | union { | ||
56 | #ifdef CONFIG_CYCLOMX_X25 | ||
57 | struct { /* X.25 specific data */ | ||
58 | u32 lo_pvc; | ||
59 | u32 hi_pvc; | ||
60 | u32 lo_svc; | ||
61 | u32 hi_svc; | ||
62 | struct cycx_x25_stats stats; | ||
63 | spinlock_t lock; | ||
64 | u32 connection_keys; | ||
65 | } x; | ||
66 | #endif | ||
67 | } u; | ||
68 | }; | ||
69 | |||
70 | /* Public Functions */ | ||
71 | void cycx_set_state(struct cycx_device *card, int state); | ||
72 | |||
73 | #ifdef CONFIG_CYCLOMX_X25 | ||
74 | int cycx_x25_wan_init(struct cycx_device *card, wandev_conf_t *conf); | ||
75 | #endif | ||
76 | #endif /* __KERNEL__ */ | ||
77 | #endif /* _CYCLOMX_H */ | ||
diff --git a/include/linux/cycx_drv.h b/include/linux/cycx_drv.h deleted file mode 100644 index 12fe6b0bfcff..000000000000 --- a/include/linux/cycx_drv.h +++ /dev/null | |||
@@ -1,64 +0,0 @@ | |||
1 | /* | ||
2 | * cycx_drv.h CYCX Support Module. Kernel API Definitions. | ||
3 | * | ||
4 | * Author: Arnaldo Carvalho de Melo <acme@conectiva.com.br> | ||
5 | * | ||
6 | * Copyright: (c) 1998-2003 Arnaldo Carvalho de Melo | ||
7 | * | ||
8 | * Based on sdladrv.h by Gene Kozin <genek@compuserve.com> | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or | ||
11 | * modify it under the terms of the GNU General Public License | ||
12 | * as published by the Free Software Foundation; either version | ||
13 | * 2 of the License, or (at your option) any later version. | ||
14 | * ============================================================================ | ||
15 | * 1999/10/23 acme cycxhw_t cleanup | ||
16 | * 1999/01/03 acme more judicious use of data types... | ||
17 | * uclong, ucchar, etc deleted, the u8, u16, u32 | ||
18 | * types are the portable way to go. | ||
19 | * 1999/01/03 acme judicious use of data types... u16, u32, etc | ||
20 | * 1998/12/26 acme FIXED_BUFFERS, CONF_OFFSET, | ||
21 | * removal of cy_read{bwl} | ||
22 | * 1998/08/08 acme Initial version. | ||
23 | */ | ||
24 | #ifndef _CYCX_DRV_H | ||
25 | #define _CYCX_DRV_H | ||
26 | |||
27 | #define CYCX_WINDOWSIZE 0x4000 /* default dual-port memory window size */ | ||
28 | #define GEN_CYCX_INTR 0x02 | ||
29 | #define RST_ENABLE 0x04 | ||
30 | #define START_CPU 0x06 | ||
31 | #define RST_DISABLE 0x08 | ||
32 | #define FIXED_BUFFERS 0x08 | ||
33 | #define TEST_PATTERN 0xaa55 | ||
34 | #define CMD_OFFSET 0x20 | ||
35 | #define CONF_OFFSET 0x0380 | ||
36 | #define RESET_OFFSET 0x3c00 /* For reset file load */ | ||
37 | #define DATA_OFFSET 0x0100 /* For code and data files load */ | ||
38 | #define START_OFFSET 0x3ff0 /* 80186 starts here */ | ||
39 | |||
40 | /** | ||
41 | * struct cycx_hw - Adapter hardware configuration | ||
42 | * @fwid - firmware ID | ||
43 | * @irq - interrupt request level | ||
44 | * @dpmbase - dual-port memory base | ||
45 | * @dpmsize - dual-port memory size | ||
46 | * @reserved - reserved for future use | ||
47 | */ | ||
48 | struct cycx_hw { | ||
49 | u32 fwid; | ||
50 | int irq; | ||
51 | void __iomem *dpmbase; | ||
52 | u32 dpmsize; | ||
53 | u32 reserved[5]; | ||
54 | }; | ||
55 | |||
56 | /* Function Prototypes */ | ||
57 | extern int cycx_setup(struct cycx_hw *hw, void *sfm, u32 len, unsigned long base); | ||
58 | extern int cycx_down(struct cycx_hw *hw); | ||
59 | extern int cycx_peek(struct cycx_hw *hw, u32 addr, void *buf, u32 len); | ||
60 | extern int cycx_poke(struct cycx_hw *hw, u32 addr, void *buf, u32 len); | ||
61 | extern int cycx_exec(void __iomem *addr); | ||
62 | |||
63 | extern void cycx_intr(struct cycx_hw *hw); | ||
64 | #endif /* _CYCX_DRV_H */ | ||
diff --git a/include/linux/wanrouter.h b/include/linux/wanrouter.h index cec4b4159767..8198a63cf459 100644 --- a/include/linux/wanrouter.h +++ b/include/linux/wanrouter.h | |||
@@ -1,129 +1,10 @@ | |||
1 | /***************************************************************************** | 1 | /* |
2 | * wanrouter.h Definitions for the WAN Multiprotocol Router Module. | 2 | * wanrouter.h Legacy declarations kept around until X25 is removed |
3 | * This module provides API and common services for WAN Link | 3 | */ |
4 | * Drivers and is completely hardware-independent. | 4 | |
5 | * | ||
6 | * Author: Nenad Corbic <ncorbic@sangoma.com> | ||
7 | * Gideon Hack | ||
8 | * Additions: Arnaldo Melo | ||
9 | * | ||
10 | * Copyright: (c) 1995-2000 Sangoma Technologies Inc. | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or | ||
13 | * modify it under the terms of the GNU General Public License | ||
14 | * as published by the Free Software Foundation; either version | ||
15 | * 2 of the License, or (at your option) any later version. | ||
16 | * ============================================================================ | ||
17 | * Jul 21, 2000 Nenad Corbic Added WAN_FT1_READY State | ||
18 | * Feb 24, 2000 Nenad Corbic Added support for socket based x25api | ||
19 | * Jan 28, 2000 Nenad Corbic Added support for the ASYNC protocol. | ||
20 | * Oct 04, 1999 Nenad Corbic Updated for 2.1.0 release | ||
21 | * Jun 02, 1999 Gideon Hack Added support for the S514 adapter. | ||
22 | * May 23, 1999 Arnaldo Melo Added local_addr to wanif_conf_t | ||
23 | * WAN_DISCONNECTING state added | ||
24 | * Jul 20, 1998 David Fong Added Inverse ARP options to 'wanif_conf_t' | ||
25 | * Jun 12, 1998 David Fong Added Cisco HDLC support. | ||
26 | * Dec 16, 1997 Jaspreet Singh Moved 'enable_IPX' and 'network_number' to | ||
27 | * 'wanif_conf_t' | ||
28 | * Dec 05, 1997 Jaspreet Singh Added 'pap', 'chap' to 'wanif_conf_t' | ||
29 | * Added 'authenticator' to 'wan_ppp_conf_t' | ||
30 | * Nov 06, 1997 Jaspreet Singh Changed Router Driver version to 1.1 from 1.0 | ||
31 | * Oct 20, 1997 Jaspreet Singh Added 'cir','bc','be' and 'mc' to 'wanif_conf_t' | ||
32 | * Added 'enable_IPX' and 'network_number' to | ||
33 | * 'wan_device_t'. Also added defines for | ||
34 | * UDP PACKET TYPE, Interrupt test, critical values | ||
35 | * for RACE conditions. | ||
36 | * Oct 05, 1997 Jaspreet Singh Added 'dlci_num' and 'dlci[100]' to | ||
37 | * 'wan_fr_conf_t' to configure a list of dlci(s) | ||
38 | * for a NODE | ||
39 | * Jul 07, 1997 Jaspreet Singh Added 'ttl' to 'wandev_conf_t' & 'wan_device_t' | ||
40 | * May 29, 1997 Jaspreet Singh Added 'tx_int_enabled' to 'wan_device_t' | ||
41 | * May 21, 1997 Jaspreet Singh Added 'udp_port' to 'wan_device_t' | ||
42 | * Apr 25, 1997 Farhan Thawar Added 'udp_port' to 'wandev_conf_t' | ||
43 | * Jan 16, 1997 Gene Kozin router_devlist made public | ||
44 | * Jan 02, 1997 Gene Kozin Initial version (based on wanpipe.h). | ||
45 | *****************************************************************************/ | ||
46 | #ifndef _ROUTER_H | 5 | #ifndef _ROUTER_H |
47 | #define _ROUTER_H | 6 | #define _ROUTER_H |
48 | 7 | ||
49 | #include <uapi/linux/wanrouter.h> | 8 | #include <uapi/linux/wanrouter.h> |
50 | 9 | ||
51 | /****** Kernel Interface ****************************************************/ | ||
52 | |||
53 | #include <linux/fs.h> /* support for device drivers */ | ||
54 | #include <linux/proc_fs.h> /* proc filesystem pragmatics */ | ||
55 | #include <linux/netdevice.h> /* support for network drivers */ | ||
56 | #include <linux/spinlock.h> /* Support for SMP Locking */ | ||
57 | |||
58 | /*---------------------------------------------------------------------------- | ||
59 | * WAN device data space. | ||
60 | */ | ||
61 | struct wan_device { | ||
62 | unsigned magic; /* magic number */ | ||
63 | char* name; /* -> WAN device name (ASCIIZ) */ | ||
64 | void* private; /* -> driver private data */ | ||
65 | unsigned config_id; /* Configuration ID */ | ||
66 | /****** hardware configuration ******/ | ||
67 | unsigned ioport; /* adapter I/O port base #1 */ | ||
68 | char S514_cpu_no[1]; /* PCI CPU Number */ | ||
69 | unsigned char S514_slot_no; /* PCI Slot Number */ | ||
70 | unsigned long maddr; /* dual-port memory address */ | ||
71 | unsigned msize; /* dual-port memory size */ | ||
72 | int irq; /* interrupt request level */ | ||
73 | int dma; /* DMA request level */ | ||
74 | unsigned bps; /* data transfer rate */ | ||
75 | unsigned mtu; /* max physical transmit unit size */ | ||
76 | unsigned udp_port; /* UDP port for management */ | ||
77 | unsigned char ttl; /* Time To Live for UDP security */ | ||
78 | unsigned enable_tx_int; /* Transmit Interrupt enabled or not */ | ||
79 | char interface; /* RS-232/V.35, etc. */ | ||
80 | char clocking; /* external/internal */ | ||
81 | char line_coding; /* NRZ/NRZI/FM0/FM1, etc. */ | ||
82 | char station; /* DTE/DCE, primary/secondary, etc. */ | ||
83 | char connection; /* permanent/switched/on-demand */ | ||
84 | char signalling; /* Signalling RS232 or V35 */ | ||
85 | char read_mode; /* read mode: Polling or interrupt */ | ||
86 | char new_if_cnt; /* Number of interfaces per wanpipe */ | ||
87 | char del_if_cnt; /* Number of times del_if() gets called */ | ||
88 | unsigned char piggyback; /* Piggibacking a port */ | ||
89 | unsigned hw_opt[4]; /* other hardware options */ | ||
90 | /****** status and statistics *******/ | ||
91 | char state; /* device state */ | ||
92 | char api_status; /* device api status */ | ||
93 | struct net_device_stats stats; /* interface statistics */ | ||
94 | unsigned reserved[16]; /* reserved for future use */ | ||
95 | unsigned long critical; /* critical section flag */ | ||
96 | spinlock_t lock; /* Support for SMP Locking */ | ||
97 | |||
98 | /****** device management methods ***/ | ||
99 | int (*setup) (struct wan_device *wandev, wandev_conf_t *conf); | ||
100 | int (*shutdown) (struct wan_device *wandev); | ||
101 | int (*update) (struct wan_device *wandev); | ||
102 | int (*ioctl) (struct wan_device *wandev, unsigned cmd, | ||
103 | unsigned long arg); | ||
104 | int (*new_if)(struct wan_device *wandev, struct net_device *dev, | ||
105 | wanif_conf_t *conf); | ||
106 | int (*del_if)(struct wan_device *wandev, struct net_device *dev); | ||
107 | /****** maintained by the router ****/ | ||
108 | struct wan_device* next; /* -> next device */ | ||
109 | struct net_device* dev; /* list of network interfaces */ | ||
110 | unsigned ndev; /* number of interfaces */ | ||
111 | struct proc_dir_entry *dent; /* proc filesystem entry */ | ||
112 | }; | ||
113 | |||
114 | /* Public functions available for device drivers */ | ||
115 | extern int register_wan_device(struct wan_device *wandev); | ||
116 | extern int unregister_wan_device(char *name); | ||
117 | |||
118 | /* Proc interface functions. These must not be called by the drivers! */ | ||
119 | extern int wanrouter_proc_init(void); | ||
120 | extern void wanrouter_proc_cleanup(void); | ||
121 | extern int wanrouter_proc_add(struct wan_device *wandev); | ||
122 | extern int wanrouter_proc_delete(struct wan_device *wandev); | ||
123 | extern long wanrouter_ioctl(struct file *file, unsigned int cmd, unsigned long arg); | ||
124 | |||
125 | /* Public Data */ | ||
126 | /* list of registered devices */ | ||
127 | extern struct wan_device *wanrouter_router_devlist; | ||
128 | |||
129 | #endif /* _ROUTER_H */ | 10 | #endif /* _ROUTER_H */ |
diff --git a/include/uapi/linux/wanrouter.h b/include/uapi/linux/wanrouter.h index 7617df2833d5..498d6c12c666 100644 --- a/include/uapi/linux/wanrouter.h +++ b/include/uapi/linux/wanrouter.h | |||
@@ -1,363 +1,9 @@ | |||
1 | /***************************************************************************** | ||
2 | * wanrouter.h Definitions for the WAN Multiprotocol Router Module. | ||
3 | * This module provides API and common services for WAN Link | ||
4 | * Drivers and is completely hardware-independent. | ||
5 | * | ||
6 | * Author: Nenad Corbic <ncorbic@sangoma.com> | ||
7 | * Gideon Hack | ||
8 | * Additions: Arnaldo Melo | ||
9 | * | ||
10 | * Copyright: (c) 1995-2000 Sangoma Technologies Inc. | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or | ||
13 | * modify it under the terms of the GNU General Public License | ||
14 | * as published by the Free Software Foundation; either version | ||
15 | * 2 of the License, or (at your option) any later version. | ||
16 | * ============================================================================ | ||
17 | * Jul 21, 2000 Nenad Corbic Added WAN_FT1_READY State | ||
18 | * Feb 24, 2000 Nenad Corbic Added support for socket based x25api | ||
19 | * Jan 28, 2000 Nenad Corbic Added support for the ASYNC protocol. | ||
20 | * Oct 04, 1999 Nenad Corbic Updated for 2.1.0 release | ||
21 | * Jun 02, 1999 Gideon Hack Added support for the S514 adapter. | ||
22 | * May 23, 1999 Arnaldo Melo Added local_addr to wanif_conf_t | ||
23 | * WAN_DISCONNECTING state added | ||
24 | * Jul 20, 1998 David Fong Added Inverse ARP options to 'wanif_conf_t' | ||
25 | * Jun 12, 1998 David Fong Added Cisco HDLC support. | ||
26 | * Dec 16, 1997 Jaspreet Singh Moved 'enable_IPX' and 'network_number' to | ||
27 | * 'wanif_conf_t' | ||
28 | * Dec 05, 1997 Jaspreet Singh Added 'pap', 'chap' to 'wanif_conf_t' | ||
29 | * Added 'authenticator' to 'wan_ppp_conf_t' | ||
30 | * Nov 06, 1997 Jaspreet Singh Changed Router Driver version to 1.1 from 1.0 | ||
31 | * Oct 20, 1997 Jaspreet Singh Added 'cir','bc','be' and 'mc' to 'wanif_conf_t' | ||
32 | * Added 'enable_IPX' and 'network_number' to | ||
33 | * 'wan_device_t'. Also added defines for | ||
34 | * UDP PACKET TYPE, Interrupt test, critical values | ||
35 | * for RACE conditions. | ||
36 | * Oct 05, 1997 Jaspreet Singh Added 'dlci_num' and 'dlci[100]' to | ||
37 | * 'wan_fr_conf_t' to configure a list of dlci(s) | ||
38 | * for a NODE | ||
39 | * Jul 07, 1997 Jaspreet Singh Added 'ttl' to 'wandev_conf_t' & 'wan_device_t' | ||
40 | * May 29, 1997 Jaspreet Singh Added 'tx_int_enabled' to 'wan_device_t' | ||
41 | * May 21, 1997 Jaspreet Singh Added 'udp_port' to 'wan_device_t' | ||
42 | * Apr 25, 1997 Farhan Thawar Added 'udp_port' to 'wandev_conf_t' | ||
43 | * Jan 16, 1997 Gene Kozin router_devlist made public | ||
44 | * Jan 02, 1997 Gene Kozin Initial version (based on wanpipe.h). | ||
45 | *****************************************************************************/ | ||
46 | |||
47 | #ifndef _UAPI_ROUTER_H | ||
48 | #define _UAPI_ROUTER_H | ||
49 | |||
50 | #define ROUTER_NAME "wanrouter" /* in case we ever change it */ | ||
51 | #define ROUTER_VERSION 1 /* version number */ | ||
52 | #define ROUTER_RELEASE 1 /* release (minor version) number */ | ||
53 | #define ROUTER_IOCTL 'W' /* for IOCTL calls */ | ||
54 | #define ROUTER_MAGIC 0x524D4157L /* signature: 'WANR' reversed */ | ||
55 | |||
56 | /* IOCTL codes for /proc/router/<device> entries (up to 255) */ | ||
57 | enum router_ioctls | ||
58 | { | ||
59 | ROUTER_SETUP = ROUTER_IOCTL<<8, /* configure device */ | ||
60 | ROUTER_DOWN, /* shut down device */ | ||
61 | ROUTER_STAT, /* get device status */ | ||
62 | ROUTER_IFNEW, /* add interface */ | ||
63 | ROUTER_IFDEL, /* delete interface */ | ||
64 | ROUTER_IFSTAT, /* get interface status */ | ||
65 | ROUTER_USER = (ROUTER_IOCTL<<8)+16, /* driver-specific calls */ | ||
66 | ROUTER_USER_MAX = (ROUTER_IOCTL<<8)+31 | ||
67 | }; | ||
68 | |||
69 | /* identifiers for displaying proc file data for dual port adapters */ | ||
70 | #define PROC_DATA_PORT_0 0x8000 /* the data is for port 0 */ | ||
71 | #define PROC_DATA_PORT_1 0x8001 /* the data is for port 1 */ | ||
72 | |||
73 | /* NLPID for packet encapsulation (ISO/IEC TR 9577) */ | ||
74 | #define NLPID_IP 0xCC /* Internet Protocol Datagram */ | ||
75 | #define NLPID_SNAP 0x80 /* IEEE Subnetwork Access Protocol */ | ||
76 | #define NLPID_CLNP 0x81 /* ISO/IEC 8473 */ | ||
77 | #define NLPID_ESIS 0x82 /* ISO/IEC 9542 */ | ||
78 | #define NLPID_ISIS 0x83 /* ISO/IEC ISIS */ | ||
79 | #define NLPID_Q933 0x08 /* CCITT Q.933 */ | ||
80 | |||
81 | /* Miscellaneous */ | ||
82 | #define WAN_IFNAME_SZ 15 /* max length of the interface name */ | ||
83 | #define WAN_DRVNAME_SZ 15 /* max length of the link driver name */ | ||
84 | #define WAN_ADDRESS_SZ 31 /* max length of the WAN media address */ | ||
85 | #define USED_BY_FIELD 8 /* max length of the used by field */ | ||
86 | |||
87 | /* Defines for UDP PACKET TYPE */ | ||
88 | #define UDP_PTPIPE_TYPE 0x01 | ||
89 | #define UDP_FPIPE_TYPE 0x02 | ||
90 | #define UDP_CPIPE_TYPE 0x03 | ||
91 | #define UDP_DRVSTATS_TYPE 0x04 | ||
92 | #define UDP_INVALID_TYPE 0x05 | ||
93 | |||
94 | /* Command return code */ | ||
95 | #define CMD_OK 0 /* normal firmware return code */ | ||
96 | #define CMD_TIMEOUT 0xFF /* firmware command timed out */ | ||
97 | |||
98 | /* UDP Packet Management */ | ||
99 | #define UDP_PKT_FRM_STACK 0x00 | ||
100 | #define UDP_PKT_FRM_NETWORK 0x01 | ||
101 | |||
102 | /* Maximum interrupt test counter */ | ||
103 | #define MAX_INTR_TEST_COUNTER 100 | ||
104 | |||
105 | /* Critical Values for RACE conditions*/ | ||
106 | #define CRITICAL_IN_ISR 0xA1 | ||
107 | #define CRITICAL_INTR_HANDLED 0xB1 | ||
108 | |||
109 | /****** Data Types **********************************************************/ | ||
110 | |||
111 | /*---------------------------------------------------------------------------- | ||
112 | * X.25-specific link-level configuration. | ||
113 | */ | ||
114 | typedef struct wan_x25_conf | ||
115 | { | ||
116 | unsigned lo_pvc; /* lowest permanent circuit number */ | ||
117 | unsigned hi_pvc; /* highest permanent circuit number */ | ||
118 | unsigned lo_svc; /* lowest switched circuit number */ | ||
119 | unsigned hi_svc; /* highest switched circuit number */ | ||
120 | unsigned hdlc_window; /* HDLC window size (1..7) */ | ||
121 | unsigned pkt_window; /* X.25 packet window size (1..7) */ | ||
122 | unsigned t1; /* HDLC timer T1, sec (1..30) */ | ||
123 | unsigned t2; /* HDLC timer T2, sec (0..29) */ | ||
124 | unsigned t4; /* HDLC supervisory frame timer = T4 * T1 */ | ||
125 | unsigned n2; /* HDLC retransmission limit (1..30) */ | ||
126 | unsigned t10_t20; /* X.25 RESTART timeout, sec (1..255) */ | ||
127 | unsigned t11_t21; /* X.25 CALL timeout, sec (1..255) */ | ||
128 | unsigned t12_t22; /* X.25 RESET timeout, sec (1..255) */ | ||
129 | unsigned t13_t23; /* X.25 CLEAR timeout, sec (1..255) */ | ||
130 | unsigned t16_t26; /* X.25 INTERRUPT timeout, sec (1..255) */ | ||
131 | unsigned t28; /* X.25 REGISTRATION timeout, sec (1..255) */ | ||
132 | unsigned r10_r20; /* RESTART retransmission limit (0..250) */ | ||
133 | unsigned r12_r22; /* RESET retransmission limit (0..250) */ | ||
134 | unsigned r13_r23; /* CLEAR retransmission limit (0..250) */ | ||
135 | unsigned ccitt_compat; /* compatibility mode: 1988/1984/1980 */ | ||
136 | unsigned x25_conf_opt; /* User defined x25 config optoins */ | ||
137 | unsigned char LAPB_hdlc_only; /* Run in HDLC only mode */ | ||
138 | unsigned char logging; /* Control connection logging */ | ||
139 | unsigned char oob_on_modem; /* Whether to send modem status to the user app */ | ||
140 | } wan_x25_conf_t; | ||
141 | |||
142 | /*---------------------------------------------------------------------------- | ||
143 | * Frame relay specific link-level configuration. | ||
144 | */ | ||
145 | typedef struct wan_fr_conf | ||
146 | { | ||
147 | unsigned signalling; /* local in-channel signalling type */ | ||
148 | unsigned t391; /* link integrity verification timer */ | ||
149 | unsigned t392; /* polling verification timer */ | ||
150 | unsigned n391; /* full status polling cycle counter */ | ||
151 | unsigned n392; /* error threshold counter */ | ||
152 | unsigned n393; /* monitored events counter */ | ||
153 | unsigned dlci_num; /* number of DLCs (access node) */ | ||
154 | unsigned dlci[100]; /* List of all DLCIs */ | ||
155 | } wan_fr_conf_t; | ||
156 | |||
157 | /*---------------------------------------------------------------------------- | ||
158 | * PPP-specific link-level configuration. | ||
159 | */ | ||
160 | typedef struct wan_ppp_conf | ||
161 | { | ||
162 | unsigned restart_tmr; /* restart timer */ | ||
163 | unsigned auth_rsrt_tmr; /* authentication timer */ | ||
164 | unsigned auth_wait_tmr; /* authentication timer */ | ||
165 | unsigned mdm_fail_tmr; /* modem failure timer */ | ||
166 | unsigned dtr_drop_tmr; /* DTR drop timer */ | ||
167 | unsigned connect_tmout; /* connection timeout */ | ||
168 | unsigned conf_retry; /* max. retry */ | ||
169 | unsigned term_retry; /* max. retry */ | ||
170 | unsigned fail_retry; /* max. retry */ | ||
171 | unsigned auth_retry; /* max. retry */ | ||
172 | unsigned auth_options; /* authentication opt. */ | ||
173 | unsigned ip_options; /* IP options */ | ||
174 | char authenticator; /* AUTHENTICATOR or not */ | ||
175 | char ip_mode; /* Static/Host/Peer */ | ||
176 | } wan_ppp_conf_t; | ||
177 | |||
178 | /*---------------------------------------------------------------------------- | ||
179 | * CHDLC-specific link-level configuration. | ||
180 | */ | ||
181 | typedef struct wan_chdlc_conf | ||
182 | { | ||
183 | unsigned char ignore_dcd; /* Protocol options: */ | ||
184 | unsigned char ignore_cts; /* Ignore these to determine */ | ||
185 | unsigned char ignore_keepalive; /* link status (Yes or No) */ | ||
186 | unsigned char hdlc_streaming; /* hdlc_streaming mode (Y/N) */ | ||
187 | unsigned char receive_only; /* no transmit buffering (Y/N) */ | ||
188 | unsigned keepalive_tx_tmr; /* transmit keepalive timer */ | ||
189 | unsigned keepalive_rx_tmr; /* receive keepalive timer */ | ||
190 | unsigned keepalive_err_margin; /* keepalive_error_tolerance */ | ||
191 | unsigned slarp_timer; /* SLARP request timer */ | ||
192 | } wan_chdlc_conf_t; | ||
193 | |||
194 | |||
195 | /*---------------------------------------------------------------------------- | ||
196 | * WAN device configuration. Passed to ROUTER_SETUP IOCTL. | ||
197 | */ | ||
198 | typedef struct wandev_conf | ||
199 | { | ||
200 | unsigned magic; /* magic number (for verification) */ | ||
201 | unsigned config_id; /* configuration structure identifier */ | ||
202 | /****** hardware configuration ******/ | ||
203 | unsigned ioport; /* adapter I/O port base */ | ||
204 | unsigned long maddr; /* dual-port memory address */ | ||
205 | unsigned msize; /* dual-port memory size */ | ||
206 | int irq; /* interrupt request level */ | ||
207 | int dma; /* DMA request level */ | ||
208 | char S514_CPU_no[1]; /* S514 PCI adapter CPU number ('A' or 'B') */ | ||
209 | unsigned PCI_slot_no; /* S514 PCI adapter slot number */ | ||
210 | char auto_pci_cfg; /* S515 PCI automatic slot detection */ | ||
211 | char comm_port; /* Communication Port (PRI=0, SEC=1) */ | ||
212 | unsigned bps; /* data transfer rate */ | ||
213 | unsigned mtu; /* maximum transmit unit size */ | ||
214 | unsigned udp_port; /* UDP port for management */ | ||
215 | unsigned char ttl; /* Time To Live for UDP security */ | ||
216 | unsigned char ft1; /* FT1 Configurator Option */ | ||
217 | char interface; /* RS-232/V.35, etc. */ | ||
218 | char clocking; /* external/internal */ | ||
219 | char line_coding; /* NRZ/NRZI/FM0/FM1, etc. */ | ||
220 | char station; /* DTE/DCE, primary/secondary, etc. */ | ||
221 | char connection; /* permanent/switched/on-demand */ | ||
222 | char read_mode; /* read mode: Polling or interrupt */ | ||
223 | char receive_only; /* disable tx buffers */ | ||
224 | char tty; /* Create a fake tty device */ | ||
225 | unsigned tty_major; /* Major number for wanpipe tty device */ | ||
226 | unsigned tty_minor; /* Minor number for wanpipe tty device */ | ||
227 | unsigned tty_mode; /* TTY operation mode SYNC or ASYNC */ | ||
228 | char backup; /* Backup Mode */ | ||
229 | unsigned hw_opt[4]; /* other hardware options */ | ||
230 | unsigned reserved[4]; | ||
231 | /****** arbitrary data ***************/ | ||
232 | unsigned data_size; /* data buffer size */ | ||
233 | void* data; /* data buffer, e.g. firmware */ | ||
234 | union /****** protocol-specific ************/ | ||
235 | { | ||
236 | wan_x25_conf_t x25; /* X.25 configuration */ | ||
237 | wan_ppp_conf_t ppp; /* PPP configuration */ | ||
238 | wan_fr_conf_t fr; /* frame relay configuration */ | ||
239 | wan_chdlc_conf_t chdlc; /* Cisco HDLC configuration */ | ||
240 | } u; | ||
241 | } wandev_conf_t; | ||
242 | |||
243 | /* 'config_id' definitions */ | ||
244 | #define WANCONFIG_X25 101 /* X.25 link */ | ||
245 | #define WANCONFIG_FR 102 /* frame relay link */ | ||
246 | #define WANCONFIG_PPP 103 /* synchronous PPP link */ | ||
247 | #define WANCONFIG_CHDLC 104 /* Cisco HDLC Link */ | ||
248 | #define WANCONFIG_BSC 105 /* BiSync Streaming */ | ||
249 | #define WANCONFIG_HDLC 106 /* HDLC Support */ | ||
250 | #define WANCONFIG_MPPP 107 /* Multi Port PPP over RAW CHDLC */ | ||
251 | |||
252 | /* | 1 | /* |
253 | * Configuration options defines. | 2 | * wanrouter.h Legacy declarations kept around until X25 is removed |
254 | */ | 3 | */ |
255 | /* general options */ | ||
256 | #define WANOPT_OFF 0 | ||
257 | #define WANOPT_ON 1 | ||
258 | #define WANOPT_NO 0 | ||
259 | #define WANOPT_YES 1 | ||
260 | |||
261 | /* intercace options */ | ||
262 | #define WANOPT_RS232 0 | ||
263 | #define WANOPT_V35 1 | ||
264 | |||
265 | /* data encoding options */ | ||
266 | #define WANOPT_NRZ 0 | ||
267 | #define WANOPT_NRZI 1 | ||
268 | #define WANOPT_FM0 2 | ||
269 | #define WANOPT_FM1 3 | ||
270 | |||
271 | /* link type options */ | ||
272 | #define WANOPT_POINTTOPOINT 0 /* RTS always active */ | ||
273 | #define WANOPT_MULTIDROP 1 /* RTS is active when transmitting */ | ||
274 | |||
275 | /* clocking options */ | ||
276 | #define WANOPT_EXTERNAL 0 | ||
277 | #define WANOPT_INTERNAL 1 | ||
278 | |||
279 | /* station options */ | ||
280 | #define WANOPT_DTE 0 | ||
281 | #define WANOPT_DCE 1 | ||
282 | #define WANOPT_CPE 0 | ||
283 | #define WANOPT_NODE 1 | ||
284 | #define WANOPT_SECONDARY 0 | ||
285 | #define WANOPT_PRIMARY 1 | ||
286 | |||
287 | /* connection options */ | ||
288 | #define WANOPT_PERMANENT 0 /* DTR always active */ | ||
289 | #define WANOPT_SWITCHED 1 /* use DTR to setup link (dial-up) */ | ||
290 | #define WANOPT_ONDEMAND 2 /* activate DTR only before sending */ | ||
291 | |||
292 | /* frame relay in-channel signalling */ | ||
293 | #define WANOPT_FR_ANSI 1 /* ANSI T1.617 Annex D */ | ||
294 | #define WANOPT_FR_Q933 2 /* ITU Q.933A */ | ||
295 | #define WANOPT_FR_LMI 3 /* LMI */ | ||
296 | |||
297 | /* PPP IP Mode Options */ | ||
298 | #define WANOPT_PPP_STATIC 0 | ||
299 | #define WANOPT_PPP_HOST 1 | ||
300 | #define WANOPT_PPP_PEER 2 | ||
301 | |||
302 | /* ASY Mode Options */ | ||
303 | #define WANOPT_ONE 1 | ||
304 | #define WANOPT_TWO 2 | ||
305 | #define WANOPT_ONE_AND_HALF 3 | ||
306 | |||
307 | #define WANOPT_NONE 0 | ||
308 | #define WANOPT_ODD 1 | ||
309 | #define WANOPT_EVEN 2 | ||
310 | |||
311 | /* CHDLC Protocol Options */ | ||
312 | /* DF Commented out for now. | ||
313 | |||
314 | #define WANOPT_CHDLC_NO_DCD IGNORE_DCD_FOR_LINK_STAT | ||
315 | #define WANOPT_CHDLC_NO_CTS IGNORE_CTS_FOR_LINK_STAT | ||
316 | #define WANOPT_CHDLC_NO_KEEPALIVE IGNORE_KPALV_FOR_LINK_STAT | ||
317 | */ | ||
318 | |||
319 | /* Port options */ | ||
320 | #define WANOPT_PRI 0 | ||
321 | #define WANOPT_SEC 1 | ||
322 | /* read mode */ | ||
323 | #define WANOPT_INTR 0 | ||
324 | #define WANOPT_POLL 1 | ||
325 | 4 | ||
326 | 5 | #ifndef _UAPI_ROUTER_H | |
327 | #define WANOPT_TTY_SYNC 0 | 6 | #define _UAPI_ROUTER_H |
328 | #define WANOPT_TTY_ASYNC 1 | ||
329 | /*---------------------------------------------------------------------------- | ||
330 | * WAN Link Status Info (for ROUTER_STAT IOCTL). | ||
331 | */ | ||
332 | typedef struct wandev_stat | ||
333 | { | ||
334 | unsigned state; /* link state */ | ||
335 | unsigned ndev; /* number of configured interfaces */ | ||
336 | |||
337 | /* link/interface configuration */ | ||
338 | unsigned connection; /* permanent/switched/on-demand */ | ||
339 | unsigned media_type; /* Frame relay/PPP/X.25/SDLC, etc. */ | ||
340 | unsigned mtu; /* max. transmit unit for this device */ | ||
341 | |||
342 | /* physical level statistics */ | ||
343 | unsigned modem_status; /* modem status */ | ||
344 | unsigned rx_frames; /* received frames count */ | ||
345 | unsigned rx_overruns; /* receiver overrun error count */ | ||
346 | unsigned rx_crc_err; /* receive CRC error count */ | ||
347 | unsigned rx_aborts; /* received aborted frames count */ | ||
348 | unsigned rx_bad_length; /* unexpetedly long/short frames count */ | ||
349 | unsigned rx_dropped; /* frames discarded at device level */ | ||
350 | unsigned tx_frames; /* transmitted frames count */ | ||
351 | unsigned tx_underruns; /* aborted transmissions (underruns) count */ | ||
352 | unsigned tx_timeouts; /* transmission timeouts */ | ||
353 | unsigned tx_rejects; /* other transmit errors */ | ||
354 | |||
355 | /* media level statistics */ | ||
356 | unsigned rx_bad_format; /* frames with invalid format */ | ||
357 | unsigned rx_bad_addr; /* frames with invalid media address */ | ||
358 | unsigned tx_retries; /* frames re-transmitted */ | ||
359 | unsigned reserved[16]; /* reserved for future use */ | ||
360 | } wandev_stat_t; | ||
361 | 7 | ||
362 | /* 'state' defines */ | 8 | /* 'state' defines */ |
363 | enum wan_states | 9 | enum wan_states |
@@ -365,88 +11,7 @@ enum wan_states | |||
365 | WAN_UNCONFIGURED, /* link/channel is not configured */ | 11 | WAN_UNCONFIGURED, /* link/channel is not configured */ |
366 | WAN_DISCONNECTED, /* link/channel is disconnected */ | 12 | WAN_DISCONNECTED, /* link/channel is disconnected */ |
367 | WAN_CONNECTING, /* connection is in progress */ | 13 | WAN_CONNECTING, /* connection is in progress */ |
368 | WAN_CONNECTED, /* link/channel is operational */ | 14 | WAN_CONNECTED /* link/channel is operational */ |
369 | WAN_LIMIT, /* for verification only */ | ||
370 | WAN_DUALPORT, /* for Dual Port cards */ | ||
371 | WAN_DISCONNECTING, | ||
372 | WAN_FT1_READY /* FT1 Configurator Ready */ | ||
373 | }; | 15 | }; |
374 | 16 | ||
375 | enum { | ||
376 | WAN_LOCAL_IP, | ||
377 | WAN_POINTOPOINT_IP, | ||
378 | WAN_NETMASK_IP, | ||
379 | WAN_BROADCAST_IP | ||
380 | }; | ||
381 | |||
382 | /* 'modem_status' masks */ | ||
383 | #define WAN_MODEM_CTS 0x0001 /* CTS line active */ | ||
384 | #define WAN_MODEM_DCD 0x0002 /* DCD line active */ | ||
385 | #define WAN_MODEM_DTR 0x0010 /* DTR line active */ | ||
386 | #define WAN_MODEM_RTS 0x0020 /* RTS line active */ | ||
387 | |||
388 | /*---------------------------------------------------------------------------- | ||
389 | * WAN interface (logical channel) configuration (for ROUTER_IFNEW IOCTL). | ||
390 | */ | ||
391 | typedef struct wanif_conf | ||
392 | { | ||
393 | unsigned magic; /* magic number */ | ||
394 | unsigned config_id; /* configuration identifier */ | ||
395 | char name[WAN_IFNAME_SZ+1]; /* interface name, ASCIIZ */ | ||
396 | char addr[WAN_ADDRESS_SZ+1]; /* media address, ASCIIZ */ | ||
397 | char usedby[USED_BY_FIELD]; /* used by API or WANPIPE */ | ||
398 | unsigned idle_timeout; /* sec, before disconnecting */ | ||
399 | unsigned hold_timeout; /* sec, before re-connecting */ | ||
400 | unsigned cir; /* Committed Information Rate fwd,bwd*/ | ||
401 | unsigned bc; /* Committed Burst Size fwd, bwd */ | ||
402 | unsigned be; /* Excess Burst Size fwd, bwd */ | ||
403 | unsigned char enable_IPX; /* Enable or Disable IPX */ | ||
404 | unsigned char inarp; /* Send Inverse ARP requests Y/N */ | ||
405 | unsigned inarp_interval; /* sec, between InARP requests */ | ||
406 | unsigned long network_number; /* Network Number for IPX */ | ||
407 | char mc; /* Multicast on or off */ | ||
408 | char local_addr[WAN_ADDRESS_SZ+1];/* local media address, ASCIIZ */ | ||
409 | unsigned char port; /* board port */ | ||
410 | unsigned char protocol; /* prococol used in this channel (TCPOX25 or X25) */ | ||
411 | char pap; /* PAP enabled or disabled */ | ||
412 | char chap; /* CHAP enabled or disabled */ | ||
413 | unsigned char userid[511]; /* List of User Id */ | ||
414 | unsigned char passwd[511]; /* List of passwords */ | ||
415 | unsigned char sysname[31]; /* Name of the system */ | ||
416 | unsigned char ignore_dcd; /* Protocol options: */ | ||
417 | unsigned char ignore_cts; /* Ignore these to determine */ | ||
418 | unsigned char ignore_keepalive; /* link status (Yes or No) */ | ||
419 | unsigned char hdlc_streaming; /* Hdlc streaming mode (Y/N) */ | ||
420 | unsigned keepalive_tx_tmr; /* transmit keepalive timer */ | ||
421 | unsigned keepalive_rx_tmr; /* receive keepalive timer */ | ||
422 | unsigned keepalive_err_margin; /* keepalive_error_tolerance */ | ||
423 | unsigned slarp_timer; /* SLARP request timer */ | ||
424 | unsigned char ttl; /* Time To Live for UDP security */ | ||
425 | char interface; /* RS-232/V.35, etc. */ | ||
426 | char clocking; /* external/internal */ | ||
427 | unsigned bps; /* data transfer rate */ | ||
428 | unsigned mtu; /* maximum transmit unit size */ | ||
429 | unsigned char if_down; /* brind down interface when disconnected */ | ||
430 | unsigned char gateway; /* Is this interface a gateway */ | ||
431 | unsigned char true_if_encoding; /* Set the dev->type to true board protocol */ | ||
432 | |||
433 | unsigned char asy_data_trans; /* async API options */ | ||
434 | unsigned char rts_hs_for_receive; /* async Protocol options */ | ||
435 | unsigned char xon_xoff_hs_for_receive; | ||
436 | unsigned char xon_xoff_hs_for_transmit; | ||
437 | unsigned char dcd_hs_for_transmit; | ||
438 | unsigned char cts_hs_for_transmit; | ||
439 | unsigned char async_mode; | ||
440 | unsigned tx_bits_per_char; | ||
441 | unsigned rx_bits_per_char; | ||
442 | unsigned stop_bits; | ||
443 | unsigned char parity; | ||
444 | unsigned break_timer; | ||
445 | unsigned inter_char_timer; | ||
446 | unsigned rx_complete_length; | ||
447 | unsigned xon_char; | ||
448 | unsigned xoff_char; | ||
449 | unsigned char receive_only; /* no transmit buffering (Y/N) */ | ||
450 | } wanif_conf_t; | ||
451 | |||
452 | #endif /* _UAPI_ROUTER_H */ | 17 | #endif /* _UAPI_ROUTER_H */ |
diff --git a/net/wanrouter/Kconfig b/net/wanrouter/Kconfig deleted file mode 100644 index a157a2e64e18..000000000000 --- a/net/wanrouter/Kconfig +++ /dev/null | |||
@@ -1,27 +0,0 @@ | |||
1 | # | ||
2 | # Configuration for WAN router | ||
3 | # | ||
4 | |||
5 | config WAN_ROUTER | ||
6 | tristate "WAN router (DEPRECATED)" | ||
7 | depends on EXPERIMENTAL | ||
8 | ---help--- | ||
9 | Wide Area Networks (WANs), such as X.25, frame relay and leased | ||
10 | lines, are used to interconnect Local Area Networks (LANs) over vast | ||
11 | distances with data transfer rates significantly higher than those | ||
12 | achievable with commonly used asynchronous modem connections. | ||
13 | Usually, a quite expensive external device called a `WAN router' is | ||
14 | needed to connect to a WAN. | ||
15 | |||
16 | As an alternative, WAN routing can be built into the Linux kernel. | ||
17 | With relatively inexpensive WAN interface cards available on the | ||
18 | market, a perfectly usable router can be built for less than half | ||
19 | the price of an external router. If you have one of those cards and | ||
20 | wish to use your Linux box as a WAN router, say Y here and also to | ||
21 | the WAN driver for your card, below. You will then need the | ||
22 | wan-tools package which is available from <ftp://ftp.sangoma.com/>. | ||
23 | |||
24 | To compile WAN routing support as a module, choose M here: the | ||
25 | module will be called wanrouter. | ||
26 | |||
27 | If unsure, say N. | ||
diff --git a/net/wanrouter/Makefile b/net/wanrouter/Makefile deleted file mode 100644 index 4da14bc48078..000000000000 --- a/net/wanrouter/Makefile +++ /dev/null | |||
@@ -1,7 +0,0 @@ | |||
1 | # | ||
2 | # Makefile for the Linux WAN router layer. | ||
3 | # | ||
4 | |||
5 | obj-$(CONFIG_WAN_ROUTER) += wanrouter.o | ||
6 | |||
7 | wanrouter-y := wanproc.o wanmain.o | ||
diff --git a/net/wanrouter/patchlevel b/net/wanrouter/patchlevel deleted file mode 100644 index c043eea7767e..000000000000 --- a/net/wanrouter/patchlevel +++ /dev/null | |||
@@ -1 +0,0 @@ | |||
1 | 2.2.1 | ||
diff --git a/net/wanrouter/wanmain.c b/net/wanrouter/wanmain.c deleted file mode 100644 index 2ab785064b7e..000000000000 --- a/net/wanrouter/wanmain.c +++ /dev/null | |||
@@ -1,782 +0,0 @@ | |||
1 | /***************************************************************************** | ||
2 | * wanmain.c WAN Multiprotocol Router Module. Main code. | ||
3 | * | ||
4 | * This module is completely hardware-independent and provides | ||
5 | * the following common services for the WAN Link Drivers: | ||
6 | * o WAN device management (registering, unregistering) | ||
7 | * o Network interface management | ||
8 | * o Physical connection management (dial-up, incoming calls) | ||
9 | * o Logical connection management (switched virtual circuits) | ||
10 | * o Protocol encapsulation/decapsulation | ||
11 | * | ||
12 | * Author: Gideon Hack | ||
13 | * | ||
14 | * Copyright: (c) 1995-1999 Sangoma Technologies Inc. | ||
15 | * | ||
16 | * This program is free software; you can redistribute it and/or | ||
17 | * modify it under the terms of the GNU General Public License | ||
18 | * as published by the Free Software Foundation; either version | ||
19 | * 2 of the License, or (at your option) any later version. | ||
20 | * ============================================================================ | ||
21 | * Nov 24, 2000 Nenad Corbic Updated for 2.4.X kernels | ||
22 | * Nov 07, 2000 Nenad Corbic Fixed the Mulit-Port PPP for kernels 2.2.16 and | ||
23 | * greater. | ||
24 | * Aug 2, 2000 Nenad Corbic Block the Multi-Port PPP from running on | ||
25 | * kernels 2.2.16 or greater. The SyncPPP | ||
26 | * has changed. | ||
27 | * Jul 13, 2000 Nenad Corbic Added SyncPPP support | ||
28 | * Added extra debugging in device_setup(). | ||
29 | * Oct 01, 1999 Gideon Hack Update for s514 PCI card | ||
30 | * Dec 27, 1996 Gene Kozin Initial version (based on Sangoma's WANPIPE) | ||
31 | * Jan 16, 1997 Gene Kozin router_devlist made public | ||
32 | * Jan 31, 1997 Alan Cox Hacked it about a bit for 2.1 | ||
33 | * Jun 27, 1997 Alan Cox realigned with vendor code | ||
34 | * Oct 15, 1997 Farhan Thawar changed wan_encapsulate to add a pad byte of 0 | ||
35 | * Apr 20, 1998 Alan Cox Fixed 2.1 symbols | ||
36 | * May 17, 1998 K. Baranowski Fixed SNAP encapsulation in wan_encapsulate | ||
37 | * Dec 15, 1998 Arnaldo Melo support for firmwares of up to 128000 bytes | ||
38 | * check wandev->setup return value | ||
39 | * Dec 22, 1998 Arnaldo Melo vmalloc/vfree used in device_setup to allocate | ||
40 | * kernel memory and copy configuration data to | ||
41 | * kernel space (for big firmwares) | ||
42 | * Jun 02, 1999 Gideon Hack Updates for Linux 2.0.X and 2.2.X kernels. | ||
43 | *****************************************************************************/ | ||
44 | |||
45 | #include <linux/stddef.h> /* offsetof(), etc. */ | ||
46 | #include <linux/capability.h> | ||
47 | #include <linux/errno.h> /* return codes */ | ||
48 | #include <linux/kernel.h> | ||
49 | #include <linux/module.h> /* support for loadable modules */ | ||
50 | #include <linux/slab.h> /* kmalloc(), kfree() */ | ||
51 | #include <linux/mutex.h> | ||
52 | #include <linux/mm.h> | ||
53 | #include <linux/string.h> /* inline mem*, str* functions */ | ||
54 | |||
55 | #include <asm/byteorder.h> /* htons(), etc. */ | ||
56 | #include <linux/wanrouter.h> /* WAN router API definitions */ | ||
57 | |||
58 | #include <linux/vmalloc.h> /* vmalloc, vfree */ | ||
59 | #include <asm/uaccess.h> /* copy_to/from_user */ | ||
60 | #include <linux/init.h> /* __initfunc et al. */ | ||
61 | |||
62 | #define DEV_TO_SLAVE(dev) (*((struct net_device **)netdev_priv(dev))) | ||
63 | |||
64 | /* | ||
65 | * Function Prototypes | ||
66 | */ | ||
67 | |||
68 | /* | ||
69 | * WAN device IOCTL handlers | ||
70 | */ | ||
71 | |||
72 | static DEFINE_MUTEX(wanrouter_mutex); | ||
73 | static int wanrouter_device_setup(struct wan_device *wandev, | ||
74 | wandev_conf_t __user *u_conf); | ||
75 | static int wanrouter_device_stat(struct wan_device *wandev, | ||
76 | wandev_stat_t __user *u_stat); | ||
77 | static int wanrouter_device_shutdown(struct wan_device *wandev); | ||
78 | static int wanrouter_device_new_if(struct wan_device *wandev, | ||
79 | wanif_conf_t __user *u_conf); | ||
80 | static int wanrouter_device_del_if(struct wan_device *wandev, | ||
81 | char __user *u_name); | ||
82 | |||
83 | /* | ||
84 | * Miscellaneous | ||
85 | */ | ||
86 | |||
87 | static struct wan_device *wanrouter_find_device(char *name); | ||
88 | static int wanrouter_delete_interface(struct wan_device *wandev, char *name); | ||
89 | static void lock_adapter_irq(spinlock_t *lock, unsigned long *smp_flags) | ||
90 | __acquires(lock); | ||
91 | static void unlock_adapter_irq(spinlock_t *lock, unsigned long *smp_flags) | ||
92 | __releases(lock); | ||
93 | |||
94 | |||
95 | |||
96 | /* | ||
97 | * Global Data | ||
98 | */ | ||
99 | |||
100 | static char wanrouter_fullname[] = "Sangoma WANPIPE Router"; | ||
101 | static char wanrouter_copyright[] = "(c) 1995-2000 Sangoma Technologies Inc."; | ||
102 | static char wanrouter_modname[] = ROUTER_NAME; /* short module name */ | ||
103 | struct wan_device* wanrouter_router_devlist; /* list of registered devices */ | ||
104 | |||
105 | /* | ||
106 | * Organize Unique Identifiers for encapsulation/decapsulation | ||
107 | */ | ||
108 | |||
109 | #if 0 | ||
110 | static unsigned char wanrouter_oui_ether[] = { 0x00, 0x00, 0x00 }; | ||
111 | static unsigned char wanrouter_oui_802_2[] = { 0x00, 0x80, 0xC2 }; | ||
112 | #endif | ||
113 | |||
114 | static int __init wanrouter_init(void) | ||
115 | { | ||
116 | int err; | ||
117 | |||
118 | printk(KERN_INFO "%s v%u.%u %s\n", | ||
119 | wanrouter_fullname, ROUTER_VERSION, ROUTER_RELEASE, | ||
120 | wanrouter_copyright); | ||
121 | |||
122 | err = wanrouter_proc_init(); | ||
123 | if (err) | ||
124 | printk(KERN_INFO "%s: can't create entry in proc filesystem!\n", | ||
125 | wanrouter_modname); | ||
126 | |||
127 | return err; | ||
128 | } | ||
129 | |||
130 | static void __exit wanrouter_cleanup (void) | ||
131 | { | ||
132 | wanrouter_proc_cleanup(); | ||
133 | } | ||
134 | |||
135 | /* | ||
136 | * This is just plain dumb. We should move the bugger to drivers/net/wan, | ||
137 | * slap it first in directory and make it module_init(). The only reason | ||
138 | * for subsys_initcall() here is that net goes after drivers (why, BTW?) | ||
139 | */ | ||
140 | subsys_initcall(wanrouter_init); | ||
141 | module_exit(wanrouter_cleanup); | ||
142 | |||
143 | /* | ||
144 | * Kernel APIs | ||
145 | */ | ||
146 | |||
147 | /* | ||
148 | * Register WAN device. | ||
149 | * o verify device credentials | ||
150 | * o create an entry for the device in the /proc/net/router directory | ||
151 | * o initialize internally maintained fields of the wan_device structure | ||
152 | * o link device data space to a singly-linked list | ||
153 | * o if it's the first device, then start kernel 'thread' | ||
154 | * o increment module use count | ||
155 | * | ||
156 | * Return: | ||
157 | * 0 Ok | ||
158 | * < 0 error. | ||
159 | * | ||
160 | * Context: process | ||
161 | */ | ||
162 | |||
163 | |||
164 | int register_wan_device(struct wan_device *wandev) | ||
165 | { | ||
166 | int err, namelen; | ||
167 | |||
168 | if ((wandev == NULL) || (wandev->magic != ROUTER_MAGIC) || | ||
169 | (wandev->name == NULL)) | ||
170 | return -EINVAL; | ||
171 | |||
172 | namelen = strlen(wandev->name); | ||
173 | if (!namelen || (namelen > WAN_DRVNAME_SZ)) | ||
174 | return -EINVAL; | ||
175 | |||
176 | if (wanrouter_find_device(wandev->name)) | ||
177 | return -EEXIST; | ||
178 | |||
179 | #ifdef WANDEBUG | ||
180 | printk(KERN_INFO "%s: registering WAN device %s\n", | ||
181 | wanrouter_modname, wandev->name); | ||
182 | #endif | ||
183 | |||
184 | /* | ||
185 | * Register /proc directory entry | ||
186 | */ | ||
187 | err = wanrouter_proc_add(wandev); | ||
188 | if (err) { | ||
189 | printk(KERN_INFO | ||
190 | "%s: can't create /proc/net/router/%s entry!\n", | ||
191 | wanrouter_modname, wandev->name); | ||
192 | return err; | ||
193 | } | ||
194 | |||
195 | /* | ||
196 | * Initialize fields of the wan_device structure maintained by the | ||
197 | * router and update local data. | ||
198 | */ | ||
199 | |||
200 | wandev->ndev = 0; | ||
201 | wandev->dev = NULL; | ||
202 | wandev->next = wanrouter_router_devlist; | ||
203 | wanrouter_router_devlist = wandev; | ||
204 | return 0; | ||
205 | } | ||
206 | |||
207 | /* | ||
208 | * Unregister WAN device. | ||
209 | * o shut down device | ||
210 | * o unlink device data space from the linked list | ||
211 | * o delete device entry in the /proc/net/router directory | ||
212 | * o decrement module use count | ||
213 | * | ||
214 | * Return: 0 Ok | ||
215 | * <0 error. | ||
216 | * Context: process | ||
217 | */ | ||
218 | |||
219 | |||
220 | int unregister_wan_device(char *name) | ||
221 | { | ||
222 | struct wan_device *wandev, *prev; | ||
223 | |||
224 | if (name == NULL) | ||
225 | return -EINVAL; | ||
226 | |||
227 | for (wandev = wanrouter_router_devlist, prev = NULL; | ||
228 | wandev && strcmp(wandev->name, name); | ||
229 | prev = wandev, wandev = wandev->next) | ||
230 | ; | ||
231 | if (wandev == NULL) | ||
232 | return -ENODEV; | ||
233 | |||
234 | #ifdef WANDEBUG | ||
235 | printk(KERN_INFO "%s: unregistering WAN device %s\n", | ||
236 | wanrouter_modname, name); | ||
237 | #endif | ||
238 | |||
239 | if (wandev->state != WAN_UNCONFIGURED) | ||
240 | wanrouter_device_shutdown(wandev); | ||
241 | |||
242 | if (prev) | ||
243 | prev->next = wandev->next; | ||
244 | else | ||
245 | wanrouter_router_devlist = wandev->next; | ||
246 | |||
247 | wanrouter_proc_delete(wandev); | ||
248 | return 0; | ||
249 | } | ||
250 | |||
251 | #if 0 | ||
252 | |||
253 | /* | ||
254 | * Encapsulate packet. | ||
255 | * | ||
256 | * Return: encapsulation header size | ||
257 | * < 0 - unsupported Ethertype | ||
258 | * | ||
259 | * Notes: | ||
260 | * 1. This function may be called on interrupt context. | ||
261 | */ | ||
262 | |||
263 | |||
264 | int wanrouter_encapsulate(struct sk_buff *skb, struct net_device *dev, | ||
265 | unsigned short type) | ||
266 | { | ||
267 | int hdr_len = 0; | ||
268 | |||
269 | switch (type) { | ||
270 | case ETH_P_IP: /* IP datagram encapsulation */ | ||
271 | hdr_len += 1; | ||
272 | skb_push(skb, 1); | ||
273 | skb->data[0] = NLPID_IP; | ||
274 | break; | ||
275 | |||
276 | case ETH_P_IPX: /* SNAP encapsulation */ | ||
277 | case ETH_P_ARP: | ||
278 | hdr_len += 7; | ||
279 | skb_push(skb, 7); | ||
280 | skb->data[0] = 0; | ||
281 | skb->data[1] = NLPID_SNAP; | ||
282 | skb_copy_to_linear_data_offset(skb, 2, wanrouter_oui_ether, | ||
283 | sizeof(wanrouter_oui_ether)); | ||
284 | *((unsigned short*)&skb->data[5]) = htons(type); | ||
285 | break; | ||
286 | |||
287 | default: /* Unknown packet type */ | ||
288 | printk(KERN_INFO | ||
289 | "%s: unsupported Ethertype 0x%04X on interface %s!\n", | ||
290 | wanrouter_modname, type, dev->name); | ||
291 | hdr_len = -EINVAL; | ||
292 | } | ||
293 | return hdr_len; | ||
294 | } | ||
295 | |||
296 | |||
297 | /* | ||
298 | * Decapsulate packet. | ||
299 | * | ||
300 | * Return: Ethertype (in network order) | ||
301 | * 0 unknown encapsulation | ||
302 | * | ||
303 | * Notes: | ||
304 | * 1. This function may be called on interrupt context. | ||
305 | */ | ||
306 | |||
307 | |||
308 | __be16 wanrouter_type_trans(struct sk_buff *skb, struct net_device *dev) | ||
309 | { | ||
310 | int cnt = skb->data[0] ? 0 : 1; /* there may be a pad present */ | ||
311 | __be16 ethertype; | ||
312 | |||
313 | switch (skb->data[cnt]) { | ||
314 | case NLPID_IP: /* IP datagramm */ | ||
315 | ethertype = htons(ETH_P_IP); | ||
316 | cnt += 1; | ||
317 | break; | ||
318 | |||
319 | case NLPID_SNAP: /* SNAP encapsulation */ | ||
320 | if (memcmp(&skb->data[cnt + 1], wanrouter_oui_ether, | ||
321 | sizeof(wanrouter_oui_ether))){ | ||
322 | printk(KERN_INFO | ||
323 | "%s: unsupported SNAP OUI %02X-%02X-%02X " | ||
324 | "on interface %s!\n", wanrouter_modname, | ||
325 | skb->data[cnt+1], skb->data[cnt+2], | ||
326 | skb->data[cnt+3], dev->name); | ||
327 | return 0; | ||
328 | } | ||
329 | ethertype = *((__be16*)&skb->data[cnt+4]); | ||
330 | cnt += 6; | ||
331 | break; | ||
332 | |||
333 | /* add other protocols, e.g. CLNP, ESIS, ISIS, if needed */ | ||
334 | |||
335 | default: | ||
336 | printk(KERN_INFO | ||
337 | "%s: unsupported NLPID 0x%02X on interface %s!\n", | ||
338 | wanrouter_modname, skb->data[cnt], dev->name); | ||
339 | return 0; | ||
340 | } | ||
341 | skb->protocol = ethertype; | ||
342 | skb->pkt_type = PACKET_HOST; /* Physically point to point */ | ||
343 | skb_pull(skb, cnt); | ||
344 | skb_reset_mac_header(skb); | ||
345 | return ethertype; | ||
346 | } | ||
347 | |||
348 | #endif /* 0 */ | ||
349 | |||
350 | /* | ||
351 | * WAN device IOCTL. | ||
352 | * o find WAN device associated with this node | ||
353 | * o execute requested action or pass command to the device driver | ||
354 | */ | ||
355 | |||
356 | long wanrouter_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | ||
357 | { | ||
358 | struct inode *inode = file->f_path.dentry->d_inode; | ||
359 | int err = 0; | ||
360 | struct proc_dir_entry *dent; | ||
361 | struct wan_device *wandev; | ||
362 | void __user *data = (void __user *)arg; | ||
363 | |||
364 | if (!capable(CAP_NET_ADMIN)) | ||
365 | return -EPERM; | ||
366 | |||
367 | if ((cmd >> 8) != ROUTER_IOCTL) | ||
368 | return -EINVAL; | ||
369 | |||
370 | dent = PDE(inode); | ||
371 | if ((dent == NULL) || (dent->data == NULL)) | ||
372 | return -EINVAL; | ||
373 | |||
374 | wandev = dent->data; | ||
375 | if (wandev->magic != ROUTER_MAGIC) | ||
376 | return -EINVAL; | ||
377 | |||
378 | mutex_lock(&wanrouter_mutex); | ||
379 | switch (cmd) { | ||
380 | case ROUTER_SETUP: | ||
381 | err = wanrouter_device_setup(wandev, data); | ||
382 | break; | ||
383 | |||
384 | case ROUTER_DOWN: | ||
385 | err = wanrouter_device_shutdown(wandev); | ||
386 | break; | ||
387 | |||
388 | case ROUTER_STAT: | ||
389 | err = wanrouter_device_stat(wandev, data); | ||
390 | break; | ||
391 | |||
392 | case ROUTER_IFNEW: | ||
393 | err = wanrouter_device_new_if(wandev, data); | ||
394 | break; | ||
395 | |||
396 | case ROUTER_IFDEL: | ||
397 | err = wanrouter_device_del_if(wandev, data); | ||
398 | break; | ||
399 | |||
400 | case ROUTER_IFSTAT: | ||
401 | break; | ||
402 | |||
403 | default: | ||
404 | if ((cmd >= ROUTER_USER) && | ||
405 | (cmd <= ROUTER_USER_MAX) && | ||
406 | wandev->ioctl) | ||
407 | err = wandev->ioctl(wandev, cmd, arg); | ||
408 | else err = -EINVAL; | ||
409 | } | ||
410 | mutex_unlock(&wanrouter_mutex); | ||
411 | return err; | ||
412 | } | ||
413 | |||
414 | /* | ||
415 | * WAN Driver IOCTL Handlers | ||
416 | */ | ||
417 | |||
418 | /* | ||
419 | * Setup WAN link device. | ||
420 | * o verify user address space | ||
421 | * o allocate kernel memory and copy configuration data to kernel space | ||
422 | * o if configuration data includes extension, copy it to kernel space too | ||
423 | * o call driver's setup() entry point | ||
424 | */ | ||
425 | |||
426 | static int wanrouter_device_setup(struct wan_device *wandev, | ||
427 | wandev_conf_t __user *u_conf) | ||
428 | { | ||
429 | void *data = NULL; | ||
430 | wandev_conf_t *conf; | ||
431 | int err = -EINVAL; | ||
432 | |||
433 | if (wandev->setup == NULL) { /* Nothing to do ? */ | ||
434 | printk(KERN_INFO "%s: ERROR, No setup script: wandev->setup()\n", | ||
435 | wandev->name); | ||
436 | return 0; | ||
437 | } | ||
438 | |||
439 | conf = kmalloc(sizeof(wandev_conf_t), GFP_KERNEL); | ||
440 | if (conf == NULL){ | ||
441 | printk(KERN_INFO "%s: ERROR, Failed to allocate kernel memory !\n", | ||
442 | wandev->name); | ||
443 | return -ENOBUFS; | ||
444 | } | ||
445 | |||
446 | if (copy_from_user(conf, u_conf, sizeof(wandev_conf_t))) { | ||
447 | printk(KERN_INFO "%s: Failed to copy user config data to kernel space!\n", | ||
448 | wandev->name); | ||
449 | kfree(conf); | ||
450 | return -EFAULT; | ||
451 | } | ||
452 | |||
453 | if (conf->magic != ROUTER_MAGIC) { | ||
454 | kfree(conf); | ||
455 | printk(KERN_INFO "%s: ERROR, Invalid MAGIC Number\n", | ||
456 | wandev->name); | ||
457 | return -EINVAL; | ||
458 | } | ||
459 | |||
460 | if (conf->data_size && conf->data) { | ||
461 | if (conf->data_size > 128000) { | ||
462 | printk(KERN_INFO | ||
463 | "%s: ERROR, Invalid firmware data size %i !\n", | ||
464 | wandev->name, conf->data_size); | ||
465 | kfree(conf); | ||
466 | return -EINVAL; | ||
467 | } | ||
468 | |||
469 | data = vmalloc(conf->data_size); | ||
470 | if (!data) { | ||
471 | printk(KERN_INFO | ||
472 | "%s: ERROR, Failed allocate kernel memory !\n", | ||
473 | wandev->name); | ||
474 | kfree(conf); | ||
475 | return -ENOBUFS; | ||
476 | } | ||
477 | if (!copy_from_user(data, conf->data, conf->data_size)) { | ||
478 | conf->data = data; | ||
479 | err = wandev->setup(wandev, conf); | ||
480 | } else { | ||
481 | printk(KERN_INFO | ||
482 | "%s: ERROR, Failed to copy from user data !\n", | ||
483 | wandev->name); | ||
484 | err = -EFAULT; | ||
485 | } | ||
486 | vfree(data); | ||
487 | } else { | ||
488 | printk(KERN_INFO | ||
489 | "%s: ERROR, No firmware found ! Firmware size = %i !\n", | ||
490 | wandev->name, conf->data_size); | ||
491 | } | ||
492 | |||
493 | kfree(conf); | ||
494 | return err; | ||
495 | } | ||
496 | |||
497 | /* | ||
498 | * Shutdown WAN device. | ||
499 | * o delete all not opened logical channels for this device | ||
500 | * o call driver's shutdown() entry point | ||
501 | */ | ||
502 | |||
503 | static int wanrouter_device_shutdown(struct wan_device *wandev) | ||
504 | { | ||
505 | struct net_device *dev; | ||
506 | int err=0; | ||
507 | |||
508 | if (wandev->state == WAN_UNCONFIGURED) | ||
509 | return 0; | ||
510 | |||
511 | printk(KERN_INFO "\n%s: Shutting Down!\n",wandev->name); | ||
512 | |||
513 | for (dev = wandev->dev; dev;) { | ||
514 | err = wanrouter_delete_interface(wandev, dev->name); | ||
515 | if (err) | ||
516 | return err; | ||
517 | /* The above function deallocates the current dev | ||
518 | * structure. Therefore, we cannot use netdev_priv(dev) | ||
519 | * as the next element: wandev->dev points to the | ||
520 | * next element */ | ||
521 | dev = wandev->dev; | ||
522 | } | ||
523 | |||
524 | if (wandev->ndev) | ||
525 | return -EBUSY; /* there are opened interfaces */ | ||
526 | |||
527 | if (wandev->shutdown) | ||
528 | err=wandev->shutdown(wandev); | ||
529 | |||
530 | return err; | ||
531 | } | ||
532 | |||
533 | /* | ||
534 | * Get WAN device status & statistics. | ||
535 | */ | ||
536 | |||
537 | static int wanrouter_device_stat(struct wan_device *wandev, | ||
538 | wandev_stat_t __user *u_stat) | ||
539 | { | ||
540 | wandev_stat_t stat; | ||
541 | |||
542 | memset(&stat, 0, sizeof(stat)); | ||
543 | |||
544 | /* Ask device driver to update device statistics */ | ||
545 | if ((wandev->state != WAN_UNCONFIGURED) && wandev->update) | ||
546 | wandev->update(wandev); | ||
547 | |||
548 | /* Fill out structure */ | ||
549 | stat.ndev = wandev->ndev; | ||
550 | stat.state = wandev->state; | ||
551 | |||
552 | if (copy_to_user(u_stat, &stat, sizeof(stat))) | ||
553 | return -EFAULT; | ||
554 | |||
555 | return 0; | ||
556 | } | ||
557 | |||
558 | /* | ||
559 | * Create new WAN interface. | ||
560 | * o verify user address space | ||
561 | * o copy configuration data to kernel address space | ||
562 | * o allocate network interface data space | ||
563 | * o call driver's new_if() entry point | ||
564 | * o make sure there is no interface name conflict | ||
565 | * o register network interface | ||
566 | */ | ||
567 | |||
568 | static int wanrouter_device_new_if(struct wan_device *wandev, | ||
569 | wanif_conf_t __user *u_conf) | ||
570 | { | ||
571 | wanif_conf_t *cnf; | ||
572 | struct net_device *dev = NULL; | ||
573 | int err; | ||
574 | |||
575 | if ((wandev->state == WAN_UNCONFIGURED) || (wandev->new_if == NULL)) | ||
576 | return -ENODEV; | ||
577 | |||
578 | cnf = kmalloc(sizeof(wanif_conf_t), GFP_KERNEL); | ||
579 | if (!cnf) | ||
580 | return -ENOBUFS; | ||
581 | |||
582 | err = -EFAULT; | ||
583 | if (copy_from_user(cnf, u_conf, sizeof(wanif_conf_t))) | ||
584 | goto out; | ||
585 | |||
586 | err = -EINVAL; | ||
587 | if (cnf->magic != ROUTER_MAGIC) | ||
588 | goto out; | ||
589 | |||
590 | if (cnf->config_id == WANCONFIG_MPPP) { | ||
591 | printk(KERN_INFO "%s: Wanpipe Mulit-Port PPP support has not been compiled in!\n", | ||
592 | wandev->name); | ||
593 | err = -EPROTONOSUPPORT; | ||
594 | goto out; | ||
595 | } else { | ||
596 | err = wandev->new_if(wandev, dev, cnf); | ||
597 | } | ||
598 | |||
599 | if (!err) { | ||
600 | /* Register network interface. This will invoke init() | ||
601 | * function supplied by the driver. If device registered | ||
602 | * successfully, add it to the interface list. | ||
603 | */ | ||
604 | |||
605 | #ifdef WANDEBUG | ||
606 | printk(KERN_INFO "%s: registering interface %s...\n", | ||
607 | wanrouter_modname, dev->name); | ||
608 | #endif | ||
609 | |||
610 | err = register_netdev(dev); | ||
611 | if (!err) { | ||
612 | struct net_device *slave = NULL; | ||
613 | unsigned long smp_flags=0; | ||
614 | |||
615 | lock_adapter_irq(&wandev->lock, &smp_flags); | ||
616 | |||
617 | if (wandev->dev == NULL) { | ||
618 | wandev->dev = dev; | ||
619 | } else { | ||
620 | for (slave=wandev->dev; | ||
621 | DEV_TO_SLAVE(slave); | ||
622 | slave = DEV_TO_SLAVE(slave)) | ||
623 | DEV_TO_SLAVE(slave) = dev; | ||
624 | } | ||
625 | ++wandev->ndev; | ||
626 | |||
627 | unlock_adapter_irq(&wandev->lock, &smp_flags); | ||
628 | err = 0; /* done !!! */ | ||
629 | goto out; | ||
630 | } | ||
631 | if (wandev->del_if) | ||
632 | wandev->del_if(wandev, dev); | ||
633 | free_netdev(dev); | ||
634 | } | ||
635 | |||
636 | out: | ||
637 | kfree(cnf); | ||
638 | return err; | ||
639 | } | ||
640 | |||
641 | |||
642 | /* | ||
643 | * Delete WAN logical channel. | ||
644 | * o verify user address space | ||
645 | * o copy configuration data to kernel address space | ||
646 | */ | ||
647 | |||
648 | static int wanrouter_device_del_if(struct wan_device *wandev, char __user *u_name) | ||
649 | { | ||
650 | char name[WAN_IFNAME_SZ + 1]; | ||
651 | int err = 0; | ||
652 | |||
653 | if (wandev->state == WAN_UNCONFIGURED) | ||
654 | return -ENODEV; | ||
655 | |||
656 | memset(name, 0, sizeof(name)); | ||
657 | |||
658 | if (copy_from_user(name, u_name, WAN_IFNAME_SZ)) | ||
659 | return -EFAULT; | ||
660 | |||
661 | err = wanrouter_delete_interface(wandev, name); | ||
662 | if (err) | ||
663 | return err; | ||
664 | |||
665 | /* If last interface being deleted, shutdown card | ||
666 | * This helps with administration at leaf nodes | ||
667 | * (You can tell if the person at the other end of the phone | ||
668 | * has an interface configured) and avoids DoS vulnerabilities | ||
669 | * in binary driver files - this fixes a problem with the current | ||
670 | * Sangoma driver going into strange states when all the network | ||
671 | * interfaces are deleted and the link irrecoverably disconnected. | ||
672 | */ | ||
673 | |||
674 | if (!wandev->ndev && wandev->shutdown) | ||
675 | err = wandev->shutdown(wandev); | ||
676 | |||
677 | return err; | ||
678 | } | ||
679 | |||
680 | /* | ||
681 | * Miscellaneous Functions | ||
682 | */ | ||
683 | |||
684 | /* | ||
685 | * Find WAN device by name. | ||
686 | * Return pointer to the WAN device data space or NULL if device not found. | ||
687 | */ | ||
688 | |||
689 | static struct wan_device *wanrouter_find_device(char *name) | ||
690 | { | ||
691 | struct wan_device *wandev; | ||
692 | |||
693 | for (wandev = wanrouter_router_devlist; | ||
694 | wandev && strcmp(wandev->name, name); | ||
695 | wandev = wandev->next); | ||
696 | return wandev; | ||
697 | } | ||
698 | |||
699 | /* | ||
700 | * Delete WAN logical channel identified by its name. | ||
701 | * o find logical channel by its name | ||
702 | * o call driver's del_if() entry point | ||
703 | * o unregister network interface | ||
704 | * o unlink channel data space from linked list of channels | ||
705 | * o release channel data space | ||
706 | * | ||
707 | * Return: 0 success | ||
708 | * -ENODEV channel not found. | ||
709 | * -EBUSY interface is open | ||
710 | * | ||
711 | * Note: If (force != 0), then device will be destroyed even if interface | ||
712 | * associated with it is open. It's caller's responsibility to make | ||
713 | * sure that opened interfaces are not removed! | ||
714 | */ | ||
715 | |||
716 | static int wanrouter_delete_interface(struct wan_device *wandev, char *name) | ||
717 | { | ||
718 | struct net_device *dev = NULL, *prev = NULL; | ||
719 | unsigned long smp_flags=0; | ||
720 | |||
721 | lock_adapter_irq(&wandev->lock, &smp_flags); | ||
722 | dev = wandev->dev; | ||
723 | prev = NULL; | ||
724 | while (dev && strcmp(name, dev->name)) { | ||
725 | struct net_device **slave = netdev_priv(dev); | ||
726 | prev = dev; | ||
727 | dev = *slave; | ||
728 | } | ||
729 | unlock_adapter_irq(&wandev->lock, &smp_flags); | ||
730 | |||
731 | if (dev == NULL) | ||
732 | return -ENODEV; /* interface not found */ | ||
733 | |||
734 | if (netif_running(dev)) | ||
735 | return -EBUSY; /* interface in use */ | ||
736 | |||
737 | if (wandev->del_if) | ||
738 | wandev->del_if(wandev, dev); | ||
739 | |||
740 | lock_adapter_irq(&wandev->lock, &smp_flags); | ||
741 | if (prev) { | ||
742 | struct net_device **prev_slave = netdev_priv(prev); | ||
743 | struct net_device **slave = netdev_priv(dev); | ||
744 | |||
745 | *prev_slave = *slave; | ||
746 | } else { | ||
747 | struct net_device **slave = netdev_priv(dev); | ||
748 | wandev->dev = *slave; | ||
749 | } | ||
750 | --wandev->ndev; | ||
751 | unlock_adapter_irq(&wandev->lock, &smp_flags); | ||
752 | |||
753 | printk(KERN_INFO "%s: unregistering '%s'\n", wandev->name, dev->name); | ||
754 | |||
755 | unregister_netdev(dev); | ||
756 | |||
757 | free_netdev(dev); | ||
758 | |||
759 | return 0; | ||
760 | } | ||
761 | |||
762 | static void lock_adapter_irq(spinlock_t *lock, unsigned long *smp_flags) | ||
763 | __acquires(lock) | ||
764 | { | ||
765 | spin_lock_irqsave(lock, *smp_flags); | ||
766 | } | ||
767 | |||
768 | |||
769 | static void unlock_adapter_irq(spinlock_t *lock, unsigned long *smp_flags) | ||
770 | __releases(lock) | ||
771 | { | ||
772 | spin_unlock_irqrestore(lock, *smp_flags); | ||
773 | } | ||
774 | |||
775 | EXPORT_SYMBOL(register_wan_device); | ||
776 | EXPORT_SYMBOL(unregister_wan_device); | ||
777 | |||
778 | MODULE_LICENSE("GPL"); | ||
779 | |||
780 | /* | ||
781 | * End | ||
782 | */ | ||
diff --git a/net/wanrouter/wanproc.c b/net/wanrouter/wanproc.c deleted file mode 100644 index c43612ee96bb..000000000000 --- a/net/wanrouter/wanproc.c +++ /dev/null | |||
@@ -1,380 +0,0 @@ | |||
1 | /***************************************************************************** | ||
2 | * wanproc.c WAN Router Module. /proc filesystem interface. | ||
3 | * | ||
4 | * This module is completely hardware-independent and provides | ||
5 | * access to the router using Linux /proc filesystem. | ||
6 | * | ||
7 | * Author: Gideon Hack | ||
8 | * | ||
9 | * Copyright: (c) 1995-1999 Sangoma Technologies Inc. | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or | ||
12 | * modify it under the terms of the GNU General Public License | ||
13 | * as published by the Free Software Foundation; either version | ||
14 | * 2 of the License, or (at your option) any later version. | ||
15 | * ============================================================================ | ||
16 | * Jun 02, 1999 Gideon Hack Updates for Linux 2.2.X kernels. | ||
17 | * Jun 29, 1997 Alan Cox Merged with 1.0.3 vendor code | ||
18 | * Jan 29, 1997 Gene Kozin v1.0.1. Implemented /proc read routines | ||
19 | * Jan 30, 1997 Alan Cox Hacked around for 2.1 | ||
20 | * Dec 13, 1996 Gene Kozin Initial version (based on Sangoma's WANPIPE) | ||
21 | *****************************************************************************/ | ||
22 | |||
23 | #include <linux/init.h> /* __initfunc et al. */ | ||
24 | #include <linux/stddef.h> /* offsetof(), etc. */ | ||
25 | #include <linux/errno.h> /* return codes */ | ||
26 | #include <linux/kernel.h> | ||
27 | #include <linux/module.h> | ||
28 | #include <linux/wanrouter.h> /* WAN router API definitions */ | ||
29 | #include <linux/seq_file.h> | ||
30 | #include <linux/mutex.h> | ||
31 | |||
32 | #include <net/net_namespace.h> | ||
33 | #include <asm/io.h> | ||
34 | |||
35 | #define PROC_STATS_FORMAT "%30s: %12lu\n" | ||
36 | |||
37 | /****** Defines and Macros **************************************************/ | ||
38 | |||
39 | #define PROT_DECODE(prot) ((prot == WANCONFIG_FR) ? " FR" :\ | ||
40 | (prot == WANCONFIG_X25) ? " X25" : \ | ||
41 | (prot == WANCONFIG_PPP) ? " PPP" : \ | ||
42 | (prot == WANCONFIG_CHDLC) ? " CHDLC": \ | ||
43 | (prot == WANCONFIG_MPPP) ? " MPPP" : \ | ||
44 | " Unknown" ) | ||
45 | |||
46 | /****** Function Prototypes *************************************************/ | ||
47 | |||
48 | #ifdef CONFIG_PROC_FS | ||
49 | |||
50 | /* Miscellaneous */ | ||
51 | |||
52 | /* | ||
53 | * Structures for interfacing with the /proc filesystem. | ||
54 | * Router creates its own directory /proc/net/router with the following | ||
55 | * entries: | ||
56 | * config device configuration | ||
57 | * status global device statistics | ||
58 | * <device> entry for each WAN device | ||
59 | */ | ||
60 | |||
61 | /* | ||
62 | * Generic /proc/net/router/<file> file and inode operations | ||
63 | */ | ||
64 | |||
65 | /* | ||
66 | * /proc/net/router | ||
67 | */ | ||
68 | |||
69 | static DEFINE_MUTEX(config_mutex); | ||
70 | static struct proc_dir_entry *proc_router; | ||
71 | |||
72 | /* Strings */ | ||
73 | |||
74 | /* | ||
75 | * Interface functions | ||
76 | */ | ||
77 | |||
78 | /****** Proc filesystem entry points ****************************************/ | ||
79 | |||
80 | /* | ||
81 | * Iterator | ||
82 | */ | ||
83 | static void *r_start(struct seq_file *m, loff_t *pos) | ||
84 | { | ||
85 | struct wan_device *wandev; | ||
86 | loff_t l = *pos; | ||
87 | |||
88 | mutex_lock(&config_mutex); | ||
89 | if (!l--) | ||
90 | return SEQ_START_TOKEN; | ||
91 | for (wandev = wanrouter_router_devlist; l-- && wandev; | ||
92 | wandev = wandev->next) | ||
93 | ; | ||
94 | return wandev; | ||
95 | } | ||
96 | |||
97 | static void *r_next(struct seq_file *m, void *v, loff_t *pos) | ||
98 | { | ||
99 | struct wan_device *wandev = v; | ||
100 | (*pos)++; | ||
101 | return (v == SEQ_START_TOKEN) ? wanrouter_router_devlist : wandev->next; | ||
102 | } | ||
103 | |||
104 | static void r_stop(struct seq_file *m, void *v) | ||
105 | { | ||
106 | mutex_unlock(&config_mutex); | ||
107 | } | ||
108 | |||
109 | static int config_show(struct seq_file *m, void *v) | ||
110 | { | ||
111 | struct wan_device *p = v; | ||
112 | if (v == SEQ_START_TOKEN) { | ||
113 | seq_puts(m, "Device name | port |IRQ|DMA| mem.addr |" | ||
114 | "mem.size|option1|option2|option3|option4\n"); | ||
115 | return 0; | ||
116 | } | ||
117 | if (!p->state) | ||
118 | return 0; | ||
119 | seq_printf(m, "%-15s|0x%-4X|%3u|%3u| 0x%-8lX |0x%-6X|%7u|%7u|%7u|%7u\n", | ||
120 | p->name, p->ioport, p->irq, p->dma, p->maddr, p->msize, | ||
121 | p->hw_opt[0], p->hw_opt[1], p->hw_opt[2], p->hw_opt[3]); | ||
122 | return 0; | ||
123 | } | ||
124 | |||
125 | static int status_show(struct seq_file *m, void *v) | ||
126 | { | ||
127 | struct wan_device *p = v; | ||
128 | if (v == SEQ_START_TOKEN) { | ||
129 | seq_puts(m, "Device name |protocol|station|interface|" | ||
130 | "clocking|baud rate| MTU |ndev|link state\n"); | ||
131 | return 0; | ||
132 | } | ||
133 | if (!p->state) | ||
134 | return 0; | ||
135 | seq_printf(m, "%-15s|%-8s| %-7s| %-9s|%-8s|%9u|%5u|%3u |", | ||
136 | p->name, | ||
137 | PROT_DECODE(p->config_id), | ||
138 | p->config_id == WANCONFIG_FR ? | ||
139 | (p->station ? "Node" : "CPE") : | ||
140 | (p->config_id == WANCONFIG_X25 ? | ||
141 | (p->station ? "DCE" : "DTE") : | ||
142 | ("N/A")), | ||
143 | p->interface ? "V.35" : "RS-232", | ||
144 | p->clocking ? "internal" : "external", | ||
145 | p->bps, | ||
146 | p->mtu, | ||
147 | p->ndev); | ||
148 | |||
149 | switch (p->state) { | ||
150 | case WAN_UNCONFIGURED: | ||
151 | seq_printf(m, "%-12s\n", "unconfigured"); | ||
152 | break; | ||
153 | case WAN_DISCONNECTED: | ||
154 | seq_printf(m, "%-12s\n", "disconnected"); | ||
155 | break; | ||
156 | case WAN_CONNECTING: | ||
157 | seq_printf(m, "%-12s\n", "connecting"); | ||
158 | break; | ||
159 | case WAN_CONNECTED: | ||
160 | seq_printf(m, "%-12s\n", "connected"); | ||
161 | break; | ||
162 | default: | ||
163 | seq_printf(m, "%-12s\n", "invalid"); | ||
164 | break; | ||
165 | } | ||
166 | return 0; | ||
167 | } | ||
168 | |||
169 | static const struct seq_operations config_op = { | ||
170 | .start = r_start, | ||
171 | .next = r_next, | ||
172 | .stop = r_stop, | ||
173 | .show = config_show, | ||
174 | }; | ||
175 | |||
176 | static const struct seq_operations status_op = { | ||
177 | .start = r_start, | ||
178 | .next = r_next, | ||
179 | .stop = r_stop, | ||
180 | .show = status_show, | ||
181 | }; | ||
182 | |||
183 | static int config_open(struct inode *inode, struct file *file) | ||
184 | { | ||
185 | return seq_open(file, &config_op); | ||
186 | } | ||
187 | |||
188 | static int status_open(struct inode *inode, struct file *file) | ||
189 | { | ||
190 | return seq_open(file, &status_op); | ||
191 | } | ||
192 | |||
193 | static const struct file_operations config_fops = { | ||
194 | .owner = THIS_MODULE, | ||
195 | .open = config_open, | ||
196 | .read = seq_read, | ||
197 | .llseek = seq_lseek, | ||
198 | .release = seq_release, | ||
199 | }; | ||
200 | |||
201 | static const struct file_operations status_fops = { | ||
202 | .owner = THIS_MODULE, | ||
203 | .open = status_open, | ||
204 | .read = seq_read, | ||
205 | .llseek = seq_lseek, | ||
206 | .release = seq_release, | ||
207 | }; | ||
208 | |||
209 | static int wandev_show(struct seq_file *m, void *v) | ||
210 | { | ||
211 | struct wan_device *wandev = m->private; | ||
212 | |||
213 | if (wandev->magic != ROUTER_MAGIC) | ||
214 | return 0; | ||
215 | |||
216 | if (!wandev->state) { | ||
217 | seq_puts(m, "device is not configured!\n"); | ||
218 | return 0; | ||
219 | } | ||
220 | |||
221 | /* Update device statistics */ | ||
222 | if (wandev->update) { | ||
223 | int err = wandev->update(wandev); | ||
224 | if (err == -EAGAIN) { | ||
225 | seq_puts(m, "Device is busy!\n"); | ||
226 | return 0; | ||
227 | } | ||
228 | if (err) { | ||
229 | seq_puts(m, "Device is not configured!\n"); | ||
230 | return 0; | ||
231 | } | ||
232 | } | ||
233 | |||
234 | seq_printf(m, PROC_STATS_FORMAT, | ||
235 | "total packets received", wandev->stats.rx_packets); | ||
236 | seq_printf(m, PROC_STATS_FORMAT, | ||
237 | "total packets transmitted", wandev->stats.tx_packets); | ||
238 | seq_printf(m, PROC_STATS_FORMAT, | ||
239 | "total bytes received", wandev->stats.rx_bytes); | ||
240 | seq_printf(m, PROC_STATS_FORMAT, | ||
241 | "total bytes transmitted", wandev->stats.tx_bytes); | ||
242 | seq_printf(m, PROC_STATS_FORMAT, | ||
243 | "bad packets received", wandev->stats.rx_errors); | ||
244 | seq_printf(m, PROC_STATS_FORMAT, | ||
245 | "packet transmit problems", wandev->stats.tx_errors); | ||
246 | seq_printf(m, PROC_STATS_FORMAT, | ||
247 | "received frames dropped", wandev->stats.rx_dropped); | ||
248 | seq_printf(m, PROC_STATS_FORMAT, | ||
249 | "transmit frames dropped", wandev->stats.tx_dropped); | ||
250 | seq_printf(m, PROC_STATS_FORMAT, | ||
251 | "multicast packets received", wandev->stats.multicast); | ||
252 | seq_printf(m, PROC_STATS_FORMAT, | ||
253 | "transmit collisions", wandev->stats.collisions); | ||
254 | seq_printf(m, PROC_STATS_FORMAT, | ||
255 | "receive length errors", wandev->stats.rx_length_errors); | ||
256 | seq_printf(m, PROC_STATS_FORMAT, | ||
257 | "receiver overrun errors", wandev->stats.rx_over_errors); | ||
258 | seq_printf(m, PROC_STATS_FORMAT, | ||
259 | "CRC errors", wandev->stats.rx_crc_errors); | ||
260 | seq_printf(m, PROC_STATS_FORMAT, | ||
261 | "frame format errors (aborts)", wandev->stats.rx_frame_errors); | ||
262 | seq_printf(m, PROC_STATS_FORMAT, | ||
263 | "receiver fifo overrun", wandev->stats.rx_fifo_errors); | ||
264 | seq_printf(m, PROC_STATS_FORMAT, | ||
265 | "receiver missed packet", wandev->stats.rx_missed_errors); | ||
266 | seq_printf(m, PROC_STATS_FORMAT, | ||
267 | "aborted frames transmitted", wandev->stats.tx_aborted_errors); | ||
268 | return 0; | ||
269 | } | ||
270 | |||
271 | static int wandev_open(struct inode *inode, struct file *file) | ||
272 | { | ||
273 | return single_open(file, wandev_show, PDE(inode)->data); | ||
274 | } | ||
275 | |||
276 | static const struct file_operations wandev_fops = { | ||
277 | .owner = THIS_MODULE, | ||
278 | .open = wandev_open, | ||
279 | .read = seq_read, | ||
280 | .llseek = seq_lseek, | ||
281 | .release = single_release, | ||
282 | .unlocked_ioctl = wanrouter_ioctl, | ||
283 | }; | ||
284 | |||
285 | /* | ||
286 | * Initialize router proc interface. | ||
287 | */ | ||
288 | |||
289 | int __init wanrouter_proc_init(void) | ||
290 | { | ||
291 | struct proc_dir_entry *p; | ||
292 | proc_router = proc_mkdir(ROUTER_NAME, init_net.proc_net); | ||
293 | if (!proc_router) | ||
294 | goto fail; | ||
295 | |||
296 | p = proc_create("config", S_IRUGO, proc_router, &config_fops); | ||
297 | if (!p) | ||
298 | goto fail_config; | ||
299 | p = proc_create("status", S_IRUGO, proc_router, &status_fops); | ||
300 | if (!p) | ||
301 | goto fail_stat; | ||
302 | return 0; | ||
303 | fail_stat: | ||
304 | remove_proc_entry("config", proc_router); | ||
305 | fail_config: | ||
306 | remove_proc_entry(ROUTER_NAME, init_net.proc_net); | ||
307 | fail: | ||
308 | return -ENOMEM; | ||
309 | } | ||
310 | |||
311 | /* | ||
312 | * Clean up router proc interface. | ||
313 | */ | ||
314 | |||
315 | void wanrouter_proc_cleanup(void) | ||
316 | { | ||
317 | remove_proc_entry("config", proc_router); | ||
318 | remove_proc_entry("status", proc_router); | ||
319 | remove_proc_entry(ROUTER_NAME, init_net.proc_net); | ||
320 | } | ||
321 | |||
322 | /* | ||
323 | * Add directory entry for WAN device. | ||
324 | */ | ||
325 | |||
326 | int wanrouter_proc_add(struct wan_device* wandev) | ||
327 | { | ||
328 | if (wandev->magic != ROUTER_MAGIC) | ||
329 | return -EINVAL; | ||
330 | |||
331 | wandev->dent = proc_create(wandev->name, S_IRUGO, | ||
332 | proc_router, &wandev_fops); | ||
333 | if (!wandev->dent) | ||
334 | return -ENOMEM; | ||
335 | wandev->dent->data = wandev; | ||
336 | return 0; | ||
337 | } | ||
338 | |||
339 | /* | ||
340 | * Delete directory entry for WAN device. | ||
341 | */ | ||
342 | int wanrouter_proc_delete(struct wan_device* wandev) | ||
343 | { | ||
344 | if (wandev->magic != ROUTER_MAGIC) | ||
345 | return -EINVAL; | ||
346 | remove_proc_entry(wandev->name, proc_router); | ||
347 | return 0; | ||
348 | } | ||
349 | |||
350 | #else | ||
351 | |||
352 | /* | ||
353 | * No /proc - output stubs | ||
354 | */ | ||
355 | |||
356 | int __init wanrouter_proc_init(void) | ||
357 | { | ||
358 | return 0; | ||
359 | } | ||
360 | |||
361 | void wanrouter_proc_cleanup(void) | ||
362 | { | ||
363 | } | ||
364 | |||
365 | int wanrouter_proc_add(struct wan_device *wandev) | ||
366 | { | ||
367 | return 0; | ||
368 | } | ||
369 | |||
370 | int wanrouter_proc_delete(struct wan_device *wandev) | ||
371 | { | ||
372 | return 0; | ||
373 | } | ||
374 | |||
375 | #endif | ||
376 | |||
377 | /* | ||
378 | * End | ||
379 | */ | ||
380 | |||