diff options
author | Adrian Bunk <bunk@stusta.de> | 2006-04-11 20:28:33 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2006-04-11 20:28:33 -0400 |
commit | 8db60bcf3021921e2d10d158641792d640e52fe8 (patch) | |
tree | 3e00cf3527645140283667c306041e790b031834 | |
parent | 7ad4d2f6901437ba4717a26d395a73ea362d25c6 (diff) |
[WAN]: Remove broken and unmaintained Sangoma drivers.
The in-kernel Sangoma drivers are both not compiling and marked as BROKEN
since at least kernel 2.6.0.
Sangoma offers out-of-tree drivers, and David Mandelstam told me Sangoma
does no longer maintain the in-kernel drivers and prefers to provide them
as a separate installation package.
This patch therefore removes these drivers.
Signed-off-by: Adrian Bunk <bunk@stusta.de>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | MAINTAINERS | 7 | ||||
-rw-r--r-- | drivers/net/wan/Kconfig | 97 | ||||
-rw-r--r-- | drivers/net/wan/Makefile | 13 | ||||
-rw-r--r-- | drivers/net/wan/sdla_chdlc.c | 4428 | ||||
-rw-r--r-- | drivers/net/wan/sdla_fr.c | 5061 | ||||
-rw-r--r-- | drivers/net/wan/sdla_ft1.c | 345 | ||||
-rw-r--r-- | drivers/net/wan/sdla_ppp.c | 3430 | ||||
-rw-r--r-- | drivers/net/wan/sdla_x25.c | 5497 | ||||
-rw-r--r-- | drivers/net/wan/sdladrv.c | 2314 | ||||
-rw-r--r-- | drivers/net/wan/sdlamain.c | 1346 | ||||
-rw-r--r-- | drivers/net/wan/wanpipe_multppp.c | 2358 | ||||
-rw-r--r-- | include/linux/sdla_asy.h | 226 | ||||
-rw-r--r-- | include/linux/sdla_chdlc.h | 813 | ||||
-rw-r--r-- | include/linux/sdla_ppp.h | 575 | ||||
-rw-r--r-- | include/linux/sdla_x25.h | 772 | ||||
-rw-r--r-- | include/linux/sdladrv.h | 66 | ||||
-rw-r--r-- | include/linux/sdlapci.h | 72 | ||||
-rw-r--r-- | include/linux/sdlasfm.h | 104 | ||||
-rw-r--r-- | include/linux/wanpipe.h | 483 | ||||
-rw-r--r-- | net/wanrouter/af_wanpipe.c | 2 |
20 files changed, 0 insertions, 28009 deletions
diff --git a/MAINTAINERS b/MAINTAINERS index d00dea52123f..6d3c401ccdb6 100644 --- a/MAINTAINERS +++ b/MAINTAINERS | |||
@@ -3058,13 +3058,6 @@ M: khali@linux-fr.org | |||
3058 | L: lm-sensors@lm-sensors.org | 3058 | L: lm-sensors@lm-sensors.org |
3059 | S: Odd Fixes | 3059 | S: Odd Fixes |
3060 | 3060 | ||
3061 | WAN ROUTER & SANGOMA WANPIPE DRIVERS & API (X.25, FRAME RELAY, PPP, CISCO HDLC) | ||
3062 | P: Nenad Corbic | ||
3063 | M: ncorbic@sangoma.com | ||
3064 | M: dm@sangoma.com | ||
3065 | W: http://www.sangoma.com | ||
3066 | S: Supported | ||
3067 | |||
3068 | WATCHDOG DEVICE DRIVERS | 3061 | WATCHDOG DEVICE DRIVERS |
3069 | P: Wim Van Sebroeck | 3062 | P: Wim Van Sebroeck |
3070 | M: wim@iguana.be | 3063 | M: wim@iguana.be |
diff --git a/drivers/net/wan/Kconfig b/drivers/net/wan/Kconfig index 883cf7da10fc..b5328b0ff927 100644 --- a/drivers/net/wan/Kconfig +++ b/drivers/net/wan/Kconfig | |||
@@ -410,103 +410,6 @@ config WAN_ROUTER_DRIVERS | |||
410 | 410 | ||
411 | If unsure, say N. | 411 | If unsure, say N. |
412 | 412 | ||
413 | config VENDOR_SANGOMA | ||
414 | tristate "Sangoma WANPIPE(tm) multiprotocol cards" | ||
415 | depends on WAN_ROUTER_DRIVERS && WAN_ROUTER && (PCI || ISA) && BROKEN | ||
416 | ---help--- | ||
417 | Driver for S514-PCI/ISA Synchronous Data Link Adapters (SDLA). | ||
418 | |||
419 | WANPIPE from Sangoma Technologies Inc. <http://www.sangoma.com/> | ||
420 | is a family of intelligent multiprotocol WAN adapters with data | ||
421 | transfer rates up to 4Mbps. Cards support: | ||
422 | |||
423 | - X.25, Frame Relay, PPP, Cisco HDLC protocols. | ||
424 | |||
425 | - API for protocols like HDLC (LAPB), HDLC Streaming, X.25, | ||
426 | Frame Relay and BiSync. | ||
427 | |||
428 | - Ethernet Bridging over Frame Relay protocol. | ||
429 | |||
430 | - MULTILINK PPP | ||
431 | |||
432 | - Async PPP (Modem Dialup) | ||
433 | |||
434 | The next questions will ask you about the protocols you want | ||
435 | the driver to support. | ||
436 | |||
437 | If you have one or more of these cards, say M to this option; | ||
438 | and read <file:Documentation/networking/wan-router.txt>. | ||
439 | |||
440 | To compile this driver as a module, choose M here: the | ||
441 | module will be called wanpipe. | ||
442 | |||
443 | config WANPIPE_CHDLC | ||
444 | bool "WANPIPE Cisco HDLC support" | ||
445 | depends on VENDOR_SANGOMA | ||
446 | ---help--- | ||
447 | Connect a WANPIPE card to a leased line using the Cisco HDLC. | ||
448 | |||
449 | - Supports Dual Port Cisco HDLC on the S514-PCI/S508-ISA cards | ||
450 | which allows user to build applications using the HDLC streaming API. | ||
451 | |||
452 | - CHDLC Streaming MULTILINK PPP that can bind multiple WANPIPE T1 | ||
453 | cards into a single logical channel. | ||
454 | |||
455 | Say Y and the Cisco HDLC support, HDLC streaming API and | ||
456 | MULTILINK PPP will be included in the driver. | ||
457 | |||
458 | config WANPIPE_FR | ||
459 | bool "WANPIPE Frame Relay support" | ||
460 | depends on VENDOR_SANGOMA | ||
461 | help | ||
462 | Connect a WANPIPE card to a Frame Relay network, or use Frame Relay | ||
463 | API to develop custom applications. | ||
464 | |||
465 | Contains the Ethernet Bridging over Frame Relay feature, where | ||
466 | a WANPIPE frame relay link can be directly connected to the Linux | ||
467 | kernel bridge. The Frame Relay option is supported on S514-PCI | ||
468 | and S508-ISA cards. | ||
469 | |||
470 | Say Y and the Frame Relay support will be included in the driver. | ||
471 | |||
472 | config WANPIPE_X25 | ||
473 | bool "WANPIPE X.25 support" | ||
474 | depends on VENDOR_SANGOMA | ||
475 | help | ||
476 | Connect a WANPIPE card to an X.25 network. | ||
477 | |||
478 | Includes the X.25 API support for custom applications over the | ||
479 | X.25 protocol. The X.25 option is supported on S514-PCI and | ||
480 | S508-ISA cards. | ||
481 | |||
482 | Say Y and the X.25 support will be included in the driver. | ||
483 | |||
484 | config WANPIPE_PPP | ||
485 | bool "WANPIPE PPP support" | ||
486 | depends on VENDOR_SANGOMA | ||
487 | help | ||
488 | Connect a WANPIPE card to a leased line using Point-to-Point | ||
489 | Protocol (PPP). | ||
490 | |||
491 | The PPP option is supported on S514-PCI/S508-ISA cards. | ||
492 | |||
493 | Say Y and the PPP support will be included in the driver. | ||
494 | |||
495 | config WANPIPE_MULTPPP | ||
496 | bool "WANPIPE Multi-Port PPP support" | ||
497 | depends on VENDOR_SANGOMA | ||
498 | help | ||
499 | Connect a WANPIPE card to a leased line using Point-to-Point | ||
500 | Protocol (PPP). | ||
501 | |||
502 | Uses in-kernel SyncPPP protocol over the Sangoma HDLC Streaming | ||
503 | adapter. In this case each Sangoma adapter port can support an | ||
504 | independent PPP connection. For example, a single Quad-Port PCI | ||
505 | adapter can support up to four independent PPP links. The PPP | ||
506 | option is supported on S514-PCI/S508-ISA cards. | ||
507 | |||
508 | Say Y and the Multi-Port PPP support will be included in the driver. | ||
509 | |||
510 | config CYCLADES_SYNC | 413 | config CYCLADES_SYNC |
511 | tristate "Cyclom 2X(tm) cards (EXPERIMENTAL)" | 414 | tristate "Cyclom 2X(tm) cards (EXPERIMENTAL)" |
512 | depends on WAN_ROUTER_DRIVERS && (PCI || ISA) | 415 | depends on WAN_ROUTER_DRIVERS && (PCI || ISA) |
diff --git a/drivers/net/wan/Makefile b/drivers/net/wan/Makefile index ce6c56b903e7..823c6d5ab90d 100644 --- a/drivers/net/wan/Makefile +++ b/drivers/net/wan/Makefile | |||
@@ -5,14 +5,6 @@ | |||
5 | # Rewritten to use lists instead of if-statements. | 5 | # Rewritten to use lists instead of if-statements. |
6 | # | 6 | # |
7 | 7 | ||
8 | wanpipe-y := sdlamain.o sdla_ft1.o | ||
9 | wanpipe-$(CONFIG_WANPIPE_X25) += sdla_x25.o | ||
10 | wanpipe-$(CONFIG_WANPIPE_FR) += sdla_fr.o | ||
11 | wanpipe-$(CONFIG_WANPIPE_CHDLC) += sdla_chdlc.o | ||
12 | wanpipe-$(CONFIG_WANPIPE_PPP) += sdla_ppp.o | ||
13 | wanpipe-$(CONFIG_WANPIPE_MULTPPP) += wanpipe_multppp.o | ||
14 | wanpipe-objs := $(wanpipe-y) | ||
15 | |||
16 | cyclomx-y := cycx_main.o | 8 | cyclomx-y := cycx_main.o |
17 | cyclomx-$(CONFIG_CYCLOMX_X25) += cycx_x25.o | 9 | cyclomx-$(CONFIG_CYCLOMX_X25) += cycx_x25.o |
18 | cyclomx-objs := $(cyclomx-y) | 10 | cyclomx-objs := $(cyclomx-y) |
@@ -43,11 +35,6 @@ obj-$(CONFIG_LANMEDIA) += lmc/ | |||
43 | 35 | ||
44 | obj-$(CONFIG_DLCI) += dlci.o | 36 | obj-$(CONFIG_DLCI) += dlci.o |
45 | obj-$(CONFIG_SDLA) += sdla.o | 37 | obj-$(CONFIG_SDLA) += sdla.o |
46 | ifeq ($(CONFIG_WANPIPE_MULTPPP),y) | ||
47 | obj-$(CONFIG_VENDOR_SANGOMA) += sdladrv.o wanpipe.o syncppp.o | ||
48 | else | ||
49 | obj-$(CONFIG_VENDOR_SANGOMA) += sdladrv.o wanpipe.o | ||
50 | endif | ||
51 | obj-$(CONFIG_CYCLADES_SYNC) += cycx_drv.o cyclomx.o | 38 | obj-$(CONFIG_CYCLADES_SYNC) += cycx_drv.o cyclomx.o |
52 | obj-$(CONFIG_LAPBETHER) += lapbether.o | 39 | obj-$(CONFIG_LAPBETHER) += lapbether.o |
53 | obj-$(CONFIG_SBNI) += sbni.o | 40 | obj-$(CONFIG_SBNI) += sbni.o |
diff --git a/drivers/net/wan/sdla_chdlc.c b/drivers/net/wan/sdla_chdlc.c deleted file mode 100644 index 496d29237e92..000000000000 --- a/drivers/net/wan/sdla_chdlc.c +++ /dev/null | |||
@@ -1,4428 +0,0 @@ | |||
1 | /***************************************************************************** | ||
2 | * sdla_chdlc.c WANPIPE(tm) Multiprotocol WAN Link Driver. Cisco HDLC module. | ||
3 | * | ||
4 | * Authors: Nenad Corbic <ncorbic@sangoma.com> | ||
5 | * Gideon Hack | ||
6 | * | ||
7 | * Copyright: (c) 1995-2001 Sangoma Technologies Inc. | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or | ||
10 | * modify it under the terms of the GNU General Public License | ||
11 | * as published by the Free Software Foundation; either version | ||
12 | * 2 of the License, or (at your option) any later version. | ||
13 | * ============================================================================ | ||
14 | * Feb 28, 2001 Nenad Corbic Updated if_tx_timeout() routine for | ||
15 | * 2.4.X kernels. | ||
16 | * Jan 25, 2001 Nenad Corbic Added a TTY Sync serial driver over the | ||
17 | * HDLC streaming protocol | ||
18 | * Added a TTY Async serial driver over the | ||
19 | * Async protocol. | ||
20 | * Dec 15, 2000 Nenad Corbic Updated for 2.4.X Kernel support | ||
21 | * Nov 13, 2000 Nenad Corbic Added true interface type encoding option. | ||
22 | * Tcpdump doesn't support CHDLC inteface | ||
23 | * types, to fix this "true type" option will set | ||
24 | * the interface type to RAW IP mode. | ||
25 | * Nov 07, 2000 Nenad Corbic Added security features for UDP debugging: | ||
26 | * Deny all and specify allowed requests. | ||
27 | * Jun 20, 2000 Nenad Corbic Fixed the API IP ERROR bug. Caused by the | ||
28 | * latest update. | ||
29 | * May 09, 2000 Nenad Corbic Option to bring down an interface | ||
30 | * upon disconnect. | ||
31 | * Mar 23, 2000 Nenad Corbic Improved task queue, bh handling. | ||
32 | * Mar 16, 2000 Nenad Corbic Fixed the SLARP Dynamic IP addressing. | ||
33 | * Mar 06, 2000 Nenad Corbic Bug Fix: corrupted mbox recovery. | ||
34 | * Feb 10, 2000 Gideon Hack Added ASYNC support. | ||
35 | * Feb 09, 2000 Nenad Corbic Fixed two shutdown bugs in update() and | ||
36 | * if_stats() functions. | ||
37 | * Jan 24, 2000 Nenad Corbic Fixed a startup wanpipe state racing, | ||
38 | * condition between if_open and isr. | ||
39 | * Jan 10, 2000 Nenad Corbic Added new socket API support. | ||
40 | * Dev 15, 1999 Nenad Corbic Fixed up header files for 2.0.X kernels | ||
41 | * Nov 20, 1999 Nenad Corbic Fixed zero length API bug. | ||
42 | * Sep 30, 1999 Nenad Corbic Fixed dynamic IP and route setup. | ||
43 | * Sep 23, 1999 Nenad Corbic Added SMP support, fixed tracing | ||
44 | * Sep 13, 1999 Nenad Corbic Split up Port 0 and 1 into separate devices. | ||
45 | * Jun 02, 1999 Gideon Hack Added support for the S514 adapter. | ||
46 | * Oct 30, 1998 Jaspreet Singh Added Support for CHDLC API (HDLC STREAMING). | ||
47 | * Oct 28, 1998 Jaspreet Singh Added Support for Dual Port CHDLC. | ||
48 | * Aug 07, 1998 David Fong Initial version. | ||
49 | *****************************************************************************/ | ||
50 | |||
51 | #include <linux/module.h> | ||
52 | #include <linux/kernel.h> /* printk(), and other useful stuff */ | ||
53 | #include <linux/stddef.h> /* offsetof(), etc. */ | ||
54 | #include <linux/errno.h> /* return codes */ | ||
55 | #include <linux/string.h> /* inline memset(), etc. */ | ||
56 | #include <linux/slab.h> /* kmalloc(), kfree() */ | ||
57 | #include <linux/wanrouter.h> /* WAN router definitions */ | ||
58 | #include <linux/wanpipe.h> /* WANPIPE common user API definitions */ | ||
59 | #include <linux/if_arp.h> /* ARPHRD_* defines */ | ||
60 | |||
61 | |||
62 | #include <asm/uaccess.h> | ||
63 | #include <linux/inetdevice.h> | ||
64 | #include <linux/netdevice.h> | ||
65 | |||
66 | #include <linux/in.h> /* sockaddr_in */ | ||
67 | #include <linux/inet.h> | ||
68 | #include <linux/if.h> | ||
69 | #include <asm/byteorder.h> /* htons(), etc. */ | ||
70 | #include <linux/sdlapci.h> | ||
71 | #include <asm/io.h> | ||
72 | |||
73 | #include <linux/sdla_chdlc.h> /* CHDLC firmware API definitions */ | ||
74 | #include <linux/sdla_asy.h> /* CHDLC (async) API definitions */ | ||
75 | |||
76 | #include <linux/if_wanpipe_common.h> /* Socket Driver common area */ | ||
77 | #include <linux/if_wanpipe.h> | ||
78 | |||
79 | /* TTY Includes */ | ||
80 | #include <linux/tty.h> | ||
81 | #include <linux/tty_flip.h> | ||
82 | #include <linux/serial.h> | ||
83 | |||
84 | |||
85 | /****** Defines & Macros ****************************************************/ | ||
86 | |||
87 | /* reasons for enabling the timer interrupt on the adapter */ | ||
88 | #define TMR_INT_ENABLED_UDP 0x01 | ||
89 | #define TMR_INT_ENABLED_UPDATE 0x02 | ||
90 | #define TMR_INT_ENABLED_CONFIG 0x10 | ||
91 | |||
92 | #define MAX_IP_ERRORS 10 | ||
93 | |||
94 | #define TTY_CHDLC_MAX_MTU 2000 | ||
95 | #define CHDLC_DFLT_DATA_LEN 1500 /* default MTU */ | ||
96 | #define CHDLC_HDR_LEN 1 | ||
97 | |||
98 | #define CHDLC_API 0x01 | ||
99 | |||
100 | #define PORT(x) (x == 0 ? "PRIMARY" : "SECONDARY" ) | ||
101 | #define MAX_BH_BUFF 10 | ||
102 | |||
103 | //#define PRINT_DEBUG | ||
104 | #ifdef PRINT_DEBUG | ||
105 | #define dbg_printk(format, a...) printk(format, ## a) | ||
106 | #else | ||
107 | #define dbg_printk(format, a...) | ||
108 | #endif | ||
109 | |||
110 | /******Data Structures*****************************************************/ | ||
111 | |||
112 | /* This structure is placed in the private data area of the device structure. | ||
113 | * The card structure used to occupy the private area but now the following | ||
114 | * structure will incorporate the card structure along with CHDLC specific data | ||
115 | */ | ||
116 | |||
117 | typedef struct chdlc_private_area | ||
118 | { | ||
119 | wanpipe_common_t common; | ||
120 | sdla_t *card; | ||
121 | int TracingEnabled; /* For enabling Tracing */ | ||
122 | unsigned long curr_trace_addr; /* Used for Tracing */ | ||
123 | unsigned long start_trace_addr; | ||
124 | unsigned long end_trace_addr; | ||
125 | unsigned long base_addr_trace_buffer; | ||
126 | unsigned long end_addr_trace_buffer; | ||
127 | unsigned short number_trace_elements; | ||
128 | unsigned available_buffer_space; | ||
129 | unsigned long router_start_time; | ||
130 | unsigned char route_status; | ||
131 | unsigned char route_removed; | ||
132 | unsigned long tick_counter; /* For 5s timeout counter */ | ||
133 | unsigned long router_up_time; | ||
134 | u32 IP_address; /* IP addressing */ | ||
135 | u32 IP_netmask; | ||
136 | u32 ip_local; | ||
137 | u32 ip_remote; | ||
138 | u32 ip_local_tmp; | ||
139 | u32 ip_remote_tmp; | ||
140 | u8 ip_error; | ||
141 | u8 config_chdlc; | ||
142 | u8 config_chdlc_timeout; | ||
143 | unsigned char mc; /* Mulitcast support on/off */ | ||
144 | unsigned short udp_pkt_lgth; /* udp packet processing */ | ||
145 | char udp_pkt_src; | ||
146 | char udp_pkt_data[MAX_LGTH_UDP_MGNT_PKT]; | ||
147 | unsigned short timer_int_enabled; | ||
148 | char update_comms_stats; /* updating comms stats */ | ||
149 | |||
150 | bh_data_t *bh_head; /* Circular buffer for chdlc_bh */ | ||
151 | unsigned long tq_working; | ||
152 | volatile int bh_write; | ||
153 | volatile int bh_read; | ||
154 | atomic_t bh_buff_used; | ||
155 | |||
156 | unsigned char interface_down; | ||
157 | |||
158 | /* Polling work queue entry. Each interface | ||
159 | * has its own work queue entry, which is used | ||
160 | * to defer events from the interrupt */ | ||
161 | struct work_struct poll_work; | ||
162 | struct timer_list poll_delay_timer; | ||
163 | |||
164 | u8 gateway; | ||
165 | u8 true_if_encoding; | ||
166 | //FIXME: add driver stats as per frame relay! | ||
167 | |||
168 | } chdlc_private_area_t; | ||
169 | |||
170 | /* Route Status options */ | ||
171 | #define NO_ROUTE 0x00 | ||
172 | #define ADD_ROUTE 0x01 | ||
173 | #define ROUTE_ADDED 0x02 | ||
174 | #define REMOVE_ROUTE 0x03 | ||
175 | |||
176 | |||
177 | /* variable for keeping track of enabling/disabling FT1 monitor status */ | ||
178 | static int rCount = 0; | ||
179 | |||
180 | /* variable for tracking how many interfaces to open for WANPIPE on the | ||
181 | two ports */ | ||
182 | |||
183 | extern void disable_irq(unsigned int); | ||
184 | extern void enable_irq(unsigned int); | ||
185 | |||
186 | /****** Function Prototypes *************************************************/ | ||
187 | /* WAN link driver entry points. These are called by the WAN router module. */ | ||
188 | static int update(struct wan_device* wandev); | ||
189 | static int new_if(struct wan_device* wandev, struct net_device* dev, | ||
190 | wanif_conf_t* conf); | ||
191 | |||
192 | /* Network device interface */ | ||
193 | static int if_init(struct net_device* dev); | ||
194 | static int if_open(struct net_device* dev); | ||
195 | static int if_close(struct net_device* dev); | ||
196 | static int if_header(struct sk_buff* skb, struct net_device* dev, | ||
197 | unsigned short type, void* daddr, void* saddr, | ||
198 | unsigned len); | ||
199 | |||
200 | static int if_rebuild_hdr (struct sk_buff *skb); | ||
201 | static struct net_device_stats* if_stats(struct net_device* dev); | ||
202 | |||
203 | static int if_send(struct sk_buff* skb, struct net_device* dev); | ||
204 | |||
205 | /* CHDLC Firmware interface functions */ | ||
206 | static int chdlc_configure (sdla_t* card, void* data); | ||
207 | static int chdlc_comm_enable (sdla_t* card); | ||
208 | static int chdlc_read_version (sdla_t* card, char* str); | ||
209 | static int chdlc_set_intr_mode (sdla_t* card, unsigned mode); | ||
210 | static int chdlc_send (sdla_t* card, void* data, unsigned len); | ||
211 | static int chdlc_read_comm_err_stats (sdla_t* card); | ||
212 | static int chdlc_read_op_stats (sdla_t* card); | ||
213 | static int chdlc_error (sdla_t *card, int err, CHDLC_MAILBOX_STRUCT *mb); | ||
214 | |||
215 | |||
216 | static int chdlc_disable_comm_shutdown (sdla_t *card); | ||
217 | static void if_tx_timeout(struct net_device *dev); | ||
218 | |||
219 | /* Miscellaneous CHDLC Functions */ | ||
220 | static int set_chdlc_config (sdla_t* card); | ||
221 | static void init_chdlc_tx_rx_buff( sdla_t* card); | ||
222 | static int process_chdlc_exception(sdla_t *card); | ||
223 | static int process_global_exception(sdla_t *card); | ||
224 | static int update_comms_stats(sdla_t* card, | ||
225 | chdlc_private_area_t* chdlc_priv_area); | ||
226 | static int configure_ip (sdla_t* card); | ||
227 | static int unconfigure_ip (sdla_t* card); | ||
228 | static void process_route(sdla_t *card); | ||
229 | static void port_set_state (sdla_t *card, int); | ||
230 | static int config_chdlc (sdla_t *card); | ||
231 | static void disable_comm (sdla_t *card); | ||
232 | |||
233 | static void trigger_chdlc_poll(struct net_device *dev); | ||
234 | static void chdlc_poll(struct net_device *dev); | ||
235 | static void chdlc_poll_delay (unsigned long dev_ptr); | ||
236 | |||
237 | |||
238 | /* Miscellaneous asynchronous interface Functions */ | ||
239 | static int set_asy_config (sdla_t* card); | ||
240 | static int asy_comm_enable (sdla_t* card); | ||
241 | |||
242 | /* Interrupt handlers */ | ||
243 | static void wpc_isr (sdla_t* card); | ||
244 | static void rx_intr (sdla_t* card); | ||
245 | static void timer_intr(sdla_t *); | ||
246 | |||
247 | /* Bottom half handlers */ | ||
248 | static void chdlc_work(struct net_device *dev); | ||
249 | static int chdlc_work_cleanup(struct net_device *dev); | ||
250 | static int bh_enqueue(struct net_device *dev, struct sk_buff *skb); | ||
251 | |||
252 | /* Miscellaneous functions */ | ||
253 | static int chk_bcast_mcast_addr(sdla_t* card, struct net_device* dev, | ||
254 | struct sk_buff *skb); | ||
255 | static int reply_udp( unsigned char *data, unsigned int mbox_len ); | ||
256 | static int intr_test( sdla_t* card); | ||
257 | static int udp_pkt_type( struct sk_buff *skb , sdla_t* card); | ||
258 | static int store_udp_mgmt_pkt(char udp_pkt_src, sdla_t* card, | ||
259 | struct sk_buff *skb, struct net_device* dev, | ||
260 | chdlc_private_area_t* chdlc_priv_area); | ||
261 | static int process_udp_mgmt_pkt(sdla_t* card, struct net_device* dev, | ||
262 | chdlc_private_area_t* chdlc_priv_area); | ||
263 | static unsigned short calc_checksum (char *, int); | ||
264 | static void s508_lock (sdla_t *card, unsigned long *smp_flags); | ||
265 | static void s508_unlock (sdla_t *card, unsigned long *smp_flags); | ||
266 | |||
267 | |||
268 | static int Intr_test_counter; | ||
269 | |||
270 | /* TTY Global Definitions */ | ||
271 | |||
272 | #define NR_PORTS 4 | ||
273 | #define WAN_TTY_MAJOR 226 | ||
274 | #define WAN_TTY_MINOR 0 | ||
275 | |||
276 | #define WAN_CARD(port) (tty_card_map[port]) | ||
277 | #define MIN_PORT 0 | ||
278 | #define MAX_PORT NR_PORTS-1 | ||
279 | |||
280 | #define CRC_LENGTH 2 | ||
281 | |||
282 | static int wanpipe_tty_init(sdla_t *card); | ||
283 | static void wanpipe_tty_receive(sdla_t *, unsigned, unsigned int); | ||
284 | static void wanpipe_tty_trigger_poll(sdla_t *card); | ||
285 | |||
286 | static struct tty_driver serial_driver; | ||
287 | static int tty_init_cnt=0; | ||
288 | |||
289 | static struct serial_state rs_table[NR_PORTS]; | ||
290 | |||
291 | static char tty_driver_mode=WANOPT_TTY_SYNC; | ||
292 | |||
293 | static char *opt_decode[] = {"NONE","CRTSCTS","XONXOFF-RX", | ||
294 | "CRTSCTS XONXOFF-RX","XONXOFF-TX", | ||
295 | "CRTSCTS XONXOFF-TX","CRTSCTS XONXOFF"}; | ||
296 | static char *p_decode[] = {"NONE","ODD","EVEN"}; | ||
297 | |||
298 | static void* tty_card_map[NR_PORTS] = {NULL,NULL,NULL,NULL}; | ||
299 | |||
300 | |||
301 | /****** Public Functions ****************************************************/ | ||
302 | |||
303 | /*============================================================================ | ||
304 | * Cisco HDLC protocol initialization routine. | ||
305 | * | ||
306 | * This routine is called by the main WANPIPE module during setup. At this | ||
307 | * point adapter is completely initialized and firmware is running. | ||
308 | * o read firmware version (to make sure it's alive) | ||
309 | * o configure adapter | ||
310 | * o initialize protocol-specific fields of the adapter data space. | ||
311 | * | ||
312 | * Return: 0 o.k. | ||
313 | * < 0 failure. | ||
314 | */ | ||
315 | int wpc_init (sdla_t* card, wandev_conf_t* conf) | ||
316 | { | ||
317 | unsigned char port_num; | ||
318 | int err; | ||
319 | unsigned long max_permitted_baud = 0; | ||
320 | SHARED_MEMORY_INFO_STRUCT *flags; | ||
321 | |||
322 | union | ||
323 | { | ||
324 | char str[80]; | ||
325 | } u; | ||
326 | volatile CHDLC_MAILBOX_STRUCT* mb; | ||
327 | CHDLC_MAILBOX_STRUCT* mb1; | ||
328 | unsigned long timeout; | ||
329 | |||
330 | /* Verify configuration ID */ | ||
331 | if (conf->config_id != WANCONFIG_CHDLC) { | ||
332 | printk(KERN_INFO "%s: invalid configuration ID %u!\n", | ||
333 | card->devname, conf->config_id); | ||
334 | return -EINVAL; | ||
335 | } | ||
336 | |||
337 | /* Find out which Port to use */ | ||
338 | if ((conf->comm_port == WANOPT_PRI) || (conf->comm_port == WANOPT_SEC)){ | ||
339 | if (card->next){ | ||
340 | |||
341 | if (conf->comm_port != card->next->u.c.comm_port){ | ||
342 | card->u.c.comm_port = conf->comm_port; | ||
343 | }else{ | ||
344 | printk(KERN_INFO "%s: ERROR - %s port used!\n", | ||
345 | card->wandev.name, PORT(conf->comm_port)); | ||
346 | return -EINVAL; | ||
347 | } | ||
348 | }else{ | ||
349 | card->u.c.comm_port = conf->comm_port; | ||
350 | } | ||
351 | }else{ | ||
352 | printk(KERN_INFO "%s: ERROR - Invalid Port Selected!\n", | ||
353 | card->wandev.name); | ||
354 | return -EINVAL; | ||
355 | } | ||
356 | |||
357 | |||
358 | /* Initialize protocol-specific fields */ | ||
359 | if(card->hw.type != SDLA_S514){ | ||
360 | |||
361 | if (card->u.c.comm_port == WANOPT_PRI){ | ||
362 | card->mbox = (void *) card->hw.dpmbase; | ||
363 | }else{ | ||
364 | card->mbox = (void *) card->hw.dpmbase + | ||
365 | SEC_BASE_ADDR_MB_STRUCT - PRI_BASE_ADDR_MB_STRUCT; | ||
366 | } | ||
367 | }else{ | ||
368 | /* for a S514 adapter, set a pointer to the actual mailbox in the */ | ||
369 | /* allocated virtual memory area */ | ||
370 | if (card->u.c.comm_port == WANOPT_PRI){ | ||
371 | card->mbox = (void *) card->hw.dpmbase + PRI_BASE_ADDR_MB_STRUCT; | ||
372 | }else{ | ||
373 | card->mbox = (void *) card->hw.dpmbase + SEC_BASE_ADDR_MB_STRUCT; | ||
374 | } | ||
375 | } | ||
376 | |||
377 | mb = mb1 = card->mbox; | ||
378 | |||
379 | if (!card->configured){ | ||
380 | |||
381 | /* The board will place an 'I' in the return code to indicate that it is | ||
382 | ready to accept commands. We expect this to be completed in less | ||
383 | than 1 second. */ | ||
384 | |||
385 | timeout = jiffies; | ||
386 | while (mb->return_code != 'I') /* Wait 1s for board to initialize */ | ||
387 | if ((jiffies - timeout) > 1*HZ) break; | ||
388 | |||
389 | if (mb->return_code != 'I') { | ||
390 | printk(KERN_INFO | ||
391 | "%s: Initialization not completed by adapter\n", | ||
392 | card->devname); | ||
393 | printk(KERN_INFO "Please contact Sangoma representative.\n"); | ||
394 | return -EIO; | ||
395 | } | ||
396 | } | ||
397 | |||
398 | /* Read firmware version. Note that when adapter initializes, it | ||
399 | * clears the mailbox, so it may appear that the first command was | ||
400 | * executed successfully when in fact it was merely erased. To work | ||
401 | * around this, we execute the first command twice. | ||
402 | */ | ||
403 | |||
404 | if (chdlc_read_version(card, u.str)) | ||
405 | return -EIO; | ||
406 | |||
407 | printk(KERN_INFO "%s: Running Cisco HDLC firmware v%s\n", | ||
408 | card->devname, u.str); | ||
409 | |||
410 | card->isr = &wpc_isr; | ||
411 | card->poll = NULL; | ||
412 | card->exec = NULL; | ||
413 | card->wandev.update = &update; | ||
414 | card->wandev.new_if = &new_if; | ||
415 | card->wandev.del_if = NULL; | ||
416 | card->wandev.udp_port = conf->udp_port; | ||
417 | card->disable_comm = &disable_comm; | ||
418 | card->wandev.new_if_cnt = 0; | ||
419 | |||
420 | /* reset the number of times the 'update()' proc has been called */ | ||
421 | card->u.c.update_call_count = 0; | ||
422 | |||
423 | card->wandev.ttl = conf->ttl; | ||
424 | card->wandev.interface = conf->interface; | ||
425 | |||
426 | if ((card->u.c.comm_port == WANOPT_SEC && conf->interface == WANOPT_V35)&& | ||
427 | card->hw.type != SDLA_S514){ | ||
428 | printk(KERN_INFO "%s: ERROR - V35 Interface not supported on S508 %s port \n", | ||
429 | card->devname, PORT(card->u.c.comm_port)); | ||
430 | return -EIO; | ||
431 | } | ||
432 | |||
433 | card->wandev.clocking = conf->clocking; | ||
434 | |||
435 | port_num = card->u.c.comm_port; | ||
436 | |||
437 | /* in API mode, we can configure for "receive only" buffering */ | ||
438 | if(card->hw.type == SDLA_S514) { | ||
439 | card->u.c.receive_only = conf->receive_only; | ||
440 | if(conf->receive_only) { | ||
441 | printk(KERN_INFO | ||
442 | "%s: Configured for 'receive only' mode\n", | ||
443 | card->devname); | ||
444 | } | ||
445 | } | ||
446 | |||
447 | /* Setup Port Bps */ | ||
448 | |||
449 | if(card->wandev.clocking) { | ||
450 | if((port_num == WANOPT_PRI) || card->u.c.receive_only) { | ||
451 | /* For Primary Port 0 */ | ||
452 | max_permitted_baud = | ||
453 | (card->hw.type == SDLA_S514) ? | ||
454 | PRI_MAX_BAUD_RATE_S514 : | ||
455 | PRI_MAX_BAUD_RATE_S508; | ||
456 | |||
457 | }else if(port_num == WANOPT_SEC) { | ||
458 | /* For Secondary Port 1 */ | ||
459 | max_permitted_baud = | ||
460 | (card->hw.type == SDLA_S514) ? | ||
461 | SEC_MAX_BAUD_RATE_S514 : | ||
462 | SEC_MAX_BAUD_RATE_S508; | ||
463 | } | ||
464 | |||
465 | if(conf->bps > max_permitted_baud) { | ||
466 | conf->bps = max_permitted_baud; | ||
467 | printk(KERN_INFO "%s: Baud too high!\n", | ||
468 | card->wandev.name); | ||
469 | printk(KERN_INFO "%s: Baud rate set to %lu bps\n", | ||
470 | card->wandev.name, max_permitted_baud); | ||
471 | } | ||
472 | card->wandev.bps = conf->bps; | ||
473 | }else{ | ||
474 | card->wandev.bps = 0; | ||
475 | } | ||
476 | |||
477 | /* Setup the Port MTU */ | ||
478 | if((port_num == WANOPT_PRI) || card->u.c.receive_only) { | ||
479 | |||
480 | /* For Primary Port 0 */ | ||
481 | card->wandev.mtu = | ||
482 | (conf->mtu >= MIN_LGTH_CHDLC_DATA_CFG) ? | ||
483 | min_t(unsigned int, conf->mtu, PRI_MAX_NO_DATA_BYTES_IN_FRAME) : | ||
484 | CHDLC_DFLT_DATA_LEN; | ||
485 | } else if(port_num == WANOPT_SEC) { | ||
486 | /* For Secondary Port 1 */ | ||
487 | card->wandev.mtu = | ||
488 | (conf->mtu >= MIN_LGTH_CHDLC_DATA_CFG) ? | ||
489 | min_t(unsigned int, conf->mtu, SEC_MAX_NO_DATA_BYTES_IN_FRAME) : | ||
490 | CHDLC_DFLT_DATA_LEN; | ||
491 | } | ||
492 | |||
493 | /* Set up the interrupt status area */ | ||
494 | /* Read the CHDLC Configuration and obtain: | ||
495 | * Ptr to shared memory infor struct | ||
496 | * Use this pointer to calculate the value of card->u.c.flags ! | ||
497 | */ | ||
498 | mb1->buffer_length = 0; | ||
499 | mb1->command = READ_CHDLC_CONFIGURATION; | ||
500 | err = sdla_exec(mb1) ? mb1->return_code : CMD_TIMEOUT; | ||
501 | if(err != COMMAND_OK) { | ||
502 | if(card->hw.type != SDLA_S514) | ||
503 | enable_irq(card->hw.irq); | ||
504 | |||
505 | chdlc_error(card, err, mb1); | ||
506 | return -EIO; | ||
507 | } | ||
508 | |||
509 | if(card->hw.type == SDLA_S514){ | ||
510 | card->u.c.flags = (void *)(card->hw.dpmbase + | ||
511 | (((CHDLC_CONFIGURATION_STRUCT *)mb1->data)-> | ||
512 | ptr_shared_mem_info_struct)); | ||
513 | }else{ | ||
514 | card->u.c.flags = (void *)(card->hw.dpmbase + | ||
515 | (((CHDLC_CONFIGURATION_STRUCT *)mb1->data)-> | ||
516 | ptr_shared_mem_info_struct % SDLA_WINDOWSIZE)); | ||
517 | } | ||
518 | |||
519 | flags = card->u.c.flags; | ||
520 | |||
521 | /* This is for the ports link state */ | ||
522 | card->wandev.state = WAN_DUALPORT; | ||
523 | card->u.c.state = WAN_DISCONNECTED; | ||
524 | |||
525 | |||
526 | if (!card->wandev.piggyback){ | ||
527 | int err; | ||
528 | |||
529 | /* Perform interrupt testing */ | ||
530 | err = intr_test(card); | ||
531 | |||
532 | if(err || (Intr_test_counter < MAX_INTR_TEST_COUNTER)) { | ||
533 | printk(KERN_INFO "%s: Interrupt test failed (%i)\n", | ||
534 | card->devname, Intr_test_counter); | ||
535 | printk(KERN_INFO "%s: Please choose another interrupt\n", | ||
536 | card->devname); | ||
537 | return -EIO; | ||
538 | } | ||
539 | |||
540 | printk(KERN_INFO "%s: Interrupt test passed (%i)\n", | ||
541 | card->devname, Intr_test_counter); | ||
542 | card->configured = 1; | ||
543 | } | ||
544 | |||
545 | if ((card->tty_opt=conf->tty) == WANOPT_YES){ | ||
546 | int err; | ||
547 | card->tty_minor = conf->tty_minor; | ||
548 | |||
549 | /* On ASYNC connections internal clocking | ||
550 | * is mandatory */ | ||
551 | if ((card->u.c.async_mode = conf->tty_mode)){ | ||
552 | card->wandev.clocking = 1; | ||
553 | } | ||
554 | err=wanpipe_tty_init(card); | ||
555 | if (err){ | ||
556 | return err; | ||
557 | } | ||
558 | }else{ | ||
559 | |||
560 | |||
561 | if (chdlc_set_intr_mode(card, APP_INT_ON_TIMER)){ | ||
562 | printk (KERN_INFO "%s: " | ||
563 | "Failed to set interrupt triggers!\n", | ||
564 | card->devname); | ||
565 | return -EIO; | ||
566 | } | ||
567 | |||
568 | /* Mask the Timer interrupt */ | ||
569 | flags->interrupt_info_struct.interrupt_permission &= | ||
570 | ~APP_INT_ON_TIMER; | ||
571 | } | ||
572 | |||
573 | /* If we are using CHDLC in backup mode, this flag will | ||
574 | * indicate not to look for IP addresses in config_chdlc()*/ | ||
575 | card->u.c.backup = conf->backup; | ||
576 | |||
577 | printk(KERN_INFO "\n"); | ||
578 | |||
579 | return 0; | ||
580 | } | ||
581 | |||
582 | /******* WAN Device Driver Entry Points *************************************/ | ||
583 | |||
584 | /*============================================================================ | ||
585 | * Update device status & statistics | ||
586 | * This procedure is called when updating the PROC file system and returns | ||
587 | * various communications statistics. These statistics are accumulated from 3 | ||
588 | * different locations: | ||
589 | * 1) The 'if_stats' recorded for the device. | ||
590 | * 2) Communication error statistics on the adapter. | ||
591 | * 3) CHDLC operational statistics on the adapter. | ||
592 | * The board level statistics are read during a timer interrupt. Note that we | ||
593 | * read the error and operational statistics during consecitive timer ticks so | ||
594 | * as to minimize the time that we are inside the interrupt handler. | ||
595 | * | ||
596 | */ | ||
597 | static int update(struct wan_device* wandev) | ||
598 | { | ||
599 | sdla_t* card = wandev->private; | ||
600 | struct net_device* dev; | ||
601 | volatile chdlc_private_area_t* chdlc_priv_area; | ||
602 | SHARED_MEMORY_INFO_STRUCT *flags; | ||
603 | unsigned long timeout; | ||
604 | |||
605 | /* sanity checks */ | ||
606 | if((wandev == NULL) || (wandev->private == NULL)) | ||
607 | return -EFAULT; | ||
608 | |||
609 | if(wandev->state == WAN_UNCONFIGURED) | ||
610 | return -ENODEV; | ||
611 | |||
612 | /* more sanity checks */ | ||
613 | if(!card->u.c.flags) | ||
614 | return -ENODEV; | ||
615 | |||
616 | if(test_bit(PERI_CRIT, (void*)&card->wandev.critical)) | ||
617 | return -EAGAIN; | ||
618 | |||
619 | if((dev=card->wandev.dev) == NULL) | ||
620 | return -ENODEV; | ||
621 | |||
622 | if((chdlc_priv_area=dev->priv) == NULL) | ||
623 | return -ENODEV; | ||
624 | |||
625 | flags = card->u.c.flags; | ||
626 | if(chdlc_priv_area->update_comms_stats){ | ||
627 | return -EAGAIN; | ||
628 | } | ||
629 | |||
630 | /* we will need 2 timer interrupts to complete the */ | ||
631 | /* reading of the statistics */ | ||
632 | chdlc_priv_area->update_comms_stats = 2; | ||
633 | flags->interrupt_info_struct.interrupt_permission |= APP_INT_ON_TIMER; | ||
634 | chdlc_priv_area->timer_int_enabled = TMR_INT_ENABLED_UPDATE; | ||
635 | |||
636 | /* wait a maximum of 1 second for the statistics to be updated */ | ||
637 | timeout = jiffies; | ||
638 | for(;;) { | ||
639 | if(chdlc_priv_area->update_comms_stats == 0) | ||
640 | break; | ||
641 | if ((jiffies - timeout) > (1 * HZ)){ | ||
642 | chdlc_priv_area->update_comms_stats = 0; | ||
643 | chdlc_priv_area->timer_int_enabled &= | ||
644 | ~TMR_INT_ENABLED_UPDATE; | ||
645 | return -EAGAIN; | ||
646 | } | ||
647 | } | ||
648 | |||
649 | return 0; | ||
650 | } | ||
651 | |||
652 | |||
653 | /*============================================================================ | ||
654 | * Create new logical channel. | ||
655 | * This routine is called by the router when ROUTER_IFNEW IOCTL is being | ||
656 | * handled. | ||
657 | * o parse media- and hardware-specific configuration | ||
658 | * o make sure that a new channel can be created | ||
659 | * o allocate resources, if necessary | ||
660 | * o prepare network device structure for registaration. | ||
661 | * | ||
662 | * Return: 0 o.k. | ||
663 | * < 0 failure (channel will not be created) | ||
664 | */ | ||
665 | static int new_if(struct wan_device* wandev, struct net_device* dev, | ||
666 | wanif_conf_t* conf) | ||
667 | { | ||
668 | sdla_t* card = wandev->private; | ||
669 | chdlc_private_area_t* chdlc_priv_area; | ||
670 | |||
671 | |||
672 | printk(KERN_INFO "%s: Configuring Interface: %s\n", | ||
673 | card->devname, conf->name); | ||
674 | |||
675 | if ((conf->name[0] == '\0') || (strlen(conf->name) > WAN_IFNAME_SZ)) { | ||
676 | printk(KERN_INFO "%s: Invalid interface name!\n", | ||
677 | card->devname); | ||
678 | return -EINVAL; | ||
679 | } | ||
680 | |||
681 | /* allocate and initialize private data */ | ||
682 | chdlc_priv_area = kmalloc(sizeof(chdlc_private_area_t), GFP_KERNEL); | ||
683 | |||
684 | if(chdlc_priv_area == NULL) | ||
685 | return -ENOMEM; | ||
686 | |||
687 | memset(chdlc_priv_area, 0, sizeof(chdlc_private_area_t)); | ||
688 | |||
689 | chdlc_priv_area->card = card; | ||
690 | chdlc_priv_area->common.sk = NULL; | ||
691 | chdlc_priv_area->common.func = NULL; | ||
692 | |||
693 | /* initialize data */ | ||
694 | strcpy(card->u.c.if_name, conf->name); | ||
695 | |||
696 | if(card->wandev.new_if_cnt > 0) { | ||
697 | kfree(chdlc_priv_area); | ||
698 | return -EEXIST; | ||
699 | } | ||
700 | |||
701 | card->wandev.new_if_cnt++; | ||
702 | |||
703 | chdlc_priv_area->TracingEnabled = 0; | ||
704 | chdlc_priv_area->route_status = NO_ROUTE; | ||
705 | chdlc_priv_area->route_removed = 0; | ||
706 | |||
707 | card->u.c.async_mode = conf->async_mode; | ||
708 | |||
709 | /* setup for asynchronous mode */ | ||
710 | if(conf->async_mode) { | ||
711 | printk(KERN_INFO "%s: Configuring for asynchronous mode\n", | ||
712 | wandev->name); | ||
713 | |||
714 | if(card->u.c.comm_port == WANOPT_PRI) { | ||
715 | printk(KERN_INFO | ||
716 | "%s:Asynchronous mode on secondary port only\n", | ||
717 | wandev->name); | ||
718 | kfree(chdlc_priv_area); | ||
719 | return -EINVAL; | ||
720 | } | ||
721 | |||
722 | if(strcmp(conf->usedby, "WANPIPE") == 0) { | ||
723 | printk(KERN_INFO | ||
724 | "%s: Running in WANIPE Async Mode\n", wandev->name); | ||
725 | card->u.c.usedby = WANPIPE; | ||
726 | }else{ | ||
727 | card->u.c.usedby = API; | ||
728 | } | ||
729 | |||
730 | if(!card->wandev.clocking) { | ||
731 | printk(KERN_INFO | ||
732 | "%s: Asynch. clocking must be 'Internal'\n", | ||
733 | wandev->name); | ||
734 | kfree(chdlc_priv_area); | ||
735 | return -EINVAL; | ||
736 | } | ||
737 | |||
738 | if((card->wandev.bps < MIN_ASY_BAUD_RATE) || | ||
739 | (card->wandev.bps > MAX_ASY_BAUD_RATE)) { | ||
740 | printk(KERN_INFO "%s: Selected baud rate is invalid.\n", | ||
741 | wandev->name); | ||
742 | printk(KERN_INFO "Must be between %u and %u bps.\n", | ||
743 | MIN_ASY_BAUD_RATE, MAX_ASY_BAUD_RATE); | ||
744 | kfree(chdlc_priv_area); | ||
745 | return -EINVAL; | ||
746 | } | ||
747 | |||
748 | card->u.c.api_options = 0; | ||
749 | if (conf->asy_data_trans == WANOPT_YES) { | ||
750 | card->u.c.api_options |= ASY_RX_DATA_TRANSPARENT; | ||
751 | } | ||
752 | |||
753 | card->u.c.protocol_options = 0; | ||
754 | if (conf->rts_hs_for_receive == WANOPT_YES) { | ||
755 | card->u.c.protocol_options |= ASY_RTS_HS_FOR_RX; | ||
756 | } | ||
757 | if (conf->xon_xoff_hs_for_receive == WANOPT_YES) { | ||
758 | card->u.c.protocol_options |= ASY_XON_XOFF_HS_FOR_RX; | ||
759 | } | ||
760 | if (conf->xon_xoff_hs_for_transmit == WANOPT_YES) { | ||
761 | card->u.c.protocol_options |= ASY_XON_XOFF_HS_FOR_TX; | ||
762 | } | ||
763 | if (conf->dcd_hs_for_transmit == WANOPT_YES) { | ||
764 | card->u.c.protocol_options |= ASY_DCD_HS_FOR_TX; | ||
765 | } | ||
766 | if (conf->cts_hs_for_transmit == WANOPT_YES) { | ||
767 | card->u.c.protocol_options |= ASY_CTS_HS_FOR_TX; | ||
768 | } | ||
769 | |||
770 | card->u.c.tx_bits_per_char = conf->tx_bits_per_char; | ||
771 | card->u.c.rx_bits_per_char = conf->rx_bits_per_char; | ||
772 | card->u.c.stop_bits = conf->stop_bits; | ||
773 | card->u.c.parity = conf->parity; | ||
774 | card->u.c.break_timer = conf->break_timer; | ||
775 | card->u.c.inter_char_timer = conf->inter_char_timer; | ||
776 | card->u.c.rx_complete_length = conf->rx_complete_length; | ||
777 | card->u.c.xon_char = conf->xon_char; | ||
778 | |||
779 | } else { /* setup for synchronous mode */ | ||
780 | |||
781 | card->u.c.protocol_options = 0; | ||
782 | if (conf->ignore_dcd == WANOPT_YES){ | ||
783 | card->u.c.protocol_options |= IGNORE_DCD_FOR_LINK_STAT; | ||
784 | } | ||
785 | if (conf->ignore_cts == WANOPT_YES){ | ||
786 | card->u.c.protocol_options |= IGNORE_CTS_FOR_LINK_STAT; | ||
787 | } | ||
788 | |||
789 | if (conf->ignore_keepalive == WANOPT_YES) { | ||
790 | card->u.c.protocol_options |= | ||
791 | IGNORE_KPALV_FOR_LINK_STAT; | ||
792 | card->u.c.kpalv_tx = MIN_Tx_KPALV_TIMER; | ||
793 | card->u.c.kpalv_rx = MIN_Rx_KPALV_TIMER; | ||
794 | card->u.c.kpalv_err = MIN_KPALV_ERR_TOL; | ||
795 | |||
796 | } else { /* Do not ignore keepalives */ | ||
797 | card->u.c.kpalv_tx = | ||
798 | ((conf->keepalive_tx_tmr - MIN_Tx_KPALV_TIMER) | ||
799 | >= 0) ? | ||
800 | min_t(unsigned int, conf->keepalive_tx_tmr,MAX_Tx_KPALV_TIMER) : | ||
801 | DEFAULT_Tx_KPALV_TIMER; | ||
802 | |||
803 | card->u.c.kpalv_rx = | ||
804 | ((conf->keepalive_rx_tmr - MIN_Rx_KPALV_TIMER) | ||
805 | >= 0) ? | ||
806 | min_t(unsigned int, conf->keepalive_rx_tmr,MAX_Rx_KPALV_TIMER) : | ||
807 | DEFAULT_Rx_KPALV_TIMER; | ||
808 | |||
809 | card->u.c.kpalv_err = | ||
810 | ((conf->keepalive_err_margin-MIN_KPALV_ERR_TOL) | ||
811 | >= 0) ? | ||
812 | min_t(unsigned int, conf->keepalive_err_margin, | ||
813 | MAX_KPALV_ERR_TOL) : | ||
814 | DEFAULT_KPALV_ERR_TOL; | ||
815 | } | ||
816 | |||
817 | /* Setup slarp timer to control delay between slarps */ | ||
818 | card->u.c.slarp_timer = | ||
819 | ((conf->slarp_timer - MIN_SLARP_REQ_TIMER) >= 0) ? | ||
820 | min_t(unsigned int, conf->slarp_timer, MAX_SLARP_REQ_TIMER) : | ||
821 | DEFAULT_SLARP_REQ_TIMER; | ||
822 | |||
823 | if (conf->hdlc_streaming == WANOPT_YES) { | ||
824 | printk(KERN_INFO "%s: Enabling HDLC STREAMING Mode\n", | ||
825 | wandev->name); | ||
826 | card->u.c.protocol_options = HDLC_STREAMING_MODE; | ||
827 | } | ||
828 | |||
829 | if ((chdlc_priv_area->true_if_encoding = conf->true_if_encoding) == WANOPT_YES){ | ||
830 | printk(KERN_INFO | ||
831 | "%s: Enabling, true interface type encoding.\n", | ||
832 | card->devname); | ||
833 | } | ||
834 | |||
835 | /* Setup wanpipe as a router (WANPIPE) or as an API */ | ||
836 | if( strcmp(conf->usedby, "WANPIPE") == 0) { | ||
837 | |||
838 | printk(KERN_INFO "%s: Running in WANPIPE mode!\n", | ||
839 | wandev->name); | ||
840 | card->u.c.usedby = WANPIPE; | ||
841 | |||
842 | /* Option to bring down the interface when | ||
843 | * the link goes down */ | ||
844 | if (conf->if_down){ | ||
845 | set_bit(DYN_OPT_ON,&chdlc_priv_area->interface_down); | ||
846 | printk(KERN_INFO | ||
847 | "%s: Dynamic interface configuration enabled\n", | ||
848 | card->devname); | ||
849 | } | ||
850 | |||
851 | } else if( strcmp(conf->usedby, "API") == 0) { | ||
852 | card->u.c.usedby = API; | ||
853 | printk(KERN_INFO "%s: Running in API mode !\n", | ||
854 | wandev->name); | ||
855 | } | ||
856 | } | ||
857 | |||
858 | /* Tells us that if this interface is a | ||
859 | * gateway or not */ | ||
860 | if ((chdlc_priv_area->gateway = conf->gateway) == WANOPT_YES){ | ||
861 | printk(KERN_INFO "%s: Interface %s is set as a gateway.\n", | ||
862 | card->devname,card->u.c.if_name); | ||
863 | } | ||
864 | |||
865 | /* Get Multicast Information */ | ||
866 | chdlc_priv_area->mc = conf->mc; | ||
867 | |||
868 | /* prepare network device data space for registration */ | ||
869 | strcpy(dev->name,card->u.c.if_name); | ||
870 | |||
871 | dev->init = &if_init; | ||
872 | dev->priv = chdlc_priv_area; | ||
873 | |||
874 | /* Initialize the polling work routine */ | ||
875 | INIT_WORK(&chdlc_priv_area->poll_work, (void*)(void*)chdlc_poll, dev); | ||
876 | |||
877 | /* Initialize the polling delay timer */ | ||
878 | init_timer(&chdlc_priv_area->poll_delay_timer); | ||
879 | chdlc_priv_area->poll_delay_timer.data = (unsigned long)dev; | ||
880 | chdlc_priv_area->poll_delay_timer.function = chdlc_poll_delay; | ||
881 | |||
882 | printk(KERN_INFO "\n"); | ||
883 | |||
884 | return 0; | ||
885 | } | ||
886 | |||
887 | |||
888 | /****** Network Device Interface ********************************************/ | ||
889 | |||
890 | /*============================================================================ | ||
891 | * Initialize Linux network interface. | ||
892 | * | ||
893 | * This routine is called only once for each interface, during Linux network | ||
894 | * interface registration. Returning anything but zero will fail interface | ||
895 | * registration. | ||
896 | */ | ||
897 | static int if_init(struct net_device* dev) | ||
898 | { | ||
899 | chdlc_private_area_t* chdlc_priv_area = dev->priv; | ||
900 | sdla_t* card = chdlc_priv_area->card; | ||
901 | struct wan_device* wandev = &card->wandev; | ||
902 | |||
903 | /* Initialize device driver entry points */ | ||
904 | dev->open = &if_open; | ||
905 | dev->stop = &if_close; | ||
906 | dev->hard_header = &if_header; | ||
907 | dev->rebuild_header = &if_rebuild_hdr; | ||
908 | dev->hard_start_xmit = &if_send; | ||
909 | dev->get_stats = &if_stats; | ||
910 | dev->tx_timeout = &if_tx_timeout; | ||
911 | dev->watchdog_timeo = TX_TIMEOUT; | ||
912 | |||
913 | /* Initialize media-specific parameters */ | ||
914 | dev->flags |= IFF_POINTOPOINT; | ||
915 | dev->flags |= IFF_NOARP; | ||
916 | |||
917 | /* Enable Mulitcasting if user selected */ | ||
918 | if (chdlc_priv_area->mc == WANOPT_YES){ | ||
919 | dev->flags |= IFF_MULTICAST; | ||
920 | } | ||
921 | |||
922 | if (chdlc_priv_area->true_if_encoding){ | ||
923 | dev->type = ARPHRD_HDLC; /* This breaks the tcpdump */ | ||
924 | }else{ | ||
925 | dev->type = ARPHRD_PPP; | ||
926 | } | ||
927 | |||
928 | dev->mtu = card->wandev.mtu; | ||
929 | /* for API usage, add the API header size to the requested MTU size */ | ||
930 | if(card->u.c.usedby == API) { | ||
931 | dev->mtu += sizeof(api_tx_hdr_t); | ||
932 | } | ||
933 | |||
934 | dev->hard_header_len = CHDLC_HDR_LEN; | ||
935 | |||
936 | /* Initialize hardware parameters */ | ||
937 | dev->irq = wandev->irq; | ||
938 | dev->dma = wandev->dma; | ||
939 | dev->base_addr = wandev->ioport; | ||
940 | dev->mem_start = wandev->maddr; | ||
941 | dev->mem_end = wandev->maddr + wandev->msize - 1; | ||
942 | |||
943 | /* Set transmit buffer queue length | ||
944 | * If too low packets will not be retransmitted | ||
945 | * by stack. | ||
946 | */ | ||
947 | dev->tx_queue_len = 100; | ||
948 | SET_MODULE_OWNER(dev); | ||
949 | |||
950 | return 0; | ||
951 | } | ||
952 | |||
953 | /*============================================================================ | ||
954 | * Open network interface. | ||
955 | * o enable communications and interrupts. | ||
956 | * o prevent module from unloading by incrementing use count | ||
957 | * | ||
958 | * Return 0 if O.k. or errno. | ||
959 | */ | ||
960 | static int if_open(struct net_device* dev) | ||
961 | { | ||
962 | chdlc_private_area_t* chdlc_priv_area = dev->priv; | ||
963 | sdla_t* card = chdlc_priv_area->card; | ||
964 | struct timeval tv; | ||
965 | int err = 0; | ||
966 | |||
967 | /* Only one open per interface is allowed */ | ||
968 | |||
969 | if (netif_running(dev)) | ||
970 | return -EBUSY; | ||
971 | |||
972 | /* Initialize the work queue entry */ | ||
973 | chdlc_priv_area->tq_working=0; | ||
974 | |||
975 | INIT_WORK(&chdlc_priv_area->common.wanpipe_work, | ||
976 | (void *)(void *)chdlc_work, dev); | ||
977 | |||
978 | /* Allocate and initialize BH circular buffer */ | ||
979 | /* Add 1 to MAX_BH_BUFF so we don't have test with (MAX_BH_BUFF-1) */ | ||
980 | chdlc_priv_area->bh_head = kmalloc((sizeof(bh_data_t)*(MAX_BH_BUFF+1)),GFP_ATOMIC); | ||
981 | memset(chdlc_priv_area->bh_head,0,(sizeof(bh_data_t)*(MAX_BH_BUFF+1))); | ||
982 | atomic_set(&chdlc_priv_area->bh_buff_used, 0); | ||
983 | |||
984 | do_gettimeofday(&tv); | ||
985 | chdlc_priv_area->router_start_time = tv.tv_sec; | ||
986 | |||
987 | netif_start_queue(dev); | ||
988 | |||
989 | wanpipe_open(card); | ||
990 | |||
991 | /* TTY is configured during wanpipe_set_termios | ||
992 | * call, not here */ | ||
993 | if (card->tty_opt) | ||
994 | return err; | ||
995 | |||
996 | set_bit(0,&chdlc_priv_area->config_chdlc); | ||
997 | chdlc_priv_area->config_chdlc_timeout=jiffies; | ||
998 | |||
999 | /* Start the CHDLC configuration after 1sec delay. | ||
1000 | * This will give the interface initilization time | ||
1001 | * to finish its configuration */ | ||
1002 | mod_timer(&chdlc_priv_area->poll_delay_timer, jiffies + HZ); | ||
1003 | return err; | ||
1004 | } | ||
1005 | |||
1006 | /*============================================================================ | ||
1007 | * Close network interface. | ||
1008 | * o if this is the last close, then disable communications and interrupts. | ||
1009 | * o reset flags. | ||
1010 | */ | ||
1011 | static int if_close(struct net_device* dev) | ||
1012 | { | ||
1013 | chdlc_private_area_t* chdlc_priv_area = dev->priv; | ||
1014 | sdla_t* card = chdlc_priv_area->card; | ||
1015 | |||
1016 | if (chdlc_priv_area->bh_head){ | ||
1017 | int i; | ||
1018 | struct sk_buff *skb; | ||
1019 | |||
1020 | for (i=0; i<(MAX_BH_BUFF+1); i++){ | ||
1021 | skb = ((bh_data_t *)&chdlc_priv_area->bh_head[i])->skb; | ||
1022 | if (skb != NULL){ | ||
1023 | dev_kfree_skb_any(skb); | ||
1024 | } | ||
1025 | } | ||
1026 | kfree(chdlc_priv_area->bh_head); | ||
1027 | chdlc_priv_area->bh_head=NULL; | ||
1028 | } | ||
1029 | |||
1030 | netif_stop_queue(dev); | ||
1031 | wanpipe_close(card); | ||
1032 | del_timer(&chdlc_priv_area->poll_delay_timer); | ||
1033 | return 0; | ||
1034 | } | ||
1035 | |||
1036 | static void disable_comm (sdla_t *card) | ||
1037 | { | ||
1038 | SHARED_MEMORY_INFO_STRUCT *flags = card->u.c.flags; | ||
1039 | |||
1040 | if (card->u.c.comm_enabled){ | ||
1041 | chdlc_disable_comm_shutdown (card); | ||
1042 | }else{ | ||
1043 | flags->interrupt_info_struct.interrupt_permission = 0; | ||
1044 | } | ||
1045 | |||
1046 | if (!tty_init_cnt) | ||
1047 | return; | ||
1048 | |||
1049 | if (card->tty_opt){ | ||
1050 | struct serial_state * state; | ||
1051 | if (!(--tty_init_cnt)){ | ||
1052 | int e1; | ||
1053 | serial_driver.refcount=0; | ||
1054 | |||
1055 | if ((e1 = tty_unregister_driver(&serial_driver))) | ||
1056 | printk("SERIAL: failed to unregister serial driver (%d)\n", | ||
1057 | e1); | ||
1058 | printk(KERN_INFO "%s: Unregistering TTY Driver, Major %i\n", | ||
1059 | card->devname,WAN_TTY_MAJOR); | ||
1060 | } | ||
1061 | card->tty=NULL; | ||
1062 | tty_card_map[card->tty_minor]=NULL; | ||
1063 | state = &rs_table[card->tty_minor]; | ||
1064 | memset(state, 0, sizeof(*state)); | ||
1065 | } | ||
1066 | return; | ||
1067 | } | ||
1068 | |||
1069 | |||
1070 | /*============================================================================ | ||
1071 | * Build media header. | ||
1072 | * | ||
1073 | * The trick here is to put packet type (Ethertype) into 'protocol' field of | ||
1074 | * the socket buffer, so that we don't forget it. If packet type is not | ||
1075 | * supported, set skb->protocol to 0 and discard packet later. | ||
1076 | * | ||
1077 | * Return: media header length. | ||
1078 | */ | ||
1079 | static int if_header(struct sk_buff* skb, struct net_device* dev, | ||
1080 | unsigned short type, void* daddr, void* saddr, | ||
1081 | unsigned len) | ||
1082 | { | ||
1083 | skb->protocol = htons(type); | ||
1084 | |||
1085 | return CHDLC_HDR_LEN; | ||
1086 | } | ||
1087 | |||
1088 | |||
1089 | /*============================================================================ | ||
1090 | * Handle transmit timeout event from netif watchdog | ||
1091 | */ | ||
1092 | static void if_tx_timeout(struct net_device *dev) | ||
1093 | { | ||
1094 | chdlc_private_area_t* chan = dev->priv; | ||
1095 | sdla_t *card = chan->card; | ||
1096 | |||
1097 | /* If our device stays busy for at least 5 seconds then we will | ||
1098 | * kick start the device by making dev->tbusy = 0. We expect | ||
1099 | * that our device never stays busy more than 5 seconds. So this | ||
1100 | * is only used as a last resort. | ||
1101 | */ | ||
1102 | |||
1103 | ++card->wandev.stats.collisions; | ||
1104 | |||
1105 | printk (KERN_INFO "%s: Transmit timed out on %s\n", card->devname,dev->name); | ||
1106 | netif_wake_queue (dev); | ||
1107 | } | ||
1108 | |||
1109 | |||
1110 | |||
1111 | /*============================================================================ | ||
1112 | * Re-build media header. | ||
1113 | * | ||
1114 | * Return: 1 physical address resolved. | ||
1115 | * 0 physical address not resolved | ||
1116 | */ | ||
1117 | static int if_rebuild_hdr (struct sk_buff *skb) | ||
1118 | { | ||
1119 | return 1; | ||
1120 | } | ||
1121 | |||
1122 | |||
1123 | /*============================================================================ | ||
1124 | * Send a packet on a network interface. | ||
1125 | * o set tbusy flag (marks start of the transmission) to block a timer-based | ||
1126 | * transmit from overlapping. | ||
1127 | * o check link state. If link is not up, then drop the packet. | ||
1128 | * o execute adapter send command. | ||
1129 | * o free socket buffer | ||
1130 | * | ||
1131 | * Return: 0 complete (socket buffer must be freed) | ||
1132 | * non-0 packet may be re-transmitted (tbusy must be set) | ||
1133 | * | ||
1134 | * Notes: | ||
1135 | * 1. This routine is called either by the protocol stack or by the "net | ||
1136 | * bottom half" (with interrupts enabled). | ||
1137 | * 2. Setting tbusy flag will inhibit further transmit requests from the | ||
1138 | * protocol stack and can be used for flow control with protocol layer. | ||
1139 | */ | ||
1140 | static int if_send(struct sk_buff* skb, struct net_device* dev) | ||
1141 | { | ||
1142 | chdlc_private_area_t *chdlc_priv_area = dev->priv; | ||
1143 | sdla_t *card = chdlc_priv_area->card; | ||
1144 | SHARED_MEMORY_INFO_STRUCT *flags = card->u.c.flags; | ||
1145 | INTERRUPT_INFORMATION_STRUCT *chdlc_int = &flags->interrupt_info_struct; | ||
1146 | int udp_type = 0; | ||
1147 | unsigned long smp_flags; | ||
1148 | int err=0; | ||
1149 | |||
1150 | netif_stop_queue(dev); | ||
1151 | |||
1152 | if (skb == NULL){ | ||
1153 | /* If we get here, some higher layer thinks we've missed an | ||
1154 | * tx-done interrupt. | ||
1155 | */ | ||
1156 | printk(KERN_INFO "%s: interface %s got kicked!\n", | ||
1157 | card->devname, dev->name); | ||
1158 | |||
1159 | netif_wake_queue(dev); | ||
1160 | return 0; | ||
1161 | } | ||
1162 | |||
1163 | if (ntohs(skb->protocol) != htons(PVC_PROT)){ | ||
1164 | |||
1165 | /* check the udp packet type */ | ||
1166 | |||
1167 | udp_type = udp_pkt_type(skb, card); | ||
1168 | |||
1169 | if (udp_type == UDP_CPIPE_TYPE){ | ||
1170 | if(store_udp_mgmt_pkt(UDP_PKT_FRM_STACK, card, skb, dev, | ||
1171 | chdlc_priv_area)){ | ||
1172 | chdlc_int->interrupt_permission |= | ||
1173 | APP_INT_ON_TIMER; | ||
1174 | } | ||
1175 | netif_start_queue(dev); | ||
1176 | return 0; | ||
1177 | } | ||
1178 | |||
1179 | /* check to see if the source IP address is a broadcast or */ | ||
1180 | /* multicast IP address */ | ||
1181 | if(chk_bcast_mcast_addr(card, dev, skb)){ | ||
1182 | ++card->wandev.stats.tx_dropped; | ||
1183 | dev_kfree_skb_any(skb); | ||
1184 | netif_start_queue(dev); | ||
1185 | return 0; | ||
1186 | } | ||
1187 | } | ||
1188 | |||
1189 | /* Lock the 508 Card: SMP is supported */ | ||
1190 | if(card->hw.type != SDLA_S514){ | ||
1191 | s508_lock(card,&smp_flags); | ||
1192 | } | ||
1193 | |||
1194 | if(test_and_set_bit(SEND_CRIT, (void*)&card->wandev.critical)) { | ||
1195 | |||
1196 | printk(KERN_INFO "%s: Critical in if_send: %lx\n", | ||
1197 | card->wandev.name,card->wandev.critical); | ||
1198 | ++card->wandev.stats.tx_dropped; | ||
1199 | netif_start_queue(dev); | ||
1200 | goto if_send_exit_crit; | ||
1201 | } | ||
1202 | |||
1203 | if(card->u.c.state != WAN_CONNECTED){ | ||
1204 | ++card->wandev.stats.tx_dropped; | ||
1205 | netif_start_queue(dev); | ||
1206 | |||
1207 | }else if(!skb->protocol){ | ||
1208 | ++card->wandev.stats.tx_errors; | ||
1209 | netif_start_queue(dev); | ||
1210 | |||
1211 | }else { | ||
1212 | void* data = skb->data; | ||
1213 | unsigned len = skb->len; | ||
1214 | unsigned char attr; | ||
1215 | |||
1216 | /* If it's an API packet pull off the API | ||
1217 | * header. Also check that the packet size | ||
1218 | * is larger than the API header | ||
1219 | */ | ||
1220 | if (card->u.c.usedby == API){ | ||
1221 | api_tx_hdr_t* api_tx_hdr; | ||
1222 | |||
1223 | /* discard the frame if we are configured for */ | ||
1224 | /* 'receive only' mode or if there is no data */ | ||
1225 | if (card->u.c.receive_only || | ||
1226 | (len <= sizeof(api_tx_hdr_t))) { | ||
1227 | |||
1228 | ++card->wandev.stats.tx_dropped; | ||
1229 | netif_start_queue(dev); | ||
1230 | goto if_send_exit_crit; | ||
1231 | } | ||
1232 | |||
1233 | api_tx_hdr = (api_tx_hdr_t *)data; | ||
1234 | attr = api_tx_hdr->attr; | ||
1235 | data += sizeof(api_tx_hdr_t); | ||
1236 | len -= sizeof(api_tx_hdr_t); | ||
1237 | } | ||
1238 | |||
1239 | if(chdlc_send(card, data, len)) { | ||
1240 | netif_stop_queue(dev); | ||
1241 | }else{ | ||
1242 | ++card->wandev.stats.tx_packets; | ||
1243 | card->wandev.stats.tx_bytes += len; | ||
1244 | |||
1245 | netif_start_queue(dev); | ||
1246 | |||
1247 | dev->trans_start = jiffies; | ||
1248 | } | ||
1249 | } | ||
1250 | |||
1251 | if_send_exit_crit: | ||
1252 | |||
1253 | if (!(err=netif_queue_stopped(dev))) { | ||
1254 | dev_kfree_skb_any(skb); | ||
1255 | }else{ | ||
1256 | chdlc_priv_area->tick_counter = jiffies; | ||
1257 | chdlc_int->interrupt_permission |= APP_INT_ON_TX_FRAME; | ||
1258 | } | ||
1259 | |||
1260 | clear_bit(SEND_CRIT, (void*)&card->wandev.critical); | ||
1261 | if(card->hw.type != SDLA_S514){ | ||
1262 | s508_unlock(card,&smp_flags); | ||
1263 | } | ||
1264 | |||
1265 | return err; | ||
1266 | } | ||
1267 | |||
1268 | |||
1269 | /*============================================================================ | ||
1270 | * Check to see if the packet to be transmitted contains a broadcast or | ||
1271 | * multicast source IP address. | ||
1272 | */ | ||
1273 | |||
1274 | static int chk_bcast_mcast_addr(sdla_t *card, struct net_device* dev, | ||
1275 | struct sk_buff *skb) | ||
1276 | { | ||
1277 | u32 src_ip_addr; | ||
1278 | u32 broadcast_ip_addr = 0; | ||
1279 | struct in_device *in_dev; | ||
1280 | |||
1281 | /* read the IP source address from the outgoing packet */ | ||
1282 | src_ip_addr = *(u32 *)(skb->data + 12); | ||
1283 | |||
1284 | /* read the IP broadcast address for the device */ | ||
1285 | in_dev = dev->ip_ptr; | ||
1286 | if(in_dev != NULL) { | ||
1287 | struct in_ifaddr *ifa= in_dev->ifa_list; | ||
1288 | if(ifa != NULL) | ||
1289 | broadcast_ip_addr = ifa->ifa_broadcast; | ||
1290 | else | ||
1291 | return 0; | ||
1292 | } | ||
1293 | |||
1294 | /* check if the IP Source Address is a Broadcast address */ | ||
1295 | if((dev->flags & IFF_BROADCAST) && (src_ip_addr == broadcast_ip_addr)) { | ||
1296 | printk(KERN_INFO "%s: Broadcast Source Address silently discarded\n", | ||
1297 | card->devname); | ||
1298 | return 1; | ||
1299 | } | ||
1300 | |||
1301 | /* check if the IP Source Address is a Multicast address */ | ||
1302 | if((ntohl(src_ip_addr) >= 0xE0000001) && | ||
1303 | (ntohl(src_ip_addr) <= 0xFFFFFFFE)) { | ||
1304 | printk(KERN_INFO "%s: Multicast Source Address silently discarded\n", | ||
1305 | card->devname); | ||
1306 | return 1; | ||
1307 | } | ||
1308 | |||
1309 | return 0; | ||
1310 | } | ||
1311 | |||
1312 | |||
1313 | /*============================================================================ | ||
1314 | * Reply to UDP Management system. | ||
1315 | * Return length of reply. | ||
1316 | */ | ||
1317 | static int reply_udp( unsigned char *data, unsigned int mbox_len ) | ||
1318 | { | ||
1319 | |||
1320 | unsigned short len, udp_length, temp, ip_length; | ||
1321 | unsigned long ip_temp; | ||
1322 | int even_bound = 0; | ||
1323 | chdlc_udp_pkt_t *c_udp_pkt = (chdlc_udp_pkt_t *)data; | ||
1324 | |||
1325 | /* Set length of packet */ | ||
1326 | len = sizeof(ip_pkt_t)+ | ||
1327 | sizeof(udp_pkt_t)+ | ||
1328 | sizeof(wp_mgmt_t)+ | ||
1329 | sizeof(cblock_t)+ | ||
1330 | sizeof(trace_info_t)+ | ||
1331 | mbox_len; | ||
1332 | |||
1333 | /* fill in UDP reply */ | ||
1334 | c_udp_pkt->wp_mgmt.request_reply = UDPMGMT_REPLY; | ||
1335 | |||
1336 | /* fill in UDP length */ | ||
1337 | udp_length = sizeof(udp_pkt_t)+ | ||
1338 | sizeof(wp_mgmt_t)+ | ||
1339 | sizeof(cblock_t)+ | ||
1340 | sizeof(trace_info_t)+ | ||
1341 | mbox_len; | ||
1342 | |||
1343 | /* put it on an even boundary */ | ||
1344 | if ( udp_length & 0x0001 ) { | ||
1345 | udp_length += 1; | ||
1346 | len += 1; | ||
1347 | even_bound = 1; | ||
1348 | } | ||
1349 | |||
1350 | temp = (udp_length<<8)|(udp_length>>8); | ||
1351 | c_udp_pkt->udp_pkt.udp_length = temp; | ||
1352 | |||
1353 | /* swap UDP ports */ | ||
1354 | temp = c_udp_pkt->udp_pkt.udp_src_port; | ||
1355 | c_udp_pkt->udp_pkt.udp_src_port = | ||
1356 | c_udp_pkt->udp_pkt.udp_dst_port; | ||
1357 | c_udp_pkt->udp_pkt.udp_dst_port = temp; | ||
1358 | |||
1359 | /* add UDP pseudo header */ | ||
1360 | temp = 0x1100; | ||
1361 | *((unsigned short *)(c_udp_pkt->data+mbox_len+even_bound)) = temp; | ||
1362 | temp = (udp_length<<8)|(udp_length>>8); | ||
1363 | *((unsigned short *)(c_udp_pkt->data+mbox_len+even_bound+2)) = temp; | ||
1364 | |||
1365 | |||
1366 | /* calculate UDP checksum */ | ||
1367 | c_udp_pkt->udp_pkt.udp_checksum = 0; | ||
1368 | c_udp_pkt->udp_pkt.udp_checksum = calc_checksum(&data[UDP_OFFSET],udp_length+UDP_OFFSET); | ||
1369 | |||
1370 | /* fill in IP length */ | ||
1371 | ip_length = len; | ||
1372 | temp = (ip_length<<8)|(ip_length>>8); | ||
1373 | c_udp_pkt->ip_pkt.total_length = temp; | ||
1374 | |||
1375 | /* swap IP addresses */ | ||
1376 | ip_temp = c_udp_pkt->ip_pkt.ip_src_address; | ||
1377 | c_udp_pkt->ip_pkt.ip_src_address = c_udp_pkt->ip_pkt.ip_dst_address; | ||
1378 | c_udp_pkt->ip_pkt.ip_dst_address = ip_temp; | ||
1379 | |||
1380 | /* fill in IP checksum */ | ||
1381 | c_udp_pkt->ip_pkt.hdr_checksum = 0; | ||
1382 | c_udp_pkt->ip_pkt.hdr_checksum = calc_checksum(data,sizeof(ip_pkt_t)); | ||
1383 | |||
1384 | return len; | ||
1385 | |||
1386 | } /* reply_udp */ | ||
1387 | |||
1388 | unsigned short calc_checksum (char *data, int len) | ||
1389 | { | ||
1390 | unsigned short temp; | ||
1391 | unsigned long sum=0; | ||
1392 | int i; | ||
1393 | |||
1394 | for( i = 0; i <len; i+=2 ) { | ||
1395 | memcpy(&temp,&data[i],2); | ||
1396 | sum += (unsigned long)temp; | ||
1397 | } | ||
1398 | |||
1399 | while (sum >> 16 ) { | ||
1400 | sum = (sum & 0xffffUL) + (sum >> 16); | ||
1401 | } | ||
1402 | |||
1403 | temp = (unsigned short)sum; | ||
1404 | temp = ~temp; | ||
1405 | |||
1406 | if( temp == 0 ) | ||
1407 | temp = 0xffff; | ||
1408 | |||
1409 | return temp; | ||
1410 | } | ||
1411 | |||
1412 | |||
1413 | /*============================================================================ | ||
1414 | * Get ethernet-style interface statistics. | ||
1415 | * Return a pointer to struct enet_statistics. | ||
1416 | */ | ||
1417 | static struct net_device_stats* if_stats(struct net_device* dev) | ||
1418 | { | ||
1419 | sdla_t *my_card; | ||
1420 | chdlc_private_area_t* chdlc_priv_area; | ||
1421 | |||
1422 | if ((chdlc_priv_area=dev->priv) == NULL) | ||
1423 | return NULL; | ||
1424 | |||
1425 | my_card = chdlc_priv_area->card; | ||
1426 | return &my_card->wandev.stats; | ||
1427 | } | ||
1428 | |||
1429 | |||
1430 | /****** Cisco HDLC Firmware Interface Functions *******************************/ | ||
1431 | |||
1432 | /*============================================================================ | ||
1433 | * Read firmware code version. | ||
1434 | * Put code version as ASCII string in str. | ||
1435 | */ | ||
1436 | static int chdlc_read_version (sdla_t* card, char* str) | ||
1437 | { | ||
1438 | CHDLC_MAILBOX_STRUCT* mb = card->mbox; | ||
1439 | int len; | ||
1440 | char err; | ||
1441 | mb->buffer_length = 0; | ||
1442 | mb->command = READ_CHDLC_CODE_VERSION; | ||
1443 | err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; | ||
1444 | |||
1445 | if(err != COMMAND_OK) { | ||
1446 | chdlc_error(card,err,mb); | ||
1447 | } | ||
1448 | else if (str) { /* is not null */ | ||
1449 | len = mb->buffer_length; | ||
1450 | memcpy(str, mb->data, len); | ||
1451 | str[len] = '\0'; | ||
1452 | } | ||
1453 | return (err); | ||
1454 | } | ||
1455 | |||
1456 | /*----------------------------------------------------------------------------- | ||
1457 | * Configure CHDLC firmware. | ||
1458 | */ | ||
1459 | static int chdlc_configure (sdla_t* card, void* data) | ||
1460 | { | ||
1461 | int err; | ||
1462 | CHDLC_MAILBOX_STRUCT *mailbox = card->mbox; | ||
1463 | int data_length = sizeof(CHDLC_CONFIGURATION_STRUCT); | ||
1464 | |||
1465 | mailbox->buffer_length = data_length; | ||
1466 | memcpy(mailbox->data, data, data_length); | ||
1467 | mailbox->command = SET_CHDLC_CONFIGURATION; | ||
1468 | err = sdla_exec(mailbox) ? mailbox->return_code : CMD_TIMEOUT; | ||
1469 | |||
1470 | if (err != COMMAND_OK) chdlc_error (card, err, mailbox); | ||
1471 | |||
1472 | return err; | ||
1473 | } | ||
1474 | |||
1475 | |||
1476 | /*============================================================================ | ||
1477 | * Set interrupt mode -- HDLC Version. | ||
1478 | */ | ||
1479 | |||
1480 | static int chdlc_set_intr_mode (sdla_t* card, unsigned mode) | ||
1481 | { | ||
1482 | CHDLC_MAILBOX_STRUCT* mb = card->mbox; | ||
1483 | CHDLC_INT_TRIGGERS_STRUCT* int_data = | ||
1484 | (CHDLC_INT_TRIGGERS_STRUCT *)mb->data; | ||
1485 | int err; | ||
1486 | |||
1487 | int_data->CHDLC_interrupt_triggers = mode; | ||
1488 | int_data->IRQ = card->hw.irq; | ||
1489 | int_data->interrupt_timer = 1; | ||
1490 | |||
1491 | mb->buffer_length = sizeof(CHDLC_INT_TRIGGERS_STRUCT); | ||
1492 | mb->command = SET_CHDLC_INTERRUPT_TRIGGERS; | ||
1493 | err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; | ||
1494 | if (err != COMMAND_OK) | ||
1495 | chdlc_error (card, err, mb); | ||
1496 | return err; | ||
1497 | } | ||
1498 | |||
1499 | |||
1500 | /*=========================================================== | ||
1501 | * chdlc_disable_comm_shutdown | ||
1502 | * | ||
1503 | * Shutdown() disables the communications. We must | ||
1504 | * have a sparate functions, because we must not | ||
1505 | * call chdlc_error() hander since the private | ||
1506 | * area has already been replaced */ | ||
1507 | |||
1508 | static int chdlc_disable_comm_shutdown (sdla_t *card) | ||
1509 | { | ||
1510 | CHDLC_MAILBOX_STRUCT* mb = card->mbox; | ||
1511 | CHDLC_INT_TRIGGERS_STRUCT* int_data = | ||
1512 | (CHDLC_INT_TRIGGERS_STRUCT *)mb->data; | ||
1513 | int err; | ||
1514 | |||
1515 | /* Disable Interrutps */ | ||
1516 | int_data->CHDLC_interrupt_triggers = 0; | ||
1517 | int_data->IRQ = card->hw.irq; | ||
1518 | int_data->interrupt_timer = 1; | ||
1519 | |||
1520 | mb->buffer_length = sizeof(CHDLC_INT_TRIGGERS_STRUCT); | ||
1521 | mb->command = SET_CHDLC_INTERRUPT_TRIGGERS; | ||
1522 | err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; | ||
1523 | |||
1524 | /* Disable Communications */ | ||
1525 | |||
1526 | if (card->u.c.async_mode) { | ||
1527 | mb->command = DISABLE_ASY_COMMUNICATIONS; | ||
1528 | }else{ | ||
1529 | mb->command = DISABLE_CHDLC_COMMUNICATIONS; | ||
1530 | } | ||
1531 | |||
1532 | mb->buffer_length = 0; | ||
1533 | err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; | ||
1534 | |||
1535 | card->u.c.comm_enabled = 0; | ||
1536 | |||
1537 | return 0; | ||
1538 | } | ||
1539 | |||
1540 | /*============================================================================ | ||
1541 | * Enable communications. | ||
1542 | */ | ||
1543 | |||
1544 | static int chdlc_comm_enable (sdla_t* card) | ||
1545 | { | ||
1546 | int err; | ||
1547 | CHDLC_MAILBOX_STRUCT* mb = card->mbox; | ||
1548 | |||
1549 | mb->buffer_length = 0; | ||
1550 | mb->command = ENABLE_CHDLC_COMMUNICATIONS; | ||
1551 | err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; | ||
1552 | if (err != COMMAND_OK) | ||
1553 | chdlc_error(card, err, mb); | ||
1554 | else | ||
1555 | card->u.c.comm_enabled = 1; | ||
1556 | |||
1557 | return err; | ||
1558 | } | ||
1559 | |||
1560 | /*============================================================================ | ||
1561 | * Read communication error statistics. | ||
1562 | */ | ||
1563 | static int chdlc_read_comm_err_stats (sdla_t* card) | ||
1564 | { | ||
1565 | int err; | ||
1566 | CHDLC_MAILBOX_STRUCT* mb = card->mbox; | ||
1567 | |||
1568 | mb->buffer_length = 0; | ||
1569 | mb->command = READ_COMMS_ERROR_STATS; | ||
1570 | err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; | ||
1571 | if (err != COMMAND_OK) | ||
1572 | chdlc_error(card,err,mb); | ||
1573 | return err; | ||
1574 | } | ||
1575 | |||
1576 | |||
1577 | /*============================================================================ | ||
1578 | * Read CHDLC operational statistics. | ||
1579 | */ | ||
1580 | static int chdlc_read_op_stats (sdla_t* card) | ||
1581 | { | ||
1582 | int err; | ||
1583 | CHDLC_MAILBOX_STRUCT* mb = card->mbox; | ||
1584 | |||
1585 | mb->buffer_length = 0; | ||
1586 | mb->command = READ_CHDLC_OPERATIONAL_STATS; | ||
1587 | err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; | ||
1588 | if (err != COMMAND_OK) | ||
1589 | chdlc_error(card,err,mb); | ||
1590 | return err; | ||
1591 | } | ||
1592 | |||
1593 | |||
1594 | /*============================================================================ | ||
1595 | * Update communications error and general packet statistics. | ||
1596 | */ | ||
1597 | static int update_comms_stats(sdla_t* card, | ||
1598 | chdlc_private_area_t* chdlc_priv_area) | ||
1599 | { | ||
1600 | CHDLC_MAILBOX_STRUCT* mb = card->mbox; | ||
1601 | COMMS_ERROR_STATS_STRUCT* err_stats; | ||
1602 | CHDLC_OPERATIONAL_STATS_STRUCT *op_stats; | ||
1603 | |||
1604 | /* on the first timer interrupt, read the comms error statistics */ | ||
1605 | if(chdlc_priv_area->update_comms_stats == 2) { | ||
1606 | if(chdlc_read_comm_err_stats(card)) | ||
1607 | return 1; | ||
1608 | err_stats = (COMMS_ERROR_STATS_STRUCT *)mb->data; | ||
1609 | card->wandev.stats.rx_over_errors = | ||
1610 | err_stats->Rx_overrun_err_count; | ||
1611 | card->wandev.stats.rx_crc_errors = | ||
1612 | err_stats->CRC_err_count; | ||
1613 | card->wandev.stats.rx_frame_errors = | ||
1614 | err_stats->Rx_abort_count; | ||
1615 | card->wandev.stats.rx_fifo_errors = | ||
1616 | err_stats->Rx_dis_pri_bfrs_full_count; | ||
1617 | card->wandev.stats.rx_missed_errors = | ||
1618 | card->wandev.stats.rx_fifo_errors; | ||
1619 | card->wandev.stats.tx_aborted_errors = | ||
1620 | err_stats->sec_Tx_abort_count; | ||
1621 | } | ||
1622 | |||
1623 | /* on the second timer interrupt, read the operational statistics */ | ||
1624 | else { | ||
1625 | if(chdlc_read_op_stats(card)) | ||
1626 | return 1; | ||
1627 | op_stats = (CHDLC_OPERATIONAL_STATS_STRUCT *)mb->data; | ||
1628 | card->wandev.stats.rx_length_errors = | ||
1629 | (op_stats->Rx_Data_discard_short_count + | ||
1630 | op_stats->Rx_Data_discard_long_count); | ||
1631 | } | ||
1632 | |||
1633 | return 0; | ||
1634 | } | ||
1635 | |||
1636 | /*============================================================================ | ||
1637 | * Send packet. | ||
1638 | * Return: 0 - o.k. | ||
1639 | * 1 - no transmit buffers available | ||
1640 | */ | ||
1641 | static int chdlc_send (sdla_t* card, void* data, unsigned len) | ||
1642 | { | ||
1643 | CHDLC_DATA_TX_STATUS_EL_STRUCT *txbuf = card->u.c.txbuf; | ||
1644 | |||
1645 | if (txbuf->opp_flag) | ||
1646 | return 1; | ||
1647 | |||
1648 | sdla_poke(&card->hw, txbuf->ptr_data_bfr, data, len); | ||
1649 | |||
1650 | txbuf->frame_length = len; | ||
1651 | txbuf->opp_flag = 1; /* start transmission */ | ||
1652 | |||
1653 | /* Update transmit buffer control fields */ | ||
1654 | card->u.c.txbuf = ++txbuf; | ||
1655 | |||
1656 | if ((void*)txbuf > card->u.c.txbuf_last) | ||
1657 | card->u.c.txbuf = card->u.c.txbuf_base; | ||
1658 | |||
1659 | return 0; | ||
1660 | } | ||
1661 | |||
1662 | /****** Firmware Error Handler **********************************************/ | ||
1663 | |||
1664 | /*============================================================================ | ||
1665 | * Firmware error handler. | ||
1666 | * This routine is called whenever firmware command returns non-zero | ||
1667 | * return code. | ||
1668 | * | ||
1669 | * Return zero if previous command has to be cancelled. | ||
1670 | */ | ||
1671 | static int chdlc_error (sdla_t *card, int err, CHDLC_MAILBOX_STRUCT *mb) | ||
1672 | { | ||
1673 | unsigned cmd = mb->command; | ||
1674 | |||
1675 | switch (err) { | ||
1676 | |||
1677 | case CMD_TIMEOUT: | ||
1678 | printk(KERN_INFO "%s: command 0x%02X timed out!\n", | ||
1679 | card->devname, cmd); | ||
1680 | break; | ||
1681 | |||
1682 | case S514_BOTH_PORTS_SAME_CLK_MODE: | ||
1683 | if(cmd == SET_CHDLC_CONFIGURATION) { | ||
1684 | printk(KERN_INFO | ||
1685 | "%s: Configure both ports for the same clock source\n", | ||
1686 | card->devname); | ||
1687 | break; | ||
1688 | } | ||
1689 | |||
1690 | default: | ||
1691 | printk(KERN_INFO "%s: command 0x%02X returned 0x%02X!\n", | ||
1692 | card->devname, cmd, err); | ||
1693 | } | ||
1694 | |||
1695 | return 0; | ||
1696 | } | ||
1697 | |||
1698 | |||
1699 | /********** Bottom Half Handlers ********************************************/ | ||
1700 | |||
1701 | /* NOTE: There is no API, BH support for Kernels lower than 2.2.X. | ||
1702 | * DO NOT INSERT ANY CODE HERE, NOTICE THE | ||
1703 | * PREPROCESSOR STATEMENT ABOVE, UNLESS YOU KNOW WHAT YOU ARE | ||
1704 | * DOING */ | ||
1705 | |||
1706 | static void chdlc_work(struct net_device * dev) | ||
1707 | { | ||
1708 | chdlc_private_area_t* chan = dev->priv; | ||
1709 | sdla_t *card = chan->card; | ||
1710 | struct sk_buff *skb; | ||
1711 | |||
1712 | if (atomic_read(&chan->bh_buff_used) == 0){ | ||
1713 | clear_bit(0, &chan->tq_working); | ||
1714 | return; | ||
1715 | } | ||
1716 | |||
1717 | while (atomic_read(&chan->bh_buff_used)){ | ||
1718 | |||
1719 | skb = ((bh_data_t *)&chan->bh_head[chan->bh_read])->skb; | ||
1720 | |||
1721 | if (skb != NULL){ | ||
1722 | |||
1723 | if (chan->common.sk == NULL || chan->common.func == NULL){ | ||
1724 | ++card->wandev.stats.rx_dropped; | ||
1725 | dev_kfree_skb_any(skb); | ||
1726 | chdlc_work_cleanup(dev); | ||
1727 | continue; | ||
1728 | } | ||
1729 | |||
1730 | if (chan->common.func(skb,dev,chan->common.sk) != 0){ | ||
1731 | /* Sock full cannot send, queue us for another | ||
1732 | * try */ | ||
1733 | atomic_set(&chan->common.receive_block,1); | ||
1734 | return; | ||
1735 | }else{ | ||
1736 | chdlc_work_cleanup(dev); | ||
1737 | } | ||
1738 | }else{ | ||
1739 | chdlc_work_cleanup(dev); | ||
1740 | } | ||
1741 | } | ||
1742 | clear_bit(0, &chan->tq_working); | ||
1743 | |||
1744 | return; | ||
1745 | } | ||
1746 | |||
1747 | static int chdlc_work_cleanup(struct net_device *dev) | ||
1748 | { | ||
1749 | chdlc_private_area_t* chan = dev->priv; | ||
1750 | |||
1751 | ((bh_data_t *)&chan->bh_head[chan->bh_read])->skb = NULL; | ||
1752 | |||
1753 | if (chan->bh_read == MAX_BH_BUFF){ | ||
1754 | chan->bh_read=0; | ||
1755 | }else{ | ||
1756 | ++chan->bh_read; | ||
1757 | } | ||
1758 | |||
1759 | atomic_dec(&chan->bh_buff_used); | ||
1760 | return 0; | ||
1761 | } | ||
1762 | |||
1763 | |||
1764 | |||
1765 | static int bh_enqueue(struct net_device *dev, struct sk_buff *skb) | ||
1766 | { | ||
1767 | /* Check for full */ | ||
1768 | chdlc_private_area_t* chan = dev->priv; | ||
1769 | sdla_t *card = chan->card; | ||
1770 | |||
1771 | if (atomic_read(&chan->bh_buff_used) == (MAX_BH_BUFF+1)){ | ||
1772 | ++card->wandev.stats.rx_dropped; | ||
1773 | dev_kfree_skb_any(skb); | ||
1774 | return 1; | ||
1775 | } | ||
1776 | |||
1777 | ((bh_data_t *)&chan->bh_head[chan->bh_write])->skb = skb; | ||
1778 | |||
1779 | if (chan->bh_write == MAX_BH_BUFF){ | ||
1780 | chan->bh_write=0; | ||
1781 | }else{ | ||
1782 | ++chan->bh_write; | ||
1783 | } | ||
1784 | |||
1785 | atomic_inc(&chan->bh_buff_used); | ||
1786 | |||
1787 | return 0; | ||
1788 | } | ||
1789 | |||
1790 | /* END OF API BH Support */ | ||
1791 | |||
1792 | |||
1793 | /****** Interrupt Handlers **************************************************/ | ||
1794 | |||
1795 | /*============================================================================ | ||
1796 | * Cisco HDLC interrupt service routine. | ||
1797 | */ | ||
1798 | static void wpc_isr (sdla_t* card) | ||
1799 | { | ||
1800 | struct net_device* dev; | ||
1801 | SHARED_MEMORY_INFO_STRUCT* flags = NULL; | ||
1802 | int i; | ||
1803 | sdla_t *my_card; | ||
1804 | |||
1805 | |||
1806 | /* Check for which port the interrupt has been generated | ||
1807 | * Since Secondary Port is piggybacking on the Primary | ||
1808 | * the check must be done here. | ||
1809 | */ | ||
1810 | |||
1811 | flags = card->u.c.flags; | ||
1812 | if (!flags->interrupt_info_struct.interrupt_type){ | ||
1813 | /* Check for a second port (piggybacking) */ | ||
1814 | if ((my_card = card->next)){ | ||
1815 | flags = my_card->u.c.flags; | ||
1816 | if (flags->interrupt_info_struct.interrupt_type){ | ||
1817 | card = my_card; | ||
1818 | card->isr(card); | ||
1819 | return; | ||
1820 | } | ||
1821 | } | ||
1822 | } | ||
1823 | |||
1824 | flags = card->u.c.flags; | ||
1825 | card->in_isr = 1; | ||
1826 | dev = card->wandev.dev; | ||
1827 | |||
1828 | /* If we get an interrupt with no network device, stop the interrupts | ||
1829 | * and issue an error */ | ||
1830 | if (!card->tty_opt && !dev && | ||
1831 | flags->interrupt_info_struct.interrupt_type != | ||
1832 | COMMAND_COMPLETE_APP_INT_PEND){ | ||
1833 | |||
1834 | goto isr_done; | ||
1835 | } | ||
1836 | |||
1837 | /* if critical due to peripheral operations | ||
1838 | * ie. update() or getstats() then reset the interrupt and | ||
1839 | * wait for the board to retrigger. | ||
1840 | */ | ||
1841 | if(test_bit(PERI_CRIT, (void*)&card->wandev.critical)) { | ||
1842 | printk(KERN_INFO "ISR CRIT TO PERI\n"); | ||
1843 | goto isr_done; | ||
1844 | } | ||
1845 | |||
1846 | /* On a 508 Card, if critical due to if_send | ||
1847 | * Major Error !!! */ | ||
1848 | if(card->hw.type != SDLA_S514) { | ||
1849 | if(test_bit(SEND_CRIT, (void*)&card->wandev.critical)) { | ||
1850 | printk(KERN_INFO "%s: Critical while in ISR: %lx\n", | ||
1851 | card->devname, card->wandev.critical); | ||
1852 | card->in_isr = 0; | ||
1853 | flags->interrupt_info_struct.interrupt_type = 0; | ||
1854 | return; | ||
1855 | } | ||
1856 | } | ||
1857 | |||
1858 | switch(flags->interrupt_info_struct.interrupt_type) { | ||
1859 | |||
1860 | case RX_APP_INT_PEND: /* 0x01: receive interrupt */ | ||
1861 | rx_intr(card); | ||
1862 | break; | ||
1863 | |||
1864 | case TX_APP_INT_PEND: /* 0x02: transmit interrupt */ | ||
1865 | flags->interrupt_info_struct.interrupt_permission &= | ||
1866 | ~APP_INT_ON_TX_FRAME; | ||
1867 | |||
1868 | if (card->tty_opt){ | ||
1869 | wanpipe_tty_trigger_poll(card); | ||
1870 | break; | ||
1871 | } | ||
1872 | |||
1873 | if (dev && netif_queue_stopped(dev)){ | ||
1874 | if (card->u.c.usedby == API){ | ||
1875 | netif_start_queue(dev); | ||
1876 | wakeup_sk_bh(dev); | ||
1877 | }else{ | ||
1878 | netif_wake_queue(dev); | ||
1879 | } | ||
1880 | } | ||
1881 | break; | ||
1882 | |||
1883 | case COMMAND_COMPLETE_APP_INT_PEND:/* 0x04: cmd cplt */ | ||
1884 | ++ Intr_test_counter; | ||
1885 | break; | ||
1886 | |||
1887 | case CHDLC_EXCEP_COND_APP_INT_PEND: /* 0x20 */ | ||
1888 | process_chdlc_exception(card); | ||
1889 | break; | ||
1890 | |||
1891 | case GLOBAL_EXCEP_COND_APP_INT_PEND: | ||
1892 | process_global_exception(card); | ||
1893 | break; | ||
1894 | |||
1895 | case TIMER_APP_INT_PEND: | ||
1896 | timer_intr(card); | ||
1897 | break; | ||
1898 | |||
1899 | default: | ||
1900 | printk(KERN_INFO "%s: spurious interrupt 0x%02X!\n", | ||
1901 | card->devname, | ||
1902 | flags->interrupt_info_struct.interrupt_type); | ||
1903 | printk(KERN_INFO "Code name: "); | ||
1904 | for(i = 0; i < 4; i ++) | ||
1905 | printk(KERN_INFO "%c", | ||
1906 | flags->global_info_struct.codename[i]); | ||
1907 | printk(KERN_INFO "\nCode version: "); | ||
1908 | for(i = 0; i < 4; i ++) | ||
1909 | printk(KERN_INFO "%c", | ||
1910 | flags->global_info_struct.codeversion[i]); | ||
1911 | printk(KERN_INFO "\n"); | ||
1912 | break; | ||
1913 | } | ||
1914 | |||
1915 | isr_done: | ||
1916 | |||
1917 | card->in_isr = 0; | ||
1918 | flags->interrupt_info_struct.interrupt_type = 0; | ||
1919 | return; | ||
1920 | } | ||
1921 | |||
1922 | /*============================================================================ | ||
1923 | * Receive interrupt handler. | ||
1924 | */ | ||
1925 | static void rx_intr (sdla_t* card) | ||
1926 | { | ||
1927 | struct net_device *dev; | ||
1928 | chdlc_private_area_t *chdlc_priv_area; | ||
1929 | SHARED_MEMORY_INFO_STRUCT *flags = card->u.c.flags; | ||
1930 | CHDLC_DATA_RX_STATUS_EL_STRUCT *rxbuf = card->u.c.rxmb; | ||
1931 | struct sk_buff *skb; | ||
1932 | unsigned len; | ||
1933 | unsigned addr = rxbuf->ptr_data_bfr; | ||
1934 | void *buf; | ||
1935 | int i,udp_type; | ||
1936 | |||
1937 | if (rxbuf->opp_flag != 0x01) { | ||
1938 | printk(KERN_INFO | ||
1939 | "%s: corrupted Rx buffer @ 0x%X, flag = 0x%02X!\n", | ||
1940 | card->devname, (unsigned)rxbuf, rxbuf->opp_flag); | ||
1941 | printk(KERN_INFO "Code name: "); | ||
1942 | for(i = 0; i < 4; i ++) | ||
1943 | printk(KERN_INFO "%c", | ||
1944 | flags->global_info_struct.codename[i]); | ||
1945 | printk(KERN_INFO "\nCode version: "); | ||
1946 | for(i = 0; i < 4; i ++) | ||
1947 | printk(KERN_INFO "%c", | ||
1948 | flags->global_info_struct.codeversion[i]); | ||
1949 | printk(KERN_INFO "\n"); | ||
1950 | |||
1951 | |||
1952 | /* Bug Fix: Mar 6 2000 | ||
1953 | * If we get a corrupted mailbox, it measn that driver | ||
1954 | * is out of sync with the firmware. There is no recovery. | ||
1955 | * If we don't turn off all interrupts for this card | ||
1956 | * the machine will crash. | ||
1957 | */ | ||
1958 | printk(KERN_INFO "%s: Critical router failure ...!!!\n", card->devname); | ||
1959 | printk(KERN_INFO "Please contact Sangoma Technologies !\n"); | ||
1960 | chdlc_set_intr_mode(card,0); | ||
1961 | return; | ||
1962 | } | ||
1963 | |||
1964 | len = rxbuf->frame_length; | ||
1965 | |||
1966 | if (card->tty_opt){ | ||
1967 | |||
1968 | if (rxbuf->error_flag){ | ||
1969 | goto rx_exit; | ||
1970 | } | ||
1971 | |||
1972 | if (len <= CRC_LENGTH){ | ||
1973 | goto rx_exit; | ||
1974 | } | ||
1975 | |||
1976 | if (!card->u.c.async_mode){ | ||
1977 | len -= CRC_LENGTH; | ||
1978 | } | ||
1979 | |||
1980 | wanpipe_tty_receive(card,addr,len); | ||
1981 | goto rx_exit; | ||
1982 | } | ||
1983 | |||
1984 | dev = card->wandev.dev; | ||
1985 | |||
1986 | if (!dev){ | ||
1987 | goto rx_exit; | ||
1988 | } | ||
1989 | |||
1990 | if (!netif_running(dev)) | ||
1991 | goto rx_exit; | ||
1992 | |||
1993 | chdlc_priv_area = dev->priv; | ||
1994 | |||
1995 | |||
1996 | /* Allocate socket buffer */ | ||
1997 | skb = dev_alloc_skb(len); | ||
1998 | |||
1999 | if (skb == NULL) { | ||
2000 | printk(KERN_INFO "%s: no socket buffers available!\n", | ||
2001 | card->devname); | ||
2002 | ++card->wandev.stats.rx_dropped; | ||
2003 | goto rx_exit; | ||
2004 | } | ||
2005 | |||
2006 | /* Copy data to the socket buffer */ | ||
2007 | if((addr + len) > card->u.c.rx_top + 1) { | ||
2008 | unsigned tmp = card->u.c.rx_top - addr + 1; | ||
2009 | buf = skb_put(skb, tmp); | ||
2010 | sdla_peek(&card->hw, addr, buf, tmp); | ||
2011 | addr = card->u.c.rx_base; | ||
2012 | len -= tmp; | ||
2013 | } | ||
2014 | |||
2015 | buf = skb_put(skb, len); | ||
2016 | sdla_peek(&card->hw, addr, buf, len); | ||
2017 | |||
2018 | skb->protocol = htons(ETH_P_IP); | ||
2019 | |||
2020 | card->wandev.stats.rx_packets ++; | ||
2021 | card->wandev.stats.rx_bytes += skb->len; | ||
2022 | udp_type = udp_pkt_type( skb, card ); | ||
2023 | |||
2024 | if(udp_type == UDP_CPIPE_TYPE) { | ||
2025 | if(store_udp_mgmt_pkt(UDP_PKT_FRM_NETWORK, | ||
2026 | card, skb, dev, chdlc_priv_area)) { | ||
2027 | flags->interrupt_info_struct. | ||
2028 | interrupt_permission |= | ||
2029 | APP_INT_ON_TIMER; | ||
2030 | } | ||
2031 | } else if(card->u.c.usedby == API) { | ||
2032 | |||
2033 | api_rx_hdr_t* api_rx_hdr; | ||
2034 | skb_push(skb, sizeof(api_rx_hdr_t)); | ||
2035 | api_rx_hdr = (api_rx_hdr_t*)&skb->data[0x00]; | ||
2036 | api_rx_hdr->error_flag = rxbuf->error_flag; | ||
2037 | api_rx_hdr->time_stamp = rxbuf->time_stamp; | ||
2038 | |||
2039 | skb->protocol = htons(PVC_PROT); | ||
2040 | skb->mac.raw = skb->data; | ||
2041 | skb->dev = dev; | ||
2042 | skb->pkt_type = WAN_PACKET_DATA; | ||
2043 | |||
2044 | bh_enqueue(dev, skb); | ||
2045 | |||
2046 | if (!test_and_set_bit(0,&chdlc_priv_area->tq_working)) | ||
2047 | wanpipe_queue_work(&chdlc_priv_area->common.wanpipe_work); | ||
2048 | }else{ | ||
2049 | /* FIXME: we should check to see if the received packet is a | ||
2050 | multicast packet so that we can increment the multicast | ||
2051 | statistic | ||
2052 | ++ chdlc_priv_area->if_stats.multicast; | ||
2053 | */ | ||
2054 | /* Pass it up the protocol stack */ | ||
2055 | |||
2056 | skb->dev = dev; | ||
2057 | skb->mac.raw = skb->data; | ||
2058 | netif_rx(skb); | ||
2059 | dev->last_rx = jiffies; | ||
2060 | } | ||
2061 | |||
2062 | rx_exit: | ||
2063 | /* Release buffer element and calculate a pointer to the next one */ | ||
2064 | rxbuf->opp_flag = 0x00; | ||
2065 | card->u.c.rxmb = ++ rxbuf; | ||
2066 | if((void*)rxbuf > card->u.c.rxbuf_last){ | ||
2067 | card->u.c.rxmb = card->u.c.rxbuf_base; | ||
2068 | } | ||
2069 | } | ||
2070 | |||
2071 | /*============================================================================ | ||
2072 | * Timer interrupt handler. | ||
2073 | * The timer interrupt is used for two purposes: | ||
2074 | * 1) Processing udp calls from 'cpipemon'. | ||
2075 | * 2) Reading board-level statistics for updating the proc file system. | ||
2076 | */ | ||
2077 | void timer_intr(sdla_t *card) | ||
2078 | { | ||
2079 | struct net_device* dev; | ||
2080 | chdlc_private_area_t* chdlc_priv_area = NULL; | ||
2081 | SHARED_MEMORY_INFO_STRUCT* flags = NULL; | ||
2082 | |||
2083 | if ((dev = card->wandev.dev)==NULL){ | ||
2084 | flags = card->u.c.flags; | ||
2085 | flags->interrupt_info_struct.interrupt_permission &= | ||
2086 | ~APP_INT_ON_TIMER; | ||
2087 | return; | ||
2088 | } | ||
2089 | |||
2090 | chdlc_priv_area = dev->priv; | ||
2091 | |||
2092 | if (chdlc_priv_area->timer_int_enabled & TMR_INT_ENABLED_CONFIG) { | ||
2093 | if (!config_chdlc(card)){ | ||
2094 | chdlc_priv_area->timer_int_enabled &= ~TMR_INT_ENABLED_CONFIG; | ||
2095 | } | ||
2096 | } | ||
2097 | |||
2098 | /* process a udp call if pending */ | ||
2099 | if(chdlc_priv_area->timer_int_enabled & TMR_INT_ENABLED_UDP) { | ||
2100 | process_udp_mgmt_pkt(card, dev, | ||
2101 | chdlc_priv_area); | ||
2102 | chdlc_priv_area->timer_int_enabled &= ~TMR_INT_ENABLED_UDP; | ||
2103 | } | ||
2104 | |||
2105 | /* read the communications statistics if required */ | ||
2106 | if(chdlc_priv_area->timer_int_enabled & TMR_INT_ENABLED_UPDATE) { | ||
2107 | update_comms_stats(card, chdlc_priv_area); | ||
2108 | if(!(-- chdlc_priv_area->update_comms_stats)) { | ||
2109 | chdlc_priv_area->timer_int_enabled &= | ||
2110 | ~TMR_INT_ENABLED_UPDATE; | ||
2111 | } | ||
2112 | } | ||
2113 | |||
2114 | /* only disable the timer interrupt if there are no udp or statistic */ | ||
2115 | /* updates pending */ | ||
2116 | if(!chdlc_priv_area->timer_int_enabled) { | ||
2117 | flags = card->u.c.flags; | ||
2118 | flags->interrupt_info_struct.interrupt_permission &= | ||
2119 | ~APP_INT_ON_TIMER; | ||
2120 | } | ||
2121 | } | ||
2122 | |||
2123 | /*------------------------------------------------------------------------------ | ||
2124 | Miscellaneous Functions | ||
2125 | - set_chdlc_config() used to set configuration options on the board | ||
2126 | ------------------------------------------------------------------------------*/ | ||
2127 | |||
2128 | static int set_chdlc_config(sdla_t* card) | ||
2129 | { | ||
2130 | CHDLC_CONFIGURATION_STRUCT cfg; | ||
2131 | |||
2132 | memset(&cfg, 0, sizeof(CHDLC_CONFIGURATION_STRUCT)); | ||
2133 | |||
2134 | if(card->wandev.clocking){ | ||
2135 | cfg.baud_rate = card->wandev.bps; | ||
2136 | } | ||
2137 | |||
2138 | cfg.line_config_options = (card->wandev.interface == WANOPT_RS232) ? | ||
2139 | INTERFACE_LEVEL_RS232 : INTERFACE_LEVEL_V35; | ||
2140 | |||
2141 | cfg.modem_config_options = 0; | ||
2142 | cfg.modem_status_timer = 100; | ||
2143 | |||
2144 | cfg.CHDLC_protocol_options = card->u.c.protocol_options; | ||
2145 | |||
2146 | if (card->tty_opt){ | ||
2147 | cfg.CHDLC_API_options = DISCARD_RX_ERROR_FRAMES; | ||
2148 | } | ||
2149 | |||
2150 | cfg.percent_data_buffer_for_Tx = (card->u.c.receive_only) ? 0 : 50; | ||
2151 | cfg.CHDLC_statistics_options = (CHDLC_TX_DATA_BYTE_COUNT_STAT | | ||
2152 | CHDLC_RX_DATA_BYTE_COUNT_STAT); | ||
2153 | |||
2154 | if (card->tty_opt){ | ||
2155 | card->wandev.mtu = TTY_CHDLC_MAX_MTU; | ||
2156 | } | ||
2157 | cfg.max_CHDLC_data_field_length = card->wandev.mtu; | ||
2158 | cfg.transmit_keepalive_timer = card->u.c.kpalv_tx; | ||
2159 | cfg.receive_keepalive_timer = card->u.c.kpalv_rx; | ||
2160 | cfg.keepalive_error_tolerance = card->u.c.kpalv_err; | ||
2161 | cfg.SLARP_request_timer = card->u.c.slarp_timer; | ||
2162 | |||
2163 | if (cfg.SLARP_request_timer) { | ||
2164 | cfg.IP_address = 0; | ||
2165 | cfg.IP_netmask = 0; | ||
2166 | |||
2167 | }else if (card->wandev.dev){ | ||
2168 | struct net_device *dev = card->wandev.dev; | ||
2169 | chdlc_private_area_t *chdlc_priv_area = dev->priv; | ||
2170 | |||
2171 | struct in_device *in_dev = dev->ip_ptr; | ||
2172 | |||
2173 | if(in_dev != NULL) { | ||
2174 | struct in_ifaddr *ifa = in_dev->ifa_list; | ||
2175 | |||
2176 | if (ifa != NULL ) { | ||
2177 | cfg.IP_address = ntohl(ifa->ifa_local); | ||
2178 | cfg.IP_netmask = ntohl(ifa->ifa_mask); | ||
2179 | chdlc_priv_area->IP_address = ntohl(ifa->ifa_local); | ||
2180 | chdlc_priv_area->IP_netmask = ntohl(ifa->ifa_mask); | ||
2181 | } | ||
2182 | } | ||
2183 | |||
2184 | /* FIXME: We must re-think this message in next release | ||
2185 | if((cfg.IP_address & 0x000000FF) > 2) { | ||
2186 | printk(KERN_WARNING "\n"); | ||
2187 | printk(KERN_WARNING " WARNING:%s configured with an\n", | ||
2188 | card->devname); | ||
2189 | printk(KERN_WARNING " invalid local IP address.\n"); | ||
2190 | printk(KERN_WARNING " Slarp pragmatics will fail.\n"); | ||
2191 | printk(KERN_WARNING " IP address should be of the\n"); | ||
2192 | printk(KERN_WARNING " format A.B.C.1 or A.B.C.2.\n"); | ||
2193 | } | ||
2194 | */ | ||
2195 | } | ||
2196 | |||
2197 | return chdlc_configure(card, &cfg); | ||
2198 | } | ||
2199 | |||
2200 | |||
2201 | /*----------------------------------------------------------------------------- | ||
2202 | set_asy_config() used to set asynchronous configuration options on the board | ||
2203 | ------------------------------------------------------------------------------*/ | ||
2204 | |||
2205 | static int set_asy_config(sdla_t* card) | ||
2206 | { | ||
2207 | |||
2208 | ASY_CONFIGURATION_STRUCT cfg; | ||
2209 | CHDLC_MAILBOX_STRUCT *mailbox = card->mbox; | ||
2210 | int err; | ||
2211 | |||
2212 | memset(&cfg, 0, sizeof(ASY_CONFIGURATION_STRUCT)); | ||
2213 | |||
2214 | if(card->wandev.clocking) | ||
2215 | cfg.baud_rate = card->wandev.bps; | ||
2216 | |||
2217 | cfg.line_config_options = (card->wandev.interface == WANOPT_RS232) ? | ||
2218 | INTERFACE_LEVEL_RS232 : INTERFACE_LEVEL_V35; | ||
2219 | |||
2220 | cfg.modem_config_options = 0; | ||
2221 | cfg.asy_API_options = card->u.c.api_options; | ||
2222 | cfg.asy_protocol_options = card->u.c.protocol_options; | ||
2223 | cfg.Tx_bits_per_char = card->u.c.tx_bits_per_char; | ||
2224 | cfg.Rx_bits_per_char = card->u.c.rx_bits_per_char; | ||
2225 | cfg.stop_bits = card->u.c.stop_bits; | ||
2226 | cfg.parity = card->u.c.parity; | ||
2227 | cfg.break_timer = card->u.c.break_timer; | ||
2228 | cfg.asy_Rx_inter_char_timer = card->u.c.inter_char_timer; | ||
2229 | cfg.asy_Rx_complete_length = card->u.c.rx_complete_length; | ||
2230 | cfg.XON_char = card->u.c.xon_char; | ||
2231 | cfg.XOFF_char = card->u.c.xoff_char; | ||
2232 | cfg.asy_statistics_options = (CHDLC_TX_DATA_BYTE_COUNT_STAT | | ||
2233 | CHDLC_RX_DATA_BYTE_COUNT_STAT); | ||
2234 | |||
2235 | mailbox->buffer_length = sizeof(ASY_CONFIGURATION_STRUCT); | ||
2236 | memcpy(mailbox->data, &cfg, mailbox->buffer_length); | ||
2237 | mailbox->command = SET_ASY_CONFIGURATION; | ||
2238 | err = sdla_exec(mailbox) ? mailbox->return_code : CMD_TIMEOUT; | ||
2239 | if (err != COMMAND_OK) | ||
2240 | chdlc_error (card, err, mailbox); | ||
2241 | return err; | ||
2242 | } | ||
2243 | |||
2244 | /*============================================================================ | ||
2245 | * Enable asynchronous communications. | ||
2246 | */ | ||
2247 | |||
2248 | static int asy_comm_enable (sdla_t* card) | ||
2249 | { | ||
2250 | |||
2251 | int err; | ||
2252 | CHDLC_MAILBOX_STRUCT* mb = card->mbox; | ||
2253 | |||
2254 | mb->buffer_length = 0; | ||
2255 | mb->command = ENABLE_ASY_COMMUNICATIONS; | ||
2256 | err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; | ||
2257 | if (err != COMMAND_OK && card->wandev.dev) | ||
2258 | chdlc_error(card, err, mb); | ||
2259 | |||
2260 | if (!err) | ||
2261 | card->u.c.comm_enabled = 1; | ||
2262 | |||
2263 | return err; | ||
2264 | } | ||
2265 | |||
2266 | /*============================================================================ | ||
2267 | * Process global exception condition | ||
2268 | */ | ||
2269 | static int process_global_exception(sdla_t *card) | ||
2270 | { | ||
2271 | CHDLC_MAILBOX_STRUCT* mbox = card->mbox; | ||
2272 | int err; | ||
2273 | |||
2274 | mbox->buffer_length = 0; | ||
2275 | mbox->command = READ_GLOBAL_EXCEPTION_CONDITION; | ||
2276 | err = sdla_exec(mbox) ? mbox->return_code : CMD_TIMEOUT; | ||
2277 | |||
2278 | if(err != CMD_TIMEOUT ){ | ||
2279 | |||
2280 | switch(mbox->return_code) { | ||
2281 | |||
2282 | case EXCEP_MODEM_STATUS_CHANGE: | ||
2283 | |||
2284 | printk(KERN_INFO "%s: Modem status change\n", | ||
2285 | card->devname); | ||
2286 | |||
2287 | switch(mbox->data[0] & (DCD_HIGH | CTS_HIGH)) { | ||
2288 | case (DCD_HIGH): | ||
2289 | printk(KERN_INFO "%s: DCD high, CTS low\n",card->devname); | ||
2290 | break; | ||
2291 | case (CTS_HIGH): | ||
2292 | printk(KERN_INFO "%s: DCD low, CTS high\n",card->devname); | ||
2293 | break; | ||
2294 | case ((DCD_HIGH | CTS_HIGH)): | ||
2295 | printk(KERN_INFO "%s: DCD high, CTS high\n",card->devname); | ||
2296 | break; | ||
2297 | default: | ||
2298 | printk(KERN_INFO "%s: DCD low, CTS low\n",card->devname); | ||
2299 | break; | ||
2300 | } | ||
2301 | break; | ||
2302 | |||
2303 | case EXCEP_TRC_DISABLED: | ||
2304 | printk(KERN_INFO "%s: Line trace disabled\n", | ||
2305 | card->devname); | ||
2306 | break; | ||
2307 | |||
2308 | case EXCEP_IRQ_TIMEOUT: | ||
2309 | printk(KERN_INFO "%s: IRQ timeout occurred\n", | ||
2310 | card->devname); | ||
2311 | break; | ||
2312 | |||
2313 | case 0x17: | ||
2314 | if (card->tty_opt){ | ||
2315 | if (card->tty && card->tty_open){ | ||
2316 | printk(KERN_INFO | ||
2317 | "%s: Modem Hangup Exception: Hanging Up!\n", | ||
2318 | card->devname); | ||
2319 | tty_hangup(card->tty); | ||
2320 | } | ||
2321 | break; | ||
2322 | } | ||
2323 | |||
2324 | /* If TTY is not used just drop throught */ | ||
2325 | |||
2326 | default: | ||
2327 | printk(KERN_INFO "%s: Global exception %x\n", | ||
2328 | card->devname, mbox->return_code); | ||
2329 | break; | ||
2330 | } | ||
2331 | } | ||
2332 | return 0; | ||
2333 | } | ||
2334 | |||
2335 | |||
2336 | /*============================================================================ | ||
2337 | * Process chdlc exception condition | ||
2338 | */ | ||
2339 | static int process_chdlc_exception(sdla_t *card) | ||
2340 | { | ||
2341 | CHDLC_MAILBOX_STRUCT* mb = card->mbox; | ||
2342 | int err; | ||
2343 | |||
2344 | mb->buffer_length = 0; | ||
2345 | mb->command = READ_CHDLC_EXCEPTION_CONDITION; | ||
2346 | err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; | ||
2347 | if(err != CMD_TIMEOUT) { | ||
2348 | |||
2349 | switch (err) { | ||
2350 | |||
2351 | case EXCEP_LINK_ACTIVE: | ||
2352 | port_set_state(card, WAN_CONNECTED); | ||
2353 | trigger_chdlc_poll(card->wandev.dev); | ||
2354 | break; | ||
2355 | |||
2356 | case EXCEP_LINK_INACTIVE_MODEM: | ||
2357 | port_set_state(card, WAN_DISCONNECTED); | ||
2358 | unconfigure_ip(card); | ||
2359 | trigger_chdlc_poll(card->wandev.dev); | ||
2360 | break; | ||
2361 | |||
2362 | case EXCEP_LINK_INACTIVE_KPALV: | ||
2363 | port_set_state(card, WAN_DISCONNECTED); | ||
2364 | printk(KERN_INFO "%s: Keepalive timer expired.\n", | ||
2365 | card->devname); | ||
2366 | unconfigure_ip(card); | ||
2367 | trigger_chdlc_poll(card->wandev.dev); | ||
2368 | break; | ||
2369 | |||
2370 | case EXCEP_IP_ADDRESS_DISCOVERED: | ||
2371 | if (configure_ip(card)) | ||
2372 | return -1; | ||
2373 | break; | ||
2374 | |||
2375 | case EXCEP_LOOPBACK_CONDITION: | ||
2376 | printk(KERN_INFO "%s: Loopback Condition Detected.\n", | ||
2377 | card->devname); | ||
2378 | break; | ||
2379 | |||
2380 | case NO_CHDLC_EXCEP_COND_TO_REPORT: | ||
2381 | printk(KERN_INFO "%s: No exceptions reported.\n", | ||
2382 | card->devname); | ||
2383 | break; | ||
2384 | } | ||
2385 | |||
2386 | } | ||
2387 | return 0; | ||
2388 | } | ||
2389 | |||
2390 | |||
2391 | /*============================================================================ | ||
2392 | * Configure IP from SLARP negotiation | ||
2393 | * This adds dynamic routes when SLARP has provided valid addresses | ||
2394 | */ | ||
2395 | |||
2396 | static int configure_ip (sdla_t* card) | ||
2397 | { | ||
2398 | struct net_device *dev = card->wandev.dev; | ||
2399 | chdlc_private_area_t *chdlc_priv_area; | ||
2400 | char err; | ||
2401 | |||
2402 | if (!dev) | ||
2403 | return 0; | ||
2404 | |||
2405 | chdlc_priv_area = dev->priv; | ||
2406 | |||
2407 | |||
2408 | /* set to discover */ | ||
2409 | if(card->u.c.slarp_timer != 0x00) { | ||
2410 | CHDLC_MAILBOX_STRUCT* mb = card->mbox; | ||
2411 | CHDLC_CONFIGURATION_STRUCT *cfg; | ||
2412 | |||
2413 | mb->buffer_length = 0; | ||
2414 | mb->command = READ_CHDLC_CONFIGURATION; | ||
2415 | err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; | ||
2416 | |||
2417 | if(err != COMMAND_OK) { | ||
2418 | chdlc_error(card,err,mb); | ||
2419 | return -1; | ||
2420 | } | ||
2421 | |||
2422 | cfg = (CHDLC_CONFIGURATION_STRUCT *)mb->data; | ||
2423 | chdlc_priv_area->IP_address = cfg->IP_address; | ||
2424 | chdlc_priv_area->IP_netmask = cfg->IP_netmask; | ||
2425 | |||
2426 | /* Set flag to add route */ | ||
2427 | chdlc_priv_area->route_status = ADD_ROUTE; | ||
2428 | |||
2429 | /* The idea here is to add the route in the poll routine. | ||
2430 | This way, we aren't in interrupt context when adding routes */ | ||
2431 | trigger_chdlc_poll(dev); | ||
2432 | } | ||
2433 | |||
2434 | return 0; | ||
2435 | } | ||
2436 | |||
2437 | |||
2438 | /*============================================================================ | ||
2439 | * Un-Configure IP negotiated by SLARP | ||
2440 | * This removes dynamic routes when the link becomes inactive. | ||
2441 | */ | ||
2442 | |||
2443 | static int unconfigure_ip (sdla_t* card) | ||
2444 | { | ||
2445 | struct net_device *dev = card->wandev.dev; | ||
2446 | chdlc_private_area_t *chdlc_priv_area; | ||
2447 | |||
2448 | if (!dev) | ||
2449 | return 0; | ||
2450 | |||
2451 | chdlc_priv_area= dev->priv; | ||
2452 | |||
2453 | if (chdlc_priv_area->route_status == ROUTE_ADDED) { | ||
2454 | |||
2455 | /* Note: If this function is called, the | ||
2456 | * port state has been DISCONNECTED. This state | ||
2457 | * change will trigger a poll_disconnected | ||
2458 | * function, that will check for this condition. | ||
2459 | */ | ||
2460 | chdlc_priv_area->route_status = REMOVE_ROUTE; | ||
2461 | |||
2462 | } | ||
2463 | return 0; | ||
2464 | } | ||
2465 | |||
2466 | /*============================================================================ | ||
2467 | * Routine to add/remove routes | ||
2468 | * Called like a polling routine when Routes are flagged to be added/removed. | ||
2469 | */ | ||
2470 | |||
2471 | static void process_route (sdla_t *card) | ||
2472 | { | ||
2473 | struct net_device *dev = card->wandev.dev; | ||
2474 | unsigned char port_num; | ||
2475 | chdlc_private_area_t *chdlc_priv_area = NULL; | ||
2476 | u32 local_IP_addr = 0; | ||
2477 | u32 remote_IP_addr = 0; | ||
2478 | u32 IP_netmask, IP_addr; | ||
2479 | int err = 0; | ||
2480 | struct in_device *in_dev; | ||
2481 | mm_segment_t fs; | ||
2482 | struct ifreq if_info; | ||
2483 | struct sockaddr_in *if_data1, *if_data2; | ||
2484 | |||
2485 | chdlc_priv_area = dev->priv; | ||
2486 | port_num = card->u.c.comm_port; | ||
2487 | |||
2488 | /* Bug Fix Mar 16 2000 | ||
2489 | * AND the IP address to the Mask before checking | ||
2490 | * the last two bits. */ | ||
2491 | |||
2492 | if((chdlc_priv_area->route_status == ADD_ROUTE) && | ||
2493 | ((chdlc_priv_area->IP_address & ~chdlc_priv_area->IP_netmask) > 2)) { | ||
2494 | |||
2495 | printk(KERN_INFO "%s: Dynamic route failure.\n",card->devname); | ||
2496 | |||
2497 | if(card->u.c.slarp_timer) { | ||
2498 | u32 addr_net = htonl(chdlc_priv_area->IP_address); | ||
2499 | |||
2500 | printk(KERN_INFO "%s: Bad IP address %u.%u.%u.%u received\n", | ||
2501 | card->devname, | ||
2502 | NIPQUAD(addr_net)); | ||
2503 | printk(KERN_INFO "%s: from remote station.\n", | ||
2504 | card->devname); | ||
2505 | |||
2506 | }else{ | ||
2507 | u32 addr_net = htonl(chdlc_priv_area->IP_address); | ||
2508 | |||
2509 | printk(KERN_INFO "%s: Bad IP address %u.%u.%u.%u issued\n", | ||
2510 | card->devname, | ||
2511 | NIPQUAD(addr_net)); | ||
2512 | printk(KERN_INFO "%s: to remote station. Local\n", | ||
2513 | card->devname); | ||
2514 | printk(KERN_INFO "%s: IP address must be A.B.C.1\n", | ||
2515 | card->devname); | ||
2516 | printk(KERN_INFO "%s: or A.B.C.2.\n",card->devname); | ||
2517 | } | ||
2518 | |||
2519 | /* remove the route due to the IP address error condition */ | ||
2520 | chdlc_priv_area->route_status = REMOVE_ROUTE; | ||
2521 | err = 1; | ||
2522 | } | ||
2523 | |||
2524 | /* If we are removing a route with bad IP addressing, then use the */ | ||
2525 | /* locally configured IP addresses */ | ||
2526 | if((chdlc_priv_area->route_status == REMOVE_ROUTE) && err) { | ||
2527 | |||
2528 | /* do not remove a bad route that has already been removed */ | ||
2529 | if(chdlc_priv_area->route_removed) { | ||
2530 | return; | ||
2531 | } | ||
2532 | |||
2533 | in_dev = dev->ip_ptr; | ||
2534 | |||
2535 | if(in_dev != NULL) { | ||
2536 | struct in_ifaddr *ifa = in_dev->ifa_list; | ||
2537 | if (ifa != NULL ) { | ||
2538 | local_IP_addr = ifa->ifa_local; | ||
2539 | IP_netmask = ifa->ifa_mask; | ||
2540 | } | ||
2541 | } | ||
2542 | }else{ | ||
2543 | /* According to Cisco HDLC, if the point-to-point address is | ||
2544 | A.B.C.1, then we are the opposite (A.B.C.2), and vice-versa. | ||
2545 | */ | ||
2546 | IP_netmask = ntohl(chdlc_priv_area->IP_netmask); | ||
2547 | remote_IP_addr = ntohl(chdlc_priv_area->IP_address); | ||
2548 | |||
2549 | |||
2550 | /* If Netmask is 255.255.255.255 the local address | ||
2551 | * calculation will fail. Default it back to 255.255.255.0 */ | ||
2552 | if (IP_netmask == 0xffffffff) | ||
2553 | IP_netmask &= 0x00ffffff; | ||
2554 | |||
2555 | /* Bug Fix Mar 16 2000 | ||
2556 | * AND the Remote IP address with IP netmask, instead | ||
2557 | * of static netmask of 255.255.255.0 */ | ||
2558 | local_IP_addr = (remote_IP_addr & IP_netmask) + | ||
2559 | (~remote_IP_addr & ntohl(0x0003)); | ||
2560 | |||
2561 | if(!card->u.c.slarp_timer) { | ||
2562 | IP_addr = local_IP_addr; | ||
2563 | local_IP_addr = remote_IP_addr; | ||
2564 | remote_IP_addr = IP_addr; | ||
2565 | } | ||
2566 | } | ||
2567 | |||
2568 | fs = get_fs(); /* Save file system */ | ||
2569 | set_fs(get_ds()); /* Get user space block */ | ||
2570 | |||
2571 | /* Setup a structure for adding/removing routes */ | ||
2572 | memset(&if_info, 0, sizeof(if_info)); | ||
2573 | strcpy(if_info.ifr_name, dev->name); | ||
2574 | |||
2575 | switch (chdlc_priv_area->route_status) { | ||
2576 | |||
2577 | case ADD_ROUTE: | ||
2578 | |||
2579 | if(!card->u.c.slarp_timer) { | ||
2580 | if_data2 = (struct sockaddr_in *)&if_info.ifr_dstaddr; | ||
2581 | if_data2->sin_addr.s_addr = remote_IP_addr; | ||
2582 | if_data2->sin_family = AF_INET; | ||
2583 | err = devinet_ioctl(SIOCSIFDSTADDR, &if_info); | ||
2584 | } else { | ||
2585 | if_data1 = (struct sockaddr_in *)&if_info.ifr_addr; | ||
2586 | if_data1->sin_addr.s_addr = local_IP_addr; | ||
2587 | if_data1->sin_family = AF_INET; | ||
2588 | if(!(err = devinet_ioctl(SIOCSIFADDR, &if_info))){ | ||
2589 | if_data2 = (struct sockaddr_in *)&if_info.ifr_dstaddr; | ||
2590 | if_data2->sin_addr.s_addr = remote_IP_addr; | ||
2591 | if_data2->sin_family = AF_INET; | ||
2592 | err = devinet_ioctl(SIOCSIFDSTADDR, &if_info); | ||
2593 | } | ||
2594 | } | ||
2595 | |||
2596 | if(err) { | ||
2597 | printk(KERN_INFO "%s: Add route %u.%u.%u.%u failed (%d)\n", | ||
2598 | card->devname, NIPQUAD(remote_IP_addr), err); | ||
2599 | } else { | ||
2600 | ((chdlc_private_area_t *)dev->priv)->route_status = ROUTE_ADDED; | ||
2601 | printk(KERN_INFO "%s: Dynamic route added.\n", | ||
2602 | card->devname); | ||
2603 | printk(KERN_INFO "%s: Local IP addr : %u.%u.%u.%u\n", | ||
2604 | card->devname, NIPQUAD(local_IP_addr)); | ||
2605 | printk(KERN_INFO "%s: Remote IP addr: %u.%u.%u.%u\n", | ||
2606 | card->devname, NIPQUAD(remote_IP_addr)); | ||
2607 | chdlc_priv_area->route_removed = 0; | ||
2608 | } | ||
2609 | break; | ||
2610 | |||
2611 | |||
2612 | case REMOVE_ROUTE: | ||
2613 | |||
2614 | /* Change the local ip address of the interface to 0. | ||
2615 | * This will also delete the destination route. | ||
2616 | */ | ||
2617 | if(!card->u.c.slarp_timer) { | ||
2618 | if_data2 = (struct sockaddr_in *)&if_info.ifr_dstaddr; | ||
2619 | if_data2->sin_addr.s_addr = 0; | ||
2620 | if_data2->sin_family = AF_INET; | ||
2621 | err = devinet_ioctl(SIOCSIFDSTADDR, &if_info); | ||
2622 | } else { | ||
2623 | if_data1 = (struct sockaddr_in *)&if_info.ifr_addr; | ||
2624 | if_data1->sin_addr.s_addr = 0; | ||
2625 | if_data1->sin_family = AF_INET; | ||
2626 | err = devinet_ioctl(SIOCSIFADDR,&if_info); | ||
2627 | |||
2628 | } | ||
2629 | if(err) { | ||
2630 | printk(KERN_INFO | ||
2631 | "%s: Remove route %u.%u.%u.%u failed, (err %d)\n", | ||
2632 | card->devname, NIPQUAD(remote_IP_addr), | ||
2633 | err); | ||
2634 | } else { | ||
2635 | ((chdlc_private_area_t *)dev->priv)->route_status = | ||
2636 | NO_ROUTE; | ||
2637 | printk(KERN_INFO "%s: Dynamic route removed: %u.%u.%u.%u\n", | ||
2638 | card->devname, NIPQUAD(local_IP_addr)); | ||
2639 | chdlc_priv_area->route_removed = 1; | ||
2640 | } | ||
2641 | break; | ||
2642 | } | ||
2643 | |||
2644 | set_fs(fs); /* Restore file system */ | ||
2645 | |||
2646 | } | ||
2647 | |||
2648 | |||
2649 | /*============================================================================= | ||
2650 | * Store a UDP management packet for later processing. | ||
2651 | */ | ||
2652 | |||
2653 | static int store_udp_mgmt_pkt(char udp_pkt_src, sdla_t* card, | ||
2654 | struct sk_buff *skb, struct net_device* dev, | ||
2655 | chdlc_private_area_t* chdlc_priv_area) | ||
2656 | { | ||
2657 | int udp_pkt_stored = 0; | ||
2658 | |||
2659 | if(!chdlc_priv_area->udp_pkt_lgth && | ||
2660 | (skb->len <= MAX_LGTH_UDP_MGNT_PKT)) { | ||
2661 | chdlc_priv_area->udp_pkt_lgth = skb->len; | ||
2662 | chdlc_priv_area->udp_pkt_src = udp_pkt_src; | ||
2663 | memcpy(chdlc_priv_area->udp_pkt_data, skb->data, skb->len); | ||
2664 | chdlc_priv_area->timer_int_enabled = TMR_INT_ENABLED_UDP; | ||
2665 | udp_pkt_stored = 1; | ||
2666 | } | ||
2667 | |||
2668 | if(udp_pkt_src == UDP_PKT_FRM_STACK){ | ||
2669 | dev_kfree_skb_any(skb); | ||
2670 | }else{ | ||
2671 | dev_kfree_skb_any(skb); | ||
2672 | } | ||
2673 | |||
2674 | return(udp_pkt_stored); | ||
2675 | } | ||
2676 | |||
2677 | |||
2678 | /*============================================================================= | ||
2679 | * Process UDP management packet. | ||
2680 | */ | ||
2681 | |||
2682 | static int process_udp_mgmt_pkt(sdla_t* card, struct net_device* dev, | ||
2683 | chdlc_private_area_t* chdlc_priv_area ) | ||
2684 | { | ||
2685 | unsigned char *buf; | ||
2686 | unsigned int frames, len; | ||
2687 | struct sk_buff *new_skb; | ||
2688 | unsigned short buffer_length, real_len; | ||
2689 | unsigned long data_ptr; | ||
2690 | unsigned data_length; | ||
2691 | int udp_mgmt_req_valid = 1; | ||
2692 | CHDLC_MAILBOX_STRUCT *mb = card->mbox; | ||
2693 | SHARED_MEMORY_INFO_STRUCT *flags = card->u.c.flags; | ||
2694 | chdlc_udp_pkt_t *chdlc_udp_pkt; | ||
2695 | struct timeval tv; | ||
2696 | int err; | ||
2697 | char ut_char; | ||
2698 | |||
2699 | chdlc_udp_pkt = (chdlc_udp_pkt_t *) chdlc_priv_area->udp_pkt_data; | ||
2700 | |||
2701 | if(chdlc_priv_area->udp_pkt_src == UDP_PKT_FRM_NETWORK){ | ||
2702 | |||
2703 | /* Only these commands are support for remote debugging. | ||
2704 | * All others are not */ | ||
2705 | switch(chdlc_udp_pkt->cblock.command) { | ||
2706 | |||
2707 | case READ_GLOBAL_STATISTICS: | ||
2708 | case READ_MODEM_STATUS: | ||
2709 | case READ_CHDLC_LINK_STATUS: | ||
2710 | case CPIPE_ROUTER_UP_TIME: | ||
2711 | case READ_COMMS_ERROR_STATS: | ||
2712 | case READ_CHDLC_OPERATIONAL_STATS: | ||
2713 | |||
2714 | /* These two commands are executed for | ||
2715 | * each request */ | ||
2716 | case READ_CHDLC_CONFIGURATION: | ||
2717 | case READ_CHDLC_CODE_VERSION: | ||
2718 | udp_mgmt_req_valid = 1; | ||
2719 | break; | ||
2720 | default: | ||
2721 | udp_mgmt_req_valid = 0; | ||
2722 | break; | ||
2723 | } | ||
2724 | } | ||
2725 | |||
2726 | if(!udp_mgmt_req_valid) { | ||
2727 | |||
2728 | /* set length to 0 */ | ||
2729 | chdlc_udp_pkt->cblock.buffer_length = 0; | ||
2730 | |||
2731 | /* set return code */ | ||
2732 | chdlc_udp_pkt->cblock.return_code = 0xCD; | ||
2733 | |||
2734 | if (net_ratelimit()){ | ||
2735 | printk(KERN_INFO | ||
2736 | "%s: Warning, Illegal UDP command attempted from network: %x\n", | ||
2737 | card->devname,chdlc_udp_pkt->cblock.command); | ||
2738 | } | ||
2739 | |||
2740 | } else { | ||
2741 | unsigned long trace_status_cfg_addr = 0; | ||
2742 | TRACE_STATUS_EL_CFG_STRUCT trace_cfg_struct; | ||
2743 | TRACE_STATUS_ELEMENT_STRUCT trace_element_struct; | ||
2744 | |||
2745 | switch(chdlc_udp_pkt->cblock.command) { | ||
2746 | |||
2747 | case CPIPE_ENABLE_TRACING: | ||
2748 | if (!chdlc_priv_area->TracingEnabled) { | ||
2749 | |||
2750 | /* OPERATE_DATALINE_MONITOR */ | ||
2751 | |||
2752 | mb->buffer_length = sizeof(LINE_TRACE_CONFIG_STRUCT); | ||
2753 | mb->command = SET_TRACE_CONFIGURATION; | ||
2754 | |||
2755 | ((LINE_TRACE_CONFIG_STRUCT *)mb->data)-> | ||
2756 | trace_config = TRACE_ACTIVE; | ||
2757 | /* Trace delay mode is not used because it slows | ||
2758 | down transfer and results in a standoff situation | ||
2759 | when there is a lot of data */ | ||
2760 | |||
2761 | /* Configure the Trace based on user inputs */ | ||
2762 | ((LINE_TRACE_CONFIG_STRUCT *)mb->data)->trace_config |= | ||
2763 | chdlc_udp_pkt->data[0]; | ||
2764 | |||
2765 | ((LINE_TRACE_CONFIG_STRUCT *)mb->data)-> | ||
2766 | trace_deactivation_timer = 4000; | ||
2767 | |||
2768 | |||
2769 | err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; | ||
2770 | if (err != COMMAND_OK) { | ||
2771 | chdlc_error(card,err,mb); | ||
2772 | card->TracingEnabled = 0; | ||
2773 | chdlc_udp_pkt->cblock.return_code = err; | ||
2774 | mb->buffer_length = 0; | ||
2775 | break; | ||
2776 | } | ||
2777 | |||
2778 | /* Get the base address of the trace element list */ | ||
2779 | mb->buffer_length = 0; | ||
2780 | mb->command = READ_TRACE_CONFIGURATION; | ||
2781 | err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; | ||
2782 | |||
2783 | if (err != COMMAND_OK) { | ||
2784 | chdlc_error(card,err,mb); | ||
2785 | chdlc_priv_area->TracingEnabled = 0; | ||
2786 | chdlc_udp_pkt->cblock.return_code = err; | ||
2787 | mb->buffer_length = 0; | ||
2788 | break; | ||
2789 | } | ||
2790 | |||
2791 | trace_status_cfg_addr =((LINE_TRACE_CONFIG_STRUCT *) | ||
2792 | mb->data) -> ptr_trace_stat_el_cfg_struct; | ||
2793 | |||
2794 | sdla_peek(&card->hw, trace_status_cfg_addr, | ||
2795 | &trace_cfg_struct, sizeof(trace_cfg_struct)); | ||
2796 | |||
2797 | chdlc_priv_area->start_trace_addr = trace_cfg_struct. | ||
2798 | base_addr_trace_status_elements; | ||
2799 | |||
2800 | chdlc_priv_area->number_trace_elements = | ||
2801 | trace_cfg_struct.number_trace_status_elements; | ||
2802 | |||
2803 | chdlc_priv_area->end_trace_addr = (unsigned long) | ||
2804 | ((TRACE_STATUS_ELEMENT_STRUCT *) | ||
2805 | chdlc_priv_area->start_trace_addr + | ||
2806 | (chdlc_priv_area->number_trace_elements - 1)); | ||
2807 | |||
2808 | chdlc_priv_area->base_addr_trace_buffer = | ||
2809 | trace_cfg_struct.base_addr_trace_buffer; | ||
2810 | |||
2811 | chdlc_priv_area->end_addr_trace_buffer = | ||
2812 | trace_cfg_struct.end_addr_trace_buffer; | ||
2813 | |||
2814 | chdlc_priv_area->curr_trace_addr = | ||
2815 | trace_cfg_struct.next_trace_element_to_use; | ||
2816 | |||
2817 | chdlc_priv_area->available_buffer_space = 2000 - | ||
2818 | sizeof(ip_pkt_t) - | ||
2819 | sizeof(udp_pkt_t) - | ||
2820 | sizeof(wp_mgmt_t) - | ||
2821 | sizeof(cblock_t) - | ||
2822 | sizeof(trace_info_t); | ||
2823 | } | ||
2824 | chdlc_udp_pkt->cblock.return_code = COMMAND_OK; | ||
2825 | mb->buffer_length = 0; | ||
2826 | chdlc_priv_area->TracingEnabled = 1; | ||
2827 | break; | ||
2828 | |||
2829 | |||
2830 | case CPIPE_DISABLE_TRACING: | ||
2831 | if (chdlc_priv_area->TracingEnabled) { | ||
2832 | |||
2833 | /* OPERATE_DATALINE_MONITOR */ | ||
2834 | mb->buffer_length = sizeof(LINE_TRACE_CONFIG_STRUCT); | ||
2835 | mb->command = SET_TRACE_CONFIGURATION; | ||
2836 | ((LINE_TRACE_CONFIG_STRUCT *)mb->data)-> | ||
2837 | trace_config = TRACE_INACTIVE; | ||
2838 | err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; | ||
2839 | } | ||
2840 | |||
2841 | chdlc_priv_area->TracingEnabled = 0; | ||
2842 | chdlc_udp_pkt->cblock.return_code = COMMAND_OK; | ||
2843 | mb->buffer_length = 0; | ||
2844 | break; | ||
2845 | |||
2846 | |||
2847 | case CPIPE_GET_TRACE_INFO: | ||
2848 | |||
2849 | if (!chdlc_priv_area->TracingEnabled) { | ||
2850 | chdlc_udp_pkt->cblock.return_code = 1; | ||
2851 | mb->buffer_length = 0; | ||
2852 | break; | ||
2853 | } | ||
2854 | |||
2855 | chdlc_udp_pkt->trace_info.ismoredata = 0x00; | ||
2856 | buffer_length = 0; /* offset of packet already occupied */ | ||
2857 | |||
2858 | for (frames=0; frames < chdlc_priv_area->number_trace_elements; frames++){ | ||
2859 | |||
2860 | trace_pkt_t *trace_pkt = (trace_pkt_t *) | ||
2861 | &chdlc_udp_pkt->data[buffer_length]; | ||
2862 | |||
2863 | sdla_peek(&card->hw, chdlc_priv_area->curr_trace_addr, | ||
2864 | (unsigned char *)&trace_element_struct, | ||
2865 | sizeof(TRACE_STATUS_ELEMENT_STRUCT)); | ||
2866 | |||
2867 | if (trace_element_struct.opp_flag == 0x00) { | ||
2868 | break; | ||
2869 | } | ||
2870 | |||
2871 | /* get pointer to real data */ | ||
2872 | data_ptr = trace_element_struct.ptr_data_bfr; | ||
2873 | |||
2874 | /* See if there is actual data on the trace buffer */ | ||
2875 | if (data_ptr){ | ||
2876 | data_length = trace_element_struct.trace_length; | ||
2877 | }else{ | ||
2878 | data_length = 0; | ||
2879 | chdlc_udp_pkt->trace_info.ismoredata = 0x01; | ||
2880 | } | ||
2881 | |||
2882 | if( (chdlc_priv_area->available_buffer_space - buffer_length) | ||
2883 | < ( sizeof(trace_pkt_t) + data_length) ) { | ||
2884 | |||
2885 | /* indicate there are more frames on board & exit */ | ||
2886 | chdlc_udp_pkt->trace_info.ismoredata = 0x01; | ||
2887 | break; | ||
2888 | } | ||
2889 | |||
2890 | trace_pkt->status = trace_element_struct.trace_type; | ||
2891 | |||
2892 | trace_pkt->time_stamp = | ||
2893 | trace_element_struct.trace_time_stamp; | ||
2894 | |||
2895 | trace_pkt->real_length = | ||
2896 | trace_element_struct.trace_length; | ||
2897 | |||
2898 | /* see if we can fit the frame into the user buffer */ | ||
2899 | real_len = trace_pkt->real_length; | ||
2900 | |||
2901 | if (data_ptr == 0) { | ||
2902 | trace_pkt->data_avail = 0x00; | ||
2903 | } else { | ||
2904 | unsigned tmp = 0; | ||
2905 | |||
2906 | /* get the data from circular buffer | ||
2907 | must check for end of buffer */ | ||
2908 | trace_pkt->data_avail = 0x01; | ||
2909 | |||
2910 | if ((data_ptr + real_len) > | ||
2911 | chdlc_priv_area->end_addr_trace_buffer + 1){ | ||
2912 | |||
2913 | tmp = chdlc_priv_area->end_addr_trace_buffer - data_ptr + 1; | ||
2914 | sdla_peek(&card->hw, data_ptr, | ||
2915 | trace_pkt->data,tmp); | ||
2916 | data_ptr = chdlc_priv_area->base_addr_trace_buffer; | ||
2917 | } | ||
2918 | |||
2919 | sdla_peek(&card->hw, data_ptr, | ||
2920 | &trace_pkt->data[tmp], real_len - tmp); | ||
2921 | } | ||
2922 | |||
2923 | /* zero the opp flag to show we got the frame */ | ||
2924 | ut_char = 0x00; | ||
2925 | sdla_poke(&card->hw, chdlc_priv_area->curr_trace_addr, &ut_char, 1); | ||
2926 | |||
2927 | /* now move onto the next frame */ | ||
2928 | chdlc_priv_area->curr_trace_addr += sizeof(TRACE_STATUS_ELEMENT_STRUCT); | ||
2929 | |||
2930 | /* check if we went over the last address */ | ||
2931 | if ( chdlc_priv_area->curr_trace_addr > chdlc_priv_area->end_trace_addr ) { | ||
2932 | chdlc_priv_area->curr_trace_addr = chdlc_priv_area->start_trace_addr; | ||
2933 | } | ||
2934 | |||
2935 | if(trace_pkt->data_avail == 0x01) { | ||
2936 | buffer_length += real_len - 1; | ||
2937 | } | ||
2938 | |||
2939 | /* for the header */ | ||
2940 | buffer_length += sizeof(trace_pkt_t); | ||
2941 | |||
2942 | } /* For Loop */ | ||
2943 | |||
2944 | if (frames == chdlc_priv_area->number_trace_elements){ | ||
2945 | chdlc_udp_pkt->trace_info.ismoredata = 0x01; | ||
2946 | } | ||
2947 | chdlc_udp_pkt->trace_info.num_frames = frames; | ||
2948 | |||
2949 | mb->buffer_length = buffer_length; | ||
2950 | chdlc_udp_pkt->cblock.buffer_length = buffer_length; | ||
2951 | |||
2952 | chdlc_udp_pkt->cblock.return_code = COMMAND_OK; | ||
2953 | |||
2954 | break; | ||
2955 | |||
2956 | |||
2957 | case CPIPE_FT1_READ_STATUS: | ||
2958 | ((unsigned char *)chdlc_udp_pkt->data )[0] = | ||
2959 | flags->FT1_info_struct.parallel_port_A_input; | ||
2960 | |||
2961 | ((unsigned char *)chdlc_udp_pkt->data )[1] = | ||
2962 | flags->FT1_info_struct.parallel_port_B_input; | ||
2963 | |||
2964 | chdlc_udp_pkt->cblock.return_code = COMMAND_OK; | ||
2965 | chdlc_udp_pkt->cblock.buffer_length = 2; | ||
2966 | mb->buffer_length = 2; | ||
2967 | break; | ||
2968 | |||
2969 | case CPIPE_ROUTER_UP_TIME: | ||
2970 | do_gettimeofday( &tv ); | ||
2971 | chdlc_priv_area->router_up_time = tv.tv_sec - | ||
2972 | chdlc_priv_area->router_start_time; | ||
2973 | *(unsigned long *)&chdlc_udp_pkt->data = | ||
2974 | chdlc_priv_area->router_up_time; | ||
2975 | mb->buffer_length = sizeof(unsigned long); | ||
2976 | chdlc_udp_pkt->cblock.buffer_length = sizeof(unsigned long); | ||
2977 | chdlc_udp_pkt->cblock.return_code = COMMAND_OK; | ||
2978 | break; | ||
2979 | |||
2980 | case FT1_MONITOR_STATUS_CTRL: | ||
2981 | /* Enable FT1 MONITOR STATUS */ | ||
2982 | if ((chdlc_udp_pkt->data[0] & ENABLE_READ_FT1_STATUS) || | ||
2983 | (chdlc_udp_pkt->data[0] & ENABLE_READ_FT1_OP_STATS)) { | ||
2984 | |||
2985 | if( rCount++ != 0 ) { | ||
2986 | chdlc_udp_pkt->cblock. | ||
2987 | return_code = COMMAND_OK; | ||
2988 | mb->buffer_length = 1; | ||
2989 | break; | ||
2990 | } | ||
2991 | } | ||
2992 | |||
2993 | /* Disable FT1 MONITOR STATUS */ | ||
2994 | if( chdlc_udp_pkt->data[0] == 0) { | ||
2995 | |||
2996 | if( --rCount != 0) { | ||
2997 | chdlc_udp_pkt->cblock. | ||
2998 | return_code = COMMAND_OK; | ||
2999 | mb->buffer_length = 1; | ||
3000 | break; | ||
3001 | } | ||
3002 | } | ||
3003 | goto dflt_1; | ||
3004 | |||
3005 | default: | ||
3006 | dflt_1: | ||
3007 | /* it's a board command */ | ||
3008 | mb->command = chdlc_udp_pkt->cblock.command; | ||
3009 | mb->buffer_length = chdlc_udp_pkt->cblock.buffer_length; | ||
3010 | if (mb->buffer_length) { | ||
3011 | memcpy(&mb->data, (unsigned char *) chdlc_udp_pkt-> | ||
3012 | data, mb->buffer_length); | ||
3013 | } | ||
3014 | /* run the command on the board */ | ||
3015 | err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; | ||
3016 | if (err != COMMAND_OK) { | ||
3017 | break; | ||
3018 | } | ||
3019 | |||
3020 | /* copy the result back to our buffer */ | ||
3021 | memcpy(&chdlc_udp_pkt->cblock, mb, sizeof(cblock_t)); | ||
3022 | |||
3023 | if (mb->buffer_length) { | ||
3024 | memcpy(&chdlc_udp_pkt->data, &mb->data, | ||
3025 | mb->buffer_length); | ||
3026 | } | ||
3027 | |||
3028 | } /* end of switch */ | ||
3029 | } /* end of else */ | ||
3030 | |||
3031 | /* Fill UDP TTL */ | ||
3032 | chdlc_udp_pkt->ip_pkt.ttl = card->wandev.ttl; | ||
3033 | |||
3034 | len = reply_udp(chdlc_priv_area->udp_pkt_data, mb->buffer_length); | ||
3035 | |||
3036 | |||
3037 | if(chdlc_priv_area->udp_pkt_src == UDP_PKT_FRM_NETWORK){ | ||
3038 | |||
3039 | /* Must check if we interrupted if_send() routine. The | ||
3040 | * tx buffers might be used. If so drop the packet */ | ||
3041 | if (!test_bit(SEND_CRIT,&card->wandev.critical)) { | ||
3042 | |||
3043 | if(!chdlc_send(card, chdlc_priv_area->udp_pkt_data, len)) { | ||
3044 | ++ card->wandev.stats.tx_packets; | ||
3045 | card->wandev.stats.tx_bytes += len; | ||
3046 | } | ||
3047 | } | ||
3048 | } else { | ||
3049 | |||
3050 | /* Pass it up the stack | ||
3051 | Allocate socket buffer */ | ||
3052 | if ((new_skb = dev_alloc_skb(len)) != NULL) { | ||
3053 | /* copy data into new_skb */ | ||
3054 | |||
3055 | buf = skb_put(new_skb, len); | ||
3056 | memcpy(buf, chdlc_priv_area->udp_pkt_data, len); | ||
3057 | |||
3058 | /* Decapsulate pkt and pass it up the protocol stack */ | ||
3059 | new_skb->protocol = htons(ETH_P_IP); | ||
3060 | new_skb->dev = dev; | ||
3061 | new_skb->mac.raw = new_skb->data; | ||
3062 | |||
3063 | netif_rx(new_skb); | ||
3064 | dev->last_rx = jiffies; | ||
3065 | } else { | ||
3066 | |||
3067 | printk(KERN_INFO "%s: no socket buffers available!\n", | ||
3068 | card->devname); | ||
3069 | } | ||
3070 | } | ||
3071 | |||
3072 | chdlc_priv_area->udp_pkt_lgth = 0; | ||
3073 | |||
3074 | return 0; | ||
3075 | } | ||
3076 | |||
3077 | /*============================================================================ | ||
3078 | * Initialize Receive and Transmit Buffers. | ||
3079 | */ | ||
3080 | |||
3081 | static void init_chdlc_tx_rx_buff( sdla_t* card) | ||
3082 | { | ||
3083 | CHDLC_MAILBOX_STRUCT* mb = card->mbox; | ||
3084 | CHDLC_TX_STATUS_EL_CFG_STRUCT *tx_config; | ||
3085 | CHDLC_RX_STATUS_EL_CFG_STRUCT *rx_config; | ||
3086 | char err; | ||
3087 | |||
3088 | mb->buffer_length = 0; | ||
3089 | mb->command = READ_CHDLC_CONFIGURATION; | ||
3090 | err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; | ||
3091 | |||
3092 | if(err != COMMAND_OK) { | ||
3093 | if (card->wandev.dev){ | ||
3094 | chdlc_error(card,err,mb); | ||
3095 | } | ||
3096 | return; | ||
3097 | } | ||
3098 | |||
3099 | if(card->hw.type == SDLA_S514) { | ||
3100 | tx_config = (CHDLC_TX_STATUS_EL_CFG_STRUCT *)(card->hw.dpmbase + | ||
3101 | (((CHDLC_CONFIGURATION_STRUCT *)mb->data)-> | ||
3102 | ptr_CHDLC_Tx_stat_el_cfg_struct)); | ||
3103 | rx_config = (CHDLC_RX_STATUS_EL_CFG_STRUCT *)(card->hw.dpmbase + | ||
3104 | (((CHDLC_CONFIGURATION_STRUCT *)mb->data)-> | ||
3105 | ptr_CHDLC_Rx_stat_el_cfg_struct)); | ||
3106 | |||
3107 | /* Setup Head and Tails for buffers */ | ||
3108 | card->u.c.txbuf_base = (void *)(card->hw.dpmbase + | ||
3109 | tx_config->base_addr_Tx_status_elements); | ||
3110 | card->u.c.txbuf_last = | ||
3111 | (CHDLC_DATA_TX_STATUS_EL_STRUCT *) | ||
3112 | card->u.c.txbuf_base + | ||
3113 | (tx_config->number_Tx_status_elements - 1); | ||
3114 | |||
3115 | card->u.c.rxbuf_base = (void *)(card->hw.dpmbase + | ||
3116 | rx_config->base_addr_Rx_status_elements); | ||
3117 | card->u.c.rxbuf_last = | ||
3118 | (CHDLC_DATA_RX_STATUS_EL_STRUCT *) | ||
3119 | card->u.c.rxbuf_base + | ||
3120 | (rx_config->number_Rx_status_elements - 1); | ||
3121 | |||
3122 | /* Set up next pointer to be used */ | ||
3123 | card->u.c.txbuf = (void *)(card->hw.dpmbase + | ||
3124 | tx_config->next_Tx_status_element_to_use); | ||
3125 | card->u.c.rxmb = (void *)(card->hw.dpmbase + | ||
3126 | rx_config->next_Rx_status_element_to_use); | ||
3127 | } | ||
3128 | else { | ||
3129 | tx_config = (CHDLC_TX_STATUS_EL_CFG_STRUCT *)(card->hw.dpmbase + | ||
3130 | (((CHDLC_CONFIGURATION_STRUCT *)mb->data)-> | ||
3131 | ptr_CHDLC_Tx_stat_el_cfg_struct % SDLA_WINDOWSIZE)); | ||
3132 | |||
3133 | rx_config = (CHDLC_RX_STATUS_EL_CFG_STRUCT *)(card->hw.dpmbase + | ||
3134 | (((CHDLC_CONFIGURATION_STRUCT *)mb->data)-> | ||
3135 | ptr_CHDLC_Rx_stat_el_cfg_struct % SDLA_WINDOWSIZE)); | ||
3136 | |||
3137 | /* Setup Head and Tails for buffers */ | ||
3138 | card->u.c.txbuf_base = (void *)(card->hw.dpmbase + | ||
3139 | (tx_config->base_addr_Tx_status_elements % SDLA_WINDOWSIZE)); | ||
3140 | card->u.c.txbuf_last = | ||
3141 | (CHDLC_DATA_TX_STATUS_EL_STRUCT *)card->u.c.txbuf_base | ||
3142 | + (tx_config->number_Tx_status_elements - 1); | ||
3143 | card->u.c.rxbuf_base = (void *)(card->hw.dpmbase + | ||
3144 | (rx_config->base_addr_Rx_status_elements % SDLA_WINDOWSIZE)); | ||
3145 | card->u.c.rxbuf_last = | ||
3146 | (CHDLC_DATA_RX_STATUS_EL_STRUCT *)card->u.c.rxbuf_base | ||
3147 | + (rx_config->number_Rx_status_elements - 1); | ||
3148 | |||
3149 | /* Set up next pointer to be used */ | ||
3150 | card->u.c.txbuf = (void *)(card->hw.dpmbase + | ||
3151 | (tx_config->next_Tx_status_element_to_use % SDLA_WINDOWSIZE)); | ||
3152 | card->u.c.rxmb = (void *)(card->hw.dpmbase + | ||
3153 | (rx_config->next_Rx_status_element_to_use % SDLA_WINDOWSIZE)); | ||
3154 | } | ||
3155 | |||
3156 | /* Setup Actual Buffer Start and end addresses */ | ||
3157 | card->u.c.rx_base = rx_config->base_addr_Rx_buffer; | ||
3158 | card->u.c.rx_top = rx_config->end_addr_Rx_buffer; | ||
3159 | |||
3160 | } | ||
3161 | |||
3162 | /*============================================================================= | ||
3163 | * Perform Interrupt Test by running READ_CHDLC_CODE_VERSION command MAX_INTR | ||
3164 | * _TEST_COUNTER times. | ||
3165 | */ | ||
3166 | static int intr_test( sdla_t* card) | ||
3167 | { | ||
3168 | CHDLC_MAILBOX_STRUCT* mb = card->mbox; | ||
3169 | int err,i; | ||
3170 | |||
3171 | Intr_test_counter = 0; | ||
3172 | |||
3173 | err = chdlc_set_intr_mode(card, APP_INT_ON_COMMAND_COMPLETE); | ||
3174 | |||
3175 | if (err == CMD_OK) { | ||
3176 | for (i = 0; i < MAX_INTR_TEST_COUNTER; i ++) { | ||
3177 | mb->buffer_length = 0; | ||
3178 | mb->command = READ_CHDLC_CODE_VERSION; | ||
3179 | err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; | ||
3180 | if (err != CMD_OK) | ||
3181 | chdlc_error(card, err, mb); | ||
3182 | } | ||
3183 | } | ||
3184 | else { | ||
3185 | return err; | ||
3186 | } | ||
3187 | |||
3188 | err = chdlc_set_intr_mode(card, 0); | ||
3189 | |||
3190 | if (err != CMD_OK) | ||
3191 | return err; | ||
3192 | |||
3193 | return 0; | ||
3194 | } | ||
3195 | |||
3196 | /*============================================================================== | ||
3197 | * Determine what type of UDP call it is. CPIPEAB ? | ||
3198 | */ | ||
3199 | static int udp_pkt_type(struct sk_buff *skb, sdla_t* card) | ||
3200 | { | ||
3201 | chdlc_udp_pkt_t *chdlc_udp_pkt = (chdlc_udp_pkt_t *)skb->data; | ||
3202 | |||
3203 | #ifdef _WAN_UDP_DEBUG | ||
3204 | printk(KERN_INFO "SIG %s = %s\n\ | ||
3205 | UPP %x = %x\n\ | ||
3206 | PRT %x = %x\n\ | ||
3207 | REQ %i = %i\n\ | ||
3208 | 36 th = %x 37th = %x\n", | ||
3209 | chdlc_udp_pkt->wp_mgmt.signature, | ||
3210 | UDPMGMT_SIGNATURE, | ||
3211 | chdlc_udp_pkt->udp_pkt.udp_dst_port, | ||
3212 | ntohs(card->wandev.udp_port), | ||
3213 | chdlc_udp_pkt->ip_pkt.protocol, | ||
3214 | UDPMGMT_UDP_PROTOCOL, | ||
3215 | chdlc_udp_pkt->wp_mgmt.request_reply, | ||
3216 | UDPMGMT_REQUEST, | ||
3217 | skb->data[36], skb->data[37]); | ||
3218 | #endif | ||
3219 | |||
3220 | if (!strncmp(chdlc_udp_pkt->wp_mgmt.signature,UDPMGMT_SIGNATURE,8) && | ||
3221 | (chdlc_udp_pkt->udp_pkt.udp_dst_port == ntohs(card->wandev.udp_port)) && | ||
3222 | (chdlc_udp_pkt->ip_pkt.protocol == UDPMGMT_UDP_PROTOCOL) && | ||
3223 | (chdlc_udp_pkt->wp_mgmt.request_reply == UDPMGMT_REQUEST)) { | ||
3224 | |||
3225 | return UDP_CPIPE_TYPE; | ||
3226 | |||
3227 | }else{ | ||
3228 | return UDP_INVALID_TYPE; | ||
3229 | } | ||
3230 | } | ||
3231 | |||
3232 | /*============================================================================ | ||
3233 | * Set PORT state. | ||
3234 | */ | ||
3235 | static void port_set_state (sdla_t *card, int state) | ||
3236 | { | ||
3237 | if (card->u.c.state != state) | ||
3238 | { | ||
3239 | switch (state) | ||
3240 | { | ||
3241 | case WAN_CONNECTED: | ||
3242 | printk (KERN_INFO "%s: Link connected!\n", | ||
3243 | card->devname); | ||
3244 | break; | ||
3245 | |||
3246 | case WAN_CONNECTING: | ||
3247 | printk (KERN_INFO "%s: Link connecting...\n", | ||
3248 | card->devname); | ||
3249 | break; | ||
3250 | |||
3251 | case WAN_DISCONNECTED: | ||
3252 | printk (KERN_INFO "%s: Link disconnected!\n", | ||
3253 | card->devname); | ||
3254 | break; | ||
3255 | } | ||
3256 | |||
3257 | card->wandev.state = card->u.c.state = state; | ||
3258 | if (card->wandev.dev){ | ||
3259 | struct net_device *dev = card->wandev.dev; | ||
3260 | chdlc_private_area_t *chdlc_priv_area = dev->priv; | ||
3261 | chdlc_priv_area->common.state = state; | ||
3262 | } | ||
3263 | } | ||
3264 | } | ||
3265 | |||
3266 | /*=========================================================================== | ||
3267 | * config_chdlc | ||
3268 | * | ||
3269 | * Configure the chdlc protocol and enable communications. | ||
3270 | * | ||
3271 | * The if_open() function binds this function to the poll routine. | ||
3272 | * Therefore, this function will run every time the chdlc interface | ||
3273 | * is brought up. We cannot run this function from the if_open | ||
3274 | * because if_open does not have access to the remote IP address. | ||
3275 | * | ||
3276 | * If the communications are not enabled, proceed to configure | ||
3277 | * the card and enable communications. | ||
3278 | * | ||
3279 | * If the communications are enabled, it means that the interface | ||
3280 | * was shutdown by ether the user or driver. In this case, we | ||
3281 | * have to check that the IP addresses have not changed. If | ||
3282 | * the IP addresses have changed, we have to reconfigure the firmware | ||
3283 | * and update the changed IP addresses. Otherwise, just exit. | ||
3284 | * | ||
3285 | */ | ||
3286 | |||
3287 | static int config_chdlc (sdla_t *card) | ||
3288 | { | ||
3289 | struct net_device *dev = card->wandev.dev; | ||
3290 | chdlc_private_area_t *chdlc_priv_area = dev->priv; | ||
3291 | SHARED_MEMORY_INFO_STRUCT *flags = card->u.c.flags; | ||
3292 | |||
3293 | if (card->u.c.comm_enabled){ | ||
3294 | |||
3295 | /* Jun 20. 2000: NC | ||
3296 | * IP addresses are not used in the API mode */ | ||
3297 | |||
3298 | if ((chdlc_priv_area->ip_local_tmp != chdlc_priv_area->ip_local || | ||
3299 | chdlc_priv_area->ip_remote_tmp != chdlc_priv_area->ip_remote) && | ||
3300 | card->u.c.usedby == WANPIPE) { | ||
3301 | |||
3302 | /* The IP addersses have changed, we must | ||
3303 | * stop the communications and reconfigure | ||
3304 | * the card. Reason: the firmware must know | ||
3305 | * the local and remote IP addresses. */ | ||
3306 | disable_comm(card); | ||
3307 | port_set_state(card, WAN_DISCONNECTED); | ||
3308 | printk(KERN_INFO | ||
3309 | "%s: IP addresses changed!\n", | ||
3310 | card->devname); | ||
3311 | printk(KERN_INFO | ||
3312 | "%s: Restarting communications ...\n", | ||
3313 | card->devname); | ||
3314 | }else{ | ||
3315 | /* IP addresses are the same and the link is up, | ||
3316 | * we don't have to do anything here. Therefore, exit */ | ||
3317 | return 0; | ||
3318 | } | ||
3319 | } | ||
3320 | |||
3321 | chdlc_priv_area->ip_local = chdlc_priv_area->ip_local_tmp; | ||
3322 | chdlc_priv_area->ip_remote = chdlc_priv_area->ip_remote_tmp; | ||
3323 | |||
3324 | |||
3325 | /* Setup the Board for asynchronous mode */ | ||
3326 | if (card->u.c.async_mode){ | ||
3327 | |||
3328 | if (set_asy_config(card)) { | ||
3329 | printk (KERN_INFO "%s: Failed CHDLC Async configuration!\n", | ||
3330 | card->devname); | ||
3331 | return 0; | ||
3332 | } | ||
3333 | }else{ | ||
3334 | /* Setup the Board for CHDLC */ | ||
3335 | if (set_chdlc_config(card)) { | ||
3336 | printk (KERN_INFO "%s: Failed CHDLC configuration!\n", | ||
3337 | card->devname); | ||
3338 | return 0; | ||
3339 | } | ||
3340 | } | ||
3341 | |||
3342 | /* Set interrupt mode and mask */ | ||
3343 | if (chdlc_set_intr_mode(card, APP_INT_ON_RX_FRAME | | ||
3344 | APP_INT_ON_GLOBAL_EXCEP_COND | | ||
3345 | APP_INT_ON_TX_FRAME | | ||
3346 | APP_INT_ON_CHDLC_EXCEP_COND | APP_INT_ON_TIMER)){ | ||
3347 | printk (KERN_INFO "%s: Failed to set interrupt triggers!\n", | ||
3348 | card->devname); | ||
3349 | return 0; | ||
3350 | } | ||
3351 | |||
3352 | |||
3353 | /* Mask the Transmit and Timer interrupt */ | ||
3354 | flags->interrupt_info_struct.interrupt_permission &= | ||
3355 | ~(APP_INT_ON_TX_FRAME | APP_INT_ON_TIMER); | ||
3356 | |||
3357 | /* In TTY mode, receive interrupt will be enabled during | ||
3358 | * wanpipe_tty_open() operation */ | ||
3359 | if (card->tty_opt){ | ||
3360 | flags->interrupt_info_struct.interrupt_permission &= ~APP_INT_ON_RX_FRAME; | ||
3361 | } | ||
3362 | |||
3363 | /* Enable communications */ | ||
3364 | if (card->u.c.async_mode){ | ||
3365 | if (asy_comm_enable(card) != 0) { | ||
3366 | printk(KERN_INFO "%s: Failed to enable async commnunication!\n", | ||
3367 | card->devname); | ||
3368 | flags->interrupt_info_struct.interrupt_permission = 0; | ||
3369 | card->u.c.comm_enabled=0; | ||
3370 | chdlc_set_intr_mode(card,0); | ||
3371 | return 0; | ||
3372 | } | ||
3373 | }else{ | ||
3374 | if (chdlc_comm_enable(card) != 0) { | ||
3375 | printk(KERN_INFO "%s: Failed to enable chdlc communications!\n", | ||
3376 | card->devname); | ||
3377 | flags->interrupt_info_struct.interrupt_permission = 0; | ||
3378 | card->u.c.comm_enabled=0; | ||
3379 | chdlc_set_intr_mode(card,0); | ||
3380 | return 0; | ||
3381 | } | ||
3382 | } | ||
3383 | |||
3384 | /* Initialize Rx/Tx buffer control fields */ | ||
3385 | init_chdlc_tx_rx_buff(card); | ||
3386 | port_set_state(card, WAN_CONNECTING); | ||
3387 | return 0; | ||
3388 | } | ||
3389 | |||
3390 | |||
3391 | /*============================================================ | ||
3392 | * chdlc_poll | ||
3393 | * | ||
3394 | * Rationale: | ||
3395 | * We cannot manipulate the routing tables, or | ||
3396 | * ip addresses withing the interrupt. Therefore | ||
3397 | * we must perform such actons outside an interrupt | ||
3398 | * at a later time. | ||
3399 | * | ||
3400 | * Description: | ||
3401 | * CHDLC polling routine, responsible for | ||
3402 | * shutting down interfaces upon disconnect | ||
3403 | * and adding/removing routes. | ||
3404 | * | ||
3405 | * Usage: | ||
3406 | * This function is executed for each CHDLC | ||
3407 | * interface through a tq_schedule bottom half. | ||
3408 | * | ||
3409 | * trigger_chdlc_poll() function is used to kick | ||
3410 | * the chldc_poll routine. | ||
3411 | */ | ||
3412 | |||
3413 | static void chdlc_poll(struct net_device *dev) | ||
3414 | { | ||
3415 | chdlc_private_area_t *chdlc_priv_area; | ||
3416 | sdla_t *card; | ||
3417 | u8 check_gateway=0; | ||
3418 | SHARED_MEMORY_INFO_STRUCT* flags; | ||
3419 | |||
3420 | |||
3421 | if (!dev || (chdlc_priv_area=dev->priv) == NULL) | ||
3422 | return; | ||
3423 | |||
3424 | card = chdlc_priv_area->card; | ||
3425 | flags = card->u.c.flags; | ||
3426 | |||
3427 | /* (Re)Configuraiton is in progress, stop what you are | ||
3428 | * doing and get out */ | ||
3429 | if (test_bit(PERI_CRIT,&card->wandev.critical)){ | ||
3430 | clear_bit(POLL_CRIT,&card->wandev.critical); | ||
3431 | return; | ||
3432 | } | ||
3433 | |||
3434 | /* if_open() function has triggered the polling routine | ||
3435 | * to determine the configured IP addresses. Once the | ||
3436 | * addresses are found, trigger the chdlc configuration */ | ||
3437 | if (test_bit(0,&chdlc_priv_area->config_chdlc)){ | ||
3438 | |||
3439 | chdlc_priv_area->ip_local_tmp = get_ip_address(dev,WAN_LOCAL_IP); | ||
3440 | chdlc_priv_area->ip_remote_tmp = get_ip_address(dev,WAN_POINTOPOINT_IP); | ||
3441 | |||
3442 | /* Jun 20. 2000 Bug Fix | ||
3443 | * Only perform this check in WANPIPE mode, since | ||
3444 | * IP addresses are not used in the API mode. */ | ||
3445 | |||
3446 | if (chdlc_priv_area->ip_local_tmp == chdlc_priv_area->ip_remote_tmp && | ||
3447 | card->u.c.slarp_timer == 0x00 && | ||
3448 | !card->u.c.backup && | ||
3449 | card->u.c.usedby == WANPIPE){ | ||
3450 | |||
3451 | if (++chdlc_priv_area->ip_error > MAX_IP_ERRORS){ | ||
3452 | printk(KERN_INFO "\n%s: --- WARNING ---\n", | ||
3453 | card->devname); | ||
3454 | printk(KERN_INFO | ||
3455 | "%s: The local IP address is the same as the\n", | ||
3456 | card->devname); | ||
3457 | printk(KERN_INFO | ||
3458 | "%s: Point-to-Point IP address.\n", | ||
3459 | card->devname); | ||
3460 | printk(KERN_INFO "%s: --- WARNING ---\n\n", | ||
3461 | card->devname); | ||
3462 | }else{ | ||
3463 | clear_bit(POLL_CRIT,&card->wandev.critical); | ||
3464 | chdlc_priv_area->poll_delay_timer.expires = jiffies+HZ; | ||
3465 | add_timer(&chdlc_priv_area->poll_delay_timer); | ||
3466 | return; | ||
3467 | } | ||
3468 | } | ||
3469 | |||
3470 | clear_bit(0,&chdlc_priv_area->config_chdlc); | ||
3471 | clear_bit(POLL_CRIT,&card->wandev.critical); | ||
3472 | |||
3473 | chdlc_priv_area->timer_int_enabled |= TMR_INT_ENABLED_CONFIG; | ||
3474 | flags->interrupt_info_struct.interrupt_permission |= APP_INT_ON_TIMER; | ||
3475 | return; | ||
3476 | } | ||
3477 | /* Dynamic interface implementation, as well as dynamic | ||
3478 | * routing. */ | ||
3479 | |||
3480 | switch (card->u.c.state){ | ||
3481 | |||
3482 | case WAN_DISCONNECTED: | ||
3483 | |||
3484 | /* If the dynamic interface configuration is on, and interface | ||
3485 | * is up, then bring down the netowrk interface */ | ||
3486 | |||
3487 | if (test_bit(DYN_OPT_ON,&chdlc_priv_area->interface_down) && | ||
3488 | !test_bit(DEV_DOWN, &chdlc_priv_area->interface_down) && | ||
3489 | card->wandev.dev->flags & IFF_UP){ | ||
3490 | |||
3491 | printk(KERN_INFO "%s: Interface %s down.\n", | ||
3492 | card->devname,card->wandev.dev->name); | ||
3493 | change_dev_flags(card->wandev.dev,(card->wandev.dev->flags&~IFF_UP)); | ||
3494 | set_bit(DEV_DOWN,&chdlc_priv_area->interface_down); | ||
3495 | chdlc_priv_area->route_status = NO_ROUTE; | ||
3496 | |||
3497 | }else{ | ||
3498 | /* We need to check if the local IP address is | ||
3499 | * zero. If it is, we shouldn't try to remove it. | ||
3500 | */ | ||
3501 | |||
3502 | if (card->wandev.dev->flags & IFF_UP && | ||
3503 | get_ip_address(card->wandev.dev,WAN_LOCAL_IP) && | ||
3504 | chdlc_priv_area->route_status != NO_ROUTE && | ||
3505 | card->u.c.slarp_timer){ | ||
3506 | |||
3507 | process_route(card); | ||
3508 | } | ||
3509 | } | ||
3510 | break; | ||
3511 | |||
3512 | case WAN_CONNECTED: | ||
3513 | |||
3514 | /* In SMP machine this code can execute before the interface | ||
3515 | * comes up. In this case, we must make sure that we do not | ||
3516 | * try to bring up the interface before dev_open() is finished */ | ||
3517 | |||
3518 | |||
3519 | /* DEV_DOWN will be set only when we bring down the interface | ||
3520 | * for the very first time. This way we know that it was us | ||
3521 | * that brought the interface down */ | ||
3522 | |||
3523 | if (test_bit(DYN_OPT_ON,&chdlc_priv_area->interface_down) && | ||
3524 | test_bit(DEV_DOWN, &chdlc_priv_area->interface_down) && | ||
3525 | !(card->wandev.dev->flags & IFF_UP)){ | ||
3526 | |||
3527 | printk(KERN_INFO "%s: Interface %s up.\n", | ||
3528 | card->devname,card->wandev.dev->name); | ||
3529 | change_dev_flags(card->wandev.dev,(card->wandev.dev->flags|IFF_UP)); | ||
3530 | clear_bit(DEV_DOWN,&chdlc_priv_area->interface_down); | ||
3531 | check_gateway=1; | ||
3532 | } | ||
3533 | |||
3534 | if (chdlc_priv_area->route_status == ADD_ROUTE && | ||
3535 | card->u.c.slarp_timer){ | ||
3536 | |||
3537 | process_route(card); | ||
3538 | check_gateway=1; | ||
3539 | } | ||
3540 | |||
3541 | if (chdlc_priv_area->gateway && check_gateway) | ||
3542 | add_gateway(card,dev); | ||
3543 | |||
3544 | break; | ||
3545 | } | ||
3546 | |||
3547 | clear_bit(POLL_CRIT,&card->wandev.critical); | ||
3548 | } | ||
3549 | |||
3550 | /*============================================================ | ||
3551 | * trigger_chdlc_poll | ||
3552 | * | ||
3553 | * Description: | ||
3554 | * Add a chdlc_poll() work entry into the keventd work queue | ||
3555 | * for a specific dlci/interface. This will kick | ||
3556 | * the fr_poll() routine at a later time. | ||
3557 | * | ||
3558 | * Usage: | ||
3559 | * Interrupts use this to defer a taks to | ||
3560 | * a polling routine. | ||
3561 | * | ||
3562 | */ | ||
3563 | static void trigger_chdlc_poll(struct net_device *dev) | ||
3564 | { | ||
3565 | chdlc_private_area_t *chdlc_priv_area; | ||
3566 | sdla_t *card; | ||
3567 | |||
3568 | if (!dev) | ||
3569 | return; | ||
3570 | |||
3571 | if ((chdlc_priv_area = dev->priv)==NULL) | ||
3572 | return; | ||
3573 | |||
3574 | card = chdlc_priv_area->card; | ||
3575 | |||
3576 | if (test_and_set_bit(POLL_CRIT,&card->wandev.critical)){ | ||
3577 | return; | ||
3578 | } | ||
3579 | if (test_bit(PERI_CRIT,&card->wandev.critical)){ | ||
3580 | return; | ||
3581 | } | ||
3582 | schedule_work(&chdlc_priv_area->poll_work); | ||
3583 | } | ||
3584 | |||
3585 | |||
3586 | static void chdlc_poll_delay (unsigned long dev_ptr) | ||
3587 | { | ||
3588 | struct net_device *dev = (struct net_device *)dev_ptr; | ||
3589 | trigger_chdlc_poll(dev); | ||
3590 | } | ||
3591 | |||
3592 | |||
3593 | void s508_lock (sdla_t *card, unsigned long *smp_flags) | ||
3594 | { | ||
3595 | spin_lock_irqsave(&card->wandev.lock, *smp_flags); | ||
3596 | if (card->next){ | ||
3597 | spin_lock(&card->next->wandev.lock); | ||
3598 | } | ||
3599 | } | ||
3600 | |||
3601 | void s508_unlock (sdla_t *card, unsigned long *smp_flags) | ||
3602 | { | ||
3603 | if (card->next){ | ||
3604 | spin_unlock(&card->next->wandev.lock); | ||
3605 | } | ||
3606 | spin_unlock_irqrestore(&card->wandev.lock, *smp_flags); | ||
3607 | } | ||
3608 | |||
3609 | //*********** TTY SECTION **************** | ||
3610 | |||
3611 | static void wanpipe_tty_trigger_tx_irq(sdla_t *card) | ||
3612 | { | ||
3613 | SHARED_MEMORY_INFO_STRUCT *flags = card->u.c.flags; | ||
3614 | INTERRUPT_INFORMATION_STRUCT *chdlc_int = &flags->interrupt_info_struct; | ||
3615 | chdlc_int->interrupt_permission |= APP_INT_ON_TX_FRAME; | ||
3616 | } | ||
3617 | |||
3618 | static void wanpipe_tty_trigger_poll(sdla_t *card) | ||
3619 | { | ||
3620 | schedule_work(&card->tty_work); | ||
3621 | } | ||
3622 | |||
3623 | static void tty_poll_work (void* data) | ||
3624 | { | ||
3625 | sdla_t *card = (sdla_t*)data; | ||
3626 | struct tty_struct *tty; | ||
3627 | |||
3628 | if ((tty=card->tty)==NULL) | ||
3629 | return; | ||
3630 | |||
3631 | tty_wakeup(tty); | ||
3632 | #if defined(SERIAL_HAVE_POLL_WAIT) | ||
3633 | wake_up_interruptible(&tty->poll_wait); | ||
3634 | #endif | ||
3635 | return; | ||
3636 | } | ||
3637 | |||
3638 | static void wanpipe_tty_close(struct tty_struct *tty, struct file * filp) | ||
3639 | { | ||
3640 | sdla_t *card; | ||
3641 | unsigned long smp_flags; | ||
3642 | |||
3643 | if (!tty || !tty->driver_data){ | ||
3644 | return; | ||
3645 | } | ||
3646 | |||
3647 | card = (sdla_t*)tty->driver_data; | ||
3648 | |||
3649 | if (!card) | ||
3650 | return; | ||
3651 | |||
3652 | printk(KERN_INFO "%s: Closing TTY Driver!\n", | ||
3653 | card->devname); | ||
3654 | |||
3655 | /* Sanity Check */ | ||
3656 | if (!card->tty_open) | ||
3657 | return; | ||
3658 | |||
3659 | wanpipe_close(card); | ||
3660 | if (--card->tty_open == 0){ | ||
3661 | |||
3662 | lock_adapter_irq(&card->wandev.lock,&smp_flags); | ||
3663 | card->tty=NULL; | ||
3664 | chdlc_disable_comm_shutdown(card); | ||
3665 | unlock_adapter_irq(&card->wandev.lock,&smp_flags); | ||
3666 | |||
3667 | kfree(card->tty_buf); | ||
3668 | card->tty_buf = NULL; | ||
3669 | kfree(card->tty_rx); | ||
3670 | card->tty_rx = NULL; | ||
3671 | } | ||
3672 | return; | ||
3673 | } | ||
3674 | static int wanpipe_tty_open(struct tty_struct *tty, struct file * filp) | ||
3675 | { | ||
3676 | unsigned long smp_flags; | ||
3677 | sdla_t *card; | ||
3678 | |||
3679 | if (!tty){ | ||
3680 | return -ENODEV; | ||
3681 | } | ||
3682 | |||
3683 | if (!tty->driver_data){ | ||
3684 | int port; | ||
3685 | port = tty->index; | ||
3686 | if ((port < 0) || (port >= NR_PORTS)) | ||
3687 | return -ENODEV; | ||
3688 | |||
3689 | tty->driver_data = WAN_CARD(port); | ||
3690 | if (!tty->driver_data) | ||
3691 | return -ENODEV; | ||
3692 | } | ||
3693 | |||
3694 | card = (sdla_t*)tty->driver_data; | ||
3695 | |||
3696 | if (!card){ | ||
3697 | lock_adapter_irq(&card->wandev.lock,&smp_flags); | ||
3698 | card->tty=NULL; | ||
3699 | unlock_adapter_irq(&card->wandev.lock,&smp_flags); | ||
3700 | return -ENODEV; | ||
3701 | } | ||
3702 | |||
3703 | printk(KERN_INFO "%s: Opening TTY Driver!\n", | ||
3704 | card->devname); | ||
3705 | |||
3706 | if (card->tty_open == 0){ | ||
3707 | lock_adapter_irq(&card->wandev.lock,&smp_flags); | ||
3708 | card->tty=tty; | ||
3709 | unlock_adapter_irq(&card->wandev.lock,&smp_flags); | ||
3710 | |||
3711 | if (!card->tty_buf){ | ||
3712 | card->tty_buf = kmalloc(TTY_CHDLC_MAX_MTU, GFP_KERNEL); | ||
3713 | if (!card->tty_buf){ | ||
3714 | card->tty_buf=NULL; | ||
3715 | card->tty=NULL; | ||
3716 | return -ENOMEM; | ||
3717 | } | ||
3718 | } | ||
3719 | |||
3720 | if (!card->tty_rx){ | ||
3721 | card->tty_rx = kmalloc(TTY_CHDLC_MAX_MTU, GFP_KERNEL); | ||
3722 | if (!card->tty_rx){ | ||
3723 | /* Free the buffer above */ | ||
3724 | kfree(card->tty_buf); | ||
3725 | card->tty_buf=NULL; | ||
3726 | card->tty=NULL; | ||
3727 | return -ENOMEM; | ||
3728 | } | ||
3729 | } | ||
3730 | } | ||
3731 | |||
3732 | ++card->tty_open; | ||
3733 | wanpipe_open(card); | ||
3734 | return 0; | ||
3735 | } | ||
3736 | |||
3737 | static int wanpipe_tty_write(struct tty_struct * tty, const unsigned char *buf, int count) | ||
3738 | { | ||
3739 | unsigned long smp_flags=0; | ||
3740 | sdla_t *card=NULL; | ||
3741 | |||
3742 | if (!tty){ | ||
3743 | dbg_printk(KERN_INFO "NO TTY in Write\n"); | ||
3744 | return -ENODEV; | ||
3745 | } | ||
3746 | |||
3747 | card = (sdla_t *)tty->driver_data; | ||
3748 | |||
3749 | if (!card){ | ||
3750 | dbg_printk(KERN_INFO "No Card in TTY Write\n"); | ||
3751 | return -ENODEV; | ||
3752 | } | ||
3753 | |||
3754 | if (count > card->wandev.mtu){ | ||
3755 | dbg_printk(KERN_INFO "Frame too big in Write %i Max: %i\n", | ||
3756 | count,card->wandev.mtu); | ||
3757 | return -EINVAL; | ||
3758 | } | ||
3759 | |||
3760 | if (card->wandev.state != WAN_CONNECTED){ | ||
3761 | dbg_printk(KERN_INFO "Card not connected in TTY Write\n"); | ||
3762 | return -EINVAL; | ||
3763 | } | ||
3764 | |||
3765 | /* Lock the 508 Card: SMP is supported */ | ||
3766 | if(card->hw.type != SDLA_S514){ | ||
3767 | s508_lock(card,&smp_flags); | ||
3768 | } | ||
3769 | |||
3770 | if (test_and_set_bit(SEND_CRIT,(void*)&card->wandev.critical)){ | ||
3771 | printk(KERN_INFO "%s: Critical in TTY Write\n", | ||
3772 | card->devname); | ||
3773 | |||
3774 | /* Lock the 508 Card: SMP is supported */ | ||
3775 | if(card->hw.type != SDLA_S514) | ||
3776 | s508_unlock(card,&smp_flags); | ||
3777 | |||
3778 | return -EINVAL; | ||
3779 | } | ||
3780 | |||
3781 | if (chdlc_send(card,(void*)buf,count)){ | ||
3782 | dbg_printk(KERN_INFO "%s: Failed to send, retry later: kernel!\n", | ||
3783 | card->devname); | ||
3784 | clear_bit(SEND_CRIT,(void*)&card->wandev.critical); | ||
3785 | |||
3786 | wanpipe_tty_trigger_tx_irq(card); | ||
3787 | |||
3788 | if(card->hw.type != SDLA_S514) | ||
3789 | s508_unlock(card,&smp_flags); | ||
3790 | return 0; | ||
3791 | } | ||
3792 | dbg_printk(KERN_INFO "%s: Packet sent OK: %i\n",card->devname,count); | ||
3793 | clear_bit(SEND_CRIT,(void*)&card->wandev.critical); | ||
3794 | |||
3795 | if(card->hw.type != SDLA_S514) | ||
3796 | s508_unlock(card,&smp_flags); | ||
3797 | |||
3798 | return count; | ||
3799 | } | ||
3800 | |||
3801 | static void wanpipe_tty_receive(sdla_t *card, unsigned addr, unsigned int len) | ||
3802 | { | ||
3803 | unsigned offset=0; | ||
3804 | unsigned olen=len; | ||
3805 | char fp=0; | ||
3806 | struct tty_struct *tty; | ||
3807 | int i; | ||
3808 | struct tty_ldisc *ld; | ||
3809 | |||
3810 | if (!card->tty_open){ | ||
3811 | dbg_printk(KERN_INFO "%s: TTY not open during receive\n", | ||
3812 | card->devname); | ||
3813 | return; | ||
3814 | } | ||
3815 | |||
3816 | if ((tty=card->tty) == NULL){ | ||
3817 | dbg_printk(KERN_INFO "%s: No TTY on receive\n", | ||
3818 | card->devname); | ||
3819 | return; | ||
3820 | } | ||
3821 | |||
3822 | if (!tty->driver_data){ | ||
3823 | dbg_printk(KERN_INFO "%s: No Driver Data, or Flip on receive\n", | ||
3824 | card->devname); | ||
3825 | return; | ||
3826 | } | ||
3827 | |||
3828 | |||
3829 | if (card->u.c.async_mode){ | ||
3830 | if ((tty->flip.count+len) >= TTY_FLIPBUF_SIZE){ | ||
3831 | if (net_ratelimit()){ | ||
3832 | printk(KERN_INFO | ||
3833 | "%s: Received packet size too big: %i bytes, Max: %i!\n", | ||
3834 | card->devname,len,TTY_FLIPBUF_SIZE); | ||
3835 | } | ||
3836 | return; | ||
3837 | } | ||
3838 | |||
3839 | |||
3840 | if((addr + len) > card->u.c.rx_top + 1) { | ||
3841 | offset = card->u.c.rx_top - addr + 1; | ||
3842 | |||
3843 | sdla_peek(&card->hw, addr, tty->flip.char_buf_ptr, offset); | ||
3844 | |||
3845 | addr = card->u.c.rx_base; | ||
3846 | len -= offset; | ||
3847 | |||
3848 | tty->flip.char_buf_ptr+=offset; | ||
3849 | tty->flip.count+=offset; | ||
3850 | for (i=0;i<offset;i++){ | ||
3851 | *tty->flip.flag_buf_ptr = 0; | ||
3852 | tty->flip.flag_buf_ptr++; | ||
3853 | } | ||
3854 | } | ||
3855 | |||
3856 | sdla_peek(&card->hw, addr, tty->flip.char_buf_ptr, len); | ||
3857 | |||
3858 | tty->flip.char_buf_ptr+=len; | ||
3859 | card->tty->flip.count+=len; | ||
3860 | for (i=0;i<len;i++){ | ||
3861 | *tty->flip.flag_buf_ptr = 0; | ||
3862 | tty->flip.flag_buf_ptr++; | ||
3863 | } | ||
3864 | |||
3865 | tty->low_latency=1; | ||
3866 | tty_flip_buffer_push(tty); | ||
3867 | }else{ | ||
3868 | if (!card->tty_rx){ | ||
3869 | if (net_ratelimit()){ | ||
3870 | printk(KERN_INFO | ||
3871 | "%s: Receive sync buffer not available!\n", | ||
3872 | card->devname); | ||
3873 | } | ||
3874 | return; | ||
3875 | } | ||
3876 | |||
3877 | if (len > TTY_CHDLC_MAX_MTU){ | ||
3878 | if (net_ratelimit()){ | ||
3879 | printk(KERN_INFO | ||
3880 | "%s: Received packet size too big: %i bytes, Max: %i!\n", | ||
3881 | card->devname,len,TTY_FLIPBUF_SIZE); | ||
3882 | } | ||
3883 | return; | ||
3884 | } | ||
3885 | |||
3886 | |||
3887 | if((addr + len) > card->u.c.rx_top + 1) { | ||
3888 | offset = card->u.c.rx_top - addr + 1; | ||
3889 | |||
3890 | sdla_peek(&card->hw, addr, card->tty_rx, offset); | ||
3891 | |||
3892 | addr = card->u.c.rx_base; | ||
3893 | len -= offset; | ||
3894 | } | ||
3895 | sdla_peek(&card->hw, addr, card->tty_rx+offset, len); | ||
3896 | ld = tty_ldisc_ref(tty); | ||
3897 | if (ld) { | ||
3898 | if (ld->receive_buf) | ||
3899 | ld->receive_buf(tty,card->tty_rx,&fp,olen); | ||
3900 | tty_ldisc_deref(ld); | ||
3901 | }else{ | ||
3902 | if (net_ratelimit()){ | ||
3903 | printk(KERN_INFO | ||
3904 | "%s: NO TTY Sync line discipline!\n", | ||
3905 | card->devname); | ||
3906 | } | ||
3907 | } | ||
3908 | } | ||
3909 | |||
3910 | dbg_printk(KERN_INFO "%s: Received Data %i\n",card->devname,olen); | ||
3911 | return; | ||
3912 | } | ||
3913 | |||
3914 | #if 0 | ||
3915 | static int wanpipe_tty_ioctl(struct tty_struct *tty, struct file * file, | ||
3916 | unsigned int cmd, unsigned long arg) | ||
3917 | { | ||
3918 | return -ENOIOCTLCMD; | ||
3919 | } | ||
3920 | #endif | ||
3921 | |||
3922 | static void wanpipe_tty_stop(struct tty_struct *tty) | ||
3923 | { | ||
3924 | return; | ||
3925 | } | ||
3926 | |||
3927 | static void wanpipe_tty_start(struct tty_struct *tty) | ||
3928 | { | ||
3929 | return; | ||
3930 | } | ||
3931 | |||
3932 | static int config_tty (sdla_t *card) | ||
3933 | { | ||
3934 | SHARED_MEMORY_INFO_STRUCT *flags = card->u.c.flags; | ||
3935 | |||
3936 | /* Setup the Board for asynchronous mode */ | ||
3937 | if (card->u.c.async_mode){ | ||
3938 | |||
3939 | if (set_asy_config(card)) { | ||
3940 | printk (KERN_INFO "%s: Failed CHDLC Async configuration!\n", | ||
3941 | card->devname); | ||
3942 | return -EINVAL; | ||
3943 | } | ||
3944 | }else{ | ||
3945 | /* Setup the Board for CHDLC */ | ||
3946 | if (set_chdlc_config(card)) { | ||
3947 | printk (KERN_INFO "%s: Failed CHDLC configuration!\n", | ||
3948 | card->devname); | ||
3949 | return -EINVAL; | ||
3950 | } | ||
3951 | } | ||
3952 | |||
3953 | /* Set interrupt mode and mask */ | ||
3954 | if (chdlc_set_intr_mode(card, APP_INT_ON_RX_FRAME | | ||
3955 | APP_INT_ON_GLOBAL_EXCEP_COND | | ||
3956 | APP_INT_ON_TX_FRAME | | ||
3957 | APP_INT_ON_CHDLC_EXCEP_COND | APP_INT_ON_TIMER)){ | ||
3958 | printk (KERN_INFO "%s: Failed to set interrupt triggers!\n", | ||
3959 | card->devname); | ||
3960 | return -EINVAL; | ||
3961 | } | ||
3962 | |||
3963 | |||
3964 | /* Mask the Transmit and Timer interrupt */ | ||
3965 | flags->interrupt_info_struct.interrupt_permission &= | ||
3966 | ~(APP_INT_ON_TX_FRAME | APP_INT_ON_TIMER); | ||
3967 | |||
3968 | |||
3969 | /* Enable communications */ | ||
3970 | if (card->u.c.async_mode){ | ||
3971 | if (asy_comm_enable(card) != 0) { | ||
3972 | printk(KERN_INFO "%s: Failed to enable async commnunication!\n", | ||
3973 | card->devname); | ||
3974 | flags->interrupt_info_struct.interrupt_permission = 0; | ||
3975 | card->u.c.comm_enabled=0; | ||
3976 | chdlc_set_intr_mode(card,0); | ||
3977 | return -EINVAL; | ||
3978 | } | ||
3979 | }else{ | ||
3980 | if (chdlc_comm_enable(card) != 0) { | ||
3981 | printk(KERN_INFO "%s: Failed to enable chdlc communications!\n", | ||
3982 | card->devname); | ||
3983 | flags->interrupt_info_struct.interrupt_permission = 0; | ||
3984 | card->u.c.comm_enabled=0; | ||
3985 | chdlc_set_intr_mode(card,0); | ||
3986 | return -EINVAL; | ||
3987 | } | ||
3988 | } | ||
3989 | |||
3990 | /* Initialize Rx/Tx buffer control fields */ | ||
3991 | init_chdlc_tx_rx_buff(card); | ||
3992 | port_set_state(card, WAN_CONNECTING); | ||
3993 | return 0; | ||
3994 | } | ||
3995 | |||
3996 | |||
3997 | static int change_speed(sdla_t *card, struct tty_struct *tty, | ||
3998 | struct termios *old_termios) | ||
3999 | { | ||
4000 | int baud, ret=0; | ||
4001 | unsigned cflag; | ||
4002 | int dbits,sbits,parity,handshaking; | ||
4003 | |||
4004 | cflag = tty->termios->c_cflag; | ||
4005 | |||
4006 | /* There is always one stop bit */ | ||
4007 | sbits=WANOPT_ONE; | ||
4008 | |||
4009 | /* Parity is defaulted to NONE */ | ||
4010 | parity = WANOPT_NONE; | ||
4011 | |||
4012 | handshaking=0; | ||
4013 | |||
4014 | /* byte size and parity */ | ||
4015 | switch (cflag & CSIZE) { | ||
4016 | case CS5: dbits = 5; break; | ||
4017 | case CS6: dbits = 6; break; | ||
4018 | case CS7: dbits = 7; break; | ||
4019 | case CS8: dbits = 8; break; | ||
4020 | /* Never happens, but GCC is too dumb to figure it out */ | ||
4021 | default: dbits = 8; break; | ||
4022 | } | ||
4023 | |||
4024 | /* One more stop bit should be supported, thus increment | ||
4025 | * the number of stop bits Max=2 */ | ||
4026 | if (cflag & CSTOPB) { | ||
4027 | sbits = WANOPT_TWO; | ||
4028 | } | ||
4029 | if (cflag & PARENB) { | ||
4030 | parity = WANOPT_EVEN; | ||
4031 | } | ||
4032 | if (cflag & PARODD){ | ||
4033 | parity = WANOPT_ODD; | ||
4034 | } | ||
4035 | |||
4036 | /* Determine divisor based on baud rate */ | ||
4037 | baud = tty_get_baud_rate(tty); | ||
4038 | |||
4039 | if (!baud) | ||
4040 | baud = 9600; /* B0 transition handled in rs_set_termios */ | ||
4041 | |||
4042 | if (cflag & CRTSCTS) { | ||
4043 | handshaking|=ASY_RTS_HS_FOR_RX; | ||
4044 | } | ||
4045 | |||
4046 | if (I_IGNPAR(tty)) | ||
4047 | parity = WANOPT_NONE; | ||
4048 | |||
4049 | if (I_IXOFF(tty)){ | ||
4050 | handshaking|=ASY_XON_XOFF_HS_FOR_RX; | ||
4051 | handshaking|=ASY_XON_XOFF_HS_FOR_TX; | ||
4052 | } | ||
4053 | |||
4054 | if (I_IXON(tty)){ | ||
4055 | handshaking|=ASY_XON_XOFF_HS_FOR_RX; | ||
4056 | handshaking|=ASY_XON_XOFF_HS_FOR_TX; | ||
4057 | } | ||
4058 | |||
4059 | if (card->u.c.async_mode){ | ||
4060 | if (card->wandev.bps != baud) | ||
4061 | ret=1; | ||
4062 | card->wandev.bps = baud; | ||
4063 | } | ||
4064 | |||
4065 | if (card->u.c.async_mode){ | ||
4066 | if (card->u.c.protocol_options != handshaking) | ||
4067 | ret=1; | ||
4068 | card->u.c.protocol_options = handshaking; | ||
4069 | |||
4070 | if (card->u.c.tx_bits_per_char != dbits) | ||
4071 | ret=1; | ||
4072 | card->u.c.tx_bits_per_char = dbits; | ||
4073 | |||
4074 | if (card->u.c.rx_bits_per_char != dbits) | ||
4075 | ret=1; | ||
4076 | card->u.c.rx_bits_per_char = dbits; | ||
4077 | |||
4078 | if (card->u.c.stop_bits != sbits) | ||
4079 | ret=1; | ||
4080 | card->u.c.stop_bits = sbits; | ||
4081 | |||
4082 | if (card->u.c.parity != parity) | ||
4083 | ret=1; | ||
4084 | card->u.c.parity = parity; | ||
4085 | |||
4086 | card->u.c.break_timer = 50; | ||
4087 | card->u.c.inter_char_timer = 10; | ||
4088 | card->u.c.rx_complete_length = 100; | ||
4089 | card->u.c.xon_char = 0xFE; | ||
4090 | }else{ | ||
4091 | card->u.c.protocol_options = HDLC_STREAMING_MODE; | ||
4092 | } | ||
4093 | |||
4094 | return ret; | ||
4095 | } | ||
4096 | |||
4097 | |||
4098 | static void wanpipe_tty_set_termios(struct tty_struct *tty, struct termios *old_termios) | ||
4099 | { | ||
4100 | sdla_t *card; | ||
4101 | int err=1; | ||
4102 | |||
4103 | if (!tty){ | ||
4104 | return; | ||
4105 | } | ||
4106 | |||
4107 | card = (sdla_t *)tty->driver_data; | ||
4108 | |||
4109 | if (!card) | ||
4110 | return; | ||
4111 | |||
4112 | if (change_speed(card, tty, old_termios) || !card->u.c.comm_enabled){ | ||
4113 | unsigned long smp_flags; | ||
4114 | |||
4115 | if (card->u.c.comm_enabled){ | ||
4116 | lock_adapter_irq(&card->wandev.lock,&smp_flags); | ||
4117 | chdlc_disable_comm_shutdown(card); | ||
4118 | unlock_adapter_irq(&card->wandev.lock,&smp_flags); | ||
4119 | } | ||
4120 | lock_adapter_irq(&card->wandev.lock,&smp_flags); | ||
4121 | err = config_tty(card); | ||
4122 | unlock_adapter_irq(&card->wandev.lock,&smp_flags); | ||
4123 | if (card->u.c.async_mode){ | ||
4124 | printk(KERN_INFO "%s: TTY Async Configuration:\n" | ||
4125 | " Baud =%i\n" | ||
4126 | " Handshaking =%s\n" | ||
4127 | " Tx Dbits =%i\n" | ||
4128 | " Rx Dbits =%i\n" | ||
4129 | " Parity =%s\n" | ||
4130 | " Stop Bits =%i\n", | ||
4131 | card->devname, | ||
4132 | card->wandev.bps, | ||
4133 | opt_decode[card->u.c.protocol_options], | ||
4134 | card->u.c.tx_bits_per_char, | ||
4135 | card->u.c.rx_bits_per_char, | ||
4136 | p_decode[card->u.c.parity] , | ||
4137 | card->u.c.stop_bits); | ||
4138 | }else{ | ||
4139 | printk(KERN_INFO "%s: TTY Sync Configuration:\n" | ||
4140 | " Baud =%i\n" | ||
4141 | " Protocol =HDLC_STREAMING\n", | ||
4142 | card->devname,card->wandev.bps); | ||
4143 | } | ||
4144 | if (!err){ | ||
4145 | port_set_state(card,WAN_CONNECTED); | ||
4146 | }else{ | ||
4147 | port_set_state(card,WAN_DISCONNECTED); | ||
4148 | } | ||
4149 | } | ||
4150 | return; | ||
4151 | } | ||
4152 | |||
4153 | static void wanpipe_tty_put_char(struct tty_struct *tty, unsigned char ch) | ||
4154 | { | ||
4155 | sdla_t *card; | ||
4156 | unsigned long smp_flags=0; | ||
4157 | |||
4158 | if (!tty){ | ||
4159 | return; | ||
4160 | } | ||
4161 | |||
4162 | card = (sdla_t *)tty->driver_data; | ||
4163 | |||
4164 | if (!card) | ||
4165 | return; | ||
4166 | |||
4167 | if (card->wandev.state != WAN_CONNECTED) | ||
4168 | return; | ||
4169 | |||
4170 | if(card->hw.type != SDLA_S514) | ||
4171 | s508_lock(card,&smp_flags); | ||
4172 | |||
4173 | if (test_and_set_bit(SEND_CRIT,(void*)&card->wandev.critical)){ | ||
4174 | |||
4175 | wanpipe_tty_trigger_tx_irq(card); | ||
4176 | |||
4177 | if(card->hw.type != SDLA_S514) | ||
4178 | s508_unlock(card,&smp_flags); | ||
4179 | return; | ||
4180 | } | ||
4181 | |||
4182 | if (chdlc_send(card,(void*)&ch,1)){ | ||
4183 | wanpipe_tty_trigger_tx_irq(card); | ||
4184 | dbg_printk("%s: Failed to TX char!\n",card->devname); | ||
4185 | } | ||
4186 | |||
4187 | dbg_printk("%s: Char TX OK\n",card->devname); | ||
4188 | |||
4189 | clear_bit(SEND_CRIT,(void*)&card->wandev.critical); | ||
4190 | |||
4191 | if(card->hw.type != SDLA_S514) | ||
4192 | s508_unlock(card,&smp_flags); | ||
4193 | |||
4194 | return; | ||
4195 | } | ||
4196 | |||
4197 | static void wanpipe_tty_flush_chars(struct tty_struct *tty) | ||
4198 | { | ||
4199 | return; | ||
4200 | } | ||
4201 | |||
4202 | static void wanpipe_tty_flush_buffer(struct tty_struct *tty) | ||
4203 | { | ||
4204 | if (!tty) | ||
4205 | return; | ||
4206 | |||
4207 | #if defined(SERIAL_HAVE_POLL_WAIT) | ||
4208 | wake_up_interruptible(&tty->poll_wait); | ||
4209 | #endif | ||
4210 | tty_wakeup(tty); | ||
4211 | return; | ||
4212 | } | ||
4213 | |||
4214 | /* | ||
4215 | * This function is used to send a high-priority XON/XOFF character to | ||
4216 | * the device | ||
4217 | */ | ||
4218 | static void wanpipe_tty_send_xchar(struct tty_struct *tty, char ch) | ||
4219 | { | ||
4220 | return; | ||
4221 | } | ||
4222 | |||
4223 | |||
4224 | static int wanpipe_tty_chars_in_buffer(struct tty_struct *tty) | ||
4225 | { | ||
4226 | return 0; | ||
4227 | } | ||
4228 | |||
4229 | |||
4230 | static int wanpipe_tty_write_room(struct tty_struct *tty) | ||
4231 | { | ||
4232 | sdla_t *card; | ||
4233 | |||
4234 | printk(KERN_INFO "TTY Write Room\n"); | ||
4235 | |||
4236 | if (!tty){ | ||
4237 | return 0; | ||
4238 | } | ||
4239 | |||
4240 | card = (sdla_t *)tty->driver_data; | ||
4241 | if (!card) | ||
4242 | return 0; | ||
4243 | |||
4244 | if (card->wandev.state != WAN_CONNECTED) | ||
4245 | return 0; | ||
4246 | |||
4247 | return SEC_MAX_NO_DATA_BYTES_IN_FRAME; | ||
4248 | } | ||
4249 | |||
4250 | |||
4251 | static int set_modem_status(sdla_t *card, unsigned char data) | ||
4252 | { | ||
4253 | CHDLC_MAILBOX_STRUCT *mb = card->mbox; | ||
4254 | int err; | ||
4255 | |||
4256 | mb->buffer_length=1; | ||
4257 | mb->command=SET_MODEM_STATUS; | ||
4258 | mb->data[0]=data; | ||
4259 | err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; | ||
4260 | if (err != COMMAND_OK) | ||
4261 | chdlc_error (card, err, mb); | ||
4262 | |||
4263 | return err; | ||
4264 | } | ||
4265 | |||
4266 | static void wanpipe_tty_hangup(struct tty_struct *tty) | ||
4267 | { | ||
4268 | sdla_t *card; | ||
4269 | unsigned long smp_flags; | ||
4270 | |||
4271 | printk(KERN_INFO "TTY Hangup!\n"); | ||
4272 | |||
4273 | if (!tty){ | ||
4274 | return; | ||
4275 | } | ||
4276 | |||
4277 | card = (sdla_t *)tty->driver_data; | ||
4278 | if (!card) | ||
4279 | return; | ||
4280 | |||
4281 | lock_adapter_irq(&card->wandev.lock,&smp_flags); | ||
4282 | set_modem_status(card,0); | ||
4283 | unlock_adapter_irq(&card->wandev.lock,&smp_flags); | ||
4284 | return; | ||
4285 | } | ||
4286 | |||
4287 | static void wanpipe_tty_break(struct tty_struct *tty, int break_state) | ||
4288 | { | ||
4289 | return; | ||
4290 | } | ||
4291 | |||
4292 | static void wanpipe_tty_wait_until_sent(struct tty_struct *tty, int timeout) | ||
4293 | { | ||
4294 | return; | ||
4295 | } | ||
4296 | |||
4297 | static void wanpipe_tty_throttle(struct tty_struct * tty) | ||
4298 | { | ||
4299 | return; | ||
4300 | } | ||
4301 | |||
4302 | static void wanpipe_tty_unthrottle(struct tty_struct * tty) | ||
4303 | { | ||
4304 | return; | ||
4305 | } | ||
4306 | |||
4307 | int wanpipe_tty_read_proc(char *page, char **start, off_t off, int count, | ||
4308 | int *eof, void *data) | ||
4309 | { | ||
4310 | return 0; | ||
4311 | } | ||
4312 | |||
4313 | /* | ||
4314 | * The serial driver boot-time initialization code! | ||
4315 | */ | ||
4316 | int wanpipe_tty_init(sdla_t *card) | ||
4317 | { | ||
4318 | struct serial_state * state; | ||
4319 | |||
4320 | /* Initialize the tty_driver structure */ | ||
4321 | |||
4322 | if (card->tty_minor < 0 || card->tty_minor > NR_PORTS){ | ||
4323 | printk(KERN_INFO "%s: Illegal Minor TTY number (0-4): %i\n", | ||
4324 | card->devname,card->tty_minor); | ||
4325 | return -EINVAL; | ||
4326 | } | ||
4327 | |||
4328 | if (WAN_CARD(card->tty_minor)){ | ||
4329 | printk(KERN_INFO "%s: TTY Minor %i, already in use\n", | ||
4330 | card->devname,card->tty_minor); | ||
4331 | return -EBUSY; | ||
4332 | } | ||
4333 | |||
4334 | if (tty_init_cnt==0){ | ||
4335 | |||
4336 | printk(KERN_INFO "%s: TTY %s Driver Init: Major %i, Minor Range %i-%i\n", | ||
4337 | card->devname, | ||
4338 | card->u.c.async_mode ? "ASYNC" : "SYNC", | ||
4339 | WAN_TTY_MAJOR,MIN_PORT,MAX_PORT); | ||
4340 | |||
4341 | tty_driver_mode = card->u.c.async_mode; | ||
4342 | |||
4343 | memset(&serial_driver, 0, sizeof(struct tty_driver)); | ||
4344 | serial_driver.magic = TTY_DRIVER_MAGIC; | ||
4345 | serial_driver.owner = THIS_MODULE; | ||
4346 | serial_driver.driver_name = "wanpipe_tty"; | ||
4347 | serial_driver.name = "ttyW"; | ||
4348 | serial_driver.major = WAN_TTY_MAJOR; | ||
4349 | serial_driver.minor_start = WAN_TTY_MINOR; | ||
4350 | serial_driver.num = NR_PORTS; | ||
4351 | serial_driver.type = TTY_DRIVER_TYPE_SERIAL; | ||
4352 | serial_driver.subtype = SERIAL_TYPE_NORMAL; | ||
4353 | |||
4354 | serial_driver.init_termios = tty_std_termios; | ||
4355 | serial_driver.init_termios.c_cflag = | ||
4356 | B9600 | CS8 | CREAD | HUPCL | CLOCAL; | ||
4357 | serial_driver.flags = TTY_DRIVER_REAL_RAW; | ||
4358 | |||
4359 | serial_driver.refcount = 1; /* !@!@^#^&!! */ | ||
4360 | |||
4361 | serial_driver.open = wanpipe_tty_open; | ||
4362 | serial_driver.close = wanpipe_tty_close; | ||
4363 | serial_driver.write = wanpipe_tty_write; | ||
4364 | |||
4365 | serial_driver.put_char = wanpipe_tty_put_char; | ||
4366 | serial_driver.flush_chars = wanpipe_tty_flush_chars; | ||
4367 | serial_driver.write_room = wanpipe_tty_write_room; | ||
4368 | serial_driver.chars_in_buffer = wanpipe_tty_chars_in_buffer; | ||
4369 | serial_driver.flush_buffer = wanpipe_tty_flush_buffer; | ||
4370 | //serial_driver.ioctl = wanpipe_tty_ioctl; | ||
4371 | serial_driver.throttle = wanpipe_tty_throttle; | ||
4372 | serial_driver.unthrottle = wanpipe_tty_unthrottle; | ||
4373 | serial_driver.send_xchar = wanpipe_tty_send_xchar; | ||
4374 | serial_driver.set_termios = wanpipe_tty_set_termios; | ||
4375 | serial_driver.stop = wanpipe_tty_stop; | ||
4376 | serial_driver.start = wanpipe_tty_start; | ||
4377 | serial_driver.hangup = wanpipe_tty_hangup; | ||
4378 | serial_driver.break_ctl = wanpipe_tty_break; | ||
4379 | serial_driver.wait_until_sent = wanpipe_tty_wait_until_sent; | ||
4380 | serial_driver.read_proc = wanpipe_tty_read_proc; | ||
4381 | |||
4382 | if (tty_register_driver(&serial_driver)){ | ||
4383 | printk(KERN_INFO "%s: Failed to register serial driver!\n", | ||
4384 | card->devname); | ||
4385 | } | ||
4386 | } | ||
4387 | |||
4388 | |||
4389 | /* The subsequent ports must comply to the initial configuration */ | ||
4390 | if (tty_driver_mode != card->u.c.async_mode){ | ||
4391 | printk(KERN_INFO "%s: Error: TTY Driver operation mode mismatch!\n", | ||
4392 | card->devname); | ||
4393 | printk(KERN_INFO "%s: The TTY driver is configured for %s!\n", | ||
4394 | card->devname, tty_driver_mode ? "ASYNC" : "SYNC"); | ||
4395 | return -EINVAL; | ||
4396 | } | ||
4397 | |||
4398 | tty_init_cnt++; | ||
4399 | |||
4400 | printk(KERN_INFO "%s: Initializing TTY %s Driver Minor %i\n", | ||
4401 | card->devname, | ||
4402 | tty_driver_mode ? "ASYNC" : "SYNC", | ||
4403 | card->tty_minor); | ||
4404 | |||
4405 | tty_card_map[card->tty_minor] = card; | ||
4406 | state = &rs_table[card->tty_minor]; | ||
4407 | |||
4408 | state->magic = SSTATE_MAGIC; | ||
4409 | state->line = 0; | ||
4410 | state->type = PORT_UNKNOWN; | ||
4411 | state->custom_divisor = 0; | ||
4412 | state->close_delay = 5*HZ/10; | ||
4413 | state->closing_wait = 30*HZ; | ||
4414 | state->icount.cts = state->icount.dsr = | ||
4415 | state->icount.rng = state->icount.dcd = 0; | ||
4416 | state->icount.rx = state->icount.tx = 0; | ||
4417 | state->icount.frame = state->icount.parity = 0; | ||
4418 | state->icount.overrun = state->icount.brk = 0; | ||
4419 | state->irq = card->wandev.irq; | ||
4420 | |||
4421 | INIT_WORK(&card->tty_work, tty_poll_work, (void*)card); | ||
4422 | return 0; | ||
4423 | } | ||
4424 | |||
4425 | |||
4426 | MODULE_LICENSE("GPL"); | ||
4427 | |||
4428 | /****** End ****************************************************************/ | ||
diff --git a/drivers/net/wan/sdla_fr.c b/drivers/net/wan/sdla_fr.c deleted file mode 100644 index 7f1ce9d4333e..000000000000 --- a/drivers/net/wan/sdla_fr.c +++ /dev/null | |||
@@ -1,5061 +0,0 @@ | |||
1 | /***************************************************************************** | ||
2 | * sdla_fr.c WANPIPE(tm) Multiprotocol WAN Link Driver. Frame relay module. | ||
3 | * | ||
4 | * Author(s): Nenad Corbic <ncorbic@sangoma.com> | ||
5 | * Gideon Hack | ||
6 | * | ||
7 | * Copyright: (c) 1995-2001 Sangoma Technologies Inc. | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or | ||
10 | * modify it under the terms of the GNU General Public License | ||
11 | * as published by the Free Software Foundation; either version | ||
12 | * 2 of the License, or (at your option) any later version. | ||
13 | * ============================================================================ | ||
14 | * Nov 23, 2000 Nenad Corbic o Added support for 2.4.X kernels | ||
15 | * Nov 15, 2000 David Rokavarg | ||
16 | * Nenad Corbic o Added frame relay bridging support. | ||
17 | * Original code from Mark Wells and Kristian Hoffmann has | ||
18 | * been integrated into the frame relay driver. | ||
19 | * Nov 13, 2000 Nenad Corbic o Added true interface type encoding option. | ||
20 | * Tcpdump doesn't support Frame Relay inteface | ||
21 | * types, to fix this true type option will set | ||
22 | * the interface type to RAW IP mode. | ||
23 | * Nov 07, 2000 Nenad Corbic o Added security features for UDP debugging: | ||
24 | * Deny all and specify allowed requests. | ||
25 | * Nov 06, 2000 Nenad Corbic o Wanpipe interfaces conform to raw packet interfaces. | ||
26 | * Moved the if_header into the if_send() routine. | ||
27 | * The if_header() was breaking the libpcap | ||
28 | * support. i.e. support for tcpdump, ethereal ... | ||
29 | * Oct 12. 2000 Nenad Corbic o Added error message in fr_configure | ||
30 | * Jul 31, 2000 Nenad Corbic o Fixed the Router UP Time. | ||
31 | * Apr 28, 2000 Nenad Corbic o Added the option to shutdown an interface | ||
32 | * when the channel gets disconnected. | ||
33 | * Apr 28, 2000 Nenad Corbic o Added M.Grants patch: disallow duplicate | ||
34 | * interface setups. | ||
35 | * Apr 25, 2000 Nenad Corbic o Added M.Grants patch: dynamically add/remove | ||
36 | * new dlcis/interfaces. | ||
37 | * Mar 23, 2000 Nenad Corbic o Improved task queue, bh handling. | ||
38 | * Mar 16, 2000 Nenad Corbic o Added Inverse ARP support | ||
39 | * Mar 13, 2000 Nenad Corbic o Added new socket API support. | ||
40 | * Mar 06, 2000 Nenad Corbic o Bug Fix: corrupted mbox recovery. | ||
41 | * Feb 24, 2000 Nenad Corbic o Fixed up FT1 UDP debugging problem. | ||
42 | * Dev 15, 1999 Nenad Corbic o Fixed up header files for 2.0.X kernels | ||
43 | * | ||
44 | * Nov 08, 1999 Nenad Corbic o Combined all debug UDP calls into one function | ||
45 | * o Removed the ARP support. This has to be done | ||
46 | * in the next version. | ||
47 | * o Only a Node can implement NO signalling. | ||
48 | * Initialize DLCI during if_open() if NO | ||
49 | * signalling. | ||
50 | * o Took out IPX support, implement in next | ||
51 | * version | ||
52 | * Sep 29, 1999 Nenad Corbic o Added SMP support and changed the update | ||
53 | * function to use timer interrupt. | ||
54 | * o Fixed the CIR bug: Set the value of BC | ||
55 | * to CIR when the CIR is enabled. | ||
56 | * o Updated comments, statistics and tracing. | ||
57 | * Jun 02, 1999 Gideon Hack o Updated for S514 support. | ||
58 | * Sep 18, 1998 Jaspreet Singh o Updated for 2.2.X kernels. | ||
59 | * Jul 31, 1998 Jaspreet Singh o Removed wpf_poll routine. The channel/DLCI | ||
60 | * status is received through an event interrupt. | ||
61 | * Jul 08, 1998 David Fong o Added inverse ARP support. | ||
62 | * Mar 26, 1997 Jaspreet Singh o Returning return codes for failed UDP cmds. | ||
63 | * Jan 28, 1997 Jaspreet Singh o Improved handling of inactive DLCIs. | ||
64 | * Dec 30, 1997 Jaspreet Singh o Replaced dev_tint() with mark_bh(NET_BH) | ||
65 | * Dec 16, 1997 Jaspreet Singh o Implemented Multiple IPX support. | ||
66 | * Nov 26, 1997 Jaspreet Singh o Improved load sharing with multiple boards | ||
67 | * o Added Cli() to protect enabling of interrupts | ||
68 | * while polling is called. | ||
69 | * Nov 24, 1997 Jaspreet Singh o Added counters to avoid enabling of interrupts | ||
70 | * when they have been disabled by another | ||
71 | * interface or routine (eg. wpf_poll). | ||
72 | * Nov 06, 1997 Jaspreet Singh o Added INTR_TEST_MODE to avoid polling | ||
73 | * routine disable interrupts during interrupt | ||
74 | * testing. | ||
75 | * Oct 20, 1997 Jaspreet Singh o Added hooks in for Router UP time. | ||
76 | * Oct 16, 1997 Jaspreet Singh o The critical flag is used to maintain flow | ||
77 | * control by avoiding RACE conditions. The | ||
78 | * cli() and restore_flags() are taken out. | ||
79 | * The fr_channel structure is appended for | ||
80 | * Driver Statistics. | ||
81 | * Oct 15, 1997 Farhan Thawar o updated if_send() and receive for IPX | ||
82 | * Aug 29, 1997 Farhan Thawar o Removed most of the cli() and sti() | ||
83 | * o Abstracted the UDP management stuff | ||
84 | * o Now use tbusy and critical more intelligently | ||
85 | * Jul 21, 1997 Jaspreet Singh o Can configure T391, T392, N391, N392 & N393 | ||
86 | * through router.conf. | ||
87 | * o Protected calls to sdla_peek() by adDing | ||
88 | * save_flags(), cli() and restore_flags(). | ||
89 | * o Added error message for Inactive DLCIs in | ||
90 | * fr_event() and update_chan_state(). | ||
91 | * o Fixed freeing up of buffers using kfree() | ||
92 | * when packets are received. | ||
93 | * Jul 07, 1997 Jaspreet Singh o Added configurable TTL for UDP packets | ||
94 | * o Added ability to discard multicast and | ||
95 | * broadcast source addressed packets | ||
96 | * Jun 27, 1997 Jaspreet Singh o Added FT1 monitor capabilities | ||
97 | * New case (0x44) statement in if_send routine | ||
98 | * Added a global variable rCount to keep track | ||
99 | * of FT1 status enabled on the board. | ||
100 | * May 29, 1997 Jaspreet Singh o Fixed major Flow Control Problem | ||
101 | * With multiple boards a problem was seen where | ||
102 | * the second board always stopped transmitting | ||
103 | * packet after running for a while. The code | ||
104 | * got into a stage where the interrupts were | ||
105 | * disabled and dev->tbusy was set to 1. | ||
106 | * This caused the If_send() routine to get into | ||
107 | * the if clause for it(0,dev->tbusy) | ||
108 | * forever. | ||
109 | * The code got into this stage due to an | ||
110 | * interrupt occurring within the if clause for | ||
111 | * set_bit(0,dev->tbusy). Since an interrupt | ||
112 | * disables furhter transmit interrupt and | ||
113 | * makes dev->tbusy = 0, this effect was undone | ||
114 | * by making dev->tbusy = 1 in the if clause. | ||
115 | * The Fix checks to see if Transmit interrupts | ||
116 | * are disabled then do not make dev->tbusy = 1 | ||
117 | * Introduced a global variable: int_occur and | ||
118 | * added tx_int_enabled in the wan_device | ||
119 | * structure. | ||
120 | * May 21, 1997 Jaspreet Singh o Fixed UDP Management for multiple | ||
121 | * boards. | ||
122 | * | ||
123 | * Apr 25, 1997 Farhan Thawar o added UDP Management stuff | ||
124 | * o fixed bug in if_send() and tx_intr() to | ||
125 | * sleep and wakeup all devices | ||
126 | * Mar 11, 1997 Farhan Thawar Version 3.1.1 | ||
127 | * o fixed (+1) bug in fr508_rx_intr() | ||
128 | * o changed if_send() to return 0 if | ||
129 | * wandev.critical() is true | ||
130 | * o free socket buffer in if_send() if | ||
131 | * returning 0 | ||
132 | * o added tx_intr() routine | ||
133 | * Jan 30, 1997 Gene Kozin Version 3.1.0 | ||
134 | * o implemented exec() entry point | ||
135 | * o fixed a bug causing driver configured as | ||
136 | * a FR switch to be stuck in WAN_ | ||
137 | * mode | ||
138 | * Jan 02, 1997 Gene Kozin Initial version. | ||
139 | *****************************************************************************/ | ||
140 | |||
141 | #include <linux/module.h> | ||
142 | #include <linux/kernel.h> /* printk(), and other useful stuff */ | ||
143 | #include <linux/stddef.h> /* offsetof(), etc. */ | ||
144 | #include <linux/errno.h> /* return codes */ | ||
145 | #include <linux/string.h> /* inline memset(), etc. */ | ||
146 | #include <linux/slab.h> /* kmalloc(), kfree() */ | ||
147 | #include <linux/wanrouter.h> /* WAN router definitions */ | ||
148 | #include <linux/wanpipe.h> /* WANPIPE common user API definitions */ | ||
149 | #include <linux/workqueue.h> | ||
150 | #include <linux/if_arp.h> /* ARPHRD_* defines */ | ||
151 | #include <asm/byteorder.h> /* htons(), etc. */ | ||
152 | #include <asm/io.h> /* for inb(), outb(), etc. */ | ||
153 | #include <linux/time.h> /* for do_gettimeofday */ | ||
154 | #include <linux/in.h> /* sockaddr_in */ | ||
155 | #include <linux/jiffies.h> /* time_after() macro */ | ||
156 | #include <asm/errno.h> | ||
157 | |||
158 | #include <linux/ip.h> | ||
159 | #include <linux/if.h> | ||
160 | |||
161 | #include <linux/if_wanpipe_common.h> /* Wanpipe Socket */ | ||
162 | #include <linux/if_wanpipe.h> | ||
163 | |||
164 | #include <linux/sdla_fr.h> /* frame relay firmware API definitions */ | ||
165 | |||
166 | #include <asm/uaccess.h> | ||
167 | #include <linux/inetdevice.h> | ||
168 | #include <linux/netdevice.h> | ||
169 | |||
170 | #include <net/route.h> /* Dynamic Route Creation */ | ||
171 | #include <linux/etherdevice.h> /* eth_type_trans() used for bridging */ | ||
172 | #include <linux/random.h> | ||
173 | |||
174 | /****** Defines & Macros ****************************************************/ | ||
175 | |||
176 | #define MAX_CMD_RETRY 10 /* max number of firmware retries */ | ||
177 | |||
178 | #define FR_HEADER_LEN 8 /* max encapsulation header size */ | ||
179 | #define FR_CHANNEL_MTU 1500 /* unfragmented logical channel MTU */ | ||
180 | |||
181 | /* Q.922 frame types */ | ||
182 | #define Q922_UI 0x03 /* Unnumbered Info frame */ | ||
183 | #define Q922_XID 0xAF | ||
184 | |||
185 | /* DLCI configured or not */ | ||
186 | #define DLCI_NOT_CONFIGURED 0x00 | ||
187 | #define DLCI_CONFIG_PENDING 0x01 | ||
188 | #define DLCI_CONFIGURED 0x02 | ||
189 | |||
190 | /* CIR enabled or not */ | ||
191 | #define CIR_ENABLED 0x00 | ||
192 | #define CIR_DISABLED 0x01 | ||
193 | |||
194 | #define FRAME_RELAY_API 1 | ||
195 | #define MAX_BH_BUFF 10 | ||
196 | |||
197 | /* For handle_IPXWAN() */ | ||
198 | #define CVHexToAscii(b) (((unsigned char)(b) > (unsigned char)9) ? ((unsigned char)'A' + ((unsigned char)(b) - (unsigned char)10)) : ((unsigned char)'0' + (unsigned char)(b))) | ||
199 | |||
200 | /****** Data Structures *****************************************************/ | ||
201 | |||
202 | /* This is an extention of the 'struct device' we create for each network | ||
203 | * interface to keep the rest of channel-specific data. | ||
204 | */ | ||
205 | typedef struct fr_channel | ||
206 | { | ||
207 | wanpipe_common_t common; | ||
208 | char name[WAN_IFNAME_SZ+1]; /* interface name, ASCIIZ */ | ||
209 | unsigned dlci_configured ; /* check whether configured or not */ | ||
210 | unsigned cir_status; /* check whether CIR enabled or not */ | ||
211 | unsigned dlci; /* logical channel number */ | ||
212 | unsigned cir; /* committed information rate */ | ||
213 | unsigned bc; /* committed burst size */ | ||
214 | unsigned be; /* excess burst size */ | ||
215 | unsigned mc; /* multicast support on or off */ | ||
216 | unsigned tx_int_status; /* Transmit Interrupt Status */ | ||
217 | unsigned short pkt_length; /* Packet Length */ | ||
218 | unsigned long router_start_time;/* Router start time in seconds */ | ||
219 | unsigned long tick_counter; /* counter for transmit time out */ | ||
220 | char dev_pending_devtint; /* interface pending dev_tint() */ | ||
221 | void *dlci_int_interface; /* pointer to the DLCI Interface */ | ||
222 | unsigned long IB_addr; /* physical address of Interface Byte */ | ||
223 | unsigned long state_tick; /* time of the last state change */ | ||
224 | unsigned char enable_IPX; /* Enable/Disable the use of IPX */ | ||
225 | unsigned long network_number; /* Internal Network Number for IPX*/ | ||
226 | sdla_t *card; /* -> owner */ | ||
227 | unsigned route_flag; /* Add/Rem dest addr in route tables */ | ||
228 | unsigned inarp; /* Inverse Arp Request status */ | ||
229 | long inarp_ready; /* Ready to send requests */ | ||
230 | int inarp_interval; /* Time between InArp Requests */ | ||
231 | unsigned long inarp_tick; /* InArp jiffies tick counter */ | ||
232 | long interface_down; /* Bring interface down on disconnect */ | ||
233 | struct net_device_stats ifstats; /* interface statistics */ | ||
234 | if_send_stat_t drvstats_if_send; | ||
235 | rx_intr_stat_t drvstats_rx_intr; | ||
236 | pipe_mgmt_stat_t drvstats_gen; | ||
237 | unsigned long router_up_time; | ||
238 | |||
239 | unsigned short transmit_length; | ||
240 | struct sk_buff *delay_skb; | ||
241 | |||
242 | bh_data_t *bh_head; /* Circular buffer for chdlc_bh */ | ||
243 | unsigned long tq_working; | ||
244 | volatile int bh_write; | ||
245 | volatile int bh_read; | ||
246 | atomic_t bh_buff_used; | ||
247 | |||
248 | /* Polling task queue. Each interface | ||
249 | * has its own task queue, which is used | ||
250 | * to defer events from the interrupt */ | ||
251 | struct work_struct fr_poll_work; | ||
252 | struct timer_list fr_arp_timer; | ||
253 | |||
254 | u32 ip_local; | ||
255 | u32 ip_remote; | ||
256 | long config_dlci; | ||
257 | long unconfig_dlci; | ||
258 | |||
259 | /* Whether this interface should be setup as a gateway. | ||
260 | * Used by dynamic route setup code */ | ||
261 | u8 gateway; | ||
262 | |||
263 | /* True interface type */ | ||
264 | u8 true_if_encoding; | ||
265 | u8 fr_header[FR_HEADER_LEN]; | ||
266 | char fr_header_len; | ||
267 | |||
268 | } fr_channel_t; | ||
269 | |||
270 | /* Route Flag options */ | ||
271 | #define NO_ROUTE 0x00 | ||
272 | #define ADD_ROUTE 0x01 | ||
273 | #define ROUTE_ADDED 0x02 | ||
274 | #define REMOVE_ROUTE 0x03 | ||
275 | #define ARP_REQ 0x04 | ||
276 | |||
277 | /* inarp options */ | ||
278 | #define INARP_NONE 0x00 | ||
279 | #define INARP_REQUEST 0x01 | ||
280 | #define INARP_CONFIGURED 0x02 | ||
281 | |||
282 | /* reasons for enabling the timer interrupt on the adapter */ | ||
283 | #define TMR_INT_ENABLED_UDP 0x01 | ||
284 | #define TMR_INT_ENABLED_UPDATE 0x02 | ||
285 | #define TMR_INT_ENABLED_ARP 0x04 | ||
286 | #define TMR_INT_ENABLED_UPDATE_STATE 0x08 | ||
287 | #define TMR_INT_ENABLED_CONFIG 0x10 | ||
288 | #define TMR_INT_ENABLED_UNCONFIG 0x20 | ||
289 | |||
290 | |||
291 | typedef struct dlci_status | ||
292 | { | ||
293 | unsigned short dlci PACKED; | ||
294 | unsigned char state PACKED; | ||
295 | } dlci_status_t; | ||
296 | |||
297 | typedef struct dlci_IB_mapping | ||
298 | { | ||
299 | unsigned short dlci PACKED; | ||
300 | unsigned long addr_value PACKED; | ||
301 | } dlci_IB_mapping_t; | ||
302 | |||
303 | /* This structure is used for DLCI list Tx interrupt mode. It is used to | ||
304 | enable interrupt bit and set the packet length for transmission | ||
305 | */ | ||
306 | typedef struct fr_dlci_interface | ||
307 | { | ||
308 | unsigned char gen_interrupt PACKED; | ||
309 | unsigned short packet_length PACKED; | ||
310 | unsigned char reserved PACKED; | ||
311 | } fr_dlci_interface_t; | ||
312 | |||
313 | /* variable for keeping track of enabling/disabling FT1 monitor status */ | ||
314 | static int rCount = 0; | ||
315 | |||
316 | extern void disable_irq(unsigned int); | ||
317 | extern void enable_irq(unsigned int); | ||
318 | |||
319 | /* variable for keeping track of number of interrupts generated during | ||
320 | * interrupt test routine | ||
321 | */ | ||
322 | static int Intr_test_counter; | ||
323 | |||
324 | /****** Function Prototypes *************************************************/ | ||
325 | |||
326 | /* WAN link driver entry points. These are called by the WAN router module. */ | ||
327 | static int update(struct wan_device *wandev); | ||
328 | static int new_if(struct wan_device *wandev, struct net_device *dev, | ||
329 | wanif_conf_t *conf); | ||
330 | static int del_if(struct wan_device *wandev, struct net_device *dev); | ||
331 | static void disable_comm (sdla_t *card); | ||
332 | |||
333 | /* WANPIPE-specific entry points */ | ||
334 | static int wpf_exec(struct sdla *card, void *u_cmd, void *u_data); | ||
335 | |||
336 | /* Network device interface */ | ||
337 | static int if_init(struct net_device *dev); | ||
338 | static int if_open(struct net_device *dev); | ||
339 | static int if_close(struct net_device *dev); | ||
340 | |||
341 | static void if_tx_timeout(struct net_device *dev); | ||
342 | |||
343 | static int if_rebuild_hdr (struct sk_buff *skb); | ||
344 | |||
345 | static int if_send(struct sk_buff *skb, struct net_device *dev); | ||
346 | static int chk_bcast_mcast_addr(sdla_t *card, struct net_device* dev, | ||
347 | struct sk_buff *skb); | ||
348 | static struct net_device_stats *if_stats(struct net_device *dev); | ||
349 | |||
350 | /* Interrupt handlers */ | ||
351 | static void fr_isr(sdla_t *card); | ||
352 | static void rx_intr(sdla_t *card); | ||
353 | static void tx_intr(sdla_t *card); | ||
354 | static void timer_intr(sdla_t *card); | ||
355 | static void spur_intr(sdla_t *card); | ||
356 | |||
357 | /* Frame relay firmware interface functions */ | ||
358 | static int fr_read_version(sdla_t *card, char *str); | ||
359 | static int fr_configure(sdla_t *card, fr_conf_t *conf); | ||
360 | static int fr_dlci_configure(sdla_t *card, fr_dlc_conf_t *conf, unsigned dlci); | ||
361 | static int fr_init_dlci (sdla_t *card, fr_channel_t *chan); | ||
362 | static int fr_set_intr_mode (sdla_t *card, unsigned mode, unsigned mtu, unsigned short timeout); | ||
363 | static int fr_comm_enable(sdla_t *card); | ||
364 | static void fr_comm_disable(sdla_t *card); | ||
365 | static int fr_get_err_stats(sdla_t *card); | ||
366 | static int fr_get_stats(sdla_t *card); | ||
367 | static int fr_add_dlci(sdla_t *card, int dlci); | ||
368 | static int fr_activate_dlci(sdla_t *card, int dlci); | ||
369 | static int fr_delete_dlci (sdla_t* card, int dlci); | ||
370 | static int fr_issue_isf(sdla_t *card, int isf); | ||
371 | static int fr_send(sdla_t *card, int dlci, unsigned char attr, int len, | ||
372 | void *buf); | ||
373 | static int fr_send_data_header(sdla_t *card, int dlci, unsigned char attr, int len, | ||
374 | void *buf,unsigned char hdr_len); | ||
375 | static unsigned int fr_send_hdr(sdla_t *card, int dlci, unsigned int offset); | ||
376 | |||
377 | static int check_dlci_config (sdla_t *card, fr_channel_t *chan); | ||
378 | static void initialize_rx_tx_buffers (sdla_t *card); | ||
379 | |||
380 | |||
381 | /* Firmware asynchronous event handlers */ | ||
382 | static int fr_event(sdla_t *card, int event, fr_mbox_t *mbox); | ||
383 | static int fr_modem_failure(sdla_t *card, fr_mbox_t *mbox); | ||
384 | static int fr_dlci_change(sdla_t *card, fr_mbox_t *mbox); | ||
385 | |||
386 | /* Miscellaneous functions */ | ||
387 | static int update_chan_state(struct net_device *dev); | ||
388 | static void set_chan_state(struct net_device *dev, int state); | ||
389 | static struct net_device *find_channel(sdla_t *card, unsigned dlci); | ||
390 | static int is_tx_ready(sdla_t *card, fr_channel_t *chan); | ||
391 | static unsigned int dec_to_uint(unsigned char *str, int len); | ||
392 | static int reply_udp( unsigned char *data, unsigned int mbox_len ); | ||
393 | |||
394 | static int intr_test( sdla_t* card ); | ||
395 | static void init_chan_statistics( fr_channel_t* chan ); | ||
396 | static void init_global_statistics( sdla_t* card ); | ||
397 | static void read_DLCI_IB_mapping( sdla_t* card, fr_channel_t* chan ); | ||
398 | static int setup_for_delayed_transmit(struct net_device* dev, | ||
399 | struct sk_buff *skb); | ||
400 | |||
401 | struct net_device *move_dev_to_next(sdla_t *card, struct net_device *dev); | ||
402 | static int check_tx_status(sdla_t *card, struct net_device *dev); | ||
403 | |||
404 | /* Frame Relay Socket API */ | ||
405 | static void trigger_fr_bh (fr_channel_t *); | ||
406 | static void fr_bh(struct net_device *dev); | ||
407 | static int fr_bh_cleanup(struct net_device *dev); | ||
408 | static int bh_enqueue(struct net_device *dev, struct sk_buff *skb); | ||
409 | |||
410 | static void trigger_fr_poll(struct net_device *dev); | ||
411 | static void fr_poll(struct net_device *dev); | ||
412 | //static void add_gateway(struct net_device *dev); | ||
413 | |||
414 | static void trigger_unconfig_fr(struct net_device *dev); | ||
415 | static void unconfig_fr (sdla_t *); | ||
416 | |||
417 | static void trigger_config_fr (sdla_t *); | ||
418 | static void config_fr (sdla_t *); | ||
419 | |||
420 | |||
421 | /* Inverse ARP and Dynamic routing functions */ | ||
422 | int process_ARP(arphdr_1490_t *ArpPacket, sdla_t *card, struct net_device *dev); | ||
423 | int is_arp(void *buf); | ||
424 | int send_inarp_request(sdla_t *card, struct net_device *dev); | ||
425 | |||
426 | static void trigger_fr_arp(struct net_device *dev); | ||
427 | static void fr_arp (unsigned long data); | ||
428 | |||
429 | |||
430 | /* Udp management functions */ | ||
431 | static int process_udp_mgmt_pkt(sdla_t *card); | ||
432 | static int udp_pkt_type( struct sk_buff *skb, sdla_t *card ); | ||
433 | static int store_udp_mgmt_pkt(int udp_type, char udp_pkt_src, sdla_t* card, | ||
434 | struct sk_buff *skb, int dlci); | ||
435 | |||
436 | /* IPX functions */ | ||
437 | static void switch_net_numbers(unsigned char *sendpacket, | ||
438 | unsigned long network_number, unsigned char incoming); | ||
439 | |||
440 | static int handle_IPXWAN(unsigned char *sendpacket, char *devname, | ||
441 | unsigned char enable_IPX, unsigned long network_number); | ||
442 | |||
443 | /* Lock Functions: SMP supported */ | ||
444 | void s508_s514_unlock(sdla_t *card, unsigned long *smp_flags); | ||
445 | void s508_s514_lock(sdla_t *card, unsigned long *smp_flags); | ||
446 | |||
447 | unsigned short calc_checksum (char *, int); | ||
448 | static int setup_fr_header(struct sk_buff *skb, | ||
449 | struct net_device* dev, char op_mode); | ||
450 | |||
451 | |||
452 | /****** Public Functions ****************************************************/ | ||
453 | |||
454 | /*============================================================================ | ||
455 | * Frame relay protocol initialization routine. | ||
456 | * | ||
457 | * This routine is called by the main WANPIPE module during setup. At this | ||
458 | * point adapter is completely initialized and firmware is running. | ||
459 | * o read firmware version (to make sure it's alive) | ||
460 | * o configure adapter | ||
461 | * o initialize protocol-specific fields of the adapter data space. | ||
462 | * | ||
463 | * Return: 0 o.k. | ||
464 | * < 0 failure. | ||
465 | */ | ||
466 | int wpf_init(sdla_t *card, wandev_conf_t *conf) | ||
467 | { | ||
468 | |||
469 | int err; | ||
470 | fr508_flags_t* flags; | ||
471 | |||
472 | union | ||
473 | { | ||
474 | char str[80]; | ||
475 | fr_conf_t cfg; | ||
476 | } u; | ||
477 | |||
478 | fr_buf_info_t* buf_info; | ||
479 | int i; | ||
480 | |||
481 | |||
482 | printk(KERN_INFO "\n"); | ||
483 | |||
484 | /* Verify configuration ID */ | ||
485 | if (conf->config_id != WANCONFIG_FR) { | ||
486 | |||
487 | printk(KERN_INFO "%s: invalid configuration ID %u!\n", | ||
488 | card->devname, conf->config_id); | ||
489 | return -EINVAL; | ||
490 | |||
491 | } | ||
492 | |||
493 | /* Initialize protocol-specific fields of adapter data space */ | ||
494 | switch (card->hw.fwid) { | ||
495 | |||
496 | case SFID_FR508: | ||
497 | card->mbox = (void*)(card->hw.dpmbase + | ||
498 | FR508_MBOX_OFFS); | ||
499 | card->flags = (void*)(card->hw.dpmbase + | ||
500 | FR508_FLAG_OFFS); | ||
501 | if(card->hw.type == SDLA_S514) { | ||
502 | card->mbox += FR_MB_VECTOR; | ||
503 | card->flags += FR_MB_VECTOR; | ||
504 | } | ||
505 | card->isr = &fr_isr; | ||
506 | break; | ||
507 | |||
508 | default: | ||
509 | return -EINVAL; | ||
510 | } | ||
511 | |||
512 | flags = card->flags; | ||
513 | |||
514 | /* Read firmware version. Note that when adapter initializes, it | ||
515 | * clears the mailbox, so it may appear that the first command was | ||
516 | * executed successfully when in fact it was merely erased. To work | ||
517 | * around this, we execute the first command twice. | ||
518 | */ | ||
519 | |||
520 | if (fr_read_version(card, NULL) || fr_read_version(card, u.str)) | ||
521 | return -EIO; | ||
522 | |||
523 | printk(KERN_INFO "%s: running frame relay firmware v%s\n", | ||
524 | card->devname, u.str); | ||
525 | |||
526 | /* Adjust configuration */ | ||
527 | conf->mtu += FR_HEADER_LEN; | ||
528 | conf->mtu = (conf->mtu >= MIN_LGTH_FR_DATA_CFG) ? | ||
529 | min_t(unsigned int, conf->mtu, FR_MAX_NO_DATA_BYTES_IN_FRAME) : | ||
530 | FR_CHANNEL_MTU + FR_HEADER_LEN; | ||
531 | |||
532 | conf->bps = min_t(unsigned int, conf->bps, 2048000); | ||
533 | |||
534 | /* Initialze the configuration structure sent to the board to zero */ | ||
535 | memset(&u.cfg, 0, sizeof(u.cfg)); | ||
536 | |||
537 | memset(card->u.f.dlci_to_dev_map, 0, sizeof(card->u.f.dlci_to_dev_map)); | ||
538 | |||
539 | /* Configure adapter firmware */ | ||
540 | |||
541 | u.cfg.mtu = conf->mtu; | ||
542 | u.cfg.kbps = conf->bps / 1000; | ||
543 | |||
544 | u.cfg.cir_fwd = u.cfg.cir_bwd = 16; | ||
545 | u.cfg.bc_fwd = u.cfg.bc_bwd = 16; | ||
546 | |||
547 | u.cfg.options = 0x0000; | ||
548 | printk(KERN_INFO "%s: Global CIR enabled by Default\n", card->devname); | ||
549 | |||
550 | switch (conf->u.fr.signalling) { | ||
551 | |||
552 | case WANOPT_FR_ANSI: | ||
553 | u.cfg.options = 0x0000; | ||
554 | break; | ||
555 | |||
556 | case WANOPT_FR_Q933: | ||
557 | u.cfg.options |= 0x0200; | ||
558 | break; | ||
559 | |||
560 | case WANOPT_FR_LMI: | ||
561 | u.cfg.options |= 0x0400; | ||
562 | break; | ||
563 | |||
564 | case WANOPT_NO: | ||
565 | u.cfg.options |= 0x0800; | ||
566 | break; | ||
567 | default: | ||
568 | printk(KERN_INFO "%s: Illegal Signalling option\n", | ||
569 | card->wandev.name); | ||
570 | return -EINVAL; | ||
571 | } | ||
572 | |||
573 | |||
574 | card->wandev.signalling = conf->u.fr.signalling; | ||
575 | |||
576 | if (conf->station == WANOPT_CPE) { | ||
577 | |||
578 | |||
579 | if (conf->u.fr.signalling == WANOPT_NO){ | ||
580 | printk(KERN_INFO | ||
581 | "%s: ERROR - For NO signalling, station must be set to Node!", | ||
582 | card->devname); | ||
583 | return -EINVAL; | ||
584 | } | ||
585 | |||
586 | u.cfg.station = 0; | ||
587 | u.cfg.options |= 0x8000; /* auto config DLCI */ | ||
588 | card->u.f.dlci_num = 0; | ||
589 | |||
590 | } else { | ||
591 | |||
592 | u.cfg.station = 1; /* switch emulation mode */ | ||
593 | |||
594 | /* For switch emulation we have to create a list of dlci(s) | ||
595 | * that will be sent to be global SET_DLCI_CONFIGURATION | ||
596 | * command in fr_configure() routine. | ||
597 | */ | ||
598 | |||
599 | card->u.f.dlci_num = min_t(unsigned int, max_t(unsigned int, conf->u.fr.dlci_num, 1), 100); | ||
600 | |||
601 | for ( i = 0; i < card->u.f.dlci_num; i++) { | ||
602 | |||
603 | card->u.f.node_dlci[i] = (unsigned short) | ||
604 | conf->u.fr.dlci[i] ? conf->u.fr.dlci[i] : 16; | ||
605 | |||
606 | } | ||
607 | } | ||
608 | |||
609 | if (conf->clocking == WANOPT_INTERNAL) | ||
610 | u.cfg.port |= 0x0001; | ||
611 | |||
612 | if (conf->interface == WANOPT_RS232) | ||
613 | u.cfg.port |= 0x0002; | ||
614 | |||
615 | if (conf->u.fr.t391) | ||
616 | u.cfg.t391 = min_t(unsigned int, conf->u.fr.t391, 30); | ||
617 | else | ||
618 | u.cfg.t391 = 5; | ||
619 | |||
620 | if (conf->u.fr.t392) | ||
621 | u.cfg.t392 = min_t(unsigned int, conf->u.fr.t392, 30); | ||
622 | else | ||
623 | u.cfg.t392 = 15; | ||
624 | |||
625 | if (conf->u.fr.n391) | ||
626 | u.cfg.n391 = min_t(unsigned int, conf->u.fr.n391, 255); | ||
627 | else | ||
628 | u.cfg.n391 = 2; | ||
629 | |||
630 | if (conf->u.fr.n392) | ||
631 | u.cfg.n392 = min_t(unsigned int, conf->u.fr.n392, 10); | ||
632 | else | ||
633 | u.cfg.n392 = 3; | ||
634 | |||
635 | if (conf->u.fr.n393) | ||
636 | u.cfg.n393 = min_t(unsigned int, conf->u.fr.n393, 10); | ||
637 | else | ||
638 | u.cfg.n393 = 4; | ||
639 | |||
640 | if (fr_configure(card, &u.cfg)) | ||
641 | return -EIO; | ||
642 | |||
643 | if (card->hw.type == SDLA_S514) { | ||
644 | |||
645 | buf_info = (void*)(card->hw.dpmbase + FR_MB_VECTOR + | ||
646 | FR508_RXBC_OFFS); | ||
647 | |||
648 | card->rxmb = (void*)(buf_info->rse_next + card->hw.dpmbase); | ||
649 | |||
650 | card->u.f.rxmb_base = | ||
651 | (void*)(buf_info->rse_base + card->hw.dpmbase); | ||
652 | |||
653 | card->u.f.rxmb_last = | ||
654 | (void*)(buf_info->rse_base + | ||
655 | (buf_info->rse_num - 1) * sizeof(fr_rx_buf_ctl_t) + | ||
656 | card->hw.dpmbase); | ||
657 | }else{ | ||
658 | buf_info = (void*)(card->hw.dpmbase + FR508_RXBC_OFFS); | ||
659 | |||
660 | card->rxmb = (void*)(buf_info->rse_next - | ||
661 | FR_MB_VECTOR + card->hw.dpmbase); | ||
662 | |||
663 | card->u.f.rxmb_base = | ||
664 | (void*)(buf_info->rse_base - | ||
665 | FR_MB_VECTOR + card->hw.dpmbase); | ||
666 | |||
667 | card->u.f.rxmb_last = | ||
668 | (void*)(buf_info->rse_base + | ||
669 | (buf_info->rse_num - 1) * sizeof(fr_rx_buf_ctl_t) - | ||
670 | FR_MB_VECTOR + card->hw.dpmbase); | ||
671 | } | ||
672 | |||
673 | card->u.f.rx_base = buf_info->buf_base; | ||
674 | card->u.f.rx_top = buf_info->buf_top; | ||
675 | |||
676 | card->u.f.tx_interrupts_pending = 0; | ||
677 | |||
678 | card->wandev.mtu = conf->mtu; | ||
679 | card->wandev.bps = conf->bps; | ||
680 | card->wandev.interface = conf->interface; | ||
681 | card->wandev.clocking = conf->clocking; | ||
682 | card->wandev.station = conf->station; | ||
683 | card->poll = NULL; | ||
684 | card->exec = &wpf_exec; | ||
685 | card->wandev.update = &update; | ||
686 | card->wandev.new_if = &new_if; | ||
687 | card->wandev.del_if = &del_if; | ||
688 | card->wandev.state = WAN_DISCONNECTED; | ||
689 | card->wandev.ttl = conf->ttl; | ||
690 | card->wandev.udp_port = conf->udp_port; | ||
691 | card->disable_comm = &disable_comm; | ||
692 | card->u.f.arp_dev = NULL; | ||
693 | |||
694 | /* Intialize global statistics for a card */ | ||
695 | init_global_statistics( card ); | ||
696 | |||
697 | card->TracingEnabled = 0; | ||
698 | |||
699 | /* Interrupt Test */ | ||
700 | Intr_test_counter = 0; | ||
701 | card->intr_mode = INTR_TEST_MODE; | ||
702 | err = intr_test( card ); | ||
703 | |||
704 | printk(KERN_INFO "%s: End of Interrupt Test rc=0x%x count=%i\n", | ||
705 | card->devname,err,Intr_test_counter); | ||
706 | |||
707 | if (err || (Intr_test_counter < MAX_INTR_TEST_COUNTER)) { | ||
708 | printk(KERN_ERR "%s: Interrupt Test Failed, Counter: %i\n", | ||
709 | card->devname, Intr_test_counter); | ||
710 | printk(KERN_ERR "Please choose another interrupt\n"); | ||
711 | err = -EIO; | ||
712 | return err; | ||
713 | } | ||
714 | |||
715 | printk(KERN_INFO "%s: Interrupt Test Passed, Counter: %i\n", | ||
716 | card->devname, Intr_test_counter); | ||
717 | |||
718 | |||
719 | /* Apr 28 2000. Nenad Corbic | ||
720 | * Enable commnunications here, not in if_open or new_if, since | ||
721 | * interfaces come down when the link is disconnected. | ||
722 | */ | ||
723 | |||
724 | /* If you enable comms and then set ints, you get a Tx int as you | ||
725 | * perform the SET_INT_TRIGGERS command. So, we only set int | ||
726 | * triggers and then adjust the interrupt mask (to disable Tx ints) | ||
727 | * before enabling comms. | ||
728 | */ | ||
729 | if (fr_set_intr_mode(card, (FR_INTR_RXRDY | FR_INTR_TXRDY | | ||
730 | FR_INTR_DLC | FR_INTR_TIMER | FR_INTR_TX_MULT_DLCIs) , | ||
731 | card->wandev.mtu, 0)) { | ||
732 | return -EIO; | ||
733 | } | ||
734 | |||
735 | flags->imask &= ~(FR_INTR_TXRDY | FR_INTR_TIMER); | ||
736 | |||
737 | if (fr_comm_enable(card)) { | ||
738 | return -EIO; | ||
739 | } | ||
740 | wanpipe_set_state(card, WAN_CONNECTED); | ||
741 | spin_lock_init(&card->u.f.if_send_lock); | ||
742 | |||
743 | printk(KERN_INFO "\n"); | ||
744 | |||
745 | return 0; | ||
746 | } | ||
747 | |||
748 | /******* WAN Device Driver Entry Points *************************************/ | ||
749 | |||
750 | /*============================================================================ | ||
751 | * Update device status & statistics. | ||
752 | */ | ||
753 | static int update(struct wan_device* wandev) | ||
754 | { | ||
755 | volatile sdla_t* card; | ||
756 | unsigned long timeout; | ||
757 | fr508_flags_t* flags; | ||
758 | |||
759 | /* sanity checks */ | ||
760 | if ((wandev == NULL) || (wandev->private == NULL)) | ||
761 | return -EFAULT; | ||
762 | |||
763 | if (wandev->state == WAN_UNCONFIGURED) | ||
764 | return -ENODEV; | ||
765 | |||
766 | card = wandev->private; | ||
767 | flags = card->flags; | ||
768 | |||
769 | |||
770 | card->u.f.update_comms_stats = 1; | ||
771 | card->u.f.timer_int_enabled |= TMR_INT_ENABLED_UPDATE; | ||
772 | flags->imask |= FR_INTR_TIMER; | ||
773 | timeout = jiffies; | ||
774 | for(;;) { | ||
775 | if(card->u.f.update_comms_stats == 0) | ||
776 | break; | ||
777 | if (time_after(jiffies, timeout + 1 * HZ)){ | ||
778 | card->u.f.update_comms_stats = 0; | ||
779 | return -EAGAIN; | ||
780 | } | ||
781 | } | ||
782 | |||
783 | return 0; | ||
784 | } | ||
785 | |||
786 | /*============================================================================ | ||
787 | * Create new logical channel. | ||
788 | * This routine is called by the router when ROUTER_IFNEW IOCTL is being | ||
789 | * handled. | ||
790 | * o parse media- and hardware-specific configuration | ||
791 | * o make sure that a new channel can be created | ||
792 | * o allocate resources, if necessary | ||
793 | * o prepare network device structure for registaration. | ||
794 | * | ||
795 | * Return: 0 o.k. | ||
796 | * < 0 failure (channel will not be created) | ||
797 | */ | ||
798 | static int new_if(struct wan_device* wandev, struct net_device* dev, | ||
799 | wanif_conf_t* conf) | ||
800 | { | ||
801 | sdla_t* card = wandev->private; | ||
802 | fr_channel_t* chan; | ||
803 | int dlci = 0; | ||
804 | int err = 0; | ||
805 | |||
806 | |||
807 | if ((conf->name[0] == '\0') || (strlen(conf->name) > WAN_IFNAME_SZ)) { | ||
808 | |||
809 | printk(KERN_INFO "%s: Invalid interface name!\n", | ||
810 | card->devname); | ||
811 | return -EINVAL; | ||
812 | } | ||
813 | |||
814 | /* allocate and initialize private data */ | ||
815 | chan = kmalloc(sizeof(fr_channel_t), GFP_KERNEL); | ||
816 | |||
817 | if (chan == NULL) | ||
818 | return -ENOMEM; | ||
819 | |||
820 | memset(chan, 0, sizeof(fr_channel_t)); | ||
821 | strcpy(chan->name, conf->name); | ||
822 | chan->card = card; | ||
823 | |||
824 | /* verify media address */ | ||
825 | if (isdigit(conf->addr[0])) { | ||
826 | |||
827 | dlci = dec_to_uint(conf->addr, 0); | ||
828 | |||
829 | if (dlci && (dlci <= HIGHEST_VALID_DLCI)) { | ||
830 | |||
831 | chan->dlci = dlci; | ||
832 | |||
833 | } else { | ||
834 | |||
835 | printk(KERN_ERR | ||
836 | "%s: Invalid DLCI %u on interface %s!\n", | ||
837 | wandev->name, dlci, chan->name); | ||
838 | err = -EINVAL; | ||
839 | } | ||
840 | |||
841 | } else { | ||
842 | printk(KERN_ERR | ||
843 | "%s: Invalid media address on interface %s!\n", | ||
844 | wandev->name, chan->name); | ||
845 | err = -EINVAL; | ||
846 | } | ||
847 | |||
848 | if ((chan->true_if_encoding = conf->true_if_encoding) == WANOPT_YES){ | ||
849 | printk(KERN_INFO | ||
850 | "%s: Enabling, true interface type encoding.\n", | ||
851 | card->devname); | ||
852 | } | ||
853 | |||
854 | |||
855 | |||
856 | /* Setup wanpipe as a router (WANPIPE) even if it is | ||
857 | * a bridged DLCI, or as an API | ||
858 | */ | ||
859 | if (strcmp(conf->usedby, "WANPIPE") == 0 || | ||
860 | strcmp(conf->usedby, "BRIDGE") == 0 || | ||
861 | strcmp(conf->usedby, "BRIDGE_N") == 0){ | ||
862 | |||
863 | if(strcmp(conf->usedby, "WANPIPE") == 0){ | ||
864 | chan->common.usedby = WANPIPE; | ||
865 | |||
866 | printk(KERN_INFO "%s: Running in WANPIPE mode.\n", | ||
867 | card->devname); | ||
868 | |||
869 | }else if(strcmp(conf->usedby, "BRIDGE") == 0){ | ||
870 | |||
871 | chan->common.usedby = BRIDGE; | ||
872 | |||
873 | printk(KERN_INFO "%s: Running in WANPIPE (BRIDGE) mode.\n", | ||
874 | card->devname); | ||
875 | }else if( strcmp(conf->usedby, "BRIDGE_N") == 0 ){ | ||
876 | |||
877 | chan->common.usedby = BRIDGE_NODE; | ||
878 | |||
879 | printk(KERN_INFO "%s: Running in WANPIPE (BRIDGE_NODE) mode.\n", | ||
880 | card->devname); | ||
881 | } | ||
882 | |||
883 | if (!err){ | ||
884 | /* Dynamic interface configuration option. | ||
885 | * On disconnect, if the options is selected, | ||
886 | * the interface will be brought down */ | ||
887 | if (conf->if_down == WANOPT_YES){ | ||
888 | set_bit(DYN_OPT_ON,&chan->interface_down); | ||
889 | printk(KERN_INFO | ||
890 | "%s: Dynamic interface configuration enabled.\n", | ||
891 | card->devname); | ||
892 | } | ||
893 | } | ||
894 | |||
895 | } else if(strcmp(conf->usedby, "API") == 0){ | ||
896 | |||
897 | chan->common.usedby = API; | ||
898 | printk(KERN_INFO "%s: Running in API mode.\n", | ||
899 | wandev->name); | ||
900 | } | ||
901 | |||
902 | if (err) { | ||
903 | |||
904 | kfree(chan); | ||
905 | return err; | ||
906 | } | ||
907 | |||
908 | /* place cir,be,bc and other channel specific information into the | ||
909 | * chan structure | ||
910 | */ | ||
911 | if (conf->cir) { | ||
912 | |||
913 | chan->cir = max_t(unsigned int, 1, | ||
914 | min_t(unsigned int, conf->cir, 512)); | ||
915 | chan->cir_status = CIR_ENABLED; | ||
916 | |||
917 | |||
918 | /* If CIR is enabled, force BC to equal CIR | ||
919 | * this solves number of potential problems if CIR is | ||
920 | * set and BC is not | ||
921 | */ | ||
922 | chan->bc = chan->cir; | ||
923 | |||
924 | if (conf->be){ | ||
925 | chan->be = max_t(unsigned int, | ||
926 | 0, min_t(unsigned int, conf->be, 511)); | ||
927 | }else{ | ||
928 | conf->be = 0; | ||
929 | } | ||
930 | |||
931 | printk (KERN_INFO "%s: CIR enabled for DLCI %i \n", | ||
932 | wandev->name,chan->dlci); | ||
933 | printk (KERN_INFO "%s: CIR = %i ; BC = %i ; BE = %i\n", | ||
934 | wandev->name,chan->cir,chan->bc,chan->be); | ||
935 | |||
936 | |||
937 | }else{ | ||
938 | chan->cir_status = CIR_DISABLED; | ||
939 | printk (KERN_INFO "%s: CIR disabled for DLCI %i\n", | ||
940 | wandev->name,chan->dlci); | ||
941 | } | ||
942 | |||
943 | chan->mc = conf->mc; | ||
944 | |||
945 | if (conf->inarp == WANOPT_YES){ | ||
946 | printk(KERN_INFO "%s: Inverse ARP Support Enabled\n",card->devname); | ||
947 | chan->inarp = conf->inarp ? INARP_REQUEST : INARP_NONE; | ||
948 | chan->inarp_interval = conf->inarp_interval ? conf->inarp_interval : 10; | ||
949 | }else{ | ||
950 | printk(KERN_INFO "%s: Inverse ARP Support Disabled\n",card->devname); | ||
951 | chan->inarp = INARP_NONE; | ||
952 | chan->inarp_interval = 10; | ||
953 | } | ||
954 | |||
955 | |||
956 | chan->dlci_configured = DLCI_NOT_CONFIGURED; | ||
957 | |||
958 | |||
959 | /*FIXME: IPX disabled in this WANPIPE version */ | ||
960 | if (conf->enable_IPX == WANOPT_YES){ | ||
961 | printk(KERN_INFO "%s: ERROR - This version of WANPIPE doesn't support IPX\n", | ||
962 | card->devname); | ||
963 | kfree(chan); | ||
964 | return -EINVAL; | ||
965 | }else{ | ||
966 | chan->enable_IPX = WANOPT_NO; | ||
967 | } | ||
968 | |||
969 | if (conf->network_number){ | ||
970 | chan->network_number = conf->network_number; | ||
971 | }else{ | ||
972 | chan->network_number = 0xDEADBEEF; | ||
973 | } | ||
974 | |||
975 | chan->route_flag = NO_ROUTE; | ||
976 | |||
977 | init_chan_statistics(chan); | ||
978 | |||
979 | chan->transmit_length = 0; | ||
980 | |||
981 | /* prepare network device data space for registration */ | ||
982 | strcpy(dev->name,chan->name); | ||
983 | |||
984 | dev->init = &if_init; | ||
985 | dev->priv = chan; | ||
986 | |||
987 | /* Initialize FR Polling Task Queue | ||
988 | * We need a poll routine for each network | ||
989 | * interface. | ||
990 | */ | ||
991 | INIT_WORK(&chan->fr_poll_work, (void *)fr_poll, dev); | ||
992 | |||
993 | init_timer(&chan->fr_arp_timer); | ||
994 | chan->fr_arp_timer.data=(unsigned long)dev; | ||
995 | chan->fr_arp_timer.function = fr_arp; | ||
996 | |||
997 | wandev->new_if_cnt++; | ||
998 | |||
999 | /* Tells us that if this interface is a | ||
1000 | * gateway or not */ | ||
1001 | if ((chan->gateway = conf->gateway) == WANOPT_YES){ | ||
1002 | printk(KERN_INFO "%s: Interface %s is set as a gateway.\n", | ||
1003 | card->devname,dev->name); | ||
1004 | } | ||
1005 | |||
1006 | /* M. Grant Patch Apr 28 2000 | ||
1007 | * Disallow duplicate dlci configurations. */ | ||
1008 | if (card->u.f.dlci_to_dev_map[chan->dlci] != NULL) { | ||
1009 | kfree(chan); | ||
1010 | return -EBUSY; | ||
1011 | } | ||
1012 | |||
1013 | /* Configure this dlci at a later date, when | ||
1014 | * the interface comes up. i.e. when if_open() | ||
1015 | * executes */ | ||
1016 | set_bit(0,&chan->config_dlci); | ||
1017 | |||
1018 | printk(KERN_INFO "\n"); | ||
1019 | |||
1020 | return 0; | ||
1021 | } | ||
1022 | |||
1023 | /*============================================================================ | ||
1024 | * Delete logical channel. | ||
1025 | */ | ||
1026 | static int del_if(struct wan_device* wandev, struct net_device* dev) | ||
1027 | { | ||
1028 | fr_channel_t* chan = dev->priv; | ||
1029 | unsigned long smp_flags=0; | ||
1030 | |||
1031 | /* This interface is dead, make sure the | ||
1032 | * ARP timer is stopped */ | ||
1033 | del_timer(&chan->fr_arp_timer); | ||
1034 | |||
1035 | /* If we are a NODE, we must unconfigure this DLCI | ||
1036 | * Trigger an unconfigure command that will | ||
1037 | * be executed in timer interrupt. We must wait | ||
1038 | * for the command to complete. */ | ||
1039 | trigger_unconfig_fr(dev); | ||
1040 | |||
1041 | lock_adapter_irq(&wandev->lock, &smp_flags); | ||
1042 | wandev->new_if_cnt--; | ||
1043 | unlock_adapter_irq(&wandev->lock, &smp_flags); | ||
1044 | |||
1045 | return 0; | ||
1046 | } | ||
1047 | |||
1048 | |||
1049 | /*===================================================================== | ||
1050 | * disable_comm | ||
1051 | * | ||
1052 | * Description: | ||
1053 | * Disable communications. | ||
1054 | * This code runs in shutdown (sdlamain.c) | ||
1055 | * under critical flag. Therefore it is not | ||
1056 | * necessary to set a critical flag here | ||
1057 | * | ||
1058 | * Usage: | ||
1059 | * Commnunications are disabled only on a card | ||
1060 | * shutdown. | ||
1061 | */ | ||
1062 | |||
1063 | static void disable_comm (sdla_t *card) | ||
1064 | { | ||
1065 | printk(KERN_INFO "%s: Disabling Communications!\n", | ||
1066 | card->devname); | ||
1067 | fr_comm_disable(card); | ||
1068 | } | ||
1069 | |||
1070 | /****** WANPIPE-specific entry points ***************************************/ | ||
1071 | |||
1072 | /*============================================================================ | ||
1073 | * Execute adapter interface command. | ||
1074 | */ | ||
1075 | static int wpf_exec (struct sdla* card, void* u_cmd, void* u_data) | ||
1076 | { | ||
1077 | fr_mbox_t* mbox = card->mbox; | ||
1078 | int retry = MAX_CMD_RETRY; | ||
1079 | int err, len; | ||
1080 | fr_cmd_t cmd; | ||
1081 | |||
1082 | if(copy_from_user((void*)&cmd, u_cmd, sizeof(cmd))) | ||
1083 | return -EFAULT; | ||
1084 | |||
1085 | /* execute command */ | ||
1086 | do | ||
1087 | { | ||
1088 | memcpy(&mbox->cmd, &cmd, sizeof(cmd)); | ||
1089 | |||
1090 | if (cmd.length){ | ||
1091 | if( copy_from_user((void*)&mbox->data, u_data, cmd.length)) | ||
1092 | return -EFAULT; | ||
1093 | } | ||
1094 | |||
1095 | if (sdla_exec(mbox)) | ||
1096 | err = mbox->cmd.result; | ||
1097 | |||
1098 | else return -EIO; | ||
1099 | |||
1100 | } while (err && retry-- && fr_event(card, err, mbox)); | ||
1101 | |||
1102 | /* return result */ | ||
1103 | if (copy_to_user(u_cmd, (void*)&mbox->cmd, sizeof(fr_cmd_t))) | ||
1104 | return -EFAULT; | ||
1105 | |||
1106 | len = mbox->cmd.length; | ||
1107 | |||
1108 | if (len && u_data && !copy_to_user(u_data, (void*)&mbox->data, len)) | ||
1109 | return -EFAULT; | ||
1110 | return 0; | ||
1111 | } | ||
1112 | |||
1113 | /****** Network Device Interface ********************************************/ | ||
1114 | |||
1115 | /*============================================================================ | ||
1116 | * Initialize Linux network interface. | ||
1117 | * | ||
1118 | * This routine is called only once for each interface, during Linux network | ||
1119 | * interface registration. Returning anything but zero will fail interface | ||
1120 | * registration. | ||
1121 | */ | ||
1122 | static int if_init(struct net_device* dev) | ||
1123 | { | ||
1124 | fr_channel_t* chan = dev->priv; | ||
1125 | sdla_t* card = chan->card; | ||
1126 | struct wan_device* wandev = &card->wandev; | ||
1127 | |||
1128 | /* Initialize device driver entry points */ | ||
1129 | dev->open = &if_open; | ||
1130 | dev->stop = &if_close; | ||
1131 | dev->hard_header = NULL; | ||
1132 | dev->rebuild_header = &if_rebuild_hdr; | ||
1133 | dev->hard_start_xmit = &if_send; | ||
1134 | dev->get_stats = &if_stats; | ||
1135 | dev->tx_timeout = &if_tx_timeout; | ||
1136 | dev->watchdog_timeo = TX_TIMEOUT; | ||
1137 | |||
1138 | if (chan->common.usedby == WANPIPE || chan->common.usedby == API){ | ||
1139 | |||
1140 | /* Initialize media-specific parameters */ | ||
1141 | if (chan->true_if_encoding){ | ||
1142 | dev->type = ARPHRD_DLCI; /* This breaks tcpdump */ | ||
1143 | }else{ | ||
1144 | dev->type = ARPHRD_PPP; /* ARP h/w type */ | ||
1145 | } | ||
1146 | |||
1147 | dev->flags |= IFF_POINTOPOINT; | ||
1148 | dev->flags |= IFF_NOARP; | ||
1149 | |||
1150 | /* Enable Multicast addressing */ | ||
1151 | if (chan->mc == WANOPT_YES){ | ||
1152 | dev->flags |= IFF_MULTICAST; | ||
1153 | } | ||
1154 | |||
1155 | dev->mtu = wandev->mtu - FR_HEADER_LEN; | ||
1156 | /* For an API, the maximum number of bytes that the stack will pass | ||
1157 | to the driver is (dev->mtu + dev->hard_header_len). So, adjust the | ||
1158 | mtu so that a frame of maximum size can be transmitted by the API. | ||
1159 | */ | ||
1160 | if(chan->common.usedby == API) { | ||
1161 | dev->mtu += (sizeof(api_tx_hdr_t) - FR_HEADER_LEN); | ||
1162 | } | ||
1163 | |||
1164 | dev->hard_header_len = FR_HEADER_LEN;/* media header length */ | ||
1165 | dev->addr_len = 2; /* hardware address length */ | ||
1166 | *(unsigned short*)dev->dev_addr = htons(chan->dlci); | ||
1167 | |||
1168 | /* Set transmit buffer queue length */ | ||
1169 | dev->tx_queue_len = 100; | ||
1170 | |||
1171 | }else{ | ||
1172 | |||
1173 | /* Setup the interface for Bridging */ | ||
1174 | int hw_addr=0; | ||
1175 | ether_setup(dev); | ||
1176 | |||
1177 | /* Use a random number to generate the MAC address */ | ||
1178 | memcpy(dev->dev_addr, "\xFE\xFC\x00\x00\x00\x00", 6); | ||
1179 | get_random_bytes(&hw_addr, sizeof(hw_addr)); | ||
1180 | *(int *)(dev->dev_addr + 2) += hw_addr; | ||
1181 | } | ||
1182 | |||
1183 | /* Initialize hardware parameters (just for reference) */ | ||
1184 | dev->irq = wandev->irq; | ||
1185 | dev->dma = wandev->dma; | ||
1186 | dev->base_addr = wandev->ioport; | ||
1187 | dev->mem_start = wandev->maddr; | ||
1188 | dev->mem_end = wandev->maddr + wandev->msize - 1; | ||
1189 | SET_MODULE_OWNER(dev); | ||
1190 | |||
1191 | return 0; | ||
1192 | } | ||
1193 | |||
1194 | /*============================================================================ | ||
1195 | * Open network interface. | ||
1196 | * o if this is the first open, then enable communications and interrupts. | ||
1197 | * o prevent module from unloading by incrementing use count | ||
1198 | * | ||
1199 | * Return 0 if O.k. or errno. | ||
1200 | */ | ||
1201 | static int if_open(struct net_device* dev) | ||
1202 | { | ||
1203 | fr_channel_t* chan = dev->priv; | ||
1204 | sdla_t* card = chan->card; | ||
1205 | int err = 0; | ||
1206 | struct timeval tv; | ||
1207 | |||
1208 | if (netif_running(dev)) | ||
1209 | return -EBUSY; | ||
1210 | |||
1211 | /* Initialize the task queue */ | ||
1212 | chan->tq_working=0; | ||
1213 | |||
1214 | INIT_WORK(&chan->common.wanpipe_work, (void *)fr_bh, dev); | ||
1215 | |||
1216 | /* Allocate and initialize BH circular buffer */ | ||
1217 | chan->bh_head = kmalloc((sizeof(bh_data_t)*MAX_BH_BUFF),GFP_ATOMIC); | ||
1218 | memset(chan->bh_head,0,(sizeof(bh_data_t)*MAX_BH_BUFF)); | ||
1219 | atomic_set(&chan->bh_buff_used, 0); | ||
1220 | |||
1221 | netif_start_queue(dev); | ||
1222 | |||
1223 | wanpipe_open(card); | ||
1224 | do_gettimeofday( &tv ); | ||
1225 | chan->router_start_time = tv.tv_sec; | ||
1226 | |||
1227 | if (test_bit(0,&chan->config_dlci)){ | ||
1228 | trigger_config_fr (card); | ||
1229 | }else if (chan->inarp == INARP_REQUEST){ | ||
1230 | trigger_fr_arp(dev); | ||
1231 | } | ||
1232 | |||
1233 | return err; | ||
1234 | } | ||
1235 | |||
1236 | /*============================================================================ | ||
1237 | * Close network interface. | ||
1238 | * o if this is the last open, then disable communications and interrupts. | ||
1239 | * o reset flags. | ||
1240 | */ | ||
1241 | static int if_close(struct net_device* dev) | ||
1242 | { | ||
1243 | fr_channel_t* chan = dev->priv; | ||
1244 | sdla_t* card = chan->card; | ||
1245 | |||
1246 | if (chan->inarp == INARP_CONFIGURED) { | ||
1247 | chan->inarp = INARP_REQUEST; | ||
1248 | } | ||
1249 | |||
1250 | netif_stop_queue(dev); | ||
1251 | wanpipe_close(card); | ||
1252 | |||
1253 | return 0; | ||
1254 | } | ||
1255 | |||
1256 | /*============================================================================ | ||
1257 | * Re-build media header. | ||
1258 | * | ||
1259 | * Return: 1 physical address resolved. | ||
1260 | * 0 physical address not resolved | ||
1261 | */ | ||
1262 | static int if_rebuild_hdr (struct sk_buff* skb) | ||
1263 | { | ||
1264 | struct net_device *dev = skb->dev; | ||
1265 | fr_channel_t* chan = dev->priv; | ||
1266 | sdla_t* card = chan->card; | ||
1267 | |||
1268 | printk(KERN_INFO "%s: rebuild_header() called for interface %s!\n", | ||
1269 | card->devname, dev->name); | ||
1270 | return 1; | ||
1271 | } | ||
1272 | |||
1273 | /*============================================================================ | ||
1274 | * Handle transmit timeout event from netif watchdog | ||
1275 | */ | ||
1276 | static void if_tx_timeout(struct net_device *dev) | ||
1277 | { | ||
1278 | fr_channel_t* chan = dev->priv; | ||
1279 | sdla_t *card = chan->card; | ||
1280 | |||
1281 | /* If our device stays busy for at least 5 seconds then we will | ||
1282 | * kick start the device by making dev->tbusy = 0. We expect | ||
1283 | * that our device never stays busy more than 5 seconds. So this | ||
1284 | * is only used as a last resort. | ||
1285 | */ | ||
1286 | |||
1287 | chan->drvstats_if_send.if_send_tbusy++; | ||
1288 | ++chan->ifstats.collisions; | ||
1289 | |||
1290 | printk (KERN_INFO "%s: Transmit timed out on %s\n", | ||
1291 | card->devname, dev->name); | ||
1292 | chan->drvstats_if_send.if_send_tbusy_timeout++; | ||
1293 | netif_wake_queue (dev); | ||
1294 | |||
1295 | } | ||
1296 | |||
1297 | |||
1298 | /*============================================================================ | ||
1299 | * Send a packet on a network interface. | ||
1300 | * o set tbusy flag (marks start of the transmission) to block a timer-based | ||
1301 | * transmit from overlapping. | ||
1302 | * o set critical flag when accessing board. | ||
1303 | * o check link state. If link is not up, then drop the packet. | ||
1304 | * o check channel status. If it's down then initiate a call. | ||
1305 | * o pass a packet to corresponding WAN device. | ||
1306 | * o free socket buffer | ||
1307 | * | ||
1308 | * Return: 0 complete (socket buffer must be freed) | ||
1309 | * non-0 packet may be re-transmitted (tbusy must be set) | ||
1310 | * | ||
1311 | * Notes: | ||
1312 | * 1. This routine is called either by the protocol stack or by the "net | ||
1313 | * bottom half" (with interrupts enabled). | ||
1314 | * | ||
1315 | * 2. Using netif_start_queue() and netif_stop_queue() | ||
1316 | * will inhibit further transmit requests from the protocol stack | ||
1317 | * and can be used for flow control with protocol layer. | ||
1318 | */ | ||
1319 | static int if_send(struct sk_buff* skb, struct net_device* dev) | ||
1320 | { | ||
1321 | fr_channel_t* chan = dev->priv; | ||
1322 | sdla_t* card = chan->card; | ||
1323 | int err; | ||
1324 | unsigned char *sendpacket; | ||
1325 | fr508_flags_t* adptr_flags = card->flags; | ||
1326 | int udp_type; | ||
1327 | long delay_tx_queued = 0; | ||
1328 | unsigned long smp_flags=0; | ||
1329 | unsigned char attr = 0; | ||
1330 | |||
1331 | chan->drvstats_if_send.if_send_entry++; | ||
1332 | |||
1333 | netif_stop_queue(dev); | ||
1334 | |||
1335 | if (skb == NULL) { | ||
1336 | /* if we get here, some higher layer thinks we've missed an | ||
1337 | * tx-done interrupt. | ||
1338 | */ | ||
1339 | printk(KERN_INFO "%s: interface %s got kicked!\n", | ||
1340 | card->devname, dev->name); | ||
1341 | chan->drvstats_if_send.if_send_skb_null ++; | ||
1342 | |||
1343 | netif_wake_queue(dev); | ||
1344 | return 0; | ||
1345 | } | ||
1346 | |||
1347 | /* If a peripheral task is running just drop packets */ | ||
1348 | if (test_bit(PERI_CRIT, &card->wandev.critical)){ | ||
1349 | |||
1350 | printk(KERN_INFO "%s: Critical in if_send(): Peripheral running!\n", | ||
1351 | card->devname); | ||
1352 | |||
1353 | dev_kfree_skb_any(skb); | ||
1354 | netif_start_queue(dev); | ||
1355 | return 0; | ||
1356 | } | ||
1357 | |||
1358 | /* We must set the 'tbusy' flag if we already have a packet queued for | ||
1359 | transmission in the transmit interrupt handler. However, we must | ||
1360 | ensure that the transmit interrupt does not reset the 'tbusy' flag | ||
1361 | just before we set it, as this will result in a "transmit timeout". | ||
1362 | */ | ||
1363 | set_bit(SEND_TXIRQ_CRIT, (void*)&card->wandev.critical); | ||
1364 | if(chan->transmit_length) { | ||
1365 | netif_stop_queue(dev); | ||
1366 | chan->tick_counter = jiffies; | ||
1367 | clear_bit(SEND_TXIRQ_CRIT, (void*)&card->wandev.critical); | ||
1368 | return 1; | ||
1369 | } | ||
1370 | clear_bit(SEND_TXIRQ_CRIT, (void*)&card->wandev.critical); | ||
1371 | |||
1372 | /* Move the if_header() code to here. By inserting frame | ||
1373 | * relay header in if_header() we would break the | ||
1374 | * tcpdump and other packet sniffers */ | ||
1375 | chan->fr_header_len = setup_fr_header(skb,dev,chan->common.usedby); | ||
1376 | if (chan->fr_header_len < 0 ){ | ||
1377 | ++chan->ifstats.tx_dropped; | ||
1378 | ++card->wandev.stats.tx_dropped; | ||
1379 | |||
1380 | dev_kfree_skb_any(skb); | ||
1381 | netif_start_queue(dev); | ||
1382 | return 0; | ||
1383 | } | ||
1384 | |||
1385 | sendpacket = skb->data; | ||
1386 | |||
1387 | udp_type = udp_pkt_type(skb, card); | ||
1388 | |||
1389 | if(udp_type != UDP_INVALID_TYPE) { | ||
1390 | if(store_udp_mgmt_pkt(udp_type, UDP_PKT_FRM_STACK, card, skb, | ||
1391 | chan->dlci)) { | ||
1392 | adptr_flags->imask |= FR_INTR_TIMER; | ||
1393 | if (udp_type == UDP_FPIPE_TYPE){ | ||
1394 | chan->drvstats_if_send. | ||
1395 | if_send_PIPE_request ++; | ||
1396 | } | ||
1397 | } | ||
1398 | netif_start_queue(dev); | ||
1399 | return 0; | ||
1400 | } | ||
1401 | |||
1402 | //FIXME: can we do better than sendpacket[2]? | ||
1403 | if ((chan->common.usedby == WANPIPE) && (sendpacket[2] == 0x45)) { | ||
1404 | |||
1405 | /* check to see if the source IP address is a broadcast or */ | ||
1406 | /* multicast IP address */ | ||
1407 | if(chk_bcast_mcast_addr(card, dev, skb)){ | ||
1408 | ++chan->ifstats.tx_dropped; | ||
1409 | ++card->wandev.stats.tx_dropped; | ||
1410 | dev_kfree_skb_any(skb); | ||
1411 | netif_start_queue(dev); | ||
1412 | return 0; | ||
1413 | } | ||
1414 | } | ||
1415 | |||
1416 | |||
1417 | /* Lock the S514/S508 card: SMP Supported */ | ||
1418 | s508_s514_lock(card,&smp_flags); | ||
1419 | |||
1420 | if (test_and_set_bit(SEND_CRIT, (void*)&card->wandev.critical)) { | ||
1421 | |||
1422 | chan->drvstats_if_send.if_send_critical_non_ISR ++; | ||
1423 | chan->ifstats.tx_dropped ++; | ||
1424 | printk(KERN_INFO "%s Critical in IF_SEND: if_send() already running!\n", | ||
1425 | card->devname); | ||
1426 | goto if_send_start_and_exit; | ||
1427 | } | ||
1428 | |||
1429 | /* API packet check: minimum packet size must be greater than | ||
1430 | * 16 byte API header */ | ||
1431 | if((chan->common.usedby == API) && (skb->len <= sizeof(api_tx_hdr_t))) { | ||
1432 | ++chan->ifstats.tx_dropped; | ||
1433 | ++card->wandev.stats.tx_dropped; | ||
1434 | |||
1435 | |||
1436 | goto if_send_start_and_exit; | ||
1437 | |||
1438 | }else{ | ||
1439 | /* During API transmission, get rid of the API header */ | ||
1440 | if (chan->common.usedby == API) { | ||
1441 | api_tx_hdr_t* api_tx_hdr; | ||
1442 | api_tx_hdr = (api_tx_hdr_t*)&skb->data[0x00]; | ||
1443 | attr = api_tx_hdr->attr; | ||
1444 | skb_pull(skb,sizeof(api_tx_hdr_t)); | ||
1445 | } | ||
1446 | } | ||
1447 | |||
1448 | if (card->wandev.state != WAN_CONNECTED) { | ||
1449 | chan->drvstats_if_send.if_send_wan_disconnected ++; | ||
1450 | ++chan->ifstats.tx_dropped; | ||
1451 | ++card->wandev.stats.tx_dropped; | ||
1452 | |||
1453 | } else if (chan->common.state != WAN_CONNECTED) { | ||
1454 | chan->drvstats_if_send.if_send_dlci_disconnected ++; | ||
1455 | |||
1456 | /* Update the DLCI state in timer interrupt */ | ||
1457 | card->u.f.timer_int_enabled |= TMR_INT_ENABLED_UPDATE_STATE; | ||
1458 | adptr_flags->imask |= FR_INTR_TIMER; | ||
1459 | |||
1460 | ++chan->ifstats.tx_dropped; | ||
1461 | ++card->wandev.stats.tx_dropped; | ||
1462 | |||
1463 | } else if (!is_tx_ready(card, chan)) { | ||
1464 | /* No tx buffers available, store for delayed transmit */ | ||
1465 | if (!setup_for_delayed_transmit(dev, skb)){ | ||
1466 | set_bit(1,&delay_tx_queued); | ||
1467 | } | ||
1468 | chan->drvstats_if_send.if_send_no_bfrs++; | ||
1469 | |||
1470 | } else if (!skb->protocol) { | ||
1471 | /* No protocols drop packet */ | ||
1472 | chan->drvstats_if_send.if_send_protocol_error ++; | ||
1473 | ++card->wandev.stats.tx_errors; | ||
1474 | |||
1475 | } else if (test_bit(ARP_CRIT,&card->wandev.critical)){ | ||
1476 | /* We are trying to send an ARP Packet, block IP data until | ||
1477 | * ARP is sent */ | ||
1478 | ++chan->ifstats.tx_dropped; | ||
1479 | ++card->wandev.stats.tx_dropped; | ||
1480 | |||
1481 | } else { | ||
1482 | //FIXME: IPX is not implemented in this version of Frame Relay ? | ||
1483 | if((chan->common.usedby == WANPIPE) && | ||
1484 | sendpacket[1] == 0x00 && | ||
1485 | sendpacket[2] == 0x80 && | ||
1486 | sendpacket[6] == 0x81 && | ||
1487 | sendpacket[7] == 0x37) { | ||
1488 | |||
1489 | if( chan->enable_IPX ) { | ||
1490 | switch_net_numbers(sendpacket, | ||
1491 | chan->network_number, 0); | ||
1492 | } else { | ||
1493 | //FIXME: Take this out when IPX is fixed | ||
1494 | printk(KERN_INFO | ||
1495 | "%s: WARNING: Unsupported IPX data in send, packet dropped\n", | ||
1496 | card->devname); | ||
1497 | } | ||
1498 | |||
1499 | }else{ | ||
1500 | err = fr_send_data_header(card, chan->dlci, attr, skb->len, skb->data, chan->fr_header_len); | ||
1501 | if (err) { | ||
1502 | switch(err) { | ||
1503 | case FRRES_CIR_OVERFLOW: | ||
1504 | case FRRES_BUFFER_OVERFLOW: | ||
1505 | if (!setup_for_delayed_transmit(dev, skb)){ | ||
1506 | set_bit(1,&delay_tx_queued); | ||
1507 | } | ||
1508 | chan->drvstats_if_send. | ||
1509 | if_send_adptr_bfrs_full ++; | ||
1510 | break; | ||
1511 | |||
1512 | case FRRES_TOO_LONG: | ||
1513 | if (net_ratelimit()){ | ||
1514 | printk(KERN_INFO | ||
1515 | "%s: Error: Frame too long, transmission failed %i\n", | ||
1516 | card->devname, (unsigned int)skb->len); | ||
1517 | } | ||
1518 | /* Drop down to default */ | ||
1519 | default: | ||
1520 | chan->drvstats_if_send. | ||
1521 | if_send_dlci_disconnected ++; | ||
1522 | ++chan->ifstats.tx_dropped; | ||
1523 | ++card->wandev.stats.tx_dropped; | ||
1524 | break; | ||
1525 | } | ||
1526 | } else { | ||
1527 | chan->drvstats_if_send. | ||
1528 | if_send_bfr_passed_to_adptr++; | ||
1529 | ++chan->ifstats.tx_packets; | ||
1530 | ++card->wandev.stats.tx_packets; | ||
1531 | |||
1532 | chan->ifstats.tx_bytes += skb->len; | ||
1533 | card->wandev.stats.tx_bytes += skb->len; | ||
1534 | dev->trans_start = jiffies; | ||
1535 | } | ||
1536 | } | ||
1537 | } | ||
1538 | |||
1539 | if_send_start_and_exit: | ||
1540 | |||
1541 | netif_start_queue(dev); | ||
1542 | |||
1543 | /* If we queued the packet for transmission, we must not | ||
1544 | * deallocate it. The packet is unlinked from the IP stack | ||
1545 | * not copied. Therefore, we must keep the original packet */ | ||
1546 | if (!test_bit(1,&delay_tx_queued)) { | ||
1547 | dev_kfree_skb_any(skb); | ||
1548 | }else{ | ||
1549 | adptr_flags->imask |= FR_INTR_TXRDY; | ||
1550 | card->u.f.tx_interrupts_pending ++; | ||
1551 | } | ||
1552 | |||
1553 | clear_bit(SEND_CRIT, (void*)&card->wandev.critical); | ||
1554 | |||
1555 | s508_s514_unlock(card,&smp_flags); | ||
1556 | |||
1557 | return 0; | ||
1558 | } | ||
1559 | |||
1560 | |||
1561 | |||
1562 | /*============================================================================ | ||
1563 | * Setup so that a frame can be transmitted on the occurrence of a transmit | ||
1564 | * interrupt. | ||
1565 | */ | ||
1566 | static int setup_for_delayed_transmit(struct net_device* dev, | ||
1567 | struct sk_buff *skb) | ||
1568 | { | ||
1569 | fr_channel_t* chan = dev->priv; | ||
1570 | sdla_t* card = chan->card; | ||
1571 | fr_dlci_interface_t* dlci_interface; | ||
1572 | int len = skb->len; | ||
1573 | |||
1574 | /* Check that the dlci is properly configured, | ||
1575 | * before using tx interrupt */ | ||
1576 | if (!chan->dlci_int_interface){ | ||
1577 | if (net_ratelimit()){ | ||
1578 | printk(KERN_INFO | ||
1579 | "%s: ERROR on DLCI %i: Not configured properly !\n", | ||
1580 | card->devname, chan->dlci); | ||
1581 | printk(KERN_INFO "%s: Please contact Sangoma Technologies\n", | ||
1582 | card->devname); | ||
1583 | } | ||
1584 | return 1; | ||
1585 | } | ||
1586 | |||
1587 | dlci_interface = chan->dlci_int_interface; | ||
1588 | |||
1589 | if(chan->transmit_length) { | ||
1590 | printk(KERN_INFO "%s: Big mess in setup_for_del...\n", | ||
1591 | card->devname); | ||
1592 | return 1; | ||
1593 | } | ||
1594 | |||
1595 | if(len > FR_MAX_NO_DATA_BYTES_IN_FRAME) { | ||
1596 | //FIXME: increment some statistic */ | ||
1597 | return 1; | ||
1598 | } | ||
1599 | |||
1600 | chan->transmit_length = len; | ||
1601 | chan->delay_skb = skb; | ||
1602 | |||
1603 | dlci_interface->gen_interrupt |= FR_INTR_TXRDY; | ||
1604 | dlci_interface->packet_length = len; | ||
1605 | |||
1606 | /* Turn on TX interrupt at the end of if_send */ | ||
1607 | return 0; | ||
1608 | } | ||
1609 | |||
1610 | |||
1611 | /*============================================================================ | ||
1612 | * Check to see if the packet to be transmitted contains a broadcast or | ||
1613 | * multicast source IP address. | ||
1614 | * Return 0 if not broadcast/multicast address, otherwise return 1. | ||
1615 | */ | ||
1616 | |||
1617 | static int chk_bcast_mcast_addr(sdla_t *card, struct net_device* dev, | ||
1618 | struct sk_buff *skb) | ||
1619 | { | ||
1620 | u32 src_ip_addr; | ||
1621 | u32 broadcast_ip_addr = 0; | ||
1622 | struct in_device *in_dev; | ||
1623 | fr_channel_t* chan = dev->priv; | ||
1624 | |||
1625 | /* read the IP source address from the outgoing packet */ | ||
1626 | src_ip_addr = *(u32 *)(skb->data + 14); | ||
1627 | |||
1628 | /* read the IP broadcast address for the device */ | ||
1629 | in_dev = dev->ip_ptr; | ||
1630 | if(in_dev != NULL) { | ||
1631 | struct in_ifaddr *ifa= in_dev->ifa_list; | ||
1632 | if(ifa != NULL) | ||
1633 | broadcast_ip_addr = ifa->ifa_broadcast; | ||
1634 | else | ||
1635 | return 0; | ||
1636 | } | ||
1637 | |||
1638 | /* check if the IP Source Address is a Broadcast address */ | ||
1639 | if((dev->flags & IFF_BROADCAST) && (src_ip_addr == broadcast_ip_addr)) { | ||
1640 | printk(KERN_INFO | ||
1641 | "%s: Broadcast Source Address silently discarded\n", | ||
1642 | card->devname); | ||
1643 | return 1; | ||
1644 | } | ||
1645 | |||
1646 | /* check if the IP Source Address is a Multicast address */ | ||
1647 | if((chan->mc == WANOPT_NO) && (ntohl(src_ip_addr) >= 0xE0000001) && | ||
1648 | (ntohl(src_ip_addr) <= 0xFFFFFFFE)) { | ||
1649 | printk(KERN_INFO | ||
1650 | "%s: Multicast Source Address silently discarded\n", | ||
1651 | card->devname); | ||
1652 | return 1; | ||
1653 | } | ||
1654 | |||
1655 | return 0; | ||
1656 | } | ||
1657 | |||
1658 | /*============================================================================ | ||
1659 | * Reply to UDP Management system. | ||
1660 | * Return nothing. | ||
1661 | */ | ||
1662 | static int reply_udp( unsigned char *data, unsigned int mbox_len ) | ||
1663 | { | ||
1664 | unsigned short len, udp_length, temp, ip_length; | ||
1665 | unsigned long ip_temp; | ||
1666 | int even_bound = 0; | ||
1667 | |||
1668 | |||
1669 | fr_udp_pkt_t *fr_udp_pkt = (fr_udp_pkt_t *)data; | ||
1670 | |||
1671 | /* Set length of packet */ | ||
1672 | len = //sizeof(fr_encap_hdr_t)+ | ||
1673 | sizeof(ip_pkt_t)+ | ||
1674 | sizeof(udp_pkt_t)+ | ||
1675 | sizeof(wp_mgmt_t)+ | ||
1676 | sizeof(cblock_t)+ | ||
1677 | mbox_len; | ||
1678 | |||
1679 | |||
1680 | /* fill in UDP reply */ | ||
1681 | fr_udp_pkt->wp_mgmt.request_reply = UDPMGMT_REPLY; | ||
1682 | |||
1683 | /* fill in UDP length */ | ||
1684 | udp_length = sizeof(udp_pkt_t)+ | ||
1685 | sizeof(wp_mgmt_t)+ | ||
1686 | sizeof(cblock_t)+ | ||
1687 | mbox_len; | ||
1688 | |||
1689 | |||
1690 | /* put it on an even boundary */ | ||
1691 | if ( udp_length & 0x0001 ) { | ||
1692 | udp_length += 1; | ||
1693 | len += 1; | ||
1694 | even_bound = 1; | ||
1695 | } | ||
1696 | |||
1697 | temp = (udp_length<<8)|(udp_length>>8); | ||
1698 | fr_udp_pkt->udp_pkt.udp_length = temp; | ||
1699 | |||
1700 | /* swap UDP ports */ | ||
1701 | temp = fr_udp_pkt->udp_pkt.udp_src_port; | ||
1702 | fr_udp_pkt->udp_pkt.udp_src_port = | ||
1703 | fr_udp_pkt->udp_pkt.udp_dst_port; | ||
1704 | fr_udp_pkt->udp_pkt.udp_dst_port = temp; | ||
1705 | |||
1706 | |||
1707 | |||
1708 | /* add UDP pseudo header */ | ||
1709 | temp = 0x1100; | ||
1710 | *((unsigned short *) | ||
1711 | (fr_udp_pkt->data+mbox_len+even_bound)) = temp; | ||
1712 | temp = (udp_length<<8)|(udp_length>>8); | ||
1713 | *((unsigned short *) | ||
1714 | (fr_udp_pkt->data+mbox_len+even_bound+2)) = temp; | ||
1715 | |||
1716 | /* calculate UDP checksum */ | ||
1717 | fr_udp_pkt->udp_pkt.udp_checksum = 0; | ||
1718 | |||
1719 | fr_udp_pkt->udp_pkt.udp_checksum = | ||
1720 | calc_checksum(&data[UDP_OFFSET/*+sizeof(fr_encap_hdr_t)*/], | ||
1721 | udp_length+UDP_OFFSET); | ||
1722 | |||
1723 | /* fill in IP length */ | ||
1724 | ip_length = udp_length + sizeof(ip_pkt_t); | ||
1725 | temp = (ip_length<<8)|(ip_length>>8); | ||
1726 | fr_udp_pkt->ip_pkt.total_length = temp; | ||
1727 | |||
1728 | /* swap IP addresses */ | ||
1729 | ip_temp = fr_udp_pkt->ip_pkt.ip_src_address; | ||
1730 | fr_udp_pkt->ip_pkt.ip_src_address = | ||
1731 | fr_udp_pkt->ip_pkt.ip_dst_address; | ||
1732 | fr_udp_pkt->ip_pkt.ip_dst_address = ip_temp; | ||
1733 | |||
1734 | |||
1735 | /* fill in IP checksum */ | ||
1736 | fr_udp_pkt->ip_pkt.hdr_checksum = 0; | ||
1737 | fr_udp_pkt->ip_pkt.hdr_checksum = | ||
1738 | calc_checksum(&data[/*sizeof(fr_encap_hdr_t)*/0], | ||
1739 | sizeof(ip_pkt_t)); | ||
1740 | |||
1741 | return len; | ||
1742 | } /* reply_udp */ | ||
1743 | |||
1744 | unsigned short calc_checksum (char *data, int len) | ||
1745 | { | ||
1746 | unsigned short temp; | ||
1747 | unsigned long sum=0; | ||
1748 | int i; | ||
1749 | |||
1750 | for( i = 0; i <len; i+=2 ) { | ||
1751 | memcpy(&temp,&data[i],2); | ||
1752 | sum += (unsigned long)temp; | ||
1753 | } | ||
1754 | |||
1755 | while (sum >> 16 ) { | ||
1756 | sum = (sum & 0xffffUL) + (sum >> 16); | ||
1757 | } | ||
1758 | |||
1759 | temp = (unsigned short)sum; | ||
1760 | temp = ~temp; | ||
1761 | |||
1762 | if( temp == 0 ) | ||
1763 | temp = 0xffff; | ||
1764 | |||
1765 | return temp; | ||
1766 | } | ||
1767 | |||
1768 | /* | ||
1769 | If incoming is 0 (outgoing)- if the net numbers is ours make it 0 | ||
1770 | if incoming is 1 - if the net number is 0 make it ours | ||
1771 | |||
1772 | */ | ||
1773 | static void switch_net_numbers(unsigned char *sendpacket, unsigned long network_number, unsigned char incoming) | ||
1774 | { | ||
1775 | unsigned long pnetwork_number; | ||
1776 | |||
1777 | pnetwork_number = (unsigned long)((sendpacket[14] << 24) + | ||
1778 | (sendpacket[15] << 16) + (sendpacket[16] << 8) + | ||
1779 | sendpacket[17]); | ||
1780 | |||
1781 | if (!incoming) { | ||
1782 | /* If the destination network number is ours, make it 0 */ | ||
1783 | if( pnetwork_number == network_number) { | ||
1784 | sendpacket[14] = sendpacket[15] = sendpacket[16] = | ||
1785 | sendpacket[17] = 0x00; | ||
1786 | } | ||
1787 | } else { | ||
1788 | /* If the incoming network is 0, make it ours */ | ||
1789 | if( pnetwork_number == 0) { | ||
1790 | sendpacket[14] = (unsigned char)(network_number >> 24); | ||
1791 | sendpacket[15] = (unsigned char)((network_number & | ||
1792 | 0x00FF0000) >> 16); | ||
1793 | sendpacket[16] = (unsigned char)((network_number & | ||
1794 | 0x0000FF00) >> 8); | ||
1795 | sendpacket[17] = (unsigned char)(network_number & | ||
1796 | 0x000000FF); | ||
1797 | } | ||
1798 | } | ||
1799 | |||
1800 | |||
1801 | pnetwork_number = (unsigned long)((sendpacket[26] << 24) + | ||
1802 | (sendpacket[27] << 16) + (sendpacket[28] << 8) + | ||
1803 | sendpacket[29]); | ||
1804 | |||
1805 | if( !incoming ) { | ||
1806 | /* If the source network is ours, make it 0 */ | ||
1807 | if( pnetwork_number == network_number) { | ||
1808 | sendpacket[26] = sendpacket[27] = sendpacket[28] = | ||
1809 | sendpacket[29] = 0x00; | ||
1810 | } | ||
1811 | } else { | ||
1812 | /* If the source network is 0, make it ours */ | ||
1813 | if( pnetwork_number == 0 ) { | ||
1814 | sendpacket[26] = (unsigned char)(network_number >> 24); | ||
1815 | sendpacket[27] = (unsigned char)((network_number & | ||
1816 | 0x00FF0000) >> 16); | ||
1817 | sendpacket[28] = (unsigned char)((network_number & | ||
1818 | 0x0000FF00) >> 8); | ||
1819 | sendpacket[29] = (unsigned char)(network_number & | ||
1820 | 0x000000FF); | ||
1821 | } | ||
1822 | } | ||
1823 | } /* switch_net_numbers */ | ||
1824 | |||
1825 | /*============================================================================ | ||
1826 | * Get ethernet-style interface statistics. | ||
1827 | * Return a pointer to struct enet_statistics. | ||
1828 | */ | ||
1829 | static struct net_device_stats *if_stats(struct net_device *dev) | ||
1830 | { | ||
1831 | fr_channel_t* chan = dev->priv; | ||
1832 | |||
1833 | if(chan == NULL) | ||
1834 | return NULL; | ||
1835 | |||
1836 | return &chan->ifstats; | ||
1837 | } | ||
1838 | |||
1839 | /****** Interrupt Handlers **************************************************/ | ||
1840 | |||
1841 | /*============================================================================ | ||
1842 | * fr_isr: S508 frame relay interrupt service routine. | ||
1843 | * | ||
1844 | * Description: | ||
1845 | * Frame relay main interrupt service route. This | ||
1846 | * function check the interrupt type and takes | ||
1847 | * the appropriate action. | ||
1848 | */ | ||
1849 | static void fr_isr (sdla_t* card) | ||
1850 | { | ||
1851 | fr508_flags_t* flags = card->flags; | ||
1852 | char *ptr = &flags->iflag; | ||
1853 | int i,err; | ||
1854 | fr_mbox_t* mbox = card->mbox; | ||
1855 | |||
1856 | /* This flag prevents nesting of interrupts. See sdla_isr() routine | ||
1857 | * in sdlamain.c. */ | ||
1858 | card->in_isr = 1; | ||
1859 | |||
1860 | ++card->statistics.isr_entry; | ||
1861 | |||
1862 | |||
1863 | /* All peripheral (configuraiton, re-configuration) events | ||
1864 | * take presidence over the ISR. Thus, retrigger */ | ||
1865 | if (test_bit(PERI_CRIT, (void*)&card->wandev.critical)) { | ||
1866 | ++card->statistics.isr_already_critical; | ||
1867 | goto fr_isr_exit; | ||
1868 | } | ||
1869 | |||
1870 | if(card->hw.type != SDLA_S514) { | ||
1871 | if (test_bit(SEND_CRIT, (void*)&card->wandev.critical)) { | ||
1872 | printk(KERN_INFO "%s: Critical while in ISR: If Send Running!\n", | ||
1873 | card->devname); | ||
1874 | ++card->statistics.isr_already_critical; | ||
1875 | goto fr_isr_exit; | ||
1876 | } | ||
1877 | } | ||
1878 | |||
1879 | switch (flags->iflag) { | ||
1880 | |||
1881 | case FR_INTR_RXRDY: /* receive interrupt */ | ||
1882 | ++card->statistics.isr_rx; | ||
1883 | rx_intr(card); | ||
1884 | break; | ||
1885 | |||
1886 | |||
1887 | case FR_INTR_TXRDY: /* transmit interrupt */ | ||
1888 | ++ card->statistics.isr_tx; | ||
1889 | tx_intr(card); | ||
1890 | break; | ||
1891 | |||
1892 | case FR_INTR_READY: | ||
1893 | Intr_test_counter++; | ||
1894 | ++card->statistics.isr_intr_test; | ||
1895 | break; | ||
1896 | |||
1897 | case FR_INTR_DLC: /* Event interrupt occurred */ | ||
1898 | mbox->cmd.command = FR_READ_STATUS; | ||
1899 | mbox->cmd.length = 0; | ||
1900 | err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; | ||
1901 | if (err) | ||
1902 | fr_event(card, err, mbox); | ||
1903 | break; | ||
1904 | |||
1905 | case FR_INTR_TIMER: /* Timer interrupt */ | ||
1906 | timer_intr(card); | ||
1907 | break; | ||
1908 | |||
1909 | default: | ||
1910 | ++card->statistics.isr_spurious; | ||
1911 | spur_intr(card); | ||
1912 | printk(KERN_INFO "%s: Interrupt Type 0x%02X!\n", | ||
1913 | card->devname, flags->iflag); | ||
1914 | |||
1915 | printk(KERN_INFO "%s: ID Bytes = ",card->devname); | ||
1916 | for(i = 0; i < 8; i ++) | ||
1917 | printk(KERN_INFO "0x%02X ", *(ptr + 0x28 + i)); | ||
1918 | printk(KERN_INFO "\n"); | ||
1919 | |||
1920 | break; | ||
1921 | } | ||
1922 | |||
1923 | fr_isr_exit: | ||
1924 | |||
1925 | card->in_isr = 0; | ||
1926 | flags->iflag = 0; | ||
1927 | return; | ||
1928 | } | ||
1929 | |||
1930 | |||
1931 | |||
1932 | /*=========================================================== | ||
1933 | * rx_intr Receive interrupt handler. | ||
1934 | * | ||
1935 | * Description | ||
1936 | * Upon receiveing an interrupt: | ||
1937 | * 1. Check that the firmware is in sync with | ||
1938 | * the driver. | ||
1939 | * 2. Find an appropriate network interface | ||
1940 | * based on the received dlci number. | ||
1941 | * 3. Check that the netowrk interface exists | ||
1942 | * and that it's setup properly. | ||
1943 | * 4. Copy the data into an skb buffer. | ||
1944 | * 5. Check the packet type and take | ||
1945 | * appropriate acton: UPD, API, ARP or Data. | ||
1946 | */ | ||
1947 | |||
1948 | static void rx_intr (sdla_t* card) | ||
1949 | { | ||
1950 | fr_rx_buf_ctl_t* frbuf = card->rxmb; | ||
1951 | fr508_flags_t* flags = card->flags; | ||
1952 | fr_channel_t* chan; | ||
1953 | char *ptr = &flags->iflag; | ||
1954 | struct sk_buff* skb; | ||
1955 | struct net_device* dev; | ||
1956 | void* buf; | ||
1957 | unsigned dlci, len, offs, len_incl_hdr; | ||
1958 | int i, udp_type; | ||
1959 | |||
1960 | |||
1961 | /* Check that firmware buffers are in sync */ | ||
1962 | if (frbuf->flag != 0x01) { | ||
1963 | |||
1964 | printk(KERN_INFO | ||
1965 | "%s: corrupted Rx buffer @ 0x%X, flag = 0x%02X!\n", | ||
1966 | card->devname, (unsigned)frbuf, frbuf->flag); | ||
1967 | |||
1968 | printk(KERN_INFO "%s: ID Bytes = ",card->devname); | ||
1969 | for(i = 0; i < 8; i ++) | ||
1970 | printk(KERN_INFO "0x%02X ", *(ptr + 0x28 + i)); | ||
1971 | printk(KERN_INFO "\n"); | ||
1972 | |||
1973 | ++card->statistics.rx_intr_corrupt_rx_bfr; | ||
1974 | |||
1975 | /* Bug Fix: Mar 6 2000 | ||
1976 | * If we get a corrupted mailbox, it means that driver | ||
1977 | * is out of sync with the firmware. There is no recovery. | ||
1978 | * If we don't turn off all interrupts for this card | ||
1979 | * the machine will crash. | ||
1980 | */ | ||
1981 | printk(KERN_INFO "%s: Critical router failure ...!!!\n", card->devname); | ||
1982 | printk(KERN_INFO "Please contact Sangoma Technologies !\n"); | ||
1983 | fr_set_intr_mode(card, 0, 0, 0); | ||
1984 | return; | ||
1985 | } | ||
1986 | |||
1987 | len = frbuf->length; | ||
1988 | dlci = frbuf->dlci; | ||
1989 | offs = frbuf->offset; | ||
1990 | |||
1991 | /* Find the network interface for this packet */ | ||
1992 | dev = find_channel(card, dlci); | ||
1993 | |||
1994 | |||
1995 | /* Check that the network interface is active and | ||
1996 | * properly setup */ | ||
1997 | if (dev == NULL) { | ||
1998 | if( net_ratelimit()) { | ||
1999 | printk(KERN_INFO "%s: received data on unconfigured DLCI %d!\n", | ||
2000 | card->devname, dlci); | ||
2001 | } | ||
2002 | ++card->statistics.rx_intr_on_orphaned_DLCI; | ||
2003 | ++card->wandev.stats.rx_dropped; | ||
2004 | goto rx_done; | ||
2005 | } | ||
2006 | |||
2007 | if ((chan = dev->priv) == NULL){ | ||
2008 | if( net_ratelimit()) { | ||
2009 | printk(KERN_INFO "%s: received data on unconfigured DLCI %d!\n", | ||
2010 | card->devname, dlci); | ||
2011 | } | ||
2012 | ++card->statistics.rx_intr_on_orphaned_DLCI; | ||
2013 | ++card->wandev.stats.rx_dropped; | ||
2014 | goto rx_done; | ||
2015 | } | ||
2016 | |||
2017 | skb = dev_alloc_skb(len); | ||
2018 | |||
2019 | if (!netif_running(dev) || (skb == NULL)){ | ||
2020 | |||
2021 | ++chan->ifstats.rx_dropped; | ||
2022 | |||
2023 | if(skb == NULL) { | ||
2024 | if (net_ratelimit()) { | ||
2025 | printk(KERN_INFO | ||
2026 | "%s: no socket buffers available!\n", | ||
2027 | card->devname); | ||
2028 | } | ||
2029 | chan->drvstats_rx_intr.rx_intr_no_socket ++; | ||
2030 | } | ||
2031 | |||
2032 | if (!netif_running(dev)){ | ||
2033 | chan->drvstats_rx_intr. | ||
2034 | rx_intr_dev_not_started ++; | ||
2035 | if (skb){ | ||
2036 | dev_kfree_skb_any(skb); | ||
2037 | } | ||
2038 | } | ||
2039 | goto rx_done; | ||
2040 | } | ||
2041 | |||
2042 | /* Copy data from the board into the socket buffer */ | ||
2043 | if ((offs + len) > card->u.f.rx_top + 1) { | ||
2044 | unsigned tmp = card->u.f.rx_top - offs + 1; | ||
2045 | |||
2046 | buf = skb_put(skb, tmp); | ||
2047 | sdla_peek(&card->hw, offs, buf, tmp); | ||
2048 | offs = card->u.f.rx_base; | ||
2049 | len -= tmp; | ||
2050 | } | ||
2051 | |||
2052 | buf = skb_put(skb, len); | ||
2053 | sdla_peek(&card->hw, offs, buf, len); | ||
2054 | |||
2055 | |||
2056 | /* We got the packet from the bard. | ||
2057 | * Check the packet type and take appropriate action */ | ||
2058 | |||
2059 | udp_type = udp_pkt_type( skb, card ); | ||
2060 | |||
2061 | if(udp_type != UDP_INVALID_TYPE) { | ||
2062 | |||
2063 | /* UDP Debug packet received, store the | ||
2064 | * packet and handle it in timer interrupt */ | ||
2065 | |||
2066 | skb_pull(skb, 1); | ||
2067 | if (wanrouter_type_trans(skb, dev)){ | ||
2068 | if(store_udp_mgmt_pkt(udp_type,UDP_PKT_FRM_NETWORK,card,skb,dlci)){ | ||
2069 | |||
2070 | flags->imask |= FR_INTR_TIMER; | ||
2071 | |||
2072 | if (udp_type == UDP_FPIPE_TYPE){ | ||
2073 | ++chan->drvstats_rx_intr.rx_intr_PIPE_request; | ||
2074 | } | ||
2075 | } | ||
2076 | } | ||
2077 | |||
2078 | }else if (chan->common.usedby == API) { | ||
2079 | |||
2080 | /* We are in API mode. | ||
2081 | * Add an API header to the RAW packet | ||
2082 | * and queue it into a circular buffer. | ||
2083 | * Then kick the fr_bh() bottom half handler */ | ||
2084 | |||
2085 | api_rx_hdr_t* api_rx_hdr; | ||
2086 | chan->drvstats_rx_intr.rx_intr_bfr_passed_to_stack ++; | ||
2087 | chan->ifstats.rx_packets ++; | ||
2088 | card->wandev.stats.rx_packets ++; | ||
2089 | |||
2090 | chan->ifstats.rx_bytes += skb->len; | ||
2091 | card->wandev.stats.rx_bytes += skb->len; | ||
2092 | |||
2093 | skb_push(skb, sizeof(api_rx_hdr_t)); | ||
2094 | api_rx_hdr = (api_rx_hdr_t*)&skb->data[0x00]; | ||
2095 | api_rx_hdr->attr = frbuf->attr; | ||
2096 | api_rx_hdr->time_stamp = frbuf->tmstamp; | ||
2097 | |||
2098 | skb->protocol = htons(ETH_P_IP); | ||
2099 | skb->mac.raw = skb->data; | ||
2100 | skb->dev = dev; | ||
2101 | skb->pkt_type = WAN_PACKET_DATA; | ||
2102 | |||
2103 | bh_enqueue(dev, skb); | ||
2104 | |||
2105 | trigger_fr_bh(chan); | ||
2106 | |||
2107 | }else if (handle_IPXWAN(skb->data,chan->name,chan->enable_IPX, chan->network_number)){ | ||
2108 | |||
2109 | //FIXME: Frame Relay IPX is not supported, Yet ! | ||
2110 | //if (chan->enable_IPX) { | ||
2111 | // fr_send(card, dlci, 0, skb->len,skb->data); | ||
2112 | //} | ||
2113 | dev_kfree_skb_any(skb); | ||
2114 | |||
2115 | } else if (is_arp(skb->data)) { | ||
2116 | |||
2117 | /* ARP support enabled Mar 16 2000 | ||
2118 | * Process incoming ARP reply/request, setup | ||
2119 | * dynamic routes. */ | ||
2120 | |||
2121 | if (process_ARP((arphdr_1490_t *)skb->data, card, dev)) { | ||
2122 | if (net_ratelimit()){ | ||
2123 | printk (KERN_INFO | ||
2124 | "%s: Error processing ARP Packet.\n", | ||
2125 | card->devname); | ||
2126 | } | ||
2127 | } | ||
2128 | dev_kfree_skb_any(skb); | ||
2129 | |||
2130 | } else if (skb->data[0] != 0x03) { | ||
2131 | |||
2132 | if (net_ratelimit()) { | ||
2133 | printk(KERN_INFO "%s: Non IETF packet discarded.\n", | ||
2134 | card->devname); | ||
2135 | } | ||
2136 | dev_kfree_skb_any(skb); | ||
2137 | |||
2138 | } else { | ||
2139 | |||
2140 | len_incl_hdr = skb->len; | ||
2141 | /* Decapsulate packet and pass it up the | ||
2142 | protocol stack */ | ||
2143 | skb->dev = dev; | ||
2144 | |||
2145 | if (chan->common.usedby == BRIDGE || chan->common.usedby == BRIDGE_NODE){ | ||
2146 | |||
2147 | /* Make sure it's an Ethernet frame, otherwise drop it */ | ||
2148 | if (!memcmp(skb->data, "\x03\x00\x80\x00\x80\xC2\x00\x07", 8)) { | ||
2149 | skb_pull(skb, 8); | ||
2150 | skb->protocol=eth_type_trans(skb,dev); | ||
2151 | }else{ | ||
2152 | ++chan->drvstats_rx_intr.rx_intr_bfr_not_passed_to_stack; | ||
2153 | ++chan->ifstats.rx_errors; | ||
2154 | ++card->wandev.stats.rx_errors; | ||
2155 | goto rx_done; | ||
2156 | } | ||
2157 | }else{ | ||
2158 | |||
2159 | /* remove hardware header */ | ||
2160 | buf = skb_pull(skb, 1); | ||
2161 | |||
2162 | if (!wanrouter_type_trans(skb, dev)) { | ||
2163 | |||
2164 | /* can't decapsulate packet */ | ||
2165 | dev_kfree_skb_any(skb); | ||
2166 | |||
2167 | ++chan->drvstats_rx_intr.rx_intr_bfr_not_passed_to_stack; | ||
2168 | ++chan->ifstats.rx_errors; | ||
2169 | ++card->wandev.stats.rx_errors; | ||
2170 | goto rx_done; | ||
2171 | } | ||
2172 | skb->mac.raw = skb->data; | ||
2173 | } | ||
2174 | |||
2175 | |||
2176 | /* Send a packet up the IP stack */ | ||
2177 | skb->dev->last_rx = jiffies; | ||
2178 | netif_rx(skb); | ||
2179 | ++chan->drvstats_rx_intr.rx_intr_bfr_passed_to_stack; | ||
2180 | ++chan->ifstats.rx_packets; | ||
2181 | ++card->wandev.stats.rx_packets; | ||
2182 | |||
2183 | chan->ifstats.rx_bytes += len_incl_hdr; | ||
2184 | card->wandev.stats.rx_bytes += len_incl_hdr; | ||
2185 | } | ||
2186 | |||
2187 | rx_done: | ||
2188 | |||
2189 | /* Release buffer element and calculate a pointer to the next one */ | ||
2190 | frbuf->flag = 0; | ||
2191 | card->rxmb = ++frbuf; | ||
2192 | if ((void*)frbuf > card->u.f.rxmb_last) | ||
2193 | card->rxmb = card->u.f.rxmb_base; | ||
2194 | |||
2195 | } | ||
2196 | |||
2197 | /*================================================================== | ||
2198 | * tx_intr: Transmit interrupt handler. | ||
2199 | * | ||
2200 | * Rationale: | ||
2201 | * If the board is busy transmitting, if_send() will | ||
2202 | * buffers a single packet and turn on | ||
2203 | * the tx interrupt. Tx interrupt will be called | ||
2204 | * by the board, once the firmware can send more | ||
2205 | * data. Thus, no polling is required. | ||
2206 | * | ||
2207 | * Description: | ||
2208 | * Tx interrupt is called for each | ||
2209 | * configured dlci channel. Thus: | ||
2210 | * 1. Obtain the netowrk interface based on the | ||
2211 | * dlci number. | ||
2212 | * 2. Check that network interface is up and | ||
2213 | * properly setup. | ||
2214 | * 3. Check for a buffered packet. | ||
2215 | * 4. Transmit the packet. | ||
2216 | * 5. If we are in WANPIPE mode, mark the | ||
2217 | * NET_BH handler. | ||
2218 | * 6. If we are in API mode, kick | ||
2219 | * the AF_WANPIPE socket for more data. | ||
2220 | * | ||
2221 | */ | ||
2222 | static void tx_intr(sdla_t *card) | ||
2223 | { | ||
2224 | fr508_flags_t* flags = card->flags; | ||
2225 | fr_tx_buf_ctl_t* bctl; | ||
2226 | struct net_device* dev; | ||
2227 | fr_channel_t* chan; | ||
2228 | |||
2229 | if(card->hw.type == SDLA_S514){ | ||
2230 | bctl = (void*)(flags->tse_offs + card->hw.dpmbase); | ||
2231 | }else{ | ||
2232 | bctl = (void*)(flags->tse_offs - FR_MB_VECTOR + | ||
2233 | card->hw.dpmbase); | ||
2234 | } | ||
2235 | |||
2236 | /* Find the structure and make it unbusy */ | ||
2237 | dev = find_channel(card, flags->dlci); | ||
2238 | if (dev == NULL){ | ||
2239 | printk(KERN_INFO "NO DEV IN TX Interrupt\n"); | ||
2240 | goto end_of_tx_intr; | ||
2241 | } | ||
2242 | |||
2243 | if ((chan = dev->priv) == NULL){ | ||
2244 | printk(KERN_INFO "NO CHAN IN TX Interrupt\n"); | ||
2245 | goto end_of_tx_intr; | ||
2246 | } | ||
2247 | |||
2248 | if(!chan->transmit_length || !chan->delay_skb) { | ||
2249 | printk(KERN_INFO "%s: tx int error - transmit length zero\n", | ||
2250 | card->wandev.name); | ||
2251 | goto end_of_tx_intr; | ||
2252 | } | ||
2253 | |||
2254 | /* If the 'if_send()' procedure is currently checking the 'tbusy' | ||
2255 | status, then we cannot transmit. Instead, we configure the microcode | ||
2256 | so as to re-issue this transmit interrupt at a later stage. | ||
2257 | */ | ||
2258 | if (test_bit(SEND_TXIRQ_CRIT, (void*)&card->wandev.critical)) { | ||
2259 | |||
2260 | fr_dlci_interface_t* dlci_interface = chan->dlci_int_interface; | ||
2261 | bctl->flag = 0xA0; | ||
2262 | dlci_interface->gen_interrupt |= FR_INTR_TXRDY; | ||
2263 | return; | ||
2264 | |||
2265 | }else{ | ||
2266 | bctl->dlci = flags->dlci; | ||
2267 | bctl->length = chan->transmit_length+chan->fr_header_len; | ||
2268 | sdla_poke(&card->hw, | ||
2269 | fr_send_hdr(card,bctl->dlci,bctl->offset), | ||
2270 | chan->delay_skb->data, | ||
2271 | chan->delay_skb->len); | ||
2272 | bctl->flag = 0xC0; | ||
2273 | |||
2274 | ++chan->ifstats.tx_packets; | ||
2275 | ++card->wandev.stats.tx_packets; | ||
2276 | chan->ifstats.tx_bytes += chan->transmit_length; | ||
2277 | card->wandev.stats.tx_bytes += chan->transmit_length; | ||
2278 | |||
2279 | /* We must free an sk buffer, which we used | ||
2280 | * for delayed transmission; Otherwise, the sock | ||
2281 | * will run out of memory */ | ||
2282 | dev_kfree_skb_any(chan->delay_skb); | ||
2283 | |||
2284 | chan->delay_skb = NULL; | ||
2285 | chan->transmit_length = 0; | ||
2286 | |||
2287 | dev->trans_start = jiffies; | ||
2288 | |||
2289 | if (netif_queue_stopped(dev)){ | ||
2290 | /* If using API, than wakeup socket BH handler */ | ||
2291 | if (chan->common.usedby == API){ | ||
2292 | netif_start_queue(dev); | ||
2293 | wakeup_sk_bh(dev); | ||
2294 | }else{ | ||
2295 | netif_wake_queue(dev); | ||
2296 | } | ||
2297 | } | ||
2298 | } | ||
2299 | |||
2300 | end_of_tx_intr: | ||
2301 | |||
2302 | /* if any other interfaces have transmit interrupts pending, | ||
2303 | * do not disable the global transmit interrupt */ | ||
2304 | if(!(-- card->u.f.tx_interrupts_pending)) | ||
2305 | flags->imask &= ~FR_INTR_TXRDY; | ||
2306 | |||
2307 | |||
2308 | } | ||
2309 | |||
2310 | |||
2311 | /*============================================================================ | ||
2312 | * timer_intr: Timer interrupt handler. | ||
2313 | * | ||
2314 | * Rationale: | ||
2315 | * All commans must be executed within the timer | ||
2316 | * interrupt since no two commands should execute | ||
2317 | * at the same time. | ||
2318 | * | ||
2319 | * Description: | ||
2320 | * The timer interrupt is used to: | ||
2321 | * 1. Processing udp calls from 'fpipemon'. | ||
2322 | * 2. Processing update calls from /proc file system | ||
2323 | * 3. Reading board-level statistics for | ||
2324 | * updating the proc file system. | ||
2325 | * 4. Sending inverse ARP request packets. | ||
2326 | * 5. Configure a dlci/channel. | ||
2327 | * 6. Unconfigure a dlci/channel. (Node only) | ||
2328 | */ | ||
2329 | |||
2330 | static void timer_intr(sdla_t *card) | ||
2331 | { | ||
2332 | fr508_flags_t* flags = card->flags; | ||
2333 | |||
2334 | /* UDP Debuging: fpipemon call */ | ||
2335 | if (card->u.f.timer_int_enabled & TMR_INT_ENABLED_UDP) { | ||
2336 | if(card->u.f.udp_type == UDP_FPIPE_TYPE) { | ||
2337 | if(process_udp_mgmt_pkt(card)) { | ||
2338 | card->u.f.timer_int_enabled &= | ||
2339 | ~TMR_INT_ENABLED_UDP; | ||
2340 | } | ||
2341 | } | ||
2342 | } | ||
2343 | |||
2344 | /* /proc update call : triggered from update() */ | ||
2345 | if (card->u.f.timer_int_enabled & TMR_INT_ENABLED_UPDATE) { | ||
2346 | fr_get_err_stats(card); | ||
2347 | fr_get_stats(card); | ||
2348 | card->u.f.update_comms_stats = 0; | ||
2349 | card->u.f.timer_int_enabled &= ~TMR_INT_ENABLED_UPDATE; | ||
2350 | } | ||
2351 | |||
2352 | /* Update the channel state call. This is call is | ||
2353 | * triggered by if_send() function */ | ||
2354 | if (card->u.f.timer_int_enabled & TMR_INT_ENABLED_UPDATE_STATE){ | ||
2355 | struct net_device *dev; | ||
2356 | if (card->wandev.state == WAN_CONNECTED){ | ||
2357 | for (dev = card->wandev.dev; dev; | ||
2358 | dev = *((struct net_device **)dev->priv)){ | ||
2359 | fr_channel_t *chan = dev->priv; | ||
2360 | if (chan->common.state != WAN_CONNECTED){ | ||
2361 | update_chan_state(dev); | ||
2362 | } | ||
2363 | } | ||
2364 | } | ||
2365 | card->u.f.timer_int_enabled &= ~TMR_INT_ENABLED_UPDATE_STATE; | ||
2366 | } | ||
2367 | |||
2368 | /* configure a dlci/channel */ | ||
2369 | if (card->u.f.timer_int_enabled & TMR_INT_ENABLED_CONFIG){ | ||
2370 | config_fr(card); | ||
2371 | card->u.f.timer_int_enabled &= ~TMR_INT_ENABLED_CONFIG; | ||
2372 | } | ||
2373 | |||
2374 | /* unconfigure a dlci/channel */ | ||
2375 | if (card->u.f.timer_int_enabled & TMR_INT_ENABLED_UNCONFIG){ | ||
2376 | unconfig_fr(card); | ||
2377 | card->u.f.timer_int_enabled &= ~TMR_INT_ENABLED_UNCONFIG; | ||
2378 | } | ||
2379 | |||
2380 | |||
2381 | /* Transmit ARP packets */ | ||
2382 | if (card->u.f.timer_int_enabled & TMR_INT_ENABLED_ARP){ | ||
2383 | int i=0; | ||
2384 | struct net_device *dev; | ||
2385 | |||
2386 | if (card->u.f.arp_dev == NULL) | ||
2387 | card->u.f.arp_dev = card->wandev.dev; | ||
2388 | |||
2389 | dev = card->u.f.arp_dev; | ||
2390 | |||
2391 | for (;;){ | ||
2392 | |||
2393 | fr_channel_t *chan = dev->priv; | ||
2394 | |||
2395 | /* If the interface is brought down cancel sending In-ARPs */ | ||
2396 | if (!(dev->flags&IFF_UP)){ | ||
2397 | clear_bit(0,&chan->inarp_ready); | ||
2398 | } | ||
2399 | |||
2400 | if (test_bit(0,&chan->inarp_ready)){ | ||
2401 | |||
2402 | if (check_tx_status(card,dev)){ | ||
2403 | set_bit(ARP_CRIT,&card->wandev.critical); | ||
2404 | break; | ||
2405 | } | ||
2406 | |||
2407 | if (!send_inarp_request(card,dev)){ | ||
2408 | trigger_fr_arp(dev); | ||
2409 | chan->inarp_tick = jiffies; | ||
2410 | } | ||
2411 | |||
2412 | clear_bit(0,&chan->inarp_ready); | ||
2413 | dev = move_dev_to_next(card,dev); | ||
2414 | break; | ||
2415 | } | ||
2416 | dev = move_dev_to_next(card,dev); | ||
2417 | |||
2418 | if (++i == card->wandev.new_if_cnt){ | ||
2419 | card->u.f.timer_int_enabled &= ~TMR_INT_ENABLED_ARP; | ||
2420 | break; | ||
2421 | } | ||
2422 | } | ||
2423 | card->u.f.arp_dev = dev; | ||
2424 | } | ||
2425 | |||
2426 | if(!card->u.f.timer_int_enabled) | ||
2427 | flags->imask &= ~FR_INTR_TIMER; | ||
2428 | } | ||
2429 | |||
2430 | |||
2431 | /*============================================================================ | ||
2432 | * spur_intr: Spurious interrupt handler. | ||
2433 | * | ||
2434 | * Description: | ||
2435 | * We don't know this interrupt. | ||
2436 | * Print a warning. | ||
2437 | */ | ||
2438 | |||
2439 | static void spur_intr (sdla_t* card) | ||
2440 | { | ||
2441 | if (net_ratelimit()){ | ||
2442 | printk(KERN_INFO "%s: spurious interrupt!\n", card->devname); | ||
2443 | } | ||
2444 | } | ||
2445 | |||
2446 | |||
2447 | //FIXME: Fix the IPX in next version | ||
2448 | /*=========================================================================== | ||
2449 | * Return 0 for non-IPXWAN packet | ||
2450 | * 1 for IPXWAN packet or IPX is not enabled! | ||
2451 | * FIXME: Use a IPX structure here not offsets | ||
2452 | */ | ||
2453 | static int handle_IPXWAN(unsigned char *sendpacket, | ||
2454 | char *devname, unsigned char enable_IPX, | ||
2455 | unsigned long network_number) | ||
2456 | { | ||
2457 | int i; | ||
2458 | |||
2459 | if( sendpacket[1] == 0x00 && sendpacket[2] == 0x80 && | ||
2460 | sendpacket[6] == 0x81 && sendpacket[7] == 0x37) { | ||
2461 | |||
2462 | /* It's an IPX packet */ | ||
2463 | if (!enable_IPX){ | ||
2464 | /* Return 1 so we don't pass it up the stack. */ | ||
2465 | //FIXME: Take this out when IPX is fixed | ||
2466 | if (net_ratelimit()){ | ||
2467 | printk (KERN_INFO | ||
2468 | "%s: WARNING: Unsupported IPX packet received and dropped\n", | ||
2469 | devname); | ||
2470 | } | ||
2471 | return 1; | ||
2472 | } | ||
2473 | } else { | ||
2474 | /* It's not IPX so return and pass it up the stack. */ | ||
2475 | return 0; | ||
2476 | } | ||
2477 | |||
2478 | if( sendpacket[24] == 0x90 && sendpacket[25] == 0x04){ | ||
2479 | /* It's IPXWAN */ | ||
2480 | |||
2481 | if( sendpacket[10] == 0x02 && sendpacket[42] == 0x00){ | ||
2482 | |||
2483 | /* It's a timer request packet */ | ||
2484 | printk(KERN_INFO "%s: Received IPXWAN Timer Request packet\n", | ||
2485 | devname); | ||
2486 | |||
2487 | /* Go through the routing options and answer no to every | ||
2488 | * option except Unnumbered RIP/SAP | ||
2489 | */ | ||
2490 | for(i = 49; sendpacket[i] == 0x00; i += 5){ | ||
2491 | /* 0x02 is the option for Unnumbered RIP/SAP */ | ||
2492 | if( sendpacket[i + 4] != 0x02){ | ||
2493 | sendpacket[i + 1] = 0; | ||
2494 | } | ||
2495 | } | ||
2496 | |||
2497 | /* Skip over the extended Node ID option */ | ||
2498 | if( sendpacket[i] == 0x04 ){ | ||
2499 | i += 8; | ||
2500 | } | ||
2501 | |||
2502 | /* We also want to turn off all header compression opt. | ||
2503 | */ | ||
2504 | for(; sendpacket[i] == 0x80 ;){ | ||
2505 | sendpacket[i + 1] = 0; | ||
2506 | i += (sendpacket[i + 2] << 8) + (sendpacket[i + 3]) + 4; | ||
2507 | } | ||
2508 | |||
2509 | /* Set the packet type to timer response */ | ||
2510 | sendpacket[42] = 0x01; | ||
2511 | |||
2512 | printk(KERN_INFO "%s: Sending IPXWAN Timer Response\n", | ||
2513 | devname); | ||
2514 | |||
2515 | } else if( sendpacket[42] == 0x02 ){ | ||
2516 | |||
2517 | /* This is an information request packet */ | ||
2518 | printk(KERN_INFO | ||
2519 | "%s: Received IPXWAN Information Request packet\n", | ||
2520 | devname); | ||
2521 | |||
2522 | /* Set the packet type to information response */ | ||
2523 | sendpacket[42] = 0x03; | ||
2524 | |||
2525 | /* Set the router name */ | ||
2526 | sendpacket[59] = 'F'; | ||
2527 | sendpacket[60] = 'P'; | ||
2528 | sendpacket[61] = 'I'; | ||
2529 | sendpacket[62] = 'P'; | ||
2530 | sendpacket[63] = 'E'; | ||
2531 | sendpacket[64] = '-'; | ||
2532 | sendpacket[65] = CVHexToAscii(network_number >> 28); | ||
2533 | sendpacket[66] = CVHexToAscii((network_number & 0x0F000000)>> 24); | ||
2534 | sendpacket[67] = CVHexToAscii((network_number & 0x00F00000)>> 20); | ||
2535 | sendpacket[68] = CVHexToAscii((network_number & 0x000F0000)>> 16); | ||
2536 | sendpacket[69] = CVHexToAscii((network_number & 0x0000F000)>> 12); | ||
2537 | sendpacket[70] = CVHexToAscii((network_number & 0x00000F00)>> 8); | ||
2538 | sendpacket[71] = CVHexToAscii((network_number & 0x000000F0)>> 4); | ||
2539 | sendpacket[72] = CVHexToAscii(network_number & 0x0000000F); | ||
2540 | for(i = 73; i < 107; i+= 1) | ||
2541 | { | ||
2542 | sendpacket[i] = 0; | ||
2543 | } | ||
2544 | |||
2545 | printk(KERN_INFO "%s: Sending IPXWAN Information Response packet\n", | ||
2546 | devname); | ||
2547 | } else { | ||
2548 | |||
2549 | printk(KERN_INFO "%s: Unknown IPXWAN packet!\n",devname); | ||
2550 | return 0; | ||
2551 | } | ||
2552 | |||
2553 | /* Set the WNodeID to our network address */ | ||
2554 | sendpacket[43] = (unsigned char)(network_number >> 24); | ||
2555 | sendpacket[44] = (unsigned char)((network_number & 0x00FF0000) >> 16); | ||
2556 | sendpacket[45] = (unsigned char)((network_number & 0x0000FF00) >> 8); | ||
2557 | sendpacket[46] = (unsigned char)(network_number & 0x000000FF); | ||
2558 | |||
2559 | return 1; | ||
2560 | } | ||
2561 | |||
2562 | /* If we get here, it's an IPX-data packet so it'll get passed up the | ||
2563 | * stack. | ||
2564 | * switch the network numbers | ||
2565 | */ | ||
2566 | switch_net_numbers(sendpacket, network_number ,1); | ||
2567 | return 0; | ||
2568 | } | ||
2569 | /*============================================================================ | ||
2570 | * process_route | ||
2571 | * | ||
2572 | * Rationale: | ||
2573 | * If the interface goes down, or we receive an ARP request, | ||
2574 | * we have to change the network interface ip addresses. | ||
2575 | * This cannot be done within the interrupt. | ||
2576 | * | ||
2577 | * Description: | ||
2578 | * | ||
2579 | * This routine is called as a polling routine to dynamically | ||
2580 | * add/delete routes negotiated by inverse ARP. It is in this | ||
2581 | * "task" because we don't want routes to be added while in | ||
2582 | * interrupt context. | ||
2583 | * | ||
2584 | * Usage: | ||
2585 | * This function is called by fr_poll() polling funtion. | ||
2586 | */ | ||
2587 | |||
2588 | static void process_route(struct net_device *dev) | ||
2589 | { | ||
2590 | fr_channel_t *chan = dev->priv; | ||
2591 | sdla_t *card = chan->card; | ||
2592 | |||
2593 | struct ifreq if_info; | ||
2594 | struct sockaddr_in *if_data; | ||
2595 | mm_segment_t fs = get_fs(); | ||
2596 | u32 ip_tmp; | ||
2597 | int err; | ||
2598 | |||
2599 | |||
2600 | switch(chan->route_flag){ | ||
2601 | |||
2602 | case ADD_ROUTE: | ||
2603 | |||
2604 | /* Set remote addresses */ | ||
2605 | memset(&if_info, 0, sizeof(if_info)); | ||
2606 | strcpy(if_info.ifr_name, dev->name); | ||
2607 | |||
2608 | set_fs(get_ds()); /* get user space block */ | ||
2609 | |||
2610 | if_data = (struct sockaddr_in *)&if_info.ifr_dstaddr; | ||
2611 | if_data->sin_addr.s_addr = chan->ip_remote; | ||
2612 | if_data->sin_family = AF_INET; | ||
2613 | err = devinet_ioctl( SIOCSIFDSTADDR, &if_info ); | ||
2614 | |||
2615 | set_fs(fs); /* restore old block */ | ||
2616 | |||
2617 | if (err) { | ||
2618 | printk(KERN_INFO | ||
2619 | "%s: Route Add failed. Error: %d\n", | ||
2620 | card->devname,err); | ||
2621 | printk(KERN_INFO "%s: Address: %u.%u.%u.%u\n", | ||
2622 | chan->name, NIPQUAD(chan->ip_remote)); | ||
2623 | |||
2624 | }else { | ||
2625 | printk(KERN_INFO "%s: Route Added Successfully: %u.%u.%u.%u\n", | ||
2626 | card->devname,NIPQUAD(chan->ip_remote)); | ||
2627 | chan->route_flag = ROUTE_ADDED; | ||
2628 | } | ||
2629 | break; | ||
2630 | |||
2631 | case REMOVE_ROUTE: | ||
2632 | |||
2633 | /* Set remote addresses */ | ||
2634 | memset(&if_info, 0, sizeof(if_info)); | ||
2635 | strcpy(if_info.ifr_name, dev->name); | ||
2636 | |||
2637 | ip_tmp = get_ip_address(dev,WAN_POINTOPOINT_IP); | ||
2638 | |||
2639 | set_fs(get_ds()); /* get user space block */ | ||
2640 | |||
2641 | if_data = (struct sockaddr_in *)&if_info.ifr_dstaddr; | ||
2642 | if_data->sin_addr.s_addr = 0; | ||
2643 | if_data->sin_family = AF_INET; | ||
2644 | err = devinet_ioctl( SIOCSIFDSTADDR, &if_info ); | ||
2645 | |||
2646 | set_fs(fs); | ||
2647 | |||
2648 | if (err) { | ||
2649 | printk(KERN_INFO | ||
2650 | "%s: Deleting of route failed. Error: %d\n", | ||
2651 | card->devname,err); | ||
2652 | printk(KERN_INFO "%s: Address: %u.%u.%u.%u\n", | ||
2653 | dev->name,NIPQUAD(chan->ip_remote) ); | ||
2654 | |||
2655 | } else { | ||
2656 | printk(KERN_INFO "%s: Route Removed Sucessfuly: %u.%u.%u.%u\n", | ||
2657 | card->devname,NIPQUAD(ip_tmp)); | ||
2658 | chan->route_flag = NO_ROUTE; | ||
2659 | } | ||
2660 | break; | ||
2661 | |||
2662 | } /* Case Statement */ | ||
2663 | |||
2664 | } | ||
2665 | |||
2666 | |||
2667 | |||
2668 | /****** Frame Relay Firmware-Specific Functions *****************************/ | ||
2669 | |||
2670 | /*============================================================================ | ||
2671 | * Read firmware code version. | ||
2672 | * o fill string str with firmware version info. | ||
2673 | */ | ||
2674 | static int fr_read_version (sdla_t* card, char* str) | ||
2675 | { | ||
2676 | fr_mbox_t* mbox = card->mbox; | ||
2677 | int retry = MAX_CMD_RETRY; | ||
2678 | int err; | ||
2679 | |||
2680 | do | ||
2681 | { | ||
2682 | mbox->cmd.command = FR_READ_CODE_VERSION; | ||
2683 | mbox->cmd.length = 0; | ||
2684 | err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; | ||
2685 | } while (err && retry-- && fr_event(card, err, mbox)); | ||
2686 | |||
2687 | if (!err && str) { | ||
2688 | int len = mbox->cmd.length; | ||
2689 | memcpy(str, mbox->data, len); | ||
2690 | str[len] = '\0'; | ||
2691 | } | ||
2692 | return err; | ||
2693 | } | ||
2694 | |||
2695 | /*============================================================================ | ||
2696 | * Set global configuration. | ||
2697 | */ | ||
2698 | static int fr_configure (sdla_t* card, fr_conf_t *conf) | ||
2699 | { | ||
2700 | fr_mbox_t* mbox = card->mbox; | ||
2701 | int retry = MAX_CMD_RETRY; | ||
2702 | int dlci_num = card->u.f.dlci_num; | ||
2703 | int err, i; | ||
2704 | |||
2705 | do | ||
2706 | { | ||
2707 | memcpy(mbox->data, conf, sizeof(fr_conf_t)); | ||
2708 | |||
2709 | if (dlci_num) for (i = 0; i < dlci_num; ++i) | ||
2710 | ((fr_conf_t*)mbox->data)->dlci[i] = | ||
2711 | card->u.f.node_dlci[i]; | ||
2712 | |||
2713 | mbox->cmd.command = FR_SET_CONFIG; | ||
2714 | mbox->cmd.length = | ||
2715 | sizeof(fr_conf_t) + dlci_num * sizeof(short); | ||
2716 | |||
2717 | err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; | ||
2718 | |||
2719 | } while (err && retry-- && fr_event(card, err, mbox)); | ||
2720 | |||
2721 | /*NC Oct 12 2000 */ | ||
2722 | if (err != CMD_OK){ | ||
2723 | printk(KERN_ERR "%s: Frame Relay Configuration Failed: rc=0x%x\n", | ||
2724 | card->devname,err); | ||
2725 | } | ||
2726 | |||
2727 | return err; | ||
2728 | } | ||
2729 | |||
2730 | /*============================================================================ | ||
2731 | * Set DLCI configuration. | ||
2732 | */ | ||
2733 | static int fr_dlci_configure (sdla_t* card, fr_dlc_conf_t *conf, unsigned dlci) | ||
2734 | { | ||
2735 | fr_mbox_t* mbox = card->mbox; | ||
2736 | int retry = MAX_CMD_RETRY; | ||
2737 | int err; | ||
2738 | |||
2739 | do | ||
2740 | { | ||
2741 | memcpy(mbox->data, conf, sizeof(fr_dlc_conf_t)); | ||
2742 | mbox->cmd.dlci = (unsigned short) dlci; | ||
2743 | mbox->cmd.command = FR_SET_CONFIG; | ||
2744 | mbox->cmd.length = sizeof(fr_dlc_conf_t); | ||
2745 | err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; | ||
2746 | } while (err && retry--); | ||
2747 | |||
2748 | return err; | ||
2749 | } | ||
2750 | /*============================================================================ | ||
2751 | * Set interrupt mode. | ||
2752 | */ | ||
2753 | static int fr_set_intr_mode (sdla_t* card, unsigned mode, unsigned mtu, | ||
2754 | unsigned short timeout) | ||
2755 | { | ||
2756 | fr_mbox_t* mbox = card->mbox; | ||
2757 | fr508_intr_ctl_t* ictl = (void*)mbox->data; | ||
2758 | int retry = MAX_CMD_RETRY; | ||
2759 | int err; | ||
2760 | |||
2761 | do | ||
2762 | { | ||
2763 | memset(ictl, 0, sizeof(fr508_intr_ctl_t)); | ||
2764 | ictl->mode = mode; | ||
2765 | ictl->tx_len = mtu; | ||
2766 | ictl->irq = card->hw.irq; | ||
2767 | |||
2768 | /* indicate timeout on timer */ | ||
2769 | if (mode & 0x20) ictl->timeout = timeout; | ||
2770 | |||
2771 | mbox->cmd.length = sizeof(fr508_intr_ctl_t); | ||
2772 | mbox->cmd.command = FR_SET_INTR_MODE; | ||
2773 | err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; | ||
2774 | |||
2775 | } while (err && retry-- && fr_event(card, err, mbox)); | ||
2776 | |||
2777 | return err; | ||
2778 | } | ||
2779 | |||
2780 | /*============================================================================ | ||
2781 | * Enable communications. | ||
2782 | */ | ||
2783 | static int fr_comm_enable (sdla_t* card) | ||
2784 | { | ||
2785 | fr_mbox_t* mbox = card->mbox; | ||
2786 | int retry = MAX_CMD_RETRY; | ||
2787 | int err; | ||
2788 | |||
2789 | do | ||
2790 | { | ||
2791 | mbox->cmd.command = FR_COMM_ENABLE; | ||
2792 | mbox->cmd.length = 0; | ||
2793 | err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; | ||
2794 | } while (err && retry-- && fr_event(card, err, mbox)); | ||
2795 | |||
2796 | return err; | ||
2797 | } | ||
2798 | |||
2799 | /*============================================================================ | ||
2800 | * fr_comm_disable | ||
2801 | * | ||
2802 | * Warning: This functin is called by the shutdown() procedure. It is void | ||
2803 | * since dev->priv are has already been deallocated and no | ||
2804 | * error checking is possible using fr_event() function. | ||
2805 | */ | ||
2806 | static void fr_comm_disable (sdla_t* card) | ||
2807 | { | ||
2808 | fr_mbox_t* mbox = card->mbox; | ||
2809 | int retry = MAX_CMD_RETRY; | ||
2810 | int err; | ||
2811 | |||
2812 | do { | ||
2813 | mbox->cmd.command = FR_SET_MODEM_STATUS; | ||
2814 | mbox->cmd.length = 1; | ||
2815 | mbox->data[0] = 0; | ||
2816 | err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; | ||
2817 | } while (err && retry--); | ||
2818 | |||
2819 | retry = MAX_CMD_RETRY; | ||
2820 | |||
2821 | do | ||
2822 | { | ||
2823 | mbox->cmd.command = FR_COMM_DISABLE; | ||
2824 | mbox->cmd.length = 0; | ||
2825 | err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; | ||
2826 | } while (err && retry--); | ||
2827 | |||
2828 | return; | ||
2829 | } | ||
2830 | |||
2831 | |||
2832 | |||
2833 | /*============================================================================ | ||
2834 | * Get communications error statistics. | ||
2835 | */ | ||
2836 | static int fr_get_err_stats (sdla_t* card) | ||
2837 | { | ||
2838 | fr_mbox_t* mbox = card->mbox; | ||
2839 | int retry = MAX_CMD_RETRY; | ||
2840 | int err; | ||
2841 | |||
2842 | |||
2843 | do | ||
2844 | { | ||
2845 | mbox->cmd.command = FR_READ_ERROR_STATS; | ||
2846 | mbox->cmd.length = 0; | ||
2847 | mbox->cmd.dlci = 0; | ||
2848 | err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; | ||
2849 | } while (err && retry-- && fr_event(card, err, mbox)); | ||
2850 | |||
2851 | if (!err) { | ||
2852 | fr_comm_stat_t* stats = (void*)mbox->data; | ||
2853 | card->wandev.stats.rx_over_errors = stats->rx_overruns; | ||
2854 | card->wandev.stats.rx_crc_errors = stats->rx_bad_crc; | ||
2855 | card->wandev.stats.rx_missed_errors = stats->rx_aborts; | ||
2856 | card->wandev.stats.rx_length_errors = stats->rx_too_long; | ||
2857 | card->wandev.stats.tx_aborted_errors = stats->tx_aborts; | ||
2858 | |||
2859 | } | ||
2860 | |||
2861 | return err; | ||
2862 | } | ||
2863 | |||
2864 | /*============================================================================ | ||
2865 | * Get statistics. | ||
2866 | */ | ||
2867 | static int fr_get_stats (sdla_t* card) | ||
2868 | { | ||
2869 | fr_mbox_t* mbox = card->mbox; | ||
2870 | int retry = MAX_CMD_RETRY; | ||
2871 | int err; | ||
2872 | |||
2873 | |||
2874 | do | ||
2875 | { | ||
2876 | mbox->cmd.command = FR_READ_STATISTICS; | ||
2877 | mbox->cmd.length = 0; | ||
2878 | mbox->cmd.dlci = 0; | ||
2879 | err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; | ||
2880 | } while (err && retry-- && fr_event(card, err, mbox)); | ||
2881 | |||
2882 | if (!err) { | ||
2883 | fr_link_stat_t* stats = (void*)mbox->data; | ||
2884 | card->wandev.stats.rx_frame_errors = stats->rx_bad_format; | ||
2885 | card->wandev.stats.rx_dropped = | ||
2886 | stats->rx_dropped + stats->rx_dropped2; | ||
2887 | } | ||
2888 | |||
2889 | return err; | ||
2890 | } | ||
2891 | |||
2892 | /*============================================================================ | ||
2893 | * Add DLCI(s) (Access Node only!). | ||
2894 | * This routine will perform the ADD_DLCIs command for the specified DLCI. | ||
2895 | */ | ||
2896 | static int fr_add_dlci (sdla_t* card, int dlci) | ||
2897 | { | ||
2898 | fr_mbox_t* mbox = card->mbox; | ||
2899 | int retry = MAX_CMD_RETRY; | ||
2900 | int err; | ||
2901 | |||
2902 | do | ||
2903 | { | ||
2904 | unsigned short* dlci_list = (void*)mbox->data; | ||
2905 | |||
2906 | mbox->cmd.length = sizeof(short); | ||
2907 | dlci_list[0] = dlci; | ||
2908 | mbox->cmd.command = FR_ADD_DLCI; | ||
2909 | err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; | ||
2910 | |||
2911 | } while (err && retry-- && fr_event(card, err, mbox)); | ||
2912 | |||
2913 | return err; | ||
2914 | } | ||
2915 | |||
2916 | /*============================================================================ | ||
2917 | * Activate DLCI(s) (Access Node only!). | ||
2918 | * This routine will perform the ACTIVATE_DLCIs command with a DLCI number. | ||
2919 | */ | ||
2920 | static int fr_activate_dlci (sdla_t* card, int dlci) | ||
2921 | { | ||
2922 | fr_mbox_t* mbox = card->mbox; | ||
2923 | int retry = MAX_CMD_RETRY; | ||
2924 | int err; | ||
2925 | |||
2926 | do | ||
2927 | { | ||
2928 | unsigned short* dlci_list = (void*)mbox->data; | ||
2929 | |||
2930 | mbox->cmd.length = sizeof(short); | ||
2931 | dlci_list[0] = dlci; | ||
2932 | mbox->cmd.command = FR_ACTIVATE_DLCI; | ||
2933 | err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; | ||
2934 | |||
2935 | } while (err && retry-- && fr_event(card, err, mbox)); | ||
2936 | |||
2937 | return err; | ||
2938 | } | ||
2939 | |||
2940 | /*============================================================================ | ||
2941 | * Delete DLCI(s) (Access Node only!). | ||
2942 | * This routine will perform the DELETE_DLCIs command with a DLCI number. | ||
2943 | */ | ||
2944 | static int fr_delete_dlci (sdla_t* card, int dlci) | ||
2945 | { | ||
2946 | fr_mbox_t* mbox = card->mbox; | ||
2947 | int retry = MAX_CMD_RETRY; | ||
2948 | int err; | ||
2949 | |||
2950 | do | ||
2951 | { | ||
2952 | unsigned short* dlci_list = (void*)mbox->data; | ||
2953 | |||
2954 | mbox->cmd.length = sizeof(short); | ||
2955 | dlci_list[0] = dlci; | ||
2956 | mbox->cmd.command = FR_DELETE_DLCI; | ||
2957 | err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; | ||
2958 | |||
2959 | } while (err && retry-- && fr_event(card, err, mbox)); | ||
2960 | |||
2961 | return err; | ||
2962 | } | ||
2963 | |||
2964 | |||
2965 | |||
2966 | /*============================================================================ | ||
2967 | * Issue in-channel signalling frame. | ||
2968 | */ | ||
2969 | static int fr_issue_isf (sdla_t* card, int isf) | ||
2970 | { | ||
2971 | fr_mbox_t* mbox = card->mbox; | ||
2972 | int retry = MAX_CMD_RETRY; | ||
2973 | int err; | ||
2974 | |||
2975 | do | ||
2976 | { | ||
2977 | mbox->data[0] = isf; | ||
2978 | mbox->cmd.length = 1; | ||
2979 | mbox->cmd.command = FR_ISSUE_IS_FRAME; | ||
2980 | err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; | ||
2981 | } while (err && retry-- && fr_event(card, err, mbox)); | ||
2982 | |||
2983 | return err; | ||
2984 | } | ||
2985 | |||
2986 | |||
2987 | static unsigned int fr_send_hdr (sdla_t*card, int dlci, unsigned int offset) | ||
2988 | { | ||
2989 | struct net_device *dev = find_channel(card,dlci); | ||
2990 | fr_channel_t *chan; | ||
2991 | |||
2992 | if (!dev || !(chan=dev->priv)) | ||
2993 | return offset; | ||
2994 | |||
2995 | if (chan->fr_header_len){ | ||
2996 | sdla_poke(&card->hw, offset, chan->fr_header, chan->fr_header_len); | ||
2997 | } | ||
2998 | |||
2999 | return offset+chan->fr_header_len; | ||
3000 | } | ||
3001 | |||
3002 | /*============================================================================ | ||
3003 | * Send a frame on a selected DLCI. | ||
3004 | */ | ||
3005 | static int fr_send_data_header (sdla_t* card, int dlci, unsigned char attr, int len, | ||
3006 | void *buf, unsigned char hdr_len) | ||
3007 | { | ||
3008 | fr_mbox_t* mbox = card->mbox + 0x800; | ||
3009 | int retry = MAX_CMD_RETRY; | ||
3010 | int err; | ||
3011 | |||
3012 | do | ||
3013 | { | ||
3014 | mbox->cmd.dlci = dlci; | ||
3015 | mbox->cmd.attr = attr; | ||
3016 | mbox->cmd.length = len+hdr_len; | ||
3017 | mbox->cmd.command = FR_WRITE; | ||
3018 | err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; | ||
3019 | } while (err && retry-- && fr_event(card, err, mbox)); | ||
3020 | |||
3021 | if (!err) { | ||
3022 | fr_tx_buf_ctl_t* frbuf; | ||
3023 | |||
3024 | if(card->hw.type == SDLA_S514) | ||
3025 | frbuf = (void*)(*(unsigned long*)mbox->data + | ||
3026 | card->hw.dpmbase); | ||
3027 | else | ||
3028 | frbuf = (void*)(*(unsigned long*)mbox->data - | ||
3029 | FR_MB_VECTOR + card->hw.dpmbase); | ||
3030 | |||
3031 | sdla_poke(&card->hw, fr_send_hdr(card,dlci,frbuf->offset), buf, len); | ||
3032 | frbuf->flag = 0x01; | ||
3033 | } | ||
3034 | |||
3035 | return err; | ||
3036 | } | ||
3037 | |||
3038 | static int fr_send (sdla_t* card, int dlci, unsigned char attr, int len, | ||
3039 | void *buf) | ||
3040 | { | ||
3041 | fr_mbox_t* mbox = card->mbox + 0x800; | ||
3042 | int retry = MAX_CMD_RETRY; | ||
3043 | int err; | ||
3044 | |||
3045 | do | ||
3046 | { | ||
3047 | mbox->cmd.dlci = dlci; | ||
3048 | mbox->cmd.attr = attr; | ||
3049 | mbox->cmd.length = len; | ||
3050 | mbox->cmd.command = FR_WRITE; | ||
3051 | err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; | ||
3052 | } while (err && retry-- && fr_event(card, err, mbox)); | ||
3053 | |||
3054 | if (!err) { | ||
3055 | fr_tx_buf_ctl_t* frbuf; | ||
3056 | |||
3057 | if(card->hw.type == SDLA_S514) | ||
3058 | frbuf = (void*)(*(unsigned long*)mbox->data + | ||
3059 | card->hw.dpmbase); | ||
3060 | else | ||
3061 | frbuf = (void*)(*(unsigned long*)mbox->data - | ||
3062 | FR_MB_VECTOR + card->hw.dpmbase); | ||
3063 | |||
3064 | sdla_poke(&card->hw, frbuf->offset, buf, len); | ||
3065 | frbuf->flag = 0x01; | ||
3066 | } | ||
3067 | |||
3068 | return err; | ||
3069 | } | ||
3070 | |||
3071 | |||
3072 | /****** Firmware Asynchronous Event Handlers ********************************/ | ||
3073 | |||
3074 | /*============================================================================ | ||
3075 | * Main asyncronous event/error handler. | ||
3076 | * This routine is called whenever firmware command returns non-zero | ||
3077 | * return code. | ||
3078 | * | ||
3079 | * Return zero if previous command has to be cancelled. | ||
3080 | */ | ||
3081 | static int fr_event (sdla_t *card, int event, fr_mbox_t* mbox) | ||
3082 | { | ||
3083 | fr508_flags_t* flags = card->flags; | ||
3084 | char *ptr = &flags->iflag; | ||
3085 | int i; | ||
3086 | |||
3087 | switch (event) { | ||
3088 | |||
3089 | case FRRES_MODEM_FAILURE: | ||
3090 | return fr_modem_failure(card, mbox); | ||
3091 | |||
3092 | case FRRES_CHANNEL_DOWN: { | ||
3093 | struct net_device *dev; | ||
3094 | |||
3095 | /* Remove all routes from associated DLCI's */ | ||
3096 | for (dev = card->wandev.dev; dev; | ||
3097 | dev = *((struct net_device **)dev->priv)) { | ||
3098 | fr_channel_t *chan = dev->priv; | ||
3099 | if (chan->route_flag == ROUTE_ADDED) { | ||
3100 | chan->route_flag = REMOVE_ROUTE; | ||
3101 | } | ||
3102 | |||
3103 | if (chan->inarp == INARP_CONFIGURED) { | ||
3104 | chan->inarp = INARP_REQUEST; | ||
3105 | } | ||
3106 | |||
3107 | /* If the link becomes disconnected then, | ||
3108 | * all channels will be disconnected | ||
3109 | * as well. | ||
3110 | */ | ||
3111 | set_chan_state(dev,WAN_DISCONNECTED); | ||
3112 | } | ||
3113 | |||
3114 | wanpipe_set_state(card, WAN_DISCONNECTED); | ||
3115 | return 1; | ||
3116 | } | ||
3117 | |||
3118 | case FRRES_CHANNEL_UP: { | ||
3119 | struct net_device *dev; | ||
3120 | |||
3121 | /* FIXME: Only startup devices that are on the list */ | ||
3122 | |||
3123 | for (dev = card->wandev.dev; dev; | ||
3124 | dev = *((struct net_device **)dev->priv)) { | ||
3125 | |||
3126 | set_chan_state(dev,WAN_CONNECTED); | ||
3127 | } | ||
3128 | |||
3129 | wanpipe_set_state(card, WAN_CONNECTED); | ||
3130 | return 1; | ||
3131 | } | ||
3132 | |||
3133 | case FRRES_DLCI_CHANGE: | ||
3134 | return fr_dlci_change(card, mbox); | ||
3135 | |||
3136 | case FRRES_DLCI_MISMATCH: | ||
3137 | printk(KERN_INFO "%s: DLCI list mismatch!\n", | ||
3138 | card->devname); | ||
3139 | return 1; | ||
3140 | |||
3141 | case CMD_TIMEOUT: | ||
3142 | printk(KERN_ERR "%s: command 0x%02X timed out!\n", | ||
3143 | card->devname, mbox->cmd.command); | ||
3144 | printk(KERN_INFO "%s: ID Bytes = ",card->devname); | ||
3145 | for(i = 0; i < 8; i ++) | ||
3146 | printk(KERN_INFO "0x%02X ", *(ptr + 0x18 + i)); | ||
3147 | printk(KERN_INFO "\n"); | ||
3148 | |||
3149 | break; | ||
3150 | |||
3151 | case FRRES_DLCI_INACTIVE: | ||
3152 | break; | ||
3153 | |||
3154 | case FRRES_CIR_OVERFLOW: | ||
3155 | break; | ||
3156 | |||
3157 | case FRRES_BUFFER_OVERFLOW: | ||
3158 | break; | ||
3159 | |||
3160 | default: | ||
3161 | printk(KERN_INFO "%s: command 0x%02X returned 0x%02X!\n" | ||
3162 | , card->devname, mbox->cmd.command, event); | ||
3163 | } | ||
3164 | |||
3165 | return 0; | ||
3166 | } | ||
3167 | |||
3168 | /*============================================================================ | ||
3169 | * Handle modem error. | ||
3170 | * | ||
3171 | * Return zero if previous command has to be cancelled. | ||
3172 | */ | ||
3173 | static int fr_modem_failure (sdla_t *card, fr_mbox_t* mbox) | ||
3174 | { | ||
3175 | printk(KERN_INFO "%s: physical link down! (modem error 0x%02X)\n", | ||
3176 | card->devname, mbox->data[0]); | ||
3177 | |||
3178 | switch (mbox->cmd.command){ | ||
3179 | case FR_WRITE: | ||
3180 | |||
3181 | case FR_READ: | ||
3182 | return 0; | ||
3183 | } | ||
3184 | |||
3185 | return 1; | ||
3186 | } | ||
3187 | |||
3188 | /*============================================================================ | ||
3189 | * Handle DLCI status change. | ||
3190 | * | ||
3191 | * Return zero if previous command has to be cancelled. | ||
3192 | */ | ||
3193 | static int fr_dlci_change (sdla_t *card, fr_mbox_t* mbox) | ||
3194 | { | ||
3195 | dlci_status_t* status = (void*)mbox->data; | ||
3196 | int cnt = mbox->cmd.length / sizeof(dlci_status_t); | ||
3197 | fr_channel_t *chan; | ||
3198 | struct net_device* dev2; | ||
3199 | |||
3200 | |||
3201 | for (; cnt; --cnt, ++status) { | ||
3202 | |||
3203 | unsigned short dlci= status->dlci; | ||
3204 | struct net_device* dev = find_channel(card, dlci); | ||
3205 | |||
3206 | if (dev == NULL){ | ||
3207 | printk(KERN_INFO | ||
3208 | "%s: CPE contains unconfigured DLCI= %d\n", | ||
3209 | card->devname, dlci); | ||
3210 | |||
3211 | printk(KERN_INFO | ||
3212 | "%s: unconfigured DLCI %d reported by network\n" | ||
3213 | , card->devname, dlci); | ||
3214 | |||
3215 | }else{ | ||
3216 | if (status->state == FR_LINK_INOPER) { | ||
3217 | printk(KERN_INFO | ||
3218 | "%s: DLCI %u is inactive!\n", | ||
3219 | card->devname, dlci); | ||
3220 | |||
3221 | if (dev && netif_running(dev)) | ||
3222 | set_chan_state(dev, WAN_DISCONNECTED); | ||
3223 | } | ||
3224 | |||
3225 | if (status->state & FR_DLCI_DELETED) { | ||
3226 | |||
3227 | printk(KERN_INFO | ||
3228 | "%s: DLCI %u has been deleted!\n", | ||
3229 | card->devname, dlci); | ||
3230 | |||
3231 | if (dev && netif_running(dev)){ | ||
3232 | |||
3233 | fr_channel_t *chan = dev->priv; | ||
3234 | |||
3235 | if (chan->route_flag == ROUTE_ADDED) { | ||
3236 | chan->route_flag = REMOVE_ROUTE; | ||
3237 | /* The state change will trigger | ||
3238 | * the fr polling routine */ | ||
3239 | } | ||
3240 | |||
3241 | if (chan->inarp == INARP_CONFIGURED) { | ||
3242 | chan->inarp = INARP_REQUEST; | ||
3243 | } | ||
3244 | |||
3245 | set_chan_state(dev, WAN_DISCONNECTED); | ||
3246 | } | ||
3247 | |||
3248 | } else if (status->state & FR_DLCI_ACTIVE) { | ||
3249 | |||
3250 | chan = dev->priv; | ||
3251 | |||
3252 | /* This flag is used for configuring specific | ||
3253 | DLCI(s) when they become active. | ||
3254 | */ | ||
3255 | chan->dlci_configured = DLCI_CONFIG_PENDING; | ||
3256 | |||
3257 | set_chan_state(dev, WAN_CONNECTED); | ||
3258 | |||
3259 | } | ||
3260 | } | ||
3261 | } | ||
3262 | |||
3263 | for (dev2 = card->wandev.dev; dev2; | ||
3264 | dev2 = *((struct net_device **)dev2->priv)){ | ||
3265 | |||
3266 | chan = dev2->priv; | ||
3267 | |||
3268 | if (chan->dlci_configured == DLCI_CONFIG_PENDING) { | ||
3269 | if (fr_init_dlci(card, chan)){ | ||
3270 | return 1; | ||
3271 | } | ||
3272 | } | ||
3273 | |||
3274 | } | ||
3275 | return 1; | ||
3276 | } | ||
3277 | |||
3278 | |||
3279 | static int fr_init_dlci (sdla_t *card, fr_channel_t *chan) | ||
3280 | { | ||
3281 | fr_dlc_conf_t cfg; | ||
3282 | |||
3283 | memset(&cfg, 0, sizeof(cfg)); | ||
3284 | |||
3285 | if ( chan->cir_status == CIR_DISABLED) { | ||
3286 | |||
3287 | cfg.cir_fwd = cfg.cir_bwd = 16; | ||
3288 | cfg.bc_fwd = cfg.bc_bwd = 16; | ||
3289 | cfg.conf_flags = 0x0001; | ||
3290 | |||
3291 | }else if (chan->cir_status == CIR_ENABLED) { | ||
3292 | |||
3293 | cfg.cir_fwd = cfg.cir_bwd = chan->cir; | ||
3294 | cfg.bc_fwd = cfg.bc_bwd = chan->bc; | ||
3295 | cfg.be_fwd = cfg.be_bwd = chan->be; | ||
3296 | cfg.conf_flags = 0x0000; | ||
3297 | } | ||
3298 | |||
3299 | if (fr_dlci_configure( card, &cfg , chan->dlci)){ | ||
3300 | printk(KERN_INFO | ||
3301 | "%s: DLCI Configure failed for %d\n", | ||
3302 | card->devname, chan->dlci); | ||
3303 | return 1; | ||
3304 | } | ||
3305 | |||
3306 | chan->dlci_configured = DLCI_CONFIGURED; | ||
3307 | |||
3308 | /* Read the interface byte mapping into the channel | ||
3309 | * structure. | ||
3310 | */ | ||
3311 | read_DLCI_IB_mapping( card, chan ); | ||
3312 | |||
3313 | return 0; | ||
3314 | } | ||
3315 | /******* Miscellaneous ******************************************************/ | ||
3316 | |||
3317 | /*============================================================================ | ||
3318 | * Update channel state. | ||
3319 | */ | ||
3320 | static int update_chan_state(struct net_device* dev) | ||
3321 | { | ||
3322 | fr_channel_t* chan = dev->priv; | ||
3323 | sdla_t* card = chan->card; | ||
3324 | fr_mbox_t* mbox = card->mbox; | ||
3325 | int retry = MAX_CMD_RETRY; | ||
3326 | int err; | ||
3327 | |||
3328 | do | ||
3329 | { | ||
3330 | mbox->cmd.command = FR_LIST_ACTIVE_DLCI; | ||
3331 | mbox->cmd.length = 0; | ||
3332 | err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; | ||
3333 | } while (err && retry-- && fr_event(card, err, mbox)); | ||
3334 | |||
3335 | if (!err) { | ||
3336 | |||
3337 | unsigned short* list = (void*)mbox->data; | ||
3338 | int cnt = mbox->cmd.length / sizeof(short); | ||
3339 | |||
3340 | err=1; | ||
3341 | |||
3342 | for (; cnt; --cnt, ++list) { | ||
3343 | |||
3344 | if (*list == chan->dlci) { | ||
3345 | set_chan_state(dev, WAN_CONNECTED); | ||
3346 | |||
3347 | |||
3348 | /* May 23 2000. NC | ||
3349 | * When a dlci is added or restarted, | ||
3350 | * the dlci_int_interface pointer must | ||
3351 | * be reinitialized. */ | ||
3352 | if (!chan->dlci_int_interface){ | ||
3353 | err=fr_init_dlci (card,chan); | ||
3354 | } | ||
3355 | break; | ||
3356 | } | ||
3357 | } | ||
3358 | } | ||
3359 | |||
3360 | return err; | ||
3361 | } | ||
3362 | |||
3363 | /*============================================================================ | ||
3364 | * Set channel state. | ||
3365 | */ | ||
3366 | static void set_chan_state(struct net_device* dev, int state) | ||
3367 | { | ||
3368 | fr_channel_t* chan = dev->priv; | ||
3369 | sdla_t* card = chan->card; | ||
3370 | |||
3371 | if (chan->common.state != state) { | ||
3372 | |||
3373 | switch (state) { | ||
3374 | |||
3375 | case WAN_CONNECTED: | ||
3376 | printk(KERN_INFO | ||
3377 | "%s: Interface %s: DLCI %d connected\n", | ||
3378 | card->devname, dev->name, chan->dlci); | ||
3379 | |||
3380 | /* If the interface was previoulsy down, | ||
3381 | * bring it up, since the channel is active */ | ||
3382 | |||
3383 | trigger_fr_poll (dev); | ||
3384 | trigger_fr_arp (dev); | ||
3385 | break; | ||
3386 | |||
3387 | case WAN_CONNECTING: | ||
3388 | printk(KERN_INFO | ||
3389 | "%s: Interface %s: DLCI %d connecting\n", | ||
3390 | card->devname, dev->name, chan->dlci); | ||
3391 | break; | ||
3392 | |||
3393 | case WAN_DISCONNECTED: | ||
3394 | printk (KERN_INFO | ||
3395 | "%s: Interface %s: DLCI %d disconnected!\n", | ||
3396 | card->devname, dev->name, chan->dlci); | ||
3397 | |||
3398 | /* If the interface is up, bring it down, | ||
3399 | * since the channel is now disconnected */ | ||
3400 | trigger_fr_poll (dev); | ||
3401 | break; | ||
3402 | } | ||
3403 | |||
3404 | chan->common.state = state; | ||
3405 | } | ||
3406 | |||
3407 | chan->state_tick = jiffies; | ||
3408 | } | ||
3409 | |||
3410 | /*============================================================================ | ||
3411 | * Find network device by its channel number. | ||
3412 | * | ||
3413 | * We need this critical flag because we change | ||
3414 | * the dlci_to_dev_map outside the interrupt. | ||
3415 | * | ||
3416 | * NOTE: del_if() functions updates this array, it uses | ||
3417 | * the spin locks to avoid corruption. | ||
3418 | */ | ||
3419 | static struct net_device* find_channel(sdla_t* card, unsigned dlci) | ||
3420 | { | ||
3421 | if(dlci > HIGHEST_VALID_DLCI) | ||
3422 | return NULL; | ||
3423 | |||
3424 | return(card->u.f.dlci_to_dev_map[dlci]); | ||
3425 | } | ||
3426 | |||
3427 | /*============================================================================ | ||
3428 | * Check to see if a frame can be sent. If no transmit buffers available, | ||
3429 | * enable transmit interrupts. | ||
3430 | * | ||
3431 | * Return: 1 - Tx buffer(s) available | ||
3432 | * 0 - no buffers available | ||
3433 | */ | ||
3434 | static int is_tx_ready (sdla_t* card, fr_channel_t* chan) | ||
3435 | { | ||
3436 | unsigned char sb; | ||
3437 | |||
3438 | if(card->hw.type == SDLA_S514) | ||
3439 | return 1; | ||
3440 | |||
3441 | sb = inb(card->hw.port); | ||
3442 | if (sb & 0x02) | ||
3443 | return 1; | ||
3444 | |||
3445 | return 0; | ||
3446 | } | ||
3447 | |||
3448 | /*============================================================================ | ||
3449 | * Convert decimal string to unsigned integer. | ||
3450 | * If len != 0 then only 'len' characters of the string are converted. | ||
3451 | */ | ||
3452 | static unsigned int dec_to_uint (unsigned char* str, int len) | ||
3453 | { | ||
3454 | unsigned val; | ||
3455 | |||
3456 | if (!len) | ||
3457 | len = strlen(str); | ||
3458 | |||
3459 | for (val = 0; len && isdigit(*str); ++str, --len) | ||
3460 | val = (val * 10) + (*str - (unsigned)'0'); | ||
3461 | |||
3462 | return val; | ||
3463 | } | ||
3464 | |||
3465 | |||
3466 | |||
3467 | /*============================================================================= | ||
3468 | * Store a UDP management packet for later processing. | ||
3469 | */ | ||
3470 | |||
3471 | static int store_udp_mgmt_pkt(int udp_type, char udp_pkt_src, sdla_t* card, | ||
3472 | struct sk_buff *skb, int dlci) | ||
3473 | { | ||
3474 | int udp_pkt_stored = 0; | ||
3475 | |||
3476 | struct net_device *dev = find_channel(card, dlci); | ||
3477 | fr_channel_t *chan; | ||
3478 | |||
3479 | if (!dev || !(chan=dev->priv)) | ||
3480 | return 1; | ||
3481 | |||
3482 | if(!card->u.f.udp_pkt_lgth && (skb->len <= MAX_LGTH_UDP_MGNT_PKT)){ | ||
3483 | card->u.f.udp_pkt_lgth = skb->len + chan->fr_header_len; | ||
3484 | card->u.f.udp_type = udp_type; | ||
3485 | card->u.f.udp_pkt_src = udp_pkt_src; | ||
3486 | card->u.f.udp_dlci = dlci; | ||
3487 | memcpy(card->u.f.udp_pkt_data, skb->data, skb->len); | ||
3488 | card->u.f.timer_int_enabled |= TMR_INT_ENABLED_UDP; | ||
3489 | udp_pkt_stored = 1; | ||
3490 | |||
3491 | }else{ | ||
3492 | printk(KERN_INFO "ERROR: UDP packet not stored for DLCI %d\n", | ||
3493 | dlci); | ||
3494 | } | ||
3495 | |||
3496 | if(udp_pkt_src == UDP_PKT_FRM_STACK){ | ||
3497 | dev_kfree_skb_any(skb); | ||
3498 | }else{ | ||
3499 | dev_kfree_skb_any(skb); | ||
3500 | } | ||
3501 | |||
3502 | return(udp_pkt_stored); | ||
3503 | } | ||
3504 | |||
3505 | |||
3506 | /*============================================================================== | ||
3507 | * Process UDP call of type FPIPE8ND | ||
3508 | */ | ||
3509 | static int process_udp_mgmt_pkt(sdla_t* card) | ||
3510 | { | ||
3511 | |||
3512 | int c_retry = MAX_CMD_RETRY; | ||
3513 | unsigned char *buf; | ||
3514 | unsigned char frames; | ||
3515 | unsigned int len; | ||
3516 | unsigned short buffer_length; | ||
3517 | struct sk_buff *new_skb; | ||
3518 | fr_mbox_t* mbox = card->mbox; | ||
3519 | int err; | ||
3520 | struct timeval tv; | ||
3521 | int udp_mgmt_req_valid = 1; | ||
3522 | struct net_device* dev; | ||
3523 | fr_channel_t* chan; | ||
3524 | fr_udp_pkt_t *fr_udp_pkt; | ||
3525 | unsigned short num_trc_els; | ||
3526 | fr_trc_el_t* ptr_trc_el; | ||
3527 | fr_trc_el_t trc_el; | ||
3528 | fpipemon_trc_t* fpipemon_trc; | ||
3529 | |||
3530 | char udp_pkt_src = card->u.f.udp_pkt_src; | ||
3531 | int dlci = card->u.f.udp_dlci; | ||
3532 | |||
3533 | /* Find network interface for this packet */ | ||
3534 | dev = find_channel(card, dlci); | ||
3535 | if (!dev){ | ||
3536 | card->u.f.udp_pkt_lgth = 0; | ||
3537 | return 1; | ||
3538 | } | ||
3539 | if ((chan = dev->priv) == NULL){ | ||
3540 | card->u.f.udp_pkt_lgth = 0; | ||
3541 | return 1; | ||
3542 | } | ||
3543 | |||
3544 | /* If the UDP packet is from the network, we are going to have to | ||
3545 | transmit a response. Before doing so, we must check to see that | ||
3546 | we are not currently transmitting a frame (in 'if_send()') and | ||
3547 | that we are not already in a 'delayed transmit' state. | ||
3548 | */ | ||
3549 | if(udp_pkt_src == UDP_PKT_FRM_NETWORK) { | ||
3550 | if (check_tx_status(card,dev)){ | ||
3551 | card->u.f.udp_pkt_lgth = 0; | ||
3552 | return 1; | ||
3553 | } | ||
3554 | } | ||
3555 | |||
3556 | fr_udp_pkt = (fr_udp_pkt_t *)card->u.f.udp_pkt_data; | ||
3557 | |||
3558 | if(udp_pkt_src == UDP_PKT_FRM_NETWORK) { | ||
3559 | |||
3560 | switch(fr_udp_pkt->cblock.command) { | ||
3561 | |||
3562 | case FR_READ_MODEM_STATUS: | ||
3563 | case FR_READ_STATUS: | ||
3564 | case FPIPE_ROUTER_UP_TIME: | ||
3565 | case FR_READ_ERROR_STATS: | ||
3566 | case FPIPE_DRIVER_STAT_GEN: | ||
3567 | case FR_READ_STATISTICS: | ||
3568 | case FR_READ_ADD_DLC_STATS: | ||
3569 | case FR_READ_CONFIG: | ||
3570 | case FR_READ_CODE_VERSION: | ||
3571 | udp_mgmt_req_valid = 1; | ||
3572 | break; | ||
3573 | default: | ||
3574 | udp_mgmt_req_valid = 0; | ||
3575 | break; | ||
3576 | } | ||
3577 | } | ||
3578 | |||
3579 | if(!udp_mgmt_req_valid) { | ||
3580 | /* set length to 0 */ | ||
3581 | fr_udp_pkt->cblock.length = 0; | ||
3582 | /* set return code */ | ||
3583 | fr_udp_pkt->cblock.result = 0xCD; | ||
3584 | |||
3585 | chan->drvstats_gen.UDP_PIPE_mgmt_direction_err ++; | ||
3586 | |||
3587 | if (net_ratelimit()){ | ||
3588 | printk(KERN_INFO | ||
3589 | "%s: Warning, Illegal UDP command attempted from network: %x\n", | ||
3590 | card->devname,fr_udp_pkt->cblock.command); | ||
3591 | } | ||
3592 | |||
3593 | } else { | ||
3594 | |||
3595 | switch(fr_udp_pkt->cblock.command) { | ||
3596 | |||
3597 | case FPIPE_ENABLE_TRACING: | ||
3598 | if(!card->TracingEnabled) { | ||
3599 | do { | ||
3600 | mbox->cmd.command = FR_SET_TRACE_CONFIG; | ||
3601 | mbox->cmd.length = 1; | ||
3602 | mbox->cmd.dlci = 0x00; | ||
3603 | mbox->data[0] = fr_udp_pkt->data[0] | | ||
3604 | RESET_TRC; | ||
3605 | err = sdla_exec(mbox) ? | ||
3606 | mbox->cmd.result : CMD_TIMEOUT; | ||
3607 | } while (err && c_retry-- && fr_event(card, err, | ||
3608 | mbox)); | ||
3609 | |||
3610 | if(err) { | ||
3611 | card->TracingEnabled = 0; | ||
3612 | /* set the return code */ | ||
3613 | fr_udp_pkt->cblock.result = | ||
3614 | mbox->cmd.result; | ||
3615 | mbox->cmd.length = 0; | ||
3616 | break; | ||
3617 | } | ||
3618 | |||
3619 | sdla_peek(&card->hw, NO_TRC_ELEMENTS_OFF, | ||
3620 | &num_trc_els, 2); | ||
3621 | sdla_peek(&card->hw, BASE_TRC_ELEMENTS_OFF, | ||
3622 | &card->u.f.trc_el_base, 4); | ||
3623 | card->u.f.curr_trc_el = card->u.f.trc_el_base; | ||
3624 | card->u.f.trc_el_last = card->u.f.curr_trc_el + | ||
3625 | ((num_trc_els - 1) * | ||
3626 | sizeof(fr_trc_el_t)); | ||
3627 | |||
3628 | /* Calculate the maximum trace data area in */ | ||
3629 | /* the UDP packet */ | ||
3630 | card->u.f.trc_bfr_space=(MAX_LGTH_UDP_MGNT_PKT - | ||
3631 | //sizeof(fr_encap_hdr_t) - | ||
3632 | sizeof(ip_pkt_t) - | ||
3633 | sizeof(udp_pkt_t) - | ||
3634 | sizeof(wp_mgmt_t) - | ||
3635 | sizeof(cblock_t)); | ||
3636 | |||
3637 | /* set return code */ | ||
3638 | fr_udp_pkt->cblock.result = 0; | ||
3639 | |||
3640 | } else { | ||
3641 | /* set return code to line trace already | ||
3642 | enabled */ | ||
3643 | fr_udp_pkt->cblock.result = 1; | ||
3644 | } | ||
3645 | |||
3646 | mbox->cmd.length = 0; | ||
3647 | card->TracingEnabled = 1; | ||
3648 | break; | ||
3649 | |||
3650 | |||
3651 | case FPIPE_DISABLE_TRACING: | ||
3652 | if(card->TracingEnabled) { | ||
3653 | |||
3654 | do { | ||
3655 | mbox->cmd.command = FR_SET_TRACE_CONFIG; | ||
3656 | mbox->cmd.length = 1; | ||
3657 | mbox->cmd.dlci = 0x00; | ||
3658 | mbox->data[0] = ~ACTIVATE_TRC; | ||
3659 | err = sdla_exec(mbox) ? | ||
3660 | mbox->cmd.result : CMD_TIMEOUT; | ||
3661 | } while (err && c_retry-- && fr_event(card, err, mbox)); | ||
3662 | } | ||
3663 | |||
3664 | /* set return code */ | ||
3665 | fr_udp_pkt->cblock.result = 0; | ||
3666 | mbox->cmd.length = 0; | ||
3667 | card->TracingEnabled = 0; | ||
3668 | break; | ||
3669 | |||
3670 | case FPIPE_GET_TRACE_INFO: | ||
3671 | |||
3672 | /* Line trace cannot be performed on the 502 */ | ||
3673 | if(!card->TracingEnabled) { | ||
3674 | /* set return code */ | ||
3675 | fr_udp_pkt->cblock.result = 1; | ||
3676 | mbox->cmd.length = 0; | ||
3677 | break; | ||
3678 | } | ||
3679 | |||
3680 | ptr_trc_el = (void *)card->u.f.curr_trc_el; | ||
3681 | |||
3682 | buffer_length = 0; | ||
3683 | fr_udp_pkt->data[0x00] = 0x00; | ||
3684 | |||
3685 | for(frames = 0; frames < MAX_FRMS_TRACED; frames ++) { | ||
3686 | |||
3687 | sdla_peek(&card->hw, (unsigned long)ptr_trc_el, | ||
3688 | (void *)&trc_el.flag, | ||
3689 | sizeof(fr_trc_el_t)); | ||
3690 | if(trc_el.flag == 0x00) { | ||
3691 | break; | ||
3692 | } | ||
3693 | if((card->u.f.trc_bfr_space - buffer_length) | ||
3694 | < sizeof(fpipemon_trc_hdr_t)) { | ||
3695 | fr_udp_pkt->data[0x00] |= MORE_TRC_DATA; | ||
3696 | break; | ||
3697 | } | ||
3698 | |||
3699 | fpipemon_trc = | ||
3700 | (fpipemon_trc_t *)&fr_udp_pkt->data[buffer_length]; | ||
3701 | fpipemon_trc->fpipemon_trc_hdr.status = | ||
3702 | trc_el.attr; | ||
3703 | fpipemon_trc->fpipemon_trc_hdr.tmstamp = | ||
3704 | trc_el.tmstamp; | ||
3705 | fpipemon_trc->fpipemon_trc_hdr.length = | ||
3706 | trc_el.length; | ||
3707 | |||
3708 | if(!trc_el.offset || !trc_el.length) { | ||
3709 | |||
3710 | fpipemon_trc->fpipemon_trc_hdr.data_passed = 0x00; | ||
3711 | |||
3712 | }else if((trc_el.length + sizeof(fpipemon_trc_hdr_t) + 1) > | ||
3713 | (card->u.f.trc_bfr_space - buffer_length)){ | ||
3714 | |||
3715 | fpipemon_trc->fpipemon_trc_hdr.data_passed = 0x00; | ||
3716 | fr_udp_pkt->data[0x00] |= MORE_TRC_DATA; | ||
3717 | |||
3718 | }else { | ||
3719 | fpipemon_trc->fpipemon_trc_hdr.data_passed = 0x01; | ||
3720 | sdla_peek(&card->hw, trc_el.offset, | ||
3721 | fpipemon_trc->data, | ||
3722 | trc_el.length); | ||
3723 | } | ||
3724 | |||
3725 | trc_el.flag = 0x00; | ||
3726 | sdla_poke(&card->hw, (unsigned long)ptr_trc_el, | ||
3727 | &trc_el.flag, 1); | ||
3728 | |||
3729 | ptr_trc_el ++; | ||
3730 | if((void *)ptr_trc_el > card->u.f.trc_el_last) | ||
3731 | ptr_trc_el = (void*)card->u.f.trc_el_base; | ||
3732 | |||
3733 | buffer_length += sizeof(fpipemon_trc_hdr_t); | ||
3734 | if(fpipemon_trc->fpipemon_trc_hdr.data_passed) { | ||
3735 | buffer_length += trc_el.length; | ||
3736 | } | ||
3737 | |||
3738 | if(fr_udp_pkt->data[0x00] & MORE_TRC_DATA) { | ||
3739 | break; | ||
3740 | } | ||
3741 | } | ||
3742 | |||
3743 | if(frames == MAX_FRMS_TRACED) { | ||
3744 | fr_udp_pkt->data[0x00] |= MORE_TRC_DATA; | ||
3745 | } | ||
3746 | |||
3747 | card->u.f.curr_trc_el = (void *)ptr_trc_el; | ||
3748 | |||
3749 | /* set the total number of frames passed */ | ||
3750 | fr_udp_pkt->data[0x00] |= | ||
3751 | ((frames << 1) & (MAX_FRMS_TRACED << 1)); | ||
3752 | |||
3753 | /* set the data length and return code */ | ||
3754 | fr_udp_pkt->cblock.length = mbox->cmd.length = buffer_length; | ||
3755 | fr_udp_pkt->cblock.result = 0; | ||
3756 | break; | ||
3757 | |||
3758 | case FPIPE_FT1_READ_STATUS: | ||
3759 | sdla_peek(&card->hw, 0xF020, | ||
3760 | &fr_udp_pkt->data[0x00] , 2); | ||
3761 | fr_udp_pkt->cblock.length = mbox->cmd.length = 2; | ||
3762 | fr_udp_pkt->cblock.result = 0; | ||
3763 | break; | ||
3764 | |||
3765 | case FPIPE_FLUSH_DRIVER_STATS: | ||
3766 | init_chan_statistics(chan); | ||
3767 | init_global_statistics(card); | ||
3768 | mbox->cmd.length = 0; | ||
3769 | break; | ||
3770 | |||
3771 | case FPIPE_ROUTER_UP_TIME: | ||
3772 | do_gettimeofday(&tv); | ||
3773 | chan->router_up_time = tv.tv_sec - | ||
3774 | chan->router_start_time; | ||
3775 | *(unsigned long *)&fr_udp_pkt->data = | ||
3776 | chan->router_up_time; | ||
3777 | mbox->cmd.length = fr_udp_pkt->cblock.length = 4; | ||
3778 | fr_udp_pkt->cblock.result = 0; | ||
3779 | break; | ||
3780 | |||
3781 | case FPIPE_DRIVER_STAT_IFSEND: | ||
3782 | memcpy(fr_udp_pkt->data, | ||
3783 | &chan->drvstats_if_send.if_send_entry, | ||
3784 | sizeof(if_send_stat_t)); | ||
3785 | mbox->cmd.length = fr_udp_pkt->cblock.length =sizeof(if_send_stat_t); | ||
3786 | fr_udp_pkt->cblock.result = 0; | ||
3787 | break; | ||
3788 | |||
3789 | case FPIPE_DRIVER_STAT_INTR: | ||
3790 | |||
3791 | memcpy(fr_udp_pkt->data, | ||
3792 | &card->statistics.isr_entry, | ||
3793 | sizeof(global_stats_t)); | ||
3794 | |||
3795 | memcpy(&fr_udp_pkt->data[sizeof(global_stats_t)], | ||
3796 | &chan->drvstats_rx_intr.rx_intr_no_socket, | ||
3797 | sizeof(rx_intr_stat_t)); | ||
3798 | |||
3799 | mbox->cmd.length = fr_udp_pkt->cblock.length = | ||
3800 | sizeof(global_stats_t) + | ||
3801 | sizeof(rx_intr_stat_t); | ||
3802 | fr_udp_pkt->cblock.result = 0; | ||
3803 | break; | ||
3804 | |||
3805 | case FPIPE_DRIVER_STAT_GEN: | ||
3806 | memcpy(fr_udp_pkt->data, | ||
3807 | &chan->drvstats_gen.UDP_PIPE_mgmt_kmalloc_err, | ||
3808 | sizeof(pipe_mgmt_stat_t)); | ||
3809 | |||
3810 | memcpy(&fr_udp_pkt->data[sizeof(pipe_mgmt_stat_t)], | ||
3811 | &card->statistics, sizeof(global_stats_t)); | ||
3812 | |||
3813 | mbox->cmd.length = fr_udp_pkt->cblock.length = sizeof(global_stats_t)+ | ||
3814 | sizeof(rx_intr_stat_t); | ||
3815 | fr_udp_pkt->cblock.result = 0; | ||
3816 | break; | ||
3817 | |||
3818 | |||
3819 | case FR_FT1_STATUS_CTRL: | ||
3820 | if(fr_udp_pkt->data[0] == 1) { | ||
3821 | if(rCount++ != 0 ){ | ||
3822 | fr_udp_pkt->cblock.result = 0; | ||
3823 | mbox->cmd.length = 1; | ||
3824 | break; | ||
3825 | } | ||
3826 | } | ||
3827 | |||
3828 | /* Disable FT1 MONITOR STATUS */ | ||
3829 | if(fr_udp_pkt->data[0] == 0) { | ||
3830 | if( --rCount != 0) { | ||
3831 | fr_udp_pkt->cblock.result = 0; | ||
3832 | mbox->cmd.length = 1; | ||
3833 | break; | ||
3834 | } | ||
3835 | } | ||
3836 | goto udp_mgmt_dflt; | ||
3837 | |||
3838 | |||
3839 | default: | ||
3840 | udp_mgmt_dflt: | ||
3841 | do { | ||
3842 | memcpy(&mbox->cmd, | ||
3843 | &fr_udp_pkt->cblock.command, | ||
3844 | sizeof(fr_cmd_t)); | ||
3845 | if(mbox->cmd.length) { | ||
3846 | memcpy(&mbox->data, | ||
3847 | (char *)fr_udp_pkt->data, | ||
3848 | mbox->cmd.length); | ||
3849 | } | ||
3850 | |||
3851 | err = sdla_exec(mbox) ? mbox->cmd.result : | ||
3852 | CMD_TIMEOUT; | ||
3853 | } while (err && c_retry-- && fr_event(card, err, mbox)); | ||
3854 | |||
3855 | if(!err) | ||
3856 | chan->drvstats_gen. | ||
3857 | UDP_PIPE_mgmt_adptr_cmnd_OK ++; | ||
3858 | else | ||
3859 | chan->drvstats_gen. | ||
3860 | UDP_PIPE_mgmt_adptr_cmnd_timeout ++; | ||
3861 | |||
3862 | /* copy the result back to our buffer */ | ||
3863 | memcpy(&fr_udp_pkt->cblock.command, | ||
3864 | &mbox->cmd, sizeof(fr_cmd_t)); | ||
3865 | |||
3866 | if(mbox->cmd.length) { | ||
3867 | memcpy(&fr_udp_pkt->data, | ||
3868 | &mbox->data, mbox->cmd.length); | ||
3869 | } | ||
3870 | } | ||
3871 | } | ||
3872 | |||
3873 | /* Fill UDP TTL */ | ||
3874 | fr_udp_pkt->ip_pkt.ttl = card->wandev.ttl; | ||
3875 | len = reply_udp(card->u.f.udp_pkt_data, mbox->cmd.length); | ||
3876 | |||
3877 | if(udp_pkt_src == UDP_PKT_FRM_NETWORK) { | ||
3878 | |||
3879 | chan->fr_header_len=2; | ||
3880 | chan->fr_header[0]=Q922_UI; | ||
3881 | chan->fr_header[1]=NLPID_IP; | ||
3882 | |||
3883 | err = fr_send_data_header(card, dlci, 0, len, | ||
3884 | card->u.f.udp_pkt_data,chan->fr_header_len); | ||
3885 | if (err){ | ||
3886 | chan->drvstats_gen.UDP_PIPE_mgmt_adptr_send_passed ++; | ||
3887 | }else{ | ||
3888 | chan->drvstats_gen.UDP_PIPE_mgmt_adptr_send_failed ++; | ||
3889 | } | ||
3890 | |||
3891 | } else { | ||
3892 | /* Allocate socket buffer */ | ||
3893 | if((new_skb = dev_alloc_skb(len)) != NULL) { | ||
3894 | |||
3895 | /* copy data into new_skb */ | ||
3896 | buf = skb_put(new_skb, len); | ||
3897 | memcpy(buf, card->u.f.udp_pkt_data, len); | ||
3898 | |||
3899 | chan->drvstats_gen. | ||
3900 | UDP_PIPE_mgmt_passed_to_stack ++; | ||
3901 | new_skb->dev = dev; | ||
3902 | new_skb->protocol = htons(ETH_P_IP); | ||
3903 | new_skb->mac.raw = new_skb->data; | ||
3904 | netif_rx(new_skb); | ||
3905 | |||
3906 | } else { | ||
3907 | chan->drvstats_gen.UDP_PIPE_mgmt_no_socket ++; | ||
3908 | printk(KERN_INFO | ||
3909 | "%s: UDP mgmt cmnd, no socket buffers available!\n", | ||
3910 | card->devname); | ||
3911 | } | ||
3912 | } | ||
3913 | |||
3914 | card->u.f.udp_pkt_lgth = 0; | ||
3915 | |||
3916 | return 1; | ||
3917 | } | ||
3918 | |||
3919 | /*============================================================================== | ||
3920 | * Send Inverse ARP Request | ||
3921 | */ | ||
3922 | |||
3923 | int send_inarp_request(sdla_t *card, struct net_device *dev) | ||
3924 | { | ||
3925 | int err=0; | ||
3926 | |||
3927 | arphdr_1490_t *ArpPacket; | ||
3928 | arphdr_fr_t *arphdr; | ||
3929 | fr_channel_t *chan = dev->priv; | ||
3930 | struct in_device *in_dev; | ||
3931 | |||
3932 | in_dev = dev->ip_ptr; | ||
3933 | |||
3934 | if(in_dev != NULL ) { | ||
3935 | |||
3936 | ArpPacket = kmalloc(sizeof(arphdr_1490_t) + sizeof(arphdr_fr_t), GFP_ATOMIC); | ||
3937 | /* SNAP Header indicating ARP */ | ||
3938 | ArpPacket->control = 0x03; | ||
3939 | ArpPacket->pad = 0x00; | ||
3940 | ArpPacket->NLPID = 0x80; | ||
3941 | ArpPacket->OUI[0] = 0; | ||
3942 | ArpPacket->OUI[1] = 0; | ||
3943 | ArpPacket->OUI[2] = 0; | ||
3944 | ArpPacket->PID = 0x0608; | ||
3945 | |||
3946 | arphdr = (arphdr_fr_t *)(ArpPacket + 1); // Go to ARP Packet | ||
3947 | |||
3948 | /* InARP request */ | ||
3949 | arphdr->ar_hrd = 0x0F00; /* Frame Relay HW type */ | ||
3950 | arphdr->ar_pro = 0x0008; /* IP Protocol */ | ||
3951 | arphdr->ar_hln = 2; /* HW addr length */ | ||
3952 | arphdr->ar_pln = 4; /* IP addr length */ | ||
3953 | arphdr->ar_op = htons(0x08); /* InARP Request */ | ||
3954 | arphdr->ar_sha = 0; /* src HW DLCI - Doesn't matter */ | ||
3955 | if(in_dev->ifa_list != NULL) | ||
3956 | arphdr->ar_sip = in_dev->ifa_list->ifa_local; /* Local Address */else | ||
3957 | arphdr->ar_sip = 0; | ||
3958 | arphdr->ar_tha = 0; /* dst HW DLCI - Doesn't matter */ | ||
3959 | arphdr->ar_tip = 0; /* Remote Address -- what we want */ | ||
3960 | |||
3961 | err = fr_send(card, chan->dlci, 0, sizeof(arphdr_1490_t) + sizeof(arphdr_fr_t), | ||
3962 | (void *)ArpPacket); | ||
3963 | |||
3964 | if (!err){ | ||
3965 | printk(KERN_INFO "\n%s: Sending InARP request on DLCI %d.\n", | ||
3966 | card->devname, chan->dlci); | ||
3967 | clear_bit(ARP_CRIT,&card->wandev.critical); | ||
3968 | } | ||
3969 | |||
3970 | kfree(ArpPacket); | ||
3971 | }else{ | ||
3972 | printk(KERN_INFO "%s: INARP ERROR: %s doesn't have a local IP address!\n", | ||
3973 | card->devname,dev->name); | ||
3974 | return 1; | ||
3975 | } | ||
3976 | |||
3977 | return 0; | ||
3978 | } | ||
3979 | |||
3980 | |||
3981 | /*============================================================================== | ||
3982 | * Check packet for ARP Type | ||
3983 | */ | ||
3984 | |||
3985 | int is_arp(void *buf) | ||
3986 | { | ||
3987 | arphdr_1490_t *arphdr = (arphdr_1490_t *)buf; | ||
3988 | |||
3989 | if (arphdr->pad == 0x00 && | ||
3990 | arphdr->NLPID == 0x80 && | ||
3991 | arphdr->PID == 0x0608) | ||
3992 | return 1; | ||
3993 | else return 0; | ||
3994 | } | ||
3995 | |||
3996 | /*============================================================================== | ||
3997 | * Process ARP Packet Type | ||
3998 | */ | ||
3999 | |||
4000 | int process_ARP(arphdr_1490_t *ArpPacket, sdla_t *card, struct net_device* dev) | ||
4001 | { | ||
4002 | |||
4003 | |||
4004 | arphdr_fr_t *arphdr = (arphdr_fr_t *)(ArpPacket + 1); /* Skip header */ | ||
4005 | fr_rx_buf_ctl_t* frbuf = card->rxmb; | ||
4006 | struct in_device *in_dev; | ||
4007 | fr_channel_t *chan = dev->priv; | ||
4008 | |||
4009 | /* Before we transmit ARP packet, we must check | ||
4010 | * to see that we are not currently transmitting a | ||
4011 | * frame (in 'if_send()') and that we are not | ||
4012 | * already in a 'delayed transmit' state. */ | ||
4013 | if (check_tx_status(card,dev)){ | ||
4014 | if (net_ratelimit()){ | ||
4015 | printk(KERN_INFO "%s: Disabling comminication to process ARP\n", | ||
4016 | card->devname); | ||
4017 | } | ||
4018 | set_bit(ARP_CRIT,&card->wandev.critical); | ||
4019 | return 0; | ||
4020 | } | ||
4021 | |||
4022 | in_dev = dev->ip_ptr; | ||
4023 | |||
4024 | /* Check that IP addresses exist for our network address */ | ||
4025 | if (in_dev == NULL || in_dev->ifa_list == NULL) | ||
4026 | return -1; | ||
4027 | |||
4028 | switch (ntohs(arphdr->ar_op)) { | ||
4029 | |||
4030 | case 0x08: // Inverse ARP request -- Send Reply, add route. | ||
4031 | |||
4032 | /* Check for valid Address */ | ||
4033 | printk(KERN_INFO "%s: Recvd PtP addr -InArp Req: %u.%u.%u.%u\n", | ||
4034 | card->devname, NIPQUAD(arphdr->ar_sip)); | ||
4035 | |||
4036 | |||
4037 | /* Check that the network address is the same as ours, only | ||
4038 | * if the netowrk mask is not 255.255.255.255. Otherwise | ||
4039 | * this check would not make sense */ | ||
4040 | |||
4041 | if (in_dev->ifa_list->ifa_mask != 0xFFFFFFFF && | ||
4042 | (in_dev->ifa_list->ifa_mask & arphdr->ar_sip) != | ||
4043 | (in_dev->ifa_list->ifa_mask & in_dev->ifa_list->ifa_local)){ | ||
4044 | printk(KERN_INFO | ||
4045 | "%s: Invalid PtP address. %u.%u.%u.%u InARP ignored.\n", | ||
4046 | card->devname,NIPQUAD(arphdr->ar_sip)); | ||
4047 | |||
4048 | printk(KERN_INFO "%s: mask %u.%u.%u.%u\n", | ||
4049 | card->devname, NIPQUAD(in_dev->ifa_list->ifa_mask)); | ||
4050 | printk(KERN_INFO "%s: local %u.%u.%u.%u\n", | ||
4051 | card->devname,NIPQUAD(in_dev->ifa_list->ifa_local)); | ||
4052 | return -1; | ||
4053 | } | ||
4054 | |||
4055 | if (in_dev->ifa_list->ifa_local == arphdr->ar_sip){ | ||
4056 | printk(KERN_INFO | ||
4057 | "%s: Local addr = PtP addr. InARP ignored.\n", | ||
4058 | card->devname); | ||
4059 | return -1; | ||
4060 | } | ||
4061 | |||
4062 | arphdr->ar_op = htons(0x09); /* InARP Reply */ | ||
4063 | |||
4064 | /* Set addresses */ | ||
4065 | arphdr->ar_tip = arphdr->ar_sip; | ||
4066 | arphdr->ar_sip = in_dev->ifa_list->ifa_local; | ||
4067 | |||
4068 | chan->ip_local = in_dev->ifa_list->ifa_local; | ||
4069 | chan->ip_remote = arphdr->ar_sip; | ||
4070 | |||
4071 | fr_send(card, frbuf->dlci, 0, frbuf->length, (void *)ArpPacket); | ||
4072 | |||
4073 | if (test_bit(ARP_CRIT,&card->wandev.critical)){ | ||
4074 | if (net_ratelimit()){ | ||
4075 | printk(KERN_INFO "%s: ARP Processed Enabling Communication!\n", | ||
4076 | card->devname); | ||
4077 | } | ||
4078 | } | ||
4079 | clear_bit(ARP_CRIT,&card->wandev.critical); | ||
4080 | |||
4081 | chan->ip_local = in_dev->ifa_list->ifa_local; | ||
4082 | chan->ip_remote = arphdr->ar_sip; | ||
4083 | |||
4084 | /* Add Route Flag */ | ||
4085 | /* The route will be added in the polling routine so | ||
4086 | that it is not interrupt context. */ | ||
4087 | |||
4088 | chan->route_flag = ADD_ROUTE; | ||
4089 | trigger_fr_poll (dev); | ||
4090 | |||
4091 | break; | ||
4092 | |||
4093 | case 0x09: // Inverse ARP reply | ||
4094 | |||
4095 | /* Check for valid Address */ | ||
4096 | printk(KERN_INFO "%s: Recvd PtP addr %u.%u.%u.%u -InArp Reply\n", | ||
4097 | card->devname, NIPQUAD(arphdr->ar_sip)); | ||
4098 | |||
4099 | |||
4100 | /* Compare network addresses, only if network mask | ||
4101 | * is not 255.255.255.255 It would not make sense | ||
4102 | * to perform this test if the mask was all 1's */ | ||
4103 | |||
4104 | if (in_dev->ifa_list->ifa_mask != 0xffffffff && | ||
4105 | (in_dev->ifa_list->ifa_mask & arphdr->ar_sip) != | ||
4106 | (in_dev->ifa_list->ifa_mask & in_dev->ifa_list->ifa_local)) { | ||
4107 | |||
4108 | printk(KERN_INFO "%s: Invalid PtP address. InARP ignored.\n", | ||
4109 | card->devname); | ||
4110 | return -1; | ||
4111 | } | ||
4112 | |||
4113 | /* Make sure that the received IP address is not | ||
4114 | * the same as our own local address */ | ||
4115 | if (in_dev->ifa_list->ifa_local == arphdr->ar_sip) { | ||
4116 | printk(KERN_INFO "%s: Local addr = PtP addr. InARP ignored.\n", | ||
4117 | card->devname); | ||
4118 | return -1; | ||
4119 | } | ||
4120 | |||
4121 | chan->ip_local = in_dev->ifa_list->ifa_local; | ||
4122 | chan->ip_remote = arphdr->ar_sip; | ||
4123 | |||
4124 | /* Add Route Flag */ | ||
4125 | /* The route will be added in the polling routine so | ||
4126 | that it is not interrupt context. */ | ||
4127 | |||
4128 | chan->route_flag = ADD_ROUTE; | ||
4129 | chan->inarp = INARP_CONFIGURED; | ||
4130 | trigger_fr_poll(dev); | ||
4131 | |||
4132 | break; | ||
4133 | default: | ||
4134 | break; // ARP's and RARP's -- Shouldn't happen. | ||
4135 | } | ||
4136 | |||
4137 | return 0; | ||
4138 | } | ||
4139 | |||
4140 | |||
4141 | /*============================================================ | ||
4142 | * trigger_fr_arp | ||
4143 | * | ||
4144 | * Description: | ||
4145 | * Add an fr_arp() task into a arp | ||
4146 | * timer handler for a specific dlci/interface. | ||
4147 | * This will kick the fr_arp() routine | ||
4148 | * within the specified time interval. | ||
4149 | * | ||
4150 | * Usage: | ||
4151 | * This timer is used to send ARP requests at | ||
4152 | * certain time intervals. | ||
4153 | * Called by an interrupt to request an action | ||
4154 | * at a later date. | ||
4155 | */ | ||
4156 | |||
4157 | static void trigger_fr_arp(struct net_device *dev) | ||
4158 | { | ||
4159 | fr_channel_t* chan = dev->priv; | ||
4160 | |||
4161 | mod_timer(&chan->fr_arp_timer, jiffies + chan->inarp_interval * HZ); | ||
4162 | return; | ||
4163 | } | ||
4164 | |||
4165 | |||
4166 | |||
4167 | /*============================================================================== | ||
4168 | * ARP Request Action | ||
4169 | * | ||
4170 | * This funciton is called by timer interrupt to send an arp request | ||
4171 | * to the remote end. | ||
4172 | */ | ||
4173 | |||
4174 | static void fr_arp (unsigned long data) | ||
4175 | { | ||
4176 | struct net_device *dev = (struct net_device *)data; | ||
4177 | fr_channel_t *chan = dev->priv; | ||
4178 | volatile sdla_t *card = chan->card; | ||
4179 | fr508_flags_t* flags = card->flags; | ||
4180 | |||
4181 | /* Send ARP packets for all devs' until | ||
4182 | * ARP state changes to CONFIGURED */ | ||
4183 | |||
4184 | if (chan->inarp == INARP_REQUEST && | ||
4185 | chan->common.state == WAN_CONNECTED && | ||
4186 | card->wandev.state == WAN_CONNECTED){ | ||
4187 | set_bit(0,&chan->inarp_ready); | ||
4188 | card->u.f.timer_int_enabled |= TMR_INT_ENABLED_ARP; | ||
4189 | flags->imask |= FR_INTR_TIMER; | ||
4190 | } | ||
4191 | |||
4192 | return; | ||
4193 | } | ||
4194 | |||
4195 | |||
4196 | /*============================================================================== | ||
4197 | * Perform the Interrupt Test by running the READ_CODE_VERSION command MAX_INTR_ | ||
4198 | * TEST_COUNTER times. | ||
4199 | */ | ||
4200 | static int intr_test( sdla_t* card ) | ||
4201 | { | ||
4202 | fr_mbox_t* mb = card->mbox; | ||
4203 | int err,i; | ||
4204 | |||
4205 | err = fr_set_intr_mode(card, FR_INTR_READY, card->wandev.mtu, 0 ); | ||
4206 | |||
4207 | if (err == CMD_OK) { | ||
4208 | |||
4209 | for ( i = 0; i < MAX_INTR_TEST_COUNTER; i++ ) { | ||
4210 | /* Run command READ_CODE_VERSION */ | ||
4211 | mb->cmd.length = 0; | ||
4212 | mb->cmd.command = FR_READ_CODE_VERSION; | ||
4213 | err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; | ||
4214 | if (err != CMD_OK) | ||
4215 | fr_event(card, err, mb); | ||
4216 | } | ||
4217 | |||
4218 | } else { | ||
4219 | return err; | ||
4220 | } | ||
4221 | |||
4222 | err = fr_set_intr_mode( card, 0, card->wandev.mtu, 0 ); | ||
4223 | |||
4224 | if( err != CMD_OK ) | ||
4225 | return err; | ||
4226 | |||
4227 | return 0; | ||
4228 | } | ||
4229 | |||
4230 | /*============================================================================== | ||
4231 | * Determine what type of UDP call it is. FPIPE8ND ? | ||
4232 | */ | ||
4233 | static int udp_pkt_type( struct sk_buff *skb, sdla_t* card ) | ||
4234 | { | ||
4235 | fr_udp_pkt_t *fr_udp_pkt = (fr_udp_pkt_t *)skb->data; | ||
4236 | |||
4237 | /* Quick HACK */ | ||
4238 | |||
4239 | |||
4240 | if((fr_udp_pkt->ip_pkt.protocol == UDPMGMT_UDP_PROTOCOL) && | ||
4241 | (fr_udp_pkt->ip_pkt.ver_inet_hdr_length == 0x45) && | ||
4242 | (fr_udp_pkt->udp_pkt.udp_dst_port == | ||
4243 | ntohs(card->wandev.udp_port)) && | ||
4244 | (fr_udp_pkt->wp_mgmt.request_reply == | ||
4245 | UDPMGMT_REQUEST)) { | ||
4246 | if(!strncmp(fr_udp_pkt->wp_mgmt.signature, | ||
4247 | UDPMGMT_FPIPE_SIGNATURE, 8)){ | ||
4248 | return UDP_FPIPE_TYPE; | ||
4249 | } | ||
4250 | } | ||
4251 | return UDP_INVALID_TYPE; | ||
4252 | } | ||
4253 | |||
4254 | |||
4255 | /*============================================================================== | ||
4256 | * Initializes the Statistics values in the fr_channel structure. | ||
4257 | */ | ||
4258 | void init_chan_statistics( fr_channel_t* chan) | ||
4259 | { | ||
4260 | memset(&chan->drvstats_if_send.if_send_entry, 0, | ||
4261 | sizeof(if_send_stat_t)); | ||
4262 | memset(&chan->drvstats_rx_intr.rx_intr_no_socket, 0, | ||
4263 | sizeof(rx_intr_stat_t)); | ||
4264 | memset(&chan->drvstats_gen.UDP_PIPE_mgmt_kmalloc_err, 0, | ||
4265 | sizeof(pipe_mgmt_stat_t)); | ||
4266 | } | ||
4267 | |||
4268 | /*============================================================================== | ||
4269 | * Initializes the Statistics values in the Sdla_t structure. | ||
4270 | */ | ||
4271 | void init_global_statistics( sdla_t* card ) | ||
4272 | { | ||
4273 | /* Intialize global statistics for a card */ | ||
4274 | memset(&card->statistics.isr_entry, 0, sizeof(global_stats_t)); | ||
4275 | } | ||
4276 | |||
4277 | static void read_DLCI_IB_mapping( sdla_t* card, fr_channel_t* chan ) | ||
4278 | { | ||
4279 | fr_mbox_t* mbox = card->mbox; | ||
4280 | int retry = MAX_CMD_RETRY; | ||
4281 | dlci_IB_mapping_t* result; | ||
4282 | int err, counter, found; | ||
4283 | |||
4284 | do { | ||
4285 | mbox->cmd.command = FR_READ_DLCI_IB_MAPPING; | ||
4286 | mbox->cmd.length = 0; | ||
4287 | err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; | ||
4288 | } while (err && retry-- && fr_event(card, err, mbox)); | ||
4289 | |||
4290 | if( mbox->cmd.result != 0){ | ||
4291 | printk(KERN_INFO "%s: Read DLCI IB Mapping failed\n", | ||
4292 | chan->name); | ||
4293 | } | ||
4294 | |||
4295 | counter = mbox->cmd.length / sizeof(dlci_IB_mapping_t); | ||
4296 | result = (void *)mbox->data; | ||
4297 | |||
4298 | found = 0; | ||
4299 | for (; counter; --counter, ++result) { | ||
4300 | if ( result->dlci == chan->dlci ) { | ||
4301 | chan->IB_addr = result->addr_value; | ||
4302 | if(card->hw.type == SDLA_S514){ | ||
4303 | chan->dlci_int_interface = | ||
4304 | (void*)(card->hw.dpmbase + | ||
4305 | chan->IB_addr); | ||
4306 | }else{ | ||
4307 | chan->dlci_int_interface = | ||
4308 | (void*)(card->hw.dpmbase + | ||
4309 | (chan->IB_addr & 0x00001FFF)); | ||
4310 | |||
4311 | } | ||
4312 | found = 1; | ||
4313 | break; | ||
4314 | } | ||
4315 | } | ||
4316 | if (!found) | ||
4317 | printk( KERN_INFO "%s: DLCI %d not found by IB MAPPING cmd\n", | ||
4318 | card->devname, chan->dlci); | ||
4319 | } | ||
4320 | |||
4321 | |||
4322 | |||
4323 | void s508_s514_lock(sdla_t *card, unsigned long *smp_flags) | ||
4324 | { | ||
4325 | if (card->hw.type != SDLA_S514){ | ||
4326 | |||
4327 | spin_lock_irqsave(&card->wandev.lock, *smp_flags); | ||
4328 | }else{ | ||
4329 | spin_lock(&card->u.f.if_send_lock); | ||
4330 | } | ||
4331 | return; | ||
4332 | } | ||
4333 | |||
4334 | |||
4335 | void s508_s514_unlock(sdla_t *card, unsigned long *smp_flags) | ||
4336 | { | ||
4337 | if (card->hw.type != SDLA_S514){ | ||
4338 | |||
4339 | spin_unlock_irqrestore (&card->wandev.lock, *smp_flags); | ||
4340 | }else{ | ||
4341 | spin_unlock(&card->u.f.if_send_lock); | ||
4342 | } | ||
4343 | return; | ||
4344 | } | ||
4345 | |||
4346 | |||
4347 | |||
4348 | /*---------------------------------------------------------------------- | ||
4349 | RECEIVE INTERRUPT: BOTTOM HALF HANDLERS | ||
4350 | ----------------------------------------------------------------------*/ | ||
4351 | |||
4352 | |||
4353 | /*======================================================== | ||
4354 | * bh_enqueue | ||
4355 | * | ||
4356 | * Description: | ||
4357 | * Insert a received packet into a circular | ||
4358 | * rx queue. This packet will be picked up | ||
4359 | * by fr_bh() and sent up the stack to the | ||
4360 | * user. | ||
4361 | * | ||
4362 | * Usage: | ||
4363 | * This function is called by rx interrupt, | ||
4364 | * in API mode. | ||
4365 | * | ||
4366 | */ | ||
4367 | |||
4368 | static int bh_enqueue(struct net_device *dev, struct sk_buff *skb) | ||
4369 | { | ||
4370 | /* Check for full */ | ||
4371 | fr_channel_t* chan = dev->priv; | ||
4372 | sdla_t *card = chan->card; | ||
4373 | |||
4374 | |||
4375 | if (atomic_read(&chan->bh_buff_used) == MAX_BH_BUFF){ | ||
4376 | ++card->wandev.stats.rx_dropped; | ||
4377 | dev_kfree_skb_any(skb); | ||
4378 | return 1; | ||
4379 | } | ||
4380 | |||
4381 | ((bh_data_t *)&chan->bh_head[chan->bh_write])->skb = skb; | ||
4382 | |||
4383 | if (chan->bh_write == (MAX_BH_BUFF-1)){ | ||
4384 | chan->bh_write=0; | ||
4385 | }else{ | ||
4386 | ++chan->bh_write; | ||
4387 | } | ||
4388 | |||
4389 | atomic_inc(&chan->bh_buff_used); | ||
4390 | |||
4391 | return 0; | ||
4392 | } | ||
4393 | |||
4394 | |||
4395 | /*======================================================== | ||
4396 | * trigger_fr_bh | ||
4397 | * | ||
4398 | * Description: | ||
4399 | * Kick the fr_bh() handler | ||
4400 | * | ||
4401 | * Usage: | ||
4402 | * rx interrupt calls this function during | ||
4403 | * the API mode. | ||
4404 | */ | ||
4405 | |||
4406 | static void trigger_fr_bh (fr_channel_t *chan) | ||
4407 | { | ||
4408 | if (!test_and_set_bit(0,&chan->tq_working)){ | ||
4409 | wanpipe_queue_work(&chan->common.wanpipe_work); | ||
4410 | } | ||
4411 | } | ||
4412 | |||
4413 | |||
4414 | /*======================================================== | ||
4415 | * fr_bh | ||
4416 | * | ||
4417 | * Description: | ||
4418 | * Frame relay receive BH handler. | ||
4419 | * Dequeue data from the BH circular | ||
4420 | * buffer and pass it up the API sock. | ||
4421 | * | ||
4422 | * Rationale: | ||
4423 | * This fuction is used to offload the | ||
4424 | * rx_interrupt during API operation mode. | ||
4425 | * The fr_bh() function executes for each | ||
4426 | * dlci/interface. | ||
4427 | * | ||
4428 | * Once receive interrupt copies data from the | ||
4429 | * card into an skb buffer, the skb buffer | ||
4430 | * is appended to a circular BH buffer. | ||
4431 | * Then the interrupt kicks fr_bh() to finish the | ||
4432 | * job at a later time (not within the interrupt). | ||
4433 | * | ||
4434 | * Usage: | ||
4435 | * Interrupts use this to defer a task to | ||
4436 | * a polling routine. | ||
4437 | * | ||
4438 | */ | ||
4439 | |||
4440 | static void fr_bh(struct net_device * dev) | ||
4441 | { | ||
4442 | fr_channel_t* chan = dev->priv; | ||
4443 | sdla_t *card = chan->card; | ||
4444 | struct sk_buff *skb; | ||
4445 | |||
4446 | if (atomic_read(&chan->bh_buff_used) == 0){ | ||
4447 | clear_bit(0, &chan->tq_working); | ||
4448 | return; | ||
4449 | } | ||
4450 | |||
4451 | while (atomic_read(&chan->bh_buff_used)){ | ||
4452 | |||
4453 | if (chan->common.sk == NULL || chan->common.func == NULL){ | ||
4454 | clear_bit(0, &chan->tq_working); | ||
4455 | return; | ||
4456 | } | ||
4457 | |||
4458 | skb = ((bh_data_t *)&chan->bh_head[chan->bh_read])->skb; | ||
4459 | |||
4460 | if (skb != NULL){ | ||
4461 | |||
4462 | if (chan->common.sk == NULL || chan->common.func == NULL){ | ||
4463 | ++card->wandev.stats.rx_dropped; | ||
4464 | ++chan->ifstats.rx_dropped; | ||
4465 | dev_kfree_skb_any(skb); | ||
4466 | fr_bh_cleanup(dev); | ||
4467 | continue; | ||
4468 | } | ||
4469 | |||
4470 | if (chan->common.func(skb,dev,chan->common.sk) != 0){ | ||
4471 | /* Sock full cannot send, queue us for | ||
4472 | * another try */ | ||
4473 | atomic_set(&chan->common.receive_block,1); | ||
4474 | return; | ||
4475 | }else{ | ||
4476 | fr_bh_cleanup(dev); | ||
4477 | } | ||
4478 | }else{ | ||
4479 | fr_bh_cleanup(dev); | ||
4480 | } | ||
4481 | } | ||
4482 | clear_bit(0, &chan->tq_working); | ||
4483 | |||
4484 | return; | ||
4485 | } | ||
4486 | |||
4487 | static int fr_bh_cleanup(struct net_device *dev) | ||
4488 | { | ||
4489 | fr_channel_t* chan = dev->priv; | ||
4490 | |||
4491 | ((bh_data_t *)&chan->bh_head[chan->bh_read])->skb = NULL; | ||
4492 | |||
4493 | if (chan->bh_read == (MAX_BH_BUFF-1)){ | ||
4494 | chan->bh_read=0; | ||
4495 | }else{ | ||
4496 | ++chan->bh_read; | ||
4497 | } | ||
4498 | |||
4499 | atomic_dec(&chan->bh_buff_used); | ||
4500 | return 0; | ||
4501 | } | ||
4502 | |||
4503 | |||
4504 | /*---------------------------------------------------------------------- | ||
4505 | POLL BH HANDLERS AND KICK ROUTINES | ||
4506 | ----------------------------------------------------------------------*/ | ||
4507 | |||
4508 | /*============================================================ | ||
4509 | * trigger_fr_poll | ||
4510 | * | ||
4511 | * Description: | ||
4512 | * Add a fr_poll() task into a tq_scheduler bh handler | ||
4513 | * for a specific dlci/interface. This will kick | ||
4514 | * the fr_poll() routine at a later time. | ||
4515 | * | ||
4516 | * Usage: | ||
4517 | * Interrupts use this to defer a taks to | ||
4518 | * a polling routine. | ||
4519 | * | ||
4520 | */ | ||
4521 | static void trigger_fr_poll(struct net_device *dev) | ||
4522 | { | ||
4523 | fr_channel_t* chan = dev->priv; | ||
4524 | schedule_work(&chan->fr_poll_work); | ||
4525 | return; | ||
4526 | } | ||
4527 | |||
4528 | |||
4529 | /*============================================================ | ||
4530 | * fr_poll | ||
4531 | * | ||
4532 | * Rationale: | ||
4533 | * We cannot manipulate the routing tables, or | ||
4534 | * ip addresses withing the interrupt. Therefore | ||
4535 | * we must perform such actons outside an interrupt | ||
4536 | * at a later time. | ||
4537 | * | ||
4538 | * Description: | ||
4539 | * Frame relay polling routine, responsible for | ||
4540 | * shutting down interfaces upon disconnect | ||
4541 | * and adding/removing routes. | ||
4542 | * | ||
4543 | * Usage: | ||
4544 | * This function is executed for each frame relay | ||
4545 | * dlci/interface through a tq_schedule bottom half. | ||
4546 | * | ||
4547 | * trigger_fr_poll() function is used to kick | ||
4548 | * the fr_poll routine. | ||
4549 | */ | ||
4550 | |||
4551 | static void fr_poll(struct net_device *dev) | ||
4552 | { | ||
4553 | |||
4554 | fr_channel_t* chan; | ||
4555 | sdla_t *card; | ||
4556 | u8 check_gateway=0; | ||
4557 | |||
4558 | if (!dev || (chan = dev->priv) == NULL) | ||
4559 | return; | ||
4560 | |||
4561 | card = chan->card; | ||
4562 | |||
4563 | /* (Re)Configuraiton is in progress, stop what you are | ||
4564 | * doing and get out */ | ||
4565 | if (test_bit(PERI_CRIT,&card->wandev.critical)){ | ||
4566 | return; | ||
4567 | } | ||
4568 | |||
4569 | switch (chan->common.state){ | ||
4570 | |||
4571 | case WAN_DISCONNECTED: | ||
4572 | |||
4573 | if (test_bit(DYN_OPT_ON,&chan->interface_down) && | ||
4574 | !test_bit(DEV_DOWN, &chan->interface_down) && | ||
4575 | dev->flags&IFF_UP){ | ||
4576 | |||
4577 | printk(KERN_INFO "%s: Interface %s is Down.\n", | ||
4578 | card->devname,dev->name); | ||
4579 | change_dev_flags(dev,dev->flags&~IFF_UP); | ||
4580 | set_bit(DEV_DOWN, &chan->interface_down); | ||
4581 | chan->route_flag = NO_ROUTE; | ||
4582 | |||
4583 | }else{ | ||
4584 | if (chan->inarp != INARP_NONE) | ||
4585 | process_route(dev); | ||
4586 | } | ||
4587 | break; | ||
4588 | |||
4589 | case WAN_CONNECTED: | ||
4590 | |||
4591 | if (test_bit(DYN_OPT_ON,&chan->interface_down) && | ||
4592 | test_bit(DEV_DOWN, &chan->interface_down) && | ||
4593 | !(dev->flags&IFF_UP)){ | ||
4594 | |||
4595 | printk(KERN_INFO "%s: Interface %s is Up.\n", | ||
4596 | card->devname,dev->name); | ||
4597 | |||
4598 | change_dev_flags(dev,dev->flags|IFF_UP); | ||
4599 | clear_bit(DEV_DOWN, &chan->interface_down); | ||
4600 | check_gateway=1; | ||
4601 | } | ||
4602 | |||
4603 | if (chan->inarp != INARP_NONE){ | ||
4604 | process_route(dev); | ||
4605 | check_gateway=1; | ||
4606 | } | ||
4607 | |||
4608 | if (chan->gateway && check_gateway) | ||
4609 | add_gateway(card,dev); | ||
4610 | |||
4611 | break; | ||
4612 | |||
4613 | } | ||
4614 | |||
4615 | return; | ||
4616 | } | ||
4617 | |||
4618 | /*============================================================== | ||
4619 | * check_tx_status | ||
4620 | * | ||
4621 | * Rationale: | ||
4622 | * We cannot transmit from an interrupt while | ||
4623 | * the if_send is transmitting data. Therefore, | ||
4624 | * we must check whether the tx buffers are | ||
4625 | * begin used, before we transmit from an | ||
4626 | * interrupt. | ||
4627 | * | ||
4628 | * Description: | ||
4629 | * Checks whether it's safe to use the transmit | ||
4630 | * buffers. | ||
4631 | * | ||
4632 | * Usage: | ||
4633 | * ARP and UDP handling routines use this function | ||
4634 | * because, they need to transmit data during | ||
4635 | * an interrupt. | ||
4636 | */ | ||
4637 | |||
4638 | static int check_tx_status(sdla_t *card, struct net_device *dev) | ||
4639 | { | ||
4640 | |||
4641 | if (card->hw.type == SDLA_S514){ | ||
4642 | if (test_bit(SEND_CRIT, (void*)&card->wandev.critical) || | ||
4643 | test_bit(SEND_TXIRQ_CRIT, (void*)&card->wandev.critical)) { | ||
4644 | return 1; | ||
4645 | } | ||
4646 | } | ||
4647 | |||
4648 | if (netif_queue_stopped(dev) || (card->u.f.tx_interrupts_pending)) | ||
4649 | return 1; | ||
4650 | |||
4651 | return 0; | ||
4652 | } | ||
4653 | |||
4654 | /*=============================================================== | ||
4655 | * move_dev_to_next | ||
4656 | * | ||
4657 | * Description: | ||
4658 | * Move the dev pointer to the next location in the | ||
4659 | * link list. Check if we are at the end of the | ||
4660 | * list, if so start from the begining. | ||
4661 | * | ||
4662 | * Usage: | ||
4663 | * Timer interrupt uses this function to efficiently | ||
4664 | * step through the devices that need to send ARP data. | ||
4665 | * | ||
4666 | */ | ||
4667 | |||
4668 | struct net_device *move_dev_to_next(sdla_t *card, struct net_device *dev) | ||
4669 | { | ||
4670 | if (card->wandev.new_if_cnt != 1){ | ||
4671 | if (!*((struct net_device **)dev->priv)) | ||
4672 | return card->wandev.dev; | ||
4673 | else | ||
4674 | return *((struct net_device **)dev->priv); | ||
4675 | } | ||
4676 | return dev; | ||
4677 | } | ||
4678 | |||
4679 | /*============================================================== | ||
4680 | * trigger_config_fr | ||
4681 | * | ||
4682 | * Rationale: | ||
4683 | * All commands must be performed inside of a | ||
4684 | * interrupt. | ||
4685 | * | ||
4686 | * Description: | ||
4687 | * Kick the config_fr() routine throught the | ||
4688 | * timer interrupt. | ||
4689 | */ | ||
4690 | |||
4691 | |||
4692 | static void trigger_config_fr (sdla_t *card) | ||
4693 | { | ||
4694 | fr508_flags_t* flags = card->flags; | ||
4695 | |||
4696 | card->u.f.timer_int_enabled |= TMR_INT_ENABLED_CONFIG; | ||
4697 | flags->imask |= FR_INTR_TIMER; | ||
4698 | } | ||
4699 | |||
4700 | |||
4701 | /*============================================================== | ||
4702 | * config_fr | ||
4703 | * | ||
4704 | * Rationale: | ||
4705 | * All commands must be performed inside of a | ||
4706 | * interrupt. | ||
4707 | & | ||
4708 | * Description: | ||
4709 | * Configure a DLCI. This function is executed | ||
4710 | * by a timer_interrupt. The if_open() function | ||
4711 | * triggers it. | ||
4712 | * | ||
4713 | * Usage: | ||
4714 | * new_if() collects all data necessary to | ||
4715 | * configure the DLCI. It sets the chan->dlci_ready | ||
4716 | * bit. When the if_open() function is executed | ||
4717 | * it checks this bit, and if its set it triggers | ||
4718 | * the timer interrupt to execute the config_fr() | ||
4719 | * function. | ||
4720 | */ | ||
4721 | |||
4722 | static void config_fr (sdla_t *card) | ||
4723 | { | ||
4724 | struct net_device *dev; | ||
4725 | fr_channel_t *chan; | ||
4726 | |||
4727 | for (dev = card->wandev.dev; dev; | ||
4728 | dev = *((struct net_device **)dev->priv)) { | ||
4729 | |||
4730 | if ((chan=dev->priv) == NULL) | ||
4731 | continue; | ||
4732 | |||
4733 | if (!test_bit(0,&chan->config_dlci)) | ||
4734 | continue; | ||
4735 | |||
4736 | clear_bit(0,&chan->config_dlci); | ||
4737 | |||
4738 | /* If signalling is set to NO, then setup | ||
4739 | * DLCI addresses right away. Don't have to wait for | ||
4740 | * link to connect. | ||
4741 | */ | ||
4742 | if (card->wandev.signalling == WANOPT_NO){ | ||
4743 | printk(KERN_INFO "%s: Signalling set to NO: Mapping DLCI's\n", | ||
4744 | card->wandev.name); | ||
4745 | if (fr_init_dlci(card,chan)){ | ||
4746 | printk(KERN_INFO "%s: ERROR: Failed to configure DLCI %i !\n", | ||
4747 | card->devname, chan->dlci); | ||
4748 | return; | ||
4749 | } | ||
4750 | } | ||
4751 | |||
4752 | if (card->wandev.station == WANOPT_CPE) { | ||
4753 | |||
4754 | update_chan_state(dev); | ||
4755 | |||
4756 | /* CPE: issue full status enquiry */ | ||
4757 | fr_issue_isf(card, FR_ISF_FSE); | ||
4758 | |||
4759 | } else { | ||
4760 | /* FR switch: activate DLCI(s) */ | ||
4761 | |||
4762 | /* For Switch emulation we have to ADD and ACTIVATE | ||
4763 | * the DLCI(s) that were configured with the SET_DLCI_ | ||
4764 | * CONFIGURATION command. Add and Activate will fail if | ||
4765 | * DLCI specified is not included in the list. | ||
4766 | * | ||
4767 | * Also If_open is called once for each interface. But | ||
4768 | * it does not get in here for all the interface. So | ||
4769 | * we have to pass the entire list of DLCI(s) to add | ||
4770 | * activate routines. | ||
4771 | */ | ||
4772 | |||
4773 | if (!check_dlci_config (card, chan)){ | ||
4774 | fr_add_dlci(card, chan->dlci); | ||
4775 | fr_activate_dlci(card, chan->dlci); | ||
4776 | } | ||
4777 | } | ||
4778 | |||
4779 | card->u.f.dlci_to_dev_map[chan->dlci] = dev; | ||
4780 | } | ||
4781 | return; | ||
4782 | } | ||
4783 | |||
4784 | |||
4785 | /*============================================================== | ||
4786 | * config_fr | ||
4787 | * | ||
4788 | * Rationale: | ||
4789 | * All commands must be executed during an interrupt. | ||
4790 | * | ||
4791 | * Description: | ||
4792 | * Trigger uncofig_fr() function through | ||
4793 | * the timer interrupt. | ||
4794 | * | ||
4795 | */ | ||
4796 | |||
4797 | static void trigger_unconfig_fr(struct net_device *dev) | ||
4798 | { | ||
4799 | fr_channel_t *chan = dev->priv; | ||
4800 | volatile sdla_t *card = chan->card; | ||
4801 | unsigned long timeout; | ||
4802 | fr508_flags_t* flags = card->flags; | ||
4803 | int reset_critical=0; | ||
4804 | |||
4805 | if (test_bit(PERI_CRIT,(void*)&card->wandev.critical)){ | ||
4806 | clear_bit(PERI_CRIT,(void*)&card->wandev.critical); | ||
4807 | reset_critical=1; | ||
4808 | } | ||
4809 | |||
4810 | /* run unconfig_dlci() function | ||
4811 | * throught the timer interrupt */ | ||
4812 | set_bit(0,(void*)&chan->unconfig_dlci); | ||
4813 | card->u.f.timer_int_enabled |= TMR_INT_ENABLED_UNCONFIG; | ||
4814 | flags->imask |= FR_INTR_TIMER; | ||
4815 | |||
4816 | /* Wait for the command to complete */ | ||
4817 | timeout = jiffies; | ||
4818 | for(;;) { | ||
4819 | |||
4820 | if(!(card->u.f.timer_int_enabled & TMR_INT_ENABLED_UNCONFIG)) | ||
4821 | break; | ||
4822 | |||
4823 | if (time_after(jiffies, timeout + 1 * HZ)){ | ||
4824 | card->u.f.timer_int_enabled &= ~TMR_INT_ENABLED_UNCONFIG; | ||
4825 | printk(KERN_INFO "%s: Failed to delete DLCI %i\n", | ||
4826 | card->devname,chan->dlci); | ||
4827 | break; | ||
4828 | } | ||
4829 | } | ||
4830 | |||
4831 | if (reset_critical){ | ||
4832 | set_bit(PERI_CRIT,(void*)&card->wandev.critical); | ||
4833 | } | ||
4834 | } | ||
4835 | |||
4836 | /*============================================================== | ||
4837 | * unconfig_fr | ||
4838 | * | ||
4839 | * Rationale: | ||
4840 | * All commands must be executed during an interrupt. | ||
4841 | * | ||
4842 | * Description: | ||
4843 | * Remove the dlci from firmware. | ||
4844 | * This funciton is used in NODE shutdown. | ||
4845 | */ | ||
4846 | |||
4847 | static void unconfig_fr (sdla_t *card) | ||
4848 | { | ||
4849 | struct net_device *dev; | ||
4850 | fr_channel_t *chan; | ||
4851 | |||
4852 | for (dev = card->wandev.dev; dev; | ||
4853 | dev = *((struct net_device **)dev->priv)){ | ||
4854 | |||
4855 | if ((chan=dev->priv) == NULL) | ||
4856 | continue; | ||
4857 | |||
4858 | if (!test_bit(0,&chan->unconfig_dlci)) | ||
4859 | continue; | ||
4860 | |||
4861 | clear_bit(0,&chan->unconfig_dlci); | ||
4862 | |||
4863 | if (card->wandev.station == WANOPT_NODE){ | ||
4864 | printk(KERN_INFO "%s: Unconfiguring DLCI %i\n", | ||
4865 | card->devname,chan->dlci); | ||
4866 | fr_delete_dlci(card,chan->dlci); | ||
4867 | } | ||
4868 | card->u.f.dlci_to_dev_map[chan->dlci] = NULL; | ||
4869 | } | ||
4870 | } | ||
4871 | |||
4872 | static int setup_fr_header(struct sk_buff *skb, struct net_device* dev, | ||
4873 | char op_mode) | ||
4874 | { | ||
4875 | fr_channel_t *chan=dev->priv; | ||
4876 | |||
4877 | if (op_mode == WANPIPE) { | ||
4878 | chan->fr_header[0]=Q922_UI; | ||
4879 | |||
4880 | switch (htons(skb->protocol)){ | ||
4881 | case ETH_P_IP: | ||
4882 | chan->fr_header[1]=NLPID_IP; | ||
4883 | break; | ||
4884 | default: | ||
4885 | return -EINVAL; | ||
4886 | } | ||
4887 | |||
4888 | return 2; | ||
4889 | } | ||
4890 | |||
4891 | /* If we are in bridging mode, we must apply | ||
4892 | * an Ethernet header | ||
4893 | */ | ||
4894 | if (op_mode == BRIDGE || op_mode == BRIDGE_NODE) { | ||
4895 | /* Encapsulate the packet as a bridged Ethernet frame. */ | ||
4896 | #ifdef DEBUG | ||
4897 | printk(KERN_INFO "%s: encapsulating skb for frame relay\n", | ||
4898 | dev->name); | ||
4899 | #endif | ||
4900 | chan->fr_header[0] = 0x03; | ||
4901 | chan->fr_header[1] = 0x00; | ||
4902 | chan->fr_header[2] = 0x80; | ||
4903 | chan->fr_header[3] = 0x00; | ||
4904 | chan->fr_header[4] = 0x80; | ||
4905 | chan->fr_header[5] = 0xC2; | ||
4906 | chan->fr_header[6] = 0x00; | ||
4907 | chan->fr_header[7] = 0x07; | ||
4908 | |||
4909 | /* Yuck. */ | ||
4910 | skb->protocol = ETH_P_802_3; | ||
4911 | return 8; | ||
4912 | } | ||
4913 | |||
4914 | return 0; | ||
4915 | } | ||
4916 | |||
4917 | |||
4918 | static int check_dlci_config (sdla_t *card, fr_channel_t *chan) | ||
4919 | { | ||
4920 | fr_mbox_t* mbox = card->mbox; | ||
4921 | int err=0; | ||
4922 | fr_conf_t *conf=NULL; | ||
4923 | unsigned short dlci_num = chan->dlci; | ||
4924 | int dlci_offset=0; | ||
4925 | struct net_device *dev = NULL; | ||
4926 | |||
4927 | mbox->cmd.command = FR_READ_CONFIG; | ||
4928 | mbox->cmd.length = 0; | ||
4929 | mbox->cmd.dlci = dlci_num; | ||
4930 | |||
4931 | err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; | ||
4932 | |||
4933 | if (err == CMD_OK){ | ||
4934 | return 0; | ||
4935 | } | ||
4936 | |||
4937 | for (dev = card->wandev.dev; dev; | ||
4938 | dev=*((struct net_device **)dev->priv)) | ||
4939 | set_chan_state(dev,WAN_DISCONNECTED); | ||
4940 | |||
4941 | printk(KERN_INFO "DLCI %i Not configured, configuring\n",dlci_num); | ||
4942 | |||
4943 | mbox->cmd.command = FR_COMM_DISABLE; | ||
4944 | mbox->cmd.length = 0; | ||
4945 | err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; | ||
4946 | if (err != CMD_OK){ | ||
4947 | fr_event(card, err, mbox); | ||
4948 | return 2; | ||
4949 | } | ||
4950 | |||
4951 | printk(KERN_INFO "Disabled Communications \n"); | ||
4952 | |||
4953 | mbox->cmd.command = FR_READ_CONFIG; | ||
4954 | mbox->cmd.length = 0; | ||
4955 | mbox->cmd.dlci = 0; | ||
4956 | |||
4957 | err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; | ||
4958 | |||
4959 | if (err != CMD_OK){ | ||
4960 | fr_event(card, err, mbox); | ||
4961 | return 2; | ||
4962 | } | ||
4963 | |||
4964 | conf = (fr_conf_t *)mbox->data; | ||
4965 | |||
4966 | dlci_offset=0; | ||
4967 | for (dev = card->wandev.dev; dev; | ||
4968 | dev = *((struct net_device **)dev->priv)) { | ||
4969 | fr_channel_t *chan_tmp = dev->priv; | ||
4970 | conf->dlci[dlci_offset] = chan_tmp->dlci; | ||
4971 | dlci_offset++; | ||
4972 | } | ||
4973 | |||
4974 | printk(KERN_INFO "Got Fr configuration Buffer Length is %x Dlci %i Dlci Off %i\n", | ||
4975 | mbox->cmd.length, | ||
4976 | mbox->cmd.length > 0x20 ? conf->dlci[0] : -1, | ||
4977 | dlci_offset ); | ||
4978 | |||
4979 | mbox->cmd.length = 0x20 + dlci_offset*2; | ||
4980 | |||
4981 | mbox->cmd.command = FR_SET_CONFIG; | ||
4982 | mbox->cmd.dlci = 0; | ||
4983 | |||
4984 | err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; | ||
4985 | |||
4986 | if (err != CMD_OK){ | ||
4987 | fr_event(card, err, mbox); | ||
4988 | return 2; | ||
4989 | } | ||
4990 | |||
4991 | initialize_rx_tx_buffers (card); | ||
4992 | |||
4993 | |||
4994 | printk(KERN_INFO "Configuraiton Succeded for new DLCI %i\n",dlci_num); | ||
4995 | |||
4996 | if (fr_comm_enable (card)){ | ||
4997 | return 2; | ||
4998 | } | ||
4999 | |||
5000 | printk(KERN_INFO "Enabling Communications \n"); | ||
5001 | |||
5002 | for (dev = card->wandev.dev; dev; | ||
5003 | dev = *((struct net_device **)dev->priv)) { | ||
5004 | fr_channel_t *chan_tmp = dev->priv; | ||
5005 | fr_init_dlci(card,chan_tmp); | ||
5006 | fr_add_dlci(card, chan_tmp->dlci); | ||
5007 | fr_activate_dlci(card, chan_tmp->dlci); | ||
5008 | } | ||
5009 | |||
5010 | printk(KERN_INFO "END OF CONFIGURAITON %i\n",dlci_num); | ||
5011 | |||
5012 | return 1; | ||
5013 | } | ||
5014 | |||
5015 | static void initialize_rx_tx_buffers (sdla_t *card) | ||
5016 | { | ||
5017 | fr_buf_info_t* buf_info; | ||
5018 | |||
5019 | if (card->hw.type == SDLA_S514) { | ||
5020 | |||
5021 | buf_info = (void*)(card->hw.dpmbase + FR_MB_VECTOR + | ||
5022 | FR508_RXBC_OFFS); | ||
5023 | |||
5024 | card->rxmb = (void*)(buf_info->rse_next + card->hw.dpmbase); | ||
5025 | |||
5026 | card->u.f.rxmb_base = | ||
5027 | (void*)(buf_info->rse_base + card->hw.dpmbase); | ||
5028 | |||
5029 | card->u.f.rxmb_last = | ||
5030 | (void*)(buf_info->rse_base + | ||
5031 | (buf_info->rse_num - 1) * sizeof(fr_rx_buf_ctl_t) + | ||
5032 | card->hw.dpmbase); | ||
5033 | }else{ | ||
5034 | buf_info = (void*)(card->hw.dpmbase + FR508_RXBC_OFFS); | ||
5035 | |||
5036 | card->rxmb = (void*)(buf_info->rse_next - | ||
5037 | FR_MB_VECTOR + card->hw.dpmbase); | ||
5038 | |||
5039 | card->u.f.rxmb_base = | ||
5040 | (void*)(buf_info->rse_base - | ||
5041 | FR_MB_VECTOR + card->hw.dpmbase); | ||
5042 | |||
5043 | card->u.f.rxmb_last = | ||
5044 | (void*)(buf_info->rse_base + | ||
5045 | (buf_info->rse_num - 1) * sizeof(fr_rx_buf_ctl_t) - | ||
5046 | FR_MB_VECTOR + card->hw.dpmbase); | ||
5047 | } | ||
5048 | |||
5049 | card->u.f.rx_base = buf_info->buf_base; | ||
5050 | card->u.f.rx_top = buf_info->buf_top; | ||
5051 | |||
5052 | card->u.f.tx_interrupts_pending = 0; | ||
5053 | |||
5054 | return; | ||
5055 | } | ||
5056 | |||
5057 | |||
5058 | |||
5059 | MODULE_LICENSE("GPL"); | ||
5060 | |||
5061 | /****** End *****************************************************************/ | ||
diff --git a/drivers/net/wan/sdla_ft1.c b/drivers/net/wan/sdla_ft1.c deleted file mode 100644 index 9d6528a50f7b..000000000000 --- a/drivers/net/wan/sdla_ft1.c +++ /dev/null | |||
@@ -1,345 +0,0 @@ | |||
1 | /***************************************************************************** | ||
2 | * sdla_chdlc.c WANPIPE(tm) Multiprotocol WAN Link Driver. Cisco HDLC module. | ||
3 | * | ||
4 | * Authors: Nenad Corbic <ncorbic@sangoma.com> | ||
5 | * Gideon Hack | ||
6 | * | ||
7 | * Copyright: (c) 1995-1999 Sangoma Technologies Inc. | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or | ||
10 | * modify it under the terms of the GNU General Public License | ||
11 | * as published by the Free Software Foundation; either version | ||
12 | * 2 of the License, or (at your option) any later version. | ||
13 | * ============================================================================ | ||
14 | * Sep 30, 1999 Nenad Corbic Fixed dynamic IP and route setup. | ||
15 | * Sep 23, 1999 Nenad Corbic Added SMP support, fixed tracing | ||
16 | * Sep 13, 1999 Nenad Corbic Split up Port 0 and 1 into separate devices. | ||
17 | * Jun 02, 1999 Gideon Hack Added support for the S514 adapter. | ||
18 | * Oct 30, 1998 Jaspreet Singh Added Support for CHDLC API (HDLC STREAMING). | ||
19 | * Oct 28, 1998 Jaspreet Singh Added Support for Dual Port CHDLC. | ||
20 | * Aug 07, 1998 David Fong Initial version. | ||
21 | *****************************************************************************/ | ||
22 | |||
23 | #include <linux/module.h> | ||
24 | #include <linux/kernel.h> /* printk(), and other useful stuff */ | ||
25 | #include <linux/stddef.h> /* offsetof(), etc. */ | ||
26 | #include <linux/errno.h> /* return codes */ | ||
27 | #include <linux/string.h> /* inline memset(), etc. */ | ||
28 | #include <linux/slab.h> /* kmalloc(), kfree() */ | ||
29 | #include <linux/wanrouter.h> /* WAN router definitions */ | ||
30 | #include <linux/wanpipe.h> /* WANPIPE common user API definitions */ | ||
31 | #include <linux/if_arp.h> /* ARPHRD_* defines */ | ||
32 | #include <linux/jiffies.h> /* time_after() macro */ | ||
33 | |||
34 | #include <linux/inetdevice.h> | ||
35 | #include <asm/uaccess.h> | ||
36 | |||
37 | #include <linux/in.h> /* sockaddr_in */ | ||
38 | #include <linux/inet.h> | ||
39 | #include <linux/if.h> | ||
40 | #include <asm/byteorder.h> /* htons(), etc. */ | ||
41 | #include <linux/sdlapci.h> | ||
42 | #include <asm/io.h> | ||
43 | |||
44 | #include <linux/sdla_chdlc.h> /* CHDLC firmware API definitions */ | ||
45 | |||
46 | /****** Defines & Macros ****************************************************/ | ||
47 | |||
48 | /* reasons for enabling the timer interrupt on the adapter */ | ||
49 | #define TMR_INT_ENABLED_UDP 0x0001 | ||
50 | #define TMR_INT_ENABLED_UPDATE 0x0002 | ||
51 | |||
52 | #define CHDLC_DFLT_DATA_LEN 1500 /* default MTU */ | ||
53 | #define CHDLC_HDR_LEN 1 | ||
54 | |||
55 | #define IFF_POINTTOPOINT 0x10 | ||
56 | |||
57 | #define WANPIPE 0x00 | ||
58 | #define API 0x01 | ||
59 | #define CHDLC_API 0x01 | ||
60 | |||
61 | #define PORT(x) (x == 0 ? "PRIMARY" : "SECONDARY" ) | ||
62 | |||
63 | |||
64 | /******Data Structures*****************************************************/ | ||
65 | |||
66 | /* This structure is placed in the private data area of the device structure. | ||
67 | * The card structure used to occupy the private area but now the following | ||
68 | * structure will incorporate the card structure along with CHDLC specific data | ||
69 | */ | ||
70 | |||
71 | typedef struct chdlc_private_area | ||
72 | { | ||
73 | struct net_device *slave; | ||
74 | sdla_t *card; | ||
75 | int TracingEnabled; /* For enabling Tracing */ | ||
76 | unsigned long curr_trace_addr; /* Used for Tracing */ | ||
77 | unsigned long start_trace_addr; | ||
78 | unsigned long end_trace_addr; | ||
79 | unsigned long base_addr_trace_buffer; | ||
80 | unsigned long end_addr_trace_buffer; | ||
81 | unsigned short number_trace_elements; | ||
82 | unsigned available_buffer_space; | ||
83 | unsigned long router_start_time; | ||
84 | unsigned char route_status; | ||
85 | unsigned char route_removed; | ||
86 | unsigned long tick_counter; /* For 5s timeout counter */ | ||
87 | unsigned long router_up_time; | ||
88 | u32 IP_address; /* IP addressing */ | ||
89 | u32 IP_netmask; | ||
90 | unsigned char mc; /* Mulitcast support on/off */ | ||
91 | unsigned short udp_pkt_lgth; /* udp packet processing */ | ||
92 | char udp_pkt_src; | ||
93 | char udp_pkt_data[MAX_LGTH_UDP_MGNT_PKT]; | ||
94 | unsigned short timer_int_enabled; | ||
95 | char update_comms_stats; /* updating comms stats */ | ||
96 | //FIXME: add driver stats as per frame relay! | ||
97 | |||
98 | } chdlc_private_area_t; | ||
99 | |||
100 | /* Route Status options */ | ||
101 | #define NO_ROUTE 0x00 | ||
102 | #define ADD_ROUTE 0x01 | ||
103 | #define ROUTE_ADDED 0x02 | ||
104 | #define REMOVE_ROUTE 0x03 | ||
105 | |||
106 | |||
107 | /****** Function Prototypes *************************************************/ | ||
108 | /* WAN link driver entry points. These are called by the WAN router module. */ | ||
109 | static int wpft1_exec (struct sdla *card, void *u_cmd, void *u_data); | ||
110 | static int chdlc_read_version (sdla_t* card, char* str); | ||
111 | static int chdlc_error (sdla_t *card, int err, CHDLC_MAILBOX_STRUCT *mb); | ||
112 | |||
113 | /****** Public Functions ****************************************************/ | ||
114 | |||
115 | /*============================================================================ | ||
116 | * Cisco HDLC protocol initialization routine. | ||
117 | * | ||
118 | * This routine is called by the main WANPIPE module during setup. At this | ||
119 | * point adapter is completely initialized and firmware is running. | ||
120 | * o read firmware version (to make sure it's alive) | ||
121 | * o configure adapter | ||
122 | * o initialize protocol-specific fields of the adapter data space. | ||
123 | * | ||
124 | * Return: 0 o.k. | ||
125 | * < 0 failure. | ||
126 | */ | ||
127 | int wpft1_init (sdla_t* card, wandev_conf_t* conf) | ||
128 | { | ||
129 | unsigned char port_num; | ||
130 | int err; | ||
131 | |||
132 | union | ||
133 | { | ||
134 | char str[80]; | ||
135 | } u; | ||
136 | volatile CHDLC_MAILBOX_STRUCT* mb; | ||
137 | CHDLC_MAILBOX_STRUCT* mb1; | ||
138 | unsigned long timeout; | ||
139 | |||
140 | /* Verify configuration ID */ | ||
141 | if (conf->config_id != WANCONFIG_CHDLC) { | ||
142 | printk(KERN_INFO "%s: invalid configuration ID %u!\n", | ||
143 | card->devname, conf->config_id); | ||
144 | return -EINVAL; | ||
145 | } | ||
146 | |||
147 | /* Use primary port */ | ||
148 | card->u.c.comm_port = 0; | ||
149 | |||
150 | |||
151 | /* Initialize protocol-specific fields */ | ||
152 | if(card->hw.type != SDLA_S514){ | ||
153 | card->mbox = (void *) card->hw.dpmbase; | ||
154 | }else{ | ||
155 | card->mbox = (void *) card->hw.dpmbase + PRI_BASE_ADDR_MB_STRUCT; | ||
156 | } | ||
157 | |||
158 | mb = mb1 = card->mbox; | ||
159 | |||
160 | if (!card->configured){ | ||
161 | |||
162 | /* The board will place an 'I' in the return code to indicate that it is | ||
163 | ready to accept commands. We expect this to be completed in less | ||
164 | than 1 second. */ | ||
165 | |||
166 | timeout = jiffies; | ||
167 | while (mb->return_code != 'I') /* Wait 1s for board to initialize */ | ||
168 | if (time_after(jiffies, timeout + 1*HZ)) break; | ||
169 | |||
170 | if (mb->return_code != 'I') { | ||
171 | printk(KERN_INFO | ||
172 | "%s: Initialization not completed by adapter\n", | ||
173 | card->devname); | ||
174 | printk(KERN_INFO "Please contact Sangoma representative.\n"); | ||
175 | return -EIO; | ||
176 | } | ||
177 | } | ||
178 | |||
179 | /* Read firmware version. Note that when adapter initializes, it | ||
180 | * clears the mailbox, so it may appear that the first command was | ||
181 | * executed successfully when in fact it was merely erased. To work | ||
182 | * around this, we execute the first command twice. | ||
183 | */ | ||
184 | |||
185 | if (chdlc_read_version(card, u.str)) | ||
186 | return -EIO; | ||
187 | |||
188 | printk(KERN_INFO "%s: Running FT1 Configuration firmware v%s\n", | ||
189 | card->devname, u.str); | ||
190 | |||
191 | card->isr = NULL; | ||
192 | card->poll = NULL; | ||
193 | card->exec = &wpft1_exec; | ||
194 | card->wandev.update = NULL; | ||
195 | card->wandev.new_if = NULL; | ||
196 | card->wandev.del_if = NULL; | ||
197 | card->wandev.state = WAN_DUALPORT; | ||
198 | card->wandev.udp_port = conf->udp_port; | ||
199 | |||
200 | card->wandev.new_if_cnt = 0; | ||
201 | |||
202 | /* This is for the ports link state */ | ||
203 | card->u.c.state = WAN_DISCONNECTED; | ||
204 | |||
205 | /* reset the number of times the 'update()' proc has been called */ | ||
206 | card->u.c.update_call_count = 0; | ||
207 | |||
208 | card->wandev.ttl = 0x7F; | ||
209 | card->wandev.interface = 0; | ||
210 | |||
211 | card->wandev.clocking = 0; | ||
212 | |||
213 | port_num = card->u.c.comm_port; | ||
214 | |||
215 | /* Setup Port Bps */ | ||
216 | |||
217 | card->wandev.bps = 0; | ||
218 | |||
219 | card->wandev.mtu = MIN_LGTH_CHDLC_DATA_CFG; | ||
220 | |||
221 | /* Set up the interrupt status area */ | ||
222 | /* Read the CHDLC Configuration and obtain: | ||
223 | * Ptr to shared memory infor struct | ||
224 | * Use this pointer to calculate the value of card->u.c.flags ! | ||
225 | */ | ||
226 | mb1->buffer_length = 0; | ||
227 | mb1->command = READ_CHDLC_CONFIGURATION; | ||
228 | err = sdla_exec(mb1) ? mb1->return_code : CMD_TIMEOUT; | ||
229 | if(err != COMMAND_OK) { | ||
230 | chdlc_error(card, err, mb1); | ||
231 | return -EIO; | ||
232 | } | ||
233 | |||
234 | if(card->hw.type == SDLA_S514){ | ||
235 | card->u.c.flags = (void *)(card->hw.dpmbase + | ||
236 | (((CHDLC_CONFIGURATION_STRUCT *)mb1->data)-> | ||
237 | ptr_shared_mem_info_struct)); | ||
238 | }else{ | ||
239 | card->u.c.flags = (void *)(card->hw.dpmbase + | ||
240 | (((CHDLC_CONFIGURATION_STRUCT *)mb1->data)-> | ||
241 | ptr_shared_mem_info_struct % SDLA_WINDOWSIZE)); | ||
242 | } | ||
243 | |||
244 | card->wandev.state = WAN_FT1_READY; | ||
245 | printk(KERN_INFO "%s: FT1 Config Ready !\n",card->devname); | ||
246 | |||
247 | return 0; | ||
248 | } | ||
249 | |||
250 | static int wpft1_exec(sdla_t *card, void *u_cmd, void *u_data) | ||
251 | { | ||
252 | CHDLC_MAILBOX_STRUCT* mbox = card->mbox; | ||
253 | int len; | ||
254 | |||
255 | if (copy_from_user((void*)&mbox->command, u_cmd, sizeof(ft1_exec_cmd_t))){ | ||
256 | return -EFAULT; | ||
257 | } | ||
258 | |||
259 | len = mbox->buffer_length; | ||
260 | |||
261 | if (len) { | ||
262 | if( copy_from_user((void*)&mbox->data, u_data, len)){ | ||
263 | return -EFAULT; | ||
264 | } | ||
265 | } | ||
266 | |||
267 | /* execute command */ | ||
268 | if (!sdla_exec(mbox)){ | ||
269 | return -EIO; | ||
270 | } | ||
271 | |||
272 | /* return result */ | ||
273 | if( copy_to_user(u_cmd, (void*)&mbox->command, sizeof(ft1_exec_cmd_t))){ | ||
274 | return -EFAULT; | ||
275 | } | ||
276 | |||
277 | len = mbox->buffer_length; | ||
278 | |||
279 | if (len && u_data && copy_to_user(u_data, (void*)&mbox->data, len)){ | ||
280 | return -EFAULT; | ||
281 | } | ||
282 | |||
283 | return 0; | ||
284 | |||
285 | } | ||
286 | |||
287 | /*============================================================================ | ||
288 | * Read firmware code version. | ||
289 | * Put code version as ASCII string in str. | ||
290 | */ | ||
291 | static int chdlc_read_version (sdla_t* card, char* str) | ||
292 | { | ||
293 | CHDLC_MAILBOX_STRUCT* mb = card->mbox; | ||
294 | int len; | ||
295 | char err; | ||
296 | mb->buffer_length = 0; | ||
297 | mb->command = READ_CHDLC_CODE_VERSION; | ||
298 | err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; | ||
299 | |||
300 | if(err != COMMAND_OK) { | ||
301 | chdlc_error(card,err,mb); | ||
302 | } | ||
303 | else if (str) { /* is not null */ | ||
304 | len = mb->buffer_length; | ||
305 | memcpy(str, mb->data, len); | ||
306 | str[len] = '\0'; | ||
307 | } | ||
308 | return (err); | ||
309 | } | ||
310 | |||
311 | /*============================================================================ | ||
312 | * Firmware error handler. | ||
313 | * This routine is called whenever firmware command returns non-zero | ||
314 | * return code. | ||
315 | * | ||
316 | * Return zero if previous command has to be cancelled. | ||
317 | */ | ||
318 | static int chdlc_error (sdla_t *card, int err, CHDLC_MAILBOX_STRUCT *mb) | ||
319 | { | ||
320 | unsigned cmd = mb->command; | ||
321 | |||
322 | switch (err) { | ||
323 | |||
324 | case CMD_TIMEOUT: | ||
325 | printk(KERN_ERR "%s: command 0x%02X timed out!\n", | ||
326 | card->devname, cmd); | ||
327 | break; | ||
328 | |||
329 | case S514_BOTH_PORTS_SAME_CLK_MODE: | ||
330 | if(cmd == SET_CHDLC_CONFIGURATION) { | ||
331 | printk(KERN_INFO | ||
332 | "%s: Configure both ports for the same clock source\n", | ||
333 | card->devname); | ||
334 | break; | ||
335 | } | ||
336 | |||
337 | default: | ||
338 | printk(KERN_INFO "%s: command 0x%02X returned 0x%02X!\n", | ||
339 | card->devname, cmd, err); | ||
340 | } | ||
341 | |||
342 | return 0; | ||
343 | } | ||
344 | |||
345 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/net/wan/sdla_ppp.c b/drivers/net/wan/sdla_ppp.c deleted file mode 100644 index a4b489cccbbf..000000000000 --- a/drivers/net/wan/sdla_ppp.c +++ /dev/null | |||
@@ -1,3430 +0,0 @@ | |||
1 | /***************************************************************************** | ||
2 | * sdla_ppp.c WANPIPE(tm) Multiprotocol WAN Link Driver. PPP module. | ||
3 | * | ||
4 | * Author: Nenad Corbic <ncorbic@sangoma.com> | ||
5 | * | ||
6 | * Copyright: (c) 1995-2001 Sangoma Technologies Inc. | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License | ||
10 | * as published by the Free Software Foundation; either version | ||
11 | * 2 of the License, or (at your option) any later version. | ||
12 | * ============================================================================ | ||
13 | * Feb 28, 2001 Nenad Corbic o Updated if_tx_timeout() routine for | ||
14 | * 2.4.X kernels. | ||
15 | * Nov 29, 2000 Nenad Corbic o Added the 2.4.x kernel support: | ||
16 | * get_ip_address() function has moved | ||
17 | * into the ppp_poll() routine. It cannot | ||
18 | * be called from an interrupt. | ||
19 | * Nov 07, 2000 Nenad Corbic o Added security features for UDP debugging: | ||
20 | * Deny all and specify allowed requests. | ||
21 | * May 02, 2000 Nenad Corbic o Added the dynamic interface shutdown | ||
22 | * option. When the link goes down, the | ||
23 | * network interface IFF_UP flag is reset. | ||
24 | * Mar 06, 2000 Nenad Corbic o Bug Fix: corrupted mbox recovery. | ||
25 | * Feb 25, 2000 Nenad Corbic o Fixed the FT1 UDP debugger problem. | ||
26 | * Feb 09, 2000 Nenad Coribc o Shutdown bug fix. update() was called | ||
27 | * with NULL dev pointer: no check. | ||
28 | * Jan 24, 2000 Nenad Corbic o Disabled use of CMD complete inter. | ||
29 | * Dev 15, 1999 Nenad Corbic o Fixed up header files for 2.0.X kernels | ||
30 | * Oct 25, 1999 Nenad Corbic o Support for 2.0.X kernels | ||
31 | * Moved dynamic route processing into | ||
32 | * a polling routine. | ||
33 | * Oct 07, 1999 Nenad Corbic o Support for S514 PCI card. | ||
34 | * Gideon Hack o UPD and Updates executed using timer interrupt | ||
35 | * Sep 10, 1999 Nenad Corbic o Fixed up the /proc statistics | ||
36 | * Jul 20, 1999 Nenad Corbic o Remove the polling routines and use | ||
37 | * interrupts instead. | ||
38 | * Sep 17, 1998 Jaspreet Singh o Updates for 2.2.X Kernels. | ||
39 | * Aug 13, 1998 Jaspreet Singh o Improved Line Tracing. | ||
40 | * Jun 22, 1998 David Fong o Added remote IP address assignment | ||
41 | * Mar 15, 1998 Alan Cox o 2.1.8x basic port. | ||
42 | * Apr 16, 1998 Jaspreet Singh o using htons() for the IPX protocol. | ||
43 | * Dec 09, 1997 Jaspreet Singh o Added PAP and CHAP. | ||
44 | * o Implemented new routines like | ||
45 | * ppp_set_inbnd_auth(), ppp_set_outbnd_auth(), | ||
46 | * tokenize() and strstrip(). | ||
47 | * Nov 27, 1997 Jaspreet Singh o Added protection against enabling of irqs | ||
48 | * while they have been disabled. | ||
49 | * Nov 24, 1997 Jaspreet Singh o Fixed another RACE condition caused by | ||
50 | * disabling and enabling of irqs. | ||
51 | * o Added new counters for stats on disable/enable | ||
52 | * IRQs. | ||
53 | * Nov 10, 1997 Jaspreet Singh o Initialized 'skb->mac.raw' to 'skb->data' | ||
54 | * before every netif_rx(). | ||
55 | * o Free up the device structure in del_if(). | ||
56 | * Nov 07, 1997 Jaspreet Singh o Changed the delay to zero for Line tracing | ||
57 | * command. | ||
58 | * Oct 20, 1997 Jaspreet Singh o Added hooks in for Router UP time. | ||
59 | * Oct 16, 1997 Jaspreet Singh o The critical flag is used to maintain flow | ||
60 | * control by avoiding RACE conditions. The | ||
61 | * cli() and restore_flags() are taken out. | ||
62 | * A new structure, "ppp_private_area", is added | ||
63 | * to provide Driver Statistics. | ||
64 | * Jul 21, 1997 Jaspreet Singh o Protected calls to sdla_peek() by adding | ||
65 | * save_flags(), cli() and restore_flags(). | ||
66 | * Jul 07, 1997 Jaspreet Singh o Added configurable TTL for UDP packets | ||
67 | * o Added ability to discard mulitcast and | ||
68 | * broacast source addressed packets. | ||
69 | * Jun 27, 1997 Jaspreet Singh o Added FT1 monitor capabilities | ||
70 | * New case (0x25) statement in if_send routine. | ||
71 | * Added a global variable rCount to keep track | ||
72 | * of FT1 status enabled on the board. | ||
73 | * May 22, 1997 Jaspreet Singh o Added change in the PPP_SET_CONFIG command for | ||
74 | * 508 card to reflect changes in the new | ||
75 | * ppp508.sfm for supporting:continous transmission | ||
76 | * of Configure-Request packets without receiving a | ||
77 | * reply | ||
78 | * OR-ed 0x300 to conf_flags | ||
79 | * o Changed connect_tmout from 900 to 0 | ||
80 | * May 21, 1997 Jaspreet Singh o Fixed UDP Management for multiple boards | ||
81 | * Apr 25, 1997 Farhan Thawar o added UDP Management stuff | ||
82 | * Mar 11, 1997 Farhan Thawar Version 3.1.1 | ||
83 | * o fixed (+1) bug in rx_intr() | ||
84 | * o changed if_send() to return 0 if | ||
85 | * wandev.critical() is true | ||
86 | * o free socket buffer in if_send() if | ||
87 | * returning 0 | ||
88 | * Jan 15, 1997 Gene Kozin Version 3.1.0 | ||
89 | * o implemented exec() entry point | ||
90 | * Jan 06, 1997 Gene Kozin Initial version. | ||
91 | *****************************************************************************/ | ||
92 | |||
93 | #include <linux/module.h> | ||
94 | #include <linux/kernel.h> /* printk(), and other useful stuff */ | ||
95 | #include <linux/stddef.h> /* offsetof(), etc. */ | ||
96 | #include <linux/errno.h> /* return codes */ | ||
97 | #include <linux/string.h> /* inline memset(), etc. */ | ||
98 | #include <linux/slab.h> /* kmalloc(), kfree() */ | ||
99 | #include <linux/wanrouter.h> /* WAN router definitions */ | ||
100 | #include <linux/wanpipe.h> /* WANPIPE common user API definitions */ | ||
101 | #include <linux/if_arp.h> /* ARPHRD_* defines */ | ||
102 | #include <asm/byteorder.h> /* htons(), etc. */ | ||
103 | #include <linux/in.h> /* sockaddr_in */ | ||
104 | #include <linux/jiffies.h> /* time_after() macro */ | ||
105 | |||
106 | |||
107 | #include <asm/uaccess.h> | ||
108 | #include <linux/inetdevice.h> | ||
109 | #include <linux/netdevice.h> | ||
110 | |||
111 | #include <linux/if.h> | ||
112 | #include <linux/sdla_ppp.h> /* PPP firmware API definitions */ | ||
113 | #include <linux/sdlasfm.h> /* S514 Type Definition */ | ||
114 | /****** Defines & Macros ****************************************************/ | ||
115 | |||
116 | #define PPP_DFLT_MTU 1500 /* default MTU */ | ||
117 | #define PPP_MAX_MTU 4000 /* maximum MTU */ | ||
118 | #define PPP_HDR_LEN 1 | ||
119 | |||
120 | #define MAX_IP_ERRORS 100 | ||
121 | |||
122 | #define CONNECT_TIMEOUT (90*HZ) /* link connection timeout */ | ||
123 | #define HOLD_DOWN_TIME (5*HZ) /* link hold down time : Changed from 30 to 5 */ | ||
124 | |||
125 | /* For handle_IPXWAN() */ | ||
126 | #define CVHexToAscii(b) (((unsigned char)(b) > (unsigned char)9) ? ((unsigned char)'A' + ((unsigned char)(b) - (unsigned char)10)) : ((unsigned char)'0' + (unsigned char)(b))) | ||
127 | |||
128 | /* Macro for enabling/disabling debugging comments */ | ||
129 | //#define NEX_DEBUG | ||
130 | #ifdef NEX_DEBUG | ||
131 | #define NEX_PRINTK(format, a...) printk(format, ## a) | ||
132 | #else | ||
133 | #define NEX_PRINTK(format, a...) | ||
134 | #endif /* NEX_DEBUG */ | ||
135 | |||
136 | #define DCD(a) ( a & 0x08 ? "HIGH" : "LOW" ) | ||
137 | #define CTS(a) ( a & 0x20 ? "HIGH" : "LOW" ) | ||
138 | #define LCP(a) ( a == 0x09 ? "OPEN" : "CLOSED" ) | ||
139 | #define IP(a) ( a == 0x09 ? "ENABLED" : "DISABLED" ) | ||
140 | |||
141 | #define TMR_INT_ENABLED_UPDATE 0x01 | ||
142 | #define TMR_INT_ENABLED_PPP_EVENT 0x02 | ||
143 | #define TMR_INT_ENABLED_UDP 0x04 | ||
144 | #define TMR_INT_ENABLED_CONFIG 0x20 | ||
145 | |||
146 | /* Set Configuraton Command Definitions */ | ||
147 | #define PERCENT_TX_BUFF 60 | ||
148 | #define TIME_BETWEEN_CONF_REQ 30 | ||
149 | #define TIME_BETWEEN_PAP_CHAP_REQ 30 | ||
150 | #define WAIT_PAP_CHAP_WITHOUT_REPLY 300 | ||
151 | #define WAIT_AFTER_DCD_CTS_LOW 5 | ||
152 | #define TIME_DCD_CTS_LOW_AFTER_LNK_DOWN 10 | ||
153 | #define WAIT_DCD_HIGH_AFTER_ENABLE_COMM 900 | ||
154 | #define MAX_CONF_REQ_WITHOUT_REPLY 10 | ||
155 | #define MAX_TERM_REQ_WITHOUT_REPLY 2 | ||
156 | #define NUM_CONF_NAK_WITHOUT_REPLY 5 | ||
157 | #define NUM_AUTH_REQ_WITHOUT_REPLY 10 | ||
158 | |||
159 | #define END_OFFSET 0x1F0 | ||
160 | |||
161 | |||
162 | /******Data Structures*****************************************************/ | ||
163 | |||
164 | /* This structure is placed in the private data area of the device structure. | ||
165 | * The card structure used to occupy the private area but now the following | ||
166 | * structure will incorporate the card structure along with PPP specific data | ||
167 | */ | ||
168 | |||
169 | typedef struct ppp_private_area | ||
170 | { | ||
171 | struct net_device *slave; | ||
172 | sdla_t* card; | ||
173 | unsigned long router_start_time; /*router start time in sec */ | ||
174 | unsigned long tick_counter; /*used for 5 second counter*/ | ||
175 | unsigned mc; /*multicast support on or off*/ | ||
176 | unsigned char enable_IPX; | ||
177 | unsigned long network_number; | ||
178 | unsigned char pap; | ||
179 | unsigned char chap; | ||
180 | unsigned char sysname[31]; /* system name for in-bnd auth*/ | ||
181 | unsigned char userid[511]; /* list of user ids */ | ||
182 | unsigned char passwd[511]; /* list of passwords */ | ||
183 | unsigned protocol; /* SKB Protocol */ | ||
184 | u32 ip_local; /* Local IP Address */ | ||
185 | u32 ip_remote; /* remote IP Address */ | ||
186 | |||
187 | u32 ip_local_tmp; | ||
188 | u32 ip_remote_tmp; | ||
189 | |||
190 | unsigned char timer_int_enabled; /* Who enabled the timer inter*/ | ||
191 | unsigned char update_comms_stats; /* Used by update function */ | ||
192 | unsigned long curr_trace_addr; /* Trace information */ | ||
193 | unsigned long start_trace_addr; | ||
194 | unsigned long end_trace_addr; | ||
195 | |||
196 | unsigned char interface_down; /* Brind down interface when channel | ||
197 | goes down */ | ||
198 | unsigned long config_wait_timeout; /* After if_open() if in dynamic if mode, | ||
199 | wait a few seconds before configuring */ | ||
200 | |||
201 | unsigned short udp_pkt_lgth; | ||
202 | char udp_pkt_src; | ||
203 | char udp_pkt_data[MAX_LGTH_UDP_MGNT_PKT]; | ||
204 | |||
205 | /* PPP specific statistics */ | ||
206 | |||
207 | if_send_stat_t if_send_stat; | ||
208 | rx_intr_stat_t rx_intr_stat; | ||
209 | pipe_mgmt_stat_t pipe_mgmt_stat; | ||
210 | |||
211 | unsigned long router_up_time; | ||
212 | |||
213 | /* Polling work queue entry. Each interface | ||
214 | * has its own work queue entry, which is used | ||
215 | * to defer events from the interrupt */ | ||
216 | struct work_struct poll_work; | ||
217 | struct timer_list poll_delay_timer; | ||
218 | |||
219 | u8 gateway; | ||
220 | u8 config_ppp; | ||
221 | u8 ip_error; | ||
222 | |||
223 | }ppp_private_area_t; | ||
224 | |||
225 | /* variable for keeping track of enabling/disabling FT1 monitor status */ | ||
226 | static int rCount = 0; | ||
227 | |||
228 | extern void disable_irq(unsigned int); | ||
229 | extern void enable_irq(unsigned int); | ||
230 | |||
231 | /****** Function Prototypes *************************************************/ | ||
232 | |||
233 | /* WAN link driver entry points. These are called by the WAN router module. */ | ||
234 | static int update(struct wan_device *wandev); | ||
235 | static int new_if(struct wan_device *wandev, struct net_device *dev, | ||
236 | wanif_conf_t *conf); | ||
237 | static int del_if(struct wan_device *wandev, struct net_device *dev); | ||
238 | |||
239 | /* WANPIPE-specific entry points */ | ||
240 | static int wpp_exec (struct sdla *card, void *u_cmd, void *u_data); | ||
241 | |||
242 | /* Network device interface */ | ||
243 | static int if_init(struct net_device *dev); | ||
244 | static int if_open(struct net_device *dev); | ||
245 | static int if_close(struct net_device *dev); | ||
246 | static int if_header(struct sk_buff *skb, struct net_device *dev, | ||
247 | unsigned short type, | ||
248 | void *daddr, void *saddr, unsigned len); | ||
249 | |||
250 | static void if_tx_timeout(struct net_device *dev); | ||
251 | |||
252 | static int if_rebuild_hdr(struct sk_buff *skb); | ||
253 | static struct net_device_stats *if_stats(struct net_device *dev); | ||
254 | static int if_send(struct sk_buff *skb, struct net_device *dev); | ||
255 | |||
256 | |||
257 | /* PPP firmware interface functions */ | ||
258 | static int ppp_read_version(sdla_t *card, char *str); | ||
259 | static int ppp_set_outbnd_auth(sdla_t *card, ppp_private_area_t *ppp_priv_area); | ||
260 | static int ppp_set_inbnd_auth(sdla_t *card, ppp_private_area_t *ppp_priv_area); | ||
261 | static int ppp_configure(sdla_t *card, void *data); | ||
262 | static int ppp_set_intr_mode(sdla_t *card, unsigned char mode); | ||
263 | static int ppp_comm_enable(sdla_t *card); | ||
264 | static int ppp_comm_disable(sdla_t *card); | ||
265 | static int ppp_comm_disable_shutdown(sdla_t *card); | ||
266 | static int ppp_get_err_stats(sdla_t *card); | ||
267 | static int ppp_send(sdla_t *card, void *data, unsigned len, unsigned proto); | ||
268 | static int ppp_error(sdla_t *card, int err, ppp_mbox_t *mb); | ||
269 | |||
270 | static void wpp_isr(sdla_t *card); | ||
271 | static void rx_intr(sdla_t *card); | ||
272 | static void event_intr(sdla_t *card); | ||
273 | static void timer_intr(sdla_t *card); | ||
274 | |||
275 | /* Background polling routines */ | ||
276 | static void process_route(sdla_t *card); | ||
277 | static void retrigger_comm(sdla_t *card); | ||
278 | |||
279 | /* Miscellaneous functions */ | ||
280 | static int read_info( sdla_t *card ); | ||
281 | static int read_connection_info (sdla_t *card); | ||
282 | static void remove_route( sdla_t *card ); | ||
283 | static int config508(struct net_device *dev, sdla_t *card); | ||
284 | static void show_disc_cause(sdla_t * card, unsigned cause); | ||
285 | static int reply_udp( unsigned char *data, unsigned int mbox_len ); | ||
286 | static void process_udp_mgmt_pkt(sdla_t *card, struct net_device *dev, | ||
287 | ppp_private_area_t *ppp_priv_area); | ||
288 | static void init_ppp_tx_rx_buff( sdla_t *card ); | ||
289 | static int intr_test( sdla_t *card ); | ||
290 | static int udp_pkt_type( struct sk_buff *skb , sdla_t *card); | ||
291 | static void init_ppp_priv_struct( ppp_private_area_t *ppp_priv_area); | ||
292 | static void init_global_statistics( sdla_t *card ); | ||
293 | static int tokenize(char *str, char **tokens); | ||
294 | static char* strstrip(char *str, char *s); | ||
295 | static int chk_bcast_mcast_addr(sdla_t* card, struct net_device* dev, | ||
296 | struct sk_buff *skb); | ||
297 | |||
298 | static int config_ppp (sdla_t *); | ||
299 | static void ppp_poll(struct net_device *dev); | ||
300 | static void trigger_ppp_poll(struct net_device *dev); | ||
301 | static void ppp_poll_delay (unsigned long dev_ptr); | ||
302 | |||
303 | |||
304 | static int Read_connection_info; | ||
305 | static int Intr_test_counter; | ||
306 | static unsigned short available_buffer_space; | ||
307 | |||
308 | |||
309 | /* IPX functions */ | ||
310 | static void switch_net_numbers(unsigned char *sendpacket, unsigned long network_number, | ||
311 | unsigned char incoming); | ||
312 | static int handle_IPXWAN(unsigned char *sendpacket, char *devname, unsigned char enable_PX, | ||
313 | unsigned long network_number, unsigned short proto); | ||
314 | |||
315 | /* Lock Functions */ | ||
316 | static void s508_lock (sdla_t *card, unsigned long *smp_flags); | ||
317 | static void s508_unlock (sdla_t *card, unsigned long *smp_flags); | ||
318 | |||
319 | static int store_udp_mgmt_pkt(char udp_pkt_src, sdla_t* card, | ||
320 | struct sk_buff *skb, struct net_device* dev, | ||
321 | ppp_private_area_t* ppp_priv_area ); | ||
322 | static unsigned short calc_checksum (char *data, int len); | ||
323 | static void disable_comm (sdla_t *card); | ||
324 | static int detect_and_fix_tx_bug (sdla_t *card); | ||
325 | |||
326 | /****** Public Functions ****************************************************/ | ||
327 | |||
328 | /*============================================================================ | ||
329 | * PPP protocol initialization routine. | ||
330 | * | ||
331 | * This routine is called by the main WANPIPE module during setup. At this | ||
332 | * point adapter is completely initialized and firmware is running. | ||
333 | * o read firmware version (to make sure it's alive) | ||
334 | * o configure adapter | ||
335 | * o initialize protocol-specific fields of the adapter data space. | ||
336 | * | ||
337 | * Return: 0 o.k. | ||
338 | * < 0 failure. | ||
339 | */ | ||
340 | int wpp_init(sdla_t *card, wandev_conf_t *conf) | ||
341 | { | ||
342 | ppp_flags_t *flags; | ||
343 | union | ||
344 | { | ||
345 | char str[80]; | ||
346 | } u; | ||
347 | |||
348 | /* Verify configuration ID */ | ||
349 | if (conf->config_id != WANCONFIG_PPP) { | ||
350 | |||
351 | printk(KERN_INFO "%s: invalid configuration ID %u!\n", | ||
352 | card->devname, conf->config_id); | ||
353 | return -EINVAL; | ||
354 | |||
355 | } | ||
356 | |||
357 | /* Initialize miscellaneous pointers to structures on the adapter */ | ||
358 | switch (card->hw.type) { | ||
359 | |||
360 | case SDLA_S508: | ||
361 | card->mbox =(void*)(card->hw.dpmbase + PPP508_MB_OFFS); | ||
362 | card->flags=(void*)(card->hw.dpmbase + PPP508_FLG_OFFS); | ||
363 | break; | ||
364 | |||
365 | case SDLA_S514: | ||
366 | card->mbox =(void*)(card->hw.dpmbase + PPP514_MB_OFFS); | ||
367 | card->flags=(void*)(card->hw.dpmbase + PPP514_FLG_OFFS); | ||
368 | break; | ||
369 | |||
370 | default: | ||
371 | return -EINVAL; | ||
372 | |||
373 | } | ||
374 | flags = card->flags; | ||
375 | |||
376 | /* Read firmware version. Note that when adapter initializes, it | ||
377 | * clears the mailbox, so it may appear that the first command was | ||
378 | * executed successfully when in fact it was merely erased. To work | ||
379 | * around this, we execute the first command twice. | ||
380 | */ | ||
381 | if (ppp_read_version(card, NULL) || ppp_read_version(card, u.str)) | ||
382 | return -EIO; | ||
383 | |||
384 | printk(KERN_INFO "%s: running PPP firmware v%s\n",card->devname, u.str); | ||
385 | /* Adjust configuration and set defaults */ | ||
386 | card->wandev.mtu = (conf->mtu) ? | ||
387 | min_t(unsigned int, conf->mtu, PPP_MAX_MTU) : PPP_DFLT_MTU; | ||
388 | |||
389 | card->wandev.bps = conf->bps; | ||
390 | card->wandev.interface = conf->interface; | ||
391 | card->wandev.clocking = conf->clocking; | ||
392 | card->wandev.station = conf->station; | ||
393 | card->isr = &wpp_isr; | ||
394 | card->poll = NULL; | ||
395 | card->exec = &wpp_exec; | ||
396 | card->wandev.update = &update; | ||
397 | card->wandev.new_if = &new_if; | ||
398 | card->wandev.del_if = &del_if; | ||
399 | card->wandev.udp_port = conf->udp_port; | ||
400 | card->wandev.ttl = conf->ttl; | ||
401 | card->wandev.state = WAN_DISCONNECTED; | ||
402 | card->disable_comm = &disable_comm; | ||
403 | card->irq_dis_if_send_count = 0; | ||
404 | card->irq_dis_poll_count = 0; | ||
405 | card->u.p.authenticator = conf->u.ppp.authenticator; | ||
406 | card->u.p.ip_mode = conf->u.ppp.ip_mode ? | ||
407 | conf->u.ppp.ip_mode : WANOPT_PPP_STATIC; | ||
408 | card->TracingEnabled = 0; | ||
409 | Read_connection_info = 1; | ||
410 | |||
411 | /* initialize global statistics */ | ||
412 | init_global_statistics( card ); | ||
413 | |||
414 | |||
415 | |||
416 | if (!card->configured){ | ||
417 | int err; | ||
418 | |||
419 | Intr_test_counter = 0; | ||
420 | err = intr_test(card); | ||
421 | |||
422 | if(err || (Intr_test_counter < MAX_INTR_TEST_COUNTER)) { | ||
423 | printk("%s: Interrupt Test Failed, Counter: %i\n", | ||
424 | card->devname, Intr_test_counter); | ||
425 | printk( "%s: Please choose another interrupt\n",card->devname); | ||
426 | return -EIO; | ||
427 | } | ||
428 | |||
429 | printk(KERN_INFO "%s: Interrupt Test Passed, Counter: %i\n", | ||
430 | card->devname, Intr_test_counter); | ||
431 | card->configured = 1; | ||
432 | } | ||
433 | |||
434 | ppp_set_intr_mode(card, PPP_INTR_TIMER); | ||
435 | |||
436 | /* Turn off the transmit and timer interrupt */ | ||
437 | flags->imask &= ~PPP_INTR_TIMER; | ||
438 | |||
439 | printk(KERN_INFO "\n"); | ||
440 | |||
441 | return 0; | ||
442 | } | ||
443 | |||
444 | /******* WAN Device Driver Entry Points *************************************/ | ||
445 | |||
446 | /*============================================================================ | ||
447 | * Update device status & statistics. | ||
448 | */ | ||
449 | static int update(struct wan_device *wandev) | ||
450 | { | ||
451 | sdla_t* card = wandev->private; | ||
452 | struct net_device* dev; | ||
453 | volatile ppp_private_area_t *ppp_priv_area; | ||
454 | ppp_flags_t *flags = card->flags; | ||
455 | unsigned long timeout; | ||
456 | |||
457 | /* sanity checks */ | ||
458 | if ((wandev == NULL) || (wandev->private == NULL)) | ||
459 | return -EFAULT; | ||
460 | |||
461 | if (wandev->state == WAN_UNCONFIGURED) | ||
462 | return -ENODEV; | ||
463 | |||
464 | /* Shutdown bug fix. This function can be | ||
465 | * called with NULL dev pointer during | ||
466 | * shutdown | ||
467 | */ | ||
468 | if ((dev=card->wandev.dev) == NULL){ | ||
469 | return -ENODEV; | ||
470 | } | ||
471 | |||
472 | if ((ppp_priv_area=dev->priv) == NULL){ | ||
473 | return -ENODEV; | ||
474 | } | ||
475 | |||
476 | ppp_priv_area->update_comms_stats = 2; | ||
477 | ppp_priv_area->timer_int_enabled |= TMR_INT_ENABLED_UPDATE; | ||
478 | flags->imask |= PPP_INTR_TIMER; | ||
479 | |||
480 | /* wait a maximum of 1 second for the statistics to be updated */ | ||
481 | timeout = jiffies; | ||
482 | for(;;) { | ||
483 | if(ppp_priv_area->update_comms_stats == 0){ | ||
484 | break; | ||
485 | } | ||
486 | if (time_after(jiffies, timeout + 1 * HZ)){ | ||
487 | ppp_priv_area->update_comms_stats = 0; | ||
488 | ppp_priv_area->timer_int_enabled &= | ||
489 | ~TMR_INT_ENABLED_UPDATE; | ||
490 | return -EAGAIN; | ||
491 | } | ||
492 | } | ||
493 | |||
494 | return 0; | ||
495 | } | ||
496 | |||
497 | /*============================================================================ | ||
498 | * Create new logical channel. | ||
499 | * This routine is called by the router when ROUTER_IFNEW IOCTL is being | ||
500 | * handled. | ||
501 | * o parse media- and hardware-specific configuration | ||
502 | * o make sure that a new channel can be created | ||
503 | * o allocate resources, if necessary | ||
504 | * o prepare network device structure for registaration. | ||
505 | * | ||
506 | * Return: 0 o.k. | ||
507 | * < 0 failure (channel will not be created) | ||
508 | */ | ||
509 | static int new_if(struct wan_device *wandev, struct net_device *dev, | ||
510 | wanif_conf_t *conf) | ||
511 | { | ||
512 | sdla_t *card = wandev->private; | ||
513 | ppp_private_area_t *ppp_priv_area; | ||
514 | |||
515 | if (wandev->ndev) | ||
516 | return -EEXIST; | ||
517 | |||
518 | |||
519 | printk(KERN_INFO "%s: Configuring Interface: %s\n", | ||
520 | card->devname, conf->name); | ||
521 | |||
522 | if ((conf->name[0] == '\0') || (strlen(conf->name) > WAN_IFNAME_SZ)) { | ||
523 | |||
524 | printk(KERN_INFO "%s: Invalid interface name!\n", | ||
525 | card->devname); | ||
526 | return -EINVAL; | ||
527 | |||
528 | } | ||
529 | |||
530 | /* allocate and initialize private data */ | ||
531 | ppp_priv_area = kmalloc(sizeof(ppp_private_area_t), GFP_KERNEL); | ||
532 | |||
533 | if( ppp_priv_area == NULL ) | ||
534 | return -ENOMEM; | ||
535 | |||
536 | memset(ppp_priv_area, 0, sizeof(ppp_private_area_t)); | ||
537 | |||
538 | ppp_priv_area->card = card; | ||
539 | |||
540 | /* initialize data */ | ||
541 | strcpy(card->u.p.if_name, conf->name); | ||
542 | |||
543 | /* initialize data in ppp_private_area structure */ | ||
544 | |||
545 | init_ppp_priv_struct( ppp_priv_area ); | ||
546 | |||
547 | ppp_priv_area->mc = conf->mc; | ||
548 | ppp_priv_area->pap = conf->pap; | ||
549 | ppp_priv_area->chap = conf->chap; | ||
550 | |||
551 | /* Option to bring down the interface when | ||
552 | * the link goes down */ | ||
553 | if (conf->if_down){ | ||
554 | set_bit(DYN_OPT_ON,&ppp_priv_area->interface_down); | ||
555 | printk("%s: Dynamic interface configuration enabled\n", | ||
556 | card->devname); | ||
557 | } | ||
558 | |||
559 | /* If no user ids are specified */ | ||
560 | if(!strlen(conf->userid) && (ppp_priv_area->pap||ppp_priv_area->chap)){ | ||
561 | kfree(ppp_priv_area); | ||
562 | return -EINVAL; | ||
563 | } | ||
564 | |||
565 | /* If no passwords are specified */ | ||
566 | if(!strlen(conf->passwd) && (ppp_priv_area->pap||ppp_priv_area->chap)){ | ||
567 | kfree(ppp_priv_area); | ||
568 | return -EINVAL; | ||
569 | } | ||
570 | |||
571 | if(strlen(conf->sysname) > 31){ | ||
572 | kfree(ppp_priv_area); | ||
573 | return -EINVAL; | ||
574 | } | ||
575 | |||
576 | /* If no system name is specified */ | ||
577 | if(!strlen(conf->sysname) && (card->u.p.authenticator)){ | ||
578 | kfree(ppp_priv_area); | ||
579 | return -EINVAL; | ||
580 | } | ||
581 | |||
582 | /* copy the data into the ppp private structure */ | ||
583 | memcpy(ppp_priv_area->userid, conf->userid, strlen(conf->userid)); | ||
584 | memcpy(ppp_priv_area->passwd, conf->passwd, strlen(conf->passwd)); | ||
585 | memcpy(ppp_priv_area->sysname, conf->sysname, strlen(conf->sysname)); | ||
586 | |||
587 | |||
588 | ppp_priv_area->enable_IPX = conf->enable_IPX; | ||
589 | if (conf->network_number){ | ||
590 | ppp_priv_area->network_number = conf->network_number; | ||
591 | }else{ | ||
592 | ppp_priv_area->network_number = 0xDEADBEEF; | ||
593 | } | ||
594 | |||
595 | /* Tells us that if this interface is a | ||
596 | * gateway or not */ | ||
597 | if ((ppp_priv_area->gateway = conf->gateway) == WANOPT_YES){ | ||
598 | printk(KERN_INFO "%s: Interface %s is set as a gateway.\n", | ||
599 | card->devname,card->u.p.if_name); | ||
600 | } | ||
601 | |||
602 | /* prepare network device data space for registration */ | ||
603 | strcpy(dev->name,card->u.p.if_name); | ||
604 | |||
605 | dev->init = &if_init; | ||
606 | dev->priv = ppp_priv_area; | ||
607 | dev->mtu = min_t(unsigned int, dev->mtu, card->wandev.mtu); | ||
608 | |||
609 | /* Initialize the polling work routine */ | ||
610 | INIT_WORK(&ppp_priv_area->poll_work, (void*)(void*)ppp_poll, dev); | ||
611 | |||
612 | /* Initialize the polling delay timer */ | ||
613 | init_timer(&ppp_priv_area->poll_delay_timer); | ||
614 | ppp_priv_area->poll_delay_timer.data = (unsigned long)dev; | ||
615 | ppp_priv_area->poll_delay_timer.function = ppp_poll_delay; | ||
616 | |||
617 | |||
618 | /* Since we start with dummy IP addresses we can say | ||
619 | * that route exists */ | ||
620 | printk(KERN_INFO "\n"); | ||
621 | |||
622 | return 0; | ||
623 | } | ||
624 | |||
625 | /*============================================================================ | ||
626 | * Delete logical channel. | ||
627 | */ | ||
628 | static int del_if(struct wan_device *wandev, struct net_device *dev) | ||
629 | { | ||
630 | return 0; | ||
631 | } | ||
632 | |||
633 | static void disable_comm (sdla_t *card) | ||
634 | { | ||
635 | ppp_comm_disable_shutdown(card); | ||
636 | return; | ||
637 | } | ||
638 | |||
639 | /****** WANPIPE-specific entry points ***************************************/ | ||
640 | |||
641 | /*============================================================================ | ||
642 | * Execute adapter interface command. | ||
643 | */ | ||
644 | |||
645 | //FIXME: Why do we need this ???? | ||
646 | static int wpp_exec(struct sdla *card, void *u_cmd, void *u_data) | ||
647 | { | ||
648 | ppp_mbox_t *mbox = card->mbox; | ||
649 | int len; | ||
650 | |||
651 | if (copy_from_user((void*)&mbox->cmd, u_cmd, sizeof(ppp_cmd_t))) | ||
652 | return -EFAULT; | ||
653 | |||
654 | len = mbox->cmd.length; | ||
655 | |||
656 | if (len) { | ||
657 | |||
658 | if( copy_from_user((void*)&mbox->data, u_data, len)) | ||
659 | return -EFAULT; | ||
660 | |||
661 | } | ||
662 | |||
663 | /* execute command */ | ||
664 | if (!sdla_exec(mbox)) | ||
665 | return -EIO; | ||
666 | |||
667 | /* return result */ | ||
668 | if( copy_to_user(u_cmd, (void*)&mbox->cmd, sizeof(ppp_cmd_t))) | ||
669 | return -EFAULT; | ||
670 | len = mbox->cmd.length; | ||
671 | |||
672 | if (len && u_data && copy_to_user(u_data, (void*)&mbox->data, len)) | ||
673 | return -EFAULT; | ||
674 | |||
675 | return 0; | ||
676 | } | ||
677 | |||
678 | /****** Network Device Interface ********************************************/ | ||
679 | |||
680 | /*============================================================================ | ||
681 | * Initialize Linux network interface. | ||
682 | * | ||
683 | * This routine is called only once for each interface, during Linux network | ||
684 | * interface registration. Returning anything but zero will fail interface | ||
685 | * registration. | ||
686 | */ | ||
687 | static int if_init(struct net_device *dev) | ||
688 | { | ||
689 | ppp_private_area_t *ppp_priv_area = dev->priv; | ||
690 | sdla_t *card = ppp_priv_area->card; | ||
691 | struct wan_device *wandev = &card->wandev; | ||
692 | |||
693 | /* Initialize device driver entry points */ | ||
694 | dev->open = &if_open; | ||
695 | dev->stop = &if_close; | ||
696 | dev->hard_header = &if_header; | ||
697 | dev->rebuild_header = &if_rebuild_hdr; | ||
698 | dev->hard_start_xmit = &if_send; | ||
699 | dev->get_stats = &if_stats; | ||
700 | dev->tx_timeout = &if_tx_timeout; | ||
701 | dev->watchdog_timeo = TX_TIMEOUT; | ||
702 | |||
703 | /* Initialize media-specific parameters */ | ||
704 | dev->type = ARPHRD_PPP; /* ARP h/w type */ | ||
705 | dev->flags |= IFF_POINTOPOINT; | ||
706 | dev->flags |= IFF_NOARP; | ||
707 | |||
708 | /* Enable Mulitcasting if specified by user*/ | ||
709 | if (ppp_priv_area->mc == WANOPT_YES){ | ||
710 | dev->flags |= IFF_MULTICAST; | ||
711 | } | ||
712 | |||
713 | dev->mtu = wandev->mtu; | ||
714 | dev->hard_header_len = PPP_HDR_LEN; /* media header length */ | ||
715 | |||
716 | /* Initialize hardware parameters (just for reference) */ | ||
717 | dev->irq = wandev->irq; | ||
718 | dev->dma = wandev->dma; | ||
719 | dev->base_addr = wandev->ioport; | ||
720 | dev->mem_start = wandev->maddr; | ||
721 | dev->mem_end = wandev->maddr + wandev->msize - 1; | ||
722 | |||
723 | /* Set transmit buffer queue length */ | ||
724 | dev->tx_queue_len = 100; | ||
725 | SET_MODULE_OWNER(dev); | ||
726 | |||
727 | return 0; | ||
728 | } | ||
729 | |||
730 | /*============================================================================ | ||
731 | * Open network interface. | ||
732 | * o enable communications and interrupts. | ||
733 | * o prevent module from unloading by incrementing use count | ||
734 | * | ||
735 | * Return 0 if O.k. or errno. | ||
736 | */ | ||
737 | static int if_open(struct net_device *dev) | ||
738 | { | ||
739 | ppp_private_area_t *ppp_priv_area = dev->priv; | ||
740 | sdla_t *card = ppp_priv_area->card; | ||
741 | struct timeval tv; | ||
742 | //unsigned long smp_flags; | ||
743 | |||
744 | if (netif_running(dev)) | ||
745 | return -EBUSY; | ||
746 | |||
747 | wanpipe_open(card); | ||
748 | |||
749 | netif_start_queue(dev); | ||
750 | |||
751 | do_gettimeofday( &tv ); | ||
752 | ppp_priv_area->router_start_time = tv.tv_sec; | ||
753 | |||
754 | /* We cannot configure the card here because we don't | ||
755 | * have access to the interface IP addresses. | ||
756 | * Once the interface initilization is complete, we will be | ||
757 | * able to access the IP addresses. Therefore, | ||
758 | * configure the ppp link in the poll routine */ | ||
759 | set_bit(0,&ppp_priv_area->config_ppp); | ||
760 | ppp_priv_area->config_wait_timeout=jiffies; | ||
761 | |||
762 | /* Start the PPP configuration after 1sec delay. | ||
763 | * This will give the interface initilization time | ||
764 | * to finish its configuration */ | ||
765 | mod_timer(&ppp_priv_area->poll_delay_timer, jiffies + HZ); | ||
766 | return 0; | ||
767 | } | ||
768 | |||
769 | /*============================================================================ | ||
770 | * Close network interface. | ||
771 | * o if this is the last open, then disable communications and interrupts. | ||
772 | * o reset flags. | ||
773 | */ | ||
774 | static int if_close(struct net_device *dev) | ||
775 | { | ||
776 | ppp_private_area_t *ppp_priv_area = dev->priv; | ||
777 | sdla_t *card = ppp_priv_area->card; | ||
778 | |||
779 | netif_stop_queue(dev); | ||
780 | wanpipe_close(card); | ||
781 | |||
782 | del_timer (&ppp_priv_area->poll_delay_timer); | ||
783 | return 0; | ||
784 | } | ||
785 | |||
786 | /*============================================================================ | ||
787 | * Build media header. | ||
788 | * | ||
789 | * The trick here is to put packet type (Ethertype) into 'protocol' field of | ||
790 | * the socket buffer, so that we don't forget it. If packet type is not | ||
791 | * supported, set skb->protocol to 0 and discard packet later. | ||
792 | * | ||
793 | * Return: media header length. | ||
794 | */ | ||
795 | static int if_header(struct sk_buff *skb, struct net_device *dev, | ||
796 | unsigned short type, void *daddr, void *saddr, unsigned len) | ||
797 | { | ||
798 | switch (type) | ||
799 | { | ||
800 | case ETH_P_IP: | ||
801 | case ETH_P_IPX: | ||
802 | skb->protocol = htons(type); | ||
803 | break; | ||
804 | |||
805 | default: | ||
806 | skb->protocol = 0; | ||
807 | } | ||
808 | |||
809 | return PPP_HDR_LEN; | ||
810 | } | ||
811 | |||
812 | /*============================================================================ | ||
813 | * Re-build media header. | ||
814 | * | ||
815 | * Return: 1 physical address resolved. | ||
816 | * 0 physical address not resolved | ||
817 | */ | ||
818 | static int if_rebuild_hdr (struct sk_buff *skb) | ||
819 | { | ||
820 | struct net_device *dev = skb->dev; | ||
821 | ppp_private_area_t *ppp_priv_area = dev->priv; | ||
822 | sdla_t *card = ppp_priv_area->card; | ||
823 | |||
824 | printk(KERN_INFO "%s: rebuild_header() called for interface %s!\n", | ||
825 | card->devname, dev->name); | ||
826 | return 1; | ||
827 | } | ||
828 | |||
829 | /*============================================================================ | ||
830 | * Handle transmit timeout event from netif watchdog | ||
831 | */ | ||
832 | static void if_tx_timeout(struct net_device *dev) | ||
833 | { | ||
834 | ppp_private_area_t* chan = dev->priv; | ||
835 | sdla_t *card = chan->card; | ||
836 | |||
837 | /* If our device stays busy for at least 5 seconds then we will | ||
838 | * kick start the device by making dev->tbusy = 0. We expect | ||
839 | * that our device never stays busy more than 5 seconds. So this | ||
840 | * is only used as a last resort. | ||
841 | */ | ||
842 | |||
843 | ++ chan->if_send_stat.if_send_tbusy; | ||
844 | ++card->wandev.stats.collisions; | ||
845 | |||
846 | printk (KERN_INFO "%s: Transmit timed out on %s\n", card->devname,dev->name); | ||
847 | ++chan->if_send_stat.if_send_tbusy_timeout; | ||
848 | netif_wake_queue (dev); | ||
849 | } | ||
850 | |||
851 | |||
852 | |||
853 | /*============================================================================ | ||
854 | * Send a packet on a network interface. | ||
855 | * o set tbusy flag (marks start of the transmission) to block a timer-based | ||
856 | * transmit from overlapping. | ||
857 | * o check link state. If link is not up, then drop the packet. | ||
858 | * o execute adapter send command. | ||
859 | * o free socket buffer | ||
860 | * | ||
861 | * Return: 0 complete (socket buffer must be freed) | ||
862 | * non-0 packet may be re-transmitted (tbusy must be set) | ||
863 | * | ||
864 | * Notes: | ||
865 | * 1. This routine is called either by the protocol stack or by the "net | ||
866 | * bottom half" (with interrupts enabled). | ||
867 | * 2. Setting tbusy flag will inhibit further transmit requests from the | ||
868 | * protocol stack and can be used for flow control with protocol layer. | ||
869 | */ | ||
870 | static int if_send (struct sk_buff *skb, struct net_device *dev) | ||
871 | { | ||
872 | ppp_private_area_t *ppp_priv_area = dev->priv; | ||
873 | sdla_t *card = ppp_priv_area->card; | ||
874 | unsigned char *sendpacket; | ||
875 | unsigned long smp_flags; | ||
876 | ppp_flags_t *flags = card->flags; | ||
877 | int udp_type; | ||
878 | int err=0; | ||
879 | |||
880 | ++ppp_priv_area->if_send_stat.if_send_entry; | ||
881 | |||
882 | netif_stop_queue(dev); | ||
883 | |||
884 | if (skb == NULL) { | ||
885 | |||
886 | /* If we get here, some higher layer thinks we've missed an | ||
887 | * tx-done interrupt. | ||
888 | */ | ||
889 | printk(KERN_INFO "%s: interface %s got kicked!\n", | ||
890 | card->devname, dev->name); | ||
891 | |||
892 | ++ppp_priv_area->if_send_stat.if_send_skb_null; | ||
893 | |||
894 | netif_wake_queue(dev); | ||
895 | return 0; | ||
896 | } | ||
897 | |||
898 | sendpacket = skb->data; | ||
899 | |||
900 | udp_type = udp_pkt_type( skb, card ); | ||
901 | |||
902 | |||
903 | if (udp_type == UDP_PTPIPE_TYPE){ | ||
904 | if(store_udp_mgmt_pkt(UDP_PKT_FRM_STACK, card, skb, dev, | ||
905 | ppp_priv_area)){ | ||
906 | flags->imask |= PPP_INTR_TIMER; | ||
907 | } | ||
908 | ++ppp_priv_area->if_send_stat.if_send_PIPE_request; | ||
909 | netif_start_queue(dev); | ||
910 | return 0; | ||
911 | } | ||
912 | |||
913 | /* Check for broadcast and multicast addresses | ||
914 | * If found, drop (deallocate) a packet and return. | ||
915 | */ | ||
916 | if(chk_bcast_mcast_addr(card, dev, skb)){ | ||
917 | ++card->wandev.stats.tx_dropped; | ||
918 | dev_kfree_skb_any(skb); | ||
919 | netif_start_queue(dev); | ||
920 | return 0; | ||
921 | } | ||
922 | |||
923 | |||
924 | if(card->hw.type != SDLA_S514){ | ||
925 | s508_lock(card,&smp_flags); | ||
926 | } | ||
927 | |||
928 | if (test_and_set_bit(SEND_CRIT, (void*)&card->wandev.critical)) { | ||
929 | |||
930 | printk(KERN_INFO "%s: Critical in if_send: %lx\n", | ||
931 | card->wandev.name,card->wandev.critical); | ||
932 | |||
933 | ++card->wandev.stats.tx_dropped; | ||
934 | ++ppp_priv_area->if_send_stat.if_send_critical_non_ISR; | ||
935 | netif_start_queue(dev); | ||
936 | goto if_send_exit_crit; | ||
937 | } | ||
938 | |||
939 | if (card->wandev.state != WAN_CONNECTED) { | ||
940 | |||
941 | ++ppp_priv_area->if_send_stat.if_send_wan_disconnected; | ||
942 | ++card->wandev.stats.tx_dropped; | ||
943 | netif_start_queue(dev); | ||
944 | |||
945 | } else if (!skb->protocol) { | ||
946 | ++ppp_priv_area->if_send_stat.if_send_protocol_error; | ||
947 | ++card->wandev.stats.tx_errors; | ||
948 | netif_start_queue(dev); | ||
949 | |||
950 | } else { | ||
951 | |||
952 | /*If it's IPX change the network numbers to 0 if they're ours.*/ | ||
953 | if( skb->protocol == htons(ETH_P_IPX) ) { | ||
954 | if(ppp_priv_area->enable_IPX) { | ||
955 | switch_net_numbers( skb->data, | ||
956 | ppp_priv_area->network_number, 0); | ||
957 | } else { | ||
958 | ++card->wandev.stats.tx_dropped; | ||
959 | netif_start_queue(dev); | ||
960 | goto if_send_exit_crit; | ||
961 | } | ||
962 | } | ||
963 | |||
964 | if (ppp_send(card, skb->data, skb->len, skb->protocol)) { | ||
965 | netif_stop_queue(dev); | ||
966 | ++ppp_priv_area->if_send_stat.if_send_adptr_bfrs_full; | ||
967 | ++ppp_priv_area->if_send_stat.if_send_tx_int_enabled; | ||
968 | } else { | ||
969 | ++ppp_priv_area->if_send_stat.if_send_bfr_passed_to_adptr; | ||
970 | ++card->wandev.stats.tx_packets; | ||
971 | card->wandev.stats.tx_bytes += skb->len; | ||
972 | netif_start_queue(dev); | ||
973 | dev->trans_start = jiffies; | ||
974 | } | ||
975 | } | ||
976 | |||
977 | if_send_exit_crit: | ||
978 | |||
979 | if (!(err=netif_queue_stopped(dev))){ | ||
980 | dev_kfree_skb_any(skb); | ||
981 | }else{ | ||
982 | ppp_priv_area->tick_counter = jiffies; | ||
983 | flags->imask |= PPP_INTR_TXRDY; /* unmask Tx interrupts */ | ||
984 | } | ||
985 | |||
986 | clear_bit(SEND_CRIT,&card->wandev.critical); | ||
987 | if(card->hw.type != SDLA_S514){ | ||
988 | s508_unlock(card,&smp_flags); | ||
989 | } | ||
990 | |||
991 | return err; | ||
992 | } | ||
993 | |||
994 | |||
995 | /*============================================================================= | ||
996 | * Store a UDP management packet for later processing. | ||
997 | */ | ||
998 | |||
999 | static int store_udp_mgmt_pkt(char udp_pkt_src, sdla_t* card, | ||
1000 | struct sk_buff *skb, struct net_device* dev, | ||
1001 | ppp_private_area_t* ppp_priv_area ) | ||
1002 | { | ||
1003 | int udp_pkt_stored = 0; | ||
1004 | |||
1005 | if(!ppp_priv_area->udp_pkt_lgth && (skb->len<=MAX_LGTH_UDP_MGNT_PKT)){ | ||
1006 | ppp_priv_area->udp_pkt_lgth = skb->len; | ||
1007 | ppp_priv_area->udp_pkt_src = udp_pkt_src; | ||
1008 | memcpy(ppp_priv_area->udp_pkt_data, skb->data, skb->len); | ||
1009 | ppp_priv_area->timer_int_enabled |= TMR_INT_ENABLED_UDP; | ||
1010 | ppp_priv_area->protocol = skb->protocol; | ||
1011 | udp_pkt_stored = 1; | ||
1012 | }else{ | ||
1013 | if (skb->len > MAX_LGTH_UDP_MGNT_PKT){ | ||
1014 | printk(KERN_INFO "%s: PIPEMON UDP request too long : %i\n", | ||
1015 | card->devname, skb->len); | ||
1016 | }else{ | ||
1017 | printk(KERN_INFO "%s: PIPEMON UPD request already pending\n", | ||
1018 | card->devname); | ||
1019 | } | ||
1020 | ppp_priv_area->udp_pkt_lgth = 0; | ||
1021 | } | ||
1022 | |||
1023 | if(udp_pkt_src == UDP_PKT_FRM_STACK){ | ||
1024 | dev_kfree_skb_any(skb); | ||
1025 | }else{ | ||
1026 | dev_kfree_skb_any(skb); | ||
1027 | } | ||
1028 | |||
1029 | return(udp_pkt_stored); | ||
1030 | } | ||
1031 | |||
1032 | |||
1033 | |||
1034 | /*============================================================================ | ||
1035 | * Reply to UDP Management system. | ||
1036 | * Return length of reply. | ||
1037 | */ | ||
1038 | static int reply_udp( unsigned char *data, unsigned int mbox_len ) | ||
1039 | { | ||
1040 | unsigned short len, udp_length, temp, ip_length; | ||
1041 | unsigned long ip_temp; | ||
1042 | int even_bound = 0; | ||
1043 | ppp_udp_pkt_t *p_udp_pkt = (ppp_udp_pkt_t *)data; | ||
1044 | |||
1045 | /* Set length of packet */ | ||
1046 | len = sizeof(ip_pkt_t)+ | ||
1047 | sizeof(udp_pkt_t)+ | ||
1048 | sizeof(wp_mgmt_t)+ | ||
1049 | sizeof(cblock_t)+ | ||
1050 | mbox_len; | ||
1051 | |||
1052 | /* fill in UDP reply */ | ||
1053 | p_udp_pkt->wp_mgmt.request_reply = UDPMGMT_REPLY; | ||
1054 | |||
1055 | /* fill in UDP length */ | ||
1056 | udp_length = sizeof(udp_pkt_t)+ | ||
1057 | sizeof(wp_mgmt_t)+ | ||
1058 | sizeof(cblock_t)+ | ||
1059 | mbox_len; | ||
1060 | |||
1061 | |||
1062 | /* put it on an even boundary */ | ||
1063 | if ( udp_length & 0x0001 ) { | ||
1064 | udp_length += 1; | ||
1065 | len += 1; | ||
1066 | even_bound=1; | ||
1067 | } | ||
1068 | |||
1069 | temp = (udp_length<<8)|(udp_length>>8); | ||
1070 | p_udp_pkt->udp_pkt.udp_length = temp; | ||
1071 | |||
1072 | |||
1073 | /* swap UDP ports */ | ||
1074 | temp = p_udp_pkt->udp_pkt.udp_src_port; | ||
1075 | p_udp_pkt->udp_pkt.udp_src_port = | ||
1076 | p_udp_pkt->udp_pkt.udp_dst_port; | ||
1077 | p_udp_pkt->udp_pkt.udp_dst_port = temp; | ||
1078 | |||
1079 | |||
1080 | /* add UDP pseudo header */ | ||
1081 | temp = 0x1100; | ||
1082 | *((unsigned short *)(p_udp_pkt->data+mbox_len+even_bound)) = temp; | ||
1083 | temp = (udp_length<<8)|(udp_length>>8); | ||
1084 | *((unsigned short *)(p_udp_pkt->data+mbox_len+even_bound+2)) = temp; | ||
1085 | |||
1086 | /* calculate UDP checksum */ | ||
1087 | p_udp_pkt->udp_pkt.udp_checksum = 0; | ||
1088 | p_udp_pkt->udp_pkt.udp_checksum = | ||
1089 | calc_checksum(&data[UDP_OFFSET],udp_length+UDP_OFFSET); | ||
1090 | |||
1091 | /* fill in IP length */ | ||
1092 | ip_length = udp_length + sizeof(ip_pkt_t); | ||
1093 | temp = (ip_length<<8)|(ip_length>>8); | ||
1094 | p_udp_pkt->ip_pkt.total_length = temp; | ||
1095 | |||
1096 | /* swap IP addresses */ | ||
1097 | ip_temp = p_udp_pkt->ip_pkt.ip_src_address; | ||
1098 | p_udp_pkt->ip_pkt.ip_src_address = p_udp_pkt->ip_pkt.ip_dst_address; | ||
1099 | p_udp_pkt->ip_pkt.ip_dst_address = ip_temp; | ||
1100 | |||
1101 | /* fill in IP checksum */ | ||
1102 | p_udp_pkt->ip_pkt.hdr_checksum = 0; | ||
1103 | p_udp_pkt->ip_pkt.hdr_checksum = calc_checksum(data,sizeof(ip_pkt_t)); | ||
1104 | |||
1105 | return len; | ||
1106 | |||
1107 | } /* reply_udp */ | ||
1108 | |||
1109 | unsigned short calc_checksum (char *data, int len) | ||
1110 | { | ||
1111 | unsigned short temp; | ||
1112 | unsigned long sum=0; | ||
1113 | int i; | ||
1114 | |||
1115 | for( i = 0; i <len; i+=2 ) { | ||
1116 | memcpy(&temp,&data[i],2); | ||
1117 | sum += (unsigned long)temp; | ||
1118 | } | ||
1119 | |||
1120 | while (sum >> 16 ) { | ||
1121 | sum = (sum & 0xffffUL) + (sum >> 16); | ||
1122 | } | ||
1123 | |||
1124 | temp = (unsigned short)sum; | ||
1125 | temp = ~temp; | ||
1126 | |||
1127 | if( temp == 0 ) | ||
1128 | temp = 0xffff; | ||
1129 | |||
1130 | return temp; | ||
1131 | } | ||
1132 | |||
1133 | /* | ||
1134 | If incoming is 0 (outgoing)- if the net numbers is ours make it 0 | ||
1135 | if incoming is 1 - if the net number is 0 make it ours | ||
1136 | |||
1137 | */ | ||
1138 | static void switch_net_numbers(unsigned char *sendpacket, unsigned long network_number, unsigned char incoming) | ||
1139 | { | ||
1140 | unsigned long pnetwork_number; | ||
1141 | |||
1142 | pnetwork_number = (unsigned long)((sendpacket[6] << 24) + | ||
1143 | (sendpacket[7] << 16) + (sendpacket[8] << 8) + | ||
1144 | sendpacket[9]); | ||
1145 | |||
1146 | if (!incoming) { | ||
1147 | //If the destination network number is ours, make it 0 | ||
1148 | if( pnetwork_number == network_number) { | ||
1149 | sendpacket[6] = sendpacket[7] = sendpacket[8] = | ||
1150 | sendpacket[9] = 0x00; | ||
1151 | } | ||
1152 | } else { | ||
1153 | //If the incoming network is 0, make it ours | ||
1154 | if( pnetwork_number == 0) { | ||
1155 | sendpacket[6] = (unsigned char)(network_number >> 24); | ||
1156 | sendpacket[7] = (unsigned char)((network_number & | ||
1157 | 0x00FF0000) >> 16); | ||
1158 | sendpacket[8] = (unsigned char)((network_number & | ||
1159 | 0x0000FF00) >> 8); | ||
1160 | sendpacket[9] = (unsigned char)(network_number & | ||
1161 | 0x000000FF); | ||
1162 | } | ||
1163 | } | ||
1164 | |||
1165 | |||
1166 | pnetwork_number = (unsigned long)((sendpacket[18] << 24) + | ||
1167 | (sendpacket[19] << 16) + (sendpacket[20] << 8) + | ||
1168 | sendpacket[21]); | ||
1169 | |||
1170 | if( !incoming ) { | ||
1171 | //If the source network is ours, make it 0 | ||
1172 | if( pnetwork_number == network_number) { | ||
1173 | sendpacket[18] = sendpacket[19] = sendpacket[20] = | ||
1174 | sendpacket[21] = 0x00; | ||
1175 | } | ||
1176 | } else { | ||
1177 | //If the source network is 0, make it ours | ||
1178 | if( pnetwork_number == 0 ) { | ||
1179 | sendpacket[18] = (unsigned char)(network_number >> 24); | ||
1180 | sendpacket[19] = (unsigned char)((network_number & | ||
1181 | 0x00FF0000) >> 16); | ||
1182 | sendpacket[20] = (unsigned char)((network_number & | ||
1183 | 0x0000FF00) >> 8); | ||
1184 | sendpacket[21] = (unsigned char)(network_number & | ||
1185 | 0x000000FF); | ||
1186 | } | ||
1187 | } | ||
1188 | } /* switch_net_numbers */ | ||
1189 | |||
1190 | /*============================================================================ | ||
1191 | * Get ethernet-style interface statistics. | ||
1192 | * Return a pointer to struct net_device_stats. | ||
1193 | */ | ||
1194 | static struct net_device_stats *if_stats(struct net_device *dev) | ||
1195 | { | ||
1196 | |||
1197 | ppp_private_area_t *ppp_priv_area = dev->priv; | ||
1198 | sdla_t* card; | ||
1199 | |||
1200 | if( ppp_priv_area == NULL ) | ||
1201 | return NULL; | ||
1202 | |||
1203 | card = ppp_priv_area->card; | ||
1204 | return &card->wandev.stats; | ||
1205 | } | ||
1206 | |||
1207 | /****** PPP Firmware Interface Functions ************************************/ | ||
1208 | |||
1209 | /*============================================================================ | ||
1210 | * Read firmware code version. | ||
1211 | * Put code version as ASCII string in str. | ||
1212 | */ | ||
1213 | static int ppp_read_version(sdla_t *card, char *str) | ||
1214 | { | ||
1215 | ppp_mbox_t *mb = card->mbox; | ||
1216 | int err; | ||
1217 | |||
1218 | memset(&mb->cmd, 0, sizeof(ppp_cmd_t)); | ||
1219 | mb->cmd.command = PPP_READ_CODE_VERSION; | ||
1220 | err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; | ||
1221 | |||
1222 | if (err != CMD_OK) | ||
1223 | |||
1224 | ppp_error(card, err, mb); | ||
1225 | |||
1226 | else if (str) { | ||
1227 | |||
1228 | int len = mb->cmd.length; | ||
1229 | |||
1230 | memcpy(str, mb->data, len); | ||
1231 | str[len] = '\0'; | ||
1232 | |||
1233 | } | ||
1234 | |||
1235 | return err; | ||
1236 | } | ||
1237 | /*=========================================================================== | ||
1238 | * Set Out-Bound Authentication. | ||
1239 | */ | ||
1240 | static int ppp_set_outbnd_auth (sdla_t *card, ppp_private_area_t *ppp_priv_area) | ||
1241 | { | ||
1242 | ppp_mbox_t *mb = card->mbox; | ||
1243 | int err; | ||
1244 | |||
1245 | memset(&mb->cmd, 0, sizeof(ppp_cmd_t)); | ||
1246 | memset(&mb->data, 0, (strlen(ppp_priv_area->userid) + | ||
1247 | strlen(ppp_priv_area->passwd) + 2 ) ); | ||
1248 | memcpy(mb->data, ppp_priv_area->userid, strlen(ppp_priv_area->userid)); | ||
1249 | memcpy((mb->data + strlen(ppp_priv_area->userid) + 1), | ||
1250 | ppp_priv_area->passwd, strlen(ppp_priv_area->passwd)); | ||
1251 | |||
1252 | mb->cmd.length = strlen(ppp_priv_area->userid) + | ||
1253 | strlen(ppp_priv_area->passwd) + 2 ; | ||
1254 | |||
1255 | mb->cmd.command = PPP_SET_OUTBOUND_AUTH; | ||
1256 | |||
1257 | err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; | ||
1258 | |||
1259 | if (err != CMD_OK) | ||
1260 | ppp_error(card, err, mb); | ||
1261 | |||
1262 | return err; | ||
1263 | } | ||
1264 | |||
1265 | /*=========================================================================== | ||
1266 | * Set In-Bound Authentication. | ||
1267 | */ | ||
1268 | static int ppp_set_inbnd_auth (sdla_t *card, ppp_private_area_t *ppp_priv_area) | ||
1269 | { | ||
1270 | ppp_mbox_t *mb = card->mbox; | ||
1271 | int err, i; | ||
1272 | char* user_tokens[32]; | ||
1273 | char* pass_tokens[32]; | ||
1274 | int userids, passwds; | ||
1275 | int add_ptr; | ||
1276 | |||
1277 | memset(&mb->cmd, 0, sizeof(ppp_cmd_t)); | ||
1278 | memset(&mb->data, 0, 1008); | ||
1279 | memcpy(mb->data, ppp_priv_area->sysname, | ||
1280 | strlen(ppp_priv_area->sysname)); | ||
1281 | |||
1282 | /* Parse the userid string and the password string and build a string | ||
1283 | to copy it to the data area of the command structure. The string | ||
1284 | will look like "SYS_NAME<NULL>USER1<NULL>PASS1<NULL>USER2<NULL>PASS2 | ||
1285 | ....<NULL> " | ||
1286 | */ | ||
1287 | userids = tokenize( ppp_priv_area->userid, user_tokens); | ||
1288 | passwds = tokenize( ppp_priv_area->passwd, pass_tokens); | ||
1289 | |||
1290 | if (userids != passwds){ | ||
1291 | printk(KERN_INFO "%s: Number of passwords does not equal the number of user ids\n", card->devname); | ||
1292 | return 1; | ||
1293 | } | ||
1294 | |||
1295 | add_ptr = strlen(ppp_priv_area->sysname) + 1; | ||
1296 | for (i=0; i<userids; i++){ | ||
1297 | memcpy((mb->data + add_ptr), user_tokens[i], | ||
1298 | strlen(user_tokens[i])); | ||
1299 | memcpy((mb->data + add_ptr + strlen(user_tokens[i]) + 1), | ||
1300 | pass_tokens[i], strlen(pass_tokens[i])); | ||
1301 | add_ptr = add_ptr + strlen(user_tokens[i]) + 1 + | ||
1302 | strlen(pass_tokens[i]) + 1; | ||
1303 | } | ||
1304 | |||
1305 | mb->cmd.length = add_ptr + 1; | ||
1306 | mb->cmd.command = PPP_SET_INBOUND_AUTH; | ||
1307 | |||
1308 | err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; | ||
1309 | |||
1310 | if (err != CMD_OK) | ||
1311 | ppp_error(card, err, mb); | ||
1312 | |||
1313 | return err; | ||
1314 | } | ||
1315 | |||
1316 | |||
1317 | /*============================================================================ | ||
1318 | * Tokenize string. | ||
1319 | * Parse a string of the following syntax: | ||
1320 | * <arg1>,<arg2>,... | ||
1321 | * and fill array of tokens with pointers to string elements. | ||
1322 | * | ||
1323 | */ | ||
1324 | static int tokenize (char *str, char **tokens) | ||
1325 | { | ||
1326 | int cnt = 0; | ||
1327 | |||
1328 | tokens[0] = strsep(&str, "/"); | ||
1329 | while (tokens[cnt] && (cnt < 32 - 1)) | ||
1330 | { | ||
1331 | tokens[cnt] = strstrip(tokens[cnt], " \t"); | ||
1332 | tokens[++cnt] = strsep(&str, "/"); | ||
1333 | } | ||
1334 | return cnt; | ||
1335 | } | ||
1336 | |||
1337 | /*============================================================================ | ||
1338 | * Strip leading and trailing spaces off the string str. | ||
1339 | */ | ||
1340 | static char* strstrip (char *str, char* s) | ||
1341 | { | ||
1342 | char *eos = str + strlen(str); /* -> end of string */ | ||
1343 | |||
1344 | while (*str && strchr(s, *str)) | ||
1345 | ++str /* strip leading spaces */ | ||
1346 | ; | ||
1347 | while ((eos > str) && strchr(s, *(eos - 1))) | ||
1348 | --eos /* strip trailing spaces */ | ||
1349 | ; | ||
1350 | *eos = '\0'; | ||
1351 | return str; | ||
1352 | } | ||
1353 | /*============================================================================ | ||
1354 | * Configure PPP firmware. | ||
1355 | */ | ||
1356 | static int ppp_configure(sdla_t *card, void *data) | ||
1357 | { | ||
1358 | ppp_mbox_t *mb = card->mbox; | ||
1359 | int data_len = sizeof(ppp508_conf_t); | ||
1360 | int err; | ||
1361 | |||
1362 | memset(&mb->cmd, 0, sizeof(ppp_cmd_t)); | ||
1363 | memcpy(mb->data, data, data_len); | ||
1364 | mb->cmd.length = data_len; | ||
1365 | mb->cmd.command = PPP_SET_CONFIG; | ||
1366 | err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; | ||
1367 | |||
1368 | if (err != CMD_OK) | ||
1369 | ppp_error(card, err, mb); | ||
1370 | |||
1371 | return err; | ||
1372 | } | ||
1373 | |||
1374 | /*============================================================================ | ||
1375 | * Set interrupt mode. | ||
1376 | */ | ||
1377 | static int ppp_set_intr_mode(sdla_t *card, unsigned char mode) | ||
1378 | { | ||
1379 | ppp_mbox_t *mb = card->mbox; | ||
1380 | ppp_intr_info_t *ppp_intr_data = (ppp_intr_info_t *) &mb->data[0]; | ||
1381 | int err; | ||
1382 | |||
1383 | memset(&mb->cmd, 0, sizeof(ppp_cmd_t)); | ||
1384 | ppp_intr_data->i_enable = mode; | ||
1385 | |||
1386 | ppp_intr_data->irq = card->hw.irq; | ||
1387 | mb->cmd.length = 2; | ||
1388 | |||
1389 | /* If timer has been enabled, set the timer delay to 1sec */ | ||
1390 | if (mode & 0x80){ | ||
1391 | ppp_intr_data->timer_len = 250; //5;//100; //250; | ||
1392 | mb->cmd.length = 4; | ||
1393 | } | ||
1394 | |||
1395 | mb->cmd.command = PPP_SET_INTR_FLAGS; | ||
1396 | err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; | ||
1397 | |||
1398 | if (err != CMD_OK) | ||
1399 | ppp_error(card, err, mb); | ||
1400 | |||
1401 | |||
1402 | return err; | ||
1403 | } | ||
1404 | |||
1405 | /*============================================================================ | ||
1406 | * Enable communications. | ||
1407 | */ | ||
1408 | static int ppp_comm_enable(sdla_t *card) | ||
1409 | { | ||
1410 | ppp_mbox_t *mb = card->mbox; | ||
1411 | int err; | ||
1412 | |||
1413 | memset(&mb->cmd, 0, sizeof(ppp_cmd_t)); | ||
1414 | mb->cmd.command = PPP_COMM_ENABLE; | ||
1415 | err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; | ||
1416 | |||
1417 | if (err != CMD_OK) | ||
1418 | ppp_error(card, err, mb); | ||
1419 | else | ||
1420 | card->u.p.comm_enabled = 1; | ||
1421 | |||
1422 | return err; | ||
1423 | } | ||
1424 | |||
1425 | /*============================================================================ | ||
1426 | * Disable communications. | ||
1427 | */ | ||
1428 | static int ppp_comm_disable(sdla_t *card) | ||
1429 | { | ||
1430 | ppp_mbox_t *mb = card->mbox; | ||
1431 | int err; | ||
1432 | |||
1433 | memset(&mb->cmd, 0, sizeof(ppp_cmd_t)); | ||
1434 | mb->cmd.command = PPP_COMM_DISABLE; | ||
1435 | err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; | ||
1436 | if (err != CMD_OK) | ||
1437 | ppp_error(card, err, mb); | ||
1438 | else | ||
1439 | card->u.p.comm_enabled = 0; | ||
1440 | |||
1441 | return err; | ||
1442 | } | ||
1443 | |||
1444 | static int ppp_comm_disable_shutdown(sdla_t *card) | ||
1445 | { | ||
1446 | ppp_mbox_t *mb = card->mbox; | ||
1447 | ppp_intr_info_t *ppp_intr_data; | ||
1448 | int err; | ||
1449 | |||
1450 | if (!mb){ | ||
1451 | return 1; | ||
1452 | } | ||
1453 | |||
1454 | ppp_intr_data = (ppp_intr_info_t *) &mb->data[0]; | ||
1455 | |||
1456 | /* Disable all interrupts */ | ||
1457 | memset(&mb->cmd, 0, sizeof(ppp_cmd_t)); | ||
1458 | ppp_intr_data->i_enable = 0; | ||
1459 | |||
1460 | ppp_intr_data->irq = card->hw.irq; | ||
1461 | mb->cmd.length = 2; | ||
1462 | |||
1463 | mb->cmd.command = PPP_SET_INTR_FLAGS; | ||
1464 | err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; | ||
1465 | |||
1466 | /* Disable communicatinons */ | ||
1467 | memset(&mb->cmd, 0, sizeof(ppp_cmd_t)); | ||
1468 | mb->cmd.command = PPP_COMM_DISABLE; | ||
1469 | err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; | ||
1470 | |||
1471 | card->u.p.comm_enabled = 0; | ||
1472 | |||
1473 | return 0; | ||
1474 | } | ||
1475 | |||
1476 | |||
1477 | |||
1478 | /*============================================================================ | ||
1479 | * Get communications error statistics. | ||
1480 | */ | ||
1481 | static int ppp_get_err_stats(sdla_t *card) | ||
1482 | { | ||
1483 | ppp_mbox_t *mb = card->mbox; | ||
1484 | int err; | ||
1485 | |||
1486 | memset(&mb->cmd, 0, sizeof(ppp_cmd_t)); | ||
1487 | mb->cmd.command = PPP_READ_ERROR_STATS; | ||
1488 | err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; | ||
1489 | |||
1490 | if (err == CMD_OK) { | ||
1491 | |||
1492 | ppp_err_stats_t* stats = (void*)mb->data; | ||
1493 | card->wandev.stats.rx_over_errors = stats->rx_overrun; | ||
1494 | card->wandev.stats.rx_crc_errors = stats->rx_bad_crc; | ||
1495 | card->wandev.stats.rx_missed_errors = stats->rx_abort; | ||
1496 | card->wandev.stats.rx_length_errors = stats->rx_lost; | ||
1497 | card->wandev.stats.tx_aborted_errors = stats->tx_abort; | ||
1498 | |||
1499 | } else | ||
1500 | ppp_error(card, err, mb); | ||
1501 | |||
1502 | return err; | ||
1503 | } | ||
1504 | |||
1505 | /*============================================================================ | ||
1506 | * Send packet. | ||
1507 | * Return: 0 - o.k. | ||
1508 | * 1 - no transmit buffers available | ||
1509 | */ | ||
1510 | static int ppp_send (sdla_t *card, void *data, unsigned len, unsigned proto) | ||
1511 | { | ||
1512 | ppp_buf_ctl_t *txbuf = card->u.p.txbuf; | ||
1513 | |||
1514 | if (txbuf->flag) | ||
1515 | return 1; | ||
1516 | |||
1517 | sdla_poke(&card->hw, txbuf->buf.ptr, data, len); | ||
1518 | |||
1519 | txbuf->length = len; /* frame length */ | ||
1520 | |||
1521 | if (proto == htons(ETH_P_IPX)) | ||
1522 | txbuf->proto = 0x01; /* protocol ID */ | ||
1523 | else | ||
1524 | txbuf->proto = 0x00; /* protocol ID */ | ||
1525 | |||
1526 | txbuf->flag = 1; /* start transmission */ | ||
1527 | |||
1528 | /* Update transmit buffer control fields */ | ||
1529 | card->u.p.txbuf = ++txbuf; | ||
1530 | |||
1531 | if ((void*)txbuf > card->u.p.txbuf_last) | ||
1532 | card->u.p.txbuf = card->u.p.txbuf_base; | ||
1533 | |||
1534 | return 0; | ||
1535 | } | ||
1536 | |||
1537 | /****** Firmware Error Handler **********************************************/ | ||
1538 | |||
1539 | /*============================================================================ | ||
1540 | * Firmware error handler. | ||
1541 | * This routine is called whenever firmware command returns non-zero | ||
1542 | * return code. | ||
1543 | * | ||
1544 | * Return zero if previous command has to be cancelled. | ||
1545 | */ | ||
1546 | static int ppp_error(sdla_t *card, int err, ppp_mbox_t *mb) | ||
1547 | { | ||
1548 | unsigned cmd = mb->cmd.command; | ||
1549 | |||
1550 | switch (err) { | ||
1551 | |||
1552 | case CMD_TIMEOUT: | ||
1553 | printk(KERN_ERR "%s: command 0x%02X timed out!\n", | ||
1554 | card->devname, cmd); | ||
1555 | break; | ||
1556 | |||
1557 | default: | ||
1558 | printk(KERN_INFO "%s: command 0x%02X returned 0x%02X!\n" | ||
1559 | , card->devname, cmd, err); | ||
1560 | } | ||
1561 | |||
1562 | return 0; | ||
1563 | } | ||
1564 | |||
1565 | /****** Interrupt Handlers **************************************************/ | ||
1566 | |||
1567 | /*============================================================================ | ||
1568 | * PPP interrupt service routine. | ||
1569 | */ | ||
1570 | static void wpp_isr (sdla_t *card) | ||
1571 | { | ||
1572 | ppp_flags_t *flags = card->flags; | ||
1573 | char *ptr = &flags->iflag; | ||
1574 | struct net_device *dev = card->wandev.dev; | ||
1575 | int i; | ||
1576 | |||
1577 | card->in_isr = 1; | ||
1578 | ++card->statistics.isr_entry; | ||
1579 | |||
1580 | if (!dev && flags->iflag != PPP_INTR_CMD){ | ||
1581 | card->in_isr = 0; | ||
1582 | flags->iflag = 0; | ||
1583 | return; | ||
1584 | } | ||
1585 | |||
1586 | if (test_bit(PERI_CRIT, (void*)&card->wandev.critical)) { | ||
1587 | card->in_isr = 0; | ||
1588 | flags->iflag = 0; | ||
1589 | return; | ||
1590 | } | ||
1591 | |||
1592 | |||
1593 | if(card->hw.type != SDLA_S514){ | ||
1594 | if (test_bit(SEND_CRIT, (void*)&card->wandev.critical)) { | ||
1595 | ++card->statistics.isr_already_critical; | ||
1596 | printk (KERN_INFO "%s: Critical while in ISR!\n", | ||
1597 | card->devname); | ||
1598 | card->in_isr = 0; | ||
1599 | flags->iflag = 0; | ||
1600 | return; | ||
1601 | } | ||
1602 | } | ||
1603 | |||
1604 | switch (flags->iflag) { | ||
1605 | |||
1606 | case PPP_INTR_RXRDY: /* receive interrupt 0x01 (bit 0)*/ | ||
1607 | ++card->statistics.isr_rx; | ||
1608 | rx_intr(card); | ||
1609 | break; | ||
1610 | |||
1611 | case PPP_INTR_TXRDY: /* transmit interrupt 0x02 (bit 1)*/ | ||
1612 | ++card->statistics.isr_tx; | ||
1613 | flags->imask &= ~PPP_INTR_TXRDY; | ||
1614 | netif_wake_queue(dev); | ||
1615 | break; | ||
1616 | |||
1617 | case PPP_INTR_CMD: /* interface command completed */ | ||
1618 | ++Intr_test_counter; | ||
1619 | ++card->statistics.isr_intr_test; | ||
1620 | break; | ||
1621 | |||
1622 | case PPP_INTR_MODEM: /* modem status change (DCD, CTS) 0x04 (bit 2)*/ | ||
1623 | case PPP_INTR_DISC: /* Data link disconnected 0x10 (bit 4)*/ | ||
1624 | case PPP_INTR_OPEN: /* Data link open 0x20 (bit 5)*/ | ||
1625 | case PPP_INTR_DROP_DTR: /* DTR drop timeout expired 0x40 bit 6 */ | ||
1626 | event_intr(card); | ||
1627 | break; | ||
1628 | |||
1629 | case PPP_INTR_TIMER: | ||
1630 | timer_intr(card); | ||
1631 | break; | ||
1632 | |||
1633 | default: /* unexpected interrupt */ | ||
1634 | ++card->statistics.isr_spurious; | ||
1635 | printk(KERN_INFO "%s: spurious interrupt 0x%02X!\n", | ||
1636 | card->devname, flags->iflag); | ||
1637 | printk(KERN_INFO "%s: ID Bytes = ",card->devname); | ||
1638 | for(i = 0; i < 8; i ++) | ||
1639 | printk(KERN_INFO "0x%02X ", *(ptr + 0x28 + i)); | ||
1640 | printk(KERN_INFO "\n"); | ||
1641 | } | ||
1642 | |||
1643 | card->in_isr = 0; | ||
1644 | flags->iflag = 0; | ||
1645 | return; | ||
1646 | } | ||
1647 | |||
1648 | /*============================================================================ | ||
1649 | * Receive interrupt handler. | ||
1650 | */ | ||
1651 | static void rx_intr(sdla_t *card) | ||
1652 | { | ||
1653 | ppp_buf_ctl_t *rxbuf = card->rxmb; | ||
1654 | struct net_device *dev = card->wandev.dev; | ||
1655 | ppp_private_area_t *ppp_priv_area; | ||
1656 | struct sk_buff *skb; | ||
1657 | unsigned len; | ||
1658 | void *buf; | ||
1659 | int i; | ||
1660 | ppp_flags_t *flags = card->flags; | ||
1661 | char *ptr = &flags->iflag; | ||
1662 | int udp_type; | ||
1663 | |||
1664 | |||
1665 | if (rxbuf->flag != 0x01) { | ||
1666 | |||
1667 | printk(KERN_INFO | ||
1668 | "%s: corrupted Rx buffer @ 0x%X, flag = 0x%02X!\n", | ||
1669 | card->devname, (unsigned)rxbuf, rxbuf->flag); | ||
1670 | |||
1671 | printk(KERN_INFO "%s: ID Bytes = ",card->devname); | ||
1672 | |||
1673 | for(i = 0; i < 8; i ++) | ||
1674 | printk(KERN_INFO "0x%02X ", *(ptr + 0x28 + i)); | ||
1675 | printk(KERN_INFO "\n"); | ||
1676 | |||
1677 | ++card->statistics.rx_intr_corrupt_rx_bfr; | ||
1678 | |||
1679 | |||
1680 | /* Bug Fix: Mar 6 2000 | ||
1681 | * If we get a corrupted mailbox, it means that driver | ||
1682 | * is out of sync with the firmware. There is no recovery. | ||
1683 | * If we don't turn off all interrupts for this card | ||
1684 | * the machine will crash. | ||
1685 | */ | ||
1686 | printk(KERN_INFO "%s: Critical router failure ...!!!\n", card->devname); | ||
1687 | printk(KERN_INFO "Please contact Sangoma Technologies !\n"); | ||
1688 | ppp_set_intr_mode(card,0); | ||
1689 | return; | ||
1690 | } | ||
1691 | |||
1692 | if (dev && netif_running(dev) && dev->priv){ | ||
1693 | |||
1694 | len = rxbuf->length; | ||
1695 | ppp_priv_area = dev->priv; | ||
1696 | |||
1697 | /* Allocate socket buffer */ | ||
1698 | skb = dev_alloc_skb(len); | ||
1699 | |||
1700 | if (skb != NULL) { | ||
1701 | |||
1702 | /* Copy data to the socket buffer */ | ||
1703 | unsigned addr = rxbuf->buf.ptr; | ||
1704 | |||
1705 | if ((addr + len) > card->u.p.rx_top + 1) { | ||
1706 | |||
1707 | unsigned tmp = card->u.p.rx_top - addr + 1; | ||
1708 | buf = skb_put(skb, tmp); | ||
1709 | sdla_peek(&card->hw, addr, buf, tmp); | ||
1710 | addr = card->u.p.rx_base; | ||
1711 | len -= tmp; | ||
1712 | } | ||
1713 | buf = skb_put(skb, len); | ||
1714 | sdla_peek(&card->hw, addr, buf, len); | ||
1715 | |||
1716 | /* Decapsulate packet */ | ||
1717 | switch (rxbuf->proto) { | ||
1718 | |||
1719 | case 0x00: | ||
1720 | skb->protocol = htons(ETH_P_IP); | ||
1721 | break; | ||
1722 | |||
1723 | case 0x01: | ||
1724 | skb->protocol = htons(ETH_P_IPX); | ||
1725 | break; | ||
1726 | } | ||
1727 | |||
1728 | udp_type = udp_pkt_type( skb, card ); | ||
1729 | |||
1730 | if (udp_type == UDP_PTPIPE_TYPE){ | ||
1731 | |||
1732 | /* Handle a UDP Request in Timer Interrupt */ | ||
1733 | if(store_udp_mgmt_pkt(UDP_PKT_FRM_NETWORK, card, skb, dev, | ||
1734 | ppp_priv_area)){ | ||
1735 | flags->imask |= PPP_INTR_TIMER; | ||
1736 | } | ||
1737 | ++ppp_priv_area->rx_intr_stat.rx_intr_PIPE_request; | ||
1738 | |||
1739 | |||
1740 | } else if (handle_IPXWAN(skb->data,card->devname, | ||
1741 | ppp_priv_area->enable_IPX, | ||
1742 | ppp_priv_area->network_number, | ||
1743 | skb->protocol)) { | ||
1744 | |||
1745 | /* Handle an IPXWAN packet */ | ||
1746 | if( ppp_priv_area->enable_IPX) { | ||
1747 | |||
1748 | /* Make sure we are not already sending */ | ||
1749 | if (!test_bit(SEND_CRIT, &card->wandev.critical)){ | ||
1750 | ppp_send(card, skb->data, skb->len, htons(ETH_P_IPX)); | ||
1751 | } | ||
1752 | dev_kfree_skb_any(skb); | ||
1753 | |||
1754 | } else { | ||
1755 | ++card->wandev.stats.rx_dropped; | ||
1756 | } | ||
1757 | } else { | ||
1758 | /* Pass data up the protocol stack */ | ||
1759 | skb->dev = dev; | ||
1760 | skb->mac.raw = skb->data; | ||
1761 | |||
1762 | ++card->wandev.stats.rx_packets; | ||
1763 | card->wandev.stats.rx_bytes += skb->len; | ||
1764 | ++ppp_priv_area->rx_intr_stat.rx_intr_bfr_passed_to_stack; | ||
1765 | netif_rx(skb); | ||
1766 | dev->last_rx = jiffies; | ||
1767 | } | ||
1768 | |||
1769 | } else { | ||
1770 | |||
1771 | if (net_ratelimit()){ | ||
1772 | printk(KERN_INFO "%s: no socket buffers available!\n", | ||
1773 | card->devname); | ||
1774 | } | ||
1775 | ++card->wandev.stats.rx_dropped; | ||
1776 | ++ppp_priv_area->rx_intr_stat.rx_intr_no_socket; | ||
1777 | } | ||
1778 | |||
1779 | } else { | ||
1780 | ++card->statistics.rx_intr_dev_not_started; | ||
1781 | } | ||
1782 | |||
1783 | /* Release buffer element and calculate a pointer to the next one */ | ||
1784 | rxbuf->flag = 0x00; | ||
1785 | card->rxmb = ++rxbuf; | ||
1786 | if ((void*)rxbuf > card->u.p.rxbuf_last) | ||
1787 | card->rxmb = card->u.p.rxbuf_base; | ||
1788 | } | ||
1789 | |||
1790 | |||
1791 | void event_intr (sdla_t *card) | ||
1792 | { | ||
1793 | |||
1794 | struct net_device* dev = card->wandev.dev; | ||
1795 | ppp_private_area_t* ppp_priv_area = dev->priv; | ||
1796 | volatile ppp_flags_t *flags = card->flags; | ||
1797 | |||
1798 | switch (flags->iflag){ | ||
1799 | |||
1800 | case PPP_INTR_MODEM: /* modem status change (DCD, CTS) 0x04 (bit 2)*/ | ||
1801 | |||
1802 | if (net_ratelimit()){ | ||
1803 | printk (KERN_INFO "%s: Modem status: DCD=%s CTS=%s\n", | ||
1804 | card->devname, DCD(flags->mstatus), CTS(flags->mstatus)); | ||
1805 | } | ||
1806 | break; | ||
1807 | |||
1808 | case PPP_INTR_DISC: /* Data link disconnected 0x10 (bit 4)*/ | ||
1809 | |||
1810 | NEX_PRINTK (KERN_INFO "Data link disconnected intr Cause %X\n", | ||
1811 | flags->disc_cause); | ||
1812 | |||
1813 | if (flags->disc_cause & | ||
1814 | (PPP_LOCAL_TERMINATION | PPP_DCD_CTS_DROP | | ||
1815 | PPP_REMOTE_TERMINATION)) { | ||
1816 | |||
1817 | if (card->u.p.ip_mode == WANOPT_PPP_PEER) { | ||
1818 | set_bit(0,&Read_connection_info); | ||
1819 | } | ||
1820 | wanpipe_set_state(card, WAN_DISCONNECTED); | ||
1821 | |||
1822 | show_disc_cause(card, flags->disc_cause); | ||
1823 | ppp_priv_area->timer_int_enabled |= TMR_INT_ENABLED_PPP_EVENT; | ||
1824 | flags->imask |= PPP_INTR_TIMER; | ||
1825 | trigger_ppp_poll(dev); | ||
1826 | } | ||
1827 | break; | ||
1828 | |||
1829 | case PPP_INTR_OPEN: /* Data link open 0x20 (bit 5)*/ | ||
1830 | |||
1831 | NEX_PRINTK (KERN_INFO "%s: PPP Link Open, LCP=%s IP=%s\n", | ||
1832 | card->devname,LCP(flags->lcp_state), | ||
1833 | IP(flags->ip_state)); | ||
1834 | |||
1835 | if (flags->lcp_state == 0x09 && | ||
1836 | (flags->ip_state == 0x09 || flags->ipx_state == 0x09)){ | ||
1837 | |||
1838 | /* Initialize the polling timer and set the state | ||
1839 | * to WAN_CONNNECTED */ | ||
1840 | |||
1841 | |||
1842 | /* BUG FIX: When the protocol restarts, during heavy | ||
1843 | * traffic, board tx buffers and driver tx buffers | ||
1844 | * can go out of sync. This checks the condition | ||
1845 | * and if the tx buffers are out of sync, the | ||
1846 | * protocols are restarted. | ||
1847 | * I don't know why the board tx buffer is out | ||
1848 | * of sync. It could be that a packets is tx | ||
1849 | * while the link is down, but that is not | ||
1850 | * possible. The other possiblility is that the | ||
1851 | * firmware doesn't reinitialize properly. | ||
1852 | * FIXME: A better fix should be found. | ||
1853 | */ | ||
1854 | if (detect_and_fix_tx_bug(card)){ | ||
1855 | |||
1856 | ppp_comm_disable(card); | ||
1857 | |||
1858 | wanpipe_set_state(card, WAN_DISCONNECTED); | ||
1859 | |||
1860 | ppp_priv_area->timer_int_enabled |= | ||
1861 | TMR_INT_ENABLED_PPP_EVENT; | ||
1862 | flags->imask |= PPP_INTR_TIMER; | ||
1863 | break; | ||
1864 | } | ||
1865 | |||
1866 | card->state_tick = jiffies; | ||
1867 | wanpipe_set_state(card, WAN_CONNECTED); | ||
1868 | |||
1869 | NEX_PRINTK(KERN_INFO "CON: L Tx: %lx B Tx: %lx || L Rx %lx B Rx %lx\n", | ||
1870 | (unsigned long)card->u.p.txbuf, *card->u.p.txbuf_next, | ||
1871 | (unsigned long)card->rxmb, *card->u.p.rxbuf_next); | ||
1872 | |||
1873 | /* Tell timer interrupt that PPP event occurred */ | ||
1874 | ppp_priv_area->timer_int_enabled |= TMR_INT_ENABLED_PPP_EVENT; | ||
1875 | flags->imask |= PPP_INTR_TIMER; | ||
1876 | |||
1877 | /* If we are in PEER mode, we must first obtain the | ||
1878 | * IP information and then go into the poll routine */ | ||
1879 | if (card->u.p.ip_mode != WANOPT_PPP_PEER){ | ||
1880 | trigger_ppp_poll(dev); | ||
1881 | } | ||
1882 | } | ||
1883 | break; | ||
1884 | |||
1885 | case PPP_INTR_DROP_DTR: /* DTR drop timeout expired 0x40 bit 6 */ | ||
1886 | |||
1887 | NEX_PRINTK(KERN_INFO "DTR Drop Timeout Interrrupt \n"); | ||
1888 | |||
1889 | if (card->u.p.ip_mode == WANOPT_PPP_PEER) { | ||
1890 | set_bit(0,&Read_connection_info); | ||
1891 | } | ||
1892 | |||
1893 | wanpipe_set_state(card, WAN_DISCONNECTED); | ||
1894 | |||
1895 | show_disc_cause(card, flags->disc_cause); | ||
1896 | ppp_priv_area->timer_int_enabled |= TMR_INT_ENABLED_PPP_EVENT; | ||
1897 | flags->imask |= PPP_INTR_TIMER; | ||
1898 | trigger_ppp_poll(dev); | ||
1899 | break; | ||
1900 | |||
1901 | default: | ||
1902 | printk(KERN_INFO "%s: Error, Invalid PPP Event\n",card->devname); | ||
1903 | } | ||
1904 | } | ||
1905 | |||
1906 | |||
1907 | |||
1908 | /* TIMER INTERRUPT */ | ||
1909 | |||
1910 | void timer_intr (sdla_t *card) | ||
1911 | { | ||
1912 | |||
1913 | struct net_device* dev = card->wandev.dev; | ||
1914 | ppp_private_area_t* ppp_priv_area = dev->priv; | ||
1915 | ppp_flags_t *flags = card->flags; | ||
1916 | |||
1917 | |||
1918 | if (ppp_priv_area->timer_int_enabled & TMR_INT_ENABLED_CONFIG){ | ||
1919 | if (!config_ppp(card)){ | ||
1920 | ppp_priv_area->timer_int_enabled &= | ||
1921 | ~TMR_INT_ENABLED_CONFIG; | ||
1922 | } | ||
1923 | } | ||
1924 | |||
1925 | /* Update statistics */ | ||
1926 | if (ppp_priv_area->timer_int_enabled & TMR_INT_ENABLED_UPDATE){ | ||
1927 | ppp_get_err_stats(card); | ||
1928 | if(!(--ppp_priv_area->update_comms_stats)){ | ||
1929 | ppp_priv_area->timer_int_enabled &= | ||
1930 | ~TMR_INT_ENABLED_UPDATE; | ||
1931 | } | ||
1932 | } | ||
1933 | |||
1934 | /* PPIPEMON UDP request */ | ||
1935 | |||
1936 | if (ppp_priv_area->timer_int_enabled & TMR_INT_ENABLED_UDP){ | ||
1937 | process_udp_mgmt_pkt(card,dev, ppp_priv_area); | ||
1938 | ppp_priv_area->timer_int_enabled &= ~TMR_INT_ENABLED_UDP; | ||
1939 | } | ||
1940 | |||
1941 | /* PPP Event */ | ||
1942 | if (ppp_priv_area->timer_int_enabled & TMR_INT_ENABLED_PPP_EVENT){ | ||
1943 | |||
1944 | if (card->wandev.state == WAN_DISCONNECTED){ | ||
1945 | retrigger_comm(card); | ||
1946 | } | ||
1947 | |||
1948 | /* If the state is CONNECTING, it means that communicatins were | ||
1949 | * enabled. When the remote side enables its comminication we | ||
1950 | * should get an interrupt PPP_INTR_OPEN, thus turn off polling | ||
1951 | */ | ||
1952 | |||
1953 | else if (card->wandev.state == WAN_CONNECTING){ | ||
1954 | /* Turn off the timer interrupt */ | ||
1955 | ppp_priv_area->timer_int_enabled &= ~TMR_INT_ENABLED_PPP_EVENT; | ||
1956 | } | ||
1957 | |||
1958 | /* If state is connected and we are in PEER mode | ||
1959 | * poll for an IP address which will be provided by remote end. | ||
1960 | */ | ||
1961 | else if ((card->wandev.state == WAN_CONNECTED && | ||
1962 | card->u.p.ip_mode == WANOPT_PPP_PEER) && | ||
1963 | test_bit(0,&Read_connection_info)){ | ||
1964 | |||
1965 | card->state_tick = jiffies; | ||
1966 | if (read_connection_info (card)){ | ||
1967 | printk(KERN_INFO "%s: Failed to read PEER IP Addresses\n", | ||
1968 | card->devname); | ||
1969 | }else{ | ||
1970 | clear_bit(0,&Read_connection_info); | ||
1971 | set_bit(1,&Read_connection_info); | ||
1972 | trigger_ppp_poll(dev); | ||
1973 | } | ||
1974 | }else{ | ||
1975 | //FIXME Put the comment back int | ||
1976 | ppp_priv_area->timer_int_enabled &= ~TMR_INT_ENABLED_PPP_EVENT; | ||
1977 | } | ||
1978 | |||
1979 | }/* End of PPP_EVENT */ | ||
1980 | |||
1981 | |||
1982 | /* Only disable the timer interrupt if there are no udp, statistic */ | ||
1983 | /* updates or events pending */ | ||
1984 | if(!ppp_priv_area->timer_int_enabled) { | ||
1985 | flags->imask &= ~PPP_INTR_TIMER; | ||
1986 | } | ||
1987 | } | ||
1988 | |||
1989 | |||
1990 | static int handle_IPXWAN(unsigned char *sendpacket, char *devname, unsigned char enable_IPX, unsigned long network_number, unsigned short proto) | ||
1991 | { | ||
1992 | int i; | ||
1993 | |||
1994 | if( proto == htons(ETH_P_IPX) ) { | ||
1995 | //It's an IPX packet | ||
1996 | if(!enable_IPX) { | ||
1997 | //Return 1 so we don't pass it up the stack. | ||
1998 | return 1; | ||
1999 | } | ||
2000 | } else { | ||
2001 | //It's not IPX so pass it up the stack. | ||
2002 | return 0; | ||
2003 | } | ||
2004 | |||
2005 | if( sendpacket[16] == 0x90 && | ||
2006 | sendpacket[17] == 0x04) | ||
2007 | { | ||
2008 | //It's IPXWAN | ||
2009 | |||
2010 | if( sendpacket[2] == 0x02 && | ||
2011 | sendpacket[34] == 0x00) | ||
2012 | { | ||
2013 | //It's a timer request packet | ||
2014 | printk(KERN_INFO "%s: Received IPXWAN Timer Request packet\n",devname); | ||
2015 | |||
2016 | //Go through the routing options and answer no to every | ||
2017 | //option except Unnumbered RIP/SAP | ||
2018 | for(i = 41; sendpacket[i] == 0x00; i += 5) | ||
2019 | { | ||
2020 | //0x02 is the option for Unnumbered RIP/SAP | ||
2021 | if( sendpacket[i + 4] != 0x02) | ||
2022 | { | ||
2023 | sendpacket[i + 1] = 0; | ||
2024 | } | ||
2025 | } | ||
2026 | |||
2027 | //Skip over the extended Node ID option | ||
2028 | if( sendpacket[i] == 0x04 ) | ||
2029 | { | ||
2030 | i += 8; | ||
2031 | } | ||
2032 | |||
2033 | //We also want to turn off all header compression opt. | ||
2034 | for(; sendpacket[i] == 0x80 ;) | ||
2035 | { | ||
2036 | sendpacket[i + 1] = 0; | ||
2037 | i += (sendpacket[i + 2] << 8) + (sendpacket[i + 3]) + 4; | ||
2038 | } | ||
2039 | |||
2040 | //Set the packet type to timer response | ||
2041 | sendpacket[34] = 0x01; | ||
2042 | |||
2043 | printk(KERN_INFO "%s: Sending IPXWAN Timer Response\n",devname); | ||
2044 | } | ||
2045 | else if( sendpacket[34] == 0x02 ) | ||
2046 | { | ||
2047 | //This is an information request packet | ||
2048 | printk(KERN_INFO "%s: Received IPXWAN Information Request packet\n",devname); | ||
2049 | |||
2050 | //Set the packet type to information response | ||
2051 | sendpacket[34] = 0x03; | ||
2052 | |||
2053 | //Set the router name | ||
2054 | sendpacket[51] = 'P'; | ||
2055 | sendpacket[52] = 'T'; | ||
2056 | sendpacket[53] = 'P'; | ||
2057 | sendpacket[54] = 'I'; | ||
2058 | sendpacket[55] = 'P'; | ||
2059 | sendpacket[56] = 'E'; | ||
2060 | sendpacket[57] = '-'; | ||
2061 | sendpacket[58] = CVHexToAscii(network_number >> 28); | ||
2062 | sendpacket[59] = CVHexToAscii((network_number & 0x0F000000)>> 24); | ||
2063 | sendpacket[60] = CVHexToAscii((network_number & 0x00F00000)>> 20); | ||
2064 | sendpacket[61] = CVHexToAscii((network_number & 0x000F0000)>> 16); | ||
2065 | sendpacket[62] = CVHexToAscii((network_number & 0x0000F000)>> 12); | ||
2066 | sendpacket[63] = CVHexToAscii((network_number & 0x00000F00)>> 8); | ||
2067 | sendpacket[64] = CVHexToAscii((network_number & 0x000000F0)>> 4); | ||
2068 | sendpacket[65] = CVHexToAscii(network_number & 0x0000000F); | ||
2069 | for(i = 66; i < 99; i+= 1) | ||
2070 | { | ||
2071 | sendpacket[i] = 0; | ||
2072 | } | ||
2073 | |||
2074 | printk(KERN_INFO "%s: Sending IPXWAN Information Response packet\n",devname); | ||
2075 | } | ||
2076 | else | ||
2077 | { | ||
2078 | printk(KERN_INFO "%s: Unknown IPXWAN packet!\n",devname); | ||
2079 | return 0; | ||
2080 | } | ||
2081 | |||
2082 | //Set the WNodeID to our network address | ||
2083 | sendpacket[35] = (unsigned char)(network_number >> 24); | ||
2084 | sendpacket[36] = (unsigned char)((network_number & 0x00FF0000) >> 16); | ||
2085 | sendpacket[37] = (unsigned char)((network_number & 0x0000FF00) >> 8); | ||
2086 | sendpacket[38] = (unsigned char)(network_number & 0x000000FF); | ||
2087 | |||
2088 | return 1; | ||
2089 | } else { | ||
2090 | //If we get here it's an IPX-data packet, so it'll get passed up the stack. | ||
2091 | |||
2092 | //switch the network numbers | ||
2093 | switch_net_numbers(sendpacket, network_number, 1); | ||
2094 | return 0; | ||
2095 | } | ||
2096 | } | ||
2097 | |||
2098 | /****** Background Polling Routines ****************************************/ | ||
2099 | |||
2100 | /* All polling functions are invoked by the TIMER interrupt in the wpp_isr | ||
2101 | * routine. | ||
2102 | */ | ||
2103 | |||
2104 | /*============================================================================ | ||
2105 | * Monitor active link phase. | ||
2106 | */ | ||
2107 | static void process_route (sdla_t *card) | ||
2108 | { | ||
2109 | ppp_flags_t *flags = card->flags; | ||
2110 | struct net_device *dev = card->wandev.dev; | ||
2111 | ppp_private_area_t *ppp_priv_area = dev->priv; | ||
2112 | |||
2113 | if ((card->u.p.ip_mode == WANOPT_PPP_PEER) && | ||
2114 | (flags->ip_state == 0x09)){ | ||
2115 | |||
2116 | /* We get ip_local from the firmware in PEER mode. | ||
2117 | * Therefore, if ip_local is 0, we failed to obtain | ||
2118 | * the remote IP address. */ | ||
2119 | if (ppp_priv_area->ip_local == 0) | ||
2120 | return; | ||
2121 | |||
2122 | printk(KERN_INFO "%s: IPCP State Opened.\n", card->devname); | ||
2123 | if (read_info( card )) { | ||
2124 | printk(KERN_INFO | ||
2125 | "%s: An error occurred in IP assignment.\n", | ||
2126 | card->devname); | ||
2127 | } else { | ||
2128 | struct in_device *in_dev = dev->ip_ptr; | ||
2129 | if (in_dev != NULL ) { | ||
2130 | struct in_ifaddr *ifa = in_dev->ifa_list; | ||
2131 | |||
2132 | printk(KERN_INFO "%s: Assigned Lcl. Addr: %u.%u.%u.%u\n", | ||
2133 | card->devname, NIPQUAD(ifa->ifa_local)); | ||
2134 | printk(KERN_INFO "%s: Assigned Rmt. Addr: %u.%u.%u.%u\n", | ||
2135 | card->devname, NIPQUAD(ifa->ifa_address)); | ||
2136 | }else{ | ||
2137 | printk(KERN_INFO | ||
2138 | "%s: Error: Failed to add a route for PPP interface %s\n", | ||
2139 | card->devname,dev->name); | ||
2140 | } | ||
2141 | } | ||
2142 | } | ||
2143 | } | ||
2144 | |||
2145 | /*============================================================================ | ||
2146 | * Monitor physical link disconnected phase. | ||
2147 | * o if interface is up and the hold-down timeout has expired, then retry | ||
2148 | * connection. | ||
2149 | */ | ||
2150 | static void retrigger_comm(sdla_t *card) | ||
2151 | { | ||
2152 | struct net_device *dev = card->wandev.dev; | ||
2153 | |||
2154 | if (dev && ((jiffies - card->state_tick) > HOLD_DOWN_TIME)) { | ||
2155 | |||
2156 | wanpipe_set_state(card, WAN_CONNECTING); | ||
2157 | |||
2158 | if(ppp_comm_enable(card) == CMD_OK){ | ||
2159 | init_ppp_tx_rx_buff( card ); | ||
2160 | } | ||
2161 | } | ||
2162 | } | ||
2163 | |||
2164 | /****** Miscellaneous Functions *********************************************/ | ||
2165 | |||
2166 | /*============================================================================ | ||
2167 | * Configure S508 adapter. | ||
2168 | */ | ||
2169 | static int config508(struct net_device *dev, sdla_t *card) | ||
2170 | { | ||
2171 | ppp508_conf_t cfg; | ||
2172 | struct in_device *in_dev = dev->ip_ptr; | ||
2173 | ppp_private_area_t *ppp_priv_area = dev->priv; | ||
2174 | |||
2175 | /* Prepare PPP configuration structure */ | ||
2176 | memset(&cfg, 0, sizeof(ppp508_conf_t)); | ||
2177 | |||
2178 | if (card->wandev.clocking) | ||
2179 | cfg.line_speed = card->wandev.bps; | ||
2180 | |||
2181 | if (card->wandev.interface == WANOPT_RS232) | ||
2182 | cfg.conf_flags |= INTERFACE_LEVEL_RS232; | ||
2183 | |||
2184 | |||
2185 | cfg.conf_flags |= DONT_TERMINATE_LNK_MAX_CONFIG; /*send Configure-Request packets forever*/ | ||
2186 | cfg.txbuf_percent = PERCENT_TX_BUFF; /* % of Tx bufs */ | ||
2187 | cfg.mtu_local = card->wandev.mtu; | ||
2188 | cfg.mtu_remote = card->wandev.mtu; /* Default */ | ||
2189 | cfg.restart_tmr = TIME_BETWEEN_CONF_REQ; /* 30 = 3sec */ | ||
2190 | cfg.auth_rsrt_tmr = TIME_BETWEEN_PAP_CHAP_REQ; /* 30 = 3sec */ | ||
2191 | cfg.auth_wait_tmr = WAIT_PAP_CHAP_WITHOUT_REPLY; /* 300 = 30s */ | ||
2192 | cfg.mdm_fail_tmr = WAIT_AFTER_DCD_CTS_LOW; /* 5 = 0.5s */ | ||
2193 | cfg.dtr_drop_tmr = TIME_DCD_CTS_LOW_AFTER_LNK_DOWN; /* 10 = 1s */ | ||
2194 | cfg.connect_tmout = WAIT_DCD_HIGH_AFTER_ENABLE_COMM; /* 900 = 90s */ | ||
2195 | cfg.conf_retry = MAX_CONF_REQ_WITHOUT_REPLY; /* 10 = 1s */ | ||
2196 | cfg.term_retry = MAX_TERM_REQ_WITHOUT_REPLY; /* 2 times */ | ||
2197 | cfg.fail_retry = NUM_CONF_NAK_WITHOUT_REPLY; /* 5 times */ | ||
2198 | cfg.auth_retry = NUM_AUTH_REQ_WITHOUT_REPLY; /* 10 times */ | ||
2199 | |||
2200 | |||
2201 | if( !card->u.p.authenticator ) { | ||
2202 | printk(KERN_INFO "%s: Device is not configured as an authenticator\n", | ||
2203 | card->devname); | ||
2204 | cfg.auth_options = NO_AUTHENTICATION; | ||
2205 | }else{ | ||
2206 | printk(KERN_INFO "%s: Device is configured as an authenticator\n", | ||
2207 | card->devname); | ||
2208 | cfg.auth_options = INBOUND_AUTH; | ||
2209 | } | ||
2210 | |||
2211 | if( ppp_priv_area->pap == WANOPT_YES){ | ||
2212 | cfg.auth_options |=PAP_AUTH; | ||
2213 | printk(KERN_INFO "%s: Pap enabled\n", card->devname); | ||
2214 | } | ||
2215 | if( ppp_priv_area->chap == WANOPT_YES){ | ||
2216 | cfg.auth_options |= CHAP_AUTH; | ||
2217 | printk(KERN_INFO "%s: Chap enabled\n", card->devname); | ||
2218 | } | ||
2219 | |||
2220 | |||
2221 | if (ppp_priv_area->enable_IPX == WANOPT_YES){ | ||
2222 | printk(KERN_INFO "%s: Enabling IPX Protocol\n",card->devname); | ||
2223 | cfg.ipx_options = ENABLE_IPX | ROUTING_PROT_DEFAULT; | ||
2224 | }else{ | ||
2225 | cfg.ipx_options = DISABLE_IPX; | ||
2226 | } | ||
2227 | |||
2228 | switch (card->u.p.ip_mode) { | ||
2229 | |||
2230 | case WANOPT_PPP_STATIC: | ||
2231 | |||
2232 | printk(KERN_INFO "%s: PPP IP Mode: STATIC\n",card->devname); | ||
2233 | cfg.ip_options = L_AND_R_IP_NO_ASSIG | | ||
2234 | ENABLE_IP; | ||
2235 | cfg.ip_local = in_dev->ifa_list->ifa_local; | ||
2236 | cfg.ip_remote = in_dev->ifa_list->ifa_address; | ||
2237 | /* Debugging code used to check that IP addresses | ||
2238 | * obtained from the kernel are correct */ | ||
2239 | |||
2240 | NEX_PRINTK(KERN_INFO "Local %u.%u.%u.%u Remote %u.%u.%u.%u Name %s\n", | ||
2241 | NIPQUAD(ip_local),NIPQUAD(ip_remote), dev->name); | ||
2242 | break; | ||
2243 | |||
2244 | case WANOPT_PPP_HOST: | ||
2245 | |||
2246 | printk(KERN_INFO "%s: PPP IP Mode: HOST\n",card->devname); | ||
2247 | cfg.ip_options = L_IP_LOCAL_ASSIG | | ||
2248 | R_IP_LOCAL_ASSIG | | ||
2249 | ENABLE_IP; | ||
2250 | cfg.ip_local = in_dev->ifa_list->ifa_local; | ||
2251 | cfg.ip_remote = in_dev->ifa_list->ifa_address; | ||
2252 | /* Debugging code used to check that IP addresses | ||
2253 | * obtained from the kernel are correct */ | ||
2254 | NEX_PRINTK (KERN_INFO "Local %u.%u.%u.%u Remote %u.%u.%u.%u Name %s\n", | ||
2255 | NIPQUAD(ip_local),NIPQUAD(ip_remote), dev->name); | ||
2256 | |||
2257 | break; | ||
2258 | |||
2259 | case WANOPT_PPP_PEER: | ||
2260 | |||
2261 | printk(KERN_INFO "%s: PPP IP Mode: PEER\n",card->devname); | ||
2262 | cfg.ip_options = L_IP_REMOTE_ASSIG | | ||
2263 | R_IP_REMOTE_ASSIG | | ||
2264 | ENABLE_IP; | ||
2265 | cfg.ip_local = 0x00; | ||
2266 | cfg.ip_remote = 0x00; | ||
2267 | break; | ||
2268 | |||
2269 | default: | ||
2270 | printk(KERN_INFO "%s: ERROR: Unsupported PPP Mode Selected\n", | ||
2271 | card->devname); | ||
2272 | printk(KERN_INFO "%s: PPP IP Modes: STATIC, PEER or HOST\n", | ||
2273 | card->devname); | ||
2274 | return 1; | ||
2275 | } | ||
2276 | |||
2277 | return ppp_configure(card, &cfg); | ||
2278 | } | ||
2279 | |||
2280 | /*============================================================================ | ||
2281 | * Show disconnection cause. | ||
2282 | */ | ||
2283 | static void show_disc_cause(sdla_t *card, unsigned cause) | ||
2284 | { | ||
2285 | if (cause & 0x0802) | ||
2286 | |||
2287 | printk(KERN_INFO "%s: link terminated by peer\n", | ||
2288 | card->devname); | ||
2289 | |||
2290 | else if (cause & 0x0004) | ||
2291 | |||
2292 | printk(KERN_INFO "%s: link terminated by user\n", | ||
2293 | card->devname); | ||
2294 | |||
2295 | else if (cause & 0x0008) | ||
2296 | |||
2297 | printk(KERN_INFO "%s: authentication failed\n", card->devname); | ||
2298 | |||
2299 | else if (cause & 0x0010) | ||
2300 | |||
2301 | printk(KERN_INFO | ||
2302 | "%s: authentication protocol negotiation failed\n", | ||
2303 | card->devname); | ||
2304 | |||
2305 | else if (cause & 0x0020) | ||
2306 | |||
2307 | printk(KERN_INFO | ||
2308 | "%s: peer's request for authentication rejected\n", | ||
2309 | card->devname); | ||
2310 | |||
2311 | else if (cause & 0x0040) | ||
2312 | |||
2313 | printk(KERN_INFO "%s: MRU option rejected by peer\n", | ||
2314 | card->devname); | ||
2315 | |||
2316 | else if (cause & 0x0080) | ||
2317 | |||
2318 | printk(KERN_INFO "%s: peer's MRU was too small\n", | ||
2319 | card->devname); | ||
2320 | |||
2321 | else if (cause & 0x0100) | ||
2322 | |||
2323 | printk(KERN_INFO "%s: failed to negotiate peer's LCP options\n", | ||
2324 | card->devname); | ||
2325 | |||
2326 | else if (cause & 0x0200) | ||
2327 | |||
2328 | printk(KERN_INFO "%s: failed to negotiate peer's IPCP options\n" | ||
2329 | , card->devname); | ||
2330 | |||
2331 | else if (cause & 0x0400) | ||
2332 | |||
2333 | printk(KERN_INFO | ||
2334 | "%s: failed to negotiate peer's IPXCP options\n", | ||
2335 | card->devname); | ||
2336 | } | ||
2337 | |||
2338 | /*============================================================================= | ||
2339 | * Process UDP call of type PTPIPEAB. | ||
2340 | */ | ||
2341 | static void process_udp_mgmt_pkt(sdla_t *card, struct net_device *dev, | ||
2342 | ppp_private_area_t *ppp_priv_area ) | ||
2343 | { | ||
2344 | unsigned char buf2[5]; | ||
2345 | unsigned char *buf; | ||
2346 | unsigned int frames, len; | ||
2347 | struct sk_buff *new_skb; | ||
2348 | unsigned short data_length, buffer_length, real_len; | ||
2349 | unsigned long data_ptr; | ||
2350 | int udp_mgmt_req_valid = 1; | ||
2351 | ppp_mbox_t *mbox = card->mbox; | ||
2352 | struct timeval tv; | ||
2353 | int err; | ||
2354 | ppp_udp_pkt_t *ppp_udp_pkt = (ppp_udp_pkt_t*)&ppp_priv_area->udp_pkt_data; | ||
2355 | |||
2356 | memcpy(&buf2, &card->wandev.udp_port, 2 ); | ||
2357 | |||
2358 | |||
2359 | if(ppp_priv_area->udp_pkt_src == UDP_PKT_FRM_NETWORK) { | ||
2360 | |||
2361 | switch(ppp_udp_pkt->cblock.command) { | ||
2362 | |||
2363 | case PPIPE_GET_IBA_DATA: | ||
2364 | case PPP_READ_CONFIG: | ||
2365 | case PPP_GET_CONNECTION_INFO: | ||
2366 | case PPIPE_ROUTER_UP_TIME: | ||
2367 | case PPP_READ_STATISTICS: | ||
2368 | case PPP_READ_ERROR_STATS: | ||
2369 | case PPP_READ_PACKET_STATS: | ||
2370 | case PPP_READ_LCP_STATS: | ||
2371 | case PPP_READ_IPCP_STATS: | ||
2372 | case PPP_READ_IPXCP_STATS: | ||
2373 | case PPP_READ_PAP_STATS: | ||
2374 | case PPP_READ_CHAP_STATS: | ||
2375 | case PPP_READ_CODE_VERSION: | ||
2376 | udp_mgmt_req_valid = 1; | ||
2377 | break; | ||
2378 | |||
2379 | default: | ||
2380 | udp_mgmt_req_valid = 0; | ||
2381 | break; | ||
2382 | } | ||
2383 | } | ||
2384 | |||
2385 | if(!udp_mgmt_req_valid) { | ||
2386 | |||
2387 | /* set length to 0 */ | ||
2388 | ppp_udp_pkt->cblock.length = 0x00; | ||
2389 | |||
2390 | /* set return code */ | ||
2391 | ppp_udp_pkt->cblock.result = 0xCD; | ||
2392 | ++ppp_priv_area->pipe_mgmt_stat.UDP_PIPE_mgmt_direction_err; | ||
2393 | |||
2394 | if (net_ratelimit()){ | ||
2395 | printk(KERN_INFO | ||
2396 | "%s: Warning, Illegal UDP command attempted from network: %x\n", | ||
2397 | card->devname,ppp_udp_pkt->cblock.command); | ||
2398 | } | ||
2399 | } else { | ||
2400 | /* Initialize the trace element */ | ||
2401 | trace_element_t trace_element; | ||
2402 | |||
2403 | switch (ppp_udp_pkt->cblock.command){ | ||
2404 | |||
2405 | /* PPIPE_ENABLE_TRACING */ | ||
2406 | case PPIPE_ENABLE_TRACING: | ||
2407 | if (!card->TracingEnabled) { | ||
2408 | |||
2409 | /* OPERATE_DATALINE_MONITOR */ | ||
2410 | mbox->cmd.command = PPP_DATALINE_MONITOR; | ||
2411 | mbox->cmd.length = 0x01; | ||
2412 | mbox->data[0] = ppp_udp_pkt->data[0]; | ||
2413 | err = sdla_exec(mbox) ? | ||
2414 | mbox->cmd.result : CMD_TIMEOUT; | ||
2415 | |||
2416 | if (err != CMD_OK) { | ||
2417 | |||
2418 | ppp_error(card, err, mbox); | ||
2419 | card->TracingEnabled = 0; | ||
2420 | |||
2421 | /* set the return code */ | ||
2422 | |||
2423 | ppp_udp_pkt->cblock.result = mbox->cmd.result; | ||
2424 | mbox->cmd.length = 0; | ||
2425 | break; | ||
2426 | } | ||
2427 | |||
2428 | sdla_peek(&card->hw, 0xC000, &buf2, 2); | ||
2429 | |||
2430 | ppp_priv_area->curr_trace_addr = 0; | ||
2431 | memcpy(&ppp_priv_area->curr_trace_addr, &buf2, 2); | ||
2432 | ppp_priv_area->start_trace_addr = | ||
2433 | ppp_priv_area->curr_trace_addr; | ||
2434 | ppp_priv_area->end_trace_addr = | ||
2435 | ppp_priv_area->start_trace_addr + END_OFFSET; | ||
2436 | |||
2437 | /* MAX_SEND_BUFFER_SIZE - 28 (IP header) | ||
2438 | - 32 (ppipemon CBLOCK) */ | ||
2439 | available_buffer_space = MAX_LGTH_UDP_MGNT_PKT - | ||
2440 | sizeof(ip_pkt_t)- | ||
2441 | sizeof(udp_pkt_t)- | ||
2442 | sizeof(wp_mgmt_t)- | ||
2443 | sizeof(cblock_t); | ||
2444 | } | ||
2445 | ppp_udp_pkt->cblock.result = 0; | ||
2446 | mbox->cmd.length = 0; | ||
2447 | card->TracingEnabled = 1; | ||
2448 | break; | ||
2449 | |||
2450 | /* PPIPE_DISABLE_TRACING */ | ||
2451 | case PPIPE_DISABLE_TRACING: | ||
2452 | |||
2453 | if(card->TracingEnabled) { | ||
2454 | |||
2455 | /* OPERATE_DATALINE_MONITOR */ | ||
2456 | mbox->cmd.command = 0x33; | ||
2457 | mbox->cmd.length = 1; | ||
2458 | mbox->data[0] = 0x00; | ||
2459 | err = sdla_exec(mbox) ? | ||
2460 | mbox->cmd.result : CMD_TIMEOUT; | ||
2461 | |||
2462 | } | ||
2463 | |||
2464 | /*set return code*/ | ||
2465 | ppp_udp_pkt->cblock.result = 0; | ||
2466 | mbox->cmd.length = 0; | ||
2467 | card->TracingEnabled = 0; | ||
2468 | break; | ||
2469 | |||
2470 | /* PPIPE_GET_TRACE_INFO */ | ||
2471 | case PPIPE_GET_TRACE_INFO: | ||
2472 | |||
2473 | if(!card->TracingEnabled) { | ||
2474 | /* set return code */ | ||
2475 | ppp_udp_pkt->cblock.result = 1; | ||
2476 | mbox->cmd.length = 0; | ||
2477 | } | ||
2478 | |||
2479 | buffer_length = 0; | ||
2480 | |||
2481 | /* frames < 62, where 62 is the number of trace | ||
2482 | information elements. There is in total 496 | ||
2483 | bytes of space and each trace information | ||
2484 | element is 8 bytes. | ||
2485 | */ | ||
2486 | for ( frames=0; frames<62; frames++) { | ||
2487 | |||
2488 | trace_pkt_t *trace_pkt = (trace_pkt_t *) | ||
2489 | &ppp_udp_pkt->data[buffer_length]; | ||
2490 | |||
2491 | /* Read the whole trace packet */ | ||
2492 | sdla_peek(&card->hw, ppp_priv_area->curr_trace_addr, | ||
2493 | &trace_element, sizeof(trace_element_t)); | ||
2494 | |||
2495 | /* no data on board so exit */ | ||
2496 | if( trace_element.opp_flag == 0x00 ) | ||
2497 | break; | ||
2498 | |||
2499 | data_ptr = trace_element.trace_data_ptr; | ||
2500 | |||
2501 | /* See if there is actual data on the trace buffer */ | ||
2502 | if (data_ptr){ | ||
2503 | data_length = trace_element.trace_length; | ||
2504 | }else{ | ||
2505 | data_length = 0; | ||
2506 | ppp_udp_pkt->data[0] |= 0x02; | ||
2507 | } | ||
2508 | |||
2509 | //FIXME: Do we need this check | ||
2510 | if ((available_buffer_space - buffer_length) | ||
2511 | < (sizeof(trace_element_t)+1)){ | ||
2512 | |||
2513 | /*indicate we have more frames | ||
2514 | * on board and exit | ||
2515 | */ | ||
2516 | ppp_udp_pkt->data[0] |= 0x02; | ||
2517 | break; | ||
2518 | } | ||
2519 | |||
2520 | trace_pkt->status = trace_element.trace_type; | ||
2521 | trace_pkt->time_stamp = trace_element.trace_time_stamp; | ||
2522 | trace_pkt->real_length = trace_element.trace_length; | ||
2523 | |||
2524 | real_len = trace_element.trace_length; | ||
2525 | |||
2526 | if(data_ptr == 0){ | ||
2527 | trace_pkt->data_avail = 0x00; | ||
2528 | }else{ | ||
2529 | /* we can take it next time */ | ||
2530 | if ((available_buffer_space - buffer_length)< | ||
2531 | (real_len + sizeof(trace_pkt_t))){ | ||
2532 | |||
2533 | ppp_udp_pkt->data[0] |= 0x02; | ||
2534 | break; | ||
2535 | } | ||
2536 | trace_pkt->data_avail = 0x01; | ||
2537 | |||
2538 | /* get the data */ | ||
2539 | sdla_peek(&card->hw, data_ptr, | ||
2540 | &trace_pkt->data, | ||
2541 | real_len); | ||
2542 | } | ||
2543 | /* zero the opp flag to | ||
2544 | show we got the frame */ | ||
2545 | buf2[0] = 0x00; | ||
2546 | sdla_poke(&card->hw, ppp_priv_area->curr_trace_addr, | ||
2547 | &buf2, 1); | ||
2548 | |||
2549 | /* now move onto the next | ||
2550 | frame */ | ||
2551 | ppp_priv_area->curr_trace_addr += 8; | ||
2552 | |||
2553 | /* check if we passed the last address */ | ||
2554 | if ( ppp_priv_area->curr_trace_addr >= | ||
2555 | ppp_priv_area->end_trace_addr){ | ||
2556 | |||
2557 | ppp_priv_area->curr_trace_addr = | ||
2558 | ppp_priv_area->start_trace_addr; | ||
2559 | } | ||
2560 | |||
2561 | /* update buffer length and make sure its even */ | ||
2562 | |||
2563 | if ( trace_pkt->data_avail == 0x01 ) { | ||
2564 | buffer_length += real_len - 1; | ||
2565 | } | ||
2566 | |||
2567 | /* for the header */ | ||
2568 | buffer_length += 8; | ||
2569 | |||
2570 | if( buffer_length & 0x0001 ) | ||
2571 | buffer_length += 1; | ||
2572 | } | ||
2573 | |||
2574 | /* ok now set the total number of frames passed | ||
2575 | in the high 5 bits */ | ||
2576 | ppp_udp_pkt->data[0] |= (frames << 2); | ||
2577 | |||
2578 | /* set the data length */ | ||
2579 | mbox->cmd.length = buffer_length; | ||
2580 | ppp_udp_pkt->cblock.length = buffer_length; | ||
2581 | |||
2582 | /* set return code */ | ||
2583 | ppp_udp_pkt->cblock.result = 0; | ||
2584 | break; | ||
2585 | |||
2586 | /* PPIPE_GET_IBA_DATA */ | ||
2587 | case PPIPE_GET_IBA_DATA: | ||
2588 | |||
2589 | mbox->cmd.length = 0x09; | ||
2590 | |||
2591 | sdla_peek(&card->hw, 0xF003, &ppp_udp_pkt->data, | ||
2592 | mbox->cmd.length); | ||
2593 | |||
2594 | /* set the length of the data */ | ||
2595 | ppp_udp_pkt->cblock.length = 0x09; | ||
2596 | |||
2597 | /* set return code */ | ||
2598 | ppp_udp_pkt->cblock.result = 0x00; | ||
2599 | ppp_udp_pkt->cblock.result = 0; | ||
2600 | break; | ||
2601 | |||
2602 | /* PPIPE_FT1_READ_STATUS */ | ||
2603 | case PPIPE_FT1_READ_STATUS: | ||
2604 | sdla_peek(&card->hw, 0xF020, &ppp_udp_pkt->data[0], 2); | ||
2605 | ppp_udp_pkt->cblock.length = mbox->cmd.length = 2; | ||
2606 | ppp_udp_pkt->cblock.result = 0; | ||
2607 | break; | ||
2608 | |||
2609 | case PPIPE_FLUSH_DRIVER_STATS: | ||
2610 | init_ppp_priv_struct( ppp_priv_area ); | ||
2611 | init_global_statistics( card ); | ||
2612 | mbox->cmd.length = 0; | ||
2613 | ppp_udp_pkt->cblock.result = 0; | ||
2614 | break; | ||
2615 | |||
2616 | |||
2617 | case PPIPE_ROUTER_UP_TIME: | ||
2618 | |||
2619 | do_gettimeofday( &tv ); | ||
2620 | ppp_priv_area->router_up_time = tv.tv_sec - | ||
2621 | ppp_priv_area->router_start_time; | ||
2622 | *(unsigned long *)&ppp_udp_pkt->data = ppp_priv_area->router_up_time; | ||
2623 | mbox->cmd.length = 4; | ||
2624 | ppp_udp_pkt->cblock.result = 0; | ||
2625 | break; | ||
2626 | |||
2627 | /* PPIPE_DRIVER_STATISTICS */ | ||
2628 | case PPIPE_DRIVER_STAT_IFSEND: | ||
2629 | memcpy(&ppp_udp_pkt->data, &ppp_priv_area->if_send_stat, | ||
2630 | sizeof(if_send_stat_t)); | ||
2631 | |||
2632 | |||
2633 | ppp_udp_pkt->cblock.result = 0; | ||
2634 | ppp_udp_pkt->cblock.length = sizeof(if_send_stat_t); | ||
2635 | mbox->cmd.length = sizeof(if_send_stat_t); | ||
2636 | break; | ||
2637 | |||
2638 | case PPIPE_DRIVER_STAT_INTR: | ||
2639 | memcpy(&ppp_udp_pkt->data, &card->statistics, | ||
2640 | sizeof(global_stats_t)); | ||
2641 | |||
2642 | memcpy(&ppp_udp_pkt->data+sizeof(global_stats_t), | ||
2643 | &ppp_priv_area->rx_intr_stat, | ||
2644 | sizeof(rx_intr_stat_t)); | ||
2645 | |||
2646 | ppp_udp_pkt->cblock.result = 0; | ||
2647 | ppp_udp_pkt->cblock.length = sizeof(global_stats_t)+ | ||
2648 | sizeof(rx_intr_stat_t); | ||
2649 | mbox->cmd.length = ppp_udp_pkt->cblock.length; | ||
2650 | break; | ||
2651 | |||
2652 | case PPIPE_DRIVER_STAT_GEN: | ||
2653 | memcpy( &ppp_udp_pkt->data, | ||
2654 | &ppp_priv_area->pipe_mgmt_stat, | ||
2655 | sizeof(pipe_mgmt_stat_t)); | ||
2656 | |||
2657 | memcpy(&ppp_udp_pkt->data+sizeof(pipe_mgmt_stat_t), | ||
2658 | &card->statistics, sizeof(global_stats_t)); | ||
2659 | |||
2660 | ppp_udp_pkt->cblock.result = 0; | ||
2661 | ppp_udp_pkt->cblock.length = sizeof(global_stats_t)+ | ||
2662 | sizeof(rx_intr_stat_t); | ||
2663 | mbox->cmd.length = ppp_udp_pkt->cblock.length; | ||
2664 | break; | ||
2665 | |||
2666 | |||
2667 | /* FT1 MONITOR STATUS */ | ||
2668 | case FT1_MONITOR_STATUS_CTRL: | ||
2669 | |||
2670 | /* Enable FT1 MONITOR STATUS */ | ||
2671 | if( ppp_udp_pkt->data[0] == 1) { | ||
2672 | |||
2673 | if( rCount++ != 0 ) { | ||
2674 | ppp_udp_pkt->cblock.result = 0; | ||
2675 | mbox->cmd.length = 1; | ||
2676 | break; | ||
2677 | } | ||
2678 | } | ||
2679 | |||
2680 | /* Disable FT1 MONITOR STATUS */ | ||
2681 | if( ppp_udp_pkt->data[0] == 0) { | ||
2682 | |||
2683 | if( --rCount != 0) { | ||
2684 | ppp_udp_pkt->cblock.result = 0; | ||
2685 | mbox->cmd.length = 1; | ||
2686 | break; | ||
2687 | } | ||
2688 | } | ||
2689 | goto udp_dflt_cmd; | ||
2690 | |||
2691 | /* WARNING: FIXME: This should be fixed. | ||
2692 | * The FT1 Status Ctrl doesn't have a break | ||
2693 | * statment. Thus, no code must be inserted | ||
2694 | * HERE: between default and above case statement */ | ||
2695 | |||
2696 | default: | ||
2697 | udp_dflt_cmd: | ||
2698 | |||
2699 | /* it's a board command */ | ||
2700 | mbox->cmd.command = ppp_udp_pkt->cblock.command; | ||
2701 | mbox->cmd.length = ppp_udp_pkt->cblock.length; | ||
2702 | |||
2703 | if(mbox->cmd.length) { | ||
2704 | memcpy(&mbox->data,(unsigned char *)ppp_udp_pkt->data, | ||
2705 | mbox->cmd.length); | ||
2706 | } | ||
2707 | |||
2708 | /* run the command on the board */ | ||
2709 | err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; | ||
2710 | |||
2711 | if (err != CMD_OK) { | ||
2712 | |||
2713 | ppp_error(card, err, mbox); | ||
2714 | ++ppp_priv_area->pipe_mgmt_stat. | ||
2715 | UDP_PIPE_mgmt_adptr_cmnd_timeout; | ||
2716 | break; | ||
2717 | } | ||
2718 | |||
2719 | ++ppp_priv_area->pipe_mgmt_stat.UDP_PIPE_mgmt_adptr_cmnd_OK; | ||
2720 | |||
2721 | /* copy the result back to our buffer */ | ||
2722 | memcpy(&ppp_udp_pkt->cblock,mbox, sizeof(cblock_t)); | ||
2723 | |||
2724 | if(mbox->cmd.length) { | ||
2725 | memcpy(&ppp_udp_pkt->data,&mbox->data,mbox->cmd.length); | ||
2726 | } | ||
2727 | |||
2728 | } /* end of switch */ | ||
2729 | } /* end of else */ | ||
2730 | |||
2731 | /* Fill UDP TTL */ | ||
2732 | ppp_udp_pkt->ip_pkt.ttl = card->wandev.ttl; | ||
2733 | len = reply_udp(ppp_priv_area->udp_pkt_data, mbox->cmd.length); | ||
2734 | |||
2735 | if (ppp_priv_area->udp_pkt_src == UDP_PKT_FRM_NETWORK) { | ||
2736 | |||
2737 | /* Make sure we are not already sending */ | ||
2738 | if (!test_bit(SEND_CRIT,&card->wandev.critical)){ | ||
2739 | ++ppp_priv_area->pipe_mgmt_stat.UDP_PIPE_mgmt_passed_to_adptr; | ||
2740 | ppp_send(card,ppp_priv_area->udp_pkt_data,len,ppp_priv_area->protocol); | ||
2741 | } | ||
2742 | |||
2743 | } else { | ||
2744 | |||
2745 | /* Pass it up the stack | ||
2746 | Allocate socket buffer */ | ||
2747 | if ((new_skb = dev_alloc_skb(len)) != NULL) { | ||
2748 | |||
2749 | /* copy data into new_skb */ | ||
2750 | |||
2751 | buf = skb_put(new_skb, len); | ||
2752 | memcpy(buf,ppp_priv_area->udp_pkt_data, len); | ||
2753 | |||
2754 | ++ppp_priv_area->pipe_mgmt_stat.UDP_PIPE_mgmt_passed_to_stack; | ||
2755 | |||
2756 | /* Decapsulate packet and pass it up the protocol | ||
2757 | stack */ | ||
2758 | new_skb->protocol = htons(ETH_P_IP); | ||
2759 | new_skb->dev = dev; | ||
2760 | new_skb->mac.raw = new_skb->data; | ||
2761 | netif_rx(new_skb); | ||
2762 | dev->last_rx = jiffies; | ||
2763 | |||
2764 | } else { | ||
2765 | |||
2766 | ++ppp_priv_area->pipe_mgmt_stat.UDP_PIPE_mgmt_no_socket; | ||
2767 | printk(KERN_INFO "no socket buffers available!\n"); | ||
2768 | } | ||
2769 | } | ||
2770 | |||
2771 | ppp_priv_area->udp_pkt_lgth = 0; | ||
2772 | |||
2773 | return; | ||
2774 | } | ||
2775 | |||
2776 | /*============================================================================= | ||
2777 | * Initial the ppp_private_area structure. | ||
2778 | */ | ||
2779 | static void init_ppp_priv_struct( ppp_private_area_t *ppp_priv_area ) | ||
2780 | { | ||
2781 | |||
2782 | memset(&ppp_priv_area->if_send_stat, 0, sizeof(if_send_stat_t)); | ||
2783 | memset(&ppp_priv_area->rx_intr_stat, 0, sizeof(rx_intr_stat_t)); | ||
2784 | memset(&ppp_priv_area->pipe_mgmt_stat, 0, sizeof(pipe_mgmt_stat_t)); | ||
2785 | } | ||
2786 | |||
2787 | /*============================================================================ | ||
2788 | * Initialize Global Statistics | ||
2789 | */ | ||
2790 | static void init_global_statistics( sdla_t *card ) | ||
2791 | { | ||
2792 | memset(&card->statistics, 0, sizeof(global_stats_t)); | ||
2793 | } | ||
2794 | |||
2795 | /*============================================================================ | ||
2796 | * Initialize Receive and Transmit Buffers. | ||
2797 | */ | ||
2798 | static void init_ppp_tx_rx_buff( sdla_t *card ) | ||
2799 | { | ||
2800 | ppp508_buf_info_t* info; | ||
2801 | |||
2802 | if (card->hw.type == SDLA_S514) { | ||
2803 | |||
2804 | info = (void*)(card->hw.dpmbase + PPP514_BUF_OFFS); | ||
2805 | |||
2806 | card->u.p.txbuf_base = (void*)(card->hw.dpmbase + | ||
2807 | info->txb_ptr); | ||
2808 | |||
2809 | card->u.p.txbuf_last = (ppp_buf_ctl_t*)card->u.p.txbuf_base + | ||
2810 | (info->txb_num - 1); | ||
2811 | |||
2812 | card->u.p.rxbuf_base = (void*)(card->hw.dpmbase + | ||
2813 | info->rxb_ptr); | ||
2814 | |||
2815 | card->u.p.rxbuf_last = (ppp_buf_ctl_t*)card->u.p.rxbuf_base + | ||
2816 | (info->rxb_num - 1); | ||
2817 | |||
2818 | } else { | ||
2819 | |||
2820 | info = (void*)(card->hw.dpmbase + PPP508_BUF_OFFS); | ||
2821 | |||
2822 | card->u.p.txbuf_base = (void*)(card->hw.dpmbase + | ||
2823 | (info->txb_ptr - PPP508_MB_VECT)); | ||
2824 | |||
2825 | card->u.p.txbuf_last = (ppp_buf_ctl_t*)card->u.p.txbuf_base + | ||
2826 | (info->txb_num - 1); | ||
2827 | |||
2828 | card->u.p.rxbuf_base = (void*)(card->hw.dpmbase + | ||
2829 | (info->rxb_ptr - PPP508_MB_VECT)); | ||
2830 | |||
2831 | card->u.p.rxbuf_last = (ppp_buf_ctl_t*)card->u.p.rxbuf_base + | ||
2832 | (info->rxb_num - 1); | ||
2833 | } | ||
2834 | |||
2835 | card->u.p.txbuf_next = (unsigned long*)&info->txb_nxt; | ||
2836 | card->u.p.rxbuf_next = (unsigned long*)&info->rxb1_ptr; | ||
2837 | |||
2838 | card->u.p.rx_base = info->rxb_base; | ||
2839 | card->u.p.rx_top = info->rxb_end; | ||
2840 | |||
2841 | card->u.p.txbuf = card->u.p.txbuf_base; | ||
2842 | card->rxmb = card->u.p.rxbuf_base; | ||
2843 | |||
2844 | } | ||
2845 | |||
2846 | /*============================================================================= | ||
2847 | * Read Connection Information (ie for Remote IP address assginment). | ||
2848 | * Called when ppp interface connected. | ||
2849 | */ | ||
2850 | static int read_info( sdla_t *card ) | ||
2851 | { | ||
2852 | struct net_device *dev = card->wandev.dev; | ||
2853 | ppp_private_area_t *ppp_priv_area = dev->priv; | ||
2854 | int err; | ||
2855 | |||
2856 | struct ifreq if_info; | ||
2857 | struct sockaddr_in *if_data1, *if_data2; | ||
2858 | mm_segment_t fs; | ||
2859 | |||
2860 | /* Set Local and remote addresses */ | ||
2861 | memset(&if_info, 0, sizeof(if_info)); | ||
2862 | strcpy(if_info.ifr_name, dev->name); | ||
2863 | |||
2864 | |||
2865 | fs = get_fs(); | ||
2866 | set_fs(get_ds()); /* get user space block */ | ||
2867 | |||
2868 | /* Change the local and remote ip address of the interface. | ||
2869 | * This will also add in the destination route. | ||
2870 | */ | ||
2871 | if_data1 = (struct sockaddr_in *)&if_info.ifr_addr; | ||
2872 | if_data1->sin_addr.s_addr = ppp_priv_area->ip_local; | ||
2873 | if_data1->sin_family = AF_INET; | ||
2874 | err = devinet_ioctl( SIOCSIFADDR, &if_info ); | ||
2875 | if_data2 = (struct sockaddr_in *)&if_info.ifr_dstaddr; | ||
2876 | if_data2->sin_addr.s_addr = ppp_priv_area->ip_remote; | ||
2877 | if_data2->sin_family = AF_INET; | ||
2878 | err = devinet_ioctl( SIOCSIFDSTADDR, &if_info ); | ||
2879 | |||
2880 | set_fs(fs); /* restore old block */ | ||
2881 | |||
2882 | if (err) { | ||
2883 | printk (KERN_INFO "%s: Adding of route failed: %i\n", | ||
2884 | card->devname,err); | ||
2885 | printk (KERN_INFO "%s: Local : %u.%u.%u.%u\n", | ||
2886 | card->devname,NIPQUAD(ppp_priv_area->ip_local)); | ||
2887 | printk (KERN_INFO "%s: Remote: %u.%u.%u.%u\n", | ||
2888 | card->devname,NIPQUAD(ppp_priv_area->ip_remote)); | ||
2889 | } | ||
2890 | return err; | ||
2891 | } | ||
2892 | |||
2893 | /*============================================================================= | ||
2894 | * Remove Dynamic Route. | ||
2895 | * Called when ppp interface disconnected. | ||
2896 | */ | ||
2897 | |||
2898 | static void remove_route( sdla_t *card ) | ||
2899 | { | ||
2900 | |||
2901 | struct net_device *dev = card->wandev.dev; | ||
2902 | long ip_addr; | ||
2903 | int err; | ||
2904 | |||
2905 | mm_segment_t fs; | ||
2906 | struct ifreq if_info; | ||
2907 | struct sockaddr_in *if_data1; | ||
2908 | struct in_device *in_dev = dev->ip_ptr; | ||
2909 | struct in_ifaddr *ifa = in_dev->ifa_list; | ||
2910 | |||
2911 | ip_addr = ifa->ifa_local; | ||
2912 | |||
2913 | /* Set Local and remote addresses */ | ||
2914 | memset(&if_info, 0, sizeof(if_info)); | ||
2915 | strcpy(if_info.ifr_name, dev->name); | ||
2916 | |||
2917 | fs = get_fs(); | ||
2918 | set_fs(get_ds()); /* get user space block */ | ||
2919 | |||
2920 | /* Change the local ip address of the interface to 0. | ||
2921 | * This will also delete the destination route. | ||
2922 | */ | ||
2923 | if_data1 = (struct sockaddr_in *)&if_info.ifr_addr; | ||
2924 | if_data1->sin_addr.s_addr = 0; | ||
2925 | if_data1->sin_family = AF_INET; | ||
2926 | err = devinet_ioctl( SIOCSIFADDR, &if_info ); | ||
2927 | |||
2928 | set_fs(fs); /* restore old block */ | ||
2929 | |||
2930 | |||
2931 | if (err) { | ||
2932 | printk (KERN_INFO "%s: Deleting dynamic route failed %d!\n", | ||
2933 | card->devname, err); | ||
2934 | return; | ||
2935 | }else{ | ||
2936 | printk (KERN_INFO "%s: PPP Deleting dynamic route %u.%u.%u.%u successfuly\n", | ||
2937 | card->devname, NIPQUAD(ip_addr)); | ||
2938 | } | ||
2939 | return; | ||
2940 | } | ||
2941 | |||
2942 | /*============================================================================= | ||
2943 | * Perform the Interrupt Test by running the READ_CODE_VERSION command MAX_INTR | ||
2944 | * _TEST_COUNTER times. | ||
2945 | */ | ||
2946 | static int intr_test( sdla_t *card ) | ||
2947 | { | ||
2948 | ppp_mbox_t *mb = card->mbox; | ||
2949 | int err,i; | ||
2950 | |||
2951 | err = ppp_set_intr_mode( card, 0x08 ); | ||
2952 | |||
2953 | if (err == CMD_OK) { | ||
2954 | |||
2955 | for (i = 0; i < MAX_INTR_TEST_COUNTER; i ++) { | ||
2956 | /* Run command READ_CODE_VERSION */ | ||
2957 | memset(&mb->cmd, 0, sizeof(ppp_cmd_t)); | ||
2958 | mb->cmd.length = 0; | ||
2959 | mb->cmd.command = PPP_READ_CODE_VERSION; | ||
2960 | err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; | ||
2961 | if (err != CMD_OK) | ||
2962 | ppp_error(card, err, mb); | ||
2963 | } | ||
2964 | } | ||
2965 | else return err; | ||
2966 | |||
2967 | err = ppp_set_intr_mode( card, 0 ); | ||
2968 | if (err != CMD_OK) | ||
2969 | return err; | ||
2970 | |||
2971 | return 0; | ||
2972 | } | ||
2973 | |||
2974 | /*============================================================================== | ||
2975 | * Determine what type of UDP call it is. DRVSTATS or PTPIPEAB ? | ||
2976 | */ | ||
2977 | static int udp_pkt_type( struct sk_buff *skb, sdla_t *card ) | ||
2978 | { | ||
2979 | unsigned char *sendpacket; | ||
2980 | unsigned char buf2[5]; | ||
2981 | ppp_udp_pkt_t *ppp_udp_pkt = (ppp_udp_pkt_t *)skb->data; | ||
2982 | |||
2983 | sendpacket = skb->data; | ||
2984 | memcpy(&buf2, &card->wandev.udp_port, 2); | ||
2985 | |||
2986 | if( ppp_udp_pkt->ip_pkt.ver_inet_hdr_length == 0x45 && /* IP packet */ | ||
2987 | sendpacket[9] == 0x11 && /* UDP packet */ | ||
2988 | sendpacket[22] == buf2[1] && /* UDP Port */ | ||
2989 | sendpacket[23] == buf2[0] && | ||
2990 | sendpacket[36] == 0x01 ) { | ||
2991 | |||
2992 | if ( sendpacket[28] == 0x50 && /* PTPIPEAB: Signature */ | ||
2993 | sendpacket[29] == 0x54 && | ||
2994 | sendpacket[30] == 0x50 && | ||
2995 | sendpacket[31] == 0x49 && | ||
2996 | sendpacket[32] == 0x50 && | ||
2997 | sendpacket[33] == 0x45 && | ||
2998 | sendpacket[34] == 0x41 && | ||
2999 | sendpacket[35] == 0x42 ){ | ||
3000 | |||
3001 | return UDP_PTPIPE_TYPE; | ||
3002 | |||
3003 | } else if(sendpacket[28] == 0x44 && /* DRVSTATS: Signature */ | ||
3004 | sendpacket[29] == 0x52 && | ||
3005 | sendpacket[30] == 0x56 && | ||
3006 | sendpacket[31] == 0x53 && | ||
3007 | sendpacket[32] == 0x54 && | ||
3008 | sendpacket[33] == 0x41 && | ||
3009 | sendpacket[34] == 0x54 && | ||
3010 | sendpacket[35] == 0x53 ){ | ||
3011 | |||
3012 | return UDP_DRVSTATS_TYPE; | ||
3013 | |||
3014 | } else | ||
3015 | return UDP_INVALID_TYPE; | ||
3016 | |||
3017 | } else | ||
3018 | return UDP_INVALID_TYPE; | ||
3019 | |||
3020 | } | ||
3021 | |||
3022 | /*============================================================================ | ||
3023 | * Check to see if the packet to be transmitted contains a broadcast or | ||
3024 | * multicast source IP address. | ||
3025 | */ | ||
3026 | |||
3027 | static int chk_bcast_mcast_addr(sdla_t *card, struct net_device* dev, | ||
3028 | struct sk_buff *skb) | ||
3029 | { | ||
3030 | u32 src_ip_addr; | ||
3031 | u32 broadcast_ip_addr = 0; | ||
3032 | struct in_device *in_dev; | ||
3033 | |||
3034 | /* read the IP source address from the outgoing packet */ | ||
3035 | src_ip_addr = *(u32 *)(skb->data + 12); | ||
3036 | |||
3037 | /* read the IP broadcast address for the device */ | ||
3038 | in_dev = dev->ip_ptr; | ||
3039 | if(in_dev != NULL) { | ||
3040 | struct in_ifaddr *ifa= in_dev->ifa_list; | ||
3041 | if(ifa != NULL) | ||
3042 | broadcast_ip_addr = ifa->ifa_broadcast; | ||
3043 | else | ||
3044 | return 0; | ||
3045 | } | ||
3046 | |||
3047 | /* check if the IP Source Address is a Broadcast address */ | ||
3048 | if((dev->flags & IFF_BROADCAST) && (src_ip_addr == broadcast_ip_addr)) { | ||
3049 | printk(KERN_INFO "%s: Broadcast Source Address silently discarded\n", | ||
3050 | card->devname); | ||
3051 | return 1; | ||
3052 | } | ||
3053 | |||
3054 | /* check if the IP Source Address is a Multicast address */ | ||
3055 | if((ntohl(src_ip_addr) >= 0xE0000001) && | ||
3056 | (ntohl(src_ip_addr) <= 0xFFFFFFFE)) { | ||
3057 | printk(KERN_INFO "%s: Multicast Source Address silently discarded\n", | ||
3058 | card->devname); | ||
3059 | return 1; | ||
3060 | } | ||
3061 | |||
3062 | return 0; | ||
3063 | } | ||
3064 | |||
3065 | void s508_lock (sdla_t *card, unsigned long *smp_flags) | ||
3066 | { | ||
3067 | spin_lock_irqsave(&card->wandev.lock, *smp_flags); | ||
3068 | } | ||
3069 | |||
3070 | void s508_unlock (sdla_t *card, unsigned long *smp_flags) | ||
3071 | { | ||
3072 | spin_unlock_irqrestore(&card->wandev.lock, *smp_flags); | ||
3073 | } | ||
3074 | |||
3075 | static int read_connection_info (sdla_t *card) | ||
3076 | { | ||
3077 | ppp_mbox_t *mb = card->mbox; | ||
3078 | struct net_device *dev = card->wandev.dev; | ||
3079 | ppp_private_area_t *ppp_priv_area = dev->priv; | ||
3080 | ppp508_connect_info_t *ppp508_connect_info; | ||
3081 | int err; | ||
3082 | |||
3083 | memset(&mb->cmd, 0, sizeof(ppp_cmd_t)); | ||
3084 | mb->cmd.length = 0; | ||
3085 | mb->cmd.command = PPP_GET_CONNECTION_INFO; | ||
3086 | err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; | ||
3087 | |||
3088 | if (err != CMD_OK) { | ||
3089 | ppp_error(card, err, mb); | ||
3090 | ppp_priv_area->ip_remote = 0; | ||
3091 | ppp_priv_area->ip_local = 0; | ||
3092 | } | ||
3093 | else { | ||
3094 | ppp508_connect_info = (ppp508_connect_info_t *)mb->data; | ||
3095 | ppp_priv_area->ip_remote = ppp508_connect_info->ip_remote; | ||
3096 | ppp_priv_area->ip_local = ppp508_connect_info->ip_local; | ||
3097 | |||
3098 | NEX_PRINTK(KERN_INFO "READ CONNECTION GOT IP ADDRESS %x, %x\n", | ||
3099 | ppp_priv_area->ip_remote, | ||
3100 | ppp_priv_area->ip_local); | ||
3101 | } | ||
3102 | |||
3103 | return err; | ||
3104 | } | ||
3105 | |||
3106 | /*=============================================================================== | ||
3107 | * config_ppp | ||
3108 | * | ||
3109 | * Configure the ppp protocol and enable communications. | ||
3110 | * | ||
3111 | * The if_open function binds this function to the poll routine. | ||
3112 | * Therefore, this function will run every time the ppp interface | ||
3113 | * is brought up. | ||
3114 | * | ||
3115 | * If the communications are not enabled, proceed to configure | ||
3116 | * the card and enable communications. | ||
3117 | * | ||
3118 | * If the communications are enabled, it means that the interface | ||
3119 | * was shutdown by ether the user or driver. In this case, we | ||
3120 | * have to check that the IP addresses have not changed. If | ||
3121 | * the IP addresses changed, we have to reconfigure the firmware | ||
3122 | * and update the changed IP addresses. Otherwise, just exit. | ||
3123 | */ | ||
3124 | static int config_ppp (sdla_t *card) | ||
3125 | { | ||
3126 | |||
3127 | struct net_device *dev = card->wandev.dev; | ||
3128 | ppp_flags_t *flags = card->flags; | ||
3129 | ppp_private_area_t *ppp_priv_area = dev->priv; | ||
3130 | |||
3131 | if (card->u.p.comm_enabled){ | ||
3132 | |||
3133 | if (ppp_priv_area->ip_local_tmp != ppp_priv_area->ip_local || | ||
3134 | ppp_priv_area->ip_remote_tmp != ppp_priv_area->ip_remote){ | ||
3135 | |||
3136 | /* The IP addersses have changed, we must | ||
3137 | * stop the communications and reconfigure | ||
3138 | * the card. Reason: the firmware must know | ||
3139 | * the local and remote IP addresses. */ | ||
3140 | disable_comm(card); | ||
3141 | wanpipe_set_state(card, WAN_DISCONNECTED); | ||
3142 | printk(KERN_INFO | ||
3143 | "%s: IP addresses changed!\n", | ||
3144 | card->devname); | ||
3145 | printk(KERN_INFO "%s: Restarting communications ...\n", | ||
3146 | card->devname); | ||
3147 | }else{ | ||
3148 | /* IP addresses are the same and the link is up, | ||
3149 | * we don't have to do anything here. Therefore, exit */ | ||
3150 | return 0; | ||
3151 | } | ||
3152 | } | ||
3153 | |||
3154 | /* Record the new IP addreses */ | ||
3155 | ppp_priv_area->ip_local = ppp_priv_area->ip_local_tmp; | ||
3156 | ppp_priv_area->ip_remote = ppp_priv_area->ip_remote_tmp; | ||
3157 | |||
3158 | if (config508(dev, card)){ | ||
3159 | printk(KERN_INFO "%s: Failed to configure PPP device\n", | ||
3160 | card->devname); | ||
3161 | return 0; | ||
3162 | } | ||
3163 | |||
3164 | if (ppp_set_intr_mode(card, PPP_INTR_RXRDY| | ||
3165 | PPP_INTR_TXRDY| | ||
3166 | PPP_INTR_MODEM| | ||
3167 | PPP_INTR_DISC | | ||
3168 | PPP_INTR_OPEN | | ||
3169 | PPP_INTR_DROP_DTR | | ||
3170 | PPP_INTR_TIMER)) { | ||
3171 | |||
3172 | printk(KERN_INFO "%s: Failed to configure board interrupts !\n", | ||
3173 | card->devname); | ||
3174 | return 0; | ||
3175 | } | ||
3176 | |||
3177 | /* Turn off the transmit and timer interrupt */ | ||
3178 | flags->imask &= ~(PPP_INTR_TXRDY | PPP_INTR_TIMER) ; | ||
3179 | |||
3180 | |||
3181 | /* If you are not the authenticator and any one of the protocol is | ||
3182 | * enabled then we call the set_out_bound_authentication. | ||
3183 | */ | ||
3184 | if ( !card->u.p.authenticator && (ppp_priv_area->pap || ppp_priv_area->chap)) { | ||
3185 | if ( ppp_set_outbnd_auth(card, ppp_priv_area) ){ | ||
3186 | printk(KERN_INFO "%s: Outbound authentication failed !\n", | ||
3187 | card->devname); | ||
3188 | return 0; | ||
3189 | } | ||
3190 | } | ||
3191 | |||
3192 | /* If you are the authenticator and any one of the protocol is enabled | ||
3193 | * then we call the set_in_bound_authentication. | ||
3194 | */ | ||
3195 | if (card->u.p.authenticator && (ppp_priv_area->pap || ppp_priv_area->chap)){ | ||
3196 | if (ppp_set_inbnd_auth(card, ppp_priv_area)){ | ||
3197 | printk(KERN_INFO "%s: Inbound authentication failed !\n", | ||
3198 | card->devname); | ||
3199 | return 0; | ||
3200 | } | ||
3201 | } | ||
3202 | |||
3203 | /* If we fail to enable communications here it's OK, | ||
3204 | * since the DTR timer will cause a disconnected, which | ||
3205 | * will retrigger communication in timer_intr() */ | ||
3206 | if (ppp_comm_enable(card) == CMD_OK) { | ||
3207 | wanpipe_set_state(card, WAN_CONNECTING); | ||
3208 | init_ppp_tx_rx_buff(card); | ||
3209 | } | ||
3210 | |||
3211 | return 0; | ||
3212 | } | ||
3213 | |||
3214 | /*============================================================ | ||
3215 | * ppp_poll | ||
3216 | * | ||
3217 | * Rationale: | ||
3218 | * We cannot manipulate the routing tables, or | ||
3219 | * ip addresses withing the interrupt. Therefore | ||
3220 | * we must perform such actons outside an interrupt | ||
3221 | * at a later time. | ||
3222 | * | ||
3223 | * Description: | ||
3224 | * PPP polling routine, responsible for | ||
3225 | * shutting down interfaces upon disconnect | ||
3226 | * and adding/removing routes. | ||
3227 | * | ||
3228 | * Usage: | ||
3229 | * This function is executed for each ppp | ||
3230 | * interface through a tq_schedule bottom half. | ||
3231 | * | ||
3232 | * trigger_ppp_poll() function is used to kick | ||
3233 | * the ppp_poll routine. | ||
3234 | */ | ||
3235 | static void ppp_poll(struct net_device *dev) | ||
3236 | { | ||
3237 | ppp_private_area_t *ppp_priv_area; | ||
3238 | sdla_t *card; | ||
3239 | u8 check_gateway=0; | ||
3240 | ppp_flags_t *flags; | ||
3241 | |||
3242 | if (!dev || (ppp_priv_area = dev->priv) == NULL) | ||
3243 | return; | ||
3244 | |||
3245 | card = ppp_priv_area->card; | ||
3246 | flags = card->flags; | ||
3247 | |||
3248 | /* Shutdown is in progress, stop what you are | ||
3249 | * doing and get out */ | ||
3250 | if (test_bit(PERI_CRIT,&card->wandev.critical)){ | ||
3251 | clear_bit(POLL_CRIT,&card->wandev.critical); | ||
3252 | return; | ||
3253 | } | ||
3254 | |||
3255 | /* if_open() function has triggered the polling routine | ||
3256 | * to determine the configured IP addresses. Once the | ||
3257 | * addresses are found, trigger the chdlc configuration */ | ||
3258 | if (test_bit(0,&ppp_priv_area->config_ppp)){ | ||
3259 | |||
3260 | ppp_priv_area->ip_local_tmp = get_ip_address(dev,WAN_LOCAL_IP); | ||
3261 | ppp_priv_area->ip_remote_tmp = get_ip_address(dev,WAN_POINTOPOINT_IP); | ||
3262 | |||
3263 | if (ppp_priv_area->ip_local_tmp == ppp_priv_area->ip_remote_tmp && | ||
3264 | card->u.p.ip_mode == WANOPT_PPP_HOST){ | ||
3265 | |||
3266 | if (++ppp_priv_area->ip_error > MAX_IP_ERRORS){ | ||
3267 | printk(KERN_INFO "\n%s: --- WARNING ---\n", | ||
3268 | card->devname); | ||
3269 | printk(KERN_INFO "%s: The local IP address is the same as the\n", | ||
3270 | card->devname); | ||
3271 | printk(KERN_INFO "%s: Point-to-Point IP address.\n", | ||
3272 | card->devname); | ||
3273 | printk(KERN_INFO "%s: --- WARNING ---\n\n", | ||
3274 | card->devname); | ||
3275 | }else{ | ||
3276 | clear_bit(POLL_CRIT,&card->wandev.critical); | ||
3277 | ppp_priv_area->poll_delay_timer.expires = jiffies+HZ; | ||
3278 | add_timer(&ppp_priv_area->poll_delay_timer); | ||
3279 | return; | ||
3280 | } | ||
3281 | } | ||
3282 | |||
3283 | ppp_priv_area->timer_int_enabled |= TMR_INT_ENABLED_CONFIG; | ||
3284 | flags->imask |= PPP_INTR_TIMER; | ||
3285 | ppp_priv_area->ip_error=0; | ||
3286 | |||
3287 | clear_bit(0,&ppp_priv_area->config_ppp); | ||
3288 | clear_bit(POLL_CRIT,&card->wandev.critical); | ||
3289 | return; | ||
3290 | } | ||
3291 | |||
3292 | /* Dynamic interface implementation, as well as dynamic | ||
3293 | * routing. */ | ||
3294 | |||
3295 | switch (card->wandev.state) { | ||
3296 | |||
3297 | case WAN_DISCONNECTED: | ||
3298 | |||
3299 | /* If the dynamic interface configuration is on, and interface | ||
3300 | * is up, then bring down the netowrk interface */ | ||
3301 | |||
3302 | if (test_bit(DYN_OPT_ON,&ppp_priv_area->interface_down) && | ||
3303 | !test_bit(DEV_DOWN,&ppp_priv_area->interface_down) && | ||
3304 | card->wandev.dev->flags & IFF_UP){ | ||
3305 | |||
3306 | printk(KERN_INFO "%s: Interface %s down.\n", | ||
3307 | card->devname,card->wandev.dev->name); | ||
3308 | change_dev_flags(card->wandev.dev, | ||
3309 | (card->wandev.dev->flags&~IFF_UP)); | ||
3310 | set_bit(DEV_DOWN,&ppp_priv_area->interface_down); | ||
3311 | }else{ | ||
3312 | /* We need to check if the local IP address is | ||
3313 | * zero. If it is, we shouldn't try to remove it. | ||
3314 | * For some reason the kernel crashes badly if | ||
3315 | * we try to remove the route twice */ | ||
3316 | |||
3317 | if (card->wandev.dev->flags & IFF_UP && | ||
3318 | get_ip_address(card->wandev.dev,WAN_LOCAL_IP) && | ||
3319 | card->u.p.ip_mode == WANOPT_PPP_PEER){ | ||
3320 | |||
3321 | remove_route(card); | ||
3322 | } | ||
3323 | } | ||
3324 | break; | ||
3325 | |||
3326 | case WAN_CONNECTED: | ||
3327 | |||
3328 | /* In SMP machine this code can execute before the interface | ||
3329 | * comes up. In this case, we must make sure that we do not | ||
3330 | * try to bring up the interface before dev_open() is finished */ | ||
3331 | |||
3332 | |||
3333 | /* DEV_DOWN will be set only when we bring down the interface | ||
3334 | * for the very first time. This way we know that it was us | ||
3335 | * that brought the interface down */ | ||
3336 | |||
3337 | if (test_bit(DYN_OPT_ON,&ppp_priv_area->interface_down) && | ||
3338 | test_bit(DEV_DOWN, &ppp_priv_area->interface_down) && | ||
3339 | !(card->wandev.dev->flags & IFF_UP)){ | ||
3340 | |||
3341 | printk(KERN_INFO "%s: Interface %s up.\n", | ||
3342 | card->devname,card->wandev.dev->name); | ||
3343 | |||
3344 | change_dev_flags(card->wandev.dev,(card->wandev.dev->flags|IFF_UP)); | ||
3345 | clear_bit(DEV_DOWN,&ppp_priv_area->interface_down); | ||
3346 | check_gateway=1; | ||
3347 | } | ||
3348 | |||
3349 | if ((card->u.p.ip_mode == WANOPT_PPP_PEER) && | ||
3350 | test_bit(1,&Read_connection_info)) { | ||
3351 | |||
3352 | process_route(card); | ||
3353 | clear_bit(1,&Read_connection_info); | ||
3354 | check_gateway=1; | ||
3355 | } | ||
3356 | |||
3357 | if (ppp_priv_area->gateway && check_gateway) | ||
3358 | add_gateway(card,dev); | ||
3359 | |||
3360 | break; | ||
3361 | } | ||
3362 | clear_bit(POLL_CRIT,&card->wandev.critical); | ||
3363 | return; | ||
3364 | } | ||
3365 | |||
3366 | /*============================================================ | ||
3367 | * trigger_ppp_poll | ||
3368 | * | ||
3369 | * Description: | ||
3370 | * Add a ppp_poll() task into a tq_scheduler bh handler | ||
3371 | * for a specific interface. This will kick | ||
3372 | * the ppp_poll() routine at a later time. | ||
3373 | * | ||
3374 | * Usage: | ||
3375 | * Interrupts use this to defer a taks to | ||
3376 | * a polling routine. | ||
3377 | * | ||
3378 | */ | ||
3379 | |||
3380 | static void trigger_ppp_poll(struct net_device *dev) | ||
3381 | { | ||
3382 | ppp_private_area_t *ppp_priv_area; | ||
3383 | if ((ppp_priv_area=dev->priv) != NULL){ | ||
3384 | |||
3385 | sdla_t *card = ppp_priv_area->card; | ||
3386 | |||
3387 | if (test_bit(PERI_CRIT,&card->wandev.critical)){ | ||
3388 | return; | ||
3389 | } | ||
3390 | |||
3391 | if (test_and_set_bit(POLL_CRIT,&card->wandev.critical)){ | ||
3392 | return; | ||
3393 | } | ||
3394 | |||
3395 | schedule_work(&ppp_priv_area->poll_work); | ||
3396 | } | ||
3397 | return; | ||
3398 | } | ||
3399 | |||
3400 | static void ppp_poll_delay (unsigned long dev_ptr) | ||
3401 | { | ||
3402 | struct net_device *dev = (struct net_device *)dev_ptr; | ||
3403 | trigger_ppp_poll(dev); | ||
3404 | } | ||
3405 | |||
3406 | /*============================================================ | ||
3407 | * detect_and_fix_tx_bug | ||
3408 | * | ||
3409 | * Description: | ||
3410 | * On connect, if the board tx buffer ptr is not the same | ||
3411 | * as the driver tx buffer ptr, we found a firmware bug. | ||
3412 | * Report the bug to the above layer. To fix the | ||
3413 | * error restart communications again. | ||
3414 | * | ||
3415 | * Usage: | ||
3416 | * | ||
3417 | */ | ||
3418 | |||
3419 | static int detect_and_fix_tx_bug (sdla_t *card) | ||
3420 | { | ||
3421 | if (((unsigned long)card->u.p.txbuf_base&0xFFF) != ((*card->u.p.txbuf_next)&0xFFF)){ | ||
3422 | NEX_PRINTK(KERN_INFO "Major Error, Fix the bug\n"); | ||
3423 | return 1; | ||
3424 | } | ||
3425 | return 0; | ||
3426 | } | ||
3427 | |||
3428 | MODULE_LICENSE("GPL"); | ||
3429 | |||
3430 | /****** End *****************************************************************/ | ||
diff --git a/drivers/net/wan/sdla_x25.c b/drivers/net/wan/sdla_x25.c deleted file mode 100644 index 63f846d6f3a6..000000000000 --- a/drivers/net/wan/sdla_x25.c +++ /dev/null | |||
@@ -1,5497 +0,0 @@ | |||
1 | /***************************************************************************** | ||
2 | * sdla_x25.c WANPIPE(tm) Multiprotocol WAN Link Driver. X.25 module. | ||
3 | * | ||
4 | * Author: Nenad Corbic <ncorbic@sangoma.com> | ||
5 | * | ||
6 | * Copyright: (c) 1995-2001 Sangoma Technologies Inc. | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License | ||
10 | * as published by the Free Software Foundation; either version | ||
11 | * 2 of the License, or (at your option) any later version. | ||
12 | * ============================================================================ | ||
13 | * Apr 03, 2001 Nenad Corbic o Fixed the rx_skb=NULL bug in x25 in rx_intr(). | ||
14 | * Dec 26, 2000 Nenad Corbic o Added a new polling routine, that uses | ||
15 | * a kernel timer (more efficient). | ||
16 | * Dec 25, 2000 Nenad Corbic o Updated for 2.4.X kernel | ||
17 | * Jul 26, 2000 Nenad Corbic o Increased the local packet buffering | ||
18 | * for API to 4096+header_size. | ||
19 | * Jul 17, 2000 Nenad Corbic o Fixed the x25 startup bug. Enable | ||
20 | * communications only after all interfaces | ||
21 | * come up. HIGH SVC/PVC is used to calculate | ||
22 | * the number of channels. | ||
23 | * Enable protocol only after all interfaces | ||
24 | * are enabled. | ||
25 | * Jul 10, 2000 Nenad Corbic o Fixed the M_BIT bug. | ||
26 | * Apr 25, 2000 Nenad Corbic o Pass Modem messages to the API. | ||
27 | * Disable idle timeout in X25 API. | ||
28 | * Apr 14, 2000 Nenad Corbic o Fixed: Large LCN number support. | ||
29 | * Maximum LCN number is 4095. | ||
30 | * Maximum number of X25 channels is 255. | ||
31 | * Apr 06, 2000 Nenad Corbic o Added SMP Support. | ||
32 | * Mar 29, 2000 Nenad Corbic o Added support for S514 PCI Card | ||
33 | * Mar 23, 2000 Nenad Corbic o Improved task queue, BH handling. | ||
34 | * Mar 14, 2000 Nenad Corbic o Updated Protocol Violation handling | ||
35 | * routines. Bug Fix. | ||
36 | * Mar 10, 2000 Nenad Corbic o Bug Fix: corrupted mbox recovery. | ||
37 | * Mar 09, 2000 Nenad Corbic o Fixed the auto HDLC bug. | ||
38 | * Mar 08, 2000 Nenad Corbic o Fixed LAPB HDLC startup problems. | ||
39 | * Application must bring the link up | ||
40 | * before tx/rx, and bring the | ||
41 | * link down on close(). | ||
42 | * Mar 06, 2000 Nenad Corbic o Added an option for logging call setup | ||
43 | * information. | ||
44 | * Feb 29, 2000 Nenad Corbic o Added support for LAPB HDLC API | ||
45 | * Feb 25, 2000 Nenad Corbic o Fixed the modem failure handling. | ||
46 | * No Modem OOB message will be passed | ||
47 | * to the user. | ||
48 | * Feb 21, 2000 Nenad Corbic o Added Xpipemon Debug Support | ||
49 | * Dec 30, 1999 Nenad Corbic o Socket based X25API | ||
50 | * Sep 17, 1998 Jaspreet Singh o Updates for 2.2.X kernel | ||
51 | * Mar 15, 1998 Alan Cox o 2.1.x porting | ||
52 | * Dec 19, 1997 Jaspreet Singh o Added multi-channel IPX support | ||
53 | * Nov 27, 1997 Jaspreet Singh o Added protection against enabling of irqs | ||
54 | * when they are disabled. | ||
55 | * Nov 17, 1997 Farhan Thawar o Added IPX support | ||
56 | * o Changed if_send() to now buffer packets when | ||
57 | * the board is busy | ||
58 | * o Removed queueing of packets via the polling | ||
59 | * routing | ||
60 | * o Changed if_send() critical flags to properly | ||
61 | * handle race conditions | ||
62 | * Nov 06, 1997 Farhan Thawar o Added support for SVC timeouts | ||
63 | * o Changed PVC encapsulation to ETH_P_IP | ||
64 | * Jul 21, 1997 Jaspreet Singh o Fixed freeing up of buffers using kfree() | ||
65 | * when packets are received. | ||
66 | * Mar 11, 1997 Farhan Thawar Version 3.1.1 | ||
67 | * o added support for V35 | ||
68 | * o changed if_send() to return 0 if | ||
69 | * wandev.critical() is true | ||
70 | * o free socket buffer in if_send() if | ||
71 | * returning 0 | ||
72 | * o added support for single '@' address to | ||
73 | * accept all incoming calls | ||
74 | * o fixed bug in set_chan_state() to disconnect | ||
75 | * Jan 15, 1997 Gene Kozin Version 3.1.0 | ||
76 | * o implemented exec() entry point | ||
77 | * Jan 07, 1997 Gene Kozin Initial version. | ||
78 | *****************************************************************************/ | ||
79 | |||
80 | /*====================================================== | ||
81 | * Includes | ||
82 | *=====================================================*/ | ||
83 | |||
84 | #include <linux/module.h> | ||
85 | #include <linux/kernel.h> /* printk(), and other useful stuff */ | ||
86 | #include <linux/stddef.h> /* offsetof(), etc. */ | ||
87 | #include <linux/errno.h> /* return codes */ | ||
88 | #include <linux/string.h> /* inline memset(), etc. */ | ||
89 | #include <linux/ctype.h> | ||
90 | #include <linux/slab.h> /* kmalloc(), kfree() */ | ||
91 | #include <linux/wanrouter.h> /* WAN router definitions */ | ||
92 | #include <linux/wanpipe.h> /* WANPIPE common user API definitions */ | ||
93 | #include <linux/workqueue.h> | ||
94 | #include <linux/jiffies.h> /* time_after() macro */ | ||
95 | #include <asm/byteorder.h> /* htons(), etc. */ | ||
96 | #include <asm/atomic.h> | ||
97 | #include <linux/delay.h> /* Experimental delay */ | ||
98 | |||
99 | #include <asm/uaccess.h> | ||
100 | |||
101 | #include <linux/if.h> | ||
102 | #include <linux/if_arp.h> | ||
103 | #include <linux/sdla_x25.h> /* X.25 firmware API definitions */ | ||
104 | #include <linux/if_wanpipe_common.h> | ||
105 | #include <linux/if_wanpipe.h> | ||
106 | |||
107 | |||
108 | /*====================================================== | ||
109 | * Defines & Macros | ||
110 | *=====================================================*/ | ||
111 | |||
112 | |||
113 | #define CMD_OK 0 /* normal firmware return code */ | ||
114 | #define CMD_TIMEOUT 0xFF /* firmware command timed out */ | ||
115 | #define MAX_CMD_RETRY 10 /* max number of firmware retries */ | ||
116 | |||
117 | #define X25_CHAN_MTU 4096 /* unfragmented logical channel MTU */ | ||
118 | #define X25_HRDHDR_SZ 7 /* max encapsulation header size */ | ||
119 | #define X25_CONCT_TMOUT (90*HZ) /* link connection timeout */ | ||
120 | #define X25_RECON_TMOUT (10*HZ) /* link connection timeout */ | ||
121 | #define CONNECT_TIMEOUT (90*HZ) /* link connection timeout */ | ||
122 | #define HOLD_DOWN_TIME (30*HZ) /* link hold down time */ | ||
123 | #define MAX_BH_BUFF 10 | ||
124 | #define M_BIT 0x01 | ||
125 | |||
126 | //#define PRINT_DEBUG 1 | ||
127 | #ifdef PRINT_DEBUG | ||
128 | #define DBG_PRINTK(format, a...) printk(format, ## a) | ||
129 | #else | ||
130 | #define DBG_PRINTK(format, a...) | ||
131 | #endif | ||
132 | |||
133 | #define TMR_INT_ENABLED_POLL_ACTIVE 0x01 | ||
134 | #define TMR_INT_ENABLED_POLL_CONNECT_ON 0x02 | ||
135 | #define TMR_INT_ENABLED_POLL_CONNECT_OFF 0x04 | ||
136 | #define TMR_INT_ENABLED_POLL_DISCONNECT 0x08 | ||
137 | #define TMR_INT_ENABLED_CMD_EXEC 0x10 | ||
138 | #define TMR_INT_ENABLED_UPDATE 0x20 | ||
139 | #define TMR_INT_ENABLED_UDP_PKT 0x40 | ||
140 | |||
141 | #define MAX_X25_ADDR_SIZE 16 | ||
142 | #define MAX_X25_DATA_SIZE 129 | ||
143 | #define MAX_X25_FACL_SIZE 110 | ||
144 | |||
145 | #define TRY_CMD_AGAIN 2 | ||
146 | #define DELAY_RESULT 1 | ||
147 | #define RETURN_RESULT 0 | ||
148 | |||
149 | #define DCD(x) (x & 0x03 ? "HIGH" : "LOW") | ||
150 | #define CTS(x) (x & 0x05 ? "HIGH" : "LOW") | ||
151 | |||
152 | |||
153 | /* Driver will not write log messages about | ||
154 | * modem status if defined.*/ | ||
155 | #define MODEM_NOT_LOG 1 | ||
156 | |||
157 | /*==================================================== | ||
158 | * For IPXWAN | ||
159 | *===================================================*/ | ||
160 | |||
161 | #define CVHexToAscii(b) (((unsigned char)(b) > (unsigned char)9) ? ((unsigned char)'A' + ((unsigned char)(b) - (unsigned char)10)) : ((unsigned char)'0' + (unsigned char)(b))) | ||
162 | |||
163 | |||
164 | /*==================================================== | ||
165 | * MEMORY DEBUGGING FUNCTION | ||
166 | *==================================================== | ||
167 | |||
168 | #define KMEM_SAFETYZONE 8 | ||
169 | |||
170 | static void * dbg_kmalloc(unsigned int size, int prio, int line) { | ||
171 | int i = 0; | ||
172 | void * v = kmalloc(size+sizeof(unsigned int)+2*KMEM_SAFETYZONE*8,prio); | ||
173 | char * c1 = v; | ||
174 | c1 += sizeof(unsigned int); | ||
175 | *((unsigned int *)v) = size; | ||
176 | |||
177 | for (i = 0; i < KMEM_SAFETYZONE; i++) { | ||
178 | c1[0] = 'D'; c1[1] = 'E'; c1[2] = 'A'; c1[3] = 'D'; | ||
179 | c1[4] = 'B'; c1[5] = 'E'; c1[6] = 'E'; c1[7] = 'F'; | ||
180 | c1 += 8; | ||
181 | } | ||
182 | c1 += size; | ||
183 | for (i = 0; i < KMEM_SAFETYZONE; i++) { | ||
184 | c1[0] = 'M'; c1[1] = 'U'; c1[2] = 'N'; c1[3] = 'G'; | ||
185 | c1[4] = 'W'; c1[5] = 'A'; c1[6] = 'L'; c1[7] = 'L'; | ||
186 | c1 += 8; | ||
187 | } | ||
188 | v = ((char *)v) + sizeof(unsigned int) + KMEM_SAFETYZONE*8; | ||
189 | printk(KERN_INFO "line %d kmalloc(%d,%d) = %p\n",line,size,prio,v); | ||
190 | return v; | ||
191 | } | ||
192 | static void dbg_kfree(void * v, int line) { | ||
193 | unsigned int * sp = (unsigned int *)(((char *)v) - (sizeof(unsigned int) + KMEM_SAFETYZONE*8)); | ||
194 | unsigned int size = *sp; | ||
195 | char * c1 = ((char *)v) - KMEM_SAFETYZONE*8; | ||
196 | int i = 0; | ||
197 | for (i = 0; i < KMEM_SAFETYZONE; i++) { | ||
198 | if ( c1[0] != 'D' || c1[1] != 'E' || c1[2] != 'A' || c1[3] != 'D' | ||
199 | || c1[4] != 'B' || c1[5] != 'E' || c1[6] != 'E' || c1[7] != 'F') { | ||
200 | printk(KERN_INFO "kmalloced block at %p has been corrupted (underrun)!\n",v); | ||
201 | printk(KERN_INFO " %4x: %2x %2x %2x %2x %2x %2x %2x %2x\n", i*8, | ||
202 | c1[0],c1[1],c1[2],c1[3],c1[4],c1[5],c1[6],c1[7] ); | ||
203 | } | ||
204 | c1 += 8; | ||
205 | } | ||
206 | c1 += size; | ||
207 | for (i = 0; i < KMEM_SAFETYZONE; i++) { | ||
208 | if ( c1[0] != 'M' || c1[1] != 'U' || c1[2] != 'N' || c1[3] != 'G' | ||
209 | || c1[4] != 'W' || c1[5] != 'A' || c1[6] != 'L' || c1[7] != 'L' | ||
210 | ) { | ||
211 | printk(KERN_INFO "kmalloced block at %p has been corrupted (overrun):\n",v); | ||
212 | printk(KERN_INFO " %4x: %2x %2x %2x %2x %2x %2x %2x %2x\n", i*8, | ||
213 | c1[0],c1[1],c1[2],c1[3],c1[4],c1[5],c1[6],c1[7] ); | ||
214 | } | ||
215 | c1 += 8; | ||
216 | } | ||
217 | printk(KERN_INFO "line %d kfree(%p)\n",line,v); | ||
218 | v = ((char *)v) - (sizeof(unsigned int) + KMEM_SAFETYZONE*8); | ||
219 | kfree(v); | ||
220 | } | ||
221 | |||
222 | #define kmalloc(x,y) dbg_kmalloc(x,y,__LINE__) | ||
223 | #define kfree(x) dbg_kfree(x,__LINE__) | ||
224 | |||
225 | ==============================================================*/ | ||
226 | |||
227 | |||
228 | |||
229 | /*=============================================== | ||
230 | * Data Structures | ||
231 | *===============================================*/ | ||
232 | |||
233 | |||
234 | /*======================================================== | ||
235 | * Name: x25_channel | ||
236 | * | ||
237 | * Purpose: To hold private informaton for each | ||
238 | * logical channel. | ||
239 | * | ||
240 | * Rationale: Per-channel debugging is possible if each | ||
241 | * channel has its own private area. | ||
242 | * | ||
243 | * Assumptions: | ||
244 | * | ||
245 | * Description: This is an extention of the struct net_device | ||
246 | * we create for each network interface to keep | ||
247 | * the rest of X.25 channel-specific data. | ||
248 | * | ||
249 | * Construct: Typedef | ||
250 | */ | ||
251 | typedef struct x25_channel | ||
252 | { | ||
253 | wanpipe_common_t common; /* common area for x25api and socket */ | ||
254 | char name[WAN_IFNAME_SZ+1]; /* interface name, ASCIIZ */ | ||
255 | char addr[WAN_ADDRESS_SZ+1]; /* media address, ASCIIZ */ | ||
256 | unsigned tx_pkt_size; | ||
257 | unsigned short protocol; /* ethertype, 0 - multiplexed */ | ||
258 | char drop_sequence; /* mark sequence for dropping */ | ||
259 | unsigned long state_tick; /* time of the last state change */ | ||
260 | unsigned idle_timeout; /* sec, before disconnecting */ | ||
261 | unsigned long i_timeout_sofar; /* # of sec's we've been idle */ | ||
262 | unsigned hold_timeout; /* sec, before re-connecting */ | ||
263 | unsigned long tick_counter; /* counter for transmit time out */ | ||
264 | char devtint; /* Weather we should dev_tint() */ | ||
265 | struct sk_buff* rx_skb; /* receive socket buffer */ | ||
266 | struct sk_buff* tx_skb; /* transmit socket buffer */ | ||
267 | |||
268 | bh_data_t *bh_head; /* Circular buffer for x25api_bh */ | ||
269 | unsigned long tq_working; | ||
270 | volatile int bh_write; | ||
271 | volatile int bh_read; | ||
272 | atomic_t bh_buff_used; | ||
273 | |||
274 | sdla_t* card; /* -> owner */ | ||
275 | struct net_device *dev; /* -> bound devce */ | ||
276 | |||
277 | int ch_idx; | ||
278 | unsigned char enable_IPX; | ||
279 | unsigned long network_number; | ||
280 | struct net_device_stats ifstats; /* interface statistics */ | ||
281 | unsigned short transmit_length; | ||
282 | unsigned short tx_offset; | ||
283 | char transmit_buffer[X25_CHAN_MTU+sizeof(x25api_hdr_t)]; | ||
284 | |||
285 | if_send_stat_t if_send_stat; | ||
286 | rx_intr_stat_t rx_intr_stat; | ||
287 | pipe_mgmt_stat_t pipe_mgmt_stat; | ||
288 | |||
289 | unsigned long router_start_time; /* Router start time in seconds */ | ||
290 | unsigned long router_up_time; | ||
291 | |||
292 | } x25_channel_t; | ||
293 | |||
294 | /* FIXME Take this out */ | ||
295 | |||
296 | #ifdef NEX_OLD_CALL_INFO | ||
297 | typedef struct x25_call_info | ||
298 | { | ||
299 | char dest[17]; PACKED;/* ASCIIZ destination address */ | ||
300 | char src[17]; PACKED;/* ASCIIZ source address */ | ||
301 | char nuser; PACKED;/* number of user data bytes */ | ||
302 | unsigned char user[127]; PACKED;/* user data */ | ||
303 | char nfacil; PACKED;/* number of facilities */ | ||
304 | struct | ||
305 | { | ||
306 | unsigned char code; PACKED; | ||
307 | unsigned char parm; PACKED; | ||
308 | } facil[64]; /* facilities */ | ||
309 | } x25_call_info_t; | ||
310 | #else | ||
311 | typedef struct x25_call_info | ||
312 | { | ||
313 | char dest[MAX_X25_ADDR_SIZE] PACKED;/* ASCIIZ destination address */ | ||
314 | char src[MAX_X25_ADDR_SIZE] PACKED;/* ASCIIZ source address */ | ||
315 | unsigned char nuser PACKED; | ||
316 | unsigned char user[MAX_X25_DATA_SIZE] PACKED;/* user data */ | ||
317 | unsigned char nfacil PACKED; | ||
318 | unsigned char facil[MAX_X25_FACL_SIZE] PACKED; | ||
319 | unsigned short lcn PACKED; | ||
320 | } x25_call_info_t; | ||
321 | #endif | ||
322 | |||
323 | |||
324 | |||
325 | /*=============================================== | ||
326 | * Private Function Prototypes | ||
327 | *==============================================*/ | ||
328 | |||
329 | |||
330 | /*================================================= | ||
331 | * WAN link driver entry points. These are | ||
332 | * called by the WAN router module. | ||
333 | */ | ||
334 | static int update(struct wan_device* wandev); | ||
335 | static int new_if(struct wan_device* wandev, struct net_device* dev, | ||
336 | wanif_conf_t* conf); | ||
337 | static int del_if(struct wan_device* wandev, struct net_device* dev); | ||
338 | static void disable_comm (sdla_t* card); | ||
339 | static void disable_comm_shutdown(sdla_t *card); | ||
340 | |||
341 | |||
342 | |||
343 | /*================================================= | ||
344 | * WANPIPE-specific entry points | ||
345 | */ | ||
346 | static int wpx_exec (struct sdla* card, void* u_cmd, void* u_data); | ||
347 | static void x25api_bh(struct net_device *dev); | ||
348 | static int x25api_bh_cleanup(struct net_device *dev); | ||
349 | static int bh_enqueue(struct net_device *dev, struct sk_buff *skb); | ||
350 | |||
351 | |||
352 | /*================================================= | ||
353 | * Network device interface | ||
354 | */ | ||
355 | static int if_init(struct net_device* dev); | ||
356 | static int if_open(struct net_device* dev); | ||
357 | static int if_close(struct net_device* dev); | ||
358 | static int if_header(struct sk_buff* skb, struct net_device* dev, | ||
359 | unsigned short type, void* daddr, void* saddr, unsigned len); | ||
360 | static int if_rebuild_hdr (struct sk_buff* skb); | ||
361 | static int if_send(struct sk_buff* skb, struct net_device* dev); | ||
362 | static struct net_device_stats *if_stats(struct net_device* dev); | ||
363 | |||
364 | static void if_tx_timeout(struct net_device *dev); | ||
365 | |||
366 | /*================================================= | ||
367 | * Interrupt handlers | ||
368 | */ | ||
369 | static void wpx_isr (sdla_t *); | ||
370 | static void rx_intr (sdla_t *); | ||
371 | static void tx_intr (sdla_t *); | ||
372 | static void status_intr (sdla_t *); | ||
373 | static void event_intr (sdla_t *); | ||
374 | static void spur_intr (sdla_t *); | ||
375 | static void timer_intr (sdla_t *); | ||
376 | |||
377 | static int tx_intr_send(sdla_t *card, struct net_device *dev); | ||
378 | static struct net_device *move_dev_to_next(sdla_t *card, | ||
379 | struct net_device *dev); | ||
380 | |||
381 | /*================================================= | ||
382 | * Background polling routines | ||
383 | */ | ||
384 | static void wpx_poll (sdla_t* card); | ||
385 | static void poll_disconnected (sdla_t* card); | ||
386 | static void poll_connecting (sdla_t* card); | ||
387 | static void poll_active (sdla_t* card); | ||
388 | static void trigger_x25_poll(sdla_t *card); | ||
389 | static void x25_timer_routine(unsigned long data); | ||
390 | |||
391 | |||
392 | |||
393 | /*================================================= | ||
394 | * X.25 firmware interface functions | ||
395 | */ | ||
396 | static int x25_get_version (sdla_t* card, char* str); | ||
397 | static int x25_configure (sdla_t* card, TX25Config* conf); | ||
398 | static int hdlc_configure (sdla_t* card, TX25Config* conf); | ||
399 | static int set_hdlc_level (sdla_t* card); | ||
400 | static int x25_get_err_stats (sdla_t* card); | ||
401 | static int x25_get_stats (sdla_t* card); | ||
402 | static int x25_set_intr_mode (sdla_t* card, int mode); | ||
403 | static int x25_close_hdlc (sdla_t* card); | ||
404 | static int x25_open_hdlc (sdla_t* card); | ||
405 | static int x25_setup_hdlc (sdla_t* card); | ||
406 | static int x25_set_dtr (sdla_t* card, int dtr); | ||
407 | static int x25_get_chan_conf (sdla_t* card, x25_channel_t* chan); | ||
408 | static int x25_place_call (sdla_t* card, x25_channel_t* chan); | ||
409 | static int x25_accept_call (sdla_t* card, int lcn, int qdm); | ||
410 | static int x25_clear_call (sdla_t* card, int lcn, int cause, int diagn); | ||
411 | static int x25_send (sdla_t* card, int lcn, int qdm, int len, void* buf); | ||
412 | static int x25_fetch_events (sdla_t* card); | ||
413 | static int x25_error (sdla_t* card, int err, int cmd, int lcn); | ||
414 | |||
415 | /*================================================= | ||
416 | * X.25 asynchronous event handlers | ||
417 | */ | ||
418 | static int incoming_call (sdla_t* card, int cmd, int lcn, TX25Mbox* mb); | ||
419 | static int call_accepted (sdla_t* card, int cmd, int lcn, TX25Mbox* mb); | ||
420 | static int call_cleared (sdla_t* card, int cmd, int lcn, TX25Mbox* mb); | ||
421 | static int timeout_event (sdla_t* card, int cmd, int lcn, TX25Mbox* mb); | ||
422 | static int restart_event (sdla_t* card, int cmd, int lcn, TX25Mbox* mb); | ||
423 | |||
424 | |||
425 | /*================================================= | ||
426 | * Miscellaneous functions | ||
427 | */ | ||
428 | static int connect (sdla_t* card); | ||
429 | static int disconnect (sdla_t* card); | ||
430 | static struct net_device* get_dev_by_lcn(struct wan_device* wandev, | ||
431 | unsigned lcn); | ||
432 | static int chan_connect(struct net_device* dev); | ||
433 | static int chan_disc(struct net_device* dev); | ||
434 | static void set_chan_state(struct net_device* dev, int state); | ||
435 | static int chan_send(struct net_device *dev, void* buff, unsigned data_len, | ||
436 | unsigned char tx_intr); | ||
437 | static unsigned char bps_to_speed_code (unsigned long bps); | ||
438 | static unsigned int dec_to_uint (unsigned char* str, int len); | ||
439 | static unsigned int hex_to_uint (unsigned char*, int); | ||
440 | static void parse_call_info (unsigned char*, x25_call_info_t*); | ||
441 | static struct net_device *find_channel(sdla_t *card, unsigned lcn); | ||
442 | static void bind_lcn_to_dev(sdla_t *card, struct net_device *dev, unsigned lcn); | ||
443 | static void setup_for_delayed_transmit(struct net_device *dev, | ||
444 | void *buf, unsigned len); | ||
445 | |||
446 | |||
447 | /*================================================= | ||
448 | * X25 API Functions | ||
449 | */ | ||
450 | static int wanpipe_pull_data_in_skb(sdla_t *card, struct net_device *dev, | ||
451 | struct sk_buff **); | ||
452 | static void timer_intr_exec(sdla_t *, unsigned char); | ||
453 | static int execute_delayed_cmd(sdla_t *card, struct net_device *dev, | ||
454 | mbox_cmd_t *usr_cmd, char bad_cmd); | ||
455 | static int api_incoming_call (sdla_t*, TX25Mbox *, int); | ||
456 | static int alloc_and_init_skb_buf (sdla_t *,struct sk_buff **, int); | ||
457 | static void send_delayed_cmd_result(sdla_t *card, struct net_device *dev, | ||
458 | TX25Mbox* mbox); | ||
459 | static int clear_confirm_event (sdla_t *, TX25Mbox*); | ||
460 | static void send_oob_msg (sdla_t *card, struct net_device *dev, TX25Mbox *mbox); | ||
461 | static int timer_intr_cmd_exec(sdla_t *card); | ||
462 | static void api_oob_event (sdla_t *card,TX25Mbox *mbox); | ||
463 | static int check_bad_command(sdla_t *card, struct net_device *dev); | ||
464 | static int channel_disconnect(sdla_t* card, struct net_device *dev); | ||
465 | static void hdlc_link_down (sdla_t*); | ||
466 | |||
467 | /*================================================= | ||
468 | * XPIPEMON Functions | ||
469 | */ | ||
470 | static int process_udp_mgmt_pkt(sdla_t *); | ||
471 | static int udp_pkt_type( struct sk_buff *, sdla_t*); | ||
472 | static int reply_udp( unsigned char *, unsigned int); | ||
473 | static void init_x25_channel_struct( x25_channel_t *); | ||
474 | static void init_global_statistics( sdla_t *); | ||
475 | static int store_udp_mgmt_pkt(int udp_type, char udp_pkt_src, sdla_t *card, | ||
476 | struct net_device *dev, | ||
477 | struct sk_buff *skb, int lcn); | ||
478 | static unsigned short calc_checksum (char *, int); | ||
479 | |||
480 | |||
481 | |||
482 | /*================================================= | ||
483 | * IPX functions | ||
484 | */ | ||
485 | static void switch_net_numbers(unsigned char *, unsigned long, unsigned char); | ||
486 | static int handle_IPXWAN(unsigned char *, char *, unsigned char , | ||
487 | unsigned long , unsigned short ); | ||
488 | |||
489 | extern void disable_irq(unsigned int); | ||
490 | extern void enable_irq(unsigned int); | ||
491 | |||
492 | static void S508_S514_lock(sdla_t *, unsigned long *); | ||
493 | static void S508_S514_unlock(sdla_t *, unsigned long *); | ||
494 | |||
495 | |||
496 | /*================================================= | ||
497 | * Global Variables | ||
498 | *=================================================*/ | ||
499 | |||
500 | |||
501 | |||
502 | /*================================================= | ||
503 | * Public Functions | ||
504 | *=================================================*/ | ||
505 | |||
506 | |||
507 | |||
508 | |||
509 | /*=================================================================== | ||
510 | * wpx_init: X.25 Protocol Initialization routine. | ||
511 | * | ||
512 | * Purpose: To initialize the protocol/firmware. | ||
513 | * | ||
514 | * Rationale: This function is called by setup() function, in | ||
515 | * sdlamain.c, to dynamically setup the x25 protocol. | ||
516 | * This is the first protocol specific function, which | ||
517 | * executes once on startup. | ||
518 | * | ||
519 | * Description: This procedure initializes the x25 firmware and | ||
520 | * sets up the mailbox, transmit and receive buffer | ||
521 | * pointers. It also initializes all debugging structures | ||
522 | * and sets up the X25 environment. | ||
523 | * | ||
524 | * Sets up hardware options defined by user in [wanpipe#] | ||
525 | * section of wanpipe#.conf configuration file. | ||
526 | * | ||
527 | * At this point adapter is completely initialized | ||
528 | * and X.25 firmware is running. | ||
529 | * o read firmware version (to make sure it's alive) | ||
530 | * o configure adapter | ||
531 | * o initialize protocol-specific fields of the | ||
532 | * adapter data space. | ||
533 | * | ||
534 | * Called by: setup() function in sdlamain.c | ||
535 | * | ||
536 | * Assumptions: None | ||
537 | * | ||
538 | * Warnings: None | ||
539 | * | ||
540 | * Return: 0 o.k. | ||
541 | * < 0 failure. | ||
542 | */ | ||
543 | |||
544 | int wpx_init (sdla_t* card, wandev_conf_t* conf) | ||
545 | { | ||
546 | union{ | ||
547 | char str[80]; | ||
548 | TX25Config cfg; | ||
549 | } u; | ||
550 | |||
551 | /* Verify configuration ID */ | ||
552 | if (conf->config_id != WANCONFIG_X25){ | ||
553 | printk(KERN_INFO "%s: invalid configuration ID %u!\n", | ||
554 | card->devname, conf->config_id) | ||
555 | ; | ||
556 | return -EINVAL; | ||
557 | } | ||
558 | |||
559 | /* Initialize protocol-specific fields */ | ||
560 | card->mbox = (void*)(card->hw.dpmbase + X25_MBOX_OFFS); | ||
561 | card->rxmb = (void*)(card->hw.dpmbase + X25_RXMBOX_OFFS); | ||
562 | card->flags = (void*)(card->hw.dpmbase + X25_STATUS_OFFS); | ||
563 | |||
564 | /* Initialize for S514 Card */ | ||
565 | if(card->hw.type == SDLA_S514) { | ||
566 | card->mbox += X25_MB_VECTOR; | ||
567 | card->flags += X25_MB_VECTOR; | ||
568 | card->rxmb += X25_MB_VECTOR; | ||
569 | } | ||
570 | |||
571 | |||
572 | /* Read firmware version. Note that when adapter initializes, it | ||
573 | * clears the mailbox, so it may appear that the first command was | ||
574 | * executed successfully when in fact it was merely erased. To work | ||
575 | * around this, we execute the first command twice. | ||
576 | */ | ||
577 | if (x25_get_version(card, NULL) || x25_get_version(card, u.str)) | ||
578 | return -EIO; | ||
579 | |||
580 | |||
581 | /* X25 firmware can run ether in X25 or LAPB HDLC mode. | ||
582 | * Check the user defined option and configure accordingly */ | ||
583 | if (conf->u.x25.LAPB_hdlc_only == WANOPT_YES){ | ||
584 | if (set_hdlc_level(card) != CMD_OK){ | ||
585 | return -EIO; | ||
586 | }else{ | ||
587 | printk(KERN_INFO "%s: running LAP_B HDLC firmware v%s\n", | ||
588 | card->devname, u.str); | ||
589 | } | ||
590 | card->u.x.LAPB_hdlc = 1; | ||
591 | }else{ | ||
592 | printk(KERN_INFO "%s: running X.25 firmware v%s\n", | ||
593 | card->devname, u.str); | ||
594 | card->u.x.LAPB_hdlc = 0; | ||
595 | } | ||
596 | |||
597 | /* Configure adapter. Here we set resonable defaults, then parse | ||
598 | * device configuration structure and set configuration options. | ||
599 | * Most configuration options are verified and corrected (if | ||
600 | * necessary) since we can't rely on the adapter to do so. | ||
601 | */ | ||
602 | memset(&u.cfg, 0, sizeof(u.cfg)); | ||
603 | u.cfg.t1 = 3; | ||
604 | u.cfg.n2 = 10; | ||
605 | u.cfg.autoHdlc = 1; /* automatic HDLC connection */ | ||
606 | u.cfg.hdlcWindow = 7; | ||
607 | u.cfg.pktWindow = 2; | ||
608 | u.cfg.station = 1; /* DTE */ | ||
609 | u.cfg.options = 0x0090; /* disable D-bit pragmatics */ | ||
610 | u.cfg.ccittCompat = 1988; | ||
611 | u.cfg.t10t20 = 30; | ||
612 | u.cfg.t11t21 = 30; | ||
613 | u.cfg.t12t22 = 30; | ||
614 | u.cfg.t13t23 = 30; | ||
615 | u.cfg.t16t26 = 30; | ||
616 | u.cfg.t28 = 30; | ||
617 | u.cfg.r10r20 = 5; | ||
618 | u.cfg.r12r22 = 5; | ||
619 | u.cfg.r13r23 = 5; | ||
620 | u.cfg.responseOpt = 1; /* RR's after every packet */ | ||
621 | |||
622 | if (card->u.x.LAPB_hdlc){ | ||
623 | u.cfg.hdlcMTU = 1027; | ||
624 | } | ||
625 | |||
626 | if (conf->u.x25.x25_conf_opt){ | ||
627 | u.cfg.options = conf->u.x25.x25_conf_opt; | ||
628 | } | ||
629 | |||
630 | if (conf->clocking != WANOPT_EXTERNAL) | ||
631 | u.cfg.baudRate = bps_to_speed_code(conf->bps); | ||
632 | |||
633 | if (conf->station != WANOPT_DTE){ | ||
634 | u.cfg.station = 0; /* DCE mode */ | ||
635 | } | ||
636 | |||
637 | if (conf->interface != WANOPT_RS232 ){ | ||
638 | u.cfg.hdlcOptions |= 0x80; /* V35 mode */ | ||
639 | } | ||
640 | |||
641 | /* adjust MTU */ | ||
642 | if (!conf->mtu || (conf->mtu >= 1024)) | ||
643 | card->wandev.mtu = 1024; | ||
644 | else if (conf->mtu >= 512) | ||
645 | card->wandev.mtu = 512; | ||
646 | else if (conf->mtu >= 256) | ||
647 | card->wandev.mtu = 256; | ||
648 | else if (conf->mtu >= 128) | ||
649 | card->wandev.mtu = 128; | ||
650 | else | ||
651 | card->wandev.mtu = 64; | ||
652 | |||
653 | u.cfg.defPktSize = u.cfg.pktMTU = card->wandev.mtu; | ||
654 | |||
655 | if (conf->u.x25.hi_pvc){ | ||
656 | card->u.x.hi_pvc = min_t(unsigned int, conf->u.x25.hi_pvc, MAX_LCN_NUM); | ||
657 | card->u.x.lo_pvc = min_t(unsigned int, conf->u.x25.lo_pvc, card->u.x.hi_pvc); | ||
658 | } | ||
659 | |||
660 | if (conf->u.x25.hi_svc){ | ||
661 | card->u.x.hi_svc = min_t(unsigned int, conf->u.x25.hi_svc, MAX_LCN_NUM); | ||
662 | card->u.x.lo_svc = min_t(unsigned int, conf->u.x25.lo_svc, card->u.x.hi_svc); | ||
663 | } | ||
664 | |||
665 | /* Figure out the total number of channels to configure */ | ||
666 | card->u.x.num_of_ch = 0; | ||
667 | if (card->u.x.hi_svc != 0){ | ||
668 | card->u.x.num_of_ch = (card->u.x.hi_svc - card->u.x.lo_svc) + 1; | ||
669 | } | ||
670 | if (card->u.x.hi_pvc != 0){ | ||
671 | card->u.x.num_of_ch += (card->u.x.hi_pvc - card->u.x.lo_pvc) + 1; | ||
672 | } | ||
673 | |||
674 | if (card->u.x.num_of_ch == 0){ | ||
675 | printk(KERN_INFO "%s: ERROR, Minimum number of PVC/SVC channels is 1 !\n" | ||
676 | "%s: Please set the Lowest/Highest PVC/SVC values !\n", | ||
677 | card->devname,card->devname); | ||
678 | return -ECHRNG; | ||
679 | } | ||
680 | |||
681 | u.cfg.loPVC = card->u.x.lo_pvc; | ||
682 | u.cfg.hiPVC = card->u.x.hi_pvc; | ||
683 | u.cfg.loTwoWaySVC = card->u.x.lo_svc; | ||
684 | u.cfg.hiTwoWaySVC = card->u.x.hi_svc; | ||
685 | |||
686 | if (conf->u.x25.hdlc_window) | ||
687 | u.cfg.hdlcWindow = min_t(unsigned int, conf->u.x25.hdlc_window, 7); | ||
688 | if (conf->u.x25.pkt_window) | ||
689 | u.cfg.pktWindow = min_t(unsigned int, conf->u.x25.pkt_window, 7); | ||
690 | |||
691 | if (conf->u.x25.t1) | ||
692 | u.cfg.t1 = min_t(unsigned int, conf->u.x25.t1, 30); | ||
693 | if (conf->u.x25.t2) | ||
694 | u.cfg.t2 = min_t(unsigned int, conf->u.x25.t2, 29); | ||
695 | if (conf->u.x25.t4) | ||
696 | u.cfg.t4 = min_t(unsigned int, conf->u.x25.t4, 240); | ||
697 | if (conf->u.x25.n2) | ||
698 | u.cfg.n2 = min_t(unsigned int, conf->u.x25.n2, 30); | ||
699 | |||
700 | if (conf->u.x25.t10_t20) | ||
701 | u.cfg.t10t20 = min_t(unsigned int, conf->u.x25.t10_t20,255); | ||
702 | if (conf->u.x25.t11_t21) | ||
703 | u.cfg.t11t21 = min_t(unsigned int, conf->u.x25.t11_t21,255); | ||
704 | if (conf->u.x25.t12_t22) | ||
705 | u.cfg.t12t22 = min_t(unsigned int, conf->u.x25.t12_t22,255); | ||
706 | if (conf->u.x25.t13_t23) | ||
707 | u.cfg.t13t23 = min_t(unsigned int, conf->u.x25.t13_t23,255); | ||
708 | if (conf->u.x25.t16_t26) | ||
709 | u.cfg.t16t26 = min_t(unsigned int, conf->u.x25.t16_t26, 255); | ||
710 | if (conf->u.x25.t28) | ||
711 | u.cfg.t28 = min_t(unsigned int, conf->u.x25.t28, 255); | ||
712 | |||
713 | if (conf->u.x25.r10_r20) | ||
714 | u.cfg.r10r20 = min_t(unsigned int, conf->u.x25.r10_r20,250); | ||
715 | if (conf->u.x25.r12_r22) | ||
716 | u.cfg.r12r22 = min_t(unsigned int, conf->u.x25.r12_r22,250); | ||
717 | if (conf->u.x25.r13_r23) | ||
718 | u.cfg.r13r23 = min_t(unsigned int, conf->u.x25.r13_r23,250); | ||
719 | |||
720 | |||
721 | if (conf->u.x25.ccitt_compat) | ||
722 | u.cfg.ccittCompat = conf->u.x25.ccitt_compat; | ||
723 | |||
724 | /* initialize adapter */ | ||
725 | if (card->u.x.LAPB_hdlc){ | ||
726 | if (hdlc_configure(card, &u.cfg) != CMD_OK) | ||
727 | return -EIO; | ||
728 | }else{ | ||
729 | if (x25_configure(card, &u.cfg) != CMD_OK) | ||
730 | return -EIO; | ||
731 | } | ||
732 | |||
733 | if ((x25_close_hdlc(card) != CMD_OK) || /* close HDLC link */ | ||
734 | (x25_set_dtr(card, 0) != CMD_OK)) /* drop DTR */ | ||
735 | return -EIO; | ||
736 | |||
737 | /* Initialize protocol-specific fields of adapter data space */ | ||
738 | card->wandev.bps = conf->bps; | ||
739 | card->wandev.interface = conf->interface; | ||
740 | card->wandev.clocking = conf->clocking; | ||
741 | card->wandev.station = conf->station; | ||
742 | card->isr = &wpx_isr; | ||
743 | card->poll = NULL; //&wpx_poll; | ||
744 | card->disable_comm = &disable_comm; | ||
745 | card->exec = &wpx_exec; | ||
746 | card->wandev.update = &update; | ||
747 | card->wandev.new_if = &new_if; | ||
748 | card->wandev.del_if = &del_if; | ||
749 | |||
750 | /* WARNING: This function cannot exit with an error | ||
751 | * after the change of state */ | ||
752 | card->wandev.state = WAN_DISCONNECTED; | ||
753 | |||
754 | card->wandev.enable_tx_int = 0; | ||
755 | card->irq_dis_if_send_count = 0; | ||
756 | card->irq_dis_poll_count = 0; | ||
757 | card->u.x.tx_dev = NULL; | ||
758 | card->u.x.no_dev = 0; | ||
759 | |||
760 | |||
761 | /* Configure for S514 PCI Card */ | ||
762 | if (card->hw.type == SDLA_S514) { | ||
763 | card->u.x.hdlc_buf_status = | ||
764 | (volatile unsigned char *) | ||
765 | (card->hw.dpmbase + X25_MB_VECTOR+ X25_MISC_HDLC_BITS); | ||
766 | }else{ | ||
767 | card->u.x.hdlc_buf_status = | ||
768 | (volatile unsigned char *)(card->hw.dpmbase + X25_MISC_HDLC_BITS); | ||
769 | } | ||
770 | |||
771 | card->u.x.poll_device=NULL; | ||
772 | card->wandev.udp_port = conf->udp_port; | ||
773 | |||
774 | /* Enable or disable call setup logging */ | ||
775 | if (conf->u.x25.logging == WANOPT_YES){ | ||
776 | printk(KERN_INFO "%s: Enabling Call Logging.\n", | ||
777 | card->devname); | ||
778 | card->u.x.logging = 1; | ||
779 | }else{ | ||
780 | card->u.x.logging = 0; | ||
781 | } | ||
782 | |||
783 | /* Enable or disable modem status reporting */ | ||
784 | if (conf->u.x25.oob_on_modem == WANOPT_YES){ | ||
785 | printk(KERN_INFO "%s: Enabling OOB on Modem change.\n", | ||
786 | card->devname); | ||
787 | card->u.x.oob_on_modem = 1; | ||
788 | }else{ | ||
789 | card->u.x.oob_on_modem = 0; | ||
790 | } | ||
791 | |||
792 | init_global_statistics(card); | ||
793 | |||
794 | INIT_WORK(&card->u.x.x25_poll_work, (void *)wpx_poll, card); | ||
795 | |||
796 | init_timer(&card->u.x.x25_timer); | ||
797 | card->u.x.x25_timer.data = (unsigned long)card; | ||
798 | card->u.x.x25_timer.function = x25_timer_routine; | ||
799 | |||
800 | return 0; | ||
801 | } | ||
802 | |||
803 | /*========================================================= | ||
804 | * WAN Device Driver Entry Points | ||
805 | *========================================================*/ | ||
806 | |||
807 | /*============================================================ | ||
808 | * Name: update(), Update device status & statistics. | ||
809 | * | ||
810 | * Purpose: To provide debugging and statitical | ||
811 | * information to the /proc file system. | ||
812 | * /proc/net/wanrouter/wanpipe# | ||
813 | * | ||
814 | * Rationale: The /proc file system is used to collect | ||
815 | * information about the kernel and drivers. | ||
816 | * Using the /proc file system the user | ||
817 | * can see exactly what the sangoma drivers are | ||
818 | * doing. And in what state they are in. | ||
819 | * | ||
820 | * Description: Collect all driver statistical information | ||
821 | * and pass it to the top laywer. | ||
822 | * | ||
823 | * Since we have to execute a debugging command, | ||
824 | * to obtain firmware statitics, we trigger a | ||
825 | * UPDATE function within the timer interrtup. | ||
826 | * We wait until the timer update is complete. | ||
827 | * Once complete return the appropriate return | ||
828 | * code to indicate that the update was successful. | ||
829 | * | ||
830 | * Called by: device_stat() in wanmain.c | ||
831 | * | ||
832 | * Assumptions: | ||
833 | * | ||
834 | * Warnings: This function will degrade the performance | ||
835 | * of the router, since it uses the mailbox. | ||
836 | * | ||
837 | * Return: 0 OK | ||
838 | * <0 Failed (or busy). | ||
839 | */ | ||
840 | |||
841 | static int update(struct wan_device* wandev) | ||
842 | { | ||
843 | volatile sdla_t* card; | ||
844 | TX25Status* status; | ||
845 | unsigned long timeout; | ||
846 | |||
847 | /* sanity checks */ | ||
848 | if ((wandev == NULL) || (wandev->private == NULL)) | ||
849 | return -EFAULT; | ||
850 | |||
851 | if (wandev->state == WAN_UNCONFIGURED) | ||
852 | return -ENODEV; | ||
853 | |||
854 | if (test_bit(SEND_CRIT, (void*)&wandev->critical)) | ||
855 | return -EAGAIN; | ||
856 | |||
857 | if (!wandev->dev) | ||
858 | return -ENODEV; | ||
859 | |||
860 | card = wandev->private; | ||
861 | status = card->flags; | ||
862 | |||
863 | card->u.x.timer_int_enabled |= TMR_INT_ENABLED_UPDATE; | ||
864 | status->imask |= INTR_ON_TIMER; | ||
865 | timeout = jiffies; | ||
866 | |||
867 | for (;;){ | ||
868 | if (!(card->u.x.timer_int_enabled & TMR_INT_ENABLED_UPDATE)){ | ||
869 | break; | ||
870 | } | ||
871 | if (time_after(jiffies, timeout + 1*HZ)){ | ||
872 | card->u.x.timer_int_enabled &= ~TMR_INT_ENABLED_UPDATE; | ||
873 | return -EAGAIN; | ||
874 | } | ||
875 | } | ||
876 | return 0; | ||
877 | } | ||
878 | |||
879 | |||
880 | /*=================================================================== | ||
881 | * Name: new_if | ||
882 | * | ||
883 | * Purpose: To allocate and initialize resources for a | ||
884 | * new logical channel. | ||
885 | * | ||
886 | * Rationale: A new channel can be added dynamically via | ||
887 | * ioctl call. | ||
888 | * | ||
889 | * Description: Allocate a private channel structure, x25_channel_t. | ||
890 | * Parse the user interface options from wanpipe#.conf | ||
891 | * configuration file. | ||
892 | * Bind the private are into the network device private | ||
893 | * area pointer (dev->priv). | ||
894 | * Prepare the network device structure for registration. | ||
895 | * | ||
896 | * Called by: ROUTER_IFNEW Ioctl call, from wanrouter_ioctl() | ||
897 | * (wanmain.c) | ||
898 | * | ||
899 | * Assumptions: None | ||
900 | * | ||
901 | * Warnings: None | ||
902 | * | ||
903 | * Return: 0 Ok | ||
904 | * <0 Failed (channel will not be created) | ||
905 | */ | ||
906 | static int new_if(struct wan_device* wandev, struct net_device* dev, | ||
907 | wanif_conf_t* conf) | ||
908 | { | ||
909 | sdla_t* card = wandev->private; | ||
910 | x25_channel_t* chan; | ||
911 | int err = 0; | ||
912 | |||
913 | if ((conf->name[0] == '\0') || (strlen(conf->name) > WAN_IFNAME_SZ)){ | ||
914 | printk(KERN_INFO "%s: invalid interface name!\n", | ||
915 | card->devname); | ||
916 | return -EINVAL; | ||
917 | } | ||
918 | |||
919 | if(card->wandev.new_if_cnt++ > 0 && card->u.x.LAPB_hdlc) { | ||
920 | printk(KERN_INFO "%s: Error: Running LAPB HDLC Mode !\n", | ||
921 | card->devname); | ||
922 | printk(KERN_INFO | ||
923 | "%s: Maximum number of network interfaces must be one !\n", | ||
924 | card->devname); | ||
925 | return -EEXIST; | ||
926 | } | ||
927 | |||
928 | /* allocate and initialize private data */ | ||
929 | chan = kmalloc(sizeof(x25_channel_t), GFP_ATOMIC); | ||
930 | if (chan == NULL){ | ||
931 | return -ENOMEM; | ||
932 | } | ||
933 | |||
934 | memset(chan, 0, sizeof(x25_channel_t)); | ||
935 | |||
936 | /* Bug Fix: Seg Err on PVC startup | ||
937 | * It must be here since bind_lcn_to_dev expects | ||
938 | * it bellow */ | ||
939 | dev->priv = chan; | ||
940 | |||
941 | strcpy(chan->name, conf->name); | ||
942 | chan->card = card; | ||
943 | chan->dev = dev; | ||
944 | chan->common.sk = NULL; | ||
945 | chan->common.func = NULL; | ||
946 | chan->common.rw_bind = 0; | ||
947 | chan->tx_skb = chan->rx_skb = NULL; | ||
948 | |||
949 | /* verify media address */ | ||
950 | if (conf->addr[0] == '@'){ /* SVC */ | ||
951 | chan->common.svc = 1; | ||
952 | strncpy(chan->addr, &conf->addr[1], WAN_ADDRESS_SZ); | ||
953 | |||
954 | /* Set channel timeouts (default if not specified) */ | ||
955 | chan->idle_timeout = (conf->idle_timeout) ? | ||
956 | conf->idle_timeout : 90; | ||
957 | chan->hold_timeout = (conf->hold_timeout) ? | ||
958 | conf->hold_timeout : 10; | ||
959 | |||
960 | }else if (isdigit(conf->addr[0])){ /* PVC */ | ||
961 | int lcn = dec_to_uint(conf->addr, 0); | ||
962 | |||
963 | if ((lcn >= card->u.x.lo_pvc) && (lcn <= card->u.x.hi_pvc)){ | ||
964 | bind_lcn_to_dev (card, dev, lcn); | ||
965 | }else{ | ||
966 | printk(KERN_ERR | ||
967 | "%s: PVC %u is out of range on interface %s!\n", | ||
968 | wandev->name, lcn, chan->name); | ||
969 | err = -EINVAL; | ||
970 | } | ||
971 | }else{ | ||
972 | printk(KERN_ERR | ||
973 | "%s: invalid media address on interface %s!\n", | ||
974 | wandev->name, chan->name); | ||
975 | err = -EINVAL; | ||
976 | } | ||
977 | |||
978 | if(strcmp(conf->usedby, "WANPIPE") == 0){ | ||
979 | printk(KERN_INFO "%s: Running in WANPIPE mode %s\n", | ||
980 | wandev->name, chan->name); | ||
981 | chan->common.usedby = WANPIPE; | ||
982 | chan->protocol = htons(ETH_P_IP); | ||
983 | |||
984 | }else if(strcmp(conf->usedby, "API") == 0){ | ||
985 | chan->common.usedby = API; | ||
986 | printk(KERN_INFO "%s: Running in API mode %s\n", | ||
987 | wandev->name, chan->name); | ||
988 | chan->protocol = htons(X25_PROT); | ||
989 | } | ||
990 | |||
991 | |||
992 | if (err){ | ||
993 | kfree(chan); | ||
994 | dev->priv = NULL; | ||
995 | return err; | ||
996 | } | ||
997 | |||
998 | chan->enable_IPX = conf->enable_IPX; | ||
999 | |||
1000 | if (chan->enable_IPX) | ||
1001 | chan->protocol = htons(ETH_P_IPX); | ||
1002 | |||
1003 | if (conf->network_number) | ||
1004 | chan->network_number = conf->network_number; | ||
1005 | else | ||
1006 | chan->network_number = 0xDEADBEEF; | ||
1007 | |||
1008 | /* prepare network device data space for registration */ | ||
1009 | strcpy(dev->name,chan->name); | ||
1010 | |||
1011 | dev->init = &if_init; | ||
1012 | |||
1013 | init_x25_channel_struct(chan); | ||
1014 | |||
1015 | return 0; | ||
1016 | } | ||
1017 | |||
1018 | /*=================================================================== | ||
1019 | * Name: del_if(), Remove a logical channel. | ||
1020 | * | ||
1021 | * Purpose: To dynamically remove a logical channel. | ||
1022 | * | ||
1023 | * Rationale: Each logical channel should be dynamically | ||
1024 | * removable. This functin is called by an | ||
1025 | * IOCTL_IFDEL ioctl call or shutdown(). | ||
1026 | * | ||
1027 | * Description: Do nothing. | ||
1028 | * | ||
1029 | * Called by: IOCTL_IFDEL : wanrouter_ioctl() from wanmain.c | ||
1030 | * shutdown() from sdlamain.c | ||
1031 | * | ||
1032 | * Assumptions: | ||
1033 | * | ||
1034 | * Warnings: | ||
1035 | * | ||
1036 | * Return: 0 Ok. Void function. | ||
1037 | */ | ||
1038 | |||
1039 | //FIXME Del IF Should be taken out now. | ||
1040 | |||
1041 | static int del_if(struct wan_device* wandev, struct net_device* dev) | ||
1042 | { | ||
1043 | return 0; | ||
1044 | } | ||
1045 | |||
1046 | |||
1047 | /*============================================================ | ||
1048 | * Name: wpx_exec | ||
1049 | * | ||
1050 | * Description: Execute adapter interface command. | ||
1051 | * This option is currently dissabled. | ||
1052 | *===========================================================*/ | ||
1053 | |||
1054 | static int wpx_exec (struct sdla* card, void* u_cmd, void* u_data) | ||
1055 | { | ||
1056 | return 0; | ||
1057 | } | ||
1058 | |||
1059 | /*============================================================ | ||
1060 | * Name: disable_comm | ||
1061 | * | ||
1062 | * Description: Disable communications during shutdown. | ||
1063 | * Dont check return code because there is | ||
1064 | * nothing we can do about it. | ||
1065 | * | ||
1066 | * Warning: Dev and private areas are gone at this point. | ||
1067 | *===========================================================*/ | ||
1068 | |||
1069 | static void disable_comm(sdla_t* card) | ||
1070 | { | ||
1071 | disable_comm_shutdown(card); | ||
1072 | del_timer(&card->u.x.x25_timer); | ||
1073 | return; | ||
1074 | } | ||
1075 | |||
1076 | |||
1077 | /*============================================================ | ||
1078 | * Network Device Interface | ||
1079 | *===========================================================*/ | ||
1080 | |||
1081 | /*=================================================================== | ||
1082 | * Name: if_init(), Netowrk Interface Initialization | ||
1083 | * | ||
1084 | * Purpose: To initialize a network interface device structure. | ||
1085 | * | ||
1086 | * Rationale: During network interface startup, the if_init | ||
1087 | * is called by the kernel to initialize the | ||
1088 | * netowrk device structure. Thus a driver | ||
1089 | * can customze a network device. | ||
1090 | * | ||
1091 | * Description: Initialize the netowrk device call back | ||
1092 | * routines. This is where we tell the kernel | ||
1093 | * which function to use when it wants to send | ||
1094 | * via our interface. | ||
1095 | * Furthermore, we initialize the device flags, | ||
1096 | * MTU and physical address of the board. | ||
1097 | * | ||
1098 | * Called by: Kernel (/usr/src/linux/net/core/dev.c) | ||
1099 | * (dev->init()) | ||
1100 | * | ||
1101 | * Assumptions: None | ||
1102 | * | ||
1103 | * Warnings: None | ||
1104 | * | ||
1105 | * Return: 0 Ok : Void function. | ||
1106 | */ | ||
1107 | static int if_init(struct net_device* dev) | ||
1108 | { | ||
1109 | x25_channel_t* chan = dev->priv; | ||
1110 | sdla_t* card = chan->card; | ||
1111 | struct wan_device* wandev = &card->wandev; | ||
1112 | |||
1113 | /* Initialize device driver entry points */ | ||
1114 | dev->open = &if_open; | ||
1115 | dev->stop = &if_close; | ||
1116 | dev->hard_header = &if_header; | ||
1117 | dev->rebuild_header = &if_rebuild_hdr; | ||
1118 | dev->hard_start_xmit = &if_send; | ||
1119 | dev->get_stats = &if_stats; | ||
1120 | dev->tx_timeout = &if_tx_timeout; | ||
1121 | dev->watchdog_timeo = TX_TIMEOUT; | ||
1122 | |||
1123 | /* Initialize media-specific parameters */ | ||
1124 | dev->type = ARPHRD_PPP; /* ARP h/w type */ | ||
1125 | dev->flags |= IFF_POINTOPOINT; | ||
1126 | dev->flags |= IFF_NOARP; | ||
1127 | |||
1128 | if (chan->common.usedby == API){ | ||
1129 | dev->mtu = X25_CHAN_MTU+sizeof(x25api_hdr_t); | ||
1130 | }else{ | ||
1131 | dev->mtu = card->wandev.mtu; | ||
1132 | } | ||
1133 | |||
1134 | dev->hard_header_len = X25_HRDHDR_SZ; /* media header length */ | ||
1135 | dev->addr_len = 2; /* hardware address length */ | ||
1136 | |||
1137 | if (!chan->common.svc){ | ||
1138 | *(unsigned short*)dev->dev_addr = htons(chan->common.lcn); | ||
1139 | } | ||
1140 | |||
1141 | /* Initialize hardware parameters (just for reference) */ | ||
1142 | dev->irq = wandev->irq; | ||
1143 | dev->dma = wandev->dma; | ||
1144 | dev->base_addr = wandev->ioport; | ||
1145 | dev->mem_start = (unsigned long)wandev->maddr; | ||
1146 | dev->mem_end = wandev->maddr + wandev->msize - 1; | ||
1147 | |||
1148 | /* Set transmit buffer queue length */ | ||
1149 | dev->tx_queue_len = 100; | ||
1150 | SET_MODULE_OWNER(dev); | ||
1151 | |||
1152 | /* FIXME Why are we doing this */ | ||
1153 | set_chan_state(dev, WAN_DISCONNECTED); | ||
1154 | return 0; | ||
1155 | } | ||
1156 | |||
1157 | |||
1158 | /*=================================================================== | ||
1159 | * Name: if_open(), Open/Bring up the Netowrk Interface | ||
1160 | * | ||
1161 | * Purpose: To bring up a network interface. | ||
1162 | * | ||
1163 | * Rationale: | ||
1164 | * | ||
1165 | * Description: Open network interface. | ||
1166 | * o prevent module from unloading by incrementing use count | ||
1167 | * o if link is disconnected then initiate connection | ||
1168 | * | ||
1169 | * Called by: Kernel (/usr/src/linux/net/core/dev.c) | ||
1170 | * (dev->open()) | ||
1171 | * | ||
1172 | * Assumptions: None | ||
1173 | * | ||
1174 | * Warnings: None | ||
1175 | * | ||
1176 | * Return: 0 Ok | ||
1177 | * <0 Failure: Interface will not come up. | ||
1178 | */ | ||
1179 | |||
1180 | static int if_open(struct net_device* dev) | ||
1181 | { | ||
1182 | x25_channel_t* chan = dev->priv; | ||
1183 | sdla_t* card = chan->card; | ||
1184 | struct timeval tv; | ||
1185 | unsigned long smp_flags; | ||
1186 | |||
1187 | if (netif_running(dev)) | ||
1188 | return -EBUSY; | ||
1189 | |||
1190 | chan->tq_working = 0; | ||
1191 | |||
1192 | /* Initialize the workqueue */ | ||
1193 | INIT_WORK(&chan->common.wanpipe_work, (void *)x25api_bh, dev); | ||
1194 | |||
1195 | /* Allocate and initialize BH circular buffer */ | ||
1196 | /* Add 1 to MAX_BH_BUFF so we don't have test with (MAX_BH_BUFF-1) */ | ||
1197 | chan->bh_head = kmalloc((sizeof(bh_data_t)*(MAX_BH_BUFF+1)),GFP_ATOMIC); | ||
1198 | |||
1199 | if (chan->bh_head == NULL){ | ||
1200 | printk(KERN_INFO "%s: ERROR, failed to allocate memory ! BH_BUFFERS !\n", | ||
1201 | card->devname); | ||
1202 | |||
1203 | return -ENOBUFS; | ||
1204 | } | ||
1205 | memset(chan->bh_head,0,(sizeof(bh_data_t)*(MAX_BH_BUFF+1))); | ||
1206 | atomic_set(&chan->bh_buff_used, 0); | ||
1207 | |||
1208 | /* Increment the number of interfaces */ | ||
1209 | ++card->u.x.no_dev; | ||
1210 | |||
1211 | wanpipe_open(card); | ||
1212 | |||
1213 | /* LAPB protocol only uses one interface, thus | ||
1214 | * start the protocol after it comes up. */ | ||
1215 | if (card->u.x.LAPB_hdlc){ | ||
1216 | if (card->open_cnt == 1){ | ||
1217 | TX25Status* status = card->flags; | ||
1218 | S508_S514_lock(card, &smp_flags); | ||
1219 | x25_set_intr_mode(card, INTR_ON_TIMER); | ||
1220 | status->imask &= ~INTR_ON_TIMER; | ||
1221 | S508_S514_unlock(card, &smp_flags); | ||
1222 | } | ||
1223 | }else{ | ||
1224 | /* X25 can have multiple interfaces thus, start the | ||
1225 | * protocol once all interfaces are up */ | ||
1226 | |||
1227 | //FIXME: There is a bug here. If interface is | ||
1228 | //brought down and up, it will try to enable comm. | ||
1229 | if (card->open_cnt == card->u.x.num_of_ch){ | ||
1230 | |||
1231 | S508_S514_lock(card, &smp_flags); | ||
1232 | connect(card); | ||
1233 | S508_S514_unlock(card, &smp_flags); | ||
1234 | |||
1235 | mod_timer(&card->u.x.x25_timer, jiffies + HZ); | ||
1236 | } | ||
1237 | } | ||
1238 | /* Device is not up until the we are in connected state */ | ||
1239 | do_gettimeofday( &tv ); | ||
1240 | chan->router_start_time = tv.tv_sec; | ||
1241 | |||
1242 | netif_start_queue(dev); | ||
1243 | |||
1244 | return 0; | ||
1245 | } | ||
1246 | |||
1247 | /*=================================================================== | ||
1248 | * Name: if_close(), Close/Bring down the Netowrk Interface | ||
1249 | * | ||
1250 | * Purpose: To bring down a network interface. | ||
1251 | * | ||
1252 | * Rationale: | ||
1253 | * | ||
1254 | * Description: Close network interface. | ||
1255 | * o decrement use module use count | ||
1256 | * | ||
1257 | * Called by: Kernel (/usr/src/linux/net/core/dev.c) | ||
1258 | * (dev->close()) | ||
1259 | * ifconfig <name> down: will trigger the kernel | ||
1260 | * which will call this function. | ||
1261 | * | ||
1262 | * Assumptions: None | ||
1263 | * | ||
1264 | * Warnings: None | ||
1265 | * | ||
1266 | * Return: 0 Ok | ||
1267 | * <0 Failure: Interface will not exit properly. | ||
1268 | */ | ||
1269 | static int if_close(struct net_device* dev) | ||
1270 | { | ||
1271 | x25_channel_t* chan = dev->priv; | ||
1272 | sdla_t* card = chan->card; | ||
1273 | unsigned long smp_flags; | ||
1274 | |||
1275 | netif_stop_queue(dev); | ||
1276 | |||
1277 | if ((chan->common.state == WAN_CONNECTED) || | ||
1278 | (chan->common.state == WAN_CONNECTING)){ | ||
1279 | S508_S514_lock(card, &smp_flags); | ||
1280 | chan_disc(dev); | ||
1281 | S508_S514_unlock(card, &smp_flags); | ||
1282 | } | ||
1283 | |||
1284 | wanpipe_close(card); | ||
1285 | |||
1286 | S508_S514_lock(card, &smp_flags); | ||
1287 | if (chan->bh_head){ | ||
1288 | int i; | ||
1289 | struct sk_buff *skb; | ||
1290 | |||
1291 | for (i=0; i<(MAX_BH_BUFF+1); i++){ | ||
1292 | skb = ((bh_data_t *)&chan->bh_head[i])->skb; | ||
1293 | if (skb != NULL){ | ||
1294 | dev_kfree_skb_any(skb); | ||
1295 | } | ||
1296 | } | ||
1297 | kfree(chan->bh_head); | ||
1298 | chan->bh_head=NULL; | ||
1299 | } | ||
1300 | S508_S514_unlock(card, &smp_flags); | ||
1301 | |||
1302 | /* If this is the last close, disconnect physical link */ | ||
1303 | if (!card->open_cnt){ | ||
1304 | S508_S514_lock(card, &smp_flags); | ||
1305 | disconnect(card); | ||
1306 | x25_set_intr_mode(card, 0); | ||
1307 | S508_S514_unlock(card, &smp_flags); | ||
1308 | } | ||
1309 | |||
1310 | /* Decrement the number of interfaces */ | ||
1311 | --card->u.x.no_dev; | ||
1312 | return 0; | ||
1313 | } | ||
1314 | |||
1315 | /*====================================================================== | ||
1316 | * Build media header. | ||
1317 | * o encapsulate packet according to encapsulation type. | ||
1318 | * | ||
1319 | * The trick here is to put packet type (Ethertype) into 'protocol' | ||
1320 | * field of the socket buffer, so that we don't forget it. | ||
1321 | * If encapsulation fails, set skb->protocol to 0 and discard | ||
1322 | * packet later. | ||
1323 | * | ||
1324 | * Return: media header length. | ||
1325 | *======================================================================*/ | ||
1326 | |||
1327 | static int if_header(struct sk_buff* skb, struct net_device* dev, | ||
1328 | unsigned short type, void* daddr, void* saddr, | ||
1329 | unsigned len) | ||
1330 | { | ||
1331 | x25_channel_t* chan = dev->priv; | ||
1332 | int hdr_len = dev->hard_header_len; | ||
1333 | |||
1334 | skb->protocol = htons(type); | ||
1335 | if (!chan->protocol){ | ||
1336 | hdr_len = wanrouter_encapsulate(skb, dev, type); | ||
1337 | if (hdr_len < 0){ | ||
1338 | hdr_len = 0; | ||
1339 | skb->protocol = htons(0); | ||
1340 | } | ||
1341 | } | ||
1342 | return hdr_len; | ||
1343 | } | ||
1344 | |||
1345 | /*=============================================================== | ||
1346 | * Re-build media header. | ||
1347 | * | ||
1348 | * Return: 1 physical address resolved. | ||
1349 | * 0 physical address not resolved | ||
1350 | *==============================================================*/ | ||
1351 | |||
1352 | static int if_rebuild_hdr (struct sk_buff* skb) | ||
1353 | { | ||
1354 | struct net_device *dev = skb->dev; | ||
1355 | x25_channel_t* chan = dev->priv; | ||
1356 | sdla_t* card = chan->card; | ||
1357 | |||
1358 | printk(KERN_INFO "%s: rebuild_header() called for interface %s!\n", | ||
1359 | card->devname, dev->name); | ||
1360 | return 1; | ||
1361 | } | ||
1362 | |||
1363 | |||
1364 | /*============================================================================ | ||
1365 | * Handle transmit timeout event from netif watchdog | ||
1366 | */ | ||
1367 | static void if_tx_timeout(struct net_device *dev) | ||
1368 | { | ||
1369 | x25_channel_t* chan = dev->priv; | ||
1370 | sdla_t *card = chan->card; | ||
1371 | |||
1372 | /* If our device stays busy for at least 5 seconds then we will | ||
1373 | * kick start the device by making dev->tbusy = 0. We expect | ||
1374 | * that our device never stays busy more than 5 seconds. So this | ||
1375 | * is only used as a last resort. | ||
1376 | */ | ||
1377 | |||
1378 | ++chan->if_send_stat.if_send_tbusy_timeout; | ||
1379 | printk (KERN_INFO "%s: Transmit timed out on %s\n", | ||
1380 | card->devname, dev->name); | ||
1381 | netif_wake_queue (dev); | ||
1382 | } | ||
1383 | |||
1384 | |||
1385 | /*========================================================================= | ||
1386 | * Send a packet on a network interface. | ||
1387 | * o set tbusy flag (marks start of the transmission). | ||
1388 | * o check link state. If link is not up, then drop the packet. | ||
1389 | * o check channel status. If it's down then initiate a call. | ||
1390 | * o pass a packet to corresponding WAN device. | ||
1391 | * o free socket buffer | ||
1392 | * | ||
1393 | * Return: 0 complete (socket buffer must be freed) | ||
1394 | * non-0 packet may be re-transmitted (tbusy must be set) | ||
1395 | * | ||
1396 | * Notes: | ||
1397 | * 1. This routine is called either by the protocol stack or by the "net | ||
1398 | * bottom half" (with interrupts enabled). | ||
1399 | * 2. Setting tbusy flag will inhibit further transmit requests from the | ||
1400 | * protocol stack and can be used for flow control with protocol layer. | ||
1401 | * | ||
1402 | *========================================================================*/ | ||
1403 | |||
1404 | static int if_send(struct sk_buff* skb, struct net_device* dev) | ||
1405 | { | ||
1406 | x25_channel_t* chan = dev->priv; | ||
1407 | sdla_t* card = chan->card; | ||
1408 | TX25Status* status = card->flags; | ||
1409 | int udp_type; | ||
1410 | unsigned long smp_flags=0; | ||
1411 | |||
1412 | ++chan->if_send_stat.if_send_entry; | ||
1413 | |||
1414 | netif_stop_queue(dev); | ||
1415 | |||
1416 | /* No need to check frame length, since socket code | ||
1417 | * will perform the check for us */ | ||
1418 | |||
1419 | chan->tick_counter = jiffies; | ||
1420 | |||
1421 | /* Critical region starts here */ | ||
1422 | S508_S514_lock(card, &smp_flags); | ||
1423 | |||
1424 | if (test_and_set_bit(SEND_CRIT, (void*)&card->wandev.critical)){ | ||
1425 | printk(KERN_INFO "Hit critical in if_send()! %lx\n",card->wandev.critical); | ||
1426 | goto if_send_crit_exit; | ||
1427 | } | ||
1428 | |||
1429 | udp_type = udp_pkt_type(skb, card); | ||
1430 | |||
1431 | if(udp_type != UDP_INVALID_TYPE) { | ||
1432 | |||
1433 | if(store_udp_mgmt_pkt(udp_type, UDP_PKT_FRM_STACK, card, dev, skb, | ||
1434 | chan->common.lcn)) { | ||
1435 | |||
1436 | status->imask |= INTR_ON_TIMER; | ||
1437 | if (udp_type == UDP_XPIPE_TYPE){ | ||
1438 | chan->if_send_stat.if_send_PIPE_request++; | ||
1439 | } | ||
1440 | } | ||
1441 | netif_start_queue(dev); | ||
1442 | clear_bit(SEND_CRIT,(void*)&card->wandev.critical); | ||
1443 | S508_S514_unlock(card, &smp_flags); | ||
1444 | return 0; | ||
1445 | } | ||
1446 | |||
1447 | if (chan->transmit_length){ | ||
1448 | //FIXME: This check doesn't make sense any more | ||
1449 | if (chan->common.state != WAN_CONNECTED){ | ||
1450 | chan->transmit_length=0; | ||
1451 | atomic_set(&chan->common.driver_busy,0); | ||
1452 | }else{ | ||
1453 | netif_stop_queue(dev); | ||
1454 | ++card->u.x.tx_interrupts_pending; | ||
1455 | status->imask |= INTR_ON_TX_FRAME; | ||
1456 | clear_bit(SEND_CRIT,(void*)&card->wandev.critical); | ||
1457 | S508_S514_unlock(card, &smp_flags); | ||
1458 | return 1; | ||
1459 | } | ||
1460 | } | ||
1461 | |||
1462 | if (card->wandev.state != WAN_CONNECTED){ | ||
1463 | ++chan->ifstats.tx_dropped; | ||
1464 | ++card->wandev.stats.tx_dropped; | ||
1465 | ++chan->if_send_stat.if_send_wan_disconnected; | ||
1466 | |||
1467 | }else if ( chan->protocol && (chan->protocol != skb->protocol)){ | ||
1468 | printk(KERN_INFO | ||
1469 | "%s: unsupported Ethertype 0x%04X on interface %s!\n", | ||
1470 | chan->name, htons(skb->protocol), dev->name); | ||
1471 | |||
1472 | printk(KERN_INFO "PROTO %Xn", htons(chan->protocol)); | ||
1473 | ++chan->ifstats.tx_errors; | ||
1474 | ++chan->ifstats.tx_dropped; | ||
1475 | ++card->wandev.stats.tx_dropped; | ||
1476 | ++chan->if_send_stat.if_send_protocol_error; | ||
1477 | |||
1478 | }else switch (chan->common.state){ | ||
1479 | |||
1480 | case WAN_DISCONNECTED: | ||
1481 | /* Try to establish connection. If succeded, then start | ||
1482 | * transmission, else drop a packet. | ||
1483 | */ | ||
1484 | if (chan->common.usedby == API){ | ||
1485 | ++chan->ifstats.tx_dropped; | ||
1486 | ++card->wandev.stats.tx_dropped; | ||
1487 | break; | ||
1488 | }else{ | ||
1489 | if (chan_connect(dev) != 0){ | ||
1490 | ++chan->ifstats.tx_dropped; | ||
1491 | ++card->wandev.stats.tx_dropped; | ||
1492 | break; | ||
1493 | } | ||
1494 | } | ||
1495 | /* fall through */ | ||
1496 | |||
1497 | case WAN_CONNECTED: | ||
1498 | if( skb->protocol == htons(ETH_P_IPX)) { | ||
1499 | if(chan->enable_IPX) { | ||
1500 | switch_net_numbers( skb->data, | ||
1501 | chan->network_number, 0); | ||
1502 | } else { | ||
1503 | ++card->wandev.stats.tx_dropped; | ||
1504 | ++chan->ifstats.tx_dropped; | ||
1505 | ++chan->if_send_stat.if_send_protocol_error; | ||
1506 | goto if_send_crit_exit; | ||
1507 | } | ||
1508 | } | ||
1509 | /* We never drop here, if cannot send than, copy | ||
1510 | * a packet into a transmit buffer | ||
1511 | */ | ||
1512 | chan_send(dev, skb->data, skb->len, 0); | ||
1513 | break; | ||
1514 | |||
1515 | default: | ||
1516 | ++chan->ifstats.tx_dropped; | ||
1517 | ++card->wandev.stats.tx_dropped; | ||
1518 | break; | ||
1519 | } | ||
1520 | |||
1521 | |||
1522 | if_send_crit_exit: | ||
1523 | |||
1524 | dev_kfree_skb_any(skb); | ||
1525 | |||
1526 | netif_start_queue(dev); | ||
1527 | clear_bit(SEND_CRIT,(void*)&card->wandev.critical); | ||
1528 | S508_S514_unlock(card, &smp_flags); | ||
1529 | return 0; | ||
1530 | } | ||
1531 | |||
1532 | /*============================================================================ | ||
1533 | * Setup so that a frame can be transmitted on the occurrence of a transmit | ||
1534 | * interrupt. | ||
1535 | *===========================================================================*/ | ||
1536 | |||
1537 | static void setup_for_delayed_transmit(struct net_device* dev, void* buf, | ||
1538 | unsigned len) | ||
1539 | { | ||
1540 | x25_channel_t* chan = dev->priv; | ||
1541 | sdla_t* card = chan->card; | ||
1542 | TX25Status* status = card->flags; | ||
1543 | |||
1544 | ++chan->if_send_stat.if_send_adptr_bfrs_full; | ||
1545 | |||
1546 | if(chan->transmit_length) { | ||
1547 | printk(KERN_INFO "%s: Error, transmit length set in delayed transmit!\n", | ||
1548 | card->devname); | ||
1549 | return; | ||
1550 | } | ||
1551 | |||
1552 | if (chan->common.usedby == API){ | ||
1553 | if (len > X25_CHAN_MTU+sizeof(x25api_hdr_t)) { | ||
1554 | ++chan->ifstats.tx_dropped; | ||
1555 | ++card->wandev.stats.tx_dropped; | ||
1556 | printk(KERN_INFO "%s: Length is too big for delayed transmit\n", | ||
1557 | card->devname); | ||
1558 | return; | ||
1559 | } | ||
1560 | }else{ | ||
1561 | if (len > X25_MAX_DATA) { | ||
1562 | ++chan->ifstats.tx_dropped; | ||
1563 | ++card->wandev.stats.tx_dropped; | ||
1564 | printk(KERN_INFO "%s: Length is too big for delayed transmit\n", | ||
1565 | card->devname); | ||
1566 | return; | ||
1567 | } | ||
1568 | } | ||
1569 | |||
1570 | chan->transmit_length = len; | ||
1571 | atomic_set(&chan->common.driver_busy,1); | ||
1572 | memcpy(chan->transmit_buffer, buf, len); | ||
1573 | |||
1574 | ++chan->if_send_stat.if_send_tx_int_enabled; | ||
1575 | |||
1576 | /* Enable Transmit Interrupt */ | ||
1577 | ++card->u.x.tx_interrupts_pending; | ||
1578 | status->imask |= INTR_ON_TX_FRAME; | ||
1579 | } | ||
1580 | |||
1581 | |||
1582 | /*=============================================================== | ||
1583 | * net_device_stats | ||
1584 | * | ||
1585 | * Get ethernet-style interface statistics. | ||
1586 | * Return a pointer to struct enet_statistics. | ||
1587 | * | ||
1588 | *==============================================================*/ | ||
1589 | static struct net_device_stats *if_stats(struct net_device* dev) | ||
1590 | { | ||
1591 | x25_channel_t *chan = dev->priv; | ||
1592 | |||
1593 | if(chan == NULL) | ||
1594 | return NULL; | ||
1595 | |||
1596 | return &chan->ifstats; | ||
1597 | } | ||
1598 | |||
1599 | |||
1600 | /* | ||
1601 | * Interrupt Handlers | ||
1602 | */ | ||
1603 | |||
1604 | /* | ||
1605 | * X.25 Interrupt Service Routine. | ||
1606 | */ | ||
1607 | |||
1608 | static void wpx_isr (sdla_t* card) | ||
1609 | { | ||
1610 | TX25Status* status = card->flags; | ||
1611 | |||
1612 | card->in_isr = 1; | ||
1613 | ++card->statistics.isr_entry; | ||
1614 | |||
1615 | if (test_bit(PERI_CRIT,(void*)&card->wandev.critical)){ | ||
1616 | card->in_isr=0; | ||
1617 | status->iflags = 0; | ||
1618 | return; | ||
1619 | } | ||
1620 | |||
1621 | if (test_bit(SEND_CRIT, (void*)&card->wandev.critical)){ | ||
1622 | |||
1623 | printk(KERN_INFO "%s: wpx_isr: wandev.critical set to 0x%02lx, int type = 0x%02x\n", | ||
1624 | card->devname, card->wandev.critical, status->iflags); | ||
1625 | card->in_isr = 0; | ||
1626 | status->iflags = 0; | ||
1627 | return; | ||
1628 | } | ||
1629 | |||
1630 | /* For all interrupts set the critical flag to CRITICAL_RX_INTR. | ||
1631 | * If the if_send routine is called with this flag set it will set | ||
1632 | * the enable transmit flag to 1. (for a delayed interrupt) | ||
1633 | */ | ||
1634 | switch (status->iflags){ | ||
1635 | |||
1636 | case RX_INTR_PENDING: /* receive interrupt */ | ||
1637 | rx_intr(card); | ||
1638 | break; | ||
1639 | |||
1640 | case TX_INTR_PENDING: /* transmit interrupt */ | ||
1641 | tx_intr(card); | ||
1642 | break; | ||
1643 | |||
1644 | case MODEM_INTR_PENDING: /* modem status interrupt */ | ||
1645 | status_intr(card); | ||
1646 | break; | ||
1647 | |||
1648 | case X25_ASY_TRANS_INTR_PENDING: /* network event interrupt */ | ||
1649 | event_intr(card); | ||
1650 | break; | ||
1651 | |||
1652 | case TIMER_INTR_PENDING: | ||
1653 | timer_intr(card); | ||
1654 | break; | ||
1655 | |||
1656 | default: /* unwanted interrupt */ | ||
1657 | spur_intr(card); | ||
1658 | } | ||
1659 | |||
1660 | card->in_isr = 0; | ||
1661 | status->iflags = 0; /* clear interrupt condition */ | ||
1662 | } | ||
1663 | |||
1664 | /* | ||
1665 | * Receive interrupt handler. | ||
1666 | * This routine handles fragmented IP packets using M-bit according to the | ||
1667 | * RFC1356. | ||
1668 | * o map ligical channel number to network interface. | ||
1669 | * o allocate socket buffer or append received packet to the existing one. | ||
1670 | * o if M-bit is reset (i.e. it's the last packet in a sequence) then | ||
1671 | * decapsulate packet and pass socket buffer to the protocol stack. | ||
1672 | * | ||
1673 | * Notes: | ||
1674 | * 1. When allocating a socket buffer, if M-bit is set then more data is | ||
1675 | * coming and we have to allocate buffer for the maximum IP packet size | ||
1676 | * expected on this channel. | ||
1677 | * 2. If something goes wrong and X.25 packet has to be dropped (e.g. no | ||
1678 | * socket buffers available) the whole packet sequence must be discarded. | ||
1679 | */ | ||
1680 | |||
1681 | static void rx_intr (sdla_t* card) | ||
1682 | { | ||
1683 | TX25Mbox* rxmb = card->rxmb; | ||
1684 | unsigned lcn = rxmb->cmd.lcn; | ||
1685 | struct net_device* dev = find_channel(card,lcn); | ||
1686 | x25_channel_t* chan; | ||
1687 | struct sk_buff* skb=NULL; | ||
1688 | |||
1689 | if (dev == NULL){ | ||
1690 | /* Invalid channel, discard packet */ | ||
1691 | printk(KERN_INFO "%s: receiving on orphaned LCN %d!\n", | ||
1692 | card->devname, lcn); | ||
1693 | return; | ||
1694 | } | ||
1695 | |||
1696 | chan = dev->priv; | ||
1697 | chan->i_timeout_sofar = jiffies; | ||
1698 | |||
1699 | |||
1700 | /* Copy the data from the board, into an | ||
1701 | * skb buffer | ||
1702 | */ | ||
1703 | if (wanpipe_pull_data_in_skb(card,dev,&skb)){ | ||
1704 | ++chan->ifstats.rx_dropped; | ||
1705 | ++card->wandev.stats.rx_dropped; | ||
1706 | ++chan->rx_intr_stat.rx_intr_no_socket; | ||
1707 | ++chan->rx_intr_stat.rx_intr_bfr_not_passed_to_stack; | ||
1708 | return; | ||
1709 | } | ||
1710 | |||
1711 | dev->last_rx = jiffies; /* timestamp */ | ||
1712 | |||
1713 | |||
1714 | /* ------------ API ----------------*/ | ||
1715 | |||
1716 | if (chan->common.usedby == API){ | ||
1717 | |||
1718 | if (bh_enqueue(dev, skb)){ | ||
1719 | ++chan->ifstats.rx_dropped; | ||
1720 | ++card->wandev.stats.rx_dropped; | ||
1721 | ++chan->rx_intr_stat.rx_intr_bfr_not_passed_to_stack; | ||
1722 | dev_kfree_skb_any(skb); | ||
1723 | return; | ||
1724 | } | ||
1725 | |||
1726 | ++chan->ifstats.rx_packets; | ||
1727 | chan->ifstats.rx_bytes += skb->len; | ||
1728 | |||
1729 | |||
1730 | chan->rx_skb = NULL; | ||
1731 | if (!test_and_set_bit(0, &chan->tq_working)){ | ||
1732 | wanpipe_queue_work(&chan->common.wanpipe_work); | ||
1733 | } | ||
1734 | return; | ||
1735 | } | ||
1736 | |||
1737 | |||
1738 | /* ------------- WANPIPE -------------------*/ | ||
1739 | |||
1740 | /* set rx_skb to NULL so we won't access it later when kernel already owns it */ | ||
1741 | chan->rx_skb=NULL; | ||
1742 | |||
1743 | /* Decapsulate packet, if necessary */ | ||
1744 | if (!skb->protocol && !wanrouter_type_trans(skb, dev)){ | ||
1745 | /* can't decapsulate packet */ | ||
1746 | dev_kfree_skb_any(skb); | ||
1747 | ++chan->ifstats.rx_errors; | ||
1748 | ++chan->ifstats.rx_dropped; | ||
1749 | ++card->wandev.stats.rx_dropped; | ||
1750 | ++chan->rx_intr_stat.rx_intr_bfr_not_passed_to_stack; | ||
1751 | |||
1752 | }else{ | ||
1753 | if( handle_IPXWAN(skb->data, chan->name, | ||
1754 | chan->enable_IPX, chan->network_number, | ||
1755 | skb->protocol)){ | ||
1756 | |||
1757 | if( chan->enable_IPX ){ | ||
1758 | if(chan_send(dev, skb->data, skb->len,0)){ | ||
1759 | chan->tx_skb = skb; | ||
1760 | }else{ | ||
1761 | dev_kfree_skb_any(skb); | ||
1762 | ++chan->rx_intr_stat.rx_intr_bfr_not_passed_to_stack; | ||
1763 | } | ||
1764 | }else{ | ||
1765 | /* increment IPX packet dropped statistic */ | ||
1766 | ++chan->ifstats.rx_dropped; | ||
1767 | ++chan->rx_intr_stat.rx_intr_bfr_not_passed_to_stack; | ||
1768 | } | ||
1769 | }else{ | ||
1770 | skb->mac.raw = skb->data; | ||
1771 | chan->ifstats.rx_bytes += skb->len; | ||
1772 | ++chan->ifstats.rx_packets; | ||
1773 | ++chan->rx_intr_stat.rx_intr_bfr_passed_to_stack; | ||
1774 | netif_rx(skb); | ||
1775 | } | ||
1776 | } | ||
1777 | |||
1778 | return; | ||
1779 | } | ||
1780 | |||
1781 | |||
1782 | static int wanpipe_pull_data_in_skb(sdla_t *card, struct net_device *dev, | ||
1783 | struct sk_buff **skb) | ||
1784 | { | ||
1785 | void *bufptr; | ||
1786 | TX25Mbox* rxmb = card->rxmb; | ||
1787 | unsigned len = rxmb->cmd.length; /* packet length */ | ||
1788 | unsigned qdm = rxmb->cmd.qdm; /* Q,D and M bits */ | ||
1789 | x25_channel_t *chan = dev->priv; | ||
1790 | struct sk_buff *new_skb = *skb; | ||
1791 | |||
1792 | if (chan->common.usedby == WANPIPE){ | ||
1793 | if (chan->drop_sequence){ | ||
1794 | if (!(qdm & 0x01)){ | ||
1795 | chan->drop_sequence = 0; | ||
1796 | } | ||
1797 | return 1; | ||
1798 | } | ||
1799 | new_skb = chan->rx_skb; | ||
1800 | }else{ | ||
1801 | /* Add on the API header to the received | ||
1802 | * data | ||
1803 | */ | ||
1804 | len += sizeof(x25api_hdr_t); | ||
1805 | } | ||
1806 | |||
1807 | if (new_skb == NULL){ | ||
1808 | int bufsize; | ||
1809 | |||
1810 | if (chan->common.usedby == WANPIPE){ | ||
1811 | bufsize = (qdm & 0x01) ? dev->mtu : len; | ||
1812 | }else{ | ||
1813 | bufsize = len; | ||
1814 | } | ||
1815 | |||
1816 | /* Allocate new socket buffer */ | ||
1817 | new_skb = dev_alloc_skb(bufsize + dev->hard_header_len); | ||
1818 | if (new_skb == NULL){ | ||
1819 | printk(KERN_INFO "%s: no socket buffers available!\n", | ||
1820 | card->devname); | ||
1821 | chan->drop_sequence = 1; /* set flag */ | ||
1822 | ++chan->ifstats.rx_dropped; | ||
1823 | return 1; | ||
1824 | } | ||
1825 | } | ||
1826 | |||
1827 | if (skb_tailroom(new_skb) < len){ | ||
1828 | /* No room for the packet. Call off the whole thing! */ | ||
1829 | dev_kfree_skb_any(new_skb); | ||
1830 | if (chan->common.usedby == WANPIPE){ | ||
1831 | chan->rx_skb = NULL; | ||
1832 | if (qdm & 0x01){ | ||
1833 | chan->drop_sequence = 1; | ||
1834 | } | ||
1835 | } | ||
1836 | |||
1837 | printk(KERN_INFO "%s: unexpectedly long packet sequence " | ||
1838 | "on interface %s!\n", card->devname, dev->name); | ||
1839 | ++chan->ifstats.rx_length_errors; | ||
1840 | return 1; | ||
1841 | } | ||
1842 | |||
1843 | bufptr = skb_put(new_skb,len); | ||
1844 | |||
1845 | |||
1846 | if (chan->common.usedby == API){ | ||
1847 | /* Fill in the x25api header | ||
1848 | */ | ||
1849 | x25api_t * api_data = (x25api_t*)bufptr; | ||
1850 | api_data->hdr.qdm = rxmb->cmd.qdm; | ||
1851 | api_data->hdr.cause = rxmb->cmd.cause; | ||
1852 | api_data->hdr.diagn = rxmb->cmd.diagn; | ||
1853 | api_data->hdr.length = rxmb->cmd.length; | ||
1854 | memcpy(api_data->data, rxmb->data, rxmb->cmd.length); | ||
1855 | }else{ | ||
1856 | memcpy(bufptr, rxmb->data, len); | ||
1857 | } | ||
1858 | |||
1859 | new_skb->dev = dev; | ||
1860 | |||
1861 | if (chan->common.usedby == API){ | ||
1862 | new_skb->mac.raw = new_skb->data; | ||
1863 | new_skb->protocol = htons(X25_PROT); | ||
1864 | new_skb->pkt_type = WAN_PACKET_DATA; | ||
1865 | }else{ | ||
1866 | new_skb->protocol = chan->protocol; | ||
1867 | chan->rx_skb = new_skb; | ||
1868 | } | ||
1869 | |||
1870 | /* If qdm bit is set, more data is coming | ||
1871 | * thus, exit and wait for more data before | ||
1872 | * sending the packet up. (Used by router only) | ||
1873 | */ | ||
1874 | if ((qdm & 0x01) && (chan->common.usedby == WANPIPE)) | ||
1875 | return 1; | ||
1876 | |||
1877 | *skb = new_skb; | ||
1878 | |||
1879 | return 0; | ||
1880 | } | ||
1881 | |||
1882 | /*=============================================================== | ||
1883 | * tx_intr | ||
1884 | * | ||
1885 | * Transmit interrupt handler. | ||
1886 | * For each dev, check that there is something to send. | ||
1887 | * If data available, transmit. | ||
1888 | * | ||
1889 | *===============================================================*/ | ||
1890 | |||
1891 | static void tx_intr (sdla_t* card) | ||
1892 | { | ||
1893 | struct net_device *dev; | ||
1894 | TX25Status* status = card->flags; | ||
1895 | unsigned char more_to_tx=0; | ||
1896 | x25_channel_t *chan=NULL; | ||
1897 | int i=0; | ||
1898 | |||
1899 | if (card->u.x.tx_dev == NULL){ | ||
1900 | card->u.x.tx_dev = card->wandev.dev; | ||
1901 | } | ||
1902 | |||
1903 | dev = card->u.x.tx_dev; | ||
1904 | |||
1905 | for (;;){ | ||
1906 | |||
1907 | chan = dev->priv; | ||
1908 | if (chan->transmit_length){ | ||
1909 | /* Device was set to transmit, check if the TX | ||
1910 | * buffers are available | ||
1911 | */ | ||
1912 | if (chan->common.state != WAN_CONNECTED){ | ||
1913 | chan->transmit_length = 0; | ||
1914 | atomic_set(&chan->common.driver_busy,0); | ||
1915 | chan->tx_offset=0; | ||
1916 | if (netif_queue_stopped(dev)){ | ||
1917 | if (chan->common.usedby == API){ | ||
1918 | netif_start_queue(dev); | ||
1919 | wakeup_sk_bh(dev); | ||
1920 | }else{ | ||
1921 | netif_wake_queue(dev); | ||
1922 | } | ||
1923 | } | ||
1924 | dev = move_dev_to_next(card,dev); | ||
1925 | break; | ||
1926 | } | ||
1927 | |||
1928 | if ((status->cflags[chan->ch_idx] & 0x40 || card->u.x.LAPB_hdlc) && | ||
1929 | (*card->u.x.hdlc_buf_status & 0x40) ){ | ||
1930 | /* Tx buffer available, we can send */ | ||
1931 | |||
1932 | if (tx_intr_send(card, dev)){ | ||
1933 | more_to_tx=1; | ||
1934 | } | ||
1935 | |||
1936 | /* If more than one interface present, move the | ||
1937 | * device pointer to the next interface, so on the | ||
1938 | * next TX interrupt we will try sending from it. | ||
1939 | */ | ||
1940 | dev = move_dev_to_next(card,dev); | ||
1941 | break; | ||
1942 | }else{ | ||
1943 | /* Tx buffers not available, but device set | ||
1944 | * the TX interrupt. Set more_to_tx and try | ||
1945 | * to transmit for other devices. | ||
1946 | */ | ||
1947 | more_to_tx=1; | ||
1948 | dev = move_dev_to_next(card,dev); | ||
1949 | } | ||
1950 | |||
1951 | }else{ | ||
1952 | /* This device was not set to transmit, | ||
1953 | * go to next | ||
1954 | */ | ||
1955 | dev = move_dev_to_next(card,dev); | ||
1956 | } | ||
1957 | |||
1958 | if (++i == card->u.x.no_dev){ | ||
1959 | if (!more_to_tx){ | ||
1960 | DBG_PRINTK(KERN_INFO "%s: Nothing to Send in TX INTR\n", | ||
1961 | card->devname); | ||
1962 | } | ||
1963 | break; | ||
1964 | } | ||
1965 | |||
1966 | } //End of FOR | ||
1967 | |||
1968 | card->u.x.tx_dev = dev; | ||
1969 | |||
1970 | if (!more_to_tx){ | ||
1971 | /* if any other interfaces have transmit interrupts pending, */ | ||
1972 | /* do not disable the global transmit interrupt */ | ||
1973 | if (!(--card->u.x.tx_interrupts_pending)){ | ||
1974 | status->imask &= ~INTR_ON_TX_FRAME; | ||
1975 | } | ||
1976 | } | ||
1977 | return; | ||
1978 | } | ||
1979 | |||
1980 | /*=============================================================== | ||
1981 | * move_dev_to_next | ||
1982 | * | ||
1983 | * | ||
1984 | *===============================================================*/ | ||
1985 | |||
1986 | |||
1987 | struct net_device *move_dev_to_next(sdla_t *card, struct net_device *dev) | ||
1988 | { | ||
1989 | if (card->u.x.no_dev != 1){ | ||
1990 | if (!*((struct net_device **)dev->priv)) | ||
1991 | return card->wandev.dev; | ||
1992 | else | ||
1993 | return *((struct net_device **)dev->priv); | ||
1994 | } | ||
1995 | return dev; | ||
1996 | } | ||
1997 | |||
1998 | /*=============================================================== | ||
1999 | * tx_intr_send | ||
2000 | * | ||
2001 | * | ||
2002 | *===============================================================*/ | ||
2003 | |||
2004 | static int tx_intr_send(sdla_t *card, struct net_device *dev) | ||
2005 | { | ||
2006 | x25_channel_t* chan = dev->priv; | ||
2007 | |||
2008 | if (chan_send (dev,chan->transmit_buffer,chan->transmit_length,1)){ | ||
2009 | |||
2010 | /* Packet was split up due to its size, do not disable | ||
2011 | * tx_intr | ||
2012 | */ | ||
2013 | return 1; | ||
2014 | } | ||
2015 | |||
2016 | chan->transmit_length=0; | ||
2017 | atomic_set(&chan->common.driver_busy,0); | ||
2018 | chan->tx_offset=0; | ||
2019 | |||
2020 | /* If we are in API mode, wakeup the | ||
2021 | * sock BH handler, not the NET_BH */ | ||
2022 | if (netif_queue_stopped(dev)){ | ||
2023 | if (chan->common.usedby == API){ | ||
2024 | netif_start_queue(dev); | ||
2025 | wakeup_sk_bh(dev); | ||
2026 | }else{ | ||
2027 | netif_wake_queue(dev); | ||
2028 | } | ||
2029 | } | ||
2030 | return 0; | ||
2031 | } | ||
2032 | |||
2033 | |||
2034 | /*=============================================================== | ||
2035 | * timer_intr | ||
2036 | * | ||
2037 | * Timer interrupt handler. | ||
2038 | * Check who called the timer interrupt and perform | ||
2039 | * action accordingly. | ||
2040 | * | ||
2041 | *===============================================================*/ | ||
2042 | |||
2043 | static void timer_intr (sdla_t *card) | ||
2044 | { | ||
2045 | TX25Status* status = card->flags; | ||
2046 | |||
2047 | if (card->u.x.timer_int_enabled & TMR_INT_ENABLED_CMD_EXEC){ | ||
2048 | |||
2049 | if (timer_intr_cmd_exec(card) == 0){ | ||
2050 | card->u.x.timer_int_enabled &= | ||
2051 | ~TMR_INT_ENABLED_CMD_EXEC; | ||
2052 | } | ||
2053 | |||
2054 | }else if(card->u.x.timer_int_enabled & TMR_INT_ENABLED_UDP_PKT) { | ||
2055 | |||
2056 | if ((*card->u.x.hdlc_buf_status & 0x40) && | ||
2057 | card->u.x.udp_type == UDP_XPIPE_TYPE){ | ||
2058 | |||
2059 | if(process_udp_mgmt_pkt(card)) { | ||
2060 | card->u.x.timer_int_enabled &= | ||
2061 | ~TMR_INT_ENABLED_UDP_PKT; | ||
2062 | } | ||
2063 | } | ||
2064 | |||
2065 | }else if (card->u.x.timer_int_enabled & TMR_INT_ENABLED_POLL_ACTIVE) { | ||
2066 | |||
2067 | struct net_device *dev = card->u.x.poll_device; | ||
2068 | x25_channel_t *chan = NULL; | ||
2069 | |||
2070 | if (!dev){ | ||
2071 | card->u.x.timer_int_enabled &= ~TMR_INT_ENABLED_POLL_ACTIVE; | ||
2072 | return; | ||
2073 | } | ||
2074 | chan = dev->priv; | ||
2075 | |||
2076 | printk(KERN_INFO | ||
2077 | "%s: Closing down Idle link %s on LCN %d\n", | ||
2078 | card->devname,chan->name,chan->common.lcn); | ||
2079 | chan->i_timeout_sofar = jiffies; | ||
2080 | chan_disc(dev); | ||
2081 | card->u.x.timer_int_enabled &= ~TMR_INT_ENABLED_POLL_ACTIVE; | ||
2082 | card->u.x.poll_device=NULL; | ||
2083 | |||
2084 | }else if (card->u.x.timer_int_enabled & TMR_INT_ENABLED_POLL_CONNECT_ON) { | ||
2085 | |||
2086 | wanpipe_set_state(card, WAN_CONNECTED); | ||
2087 | if (card->u.x.LAPB_hdlc){ | ||
2088 | struct net_device *dev = card->wandev.dev; | ||
2089 | set_chan_state(dev,WAN_CONNECTED); | ||
2090 | send_delayed_cmd_result(card,dev,card->mbox); | ||
2091 | } | ||
2092 | |||
2093 | /* 0x8F enable all interrupts */ | ||
2094 | x25_set_intr_mode(card, INTR_ON_RX_FRAME| | ||
2095 | INTR_ON_TX_FRAME| | ||
2096 | INTR_ON_MODEM_STATUS_CHANGE| | ||
2097 | //INTR_ON_COMMAND_COMPLETE| | ||
2098 | X25_ASY_TRANS_INTR_PENDING | | ||
2099 | INTR_ON_TIMER | | ||
2100 | DIRECT_RX_INTR_USAGE | ||
2101 | ); | ||
2102 | |||
2103 | status->imask &= ~INTR_ON_TX_FRAME; /* mask Tx interrupts */ | ||
2104 | card->u.x.timer_int_enabled &= ~TMR_INT_ENABLED_POLL_CONNECT_ON; | ||
2105 | |||
2106 | }else if (card->u.x.timer_int_enabled & TMR_INT_ENABLED_POLL_CONNECT_OFF) { | ||
2107 | |||
2108 | //printk(KERN_INFO "Poll connect, Turning OFF\n"); | ||
2109 | disconnect(card); | ||
2110 | card->u.x.timer_int_enabled &= ~TMR_INT_ENABLED_POLL_CONNECT_OFF; | ||
2111 | |||
2112 | }else if (card->u.x.timer_int_enabled & TMR_INT_ENABLED_POLL_DISCONNECT) { | ||
2113 | |||
2114 | //printk(KERN_INFO "POll disconnect, trying to connect\n"); | ||
2115 | connect(card); | ||
2116 | card->u.x.timer_int_enabled &= ~TMR_INT_ENABLED_POLL_DISCONNECT; | ||
2117 | |||
2118 | }else if (card->u.x.timer_int_enabled & TMR_INT_ENABLED_UPDATE){ | ||
2119 | |||
2120 | if (*card->u.x.hdlc_buf_status & 0x40){ | ||
2121 | x25_get_err_stats(card); | ||
2122 | x25_get_stats(card); | ||
2123 | card->u.x.timer_int_enabled &= ~TMR_INT_ENABLED_UPDATE; | ||
2124 | } | ||
2125 | } | ||
2126 | |||
2127 | if(!card->u.x.timer_int_enabled){ | ||
2128 | //printk(KERN_INFO "Turning Timer Off \n"); | ||
2129 | status->imask &= ~INTR_ON_TIMER; | ||
2130 | } | ||
2131 | } | ||
2132 | |||
2133 | /*==================================================================== | ||
2134 | * Modem status interrupt handler. | ||
2135 | *===================================================================*/ | ||
2136 | static void status_intr (sdla_t* card) | ||
2137 | { | ||
2138 | |||
2139 | /* Added to avoid Modem status message flooding */ | ||
2140 | static TX25ModemStatus last_stat; | ||
2141 | |||
2142 | TX25Mbox* mbox = card->mbox; | ||
2143 | TX25ModemStatus *modem_status; | ||
2144 | struct net_device *dev; | ||
2145 | x25_channel_t *chan; | ||
2146 | int err; | ||
2147 | |||
2148 | memset(&mbox->cmd, 0, sizeof(TX25Cmd)); | ||
2149 | mbox->cmd.command = X25_READ_MODEM_STATUS; | ||
2150 | err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; | ||
2151 | if (err){ | ||
2152 | x25_error(card, err, X25_READ_MODEM_STATUS, 0); | ||
2153 | }else{ | ||
2154 | |||
2155 | modem_status = (TX25ModemStatus*)mbox->data; | ||
2156 | |||
2157 | /* Check if the last status was the same | ||
2158 | * if it was, do NOT print message again */ | ||
2159 | |||
2160 | if (last_stat.status != modem_status->status){ | ||
2161 | |||
2162 | printk(KERN_INFO "%s: Modem Status Change: DCD=%s, CTS=%s\n", | ||
2163 | card->devname,DCD(modem_status->status),CTS(modem_status->status)); | ||
2164 | |||
2165 | last_stat.status = modem_status->status; | ||
2166 | |||
2167 | if (card->u.x.oob_on_modem){ | ||
2168 | |||
2169 | mbox->cmd.pktType = mbox->cmd.command; | ||
2170 | mbox->cmd.result = 0x08; | ||
2171 | |||
2172 | /* Send a OOB to all connected sockets */ | ||
2173 | for (dev = card->wandev.dev; dev; | ||
2174 | dev = *((struct net_device**)dev->priv)) { | ||
2175 | chan=dev->priv; | ||
2176 | if (chan->common.usedby == API){ | ||
2177 | send_oob_msg(card,dev,mbox); | ||
2178 | } | ||
2179 | } | ||
2180 | |||
2181 | /* The modem OOB message will probably kill the | ||
2182 | * the link. If we don't clear the flag here, | ||
2183 | * a deadlock could occur */ | ||
2184 | if (atomic_read(&card->u.x.command_busy)){ | ||
2185 | atomic_set(&card->u.x.command_busy,0); | ||
2186 | } | ||
2187 | } | ||
2188 | } | ||
2189 | } | ||
2190 | |||
2191 | memset(&mbox->cmd, 0, sizeof(TX25Cmd)); | ||
2192 | mbox->cmd.command = X25_HDLC_LINK_STATUS; | ||
2193 | err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; | ||
2194 | if (err){ | ||
2195 | x25_error(card, err, X25_HDLC_LINK_STATUS, 0); | ||
2196 | } | ||
2197 | |||
2198 | } | ||
2199 | |||
2200 | /*==================================================================== | ||
2201 | * Network event interrupt handler. | ||
2202 | *===================================================================*/ | ||
2203 | static void event_intr (sdla_t* card) | ||
2204 | { | ||
2205 | x25_fetch_events(card); | ||
2206 | } | ||
2207 | |||
2208 | /*==================================================================== | ||
2209 | * Spurious interrupt handler. | ||
2210 | * o print a warning | ||
2211 | * o | ||
2212 | *====================================================================*/ | ||
2213 | |||
2214 | static void spur_intr (sdla_t* card) | ||
2215 | { | ||
2216 | printk(KERN_INFO "%s: spurious interrupt!\n", card->devname); | ||
2217 | } | ||
2218 | |||
2219 | |||
2220 | /* | ||
2221 | * Background Polling Routines | ||
2222 | */ | ||
2223 | |||
2224 | /*==================================================================== | ||
2225 | * Main polling routine. | ||
2226 | * This routine is repeatedly called by the WANPIPE 'thread' to allow for | ||
2227 | * time-dependent housekeeping work. | ||
2228 | * | ||
2229 | * Notes: | ||
2230 | * 1. This routine may be called on interrupt context with all interrupts | ||
2231 | * enabled. Beware! | ||
2232 | *====================================================================*/ | ||
2233 | |||
2234 | static void wpx_poll (sdla_t *card) | ||
2235 | { | ||
2236 | if (!card->wandev.dev){ | ||
2237 | goto wpx_poll_exit; | ||
2238 | } | ||
2239 | |||
2240 | if (card->open_cnt != card->u.x.num_of_ch){ | ||
2241 | goto wpx_poll_exit; | ||
2242 | } | ||
2243 | |||
2244 | if (test_bit(PERI_CRIT,&card->wandev.critical)){ | ||
2245 | goto wpx_poll_exit; | ||
2246 | } | ||
2247 | |||
2248 | if (test_bit(SEND_CRIT,&card->wandev.critical)){ | ||
2249 | goto wpx_poll_exit; | ||
2250 | } | ||
2251 | |||
2252 | switch(card->wandev.state){ | ||
2253 | case WAN_CONNECTED: | ||
2254 | poll_active(card); | ||
2255 | break; | ||
2256 | |||
2257 | case WAN_CONNECTING: | ||
2258 | poll_connecting(card); | ||
2259 | break; | ||
2260 | |||
2261 | case WAN_DISCONNECTED: | ||
2262 | poll_disconnected(card); | ||
2263 | break; | ||
2264 | } | ||
2265 | |||
2266 | wpx_poll_exit: | ||
2267 | clear_bit(POLL_CRIT,&card->wandev.critical); | ||
2268 | return; | ||
2269 | } | ||
2270 | |||
2271 | static void trigger_x25_poll(sdla_t *card) | ||
2272 | { | ||
2273 | schedule_work(&card->u.x.x25_poll_work); | ||
2274 | } | ||
2275 | |||
2276 | /*==================================================================== | ||
2277 | * Handle physical link establishment phase. | ||
2278 | * o if connection timed out, disconnect the link. | ||
2279 | *===================================================================*/ | ||
2280 | |||
2281 | static void poll_connecting (sdla_t* card) | ||
2282 | { | ||
2283 | volatile TX25Status* status = card->flags; | ||
2284 | |||
2285 | if (status->gflags & X25_HDLC_ABM){ | ||
2286 | |||
2287 | timer_intr_exec (card, TMR_INT_ENABLED_POLL_CONNECT_ON); | ||
2288 | |||
2289 | }else if ((jiffies - card->state_tick) > CONNECT_TIMEOUT){ | ||
2290 | |||
2291 | timer_intr_exec (card, TMR_INT_ENABLED_POLL_CONNECT_OFF); | ||
2292 | |||
2293 | } | ||
2294 | } | ||
2295 | |||
2296 | /*==================================================================== | ||
2297 | * Handle physical link disconnected phase. | ||
2298 | * o if hold-down timeout has expired and there are open interfaces, | ||
2299 | * connect link. | ||
2300 | *===================================================================*/ | ||
2301 | |||
2302 | static void poll_disconnected (sdla_t* card) | ||
2303 | { | ||
2304 | struct net_device *dev; | ||
2305 | x25_channel_t *chan; | ||
2306 | TX25Status* status = card->flags; | ||
2307 | |||
2308 | if (!card->u.x.LAPB_hdlc && card->open_cnt && | ||
2309 | ((jiffies - card->state_tick) > HOLD_DOWN_TIME)){ | ||
2310 | timer_intr_exec(card, TMR_INT_ENABLED_POLL_DISCONNECT); | ||
2311 | } | ||
2312 | |||
2313 | |||
2314 | if ((dev=card->wandev.dev) == NULL) | ||
2315 | return; | ||
2316 | |||
2317 | if ((chan=dev->priv) == NULL) | ||
2318 | return; | ||
2319 | |||
2320 | if (chan->common.usedby == API && | ||
2321 | atomic_read(&chan->common.command) && | ||
2322 | card->u.x.LAPB_hdlc){ | ||
2323 | |||
2324 | if (!(card->u.x.timer_int_enabled & TMR_INT_ENABLED_CMD_EXEC)) | ||
2325 | card->u.x.timer_int_enabled |= TMR_INT_ENABLED_CMD_EXEC; | ||
2326 | |||
2327 | if (!(status->imask & INTR_ON_TIMER)) | ||
2328 | status->imask |= INTR_ON_TIMER; | ||
2329 | } | ||
2330 | |||
2331 | } | ||
2332 | |||
2333 | /*==================================================================== | ||
2334 | * Handle active link phase. | ||
2335 | * o fetch X.25 asynchronous events. | ||
2336 | * o kick off transmission on all interfaces. | ||
2337 | *===================================================================*/ | ||
2338 | |||
2339 | static void poll_active (sdla_t* card) | ||
2340 | { | ||
2341 | struct net_device* dev; | ||
2342 | TX25Status* status = card->flags; | ||
2343 | |||
2344 | for (dev = card->wandev.dev; dev; | ||
2345 | dev = *((struct net_device **)dev->priv)){ | ||
2346 | x25_channel_t* chan = dev->priv; | ||
2347 | |||
2348 | /* If SVC has been idle long enough, close virtual circuit */ | ||
2349 | if ( chan->common.svc && | ||
2350 | chan->common.state == WAN_CONNECTED && | ||
2351 | chan->common.usedby == WANPIPE ){ | ||
2352 | |||
2353 | if( (jiffies - chan->i_timeout_sofar) / HZ > chan->idle_timeout ){ | ||
2354 | /* Close svc */ | ||
2355 | card->u.x.poll_device=dev; | ||
2356 | timer_intr_exec (card, TMR_INT_ENABLED_POLL_ACTIVE); | ||
2357 | } | ||
2358 | } | ||
2359 | |||
2360 | #ifdef PRINT_DEBUG | ||
2361 | chan->ifstats.tx_compressed = atomic_read(&chan->common.command); | ||
2362 | chan->ifstats.tx_errors = chan->common.state; | ||
2363 | chan->ifstats.rx_fifo_errors = atomic_read(&card->u.x.command_busy); | ||
2364 | ++chan->ifstats.tx_bytes; | ||
2365 | |||
2366 | chan->ifstats.rx_fifo_errors=atomic_read(&chan->common.disconnect); | ||
2367 | chan->ifstats.multicast=atomic_read(&chan->bh_buff_used); | ||
2368 | chan->ifstats.rx_length_errors=*card->u.x.hdlc_buf_status; | ||
2369 | #endif | ||
2370 | |||
2371 | if (chan->common.usedby == API && | ||
2372 | atomic_read(&chan->common.command) && | ||
2373 | !card->u.x.LAPB_hdlc){ | ||
2374 | |||
2375 | if (!(card->u.x.timer_int_enabled & TMR_INT_ENABLED_CMD_EXEC)) | ||
2376 | card->u.x.timer_int_enabled |= TMR_INT_ENABLED_CMD_EXEC; | ||
2377 | |||
2378 | if (!(status->imask & INTR_ON_TIMER)) | ||
2379 | status->imask |= INTR_ON_TIMER; | ||
2380 | } | ||
2381 | |||
2382 | if ((chan->common.usedby == API) && | ||
2383 | atomic_read(&chan->common.disconnect)){ | ||
2384 | |||
2385 | if (chan->common.state == WAN_DISCONNECTED){ | ||
2386 | atomic_set(&chan->common.disconnect,0); | ||
2387 | return; | ||
2388 | } | ||
2389 | |||
2390 | atomic_set(&chan->common.command,X25_CLEAR_CALL); | ||
2391 | if (!(card->u.x.timer_int_enabled & TMR_INT_ENABLED_CMD_EXEC)) | ||
2392 | card->u.x.timer_int_enabled |= TMR_INT_ENABLED_CMD_EXEC; | ||
2393 | |||
2394 | if (!(status->imask & INTR_ON_TIMER)) | ||
2395 | status->imask |= INTR_ON_TIMER; | ||
2396 | } | ||
2397 | } | ||
2398 | } | ||
2399 | |||
2400 | static void timer_intr_exec(sdla_t *card, unsigned char TYPE) | ||
2401 | { | ||
2402 | TX25Status* status = card->flags; | ||
2403 | card->u.x.timer_int_enabled |= TYPE; | ||
2404 | if (!(status->imask & INTR_ON_TIMER)) | ||
2405 | status->imask |= INTR_ON_TIMER; | ||
2406 | } | ||
2407 | |||
2408 | |||
2409 | /*==================================================================== | ||
2410 | * SDLA Firmware-Specific Functions | ||
2411 | * | ||
2412 | * Almost all X.25 commands can unexpetedly fail due to so called 'X.25 | ||
2413 | * asynchronous events' such as restart, interrupt, incoming call request, | ||
2414 | * call clear request, etc. They can't be ignored and have to be delt with | ||
2415 | * immediately. To tackle with this problem we execute each interface | ||
2416 | * command in a loop until good return code is received or maximum number | ||
2417 | * of retries is reached. Each interface command returns non-zero return | ||
2418 | * code, an asynchronous event/error handler x25_error() is called. | ||
2419 | *====================================================================*/ | ||
2420 | |||
2421 | /*==================================================================== | ||
2422 | * Read X.25 firmware version. | ||
2423 | * Put code version as ASCII string in str. | ||
2424 | *===================================================================*/ | ||
2425 | |||
2426 | static int x25_get_version (sdla_t* card, char* str) | ||
2427 | { | ||
2428 | TX25Mbox* mbox = card->mbox; | ||
2429 | int retry = MAX_CMD_RETRY; | ||
2430 | int err; | ||
2431 | |||
2432 | do | ||
2433 | { | ||
2434 | memset(&mbox->cmd, 0, sizeof(TX25Cmd)); | ||
2435 | mbox->cmd.command = X25_READ_CODE_VERSION; | ||
2436 | err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; | ||
2437 | } while (err && retry-- && | ||
2438 | x25_error(card, err, X25_READ_CODE_VERSION, 0)); | ||
2439 | |||
2440 | if (!err && str) | ||
2441 | { | ||
2442 | int len = mbox->cmd.length; | ||
2443 | |||
2444 | memcpy(str, mbox->data, len); | ||
2445 | str[len] = '\0'; | ||
2446 | } | ||
2447 | return err; | ||
2448 | } | ||
2449 | |||
2450 | /*==================================================================== | ||
2451 | * Configure adapter. | ||
2452 | *===================================================================*/ | ||
2453 | |||
2454 | static int x25_configure (sdla_t* card, TX25Config* conf) | ||
2455 | { | ||
2456 | TX25Mbox* mbox = card->mbox; | ||
2457 | int retry = MAX_CMD_RETRY; | ||
2458 | int err; | ||
2459 | |||
2460 | do{ | ||
2461 | memset(&mbox->cmd, 0, sizeof(TX25Cmd)); | ||
2462 | memcpy(mbox->data, (void*)conf, sizeof(TX25Config)); | ||
2463 | mbox->cmd.length = sizeof(TX25Config); | ||
2464 | mbox->cmd.command = X25_SET_CONFIGURATION; | ||
2465 | err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; | ||
2466 | } while (err && retry-- && x25_error(card, err, X25_SET_CONFIGURATION, 0)); | ||
2467 | return err; | ||
2468 | } | ||
2469 | |||
2470 | /*==================================================================== | ||
2471 | * Configure adapter for HDLC only. | ||
2472 | *===================================================================*/ | ||
2473 | |||
2474 | static int hdlc_configure (sdla_t* card, TX25Config* conf) | ||
2475 | { | ||
2476 | TX25Mbox* mbox = card->mbox; | ||
2477 | int retry = MAX_CMD_RETRY; | ||
2478 | int err; | ||
2479 | |||
2480 | do{ | ||
2481 | memset(&mbox->cmd, 0, sizeof(TX25Cmd)); | ||
2482 | memcpy(mbox->data, (void*)conf, sizeof(TX25Config)); | ||
2483 | mbox->cmd.length = sizeof(TX25Config); | ||
2484 | mbox->cmd.command = X25_HDLC_SET_CONFIG; | ||
2485 | err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; | ||
2486 | } while (err && retry-- && x25_error(card, err, X25_SET_CONFIGURATION, 0)); | ||
2487 | |||
2488 | return err; | ||
2489 | } | ||
2490 | |||
2491 | static int set_hdlc_level (sdla_t* card) | ||
2492 | { | ||
2493 | |||
2494 | TX25Mbox* mbox = card->mbox; | ||
2495 | int retry = MAX_CMD_RETRY; | ||
2496 | int err; | ||
2497 | |||
2498 | do{ | ||
2499 | memset(&mbox->cmd, 0, sizeof(TX25Cmd)); | ||
2500 | mbox->cmd.command = SET_PROTOCOL_LEVEL; | ||
2501 | mbox->cmd.length = 1; | ||
2502 | mbox->data[0] = HDLC_LEVEL; //| DO_HDLC_LEVEL_ERROR_CHECKING; | ||
2503 | err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; | ||
2504 | } while (err && retry-- && x25_error(card, err, SET_PROTOCOL_LEVEL, 0)); | ||
2505 | |||
2506 | return err; | ||
2507 | } | ||
2508 | |||
2509 | |||
2510 | |||
2511 | /*==================================================================== | ||
2512 | * Get communications error statistics. | ||
2513 | *====================================================================*/ | ||
2514 | |||
2515 | static int x25_get_err_stats (sdla_t* card) | ||
2516 | { | ||
2517 | TX25Mbox* mbox = card->mbox; | ||
2518 | int retry = MAX_CMD_RETRY; | ||
2519 | int err; | ||
2520 | |||
2521 | do | ||
2522 | { | ||
2523 | memset(&mbox->cmd, 0, sizeof(TX25Cmd)); | ||
2524 | mbox->cmd.command = X25_HDLC_READ_COMM_ERR; | ||
2525 | err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; | ||
2526 | } while (err && retry-- && x25_error(card, err, X25_HDLC_READ_COMM_ERR, 0)); | ||
2527 | |||
2528 | if (!err) | ||
2529 | { | ||
2530 | THdlcCommErr* stats = (void*)mbox->data; | ||
2531 | |||
2532 | card->wandev.stats.rx_over_errors = stats->rxOverrun; | ||
2533 | card->wandev.stats.rx_crc_errors = stats->rxBadCrc; | ||
2534 | card->wandev.stats.rx_missed_errors = stats->rxAborted; | ||
2535 | card->wandev.stats.tx_aborted_errors = stats->txAborted; | ||
2536 | } | ||
2537 | return err; | ||
2538 | } | ||
2539 | |||
2540 | /*==================================================================== | ||
2541 | * Get protocol statistics. | ||
2542 | *===================================================================*/ | ||
2543 | |||
2544 | static int x25_get_stats (sdla_t* card) | ||
2545 | { | ||
2546 | TX25Mbox* mbox = card->mbox; | ||
2547 | int retry = MAX_CMD_RETRY; | ||
2548 | int err; | ||
2549 | |||
2550 | do | ||
2551 | { | ||
2552 | memset(&mbox->cmd, 0, sizeof(TX25Cmd)); | ||
2553 | mbox->cmd.command = X25_READ_STATISTICS; | ||
2554 | err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; | ||
2555 | } while (err && retry-- && x25_error(card, err, X25_READ_STATISTICS, 0)) ; | ||
2556 | |||
2557 | if (!err) | ||
2558 | { | ||
2559 | TX25Stats* stats = (void*)mbox->data; | ||
2560 | |||
2561 | card->wandev.stats.rx_packets = stats->rxData; | ||
2562 | card->wandev.stats.tx_packets = stats->txData; | ||
2563 | } | ||
2564 | return err; | ||
2565 | } | ||
2566 | |||
2567 | /*==================================================================== | ||
2568 | * Close HDLC link. | ||
2569 | *===================================================================*/ | ||
2570 | |||
2571 | static int x25_close_hdlc (sdla_t* card) | ||
2572 | { | ||
2573 | TX25Mbox* mbox = card->mbox; | ||
2574 | int retry = MAX_CMD_RETRY; | ||
2575 | int err; | ||
2576 | |||
2577 | do | ||
2578 | { | ||
2579 | memset(&mbox->cmd, 0, sizeof(TX25Cmd)); | ||
2580 | mbox->cmd.command = X25_HDLC_LINK_CLOSE; | ||
2581 | err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; | ||
2582 | } while (err && retry-- && x25_error(card, err, X25_HDLC_LINK_CLOSE, 0)); | ||
2583 | |||
2584 | return err; | ||
2585 | } | ||
2586 | |||
2587 | |||
2588 | /*==================================================================== | ||
2589 | * Open HDLC link. | ||
2590 | *===================================================================*/ | ||
2591 | |||
2592 | static int x25_open_hdlc (sdla_t* card) | ||
2593 | { | ||
2594 | TX25Mbox* mbox = card->mbox; | ||
2595 | int retry = MAX_CMD_RETRY; | ||
2596 | int err; | ||
2597 | |||
2598 | do | ||
2599 | { | ||
2600 | memset(&mbox->cmd, 0, sizeof(TX25Cmd)); | ||
2601 | mbox->cmd.command = X25_HDLC_LINK_OPEN; | ||
2602 | err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; | ||
2603 | } while (err && retry-- && x25_error(card, err, X25_HDLC_LINK_OPEN, 0)); | ||
2604 | |||
2605 | return err; | ||
2606 | } | ||
2607 | |||
2608 | /*===================================================================== | ||
2609 | * Setup HDLC link. | ||
2610 | *====================================================================*/ | ||
2611 | static int x25_setup_hdlc (sdla_t* card) | ||
2612 | { | ||
2613 | TX25Mbox* mbox = card->mbox; | ||
2614 | int retry = MAX_CMD_RETRY; | ||
2615 | int err; | ||
2616 | |||
2617 | do | ||
2618 | { | ||
2619 | memset(&mbox->cmd, 0, sizeof(TX25Cmd)); | ||
2620 | mbox->cmd.command = X25_HDLC_LINK_SETUP; | ||
2621 | err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; | ||
2622 | } while (err && retry-- && x25_error(card, err, X25_HDLC_LINK_SETUP, 0)); | ||
2623 | |||
2624 | return err; | ||
2625 | } | ||
2626 | |||
2627 | /*==================================================================== | ||
2628 | * Set (raise/drop) DTR. | ||
2629 | *===================================================================*/ | ||
2630 | |||
2631 | static int x25_set_dtr (sdla_t* card, int dtr) | ||
2632 | { | ||
2633 | TX25Mbox* mbox = card->mbox; | ||
2634 | int retry = MAX_CMD_RETRY; | ||
2635 | int err; | ||
2636 | |||
2637 | do | ||
2638 | { | ||
2639 | memset(&mbox->cmd, 0, sizeof(TX25Cmd)); | ||
2640 | mbox->data[0] = 0; | ||
2641 | mbox->data[2] = 0; | ||
2642 | mbox->data[1] = dtr ? 0x02 : 0x01; | ||
2643 | mbox->cmd.length = 3; | ||
2644 | mbox->cmd.command = X25_SET_GLOBAL_VARS; | ||
2645 | err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; | ||
2646 | } while (err && retry-- && x25_error(card, err, X25_SET_GLOBAL_VARS, 0)); | ||
2647 | |||
2648 | return err; | ||
2649 | } | ||
2650 | |||
2651 | /*==================================================================== | ||
2652 | * Set interrupt mode. | ||
2653 | *===================================================================*/ | ||
2654 | |||
2655 | static int x25_set_intr_mode (sdla_t* card, int mode) | ||
2656 | { | ||
2657 | TX25Mbox* mbox = card->mbox; | ||
2658 | int retry = MAX_CMD_RETRY; | ||
2659 | int err; | ||
2660 | |||
2661 | do | ||
2662 | { | ||
2663 | memset(&mbox->cmd, 0, sizeof(TX25Cmd)); | ||
2664 | mbox->data[0] = mode; | ||
2665 | if (card->hw.fwid == SFID_X25_508){ | ||
2666 | mbox->data[1] = card->hw.irq; | ||
2667 | mbox->data[2] = 2; | ||
2668 | mbox->cmd.length = 3; | ||
2669 | }else { | ||
2670 | mbox->cmd.length = 1; | ||
2671 | } | ||
2672 | mbox->cmd.command = X25_SET_INTERRUPT_MODE; | ||
2673 | err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; | ||
2674 | } while (err && retry-- && x25_error(card, err, X25_SET_INTERRUPT_MODE, 0)); | ||
2675 | |||
2676 | return err; | ||
2677 | } | ||
2678 | |||
2679 | /*==================================================================== | ||
2680 | * Read X.25 channel configuration. | ||
2681 | *===================================================================*/ | ||
2682 | |||
2683 | static int x25_get_chan_conf (sdla_t* card, x25_channel_t* chan) | ||
2684 | { | ||
2685 | TX25Mbox* mbox = card->mbox; | ||
2686 | int retry = MAX_CMD_RETRY; | ||
2687 | int lcn = chan->common.lcn; | ||
2688 | int err; | ||
2689 | |||
2690 | do{ | ||
2691 | memset(&mbox->cmd, 0, sizeof(TX25Cmd)); | ||
2692 | mbox->cmd.lcn = lcn; | ||
2693 | mbox->cmd.command = X25_READ_CHANNEL_CONFIG; | ||
2694 | err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; | ||
2695 | } while (err && retry-- && x25_error(card, err, X25_READ_CHANNEL_CONFIG, lcn)); | ||
2696 | |||
2697 | if (!err) | ||
2698 | { | ||
2699 | TX25Status* status = card->flags; | ||
2700 | |||
2701 | /* calculate an offset into the array of status bytes */ | ||
2702 | if (card->u.x.hi_svc <= X25_MAX_CHAN){ | ||
2703 | |||
2704 | chan->ch_idx = lcn - 1; | ||
2705 | |||
2706 | }else{ | ||
2707 | int offset; | ||
2708 | |||
2709 | /* FIX: Apr 14 2000 : Nenad Corbic | ||
2710 | * The data field was being compared to 0x1F using | ||
2711 | * '&&' instead of '&'. | ||
2712 | * This caused X25API to fail for LCNs greater than 255. | ||
2713 | */ | ||
2714 | switch (mbox->data[0] & 0x1F) | ||
2715 | { | ||
2716 | case 0x01: | ||
2717 | offset = status->pvc_map; break; | ||
2718 | case 0x03: | ||
2719 | offset = status->icc_map; break; | ||
2720 | case 0x07: | ||
2721 | offset = status->twc_map; break; | ||
2722 | case 0x0B: | ||
2723 | offset = status->ogc_map; break; | ||
2724 | default: | ||
2725 | offset = 0; | ||
2726 | } | ||
2727 | chan->ch_idx = lcn - 1 - offset; | ||
2728 | } | ||
2729 | |||
2730 | /* get actual transmit packet size on this channel */ | ||
2731 | switch(mbox->data[1] & 0x38) | ||
2732 | { | ||
2733 | case 0x00: | ||
2734 | chan->tx_pkt_size = 16; | ||
2735 | break; | ||
2736 | case 0x08: | ||
2737 | chan->tx_pkt_size = 32; | ||
2738 | break; | ||
2739 | case 0x10: | ||
2740 | chan->tx_pkt_size = 64; | ||
2741 | break; | ||
2742 | case 0x18: | ||
2743 | chan->tx_pkt_size = 128; | ||
2744 | break; | ||
2745 | case 0x20: | ||
2746 | chan->tx_pkt_size = 256; | ||
2747 | break; | ||
2748 | case 0x28: | ||
2749 | chan->tx_pkt_size = 512; | ||
2750 | break; | ||
2751 | case 0x30: | ||
2752 | chan->tx_pkt_size = 1024; | ||
2753 | break; | ||
2754 | } | ||
2755 | if (card->u.x.logging) | ||
2756 | printk(KERN_INFO "%s: X.25 packet size on LCN %d is %d.\n", | ||
2757 | card->devname, lcn, chan->tx_pkt_size); | ||
2758 | } | ||
2759 | return err; | ||
2760 | } | ||
2761 | |||
2762 | /*==================================================================== | ||
2763 | * Place X.25 call. | ||
2764 | *====================================================================*/ | ||
2765 | |||
2766 | static int x25_place_call (sdla_t* card, x25_channel_t* chan) | ||
2767 | { | ||
2768 | TX25Mbox* mbox = card->mbox; | ||
2769 | int retry = MAX_CMD_RETRY; | ||
2770 | int err; | ||
2771 | char str[64]; | ||
2772 | |||
2773 | |||
2774 | if (chan->protocol == htons(ETH_P_IP)){ | ||
2775 | sprintf(str, "-d%s -uCC", chan->addr); | ||
2776 | |||
2777 | }else if (chan->protocol == htons(ETH_P_IPX)){ | ||
2778 | sprintf(str, "-d%s -u800000008137", chan->addr); | ||
2779 | |||
2780 | } | ||
2781 | |||
2782 | do | ||
2783 | { | ||
2784 | memset(&mbox->cmd, 0, sizeof(TX25Cmd)); | ||
2785 | strcpy(mbox->data, str); | ||
2786 | mbox->cmd.length = strlen(str); | ||
2787 | mbox->cmd.command = X25_PLACE_CALL; | ||
2788 | err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; | ||
2789 | } while (err && retry-- && x25_error(card, err, X25_PLACE_CALL, 0)); | ||
2790 | |||
2791 | if (!err){ | ||
2792 | bind_lcn_to_dev (card, chan->dev, mbox->cmd.lcn); | ||
2793 | } | ||
2794 | return err; | ||
2795 | } | ||
2796 | |||
2797 | /*==================================================================== | ||
2798 | * Accept X.25 call. | ||
2799 | *====================================================================*/ | ||
2800 | |||
2801 | static int x25_accept_call (sdla_t* card, int lcn, int qdm) | ||
2802 | { | ||
2803 | TX25Mbox* mbox = card->mbox; | ||
2804 | int retry = MAX_CMD_RETRY; | ||
2805 | int err; | ||
2806 | |||
2807 | do | ||
2808 | { | ||
2809 | memset(&mbox->cmd, 0, sizeof(TX25Cmd)); | ||
2810 | mbox->cmd.lcn = lcn; | ||
2811 | mbox->cmd.qdm = qdm; | ||
2812 | mbox->cmd.command = X25_ACCEPT_CALL; | ||
2813 | err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; | ||
2814 | } while (err && retry-- && x25_error(card, err, X25_ACCEPT_CALL, lcn)); | ||
2815 | |||
2816 | return err; | ||
2817 | } | ||
2818 | |||
2819 | /*==================================================================== | ||
2820 | * Clear X.25 call. | ||
2821 | *====================================================================*/ | ||
2822 | |||
2823 | static int x25_clear_call (sdla_t* card, int lcn, int cause, int diagn) | ||
2824 | { | ||
2825 | TX25Mbox* mbox = card->mbox; | ||
2826 | int retry = MAX_CMD_RETRY; | ||
2827 | int err; | ||
2828 | |||
2829 | do | ||
2830 | { | ||
2831 | memset(&mbox->cmd, 0, sizeof(TX25Cmd)); | ||
2832 | mbox->cmd.lcn = lcn; | ||
2833 | mbox->cmd.cause = cause; | ||
2834 | mbox->cmd.diagn = diagn; | ||
2835 | mbox->cmd.command = X25_CLEAR_CALL; | ||
2836 | err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; | ||
2837 | } while (err && retry-- && x25_error(card, err, X25_CLEAR_CALL, lcn)); | ||
2838 | |||
2839 | return err; | ||
2840 | } | ||
2841 | |||
2842 | /*==================================================================== | ||
2843 | * Send X.25 data packet. | ||
2844 | *====================================================================*/ | ||
2845 | |||
2846 | static int x25_send (sdla_t* card, int lcn, int qdm, int len, void* buf) | ||
2847 | { | ||
2848 | TX25Mbox* mbox = card->mbox; | ||
2849 | int retry = MAX_CMD_RETRY; | ||
2850 | int err; | ||
2851 | unsigned char cmd; | ||
2852 | |||
2853 | if (card->u.x.LAPB_hdlc) | ||
2854 | cmd = X25_HDLC_WRITE; | ||
2855 | else | ||
2856 | cmd = X25_WRITE; | ||
2857 | |||
2858 | do | ||
2859 | { | ||
2860 | memset(&mbox->cmd, 0, sizeof(TX25Cmd)); | ||
2861 | memcpy(mbox->data, buf, len); | ||
2862 | mbox->cmd.length = len; | ||
2863 | mbox->cmd.lcn = lcn; | ||
2864 | |||
2865 | if (card->u.x.LAPB_hdlc){ | ||
2866 | mbox->cmd.pf = qdm; | ||
2867 | }else{ | ||
2868 | mbox->cmd.qdm = qdm; | ||
2869 | } | ||
2870 | |||
2871 | mbox->cmd.command = cmd; | ||
2872 | err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; | ||
2873 | } while (err && retry-- && x25_error(card, err, cmd , lcn)); | ||
2874 | |||
2875 | |||
2876 | /* If buffers are busy the return code for LAPB HDLC is | ||
2877 | * 1. The above functions are looking for return code | ||
2878 | * of X25RES_NOT_READY if busy. */ | ||
2879 | |||
2880 | if (card->u.x.LAPB_hdlc && err == 1){ | ||
2881 | err = X25RES_NOT_READY; | ||
2882 | } | ||
2883 | |||
2884 | return err; | ||
2885 | } | ||
2886 | |||
2887 | /*==================================================================== | ||
2888 | * Fetch X.25 asynchronous events. | ||
2889 | *===================================================================*/ | ||
2890 | |||
2891 | static int x25_fetch_events (sdla_t* card) | ||
2892 | { | ||
2893 | TX25Status* status = card->flags; | ||
2894 | TX25Mbox* mbox = card->mbox; | ||
2895 | int err = 0; | ||
2896 | |||
2897 | if (status->gflags & 0x20) | ||
2898 | { | ||
2899 | memset(&mbox->cmd, 0, sizeof(TX25Cmd)); | ||
2900 | mbox->cmd.command = X25_IS_DATA_AVAILABLE; | ||
2901 | err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; | ||
2902 | if (err) x25_error(card, err, X25_IS_DATA_AVAILABLE, 0); | ||
2903 | } | ||
2904 | return err; | ||
2905 | } | ||
2906 | |||
2907 | /*==================================================================== | ||
2908 | * X.25 asynchronous event/error handler. | ||
2909 | * This routine is called each time interface command returns | ||
2910 | * non-zero return code to handle X.25 asynchronous events and | ||
2911 | * common errors. Return non-zero to repeat command or zero to | ||
2912 | * cancel it. | ||
2913 | * | ||
2914 | * Notes: | ||
2915 | * 1. This function may be called recursively, as handling some of the | ||
2916 | * asynchronous events (e.g. call request) requires execution of the | ||
2917 | * interface command(s) that, in turn, may also return asynchronous | ||
2918 | * events. To avoid re-entrancy problems we copy mailbox to dynamically | ||
2919 | * allocated memory before processing events. | ||
2920 | *====================================================================*/ | ||
2921 | |||
2922 | static int x25_error (sdla_t* card, int err, int cmd, int lcn) | ||
2923 | { | ||
2924 | int retry = 1; | ||
2925 | unsigned dlen = ((TX25Mbox*)card->mbox)->cmd.length; | ||
2926 | TX25Mbox* mb; | ||
2927 | |||
2928 | mb = kmalloc(sizeof(TX25Mbox) + dlen, GFP_ATOMIC); | ||
2929 | if (mb == NULL) | ||
2930 | { | ||
2931 | printk(KERN_ERR "%s: x25_error() out of memory!\n", | ||
2932 | card->devname); | ||
2933 | return 0; | ||
2934 | } | ||
2935 | memcpy(mb, card->mbox, sizeof(TX25Mbox) + dlen); | ||
2936 | switch (err){ | ||
2937 | |||
2938 | case X25RES_ASYNC_PACKET: /* X.25 asynchronous packet was received */ | ||
2939 | |||
2940 | mb->data[dlen] = '\0'; | ||
2941 | |||
2942 | switch (mb->cmd.pktType & 0x7F){ | ||
2943 | |||
2944 | case ASE_CALL_RQST: /* incoming call */ | ||
2945 | retry = incoming_call(card, cmd, lcn, mb); | ||
2946 | break; | ||
2947 | |||
2948 | case ASE_CALL_ACCEPTED: /* connected */ | ||
2949 | retry = call_accepted(card, cmd, lcn, mb); | ||
2950 | break; | ||
2951 | |||
2952 | case ASE_CLEAR_RQST: /* call clear request */ | ||
2953 | retry = call_cleared(card, cmd, lcn, mb); | ||
2954 | break; | ||
2955 | |||
2956 | case ASE_RESET_RQST: /* reset request */ | ||
2957 | printk(KERN_INFO "%s: X.25 reset request on LCN %d! " | ||
2958 | "Cause:0x%02X Diagn:0x%02X\n", | ||
2959 | card->devname, mb->cmd.lcn, mb->cmd.cause, | ||
2960 | mb->cmd.diagn); | ||
2961 | api_oob_event (card,mb); | ||
2962 | break; | ||
2963 | |||
2964 | case ASE_RESTART_RQST: /* restart request */ | ||
2965 | retry = restart_event(card, cmd, lcn, mb); | ||
2966 | break; | ||
2967 | |||
2968 | case ASE_CLEAR_CONFRM: | ||
2969 | if (clear_confirm_event (card,mb)) | ||
2970 | break; | ||
2971 | |||
2972 | /* I use the goto statement here so if | ||
2973 | * somebody inserts code between the | ||
2974 | * case and default, we will not have | ||
2975 | * ghost problems */ | ||
2976 | |||
2977 | goto dflt_1; | ||
2978 | |||
2979 | default: | ||
2980 | dflt_1: | ||
2981 | printk(KERN_INFO "%s: X.25 event 0x%02X on LCN %d! " | ||
2982 | "Cause:0x%02X Diagn:0x%02X\n", | ||
2983 | card->devname, mb->cmd.pktType, | ||
2984 | mb->cmd.lcn, mb->cmd.cause, mb->cmd.diagn); | ||
2985 | } | ||
2986 | break; | ||
2987 | |||
2988 | case X25RES_PROTO_VIOLATION: /* X.25 protocol violation indication */ | ||
2989 | |||
2990 | /* Bug Fix: Mar 14 2000 | ||
2991 | * The Protocol violation error conditions were | ||
2992 | * not handled previously */ | ||
2993 | |||
2994 | switch (mb->cmd.pktType & 0x7F){ | ||
2995 | |||
2996 | case PVE_CLEAR_RQST: /* Clear request */ | ||
2997 | retry = call_cleared(card, cmd, lcn, mb); | ||
2998 | break; | ||
2999 | |||
3000 | case PVE_RESET_RQST: /* Reset request */ | ||
3001 | printk(KERN_INFO "%s: X.25 reset request on LCN %d! " | ||
3002 | "Cause:0x%02X Diagn:0x%02X\n", | ||
3003 | card->devname, mb->cmd.lcn, mb->cmd.cause, | ||
3004 | mb->cmd.diagn); | ||
3005 | api_oob_event (card,mb); | ||
3006 | break; | ||
3007 | |||
3008 | case PVE_RESTART_RQST: /* Restart request */ | ||
3009 | retry = restart_event(card, cmd, lcn, mb); | ||
3010 | break; | ||
3011 | |||
3012 | default : | ||
3013 | printk(KERN_INFO | ||
3014 | "%s: X.25 protocol violation on LCN %d! " | ||
3015 | "Packet:0x%02X Cause:0x%02X Diagn:0x%02X\n", | ||
3016 | card->devname, mb->cmd.lcn, | ||
3017 | mb->cmd.pktType & 0x7F, mb->cmd.cause, mb->cmd.diagn); | ||
3018 | api_oob_event(card,mb); | ||
3019 | } | ||
3020 | break; | ||
3021 | |||
3022 | case 0x42: /* X.25 timeout */ | ||
3023 | retry = timeout_event(card, cmd, lcn, mb); | ||
3024 | break; | ||
3025 | |||
3026 | case 0x43: /* X.25 retry limit exceeded */ | ||
3027 | printk(KERN_INFO | ||
3028 | "%s: exceeded X.25 retry limit on LCN %d! " | ||
3029 | "Packet:0x%02X Diagn:0x%02X\n", card->devname, | ||
3030 | mb->cmd.lcn, mb->cmd.pktType, mb->cmd.diagn) | ||
3031 | ; | ||
3032 | break; | ||
3033 | |||
3034 | case 0x08: /* modem failure */ | ||
3035 | #ifndef MODEM_NOT_LOG | ||
3036 | printk(KERN_INFO "%s: modem failure!\n", card->devname); | ||
3037 | #endif /* MODEM_NOT_LOG */ | ||
3038 | api_oob_event(card,mb); | ||
3039 | break; | ||
3040 | |||
3041 | case 0x09: /* N2 retry limit */ | ||
3042 | printk(KERN_INFO "%s: exceeded HDLC retry limit!\n", | ||
3043 | card->devname); | ||
3044 | api_oob_event(card,mb); | ||
3045 | break; | ||
3046 | |||
3047 | case 0x06: /* unnumbered frame was received while in ABM */ | ||
3048 | printk(KERN_INFO "%s: received Unnumbered frame 0x%02X!\n", | ||
3049 | card->devname, mb->data[0]); | ||
3050 | api_oob_event(card,mb); | ||
3051 | break; | ||
3052 | |||
3053 | case CMD_TIMEOUT: | ||
3054 | printk(KERN_ERR "%s: command 0x%02X timed out!\n", | ||
3055 | card->devname, cmd) | ||
3056 | ; | ||
3057 | retry = 0; /* abort command */ | ||
3058 | break; | ||
3059 | |||
3060 | case X25RES_NOT_READY: | ||
3061 | retry = 1; | ||
3062 | break; | ||
3063 | |||
3064 | case 0x01: | ||
3065 | if (card->u.x.LAPB_hdlc) | ||
3066 | break; | ||
3067 | |||
3068 | if (mb->cmd.command == 0x16) | ||
3069 | break; | ||
3070 | /* I use the goto statement here so if | ||
3071 | * somebody inserts code between the | ||
3072 | * case and default, we will not have | ||
3073 | * ghost problems */ | ||
3074 | goto dflt_2; | ||
3075 | |||
3076 | default: | ||
3077 | dflt_2: | ||
3078 | printk(KERN_INFO "%s: command 0x%02X returned 0x%02X! Lcn %i\n", | ||
3079 | card->devname, cmd, err, mb->cmd.lcn) | ||
3080 | ; | ||
3081 | retry = 0; /* abort command */ | ||
3082 | } | ||
3083 | kfree(mb); | ||
3084 | return retry; | ||
3085 | } | ||
3086 | |||
3087 | /*==================================================================== | ||
3088 | * X.25 Asynchronous Event Handlers | ||
3089 | * These functions are called by the x25_error() and should return 0, if | ||
3090 | * the command resulting in the asynchronous event must be aborted. | ||
3091 | *====================================================================*/ | ||
3092 | |||
3093 | |||
3094 | |||
3095 | /*==================================================================== | ||
3096 | *Handle X.25 incoming call request. | ||
3097 | * RFC 1356 establishes the following rules: | ||
3098 | * 1. The first octet in the Call User Data (CUD) field of the call | ||
3099 | * request packet contains NLPID identifying protocol encapsulation | ||
3100 | * 2. Calls MUST NOT be accepted unless router supports requested | ||
3101 | * protocol encapsulation. | ||
3102 | * 3. A diagnostic code 249 defined by ISO/IEC 8208 may be used | ||
3103 | * when clearing a call because protocol encapsulation is not | ||
3104 | * supported. | ||
3105 | * 4. If an incoming call is received while a call request is | ||
3106 | * pending (i.e. call collision has occurred), the incoming call | ||
3107 | * shall be rejected and call request shall be retried. | ||
3108 | *====================================================================*/ | ||
3109 | |||
3110 | static int incoming_call (sdla_t* card, int cmd, int lcn, TX25Mbox* mb) | ||
3111 | { | ||
3112 | struct wan_device* wandev = &card->wandev; | ||
3113 | int new_lcn = mb->cmd.lcn; | ||
3114 | struct net_device* dev = get_dev_by_lcn(wandev, new_lcn); | ||
3115 | x25_channel_t* chan = NULL; | ||
3116 | int accept = 0; /* set to '1' if o.k. to accept call */ | ||
3117 | unsigned int user_data; | ||
3118 | x25_call_info_t* info; | ||
3119 | |||
3120 | /* Make sure there is no call collision */ | ||
3121 | if (dev != NULL) | ||
3122 | { | ||
3123 | printk(KERN_INFO | ||
3124 | "%s: X.25 incoming call collision on LCN %d!\n", | ||
3125 | card->devname, new_lcn); | ||
3126 | |||
3127 | x25_clear_call(card, new_lcn, 0, 0); | ||
3128 | return 1; | ||
3129 | } | ||
3130 | |||
3131 | /* Make sure D bit is not set in call request */ | ||
3132 | //FIXME: THIS IS NOT TURE !!!! TAKE IT OUT | ||
3133 | // if (mb->cmd.qdm & 0x02) | ||
3134 | // { | ||
3135 | // printk(KERN_INFO | ||
3136 | // "%s: X.25 incoming call on LCN %d with D-bit set!\n", | ||
3137 | // card->devname, new_lcn); | ||
3138 | // | ||
3139 | // x25_clear_call(card, new_lcn, 0, 0); | ||
3140 | // return 1; | ||
3141 | // } | ||
3142 | |||
3143 | /* Parse call request data */ | ||
3144 | info = kmalloc(sizeof(x25_call_info_t), GFP_ATOMIC); | ||
3145 | if (info == NULL) | ||
3146 | { | ||
3147 | printk(KERN_ERR | ||
3148 | "%s: not enough memory to parse X.25 incoming call " | ||
3149 | "on LCN %d!\n", card->devname, new_lcn); | ||
3150 | x25_clear_call(card, new_lcn, 0, 0); | ||
3151 | return 1; | ||
3152 | } | ||
3153 | |||
3154 | parse_call_info(mb->data, info); | ||
3155 | |||
3156 | if (card->u.x.logging) | ||
3157 | printk(KERN_INFO "\n%s: X.25 incoming call on LCN %d!\n", | ||
3158 | card->devname, new_lcn); | ||
3159 | |||
3160 | /* Conver the first two ASCII characters into an | ||
3161 | * interger. Used to check the incoming protocol | ||
3162 | */ | ||
3163 | user_data = hex_to_uint(info->user,2); | ||
3164 | |||
3165 | /* Find available channel */ | ||
3166 | for (dev = wandev->dev; dev; dev = *((struct net_device **)dev->priv)) { | ||
3167 | chan = dev->priv; | ||
3168 | |||
3169 | if (chan->common.usedby == API) | ||
3170 | continue; | ||
3171 | |||
3172 | if (!chan->common.svc || (chan->common.state != WAN_DISCONNECTED)) | ||
3173 | continue; | ||
3174 | |||
3175 | if (user_data == NLPID_IP && chan->protocol != htons(ETH_P_IP)){ | ||
3176 | printk(KERN_INFO "IP packet but configured for IPX : %x, %x\n", | ||
3177 | htons(chan->protocol), info->user[0]); | ||
3178 | continue; | ||
3179 | } | ||
3180 | |||
3181 | if (user_data == NLPID_SNAP && chan->protocol != htons(ETH_P_IPX)){ | ||
3182 | printk(KERN_INFO "IPX packet but configured for IP: %x\n", | ||
3183 | htons(chan->protocol)); | ||
3184 | continue; | ||
3185 | } | ||
3186 | if (strcmp(info->src, chan->addr) == 0) | ||
3187 | break; | ||
3188 | |||
3189 | /* If just an '@' is specified, accept all incoming calls */ | ||
3190 | if (strcmp(chan->addr, "") == 0) | ||
3191 | break; | ||
3192 | } | ||
3193 | |||
3194 | if (dev == NULL){ | ||
3195 | |||
3196 | /* If the call is not for any WANPIPE interfaces | ||
3197 | * check to see if there is an API listening queue | ||
3198 | * waiting for data. If there is send the packet | ||
3199 | * up the stack. | ||
3200 | */ | ||
3201 | if (card->sk != NULL && card->func != NULL){ | ||
3202 | if (api_incoming_call(card,mb,new_lcn)){ | ||
3203 | x25_clear_call(card, new_lcn, 0, 0); | ||
3204 | } | ||
3205 | accept = 0; | ||
3206 | }else{ | ||
3207 | printk(KERN_INFO "%s: no channels available!\n", | ||
3208 | card->devname); | ||
3209 | |||
3210 | x25_clear_call(card, new_lcn, 0, 0); | ||
3211 | } | ||
3212 | |||
3213 | }else if (info->nuser == 0){ | ||
3214 | |||
3215 | printk(KERN_INFO | ||
3216 | "%s: no user data in incoming call on LCN %d!\n", | ||
3217 | card->devname, new_lcn) | ||
3218 | ; | ||
3219 | x25_clear_call(card, new_lcn, 0, 0); | ||
3220 | |||
3221 | }else switch (info->user[0]){ | ||
3222 | |||
3223 | case 0: /* multiplexed */ | ||
3224 | chan->protocol = htons(0); | ||
3225 | accept = 1; | ||
3226 | break; | ||
3227 | |||
3228 | case NLPID_IP: /* IP datagrams */ | ||
3229 | accept = 1; | ||
3230 | break; | ||
3231 | |||
3232 | case NLPID_SNAP: /* IPX datagrams */ | ||
3233 | accept = 1; | ||
3234 | break; | ||
3235 | |||
3236 | default: | ||
3237 | printk(KERN_INFO | ||
3238 | "%s: unsupported NLPID 0x%02X in incoming call " | ||
3239 | "on LCN %d!\n", card->devname, info->user[0], new_lcn); | ||
3240 | x25_clear_call(card, new_lcn, 0, 249); | ||
3241 | } | ||
3242 | |||
3243 | if (accept && (x25_accept_call(card, new_lcn, 0) == CMD_OK)){ | ||
3244 | |||
3245 | bind_lcn_to_dev (card, chan->dev, new_lcn); | ||
3246 | |||
3247 | if (x25_get_chan_conf(card, chan) == CMD_OK) | ||
3248 | set_chan_state(dev, WAN_CONNECTED); | ||
3249 | else | ||
3250 | x25_clear_call(card, new_lcn, 0, 0); | ||
3251 | } | ||
3252 | kfree(info); | ||
3253 | return 1; | ||
3254 | } | ||
3255 | |||
3256 | /*==================================================================== | ||
3257 | * Handle accepted call. | ||
3258 | *====================================================================*/ | ||
3259 | |||
3260 | static int call_accepted (sdla_t* card, int cmd, int lcn, TX25Mbox* mb) | ||
3261 | { | ||
3262 | unsigned new_lcn = mb->cmd.lcn; | ||
3263 | struct net_device* dev = find_channel(card, new_lcn); | ||
3264 | x25_channel_t* chan; | ||
3265 | |||
3266 | if (dev == NULL){ | ||
3267 | printk(KERN_INFO | ||
3268 | "%s: clearing orphaned connection on LCN %d!\n", | ||
3269 | card->devname, new_lcn); | ||
3270 | x25_clear_call(card, new_lcn, 0, 0); | ||
3271 | return 1; | ||
3272 | } | ||
3273 | |||
3274 | if (card->u.x.logging) | ||
3275 | printk(KERN_INFO "%s: X.25 call accepted on Dev %s and LCN %d!\n", | ||
3276 | card->devname, dev->name, new_lcn); | ||
3277 | |||
3278 | /* Get channel configuration and notify router */ | ||
3279 | chan = dev->priv; | ||
3280 | if (x25_get_chan_conf(card, chan) != CMD_OK) | ||
3281 | { | ||
3282 | x25_clear_call(card, new_lcn, 0, 0); | ||
3283 | return 1; | ||
3284 | } | ||
3285 | |||
3286 | set_chan_state(dev, WAN_CONNECTED); | ||
3287 | |||
3288 | if (chan->common.usedby == API){ | ||
3289 | send_delayed_cmd_result(card,dev,mb); | ||
3290 | bind_lcn_to_dev (card, dev, new_lcn); | ||
3291 | } | ||
3292 | |||
3293 | return 1; | ||
3294 | } | ||
3295 | |||
3296 | /*==================================================================== | ||
3297 | * Handle cleared call. | ||
3298 | *====================================================================*/ | ||
3299 | |||
3300 | static int call_cleared (sdla_t* card, int cmd, int lcn, TX25Mbox* mb) | ||
3301 | { | ||
3302 | unsigned new_lcn = mb->cmd.lcn; | ||
3303 | struct net_device* dev = find_channel(card, new_lcn); | ||
3304 | x25_channel_t *chan; | ||
3305 | unsigned char old_state; | ||
3306 | |||
3307 | if (card->u.x.logging){ | ||
3308 | printk(KERN_INFO "%s: X.25 clear request on LCN %d! Cause:0x%02X " | ||
3309 | "Diagn:0x%02X\n", | ||
3310 | card->devname, new_lcn, mb->cmd.cause, mb->cmd.diagn); | ||
3311 | } | ||
3312 | |||
3313 | if (dev == NULL){ | ||
3314 | printk(KERN_INFO "%s: X.25 clear request : No device for clear\n", | ||
3315 | card->devname); | ||
3316 | return 1; | ||
3317 | } | ||
3318 | |||
3319 | chan=dev->priv; | ||
3320 | |||
3321 | old_state = chan->common.state; | ||
3322 | |||
3323 | set_chan_state(dev, WAN_DISCONNECTED); | ||
3324 | |||
3325 | if (chan->common.usedby == API){ | ||
3326 | |||
3327 | switch (old_state){ | ||
3328 | |||
3329 | case WAN_CONNECTING: | ||
3330 | send_delayed_cmd_result(card,dev,mb); | ||
3331 | break; | ||
3332 | case WAN_CONNECTED: | ||
3333 | send_oob_msg(card,dev,mb); | ||
3334 | break; | ||
3335 | } | ||
3336 | } | ||
3337 | |||
3338 | return ((cmd == X25_WRITE) && (lcn == new_lcn)) ? 0 : 1; | ||
3339 | } | ||
3340 | |||
3341 | /*==================================================================== | ||
3342 | * Handle X.25 restart event. | ||
3343 | *====================================================================*/ | ||
3344 | |||
3345 | static int restart_event (sdla_t* card, int cmd, int lcn, TX25Mbox* mb) | ||
3346 | { | ||
3347 | struct wan_device* wandev = &card->wandev; | ||
3348 | struct net_device* dev; | ||
3349 | x25_channel_t *chan; | ||
3350 | unsigned char old_state; | ||
3351 | |||
3352 | printk(KERN_INFO | ||
3353 | "%s: X.25 restart request! Cause:0x%02X Diagn:0x%02X\n", | ||
3354 | card->devname, mb->cmd.cause, mb->cmd.diagn); | ||
3355 | |||
3356 | /* down all logical channels */ | ||
3357 | for (dev = wandev->dev; dev; dev = *((struct net_device **)dev->priv)) { | ||
3358 | chan=dev->priv; | ||
3359 | old_state = chan->common.state; | ||
3360 | |||
3361 | set_chan_state(dev, WAN_DISCONNECTED); | ||
3362 | |||
3363 | if (chan->common.usedby == API){ | ||
3364 | switch (old_state){ | ||
3365 | |||
3366 | case WAN_CONNECTING: | ||
3367 | send_delayed_cmd_result(card,dev,mb); | ||
3368 | break; | ||
3369 | case WAN_CONNECTED: | ||
3370 | send_oob_msg(card,dev,mb); | ||
3371 | break; | ||
3372 | } | ||
3373 | } | ||
3374 | } | ||
3375 | return (cmd == X25_WRITE) ? 0 : 1; | ||
3376 | } | ||
3377 | |||
3378 | /*==================================================================== | ||
3379 | * Handle timeout event. | ||
3380 | *====================================================================*/ | ||
3381 | |||
3382 | static int timeout_event (sdla_t* card, int cmd, int lcn, TX25Mbox* mb) | ||
3383 | { | ||
3384 | unsigned new_lcn = mb->cmd.lcn; | ||
3385 | |||
3386 | if (mb->cmd.pktType == 0x05) /* call request time out */ | ||
3387 | { | ||
3388 | struct net_device* dev = find_channel(card,new_lcn); | ||
3389 | |||
3390 | printk(KERN_INFO "%s: X.25 call timed timeout on LCN %d!\n", | ||
3391 | card->devname, new_lcn); | ||
3392 | |||
3393 | if (dev){ | ||
3394 | x25_channel_t *chan = dev->priv; | ||
3395 | set_chan_state(dev, WAN_DISCONNECTED); | ||
3396 | |||
3397 | if (chan->common.usedby == API){ | ||
3398 | send_delayed_cmd_result(card,dev,card->mbox); | ||
3399 | } | ||
3400 | } | ||
3401 | }else{ | ||
3402 | printk(KERN_INFO "%s: X.25 packet 0x%02X timeout on LCN %d!\n", | ||
3403 | card->devname, mb->cmd.pktType, new_lcn); | ||
3404 | } | ||
3405 | return 1; | ||
3406 | } | ||
3407 | |||
3408 | /* | ||
3409 | * Miscellaneous | ||
3410 | */ | ||
3411 | |||
3412 | /*==================================================================== | ||
3413 | * Establish physical connection. | ||
3414 | * o open HDLC and raise DTR | ||
3415 | * | ||
3416 | * Return: 0 connection established | ||
3417 | * 1 connection is in progress | ||
3418 | * <0 error | ||
3419 | *===================================================================*/ | ||
3420 | |||
3421 | static int connect (sdla_t* card) | ||
3422 | { | ||
3423 | TX25Status* status = card->flags; | ||
3424 | |||
3425 | if (x25_open_hdlc(card) || x25_setup_hdlc(card)) | ||
3426 | return -EIO; | ||
3427 | |||
3428 | wanpipe_set_state(card, WAN_CONNECTING); | ||
3429 | |||
3430 | x25_set_intr_mode(card, INTR_ON_TIMER); | ||
3431 | status->imask &= ~INTR_ON_TIMER; | ||
3432 | |||
3433 | return 1; | ||
3434 | } | ||
3435 | |||
3436 | /* | ||
3437 | * Tear down physical connection. | ||
3438 | * o close HDLC link | ||
3439 | * o drop DTR | ||
3440 | * | ||
3441 | * Return: 0 | ||
3442 | * <0 error | ||
3443 | */ | ||
3444 | |||
3445 | static int disconnect (sdla_t* card) | ||
3446 | { | ||
3447 | wanpipe_set_state(card, WAN_DISCONNECTED); | ||
3448 | x25_set_intr_mode(card, INTR_ON_TIMER); /* disable all interrupt except timer */ | ||
3449 | x25_close_hdlc(card); /* close HDLC link */ | ||
3450 | x25_set_dtr(card, 0); /* drop DTR */ | ||
3451 | return 0; | ||
3452 | } | ||
3453 | |||
3454 | /* | ||
3455 | * Find network device by its channel number. | ||
3456 | */ | ||
3457 | |||
3458 | static struct net_device* get_dev_by_lcn(struct wan_device* wandev, | ||
3459 | unsigned lcn) | ||
3460 | { | ||
3461 | struct net_device* dev; | ||
3462 | |||
3463 | for (dev = wandev->dev; dev; dev = *((struct net_device **)dev->priv)) | ||
3464 | if (((x25_channel_t*)dev->priv)->common.lcn == lcn) | ||
3465 | break; | ||
3466 | return dev; | ||
3467 | } | ||
3468 | |||
3469 | /* | ||
3470 | * Initiate connection on the logical channel. | ||
3471 | * o for PVC we just get channel configuration | ||
3472 | * o for SVCs place an X.25 call | ||
3473 | * | ||
3474 | * Return: 0 connected | ||
3475 | * >0 connection in progress | ||
3476 | * <0 failure | ||
3477 | */ | ||
3478 | |||
3479 | static int chan_connect(struct net_device* dev) | ||
3480 | { | ||
3481 | x25_channel_t* chan = dev->priv; | ||
3482 | sdla_t* card = chan->card; | ||
3483 | |||
3484 | if (chan->common.svc && chan->common.usedby == WANPIPE){ | ||
3485 | if (!chan->addr[0]){ | ||
3486 | printk(KERN_INFO "%s: No Destination Address\n", | ||
3487 | card->devname); | ||
3488 | return -EINVAL; /* no destination address */ | ||
3489 | } | ||
3490 | printk(KERN_INFO "%s: placing X.25 call to %s ...\n", | ||
3491 | card->devname, chan->addr); | ||
3492 | |||
3493 | if (x25_place_call(card, chan) != CMD_OK) | ||
3494 | return -EIO; | ||
3495 | |||
3496 | set_chan_state(dev, WAN_CONNECTING); | ||
3497 | return 1; | ||
3498 | }else{ | ||
3499 | if (x25_get_chan_conf(card, chan) != CMD_OK) | ||
3500 | return -EIO; | ||
3501 | |||
3502 | set_chan_state(dev, WAN_CONNECTED); | ||
3503 | } | ||
3504 | return 0; | ||
3505 | } | ||
3506 | |||
3507 | /* | ||
3508 | * Disconnect logical channel. | ||
3509 | * o if SVC then clear X.25 call | ||
3510 | */ | ||
3511 | |||
3512 | static int chan_disc(struct net_device* dev) | ||
3513 | { | ||
3514 | x25_channel_t* chan = dev->priv; | ||
3515 | |||
3516 | if (chan->common.svc){ | ||
3517 | x25_clear_call(chan->card, chan->common.lcn, 0, 0); | ||
3518 | |||
3519 | /* For API we disconnect on clear | ||
3520 | * confirmation. | ||
3521 | */ | ||
3522 | if (chan->common.usedby == API) | ||
3523 | return 0; | ||
3524 | } | ||
3525 | |||
3526 | set_chan_state(dev, WAN_DISCONNECTED); | ||
3527 | |||
3528 | return 0; | ||
3529 | } | ||
3530 | |||
3531 | /* | ||
3532 | * Set logical channel state. | ||
3533 | */ | ||
3534 | |||
3535 | static void set_chan_state(struct net_device* dev, int state) | ||
3536 | { | ||
3537 | x25_channel_t* chan = dev->priv; | ||
3538 | sdla_t* card = chan->card; | ||
3539 | unsigned long flags; | ||
3540 | |||
3541 | save_flags(flags); | ||
3542 | cli(); | ||
3543 | if (chan->common.state != state) | ||
3544 | { | ||
3545 | switch (state) | ||
3546 | { | ||
3547 | case WAN_CONNECTED: | ||
3548 | if (card->u.x.logging){ | ||
3549 | printk (KERN_INFO | ||
3550 | "%s: interface %s connected, lcn %i !\n", | ||
3551 | card->devname, dev->name,chan->common.lcn); | ||
3552 | } | ||
3553 | *(unsigned short*)dev->dev_addr = htons(chan->common.lcn); | ||
3554 | chan->i_timeout_sofar = jiffies; | ||
3555 | |||
3556 | /* LAPB is PVC Based */ | ||
3557 | if (card->u.x.LAPB_hdlc) | ||
3558 | chan->common.svc=0; | ||
3559 | break; | ||
3560 | |||
3561 | case WAN_CONNECTING: | ||
3562 | if (card->u.x.logging){ | ||
3563 | printk (KERN_INFO | ||
3564 | "%s: interface %s connecting, lcn %i ...\n", | ||
3565 | card->devname, dev->name, chan->common.lcn); | ||
3566 | } | ||
3567 | break; | ||
3568 | |||
3569 | case WAN_DISCONNECTED: | ||
3570 | if (card->u.x.logging){ | ||
3571 | printk (KERN_INFO | ||
3572 | "%s: interface %s disconnected, lcn %i !\n", | ||
3573 | card->devname, dev->name,chan->common.lcn); | ||
3574 | } | ||
3575 | atomic_set(&chan->common.disconnect,0); | ||
3576 | |||
3577 | if (chan->common.svc) { | ||
3578 | *(unsigned short*)dev->dev_addr = 0; | ||
3579 | card->u.x.svc_to_dev_map[(chan->common.lcn%X25_MAX_CHAN)]=NULL; | ||
3580 | chan->common.lcn = 0; | ||
3581 | } | ||
3582 | |||
3583 | if (chan->transmit_length){ | ||
3584 | chan->transmit_length=0; | ||
3585 | atomic_set(&chan->common.driver_busy,0); | ||
3586 | chan->tx_offset=0; | ||
3587 | if (netif_queue_stopped(dev)){ | ||
3588 | netif_wake_queue(dev); | ||
3589 | } | ||
3590 | } | ||
3591 | atomic_set(&chan->common.command,0); | ||
3592 | break; | ||
3593 | |||
3594 | case WAN_DISCONNECTING: | ||
3595 | if (card->u.x.logging){ | ||
3596 | printk (KERN_INFO | ||
3597 | "\n%s: interface %s disconnecting, lcn %i ...\n", | ||
3598 | card->devname, dev->name,chan->common.lcn); | ||
3599 | } | ||
3600 | atomic_set(&chan->common.disconnect,0); | ||
3601 | break; | ||
3602 | } | ||
3603 | chan->common.state = state; | ||
3604 | } | ||
3605 | chan->state_tick = jiffies; | ||
3606 | restore_flags(flags); | ||
3607 | } | ||
3608 | |||
3609 | /* | ||
3610 | * Send packet on a logical channel. | ||
3611 | * When this function is called, tx_skb field of the channel data | ||
3612 | * space points to the transmit socket buffer. When transmission | ||
3613 | * is complete, release socket buffer and reset 'tbusy' flag. | ||
3614 | * | ||
3615 | * Return: 0 - transmission complete | ||
3616 | * 1 - busy | ||
3617 | * | ||
3618 | * Notes: | ||
3619 | * 1. If packet length is greater than MTU for this channel, we'll fragment | ||
3620 | * the packet into 'complete sequence' using M-bit. | ||
3621 | * 2. When transmission is complete, an event notification should be issued | ||
3622 | * to the router. | ||
3623 | */ | ||
3624 | |||
3625 | static int chan_send(struct net_device* dev, void* buff, unsigned data_len, | ||
3626 | unsigned char tx_intr) | ||
3627 | { | ||
3628 | x25_channel_t* chan = dev->priv; | ||
3629 | sdla_t* card = chan->card; | ||
3630 | TX25Status* status = card->flags; | ||
3631 | unsigned len=0, qdm=0, res=0, orig_len = 0; | ||
3632 | void *data; | ||
3633 | |||
3634 | /* Check to see if channel is ready */ | ||
3635 | if ((!(status->cflags[chan->ch_idx] & 0x40) && !card->u.x.LAPB_hdlc) || | ||
3636 | !(*card->u.x.hdlc_buf_status & 0x40)){ | ||
3637 | |||
3638 | if (!tx_intr){ | ||
3639 | setup_for_delayed_transmit (dev, buff, data_len); | ||
3640 | return 0; | ||
3641 | }else{ | ||
3642 | /* By returning 0 to tx_intr the packet will be dropped */ | ||
3643 | ++card->wandev.stats.tx_dropped; | ||
3644 | ++chan->ifstats.tx_dropped; | ||
3645 | printk(KERN_INFO "%s: ERROR, Tx intr could not send, dropping %s:\n", | ||
3646 | card->devname,dev->name); | ||
3647 | ++chan->if_send_stat.if_send_bfr_not_passed_to_adptr; | ||
3648 | return 0; | ||
3649 | } | ||
3650 | } | ||
3651 | |||
3652 | if (chan->common.usedby == API){ | ||
3653 | /* Remove the API Header */ | ||
3654 | x25api_hdr_t *api_data = (x25api_hdr_t *)buff; | ||
3655 | |||
3656 | /* Set the qdm bits from the packet header | ||
3657 | * User has the option to set the qdm bits | ||
3658 | */ | ||
3659 | qdm = api_data->qdm; | ||
3660 | |||
3661 | orig_len = len = data_len - sizeof(x25api_hdr_t); | ||
3662 | data = (unsigned char*)buff + sizeof(x25api_hdr_t); | ||
3663 | }else{ | ||
3664 | data = buff; | ||
3665 | orig_len = len = data_len; | ||
3666 | } | ||
3667 | |||
3668 | if (tx_intr){ | ||
3669 | /* We are in tx_intr, minus the tx_offset from | ||
3670 | * the total length. The tx_offset part of the | ||
3671 | * data has already been sent. Also, move the | ||
3672 | * data pointer to proper offset location. | ||
3673 | */ | ||
3674 | len -= chan->tx_offset; | ||
3675 | data = (unsigned char*)data + chan->tx_offset; | ||
3676 | } | ||
3677 | |||
3678 | /* Check if the packet length is greater than MTU | ||
3679 | * If YES: Cut the len to MTU and set the M bit | ||
3680 | */ | ||
3681 | if (len > chan->tx_pkt_size && !card->u.x.LAPB_hdlc){ | ||
3682 | len = chan->tx_pkt_size; | ||
3683 | qdm |= M_BIT; | ||
3684 | } | ||
3685 | |||
3686 | |||
3687 | /* Pass only first three bits of the qdm byte to the send | ||
3688 | * routine. In case user sets any other bit which might | ||
3689 | * cause errors. | ||
3690 | */ | ||
3691 | |||
3692 | switch(x25_send(card, chan->common.lcn, (qdm&0x07), len, data)){ | ||
3693 | case 0x00: /* success */ | ||
3694 | chan->i_timeout_sofar = jiffies; | ||
3695 | |||
3696 | dev->trans_start=jiffies; | ||
3697 | |||
3698 | if ((qdm & M_BIT) && !card->u.x.LAPB_hdlc){ | ||
3699 | if (!tx_intr){ | ||
3700 | /* The M bit was set, which means that part of the | ||
3701 | * packet has been sent. Copy the packet into a buffer | ||
3702 | * and set the offset to len, so on next tx_inter | ||
3703 | * the packet will be sent using the below offset. | ||
3704 | */ | ||
3705 | chan->tx_offset += len; | ||
3706 | |||
3707 | ++chan->ifstats.tx_packets; | ||
3708 | chan->ifstats.tx_bytes += len; | ||
3709 | |||
3710 | if (chan->tx_offset < orig_len){ | ||
3711 | setup_for_delayed_transmit (dev, buff, data_len); | ||
3712 | } | ||
3713 | res=0; | ||
3714 | }else{ | ||
3715 | /* We are already in tx_inter, thus data is already | ||
3716 | * in the buffer. Update the offset and wait for | ||
3717 | * next tx_intr. We add on to the offset, since data can | ||
3718 | * be X number of times larger than max data size. | ||
3719 | */ | ||
3720 | ++chan->ifstats.tx_packets; | ||
3721 | chan->ifstats.tx_bytes += len; | ||
3722 | |||
3723 | ++chan->if_send_stat.if_send_bfr_passed_to_adptr; | ||
3724 | chan->tx_offset += len; | ||
3725 | |||
3726 | /* The user can set the qdm bit as well. | ||
3727 | * If the entire packet was sent and qdm is still | ||
3728 | * set, than it's the user who has set the M bit. In that, | ||
3729 | * case indicate that the packet was send by returning | ||
3730 | * 0 and wait for a new packet. Otherwise, wait for next | ||
3731 | * tx interrupt to send the rest of the packet */ | ||
3732 | |||
3733 | if (chan->tx_offset < orig_len){ | ||
3734 | res=1; | ||
3735 | }else{ | ||
3736 | res=0; | ||
3737 | } | ||
3738 | } | ||
3739 | }else{ | ||
3740 | ++chan->ifstats.tx_packets; | ||
3741 | chan->ifstats.tx_bytes += len; | ||
3742 | ++chan->if_send_stat.if_send_bfr_passed_to_adptr; | ||
3743 | res=0; | ||
3744 | } | ||
3745 | break; | ||
3746 | |||
3747 | case 0x33: /* Tx busy */ | ||
3748 | if (tx_intr){ | ||
3749 | printk(KERN_INFO "%s: Tx_intr: Big Error dropping packet %s\n", | ||
3750 | card->devname,dev->name); | ||
3751 | ++chan->ifstats.tx_dropped; | ||
3752 | ++card->wandev.stats.tx_dropped; | ||
3753 | ++chan->if_send_stat.if_send_bfr_not_passed_to_adptr; | ||
3754 | res=0; | ||
3755 | }else{ | ||
3756 | DBG_PRINTK(KERN_INFO | ||
3757 | "%s: Send: Big Error should have tx: storring %s\n", | ||
3758 | card->devname,dev->name); | ||
3759 | setup_for_delayed_transmit (dev, buff, data_len); | ||
3760 | res=1; | ||
3761 | } | ||
3762 | break; | ||
3763 | |||
3764 | default: /* failure */ | ||
3765 | ++chan->ifstats.tx_errors; | ||
3766 | if (tx_intr){ | ||
3767 | printk(KERN_INFO "%s: Tx_intr: Failure to send, dropping %s\n", | ||
3768 | card->devname,dev->name); | ||
3769 | ++chan->ifstats.tx_dropped; | ||
3770 | ++card->wandev.stats.tx_dropped; | ||
3771 | ++chan->if_send_stat.if_send_bfr_not_passed_to_adptr; | ||
3772 | res=0; | ||
3773 | }else{ | ||
3774 | DBG_PRINTK(KERN_INFO "%s: Send: Failure to send !!!, storing %s\n", | ||
3775 | card->devname,dev->name); | ||
3776 | setup_for_delayed_transmit (dev, buff, data_len); | ||
3777 | res=1; | ||
3778 | } | ||
3779 | break; | ||
3780 | } | ||
3781 | return res; | ||
3782 | } | ||
3783 | |||
3784 | |||
3785 | /* | ||
3786 | * Parse X.25 call request data and fill x25_call_info_t structure. | ||
3787 | */ | ||
3788 | |||
3789 | static void parse_call_info (unsigned char* str, x25_call_info_t* info) | ||
3790 | { | ||
3791 | memset(info, 0, sizeof(x25_call_info_t)); | ||
3792 | for (; *str; ++str) | ||
3793 | { | ||
3794 | int i; | ||
3795 | unsigned char ch; | ||
3796 | |||
3797 | if (*str == '-') switch (str[1]) { | ||
3798 | |||
3799 | /* Take minus 2 off the maximum size so that | ||
3800 | * last byte is 0. This way we can use string | ||
3801 | * manipulaton functions on call information. | ||
3802 | */ | ||
3803 | |||
3804 | case 'd': /* destination address */ | ||
3805 | for (i = 0; i < (MAX_X25_ADDR_SIZE-2); ++i){ | ||
3806 | ch = str[2+i]; | ||
3807 | if (isspace(ch)) break; | ||
3808 | info->dest[i] = ch; | ||
3809 | } | ||
3810 | break; | ||
3811 | |||
3812 | case 's': /* source address */ | ||
3813 | for (i = 0; i < (MAX_X25_ADDR_SIZE-2); ++i){ | ||
3814 | ch = str[2+i]; | ||
3815 | if (isspace(ch)) break; | ||
3816 | info->src[i] = ch; | ||
3817 | } | ||
3818 | break; | ||
3819 | |||
3820 | case 'u': /* user data */ | ||
3821 | for (i = 0; i < (MAX_X25_DATA_SIZE-2); ++i){ | ||
3822 | ch = str[2+i]; | ||
3823 | if (isspace(ch)) break; | ||
3824 | info->user[i] = ch; | ||
3825 | } | ||
3826 | info->nuser = i; | ||
3827 | break; | ||
3828 | |||
3829 | case 'f': /* facilities */ | ||
3830 | for (i = 0; i < (MAX_X25_FACL_SIZE-2); ++i){ | ||
3831 | ch = str[2+i]; | ||
3832 | if (isspace(ch)) break; | ||
3833 | info->facil[i] = ch; | ||
3834 | } | ||
3835 | info->nfacil = i; | ||
3836 | break; | ||
3837 | } | ||
3838 | } | ||
3839 | } | ||
3840 | |||
3841 | /* | ||
3842 | * Convert line speed in bps to a number used by S502 code. | ||
3843 | */ | ||
3844 | |||
3845 | static unsigned char bps_to_speed_code (unsigned long bps) | ||
3846 | { | ||
3847 | unsigned char number; | ||
3848 | |||
3849 | if (bps <= 1200) number = 0x01; | ||
3850 | else if (bps <= 2400) number = 0x02; | ||
3851 | else if (bps <= 4800) number = 0x03; | ||
3852 | else if (bps <= 9600) number = 0x04; | ||
3853 | else if (bps <= 19200) number = 0x05; | ||
3854 | else if (bps <= 38400) number = 0x06; | ||
3855 | else if (bps <= 45000) number = 0x07; | ||
3856 | else if (bps <= 56000) number = 0x08; | ||
3857 | else if (bps <= 64000) number = 0x09; | ||
3858 | else if (bps <= 74000) number = 0x0A; | ||
3859 | else if (bps <= 112000) number = 0x0B; | ||
3860 | else if (bps <= 128000) number = 0x0C; | ||
3861 | else number = 0x0D; | ||
3862 | |||
3863 | return number; | ||
3864 | } | ||
3865 | |||
3866 | /* | ||
3867 | * Convert decimal string to unsigned integer. | ||
3868 | * If len != 0 then only 'len' characters of the string are converted. | ||
3869 | */ | ||
3870 | |||
3871 | static unsigned int dec_to_uint (unsigned char* str, int len) | ||
3872 | { | ||
3873 | unsigned val; | ||
3874 | |||
3875 | if (!len) | ||
3876 | len = strlen(str); | ||
3877 | |||
3878 | for (val = 0; len && isdigit(*str); ++str, --len) | ||
3879 | val = (val * 10) + (*str - (unsigned)'0'); | ||
3880 | |||
3881 | return val; | ||
3882 | } | ||
3883 | |||
3884 | /* | ||
3885 | * Convert hex string to unsigned integer. | ||
3886 | * If len != 0 then only 'len' characters of the string are conferted. | ||
3887 | */ | ||
3888 | |||
3889 | static unsigned int hex_to_uint (unsigned char* str, int len) | ||
3890 | { | ||
3891 | unsigned val, ch; | ||
3892 | |||
3893 | if (!len) | ||
3894 | len = strlen(str); | ||
3895 | |||
3896 | for (val = 0; len; ++str, --len) | ||
3897 | { | ||
3898 | ch = *str; | ||
3899 | if (isdigit(ch)) | ||
3900 | val = (val << 4) + (ch - (unsigned)'0'); | ||
3901 | else if (isxdigit(ch)) | ||
3902 | val = (val << 4) + ((ch & 0xDF) - (unsigned)'A' + 10); | ||
3903 | else break; | ||
3904 | } | ||
3905 | return val; | ||
3906 | } | ||
3907 | |||
3908 | |||
3909 | static int handle_IPXWAN(unsigned char *sendpacket, char *devname, unsigned char enable_IPX, unsigned long network_number, unsigned short proto) | ||
3910 | { | ||
3911 | int i; | ||
3912 | |||
3913 | if( proto == ETH_P_IPX) { | ||
3914 | /* It's an IPX packet */ | ||
3915 | if(!enable_IPX) { | ||
3916 | /* Return 1 so we don't pass it up the stack. */ | ||
3917 | return 1; | ||
3918 | } | ||
3919 | } else { | ||
3920 | /* It's not IPX so pass it up the stack.*/ | ||
3921 | return 0; | ||
3922 | } | ||
3923 | |||
3924 | if( sendpacket[16] == 0x90 && | ||
3925 | sendpacket[17] == 0x04) | ||
3926 | { | ||
3927 | /* It's IPXWAN */ | ||
3928 | |||
3929 | if( sendpacket[2] == 0x02 && | ||
3930 | sendpacket[34] == 0x00) | ||
3931 | { | ||
3932 | /* It's a timer request packet */ | ||
3933 | printk(KERN_INFO "%s: Received IPXWAN Timer Request packet\n",devname); | ||
3934 | |||
3935 | /* Go through the routing options and answer no to every | ||
3936 | * option except Unnumbered RIP/SAP | ||
3937 | */ | ||
3938 | for(i = 41; sendpacket[i] == 0x00; i += 5) | ||
3939 | { | ||
3940 | /* 0x02 is the option for Unnumbered RIP/SAP */ | ||
3941 | if( sendpacket[i + 4] != 0x02) | ||
3942 | { | ||
3943 | sendpacket[i + 1] = 0; | ||
3944 | } | ||
3945 | } | ||
3946 | |||
3947 | /* Skip over the extended Node ID option */ | ||
3948 | if( sendpacket[i] == 0x04 ) | ||
3949 | { | ||
3950 | i += 8; | ||
3951 | } | ||
3952 | |||
3953 | /* We also want to turn off all header compression opt. */ | ||
3954 | for(; sendpacket[i] == 0x80 ;) | ||
3955 | { | ||
3956 | sendpacket[i + 1] = 0; | ||
3957 | i += (sendpacket[i + 2] << 8) + (sendpacket[i + 3]) + 4; | ||
3958 | } | ||
3959 | |||
3960 | /* Set the packet type to timer response */ | ||
3961 | sendpacket[34] = 0x01; | ||
3962 | |||
3963 | printk(KERN_INFO "%s: Sending IPXWAN Timer Response\n",devname); | ||
3964 | } | ||
3965 | else if( sendpacket[34] == 0x02 ) | ||
3966 | { | ||
3967 | /* This is an information request packet */ | ||
3968 | printk(KERN_INFO "%s: Received IPXWAN Information Request packet\n",devname); | ||
3969 | |||
3970 | /* Set the packet type to information response */ | ||
3971 | sendpacket[34] = 0x03; | ||
3972 | |||
3973 | /* Set the router name */ | ||
3974 | sendpacket[51] = 'X'; | ||
3975 | sendpacket[52] = 'T'; | ||
3976 | sendpacket[53] = 'P'; | ||
3977 | sendpacket[54] = 'I'; | ||
3978 | sendpacket[55] = 'P'; | ||
3979 | sendpacket[56] = 'E'; | ||
3980 | sendpacket[57] = '-'; | ||
3981 | sendpacket[58] = CVHexToAscii(network_number >> 28); | ||
3982 | sendpacket[59] = CVHexToAscii((network_number & 0x0F000000)>> 24); | ||
3983 | sendpacket[60] = CVHexToAscii((network_number & 0x00F00000)>> 20); | ||
3984 | sendpacket[61] = CVHexToAscii((network_number & 0x000F0000)>> 16); | ||
3985 | sendpacket[62] = CVHexToAscii((network_number & 0x0000F000)>> 12); | ||
3986 | sendpacket[63] = CVHexToAscii((network_number & 0x00000F00)>> 8); | ||
3987 | sendpacket[64] = CVHexToAscii((network_number & 0x000000F0)>> 4); | ||
3988 | sendpacket[65] = CVHexToAscii(network_number & 0x0000000F); | ||
3989 | for(i = 66; i < 99; i+= 1) | ||
3990 | { | ||
3991 | sendpacket[i] = 0; | ||
3992 | } | ||
3993 | |||
3994 | printk(KERN_INFO "%s: Sending IPXWAN Information Response packet\n",devname); | ||
3995 | } | ||
3996 | else | ||
3997 | { | ||
3998 | printk(KERN_INFO "%s: Unknown IPXWAN packet!\n",devname); | ||
3999 | return 0; | ||
4000 | } | ||
4001 | |||
4002 | /* Set the WNodeID to our network address */ | ||
4003 | sendpacket[35] = (unsigned char)(network_number >> 24); | ||
4004 | sendpacket[36] = (unsigned char)((network_number & 0x00FF0000) >> 16); | ||
4005 | sendpacket[37] = (unsigned char)((network_number & 0x0000FF00) >> 8); | ||
4006 | sendpacket[38] = (unsigned char)(network_number & 0x000000FF); | ||
4007 | |||
4008 | return 1; | ||
4009 | } else { | ||
4010 | /*If we get here it's an IPX-data packet, so it'll get passed up the stack. | ||
4011 | */ | ||
4012 | /* switch the network numbers */ | ||
4013 | switch_net_numbers(sendpacket, network_number, 1); | ||
4014 | return 0; | ||
4015 | } | ||
4016 | } | ||
4017 | |||
4018 | /* | ||
4019 | * If incoming is 0 (outgoing)- if the net numbers is ours make it 0 | ||
4020 | * if incoming is 1 - if the net number is 0 make it ours | ||
4021 | */ | ||
4022 | |||
4023 | static void switch_net_numbers(unsigned char *sendpacket, unsigned long network_number, unsigned char incoming) | ||
4024 | { | ||
4025 | unsigned long pnetwork_number; | ||
4026 | |||
4027 | pnetwork_number = (unsigned long)((sendpacket[6] << 24) + | ||
4028 | (sendpacket[7] << 16) + (sendpacket[8] << 8) + | ||
4029 | sendpacket[9]); | ||
4030 | |||
4031 | |||
4032 | if (!incoming) { | ||
4033 | /*If the destination network number is ours, make it 0 */ | ||
4034 | if( pnetwork_number == network_number) { | ||
4035 | sendpacket[6] = sendpacket[7] = sendpacket[8] = | ||
4036 | sendpacket[9] = 0x00; | ||
4037 | } | ||
4038 | } else { | ||
4039 | /* If the incoming network is 0, make it ours */ | ||
4040 | if( pnetwork_number == 0) { | ||
4041 | sendpacket[6] = (unsigned char)(network_number >> 24); | ||
4042 | sendpacket[7] = (unsigned char)((network_number & | ||
4043 | 0x00FF0000) >> 16); | ||
4044 | sendpacket[8] = (unsigned char)((network_number & | ||
4045 | 0x0000FF00) >> 8); | ||
4046 | sendpacket[9] = (unsigned char)(network_number & | ||
4047 | 0x000000FF); | ||
4048 | } | ||
4049 | } | ||
4050 | |||
4051 | |||
4052 | pnetwork_number = (unsigned long)((sendpacket[18] << 24) + | ||
4053 | (sendpacket[19] << 16) + (sendpacket[20] << 8) + | ||
4054 | sendpacket[21]); | ||
4055 | |||
4056 | |||
4057 | if( !incoming ) { | ||
4058 | /* If the source network is ours, make it 0 */ | ||
4059 | if( pnetwork_number == network_number) { | ||
4060 | sendpacket[18] = sendpacket[19] = sendpacket[20] = | ||
4061 | sendpacket[21] = 0x00; | ||
4062 | } | ||
4063 | } else { | ||
4064 | /* If the source network is 0, make it ours */ | ||
4065 | if( pnetwork_number == 0 ) { | ||
4066 | sendpacket[18] = (unsigned char)(network_number >> 24); | ||
4067 | sendpacket[19] = (unsigned char)((network_number & | ||
4068 | 0x00FF0000) >> 16); | ||
4069 | sendpacket[20] = (unsigned char)((network_number & | ||
4070 | 0x0000FF00) >> 8); | ||
4071 | sendpacket[21] = (unsigned char)(network_number & | ||
4072 | 0x000000FF); | ||
4073 | } | ||
4074 | } | ||
4075 | } /* switch_net_numbers */ | ||
4076 | |||
4077 | |||
4078 | |||
4079 | |||
4080 | /********************* X25API SPECIFIC FUNCTIONS ****************/ | ||
4081 | |||
4082 | |||
4083 | /*=============================================================== | ||
4084 | * find_channel | ||
4085 | * | ||
4086 | * Manages the lcn to device map. It increases performance | ||
4087 | * because it eliminates the need to search through the link | ||
4088 | * list for a device which is bounded to a specific lcn. | ||
4089 | * | ||
4090 | *===============================================================*/ | ||
4091 | |||
4092 | |||
4093 | struct net_device *find_channel(sdla_t *card, unsigned lcn) | ||
4094 | { | ||
4095 | if (card->u.x.LAPB_hdlc){ | ||
4096 | |||
4097 | return card->wandev.dev; | ||
4098 | |||
4099 | }else{ | ||
4100 | /* We don't know whether the incoming lcn | ||
4101 | * is a PVC or an SVC channel. But we do know that | ||
4102 | * the lcn cannot be for both the PVC and the SVC | ||
4103 | * channel. | ||
4104 | |||
4105 | * If the lcn number is greater or equal to 255, | ||
4106 | * take the modulo 255 of that number. We only have | ||
4107 | * 255 locations, thus higher numbers must be mapped | ||
4108 | * to a number between 0 and 245. | ||
4109 | |||
4110 | * We must separate pvc's and svc's since two don't | ||
4111 | * have to be contiguous. Meaning pvc's can start | ||
4112 | * from 1 to 10 and svc's can start from 256 to 266. | ||
4113 | * But 256%255 is 1, i.e. CONFLICT. | ||
4114 | */ | ||
4115 | |||
4116 | |||
4117 | /* Highest LCN number must be less or equal to 4096 */ | ||
4118 | if ((lcn <= MAX_LCN_NUM) && (lcn > 0)){ | ||
4119 | |||
4120 | if (lcn < X25_MAX_CHAN){ | ||
4121 | if (card->u.x.svc_to_dev_map[lcn]) | ||
4122 | return card->u.x.svc_to_dev_map[lcn]; | ||
4123 | |||
4124 | if (card->u.x.pvc_to_dev_map[lcn]) | ||
4125 | return card->u.x.pvc_to_dev_map[lcn]; | ||
4126 | |||
4127 | }else{ | ||
4128 | int new_lcn = lcn%X25_MAX_CHAN; | ||
4129 | if (card->u.x.svc_to_dev_map[new_lcn]) | ||
4130 | return card->u.x.svc_to_dev_map[new_lcn]; | ||
4131 | |||
4132 | if (card->u.x.pvc_to_dev_map[new_lcn]) | ||
4133 | return card->u.x.pvc_to_dev_map[new_lcn]; | ||
4134 | } | ||
4135 | } | ||
4136 | return NULL; | ||
4137 | } | ||
4138 | } | ||
4139 | |||
4140 | void bind_lcn_to_dev(sdla_t *card, struct net_device *dev, unsigned lcn) | ||
4141 | { | ||
4142 | x25_channel_t *chan = dev->priv; | ||
4143 | |||
4144 | /* Modulo the lcn number by X25_MAX_CHAN (255) | ||
4145 | * because the lcn number can be greater than 255 | ||
4146 | * | ||
4147 | * We need to split svc and pvc since they don't have | ||
4148 | * to be contigous. | ||
4149 | */ | ||
4150 | |||
4151 | if (chan->common.svc){ | ||
4152 | card->u.x.svc_to_dev_map[(lcn % X25_MAX_CHAN)] = dev; | ||
4153 | }else{ | ||
4154 | card->u.x.pvc_to_dev_map[(lcn % X25_MAX_CHAN)] = dev; | ||
4155 | } | ||
4156 | chan->common.lcn = lcn; | ||
4157 | } | ||
4158 | |||
4159 | |||
4160 | |||
4161 | /*=============================================================== | ||
4162 | * x25api_bh | ||
4163 | * | ||
4164 | * | ||
4165 | *==============================================================*/ | ||
4166 | |||
4167 | static void x25api_bh(struct net_device* dev) | ||
4168 | { | ||
4169 | x25_channel_t* chan = dev->priv; | ||
4170 | sdla_t* card = chan->card; | ||
4171 | struct sk_buff *skb; | ||
4172 | |||
4173 | if (atomic_read(&chan->bh_buff_used) == 0){ | ||
4174 | printk(KERN_INFO "%s: BH Buffer Empty in BH\n", | ||
4175 | card->devname); | ||
4176 | clear_bit(0, &chan->tq_working); | ||
4177 | return; | ||
4178 | } | ||
4179 | |||
4180 | while (atomic_read(&chan->bh_buff_used)){ | ||
4181 | |||
4182 | /* If the sock is in the process of unlinking the | ||
4183 | * driver from the socket, we must get out. | ||
4184 | * This never happends but is a sanity check. */ | ||
4185 | if (test_bit(0,&chan->common.common_critical)){ | ||
4186 | clear_bit(0, &chan->tq_working); | ||
4187 | return; | ||
4188 | } | ||
4189 | |||
4190 | /* If LAPB HDLC, do not drop packets if socket is | ||
4191 | * not connected. Let the buffer fill up and | ||
4192 | * turn off rx interrupt */ | ||
4193 | if (card->u.x.LAPB_hdlc){ | ||
4194 | if (chan->common.sk == NULL || chan->common.func == NULL){ | ||
4195 | clear_bit(0, &chan->tq_working); | ||
4196 | return; | ||
4197 | } | ||
4198 | } | ||
4199 | |||
4200 | skb = ((bh_data_t *)&chan->bh_head[chan->bh_read])->skb; | ||
4201 | |||
4202 | if (skb == NULL){ | ||
4203 | printk(KERN_INFO "%s: BH Skb empty for read %i\n", | ||
4204 | card->devname,chan->bh_read); | ||
4205 | }else{ | ||
4206 | |||
4207 | if (chan->common.sk == NULL || chan->common.func == NULL){ | ||
4208 | printk(KERN_INFO "%s: BH: Socket disconnected, dropping\n", | ||
4209 | card->devname); | ||
4210 | dev_kfree_skb_any(skb); | ||
4211 | x25api_bh_cleanup(dev); | ||
4212 | ++chan->ifstats.rx_dropped; | ||
4213 | ++chan->rx_intr_stat.rx_intr_bfr_not_passed_to_stack; | ||
4214 | continue; | ||
4215 | } | ||
4216 | |||
4217 | |||
4218 | if (chan->common.func(skb,dev,chan->common.sk) != 0){ | ||
4219 | /* Sock full cannot send, queue us for another | ||
4220 | * try | ||
4221 | */ | ||
4222 | printk(KERN_INFO "%s: BH: !!! Packet failed to send !!!!! \n", | ||
4223 | card->devname); | ||
4224 | atomic_set(&chan->common.receive_block,1); | ||
4225 | return; | ||
4226 | }else{ | ||
4227 | x25api_bh_cleanup(dev); | ||
4228 | ++chan->rx_intr_stat.rx_intr_bfr_passed_to_stack; | ||
4229 | } | ||
4230 | } | ||
4231 | } | ||
4232 | clear_bit(0, &chan->tq_working); | ||
4233 | |||
4234 | return; | ||
4235 | } | ||
4236 | |||
4237 | /*=============================================================== | ||
4238 | * x25api_bh_cleanup | ||
4239 | * | ||
4240 | * | ||
4241 | *==============================================================*/ | ||
4242 | |||
4243 | static int x25api_bh_cleanup(struct net_device *dev) | ||
4244 | { | ||
4245 | x25_channel_t* chan = dev->priv; | ||
4246 | sdla_t *card = chan->card; | ||
4247 | TX25Status* status = card->flags; | ||
4248 | |||
4249 | |||
4250 | ((bh_data_t *)&chan->bh_head[chan->bh_read])->skb = NULL; | ||
4251 | |||
4252 | if (chan->bh_read == MAX_BH_BUFF){ | ||
4253 | chan->bh_read=0; | ||
4254 | }else{ | ||
4255 | ++chan->bh_read; | ||
4256 | } | ||
4257 | |||
4258 | /* If the Receive interrupt was off, it means | ||
4259 | * that we filled up our circular buffer. Check | ||
4260 | * that we have space in the buffer. If so | ||
4261 | * turn the RX interrupt back on. | ||
4262 | */ | ||
4263 | if (!(status->imask & INTR_ON_RX_FRAME)){ | ||
4264 | if (atomic_read(&chan->bh_buff_used) < (MAX_BH_BUFF+1)){ | ||
4265 | printk(KERN_INFO "%s: BH: Turning on the interrupt\n", | ||
4266 | card->devname); | ||
4267 | status->imask |= INTR_ON_RX_FRAME; | ||
4268 | } | ||
4269 | } | ||
4270 | |||
4271 | atomic_dec(&chan->bh_buff_used); | ||
4272 | return 0; | ||
4273 | } | ||
4274 | |||
4275 | |||
4276 | /*=============================================================== | ||
4277 | * bh_enqueue | ||
4278 | * | ||
4279 | * | ||
4280 | *==============================================================*/ | ||
4281 | |||
4282 | static int bh_enqueue(struct net_device *dev, struct sk_buff *skb) | ||
4283 | { | ||
4284 | x25_channel_t* chan = dev->priv; | ||
4285 | sdla_t *card = chan->card; | ||
4286 | TX25Status* status = card->flags; | ||
4287 | |||
4288 | if (atomic_read(&chan->bh_buff_used) == (MAX_BH_BUFF+1)){ | ||
4289 | printk(KERN_INFO "%s: Bottom half buffer FULL\n", | ||
4290 | card->devname); | ||
4291 | return 1; | ||
4292 | } | ||
4293 | |||
4294 | ((bh_data_t *)&chan->bh_head[chan->bh_write])->skb = skb; | ||
4295 | |||
4296 | if (chan->bh_write == MAX_BH_BUFF){ | ||
4297 | chan->bh_write=0; | ||
4298 | }else{ | ||
4299 | ++chan->bh_write; | ||
4300 | } | ||
4301 | |||
4302 | atomic_inc(&chan->bh_buff_used); | ||
4303 | |||
4304 | if (atomic_read(&chan->bh_buff_used) == (MAX_BH_BUFF+1)){ | ||
4305 | printk(KERN_INFO "%s: Buffer is now full, Turning off RX Intr\n", | ||
4306 | card->devname); | ||
4307 | status->imask &= ~INTR_ON_RX_FRAME; | ||
4308 | } | ||
4309 | |||
4310 | return 0; | ||
4311 | } | ||
4312 | |||
4313 | |||
4314 | /*=============================================================== | ||
4315 | * timer_intr_cmd_exec | ||
4316 | * | ||
4317 | * Called by timer interrupt to execute a command | ||
4318 | *===============================================================*/ | ||
4319 | |||
4320 | static int timer_intr_cmd_exec (sdla_t* card) | ||
4321 | { | ||
4322 | struct net_device *dev; | ||
4323 | unsigned char more_to_exec=0; | ||
4324 | volatile x25_channel_t *chan=NULL; | ||
4325 | int i=0,bad_cmd=0,err=0; | ||
4326 | |||
4327 | if (card->u.x.cmd_dev == NULL){ | ||
4328 | card->u.x.cmd_dev = card->wandev.dev; | ||
4329 | } | ||
4330 | |||
4331 | dev = card->u.x.cmd_dev; | ||
4332 | |||
4333 | for (;;){ | ||
4334 | |||
4335 | chan = dev->priv; | ||
4336 | |||
4337 | if (atomic_read(&chan->common.command)){ | ||
4338 | |||
4339 | bad_cmd = check_bad_command(card,dev); | ||
4340 | |||
4341 | if ((!chan->common.mbox || atomic_read(&chan->common.disconnect)) && | ||
4342 | !bad_cmd){ | ||
4343 | |||
4344 | /* Socket has died or exited, We must bring the | ||
4345 | * channel down before anybody else tries to | ||
4346 | * use it */ | ||
4347 | err = channel_disconnect(card,dev); | ||
4348 | }else{ | ||
4349 | err = execute_delayed_cmd(card, dev, | ||
4350 | (mbox_cmd_t*)chan->common.mbox, | ||
4351 | bad_cmd); | ||
4352 | } | ||
4353 | |||
4354 | switch (err){ | ||
4355 | |||
4356 | case RETURN_RESULT: | ||
4357 | |||
4358 | /* Return the result to the socket without | ||
4359 | * delay. NO_WAIT Command */ | ||
4360 | atomic_set(&chan->common.command,0); | ||
4361 | if (atomic_read(&card->u.x.command_busy)) | ||
4362 | atomic_set(&card->u.x.command_busy,0); | ||
4363 | |||
4364 | send_delayed_cmd_result(card,dev,card->mbox); | ||
4365 | |||
4366 | more_to_exec=0; | ||
4367 | break; | ||
4368 | case DELAY_RESULT: | ||
4369 | |||
4370 | /* Wait for the remote to respond, before | ||
4371 | * sending the result up to the socket. | ||
4372 | * WAIT command */ | ||
4373 | if (atomic_read(&card->u.x.command_busy)) | ||
4374 | atomic_set(&card->u.x.command_busy,0); | ||
4375 | |||
4376 | atomic_set(&chan->common.command,0); | ||
4377 | more_to_exec=0; | ||
4378 | break; | ||
4379 | default: | ||
4380 | |||
4381 | /* If command could not be executed for | ||
4382 | * some reason (i.e return code 0x33 busy) | ||
4383 | * set the more_to_exec bit which will | ||
4384 | * indicate that this command must be exectued | ||
4385 | * again during next timer interrupt | ||
4386 | */ | ||
4387 | more_to_exec=1; | ||
4388 | if (atomic_read(&card->u.x.command_busy) == 0) | ||
4389 | atomic_set(&card->u.x.command_busy,1); | ||
4390 | break; | ||
4391 | } | ||
4392 | |||
4393 | bad_cmd=0; | ||
4394 | |||
4395 | /* If flags is set, there are no hdlc buffers, | ||
4396 | * thus, wait for the next pass and try the | ||
4397 | * same command again. Otherwise, start searching | ||
4398 | * from next device on the next pass. | ||
4399 | */ | ||
4400 | if (!more_to_exec){ | ||
4401 | dev = move_dev_to_next(card,dev); | ||
4402 | } | ||
4403 | break; | ||
4404 | }else{ | ||
4405 | /* This device has nothing to execute, | ||
4406 | * go to next. | ||
4407 | */ | ||
4408 | if (atomic_read(&card->u.x.command_busy)) | ||
4409 | atomic_set(&card->u.x.command_busy,0); | ||
4410 | dev = move_dev_to_next(card,dev); | ||
4411 | } | ||
4412 | |||
4413 | if (++i == card->u.x.no_dev){ | ||
4414 | if (!more_to_exec){ | ||
4415 | DBG_PRINTK(KERN_INFO "%s: Nothing to execute in Timer\n", | ||
4416 | card->devname); | ||
4417 | if (atomic_read(&card->u.x.command_busy)){ | ||
4418 | atomic_set(&card->u.x.command_busy,0); | ||
4419 | } | ||
4420 | } | ||
4421 | break; | ||
4422 | } | ||
4423 | |||
4424 | } //End of FOR | ||
4425 | |||
4426 | card->u.x.cmd_dev = dev; | ||
4427 | |||
4428 | if (more_to_exec){ | ||
4429 | /* If more commands are pending, do not turn off timer | ||
4430 | * interrupt */ | ||
4431 | return 1; | ||
4432 | }else{ | ||
4433 | /* No more commands, turn off timer interrupt */ | ||
4434 | return 0; | ||
4435 | } | ||
4436 | } | ||
4437 | |||
4438 | /*=============================================================== | ||
4439 | * execute_delayed_cmd | ||
4440 | * | ||
4441 | * Execute an API command which was passed down from the | ||
4442 | * sock. Sock is very limited in which commands it can | ||
4443 | * execute. Wait and No Wait commands are supported. | ||
4444 | * Place Call, Clear Call and Reset wait commands, where | ||
4445 | * Accept Call is a no_wait command. | ||
4446 | * | ||
4447 | *===============================================================*/ | ||
4448 | |||
4449 | static int execute_delayed_cmd(sdla_t* card, struct net_device *dev, | ||
4450 | mbox_cmd_t *usr_cmd, char bad_cmd) | ||
4451 | { | ||
4452 | TX25Mbox* mbox = card->mbox; | ||
4453 | int err; | ||
4454 | x25_channel_t *chan = dev->priv; | ||
4455 | int delay=RETURN_RESULT; | ||
4456 | |||
4457 | if (!(*card->u.x.hdlc_buf_status & 0x40) && !bad_cmd){ | ||
4458 | return TRY_CMD_AGAIN; | ||
4459 | } | ||
4460 | |||
4461 | /* This way a command is guaranteed to be executed for | ||
4462 | * a specific lcn, the network interface is bound to. */ | ||
4463 | usr_cmd->cmd.lcn = chan->common.lcn; | ||
4464 | |||
4465 | |||
4466 | /* If channel is pvc, instead of place call | ||
4467 | * run x25_channel configuration. If running LAPB HDLC | ||
4468 | * enable communications. | ||
4469 | */ | ||
4470 | if ((!chan->common.svc) && (usr_cmd->cmd.command == X25_PLACE_CALL)){ | ||
4471 | |||
4472 | if (card->u.x.LAPB_hdlc){ | ||
4473 | DBG_PRINTK(KERN_INFO "LAPB: Connecting\n"); | ||
4474 | connect(card); | ||
4475 | set_chan_state(dev,WAN_CONNECTING); | ||
4476 | return DELAY_RESULT; | ||
4477 | }else{ | ||
4478 | DBG_PRINTK(KERN_INFO "%s: PVC is CONNECTING\n",card->devname); | ||
4479 | if (x25_get_chan_conf(card, chan) == CMD_OK){ | ||
4480 | set_chan_state(dev, WAN_CONNECTED); | ||
4481 | }else{ | ||
4482 | set_chan_state(dev, WAN_DISCONNECTED); | ||
4483 | } | ||
4484 | return RETURN_RESULT; | ||
4485 | } | ||
4486 | } | ||
4487 | |||
4488 | /* Copy the socket mbox command onto the board */ | ||
4489 | |||
4490 | memcpy(&mbox->cmd, &usr_cmd->cmd, sizeof(TX25Cmd)); | ||
4491 | if (usr_cmd->cmd.length){ | ||
4492 | memcpy(mbox->data, usr_cmd->data, usr_cmd->cmd.length); | ||
4493 | } | ||
4494 | |||
4495 | /* Check if command is bad. We need to copy the cmd into | ||
4496 | * the buffer regardless since we return the, mbox to | ||
4497 | * the user */ | ||
4498 | if (bad_cmd){ | ||
4499 | mbox->cmd.result=0x01; | ||
4500 | return RETURN_RESULT; | ||
4501 | } | ||
4502 | |||
4503 | err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; | ||
4504 | |||
4505 | if (err != CMD_OK && err != X25RES_NOT_READY) | ||
4506 | x25_error(card, err, usr_cmd->cmd.command, usr_cmd->cmd.lcn); | ||
4507 | |||
4508 | if (mbox->cmd.result == X25RES_NOT_READY){ | ||
4509 | return TRY_CMD_AGAIN; | ||
4510 | } | ||
4511 | |||
4512 | switch (mbox->cmd.command){ | ||
4513 | |||
4514 | case X25_PLACE_CALL: | ||
4515 | |||
4516 | switch (mbox->cmd.result){ | ||
4517 | |||
4518 | case CMD_OK: | ||
4519 | |||
4520 | /* Check if Place call is a wait command or a | ||
4521 | * no wait command */ | ||
4522 | if (atomic_read(&chan->common.command) & 0x80) | ||
4523 | delay=RETURN_RESULT; | ||
4524 | else | ||
4525 | delay=DELAY_RESULT; | ||
4526 | |||
4527 | |||
4528 | DBG_PRINTK(KERN_INFO "\n%s: PLACE CALL Binding dev %s to lcn %i\n", | ||
4529 | card->devname,dev->name, mbox->cmd.lcn); | ||
4530 | |||
4531 | bind_lcn_to_dev (card, dev, mbox->cmd.lcn); | ||
4532 | set_chan_state(dev, WAN_CONNECTING); | ||
4533 | break; | ||
4534 | |||
4535 | |||
4536 | default: | ||
4537 | delay=RETURN_RESULT; | ||
4538 | set_chan_state(dev, WAN_DISCONNECTED); | ||
4539 | break; | ||
4540 | } | ||
4541 | break; | ||
4542 | |||
4543 | case X25_ACCEPT_CALL: | ||
4544 | |||
4545 | switch (mbox->cmd.result){ | ||
4546 | |||
4547 | case CMD_OK: | ||
4548 | |||
4549 | DBG_PRINTK(KERN_INFO "\n%s: ACCEPT Binding dev %s to lcn %i\n", | ||
4550 | card->devname,dev->name,mbox->cmd.lcn); | ||
4551 | |||
4552 | bind_lcn_to_dev (card, dev, mbox->cmd.lcn); | ||
4553 | |||
4554 | if (x25_get_chan_conf(card, chan) == CMD_OK){ | ||
4555 | |||
4556 | set_chan_state(dev, WAN_CONNECTED); | ||
4557 | delay=RETURN_RESULT; | ||
4558 | |||
4559 | }else{ | ||
4560 | if (x25_clear_call(card, usr_cmd->cmd.lcn, 0, 0) == CMD_OK){ | ||
4561 | /* if clear is successful, wait for clear confirm | ||
4562 | */ | ||
4563 | delay=DELAY_RESULT; | ||
4564 | }else{ | ||
4565 | /* Do not change the state here. If we fail | ||
4566 | * the accept the return code is send up | ||
4567 | *the stack, which will ether retry | ||
4568 | * or clear the call | ||
4569 | */ | ||
4570 | DBG_PRINTK(KERN_INFO | ||
4571 | "%s: ACCEPT: STATE MAY BE CURRUPTED 2 !!!!!\n", | ||
4572 | card->devname); | ||
4573 | delay=RETURN_RESULT; | ||
4574 | } | ||
4575 | } | ||
4576 | break; | ||
4577 | |||
4578 | |||
4579 | case X25RES_ASYNC_PACKET: | ||
4580 | delay=TRY_CMD_AGAIN; | ||
4581 | break; | ||
4582 | |||
4583 | default: | ||
4584 | DBG_PRINTK(KERN_INFO "%s: ACCEPT FAILED\n",card->devname); | ||
4585 | if (x25_clear_call(card, usr_cmd->cmd.lcn, 0, 0) == CMD_OK){ | ||
4586 | delay=DELAY_RESULT; | ||
4587 | }else{ | ||
4588 | /* Do not change the state here. If we fail the accept. The | ||
4589 | * return code is send up the stack, which will ether retry | ||
4590 | * or clear the call */ | ||
4591 | DBG_PRINTK(KERN_INFO | ||
4592 | "%s: ACCEPT: STATE MAY BE CORRUPTED 1 !!!!!\n", | ||
4593 | card->devname); | ||
4594 | delay=RETURN_RESULT; | ||
4595 | } | ||
4596 | } | ||
4597 | break; | ||
4598 | |||
4599 | case X25_CLEAR_CALL: | ||
4600 | |||
4601 | switch (mbox->cmd.result){ | ||
4602 | |||
4603 | case CMD_OK: | ||
4604 | DBG_PRINTK(KERN_INFO | ||
4605 | "CALL CLEAR OK: Dev %s Mbox Lcn %i Chan Lcn %i\n", | ||
4606 | dev->name,mbox->cmd.lcn,chan->common.lcn); | ||
4607 | set_chan_state(dev, WAN_DISCONNECTING); | ||
4608 | delay = DELAY_RESULT; | ||
4609 | break; | ||
4610 | |||
4611 | case X25RES_CHANNEL_IN_USE: | ||
4612 | case X25RES_ASYNC_PACKET: | ||
4613 | delay = TRY_CMD_AGAIN; | ||
4614 | break; | ||
4615 | |||
4616 | case X25RES_LINK_NOT_IN_ABM: | ||
4617 | case X25RES_INVAL_LCN: | ||
4618 | case X25RES_INVAL_STATE: | ||
4619 | set_chan_state(dev, WAN_DISCONNECTED); | ||
4620 | delay = RETURN_RESULT; | ||
4621 | break; | ||
4622 | |||
4623 | default: | ||
4624 | /* If command did not execute because of user | ||
4625 | * fault, do not change the state. This will | ||
4626 | * signal the socket that clear command failed. | ||
4627 | * User can retry or close the socket. | ||
4628 | * When socket gets killed, it will set the | ||
4629 | * chan->disconnect which will signal | ||
4630 | * driver to clear the call */ | ||
4631 | printk(KERN_INFO "%s: Clear Command Failed, Rc %x\n", | ||
4632 | card->devname,mbox->cmd.command); | ||
4633 | delay = RETURN_RESULT; | ||
4634 | } | ||
4635 | break; | ||
4636 | } | ||
4637 | |||
4638 | return delay; | ||
4639 | } | ||
4640 | |||
4641 | /*=============================================================== | ||
4642 | * api_incoming_call | ||
4643 | * | ||
4644 | * Pass an incoming call request up the listening | ||
4645 | * sock. If the API sock is not listening reject the | ||
4646 | * call. | ||
4647 | * | ||
4648 | *===============================================================*/ | ||
4649 | |||
4650 | static int api_incoming_call (sdla_t* card, TX25Mbox *mbox, int lcn) | ||
4651 | { | ||
4652 | struct sk_buff *skb; | ||
4653 | int len = sizeof(TX25Cmd)+mbox->cmd.length; | ||
4654 | |||
4655 | if (alloc_and_init_skb_buf(card, &skb, len)){ | ||
4656 | printk(KERN_INFO "%s: API incoming call, no memory\n",card->devname); | ||
4657 | return 1; | ||
4658 | } | ||
4659 | |||
4660 | memcpy(skb_put(skb,len),&mbox->cmd,len); | ||
4661 | |||
4662 | skb->mac.raw = skb->data; | ||
4663 | skb->protocol = htons(X25_PROT); | ||
4664 | skb->pkt_type = WAN_PACKET_ASYNC; | ||
4665 | |||
4666 | if (card->func(skb,card->sk) < 0){ | ||
4667 | printk(KERN_INFO "%s: MAJOR ERROR: Failed to send up place call \n",card->devname); | ||
4668 | dev_kfree_skb_any(skb); | ||
4669 | return 1; | ||
4670 | } | ||
4671 | |||
4672 | return 0; | ||
4673 | } | ||
4674 | |||
4675 | /*=============================================================== | ||
4676 | * send_delayed_cmd_result | ||
4677 | * | ||
4678 | * Wait commands like PLEACE CALL or CLEAR CALL must wait | ||
4679 | * until the result arrives. This function passes | ||
4680 | * the result to a waiting sock. | ||
4681 | * | ||
4682 | *===============================================================*/ | ||
4683 | static void send_delayed_cmd_result(sdla_t *card, struct net_device *dev, | ||
4684 | TX25Mbox* mbox) | ||
4685 | { | ||
4686 | x25_channel_t *chan = dev->priv; | ||
4687 | mbox_cmd_t *usr_cmd = (mbox_cmd_t *)chan->common.mbox; | ||
4688 | struct sk_buff *skb; | ||
4689 | int len=sizeof(unsigned char); | ||
4690 | |||
4691 | atomic_set(&chan->common.command,0); | ||
4692 | |||
4693 | /* If the sock is in the process of unlinking the | ||
4694 | * driver from the socket, we must get out. | ||
4695 | * This never happends but is a sanity check. */ | ||
4696 | if (test_bit(0,&chan->common.common_critical)){ | ||
4697 | return; | ||
4698 | } | ||
4699 | |||
4700 | if (!usr_cmd || !chan->common.sk || !chan->common.func){ | ||
4701 | DBG_PRINTK(KERN_INFO "Delay result: Sock not bounded sk: %u, func: %u, mbox: %u\n", | ||
4702 | (unsigned int)chan->common.sk, | ||
4703 | (unsigned int)chan->common.func, | ||
4704 | (unsigned int)usr_cmd); | ||
4705 | return; | ||
4706 | } | ||
4707 | |||
4708 | memcpy(&usr_cmd->cmd, &mbox->cmd, sizeof(TX25Cmd)); | ||
4709 | if (mbox->cmd.length > 0){ | ||
4710 | memcpy(usr_cmd->data, mbox->data, mbox->cmd.length); | ||
4711 | } | ||
4712 | |||
4713 | if (alloc_and_init_skb_buf(card,&skb,len)){ | ||
4714 | printk(KERN_INFO "Delay result: No sock buffers\n"); | ||
4715 | return; | ||
4716 | } | ||
4717 | |||
4718 | memcpy(skb_put(skb,len),&mbox->cmd.command,len); | ||
4719 | |||
4720 | skb->mac.raw = skb->data; | ||
4721 | skb->pkt_type = WAN_PACKET_CMD; | ||
4722 | |||
4723 | chan->common.func(skb,dev,chan->common.sk); | ||
4724 | } | ||
4725 | |||
4726 | /*=============================================================== | ||
4727 | * clear_confirm_event | ||
4728 | * | ||
4729 | * Pass the clear confirmation event up the sock. The | ||
4730 | * API will disconnect only after the clear confirmation | ||
4731 | * has been received. | ||
4732 | * | ||
4733 | * Depending on the state, clear confirmation could | ||
4734 | * be an OOB event, or a result of an API command. | ||
4735 | *===============================================================*/ | ||
4736 | |||
4737 | static int clear_confirm_event (sdla_t *card, TX25Mbox* mb) | ||
4738 | { | ||
4739 | struct net_device *dev; | ||
4740 | x25_channel_t *chan; | ||
4741 | unsigned char old_state; | ||
4742 | |||
4743 | dev = find_channel(card,mb->cmd.lcn); | ||
4744 | if (!dev){ | ||
4745 | DBG_PRINTK(KERN_INFO "%s: *** GOT CLEAR BUT NO DEV %i\n", | ||
4746 | card->devname,mb->cmd.lcn); | ||
4747 | return 0; | ||
4748 | } | ||
4749 | |||
4750 | chan=dev->priv; | ||
4751 | DBG_PRINTK(KERN_INFO "%s: GOT CLEAR CONFIRM %s: Mbox lcn %i Chan lcn %i\n", | ||
4752 | card->devname, dev->name, mb->cmd.lcn, chan->common.lcn); | ||
4753 | |||
4754 | /* If not API fall through to default. | ||
4755 | * If API, send the result to a waiting | ||
4756 | * socket. | ||
4757 | */ | ||
4758 | |||
4759 | old_state = chan->common.state; | ||
4760 | set_chan_state(dev, WAN_DISCONNECTED); | ||
4761 | |||
4762 | if (chan->common.usedby == API){ | ||
4763 | switch (old_state) { | ||
4764 | |||
4765 | case WAN_DISCONNECTING: | ||
4766 | case WAN_CONNECTING: | ||
4767 | send_delayed_cmd_result(card,dev,mb); | ||
4768 | break; | ||
4769 | case WAN_CONNECTED: | ||
4770 | send_oob_msg(card,dev,mb); | ||
4771 | break; | ||
4772 | } | ||
4773 | return 1; | ||
4774 | } | ||
4775 | |||
4776 | return 0; | ||
4777 | } | ||
4778 | |||
4779 | /*=============================================================== | ||
4780 | * send_oob_msg | ||
4781 | * | ||
4782 | * Construct an NEM Message and pass it up the connected | ||
4783 | * sock. If the sock is not bounded discard the NEM. | ||
4784 | * | ||
4785 | *===============================================================*/ | ||
4786 | |||
4787 | static void send_oob_msg(sdla_t *card, struct net_device *dev, TX25Mbox *mbox) | ||
4788 | { | ||
4789 | x25_channel_t *chan = dev->priv; | ||
4790 | mbox_cmd_t *usr_cmd = (mbox_cmd_t *)chan->common.mbox; | ||
4791 | struct sk_buff *skb; | ||
4792 | int len=sizeof(x25api_hdr_t)+mbox->cmd.length; | ||
4793 | x25api_t *api_hdr; | ||
4794 | |||
4795 | /* If the sock is in the process of unlinking the | ||
4796 | * driver from the socket, we must get out. | ||
4797 | * This never happends but is a sanity check. */ | ||
4798 | if (test_bit(0,&chan->common.common_critical)){ | ||
4799 | return; | ||
4800 | } | ||
4801 | |||
4802 | if (!usr_cmd || !chan->common.sk || !chan->common.func){ | ||
4803 | DBG_PRINTK(KERN_INFO "OOB MSG: Sock not bounded\n"); | ||
4804 | return; | ||
4805 | } | ||
4806 | |||
4807 | memcpy(&usr_cmd->cmd, &mbox->cmd, sizeof(TX25Cmd)); | ||
4808 | if (mbox->cmd.length > 0){ | ||
4809 | memcpy(usr_cmd->data, mbox->data, mbox->cmd.length); | ||
4810 | } | ||
4811 | |||
4812 | if (alloc_and_init_skb_buf(card,&skb,len)){ | ||
4813 | printk(KERN_INFO "%s: OOB MSG: No sock buffers\n",card->devname); | ||
4814 | return; | ||
4815 | } | ||
4816 | |||
4817 | api_hdr = (x25api_t*)skb_put(skb,len); | ||
4818 | api_hdr->hdr.pktType = mbox->cmd.pktType & 0x7F; | ||
4819 | api_hdr->hdr.qdm = mbox->cmd.qdm; | ||
4820 | api_hdr->hdr.cause = mbox->cmd.cause; | ||
4821 | api_hdr->hdr.diagn = mbox->cmd.diagn; | ||
4822 | api_hdr->hdr.length = mbox->cmd.length; | ||
4823 | api_hdr->hdr.result = mbox->cmd.result; | ||
4824 | api_hdr->hdr.lcn = mbox->cmd.lcn; | ||
4825 | |||
4826 | if (mbox->cmd.length > 0){ | ||
4827 | memcpy(api_hdr->data,mbox->data,mbox->cmd.length); | ||
4828 | } | ||
4829 | |||
4830 | skb->mac.raw = skb->data; | ||
4831 | skb->pkt_type = WAN_PACKET_ERR; | ||
4832 | |||
4833 | if (chan->common.func(skb,dev,chan->common.sk) < 0){ | ||
4834 | if (bh_enqueue(dev,skb)){ | ||
4835 | printk(KERN_INFO "%s: Dropping OOB MSG\n",card->devname); | ||
4836 | dev_kfree_skb_any(skb); | ||
4837 | } | ||
4838 | } | ||
4839 | |||
4840 | DBG_PRINTK(KERN_INFO "%s: OOB MSG OK, %s, lcn %i\n", | ||
4841 | card->devname, dev->name, mbox->cmd.lcn); | ||
4842 | } | ||
4843 | |||
4844 | /*=============================================================== | ||
4845 | * alloc_and_init_skb_buf | ||
4846 | * | ||
4847 | * Allocate and initialize an skb buffer. | ||
4848 | * | ||
4849 | *===============================================================*/ | ||
4850 | |||
4851 | static int alloc_and_init_skb_buf (sdla_t *card, struct sk_buff **skb, int len) | ||
4852 | { | ||
4853 | struct sk_buff *new_skb = *skb; | ||
4854 | |||
4855 | new_skb = dev_alloc_skb(len + X25_HRDHDR_SZ); | ||
4856 | if (new_skb == NULL){ | ||
4857 | printk(KERN_INFO "%s: no socket buffers available!\n", | ||
4858 | card->devname); | ||
4859 | return 1; | ||
4860 | } | ||
4861 | |||
4862 | if (skb_tailroom(new_skb) < len){ | ||
4863 | /* No room for the packet. Call off the whole thing! */ | ||
4864 | dev_kfree_skb_any(new_skb); | ||
4865 | printk(KERN_INFO "%s: Listen: unexpectedly long packet sequence\n" | ||
4866 | ,card->devname); | ||
4867 | *skb = NULL; | ||
4868 | return 1; | ||
4869 | } | ||
4870 | |||
4871 | *skb = new_skb; | ||
4872 | return 0; | ||
4873 | |||
4874 | } | ||
4875 | |||
4876 | /*=============================================================== | ||
4877 | * api_oob_event | ||
4878 | * | ||
4879 | * Send an OOB event up to the sock | ||
4880 | * | ||
4881 | *===============================================================*/ | ||
4882 | |||
4883 | static void api_oob_event (sdla_t *card,TX25Mbox *mbox) | ||
4884 | { | ||
4885 | struct net_device *dev = find_channel(card, mbox->cmd.lcn); | ||
4886 | x25_channel_t *chan; | ||
4887 | |||
4888 | if (!dev) | ||
4889 | return; | ||
4890 | |||
4891 | chan=dev->priv; | ||
4892 | |||
4893 | if (chan->common.usedby == API) | ||
4894 | send_oob_msg(card,dev,mbox); | ||
4895 | |||
4896 | } | ||
4897 | |||
4898 | |||
4899 | |||
4900 | |||
4901 | static int channel_disconnect(sdla_t* card, struct net_device *dev) | ||
4902 | { | ||
4903 | |||
4904 | int err; | ||
4905 | x25_channel_t *chan = dev->priv; | ||
4906 | |||
4907 | DBG_PRINTK(KERN_INFO "%s: TIMER: %s, Device down disconnecting\n", | ||
4908 | card->devname,dev->name); | ||
4909 | |||
4910 | if (chan->common.svc){ | ||
4911 | err = x25_clear_call(card,chan->common.lcn,0,0); | ||
4912 | }else{ | ||
4913 | /* If channel is PVC or LAPB HDLC, there is no call | ||
4914 | * to be cleared, thus drop down to the default | ||
4915 | * area | ||
4916 | */ | ||
4917 | err = 1; | ||
4918 | } | ||
4919 | |||
4920 | switch (err){ | ||
4921 | |||
4922 | case X25RES_CHANNEL_IN_USE: | ||
4923 | case X25RES_NOT_READY: | ||
4924 | err = TRY_CMD_AGAIN; | ||
4925 | break; | ||
4926 | case CMD_OK: | ||
4927 | DBG_PRINTK(KERN_INFO "CALL CLEAR OK: Dev %s Chan Lcn %i\n", | ||
4928 | dev->name,chan->common.lcn); | ||
4929 | |||
4930 | set_chan_state(dev,WAN_DISCONNECTING); | ||
4931 | atomic_set(&chan->common.command,0); | ||
4932 | err = DELAY_RESULT; | ||
4933 | break; | ||
4934 | default: | ||
4935 | /* If LAPB HDLC protocol, bring the whole link down | ||
4936 | * once the application terminates | ||
4937 | */ | ||
4938 | |||
4939 | set_chan_state(dev,WAN_DISCONNECTED); | ||
4940 | |||
4941 | if (card->u.x.LAPB_hdlc){ | ||
4942 | DBG_PRINTK(KERN_INFO "LAPB: Disconnecting Link\n"); | ||
4943 | hdlc_link_down (card); | ||
4944 | } | ||
4945 | atomic_set(&chan->common.command,0); | ||
4946 | err = RETURN_RESULT; | ||
4947 | break; | ||
4948 | } | ||
4949 | |||
4950 | return err; | ||
4951 | } | ||
4952 | |||
4953 | static void hdlc_link_down (sdla_t *card) | ||
4954 | { | ||
4955 | TX25Mbox* mbox = card->mbox; | ||
4956 | int retry = 5; | ||
4957 | int err=0; | ||
4958 | |||
4959 | do { | ||
4960 | memset(mbox,0,sizeof(TX25Mbox)); | ||
4961 | mbox->cmd.command = X25_HDLC_LINK_DISC; | ||
4962 | mbox->cmd.length = 1; | ||
4963 | mbox->data[0]=0; | ||
4964 | err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; | ||
4965 | |||
4966 | } while (err && retry-- && x25_error(card, err, X25_HDLC_LINK_DISC, 0)); | ||
4967 | |||
4968 | if (err) | ||
4969 | printk(KERN_INFO "%s: Hdlc Link Down Failed %x\n",card->devname,err); | ||
4970 | |||
4971 | disconnect (card); | ||
4972 | |||
4973 | } | ||
4974 | |||
4975 | static int check_bad_command(sdla_t* card, struct net_device *dev) | ||
4976 | { | ||
4977 | x25_channel_t *chan = dev->priv; | ||
4978 | int bad_cmd = 0; | ||
4979 | |||
4980 | switch (atomic_read(&chan->common.command)&0x7F){ | ||
4981 | |||
4982 | case X25_PLACE_CALL: | ||
4983 | if (chan->common.state != WAN_DISCONNECTED) | ||
4984 | bad_cmd=1; | ||
4985 | break; | ||
4986 | case X25_CLEAR_CALL: | ||
4987 | if (chan->common.state == WAN_DISCONNECTED) | ||
4988 | bad_cmd=1; | ||
4989 | break; | ||
4990 | case X25_ACCEPT_CALL: | ||
4991 | if (chan->common.state != WAN_CONNECTING) | ||
4992 | bad_cmd=1; | ||
4993 | break; | ||
4994 | case X25_RESET: | ||
4995 | if (chan->common.state != WAN_CONNECTED) | ||
4996 | bad_cmd=1; | ||
4997 | break; | ||
4998 | default: | ||
4999 | bad_cmd=1; | ||
5000 | break; | ||
5001 | } | ||
5002 | |||
5003 | if (bad_cmd){ | ||
5004 | printk(KERN_INFO "%s: Invalid State, BAD Command %x, dev %s, lcn %i, st %i\n", | ||
5005 | card->devname,atomic_read(&chan->common.command),dev->name, | ||
5006 | chan->common.lcn, chan->common.state); | ||
5007 | } | ||
5008 | |||
5009 | return bad_cmd; | ||
5010 | } | ||
5011 | |||
5012 | |||
5013 | |||
5014 | /*************************** XPIPEMON FUNCTIONS **************************/ | ||
5015 | |||
5016 | /*============================================================================== | ||
5017 | * Process UDP call of type XPIPE | ||
5018 | */ | ||
5019 | |||
5020 | static int process_udp_mgmt_pkt(sdla_t *card) | ||
5021 | { | ||
5022 | int c_retry = MAX_CMD_RETRY; | ||
5023 | unsigned int len; | ||
5024 | struct sk_buff *new_skb; | ||
5025 | TX25Mbox *mbox = card->mbox; | ||
5026 | int err; | ||
5027 | int udp_mgmt_req_valid = 1; | ||
5028 | struct net_device *dev; | ||
5029 | x25_channel_t *chan; | ||
5030 | unsigned short lcn; | ||
5031 | struct timeval tv; | ||
5032 | |||
5033 | |||
5034 | x25_udp_pkt_t *x25_udp_pkt; | ||
5035 | x25_udp_pkt = (x25_udp_pkt_t *)card->u.x.udp_pkt_data; | ||
5036 | |||
5037 | dev = card->u.x.udp_dev; | ||
5038 | chan = dev->priv; | ||
5039 | lcn = chan->common.lcn; | ||
5040 | |||
5041 | switch(x25_udp_pkt->cblock.command) { | ||
5042 | |||
5043 | /* XPIPE_ENABLE_TRACE */ | ||
5044 | case XPIPE_ENABLE_TRACING: | ||
5045 | |||
5046 | /* XPIPE_GET_TRACE_INFO */ | ||
5047 | case XPIPE_GET_TRACE_INFO: | ||
5048 | |||
5049 | /* SET FT1 MODE */ | ||
5050 | case XPIPE_SET_FT1_MODE: | ||
5051 | |||
5052 | if(card->u.x.udp_pkt_src == UDP_PKT_FRM_NETWORK) { | ||
5053 | ++chan->pipe_mgmt_stat.UDP_PIPE_mgmt_direction_err; | ||
5054 | udp_mgmt_req_valid = 0; | ||
5055 | break; | ||
5056 | } | ||
5057 | |||
5058 | /* XPIPE_FT1_READ_STATUS */ | ||
5059 | case XPIPE_FT1_READ_STATUS: | ||
5060 | |||
5061 | /* FT1 MONITOR STATUS */ | ||
5062 | case XPIPE_FT1_STATUS_CTRL: | ||
5063 | if(card->hw.fwid != SFID_X25_508) { | ||
5064 | ++chan->pipe_mgmt_stat.UDP_PIPE_mgmt_adptr_type_err; | ||
5065 | udp_mgmt_req_valid = 0; | ||
5066 | break; | ||
5067 | } | ||
5068 | default: | ||
5069 | break; | ||
5070 | } | ||
5071 | |||
5072 | if(!udp_mgmt_req_valid) { | ||
5073 | /* set length to 0 */ | ||
5074 | x25_udp_pkt->cblock.length = 0; | ||
5075 | /* set return code */ | ||
5076 | x25_udp_pkt->cblock.result = (card->hw.fwid != SFID_X25_508) ? 0x1F : 0xCD; | ||
5077 | |||
5078 | } else { | ||
5079 | |||
5080 | switch (x25_udp_pkt->cblock.command) { | ||
5081 | |||
5082 | |||
5083 | case XPIPE_FLUSH_DRIVER_STATS: | ||
5084 | init_x25_channel_struct(chan); | ||
5085 | init_global_statistics(card); | ||
5086 | mbox->cmd.length = 0; | ||
5087 | break; | ||
5088 | |||
5089 | |||
5090 | case XPIPE_DRIVER_STAT_IFSEND: | ||
5091 | memcpy(x25_udp_pkt->data, &chan->if_send_stat, sizeof(if_send_stat_t)); | ||
5092 | mbox->cmd.length = sizeof(if_send_stat_t); | ||
5093 | x25_udp_pkt->cblock.length = mbox->cmd.length; | ||
5094 | break; | ||
5095 | |||
5096 | case XPIPE_DRIVER_STAT_INTR: | ||
5097 | memcpy(&x25_udp_pkt->data[0], &card->statistics, sizeof(global_stats_t)); | ||
5098 | memcpy(&x25_udp_pkt->data[sizeof(global_stats_t)], | ||
5099 | &chan->rx_intr_stat, sizeof(rx_intr_stat_t)); | ||
5100 | |||
5101 | mbox->cmd.length = sizeof(global_stats_t) + | ||
5102 | sizeof(rx_intr_stat_t); | ||
5103 | x25_udp_pkt->cblock.length = mbox->cmd.length; | ||
5104 | break; | ||
5105 | |||
5106 | case XPIPE_DRIVER_STAT_GEN: | ||
5107 | memcpy(x25_udp_pkt->data, | ||
5108 | &chan->pipe_mgmt_stat.UDP_PIPE_mgmt_kmalloc_err, | ||
5109 | sizeof(pipe_mgmt_stat_t)); | ||
5110 | |||
5111 | memcpy(&x25_udp_pkt->data[sizeof(pipe_mgmt_stat_t)], | ||
5112 | &card->statistics, sizeof(global_stats_t)); | ||
5113 | |||
5114 | x25_udp_pkt->cblock.result = 0; | ||
5115 | x25_udp_pkt->cblock.length = sizeof(global_stats_t)+ | ||
5116 | sizeof(rx_intr_stat_t); | ||
5117 | mbox->cmd.length = x25_udp_pkt->cblock.length; | ||
5118 | break; | ||
5119 | |||
5120 | case XPIPE_ROUTER_UP_TIME: | ||
5121 | do_gettimeofday(&tv); | ||
5122 | chan->router_up_time = tv.tv_sec - chan->router_start_time; | ||
5123 | *(unsigned long *)&x25_udp_pkt->data = chan->router_up_time; | ||
5124 | x25_udp_pkt->cblock.length = mbox->cmd.length = 4; | ||
5125 | x25_udp_pkt->cblock.result = 0; | ||
5126 | break; | ||
5127 | |||
5128 | default : | ||
5129 | |||
5130 | do { | ||
5131 | memcpy(&mbox->cmd, &x25_udp_pkt->cblock.command, sizeof(TX25Cmd)); | ||
5132 | if(mbox->cmd.length){ | ||
5133 | memcpy(&mbox->data, | ||
5134 | (char *)x25_udp_pkt->data, | ||
5135 | mbox->cmd.length); | ||
5136 | } | ||
5137 | |||
5138 | err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; | ||
5139 | } while (err && c_retry-- && x25_error(card, err, mbox->cmd.command, 0)); | ||
5140 | |||
5141 | |||
5142 | if ( err == CMD_OK || | ||
5143 | (err == 1 && | ||
5144 | (mbox->cmd.command == 0x06 || | ||
5145 | mbox->cmd.command == 0x16) ) ){ | ||
5146 | |||
5147 | ++chan->pipe_mgmt_stat.UDP_PIPE_mgmt_adptr_cmnd_OK; | ||
5148 | } else { | ||
5149 | ++chan->pipe_mgmt_stat.UDP_PIPE_mgmt_adptr_cmnd_timeout; | ||
5150 | } | ||
5151 | |||
5152 | /* copy the result back to our buffer */ | ||
5153 | memcpy(&x25_udp_pkt->cblock.command, &mbox->cmd, sizeof(TX25Cmd)); | ||
5154 | |||
5155 | if(mbox->cmd.length) { | ||
5156 | memcpy(&x25_udp_pkt->data, &mbox->data, mbox->cmd.length); | ||
5157 | } | ||
5158 | break; | ||
5159 | |||
5160 | } //switch | ||
5161 | |||
5162 | } | ||
5163 | |||
5164 | /* Fill UDP TTL */ | ||
5165 | |||
5166 | x25_udp_pkt->ip_pkt.ttl = card->wandev.ttl; | ||
5167 | len = reply_udp(card->u.x.udp_pkt_data, mbox->cmd.length); | ||
5168 | |||
5169 | |||
5170 | if(card->u.x.udp_pkt_src == UDP_PKT_FRM_NETWORK) { | ||
5171 | |||
5172 | err = x25_send(card, lcn, 0, len, card->u.x.udp_pkt_data); | ||
5173 | if (!err) | ||
5174 | ++chan->pipe_mgmt_stat.UDP_PIPE_mgmt_adptr_send_passed; | ||
5175 | else | ||
5176 | ++chan->pipe_mgmt_stat.UDP_PIPE_mgmt_adptr_send_failed; | ||
5177 | |||
5178 | } else { | ||
5179 | |||
5180 | /* Allocate socket buffer */ | ||
5181 | if((new_skb = dev_alloc_skb(len)) != NULL) { | ||
5182 | void *buf; | ||
5183 | |||
5184 | /* copy data into new_skb */ | ||
5185 | buf = skb_put(new_skb, len); | ||
5186 | memcpy(buf, card->u.x.udp_pkt_data, len); | ||
5187 | |||
5188 | /* Decapsulate packet and pass it up the protocol | ||
5189 | stack */ | ||
5190 | new_skb->dev = dev; | ||
5191 | |||
5192 | if (chan->common.usedby == API) | ||
5193 | new_skb->protocol = htons(X25_PROT); | ||
5194 | else | ||
5195 | new_skb->protocol = htons(ETH_P_IP); | ||
5196 | |||
5197 | new_skb->mac.raw = new_skb->data; | ||
5198 | |||
5199 | netif_rx(new_skb); | ||
5200 | ++chan->pipe_mgmt_stat.UDP_PIPE_mgmt_passed_to_stack; | ||
5201 | |||
5202 | } else { | ||
5203 | ++chan->pipe_mgmt_stat.UDP_PIPE_mgmt_no_socket; | ||
5204 | printk(KERN_INFO | ||
5205 | "%s: UDP mgmt cmnd, no socket buffers available!\n", | ||
5206 | card->devname); | ||
5207 | } | ||
5208 | } | ||
5209 | |||
5210 | card->u.x.udp_pkt_lgth = 0; | ||
5211 | |||
5212 | return 1; | ||
5213 | } | ||
5214 | |||
5215 | |||
5216 | /*============================================================================== | ||
5217 | * Determine what type of UDP call it is. DRVSTATS or XPIPE8ND ? | ||
5218 | */ | ||
5219 | static int udp_pkt_type( struct sk_buff *skb, sdla_t* card ) | ||
5220 | { | ||
5221 | x25_udp_pkt_t *x25_udp_pkt = (x25_udp_pkt_t *)skb->data; | ||
5222 | |||
5223 | if((x25_udp_pkt->ip_pkt.protocol == UDPMGMT_UDP_PROTOCOL) && | ||
5224 | (x25_udp_pkt->ip_pkt.ver_inet_hdr_length == 0x45) && | ||
5225 | (x25_udp_pkt->udp_pkt.udp_dst_port == ntohs(card->wandev.udp_port)) && | ||
5226 | (x25_udp_pkt->wp_mgmt.request_reply == UDPMGMT_REQUEST)) { | ||
5227 | |||
5228 | if(!strncmp(x25_udp_pkt->wp_mgmt.signature, | ||
5229 | UDPMGMT_XPIPE_SIGNATURE, 8)){ | ||
5230 | return UDP_XPIPE_TYPE; | ||
5231 | }else{ | ||
5232 | printk(KERN_INFO "%s: UDP Packet, Failed Signature !\n", | ||
5233 | card->devname); | ||
5234 | } | ||
5235 | } | ||
5236 | |||
5237 | return UDP_INVALID_TYPE; | ||
5238 | } | ||
5239 | |||
5240 | |||
5241 | /*============================================================================ | ||
5242 | * Reply to UDP Management system. | ||
5243 | * Return nothing. | ||
5244 | */ | ||
5245 | static int reply_udp( unsigned char *data, unsigned int mbox_len ) | ||
5246 | { | ||
5247 | unsigned short len, udp_length, temp, ip_length; | ||
5248 | unsigned long ip_temp; | ||
5249 | int even_bound = 0; | ||
5250 | |||
5251 | |||
5252 | x25_udp_pkt_t *x25_udp_pkt = (x25_udp_pkt_t *)data; | ||
5253 | |||
5254 | /* Set length of packet */ | ||
5255 | len = sizeof(ip_pkt_t)+ | ||
5256 | sizeof(udp_pkt_t)+ | ||
5257 | sizeof(wp_mgmt_t)+ | ||
5258 | sizeof(cblock_t)+ | ||
5259 | mbox_len; | ||
5260 | |||
5261 | |||
5262 | /* fill in UDP reply */ | ||
5263 | x25_udp_pkt->wp_mgmt.request_reply = UDPMGMT_REPLY; | ||
5264 | |||
5265 | /* fill in UDP length */ | ||
5266 | udp_length = sizeof(udp_pkt_t)+ | ||
5267 | sizeof(wp_mgmt_t)+ | ||
5268 | sizeof(cblock_t)+ | ||
5269 | mbox_len; | ||
5270 | |||
5271 | |||
5272 | /* put it on an even boundary */ | ||
5273 | if ( udp_length & 0x0001 ) { | ||
5274 | udp_length += 1; | ||
5275 | len += 1; | ||
5276 | even_bound = 1; | ||
5277 | } | ||
5278 | |||
5279 | temp = (udp_length<<8)|(udp_length>>8); | ||
5280 | x25_udp_pkt->udp_pkt.udp_length = temp; | ||
5281 | |||
5282 | /* swap UDP ports */ | ||
5283 | temp = x25_udp_pkt->udp_pkt.udp_src_port; | ||
5284 | x25_udp_pkt->udp_pkt.udp_src_port = | ||
5285 | x25_udp_pkt->udp_pkt.udp_dst_port; | ||
5286 | x25_udp_pkt->udp_pkt.udp_dst_port = temp; | ||
5287 | |||
5288 | |||
5289 | |||
5290 | /* add UDP pseudo header */ | ||
5291 | temp = 0x1100; | ||
5292 | *((unsigned short *) | ||
5293 | (x25_udp_pkt->data+mbox_len+even_bound)) = temp; | ||
5294 | temp = (udp_length<<8)|(udp_length>>8); | ||
5295 | *((unsigned short *) | ||
5296 | (x25_udp_pkt->data+mbox_len+even_bound+2)) = temp; | ||
5297 | |||
5298 | /* calculate UDP checksum */ | ||
5299 | x25_udp_pkt->udp_pkt.udp_checksum = 0; | ||
5300 | |||
5301 | x25_udp_pkt->udp_pkt.udp_checksum = | ||
5302 | calc_checksum(&data[UDP_OFFSET], udp_length+UDP_OFFSET); | ||
5303 | |||
5304 | /* fill in IP length */ | ||
5305 | ip_length = len; | ||
5306 | temp = (ip_length<<8)|(ip_length>>8); | ||
5307 | x25_udp_pkt->ip_pkt.total_length = temp; | ||
5308 | |||
5309 | /* swap IP addresses */ | ||
5310 | ip_temp = x25_udp_pkt->ip_pkt.ip_src_address; | ||
5311 | x25_udp_pkt->ip_pkt.ip_src_address = | ||
5312 | x25_udp_pkt->ip_pkt.ip_dst_address; | ||
5313 | x25_udp_pkt->ip_pkt.ip_dst_address = ip_temp; | ||
5314 | |||
5315 | |||
5316 | /* fill in IP checksum */ | ||
5317 | x25_udp_pkt->ip_pkt.hdr_checksum = 0; | ||
5318 | x25_udp_pkt->ip_pkt.hdr_checksum = calc_checksum(data, sizeof(ip_pkt_t)); | ||
5319 | |||
5320 | return len; | ||
5321 | } /* reply_udp */ | ||
5322 | |||
5323 | unsigned short calc_checksum (char *data, int len) | ||
5324 | { | ||
5325 | unsigned short temp; | ||
5326 | unsigned long sum=0; | ||
5327 | int i; | ||
5328 | |||
5329 | for( i = 0; i <len; i+=2 ) { | ||
5330 | memcpy(&temp,&data[i],2); | ||
5331 | sum += (unsigned long)temp; | ||
5332 | } | ||
5333 | |||
5334 | while (sum >> 16 ) { | ||
5335 | sum = (sum & 0xffffUL) + (sum >> 16); | ||
5336 | } | ||
5337 | |||
5338 | temp = (unsigned short)sum; | ||
5339 | temp = ~temp; | ||
5340 | |||
5341 | if( temp == 0 ) | ||
5342 | temp = 0xffff; | ||
5343 | |||
5344 | return temp; | ||
5345 | } | ||
5346 | |||
5347 | /*============================================================================= | ||
5348 | * Store a UDP management packet for later processing. | ||
5349 | */ | ||
5350 | |||
5351 | static int store_udp_mgmt_pkt(int udp_type, char udp_pkt_src, sdla_t* card, | ||
5352 | struct net_device *dev, struct sk_buff *skb, | ||
5353 | int lcn) | ||
5354 | { | ||
5355 | int udp_pkt_stored = 0; | ||
5356 | |||
5357 | if(!card->u.x.udp_pkt_lgth && (skb->len <= MAX_LGTH_UDP_MGNT_PKT)){ | ||
5358 | card->u.x.udp_pkt_lgth = skb->len; | ||
5359 | card->u.x.udp_type = udp_type; | ||
5360 | card->u.x.udp_pkt_src = udp_pkt_src; | ||
5361 | card->u.x.udp_lcn = lcn; | ||
5362 | card->u.x.udp_dev = dev; | ||
5363 | memcpy(card->u.x.udp_pkt_data, skb->data, skb->len); | ||
5364 | card->u.x.timer_int_enabled |= TMR_INT_ENABLED_UDP_PKT; | ||
5365 | udp_pkt_stored = 1; | ||
5366 | |||
5367 | }else{ | ||
5368 | printk(KERN_INFO "%s: ERROR: UDP packet not stored for LCN %d\n", | ||
5369 | card->devname,lcn); | ||
5370 | } | ||
5371 | |||
5372 | if(udp_pkt_src == UDP_PKT_FRM_STACK){ | ||
5373 | dev_kfree_skb_any(skb); | ||
5374 | }else{ | ||
5375 | dev_kfree_skb_any(skb); | ||
5376 | } | ||
5377 | |||
5378 | return(udp_pkt_stored); | ||
5379 | } | ||
5380 | |||
5381 | |||
5382 | |||
5383 | /*============================================================================= | ||
5384 | * Initial the ppp_private_area structure. | ||
5385 | */ | ||
5386 | static void init_x25_channel_struct( x25_channel_t *chan ) | ||
5387 | { | ||
5388 | memset(&chan->if_send_stat.if_send_entry,0,sizeof(if_send_stat_t)); | ||
5389 | memset(&chan->rx_intr_stat.rx_intr_no_socket,0,sizeof(rx_intr_stat_t)); | ||
5390 | memset(&chan->pipe_mgmt_stat.UDP_PIPE_mgmt_kmalloc_err,0,sizeof(pipe_mgmt_stat_t)); | ||
5391 | } | ||
5392 | |||
5393 | /*============================================================================ | ||
5394 | * Initialize Global Statistics | ||
5395 | */ | ||
5396 | static void init_global_statistics( sdla_t *card ) | ||
5397 | { | ||
5398 | memset(&card->statistics.isr_entry,0,sizeof(global_stats_t)); | ||
5399 | } | ||
5400 | |||
5401 | |||
5402 | /*=============================================================== | ||
5403 | * SMP Support | ||
5404 | * ==============================================================*/ | ||
5405 | |||
5406 | static void S508_S514_lock(sdla_t *card, unsigned long *smp_flags) | ||
5407 | { | ||
5408 | spin_lock_irqsave(&card->wandev.lock, *smp_flags); | ||
5409 | } | ||
5410 | static void S508_S514_unlock(sdla_t *card, unsigned long *smp_flags) | ||
5411 | { | ||
5412 | spin_unlock_irqrestore(&card->wandev.lock, *smp_flags); | ||
5413 | } | ||
5414 | |||
5415 | /*=============================================================== | ||
5416 | * x25_timer_routine | ||
5417 | * | ||
5418 | * A more efficient polling routine. Each half a second | ||
5419 | * queue a polling task. We want to do the polling in a | ||
5420 | * task not timer, because timer runs in interrupt time. | ||
5421 | * | ||
5422 | * FIXME Polling should be rethinked. | ||
5423 | *==============================================================*/ | ||
5424 | |||
5425 | static void x25_timer_routine(unsigned long data) | ||
5426 | { | ||
5427 | sdla_t *card = (sdla_t*)data; | ||
5428 | |||
5429 | if (!card->wandev.dev){ | ||
5430 | printk(KERN_INFO "%s: Stopping the X25 Poll Timer: No Dev.\n", | ||
5431 | card->devname); | ||
5432 | return; | ||
5433 | } | ||
5434 | |||
5435 | if (card->open_cnt != card->u.x.num_of_ch){ | ||
5436 | printk(KERN_INFO "%s: Stopping the X25 Poll Timer: Interface down.\n", | ||
5437 | card->devname); | ||
5438 | return; | ||
5439 | } | ||
5440 | |||
5441 | if (test_bit(PERI_CRIT,&card->wandev.critical)){ | ||
5442 | printk(KERN_INFO "%s: Stopping the X25 Poll Timer: Shutting down.\n", | ||
5443 | card->devname); | ||
5444 | return; | ||
5445 | } | ||
5446 | |||
5447 | if (!test_and_set_bit(POLL_CRIT,&card->wandev.critical)){ | ||
5448 | trigger_x25_poll(card); | ||
5449 | } | ||
5450 | |||
5451 | card->u.x.x25_timer.expires=jiffies+(HZ>>1); | ||
5452 | add_timer(&card->u.x.x25_timer); | ||
5453 | return; | ||
5454 | } | ||
5455 | |||
5456 | void disable_comm_shutdown(sdla_t *card) | ||
5457 | { | ||
5458 | TX25Mbox* mbox = card->mbox; | ||
5459 | int err; | ||
5460 | |||
5461 | /* Turn of interrutps */ | ||
5462 | mbox->data[0] = 0; | ||
5463 | if (card->hw.fwid == SFID_X25_508){ | ||
5464 | mbox->data[1] = card->hw.irq; | ||
5465 | mbox->data[2] = 2; | ||
5466 | mbox->cmd.length = 3; | ||
5467 | }else { | ||
5468 | mbox->cmd.length = 1; | ||
5469 | } | ||
5470 | mbox->cmd.command = X25_SET_INTERRUPT_MODE; | ||
5471 | err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; | ||
5472 | if (err) | ||
5473 | printk(KERN_INFO "INTERRUPT OFF FAIED %x\n",err); | ||
5474 | |||
5475 | /* Bring down HDLC */ | ||
5476 | mbox->cmd.command = X25_HDLC_LINK_CLOSE; | ||
5477 | mbox->cmd.length = 0; | ||
5478 | err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; | ||
5479 | if (err) | ||
5480 | printk(KERN_INFO "LINK CLOSED FAILED %x\n",err); | ||
5481 | |||
5482 | |||
5483 | /* Brind down DTR */ | ||
5484 | mbox->data[0] = 0; | ||
5485 | mbox->data[2] = 0; | ||
5486 | mbox->data[1] = 0x01; | ||
5487 | mbox->cmd.length = 3; | ||
5488 | mbox->cmd.command = X25_SET_GLOBAL_VARS; | ||
5489 | err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; | ||
5490 | if (err) | ||
5491 | printk(KERN_INFO "DTR DOWN FAILED %x\n",err); | ||
5492 | |||
5493 | } | ||
5494 | |||
5495 | MODULE_LICENSE("GPL"); | ||
5496 | |||
5497 | /****** End *****************************************************************/ | ||
diff --git a/drivers/net/wan/sdladrv.c b/drivers/net/wan/sdladrv.c deleted file mode 100644 index 032c0f81928e..000000000000 --- a/drivers/net/wan/sdladrv.c +++ /dev/null | |||
@@ -1,2314 +0,0 @@ | |||
1 | /***************************************************************************** | ||
2 | * sdladrv.c SDLA Support Module. Main module. | ||
3 | * | ||
4 | * This module is a library of common hardware-specific functions | ||
5 | * used by all Sangoma drivers. | ||
6 | * | ||
7 | * Author: Gideon Hack | ||
8 | * | ||
9 | * Copyright: (c) 1995-2000 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 | * Mar 20, 2001 Nenad Corbic Added the auto_pci_cfg filed, to support | ||
17 | * the PCISLOT #0. | ||
18 | * Apr 04, 2000 Nenad Corbic Fixed the auto memory detection code. | ||
19 | * The memory test at address 0xC8000. | ||
20 | * Mar 09, 2000 Nenad Corbic Added Gideon's Bug Fix: clear pci | ||
21 | * interrupt flags on initial load. | ||
22 | * Jun 02, 1999 Gideon Hack Added support for the S514 adapter. | ||
23 | * Updates for Linux 2.2.X kernels. | ||
24 | * Sep 17, 1998 Jaspreet Singh Updates for linux 2.2.X kernels | ||
25 | * Dec 20, 1996 Gene Kozin Version 3.0.0. Complete overhaul. | ||
26 | * Jul 12, 1996 Gene Kozin Changes for Linux 2.0 compatibility. | ||
27 | * Jun 12, 1996 Gene Kozin Added support for S503 card. | ||
28 | * Apr 30, 1996 Gene Kozin SDLA hardware interrupt is acknowledged before | ||
29 | * calling protocolspecific ISR. | ||
30 | * Register I/O ports with Linux kernel. | ||
31 | * Miscellaneous bug fixes. | ||
32 | * Dec 20, 1995 Gene Kozin Fixed a bug in interrupt routine. | ||
33 | * Oct 14, 1995 Gene Kozin Initial version. | ||
34 | *****************************************************************************/ | ||
35 | |||
36 | /***************************************************************************** | ||
37 | * Notes: | ||
38 | * ------ | ||
39 | * 1. This code is ment to be system-independent (as much as possible). To | ||
40 | * achive this, various macros are used to hide system-specific interfaces. | ||
41 | * To compile this code, one of the following constants must be defined: | ||
42 | * | ||
43 | * Platform Define | ||
44 | * -------- ------ | ||
45 | * Linux _LINUX_ | ||
46 | * SCO Unix _SCO_UNIX_ | ||
47 | * | ||
48 | * 2. Supported adapter types: | ||
49 | * | ||
50 | * S502A | ||
51 | * ES502A (S502E) | ||
52 | * S503 | ||
53 | * S507 | ||
54 | * S508 (S509) | ||
55 | * | ||
56 | * 3. S502A Notes: | ||
57 | * | ||
58 | * There is no separate DPM window enable/disable control in S502A. It | ||
59 | * opens immediately after a window number it written to the HMCR | ||
60 | * register. To close the window, HMCR has to be written a value | ||
61 | * ????1111b (e.g. 0x0F or 0xFF). | ||
62 | * | ||
63 | * S502A DPM window cannot be located at offset E000 (e.g. 0xAE000). | ||
64 | * | ||
65 | * There should be a delay of ??? before reading back S502A status | ||
66 | * register. | ||
67 | * | ||
68 | * 4. S502E Notes: | ||
69 | * | ||
70 | * S502E has a h/w bug: although default IRQ line state is HIGH, enabling | ||
71 | * interrupts by setting bit 1 of the control register (BASE) to '1' | ||
72 | * causes it to go LOW! Therefore, disabling interrupts by setting that | ||
73 | * bit to '0' causes low-to-high transition on IRQ line (ghosty | ||
74 | * interrupt). The same occurs when disabling CPU by resetting bit 0 of | ||
75 | * CPU control register (BASE+3) - see the next note. | ||
76 | * | ||
77 | * S502E CPU and DPM control is limited: | ||
78 | * | ||
79 | * o CPU cannot be stopped independently. Resetting bit 0 of the CPUi | ||
80 | * control register (BASE+3) shuts the board down entirely, including | ||
81 | * DPM; | ||
82 | * | ||
83 | * o DPM access cannot be controlled dynamically. Ones CPU is started, | ||
84 | * bit 1 of the control register (BASE) is used to enable/disable IRQ, | ||
85 | * so that access to shared memory cannot be disabled while CPU is | ||
86 | * running. | ||
87 | ****************************************************************************/ | ||
88 | |||
89 | #define _LINUX_ | ||
90 | |||
91 | #if defined(_LINUX_) /****** Linux *******************************/ | ||
92 | |||
93 | #include <linux/config.h> | ||
94 | #include <linux/kernel.h> /* printk(), and other useful stuff */ | ||
95 | #include <linux/stddef.h> /* offsetof(), etc. */ | ||
96 | #include <linux/errno.h> /* return codes */ | ||
97 | #include <linux/string.h> /* inline memset(), etc. */ | ||
98 | #include <linux/module.h> /* support for loadable modules */ | ||
99 | #include <linux/jiffies.h> /* for jiffies, HZ, etc. */ | ||
100 | #include <linux/sdladrv.h> /* API definitions */ | ||
101 | #include <linux/sdlasfm.h> /* SDLA firmware module definitions */ | ||
102 | #include <linux/sdlapci.h> /* SDLA PCI hardware definitions */ | ||
103 | #include <linux/pci.h> /* PCI defines and function prototypes */ | ||
104 | #include <asm/io.h> /* for inb(), outb(), etc. */ | ||
105 | |||
106 | #define _INB(port) (inb(port)) | ||
107 | #define _OUTB(port, byte) (outb((byte),(port))) | ||
108 | #define SYSTEM_TICK jiffies | ||
109 | |||
110 | #include <linux/init.h> | ||
111 | |||
112 | |||
113 | #elif defined(_SCO_UNIX_) /****** SCO Unix ****************************/ | ||
114 | |||
115 | #if !defined(INKERNEL) | ||
116 | #error This code MUST be compiled in kernel mode! | ||
117 | #endif | ||
118 | #include <sys/sdladrv.h> /* API definitions */ | ||
119 | #include <sys/sdlasfm.h> /* SDLA firmware module definitions */ | ||
120 | #include <sys/inline.h> /* for inb(), outb(), etc. */ | ||
121 | #define _INB(port) (inb(port)) | ||
122 | #define _OUTB(port, byte) (outb((port),(byte))) | ||
123 | #define SYSTEM_TICK lbolt | ||
124 | |||
125 | #else | ||
126 | #error Unknown system type! | ||
127 | #endif | ||
128 | |||
129 | #define MOD_VERSION 3 | ||
130 | #define MOD_RELEASE 0 | ||
131 | |||
132 | #define SDLA_IODELAY 100 /* I/O Rd/Wr delay, 10 works for 486DX2-66 */ | ||
133 | #define EXEC_DELAY 20 /* shared memory access delay, mks */ | ||
134 | #define EXEC_TIMEOUT (HZ*2) /* command timeout, in ticks */ | ||
135 | |||
136 | /* I/O port address range */ | ||
137 | #define S502A_IORANGE 3 | ||
138 | #define S502E_IORANGE 4 | ||
139 | #define S503_IORANGE 3 | ||
140 | #define S507_IORANGE 4 | ||
141 | #define S508_IORANGE 4 | ||
142 | |||
143 | /* Maximum amount of memory */ | ||
144 | #define S502_MAXMEM 0x10000L | ||
145 | #define S503_MAXMEM 0x10000L | ||
146 | #define S507_MAXMEM 0x40000L | ||
147 | #define S508_MAXMEM 0x40000L | ||
148 | |||
149 | /* Minimum amount of memory */ | ||
150 | #define S502_MINMEM 0x8000L | ||
151 | #define S503_MINMEM 0x8000L | ||
152 | #define S507_MINMEM 0x20000L | ||
153 | #define S508_MINMEM 0x20000L | ||
154 | #define NO_PORT -1 | ||
155 | |||
156 | |||
157 | |||
158 | |||
159 | |||
160 | /****** Function Prototypes *************************************************/ | ||
161 | |||
162 | /* Hardware-specific functions */ | ||
163 | static int sdla_detect (sdlahw_t* hw); | ||
164 | static int sdla_autodpm (sdlahw_t* hw); | ||
165 | static int sdla_setdpm (sdlahw_t* hw); | ||
166 | static int sdla_load (sdlahw_t* hw, sfm_t* sfm, unsigned len); | ||
167 | static int sdla_init (sdlahw_t* hw); | ||
168 | static unsigned long sdla_memtest (sdlahw_t* hw); | ||
169 | static int sdla_bootcfg (sdlahw_t* hw, sfm_info_t* sfminfo); | ||
170 | static unsigned char make_config_byte (sdlahw_t* hw); | ||
171 | static int sdla_start (sdlahw_t* hw, unsigned addr); | ||
172 | |||
173 | static int init_s502a (sdlahw_t* hw); | ||
174 | static int init_s502e (sdlahw_t* hw); | ||
175 | static int init_s503 (sdlahw_t* hw); | ||
176 | static int init_s507 (sdlahw_t* hw); | ||
177 | static int init_s508 (sdlahw_t* hw); | ||
178 | |||
179 | static int detect_s502a (int port); | ||
180 | static int detect_s502e (int port); | ||
181 | static int detect_s503 (int port); | ||
182 | static int detect_s507 (int port); | ||
183 | static int detect_s508 (int port); | ||
184 | static int detect_s514 (sdlahw_t* hw); | ||
185 | static int find_s514_adapter(sdlahw_t* hw, char find_first_S514_card); | ||
186 | |||
187 | /* Miscellaneous functions */ | ||
188 | static void peek_by_4 (unsigned long src, void* buf, unsigned len); | ||
189 | static void poke_by_4 (unsigned long dest, void* buf, unsigned len); | ||
190 | static int calibrate_delay (int mks); | ||
191 | static int get_option_index (unsigned* optlist, unsigned optval); | ||
192 | static unsigned check_memregion (void* ptr, unsigned len); | ||
193 | static unsigned test_memregion (void* ptr, unsigned len); | ||
194 | static unsigned short checksum (unsigned char* buf, unsigned len); | ||
195 | static int init_pci_slot(sdlahw_t *); | ||
196 | |||
197 | static int pci_probe(sdlahw_t *hw); | ||
198 | |||
199 | /****** Global Data ********************************************************** | ||
200 | * Note: All data must be explicitly initialized!!! | ||
201 | */ | ||
202 | |||
203 | static struct pci_device_id sdladrv_pci_tbl[] = { | ||
204 | { V3_VENDOR_ID, V3_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, }, | ||
205 | { } /* Terminating entry */ | ||
206 | }; | ||
207 | MODULE_DEVICE_TABLE(pci, sdladrv_pci_tbl); | ||
208 | |||
209 | MODULE_LICENSE("GPL"); | ||
210 | |||
211 | /* private data */ | ||
212 | static char modname[] = "sdladrv"; | ||
213 | static char fullname[] = "SDLA Support Module"; | ||
214 | static char copyright[] = "(c) 1995-1999 Sangoma Technologies Inc."; | ||
215 | static unsigned exec_idle; | ||
216 | |||
217 | /* Hardware configuration options. | ||
218 | * These are arrays of configuration options used by verification routines. | ||
219 | * The first element of each array is its size (i.e. number of options). | ||
220 | */ | ||
221 | static unsigned s502_port_options[] = | ||
222 | { 4, 0x250, 0x300, 0x350, 0x360 } | ||
223 | ; | ||
224 | static unsigned s503_port_options[] = | ||
225 | { 8, 0x250, 0x254, 0x300, 0x304, 0x350, 0x354, 0x360, 0x364 } | ||
226 | ; | ||
227 | static unsigned s508_port_options[] = | ||
228 | { 8, 0x250, 0x270, 0x280, 0x300, 0x350, 0x360, 0x380, 0x390 } | ||
229 | ; | ||
230 | |||
231 | static unsigned s502a_irq_options[] = { 0 }; | ||
232 | static unsigned s502e_irq_options[] = { 4, 2, 3, 5, 7 }; | ||
233 | static unsigned s503_irq_options[] = { 5, 2, 3, 4, 5, 7 }; | ||
234 | static unsigned s508_irq_options[] = { 8, 3, 4, 5, 7, 10, 11, 12, 15 }; | ||
235 | |||
236 | static unsigned s502a_dpmbase_options[] = | ||
237 | { | ||
238 | 28, | ||
239 | 0xA0000, 0xA2000, 0xA4000, 0xA6000, 0xA8000, 0xAA000, 0xAC000, | ||
240 | 0xC0000, 0xC2000, 0xC4000, 0xC6000, 0xC8000, 0xCA000, 0xCC000, | ||
241 | 0xD0000, 0xD2000, 0xD4000, 0xD6000, 0xD8000, 0xDA000, 0xDC000, | ||
242 | 0xE0000, 0xE2000, 0xE4000, 0xE6000, 0xE8000, 0xEA000, 0xEC000, | ||
243 | }; | ||
244 | static unsigned s507_dpmbase_options[] = | ||
245 | { | ||
246 | 32, | ||
247 | 0xA0000, 0xA2000, 0xA4000, 0xA6000, 0xA8000, 0xAA000, 0xAC000, 0xAE000, | ||
248 | 0xB0000, 0xB2000, 0xB4000, 0xB6000, 0xB8000, 0xBA000, 0xBC000, 0xBE000, | ||
249 | 0xC0000, 0xC2000, 0xC4000, 0xC6000, 0xC8000, 0xCA000, 0xCC000, 0xCE000, | ||
250 | 0xE0000, 0xE2000, 0xE4000, 0xE6000, 0xE8000, 0xEA000, 0xEC000, 0xEE000, | ||
251 | }; | ||
252 | static unsigned s508_dpmbase_options[] = /* incl. S502E and S503 */ | ||
253 | { | ||
254 | 32, | ||
255 | 0xA0000, 0xA2000, 0xA4000, 0xA6000, 0xA8000, 0xAA000, 0xAC000, 0xAE000, | ||
256 | 0xC0000, 0xC2000, 0xC4000, 0xC6000, 0xC8000, 0xCA000, 0xCC000, 0xCE000, | ||
257 | 0xD0000, 0xD2000, 0xD4000, 0xD6000, 0xD8000, 0xDA000, 0xDC000, 0xDE000, | ||
258 | 0xE0000, 0xE2000, 0xE4000, 0xE6000, 0xE8000, 0xEA000, 0xEC000, 0xEE000, | ||
259 | }; | ||
260 | |||
261 | /* | ||
262 | static unsigned s502_dpmsize_options[] = { 2, 0x2000, 0x10000 }; | ||
263 | static unsigned s507_dpmsize_options[] = { 2, 0x2000, 0x4000 }; | ||
264 | static unsigned s508_dpmsize_options[] = { 1, 0x2000 }; | ||
265 | */ | ||
266 | |||
267 | static unsigned s502a_pclk_options[] = { 2, 3600, 7200 }; | ||
268 | static unsigned s502e_pclk_options[] = { 5, 3600, 5000, 7200, 8000, 10000 }; | ||
269 | static unsigned s503_pclk_options[] = { 3, 7200, 8000, 10000 }; | ||
270 | static unsigned s507_pclk_options[] = { 1, 12288 }; | ||
271 | static unsigned s508_pclk_options[] = { 1, 16000 }; | ||
272 | |||
273 | /* Host memory control register masks */ | ||
274 | static unsigned char s502a_hmcr[] = | ||
275 | { | ||
276 | 0x10, 0x12, 0x14, 0x16, 0x18, 0x1A, 0x1C, /* A0000 - AC000 */ | ||
277 | 0x20, 0x22, 0x24, 0x26, 0x28, 0x2A, 0x2C, /* C0000 - CC000 */ | ||
278 | 0x00, 0x02, 0x04, 0x06, 0x08, 0x0A, 0x0C, /* D0000 - DC000 */ | ||
279 | 0x30, 0x32, 0x34, 0x36, 0x38, 0x3A, 0x3C, /* E0000 - EC000 */ | ||
280 | }; | ||
281 | static unsigned char s502e_hmcr[] = | ||
282 | { | ||
283 | 0x10, 0x12, 0x14, 0x16, 0x18, 0x1A, 0x1C, 0x1E, /* A0000 - AE000 */ | ||
284 | 0x20, 0x22, 0x24, 0x26, 0x28, 0x2A, 0x2C, 0x2E, /* C0000 - CE000 */ | ||
285 | 0x00, 0x02, 0x04, 0x06, 0x08, 0x0A, 0x0C, 0x0E, /* D0000 - DE000 */ | ||
286 | 0x30, 0x32, 0x34, 0x36, 0x38, 0x3A, 0x3C, 0x3E, /* E0000 - EE000 */ | ||
287 | }; | ||
288 | static unsigned char s507_hmcr[] = | ||
289 | { | ||
290 | 0x00, 0x02, 0x04, 0x06, 0x08, 0x0A, 0x0C, 0x0E, /* A0000 - AE000 */ | ||
291 | 0x40, 0x42, 0x44, 0x46, 0x48, 0x4A, 0x4C, 0x4E, /* B0000 - BE000 */ | ||
292 | 0x80, 0x82, 0x84, 0x86, 0x88, 0x8A, 0x8C, 0x8E, /* C0000 - CE000 */ | ||
293 | 0xC0, 0xC2, 0xC4, 0xC6, 0xC8, 0xCA, 0xCC, 0xCE, /* E0000 - EE000 */ | ||
294 | }; | ||
295 | static unsigned char s508_hmcr[] = | ||
296 | { | ||
297 | 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* A0000 - AE000 */ | ||
298 | 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* C0000 - CE000 */ | ||
299 | 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, /* D0000 - DE000 */ | ||
300 | 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, /* E0000 - EE000 */ | ||
301 | }; | ||
302 | |||
303 | static unsigned char s507_irqmask[] = | ||
304 | { | ||
305 | 0x00, 0x20, 0x40, 0x60, 0x80, 0xA0, 0xC0, 0xE0 | ||
306 | }; | ||
307 | |||
308 | static int pci_slot_ar[MAX_S514_CARDS]; | ||
309 | |||
310 | /******* Kernel Loadable Module Entry Points ********************************/ | ||
311 | |||
312 | /*============================================================================ | ||
313 | * Module 'insert' entry point. | ||
314 | * o print announcement | ||
315 | * o initialize static data | ||
316 | * o calibrate SDLA shared memory access delay. | ||
317 | * | ||
318 | * Return: 0 Ok | ||
319 | * < 0 error. | ||
320 | * Context: process | ||
321 | */ | ||
322 | |||
323 | static int __init sdladrv_init(void) | ||
324 | { | ||
325 | int i=0; | ||
326 | |||
327 | printk(KERN_INFO "%s v%u.%u %s\n", | ||
328 | fullname, MOD_VERSION, MOD_RELEASE, copyright); | ||
329 | exec_idle = calibrate_delay(EXEC_DELAY); | ||
330 | #ifdef WANDEBUG | ||
331 | printk(KERN_DEBUG "%s: exec_idle = %d\n", modname, exec_idle); | ||
332 | #endif | ||
333 | |||
334 | /* Initialize the PCI Card array, which | ||
335 | * will store flags, used to mark | ||
336 | * card initialization state */ | ||
337 | for (i=0; i<MAX_S514_CARDS; i++) | ||
338 | pci_slot_ar[i] = 0xFF; | ||
339 | |||
340 | return 0; | ||
341 | } | ||
342 | |||
343 | /*============================================================================ | ||
344 | * Module 'remove' entry point. | ||
345 | * o release all remaining system resources | ||
346 | */ | ||
347 | static void __exit sdladrv_cleanup(void) | ||
348 | { | ||
349 | } | ||
350 | |||
351 | module_init(sdladrv_init); | ||
352 | module_exit(sdladrv_cleanup); | ||
353 | |||
354 | /******* Kernel APIs ********************************************************/ | ||
355 | |||
356 | /*============================================================================ | ||
357 | * Set up adapter. | ||
358 | * o detect adapter type | ||
359 | * o verify hardware configuration options | ||
360 | * o check for hardware conflicts | ||
361 | * o set up adapter shared memory | ||
362 | * o test adapter memory | ||
363 | * o load firmware | ||
364 | * Return: 0 ok. | ||
365 | * < 0 error | ||
366 | */ | ||
367 | |||
368 | EXPORT_SYMBOL(sdla_setup); | ||
369 | |||
370 | int sdla_setup (sdlahw_t* hw, void* sfm, unsigned len) | ||
371 | { | ||
372 | unsigned* irq_opt = NULL; /* IRQ options */ | ||
373 | unsigned* dpmbase_opt = NULL; /* DPM window base options */ | ||
374 | unsigned* pclk_opt = NULL; /* CPU clock rate options */ | ||
375 | int err=0; | ||
376 | |||
377 | if (sdla_detect(hw)) { | ||
378 | if(hw->type != SDLA_S514) | ||
379 | printk(KERN_INFO "%s: no SDLA card found at port 0x%X\n", | ||
380 | modname, hw->port); | ||
381 | return -EINVAL; | ||
382 | } | ||
383 | |||
384 | if(hw->type != SDLA_S514) { | ||
385 | printk(KERN_INFO "%s: found S%04u card at port 0x%X.\n", | ||
386 | modname, hw->type, hw->port); | ||
387 | |||
388 | hw->dpmsize = SDLA_WINDOWSIZE; | ||
389 | switch (hw->type) { | ||
390 | case SDLA_S502A: | ||
391 | hw->io_range = S502A_IORANGE; | ||
392 | irq_opt = s502a_irq_options; | ||
393 | dpmbase_opt = s502a_dpmbase_options; | ||
394 | pclk_opt = s502a_pclk_options; | ||
395 | break; | ||
396 | |||
397 | case SDLA_S502E: | ||
398 | hw->io_range = S502E_IORANGE; | ||
399 | irq_opt = s502e_irq_options; | ||
400 | dpmbase_opt = s508_dpmbase_options; | ||
401 | pclk_opt = s502e_pclk_options; | ||
402 | break; | ||
403 | |||
404 | case SDLA_S503: | ||
405 | hw->io_range = S503_IORANGE; | ||
406 | irq_opt = s503_irq_options; | ||
407 | dpmbase_opt = s508_dpmbase_options; | ||
408 | pclk_opt = s503_pclk_options; | ||
409 | break; | ||
410 | |||
411 | case SDLA_S507: | ||
412 | hw->io_range = S507_IORANGE; | ||
413 | irq_opt = s508_irq_options; | ||
414 | dpmbase_opt = s507_dpmbase_options; | ||
415 | pclk_opt = s507_pclk_options; | ||
416 | break; | ||
417 | |||
418 | case SDLA_S508: | ||
419 | hw->io_range = S508_IORANGE; | ||
420 | irq_opt = s508_irq_options; | ||
421 | dpmbase_opt = s508_dpmbase_options; | ||
422 | pclk_opt = s508_pclk_options; | ||
423 | break; | ||
424 | } | ||
425 | |||
426 | /* Verify IRQ configuration options */ | ||
427 | if (!get_option_index(irq_opt, hw->irq)) { | ||
428 | printk(KERN_INFO "%s: IRQ %d is invalid!\n", | ||
429 | modname, hw->irq); | ||
430 | return -EINVAL; | ||
431 | } | ||
432 | |||
433 | /* Verify CPU clock rate configuration options */ | ||
434 | if (hw->pclk == 0) | ||
435 | hw->pclk = pclk_opt[1]; /* use default */ | ||
436 | |||
437 | else if (!get_option_index(pclk_opt, hw->pclk)) { | ||
438 | printk(KERN_INFO "%s: CPU clock %u is invalid!\n", | ||
439 | modname, hw->pclk); | ||
440 | return -EINVAL; | ||
441 | } | ||
442 | printk(KERN_INFO "%s: assuming CPU clock rate of %u kHz.\n", | ||
443 | modname, hw->pclk); | ||
444 | |||
445 | /* Setup adapter dual-port memory window and test memory */ | ||
446 | if (hw->dpmbase == 0) { | ||
447 | err = sdla_autodpm(hw); | ||
448 | if (err) { | ||
449 | printk(KERN_INFO | ||
450 | "%s: can't find available memory region!\n", | ||
451 | modname); | ||
452 | return err; | ||
453 | } | ||
454 | } | ||
455 | else if (!get_option_index(dpmbase_opt, | ||
456 | virt_to_phys(hw->dpmbase))) { | ||
457 | printk(KERN_INFO | ||
458 | "%s: memory address 0x%lX is invalid!\n", | ||
459 | modname, virt_to_phys(hw->dpmbase)); | ||
460 | return -EINVAL; | ||
461 | } | ||
462 | else if (sdla_setdpm(hw)) { | ||
463 | printk(KERN_INFO | ||
464 | "%s: 8K memory region at 0x%lX is not available!\n", | ||
465 | modname, virt_to_phys(hw->dpmbase)); | ||
466 | return -EINVAL; | ||
467 | } | ||
468 | printk(KERN_INFO | ||
469 | "%s: dual-port memory window is set at 0x%lX.\n", | ||
470 | modname, virt_to_phys(hw->dpmbase)); | ||
471 | |||
472 | |||
473 | /* If we find memory in 0xE**** Memory region, | ||
474 | * warn the user to disable the SHADOW RAM. | ||
475 | * Since memory corruption can occur if SHADOW is | ||
476 | * enabled. This can causes random crashes ! */ | ||
477 | if (virt_to_phys(hw->dpmbase) >= 0xE0000){ | ||
478 | printk(KERN_WARNING "\n%s: !!!!!!!! WARNING !!!!!!!!\n",modname); | ||
479 | printk(KERN_WARNING "%s: WANPIPE is using 0x%lX memory region !!!\n", | ||
480 | modname, virt_to_phys(hw->dpmbase)); | ||
481 | printk(KERN_WARNING " Please disable the SHADOW RAM, otherwise\n"); | ||
482 | printk(KERN_WARNING " your system might crash randomly from time to time !\n"); | ||
483 | printk(KERN_WARNING "%s: !!!!!!!! WARNING !!!!!!!!\n\n",modname); | ||
484 | } | ||
485 | } | ||
486 | |||
487 | else { | ||
488 | hw->memory = test_memregion((void*)hw->dpmbase, | ||
489 | MAX_SIZEOF_S514_MEMORY); | ||
490 | if(hw->memory < (256 * 1024)) { | ||
491 | printk(KERN_INFO | ||
492 | "%s: error in testing S514 memory (0x%lX)\n", | ||
493 | modname, hw->memory); | ||
494 | sdla_down(hw); | ||
495 | return -EINVAL; | ||
496 | } | ||
497 | } | ||
498 | |||
499 | printk(KERN_INFO "%s: found %luK bytes of on-board memory\n", | ||
500 | modname, hw->memory / 1024); | ||
501 | |||
502 | /* Load firmware. If loader fails then shut down adapter */ | ||
503 | err = sdla_load(hw, sfm, len); | ||
504 | if (err) sdla_down(hw); /* shutdown adapter */ | ||
505 | |||
506 | return err; | ||
507 | } | ||
508 | |||
509 | /*============================================================================ | ||
510 | * Shut down SDLA: disable shared memory access and interrupts, stop CPU, etc. | ||
511 | */ | ||
512 | |||
513 | EXPORT_SYMBOL(sdla_down); | ||
514 | |||
515 | int sdla_down (sdlahw_t* hw) | ||
516 | { | ||
517 | unsigned port = hw->port; | ||
518 | int i; | ||
519 | unsigned char CPU_no; | ||
520 | u32 int_config, int_status; | ||
521 | |||
522 | if(!port && (hw->type != SDLA_S514)) | ||
523 | return -EFAULT; | ||
524 | |||
525 | switch (hw->type) { | ||
526 | case SDLA_S502A: | ||
527 | _OUTB(port, 0x08); /* halt CPU */ | ||
528 | _OUTB(port, 0x08); | ||
529 | _OUTB(port, 0x08); | ||
530 | hw->regs[0] = 0x08; | ||
531 | _OUTB(port + 1, 0xFF); /* close memory window */ | ||
532 | hw->regs[1] = 0xFF; | ||
533 | break; | ||
534 | |||
535 | case SDLA_S502E: | ||
536 | _OUTB(port + 3, 0); /* stop CPU */ | ||
537 | _OUTB(port, 0); /* reset board */ | ||
538 | for (i = 0; i < S502E_IORANGE; ++i) | ||
539 | hw->regs[i] = 0 | ||
540 | ; | ||
541 | break; | ||
542 | |||
543 | case SDLA_S503: | ||
544 | case SDLA_S507: | ||
545 | case SDLA_S508: | ||
546 | _OUTB(port, 0); /* reset board logic */ | ||
547 | hw->regs[0] = 0; | ||
548 | break; | ||
549 | |||
550 | case SDLA_S514: | ||
551 | /* halt the adapter */ | ||
552 | *(char *)hw->vector = S514_CPU_HALT; | ||
553 | CPU_no = hw->S514_cpu_no[0]; | ||
554 | |||
555 | /* disable the PCI IRQ and disable memory access */ | ||
556 | pci_read_config_dword(hw->pci_dev, PCI_INT_CONFIG, &int_config); | ||
557 | int_config &= (CPU_no == S514_CPU_A) ? ~PCI_DISABLE_IRQ_CPU_A : ~PCI_DISABLE_IRQ_CPU_B; | ||
558 | pci_write_config_dword(hw->pci_dev, PCI_INT_CONFIG, int_config); | ||
559 | read_S514_int_stat(hw, &int_status); | ||
560 | S514_intack(hw, int_status); | ||
561 | if(CPU_no == S514_CPU_A) | ||
562 | pci_write_config_dword(hw->pci_dev, PCI_MAP0_DWORD, | ||
563 | PCI_CPU_A_MEM_DISABLE); | ||
564 | else | ||
565 | pci_write_config_dword(hw->pci_dev, PCI_MAP1_DWORD, | ||
566 | PCI_CPU_B_MEM_DISABLE); | ||
567 | |||
568 | /* free up the allocated virtual memory */ | ||
569 | iounmap((void *)hw->dpmbase); | ||
570 | iounmap((void *)hw->vector); | ||
571 | break; | ||
572 | |||
573 | |||
574 | default: | ||
575 | return -EINVAL; | ||
576 | } | ||
577 | return 0; | ||
578 | } | ||
579 | |||
580 | /*============================================================================ | ||
581 | * Map shared memory window into SDLA address space. | ||
582 | */ | ||
583 | |||
584 | EXPORT_SYMBOL(sdla_mapmem); | ||
585 | |||
586 | int sdla_mapmem (sdlahw_t* hw, unsigned long addr) | ||
587 | { | ||
588 | unsigned port = hw->port; | ||
589 | register int tmp; | ||
590 | |||
591 | switch (hw->type) { | ||
592 | case SDLA_S502A: | ||
593 | case SDLA_S502E: | ||
594 | if (addr < S502_MAXMEM) { /* verify parameter */ | ||
595 | tmp = addr >> 13; /* convert to register mask */ | ||
596 | _OUTB(port + 2, tmp); | ||
597 | hw->regs[2] = tmp; | ||
598 | } | ||
599 | else return -EINVAL; | ||
600 | break; | ||
601 | |||
602 | case SDLA_S503: | ||
603 | if (addr < S503_MAXMEM) { /* verify parameter */ | ||
604 | tmp = (hw->regs[0] & 0x8F) | ((addr >> 9) & 0x70); | ||
605 | _OUTB(port, tmp); | ||
606 | hw->regs[0] = tmp; | ||
607 | } | ||
608 | else return -EINVAL; | ||
609 | break; | ||
610 | |||
611 | case SDLA_S507: | ||
612 | if (addr < S507_MAXMEM) { | ||
613 | if (!(_INB(port) & 0x02)) | ||
614 | return -EIO; | ||
615 | tmp = addr >> 13; /* convert to register mask */ | ||
616 | _OUTB(port + 2, tmp); | ||
617 | hw->regs[2] = tmp; | ||
618 | } | ||
619 | else return -EINVAL; | ||
620 | break; | ||
621 | |||
622 | case SDLA_S508: | ||
623 | if (addr < S508_MAXMEM) { | ||
624 | tmp = addr >> 13; /* convert to register mask */ | ||
625 | _OUTB(port + 2, tmp); | ||
626 | hw->regs[2] = tmp; | ||
627 | } | ||
628 | else return -EINVAL; | ||
629 | break; | ||
630 | |||
631 | case SDLA_S514: | ||
632 | return 0; | ||
633 | |||
634 | default: | ||
635 | return -EINVAL; | ||
636 | } | ||
637 | hw->vector = addr & 0xFFFFE000L; | ||
638 | return 0; | ||
639 | } | ||
640 | |||
641 | /*============================================================================ | ||
642 | * Enable interrupt generation. | ||
643 | */ | ||
644 | |||
645 | static int sdla_inten (sdlahw_t* hw) | ||
646 | { | ||
647 | unsigned port = hw->port; | ||
648 | int tmp, i; | ||
649 | |||
650 | switch (hw->type) { | ||
651 | case SDLA_S502E: | ||
652 | /* Note thar interrupt control operations on S502E are allowed | ||
653 | * only if CPU is enabled (bit 0 of status register is set). | ||
654 | */ | ||
655 | if (_INB(port) & 0x01) { | ||
656 | _OUTB(port, 0x02); /* bit1 = 1, bit2 = 0 */ | ||
657 | _OUTB(port, 0x06); /* bit1 = 1, bit2 = 1 */ | ||
658 | hw->regs[0] = 0x06; | ||
659 | } | ||
660 | else return -EIO; | ||
661 | break; | ||
662 | |||
663 | case SDLA_S503: | ||
664 | tmp = hw->regs[0] | 0x04; | ||
665 | _OUTB(port, tmp); | ||
666 | hw->regs[0] = tmp; /* update mirror */ | ||
667 | for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ | ||
668 | if (!(_INB(port) & 0x02)) /* verify */ | ||
669 | return -EIO; | ||
670 | break; | ||
671 | |||
672 | case SDLA_S508: | ||
673 | tmp = hw->regs[0] | 0x10; | ||
674 | _OUTB(port, tmp); | ||
675 | hw->regs[0] = tmp; /* update mirror */ | ||
676 | for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ | ||
677 | if (!(_INB(port + 1) & 0x10)) /* verify */ | ||
678 | return -EIO; | ||
679 | break; | ||
680 | |||
681 | case SDLA_S502A: | ||
682 | case SDLA_S507: | ||
683 | break; | ||
684 | |||
685 | case SDLA_S514: | ||
686 | break; | ||
687 | |||
688 | default: | ||
689 | return -EINVAL; | ||
690 | |||
691 | } | ||
692 | return 0; | ||
693 | } | ||
694 | |||
695 | /*============================================================================ | ||
696 | * Disable interrupt generation. | ||
697 | */ | ||
698 | |||
699 | #if 0 | ||
700 | int sdla_intde (sdlahw_t* hw) | ||
701 | { | ||
702 | unsigned port = hw->port; | ||
703 | int tmp, i; | ||
704 | |||
705 | switch (hw->type) { | ||
706 | case SDLA_S502E: | ||
707 | /* Notes: | ||
708 | * 1) interrupt control operations are allowed only if CPU is | ||
709 | * enabled (bit 0 of status register is set). | ||
710 | * 2) disabling interrupts using bit 1 of control register | ||
711 | * causes IRQ line go high, therefore we are going to use | ||
712 | * 0x04 instead: lower it to inhibit interrupts to PC. | ||
713 | */ | ||
714 | if (_INB(port) & 0x01) { | ||
715 | _OUTB(port, hw->regs[0] & ~0x04); | ||
716 | hw->regs[0] &= ~0x04; | ||
717 | } | ||
718 | else return -EIO; | ||
719 | break; | ||
720 | |||
721 | case SDLA_S503: | ||
722 | tmp = hw->regs[0] & ~0x04; | ||
723 | _OUTB(port, tmp); | ||
724 | hw->regs[0] = tmp; /* update mirror */ | ||
725 | for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ | ||
726 | if (_INB(port) & 0x02) /* verify */ | ||
727 | return -EIO; | ||
728 | break; | ||
729 | |||
730 | case SDLA_S508: | ||
731 | tmp = hw->regs[0] & ~0x10; | ||
732 | _OUTB(port, tmp); | ||
733 | hw->regs[0] = tmp; /* update mirror */ | ||
734 | for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ | ||
735 | if (_INB(port) & 0x10) /* verify */ | ||
736 | return -EIO; | ||
737 | break; | ||
738 | |||
739 | case SDLA_S502A: | ||
740 | case SDLA_S507: | ||
741 | break; | ||
742 | |||
743 | default: | ||
744 | return -EINVAL; | ||
745 | } | ||
746 | return 0; | ||
747 | } | ||
748 | #endif /* 0 */ | ||
749 | |||
750 | /*============================================================================ | ||
751 | * Acknowledge SDLA hardware interrupt. | ||
752 | */ | ||
753 | |||
754 | static int sdla_intack (sdlahw_t* hw) | ||
755 | { | ||
756 | unsigned port = hw->port; | ||
757 | int tmp; | ||
758 | |||
759 | switch (hw->type) { | ||
760 | case SDLA_S502E: | ||
761 | /* To acknoledge hardware interrupt we have to toggle bit 3 of | ||
762 | * control register: \_/ | ||
763 | * Note that interrupt control operations on S502E are allowed | ||
764 | * only if CPU is enabled (bit 1 of status register is set). | ||
765 | */ | ||
766 | if (_INB(port) & 0x01) { | ||
767 | tmp = hw->regs[0] & ~0x04; | ||
768 | _OUTB(port, tmp); | ||
769 | tmp |= 0x04; | ||
770 | _OUTB(port, tmp); | ||
771 | hw->regs[0] = tmp; | ||
772 | } | ||
773 | else return -EIO; | ||
774 | break; | ||
775 | |||
776 | case SDLA_S503: | ||
777 | if (_INB(port) & 0x04) { | ||
778 | tmp = hw->regs[0] & ~0x08; | ||
779 | _OUTB(port, tmp); | ||
780 | tmp |= 0x08; | ||
781 | _OUTB(port, tmp); | ||
782 | hw->regs[0] = tmp; | ||
783 | } | ||
784 | break; | ||
785 | |||
786 | case SDLA_S502A: | ||
787 | case SDLA_S507: | ||
788 | case SDLA_S508: | ||
789 | break; | ||
790 | |||
791 | default: | ||
792 | return -EINVAL; | ||
793 | } | ||
794 | return 0; | ||
795 | } | ||
796 | |||
797 | |||
798 | /*============================================================================ | ||
799 | * Acknowledge S514 hardware interrupt. | ||
800 | */ | ||
801 | |||
802 | EXPORT_SYMBOL(S514_intack); | ||
803 | |||
804 | void S514_intack (sdlahw_t* hw, u32 int_status) | ||
805 | { | ||
806 | pci_write_config_dword(hw->pci_dev, PCI_INT_STATUS, int_status); | ||
807 | } | ||
808 | |||
809 | |||
810 | /*============================================================================ | ||
811 | * Read the S514 hardware interrupt status. | ||
812 | */ | ||
813 | |||
814 | EXPORT_SYMBOL(read_S514_int_stat); | ||
815 | |||
816 | void read_S514_int_stat (sdlahw_t* hw, u32* int_status) | ||
817 | { | ||
818 | pci_read_config_dword(hw->pci_dev, PCI_INT_STATUS, int_status); | ||
819 | } | ||
820 | |||
821 | |||
822 | /*============================================================================ | ||
823 | * Generate an interrupt to adapter's CPU. | ||
824 | */ | ||
825 | |||
826 | #if 0 | ||
827 | int sdla_intr (sdlahw_t* hw) | ||
828 | { | ||
829 | unsigned port = hw->port; | ||
830 | |||
831 | switch (hw->type) { | ||
832 | case SDLA_S502A: | ||
833 | if (!(_INB(port) & 0x40)) { | ||
834 | _OUTB(port, 0x10); /* issue NMI to CPU */ | ||
835 | hw->regs[0] = 0x10; | ||
836 | } | ||
837 | else return -EIO; | ||
838 | break; | ||
839 | |||
840 | case SDLA_S507: | ||
841 | if ((_INB(port) & 0x06) == 0x06) { | ||
842 | _OUTB(port + 3, 0); | ||
843 | } | ||
844 | else return -EIO; | ||
845 | break; | ||
846 | |||
847 | case SDLA_S508: | ||
848 | if (_INB(port + 1) & 0x02) { | ||
849 | _OUTB(port, 0x08); | ||
850 | } | ||
851 | else return -EIO; | ||
852 | break; | ||
853 | |||
854 | case SDLA_S502E: | ||
855 | case SDLA_S503: | ||
856 | default: | ||
857 | return -EINVAL; | ||
858 | } | ||
859 | return 0; | ||
860 | } | ||
861 | #endif /* 0 */ | ||
862 | |||
863 | /*============================================================================ | ||
864 | * Execute Adapter Command. | ||
865 | * o Set exec flag. | ||
866 | * o Busy-wait until flag is reset. | ||
867 | * o Return number of loops made, or 0 if command timed out. | ||
868 | */ | ||
869 | |||
870 | EXPORT_SYMBOL(sdla_exec); | ||
871 | |||
872 | int sdla_exec (void* opflag) | ||
873 | { | ||
874 | volatile unsigned char* flag = opflag; | ||
875 | unsigned long tstop; | ||
876 | int nloops; | ||
877 | |||
878 | if(readb(flag) != 0x00) { | ||
879 | printk(KERN_INFO | ||
880 | "WANPIPE: opp flag set on entry to sdla_exec\n"); | ||
881 | return 0; | ||
882 | } | ||
883 | |||
884 | writeb(0x01, flag); | ||
885 | |||
886 | tstop = SYSTEM_TICK + EXEC_TIMEOUT; | ||
887 | |||
888 | for (nloops = 1; (readb(flag) == 0x01); ++ nloops) { | ||
889 | unsigned delay = exec_idle; | ||
890 | while (-- delay); /* delay */ | ||
891 | if (SYSTEM_TICK > tstop) return 0; /* time is up! */ | ||
892 | } | ||
893 | return nloops; | ||
894 | } | ||
895 | |||
896 | /*============================================================================ | ||
897 | * Read absolute adapter memory. | ||
898 | * Transfer data from adapter's memory to data buffer. | ||
899 | * | ||
900 | * Note: | ||
901 | * Care should be taken when crossing dual-port memory window boundary. | ||
902 | * This function is not atomic, so caller must disable interrupt if | ||
903 | * interrupt routines are accessing adapter shared memory. | ||
904 | */ | ||
905 | |||
906 | EXPORT_SYMBOL(sdla_peek); | ||
907 | |||
908 | int sdla_peek (sdlahw_t* hw, unsigned long addr, void* buf, unsigned len) | ||
909 | { | ||
910 | |||
911 | if (addr + len > hw->memory) /* verify arguments */ | ||
912 | return -EINVAL; | ||
913 | |||
914 | if(hw->type == SDLA_S514) { /* copy data for the S514 adapter */ | ||
915 | peek_by_4 ((unsigned long)hw->dpmbase + addr, buf, len); | ||
916 | return 0; | ||
917 | } | ||
918 | |||
919 | else { /* copy data for the S508 adapter */ | ||
920 | unsigned long oldvec = hw->vector; | ||
921 | unsigned winsize = hw->dpmsize; | ||
922 | unsigned curpos, curlen; /* current offset and block size */ | ||
923 | unsigned long curvec; /* current DPM window vector */ | ||
924 | int err = 0; | ||
925 | |||
926 | while (len && !err) { | ||
927 | curpos = addr % winsize; /* current window offset */ | ||
928 | curvec = addr - curpos; /* current window vector */ | ||
929 | curlen = (len > (winsize - curpos)) ? | ||
930 | (winsize - curpos) : len; | ||
931 | /* Relocate window and copy block of data */ | ||
932 | err = sdla_mapmem(hw, curvec); | ||
933 | peek_by_4 ((unsigned long)hw->dpmbase + curpos, buf, | ||
934 | curlen); | ||
935 | addr += curlen; | ||
936 | buf = (char*)buf + curlen; | ||
937 | len -= curlen; | ||
938 | } | ||
939 | |||
940 | /* Restore DPM window position */ | ||
941 | sdla_mapmem(hw, oldvec); | ||
942 | return err; | ||
943 | } | ||
944 | } | ||
945 | |||
946 | |||
947 | /*============================================================================ | ||
948 | * Read data from adapter's memory to a data buffer in 4-byte chunks. | ||
949 | * Note that we ensure that the SDLA memory address is on a 4-byte boundary | ||
950 | * before we begin moving the data in 4-byte chunks. | ||
951 | */ | ||
952 | |||
953 | static void peek_by_4 (unsigned long src, void* buf, unsigned len) | ||
954 | { | ||
955 | |||
956 | /* byte copy data until we get to a 4-byte boundary */ | ||
957 | while (len && (src & 0x03)) { | ||
958 | *(char *)buf ++ = readb(src ++); | ||
959 | len --; | ||
960 | } | ||
961 | |||
962 | /* copy data in 4-byte chunks */ | ||
963 | while (len >= 4) { | ||
964 | *(unsigned long *)buf = readl(src); | ||
965 | buf += 4; | ||
966 | src += 4; | ||
967 | len -= 4; | ||
968 | } | ||
969 | |||
970 | /* byte copy any remaining data */ | ||
971 | while (len) { | ||
972 | *(char *)buf ++ = readb(src ++); | ||
973 | len --; | ||
974 | } | ||
975 | } | ||
976 | |||
977 | |||
978 | /*============================================================================ | ||
979 | * Write Absolute Adapter Memory. | ||
980 | * Transfer data from data buffer to adapter's memory. | ||
981 | * | ||
982 | * Note: | ||
983 | * Care should be taken when crossing dual-port memory window boundary. | ||
984 | * This function is not atomic, so caller must disable interrupt if | ||
985 | * interrupt routines are accessing adapter shared memory. | ||
986 | */ | ||
987 | |||
988 | EXPORT_SYMBOL(sdla_poke); | ||
989 | |||
990 | int sdla_poke (sdlahw_t* hw, unsigned long addr, void* buf, unsigned len) | ||
991 | { | ||
992 | |||
993 | if (addr + len > hw->memory) /* verify arguments */ | ||
994 | return -EINVAL; | ||
995 | |||
996 | if(hw->type == SDLA_S514) { /* copy data for the S514 adapter */ | ||
997 | poke_by_4 ((unsigned long)hw->dpmbase + addr, buf, len); | ||
998 | return 0; | ||
999 | } | ||
1000 | |||
1001 | else { /* copy data for the S508 adapter */ | ||
1002 | unsigned long oldvec = hw->vector; | ||
1003 | unsigned winsize = hw->dpmsize; | ||
1004 | unsigned curpos, curlen; /* current offset and block size */ | ||
1005 | unsigned long curvec; /* current DPM window vector */ | ||
1006 | int err = 0; | ||
1007 | |||
1008 | while (len && !err) { | ||
1009 | curpos = addr % winsize; /* current window offset */ | ||
1010 | curvec = addr - curpos; /* current window vector */ | ||
1011 | curlen = (len > (winsize - curpos)) ? | ||
1012 | (winsize - curpos) : len; | ||
1013 | /* Relocate window and copy block of data */ | ||
1014 | sdla_mapmem(hw, curvec); | ||
1015 | poke_by_4 ((unsigned long)hw->dpmbase + curpos, buf, | ||
1016 | curlen); | ||
1017 | addr += curlen; | ||
1018 | buf = (char*)buf + curlen; | ||
1019 | len -= curlen; | ||
1020 | } | ||
1021 | |||
1022 | /* Restore DPM window position */ | ||
1023 | sdla_mapmem(hw, oldvec); | ||
1024 | return err; | ||
1025 | } | ||
1026 | } | ||
1027 | |||
1028 | |||
1029 | /*============================================================================ | ||
1030 | * Write from a data buffer to adapter's memory in 4-byte chunks. | ||
1031 | * Note that we ensure that the SDLA memory address is on a 4-byte boundary | ||
1032 | * before we begin moving the data in 4-byte chunks. | ||
1033 | */ | ||
1034 | |||
1035 | static void poke_by_4 (unsigned long dest, void* buf, unsigned len) | ||
1036 | { | ||
1037 | |||
1038 | /* byte copy data until we get to a 4-byte boundary */ | ||
1039 | while (len && (dest & 0x03)) { | ||
1040 | writeb (*(char *)buf ++, dest ++); | ||
1041 | len --; | ||
1042 | } | ||
1043 | |||
1044 | /* copy data in 4-byte chunks */ | ||
1045 | while (len >= 4) { | ||
1046 | writel (*(unsigned long *)buf, dest); | ||
1047 | dest += 4; | ||
1048 | buf += 4; | ||
1049 | len -= 4; | ||
1050 | } | ||
1051 | |||
1052 | /* byte copy any remaining data */ | ||
1053 | while (len) { | ||
1054 | writeb (*(char *)buf ++ , dest ++); | ||
1055 | len --; | ||
1056 | } | ||
1057 | } | ||
1058 | |||
1059 | |||
1060 | #ifdef DONT_COMPIPLE_THIS | ||
1061 | #endif /* DONT_COMPIPLE_THIS */ | ||
1062 | |||
1063 | /****** Hardware-Specific Functions *****************************************/ | ||
1064 | |||
1065 | /*============================================================================ | ||
1066 | * Detect adapter type. | ||
1067 | * o if adapter type is specified then call detection routine for that adapter | ||
1068 | * type. Otherwise call detection routines for every adapter types until | ||
1069 | * adapter is detected. | ||
1070 | * | ||
1071 | * Notes: | ||
1072 | * 1) Detection tests are destructive! Adapter will be left in shutdown state | ||
1073 | * after the test. | ||
1074 | */ | ||
1075 | static int sdla_detect (sdlahw_t* hw) | ||
1076 | { | ||
1077 | unsigned port = hw->port; | ||
1078 | int err = 0; | ||
1079 | |||
1080 | if (!port && (hw->type != SDLA_S514)) | ||
1081 | return -EFAULT; | ||
1082 | |||
1083 | switch (hw->type) { | ||
1084 | case SDLA_S502A: | ||
1085 | if (!detect_s502a(port)) err = -ENODEV; | ||
1086 | break; | ||
1087 | |||
1088 | case SDLA_S502E: | ||
1089 | if (!detect_s502e(port)) err = -ENODEV; | ||
1090 | break; | ||
1091 | |||
1092 | case SDLA_S503: | ||
1093 | if (!detect_s503(port)) err = -ENODEV; | ||
1094 | break; | ||
1095 | |||
1096 | case SDLA_S507: | ||
1097 | if (!detect_s507(port)) err = -ENODEV; | ||
1098 | break; | ||
1099 | |||
1100 | case SDLA_S508: | ||
1101 | if (!detect_s508(port)) err = -ENODEV; | ||
1102 | break; | ||
1103 | |||
1104 | case SDLA_S514: | ||
1105 | if (!detect_s514(hw)) err = -ENODEV; | ||
1106 | break; | ||
1107 | |||
1108 | default: | ||
1109 | if (detect_s502a(port)) | ||
1110 | hw->type = SDLA_S502A; | ||
1111 | else if (detect_s502e(port)) | ||
1112 | hw->type = SDLA_S502E; | ||
1113 | else if (detect_s503(port)) | ||
1114 | hw->type = SDLA_S503; | ||
1115 | else if (detect_s507(port)) | ||
1116 | hw->type = SDLA_S507; | ||
1117 | else if (detect_s508(port)) | ||
1118 | hw->type = SDLA_S508; | ||
1119 | else err = -ENODEV; | ||
1120 | } | ||
1121 | return err; | ||
1122 | } | ||
1123 | |||
1124 | /*============================================================================ | ||
1125 | * Autoselect memory region. | ||
1126 | * o try all available DMP address options from the top down until success. | ||
1127 | */ | ||
1128 | static int sdla_autodpm (sdlahw_t* hw) | ||
1129 | { | ||
1130 | int i, err = -EINVAL; | ||
1131 | unsigned* opt; | ||
1132 | |||
1133 | switch (hw->type) { | ||
1134 | case SDLA_S502A: | ||
1135 | opt = s502a_dpmbase_options; | ||
1136 | break; | ||
1137 | |||
1138 | case SDLA_S502E: | ||
1139 | case SDLA_S503: | ||
1140 | case SDLA_S508: | ||
1141 | opt = s508_dpmbase_options; | ||
1142 | break; | ||
1143 | |||
1144 | case SDLA_S507: | ||
1145 | opt = s507_dpmbase_options; | ||
1146 | break; | ||
1147 | |||
1148 | default: | ||
1149 | return -EINVAL; | ||
1150 | } | ||
1151 | |||
1152 | /* Start testing from 8th position, address | ||
1153 | * 0xC8000 from the 508 address table. | ||
1154 | * We don't want to test A**** addresses, since | ||
1155 | * they are usually used for Video */ | ||
1156 | for (i = 8; i <= opt[0] && err; i++) { | ||
1157 | hw->dpmbase = phys_to_virt(opt[i]); | ||
1158 | err = sdla_setdpm(hw); | ||
1159 | } | ||
1160 | return err; | ||
1161 | } | ||
1162 | |||
1163 | /*============================================================================ | ||
1164 | * Set up adapter dual-port memory window. | ||
1165 | * o shut down adapter | ||
1166 | * o make sure that no physical memory exists in this region, i.e entire | ||
1167 | * region reads 0xFF and is not writable when adapter is shut down. | ||
1168 | * o initialize adapter hardware | ||
1169 | * o make sure that region is usable with SDLA card, i.e. we can write to it | ||
1170 | * when adapter is configured. | ||
1171 | */ | ||
1172 | static int sdla_setdpm (sdlahw_t* hw) | ||
1173 | { | ||
1174 | int err; | ||
1175 | |||
1176 | /* Shut down card and verify memory region */ | ||
1177 | sdla_down(hw); | ||
1178 | if (check_memregion(hw->dpmbase, hw->dpmsize)) | ||
1179 | return -EINVAL; | ||
1180 | |||
1181 | /* Initialize adapter and test on-board memory segment by segment. | ||
1182 | * If memory size appears to be less than shared memory window size, | ||
1183 | * assume that memory region is unusable. | ||
1184 | */ | ||
1185 | err = sdla_init(hw); | ||
1186 | if (err) return err; | ||
1187 | |||
1188 | if (sdla_memtest(hw) < hw->dpmsize) { /* less than window size */ | ||
1189 | sdla_down(hw); | ||
1190 | return -EIO; | ||
1191 | } | ||
1192 | sdla_mapmem(hw, 0L); /* set window vector at bottom */ | ||
1193 | return 0; | ||
1194 | } | ||
1195 | |||
1196 | /*============================================================================ | ||
1197 | * Load adapter from the memory image of the SDLA firmware module. | ||
1198 | * o verify firmware integrity and compatibility | ||
1199 | * o start adapter up | ||
1200 | */ | ||
1201 | static int sdla_load (sdlahw_t* hw, sfm_t* sfm, unsigned len) | ||
1202 | { | ||
1203 | |||
1204 | int i; | ||
1205 | |||
1206 | /* Verify firmware signature */ | ||
1207 | if (strcmp(sfm->signature, SFM_SIGNATURE)) { | ||
1208 | printk(KERN_INFO "%s: not SDLA firmware!\n", | ||
1209 | modname); | ||
1210 | return -EINVAL; | ||
1211 | } | ||
1212 | |||
1213 | /* Verify firmware module format version */ | ||
1214 | if (sfm->version != SFM_VERSION) { | ||
1215 | printk(KERN_INFO | ||
1216 | "%s: firmware format %u rejected! Expecting %u.\n", | ||
1217 | modname, sfm->version, SFM_VERSION); | ||
1218 | return -EINVAL; | ||
1219 | } | ||
1220 | |||
1221 | /* Verify firmware module length and checksum */ | ||
1222 | if ((len - offsetof(sfm_t, image) != sfm->info.codesize) || | ||
1223 | (checksum((void*)&sfm->info, | ||
1224 | sizeof(sfm_info_t) + sfm->info.codesize) != sfm->checksum)) { | ||
1225 | printk(KERN_INFO "%s: firmware corrupted!\n", modname); | ||
1226 | return -EINVAL; | ||
1227 | } | ||
1228 | |||
1229 | /* Announce */ | ||
1230 | printk(KERN_INFO "%s: loading %s (ID=%u)...\n", modname, | ||
1231 | (sfm->descr[0] != '\0') ? sfm->descr : "unknown firmware", | ||
1232 | sfm->info.codeid); | ||
1233 | |||
1234 | if(hw->type == SDLA_S514) | ||
1235 | printk(KERN_INFO "%s: loading S514 adapter, CPU %c\n", | ||
1236 | modname, hw->S514_cpu_no[0]); | ||
1237 | |||
1238 | /* Scan through the list of compatible adapters and make sure our | ||
1239 | * adapter type is listed. | ||
1240 | */ | ||
1241 | for (i = 0; | ||
1242 | (i < SFM_MAX_SDLA) && (sfm->info.adapter[i] != hw->type); | ||
1243 | ++i); | ||
1244 | |||
1245 | if (i == SFM_MAX_SDLA) { | ||
1246 | printk(KERN_INFO "%s: firmware is not compatible with S%u!\n", | ||
1247 | modname, hw->type); | ||
1248 | return -EINVAL; | ||
1249 | } | ||
1250 | |||
1251 | |||
1252 | /* Make sure there is enough on-board memory */ | ||
1253 | if (hw->memory < sfm->info.memsize) { | ||
1254 | printk(KERN_INFO | ||
1255 | "%s: firmware needs %lu bytes of on-board memory!\n", | ||
1256 | modname, sfm->info.memsize); | ||
1257 | return -EINVAL; | ||
1258 | } | ||
1259 | |||
1260 | /* Move code onto adapter */ | ||
1261 | if (sdla_poke(hw, sfm->info.codeoffs, sfm->image, sfm->info.codesize)) { | ||
1262 | printk(KERN_INFO "%s: failed to load code segment!\n", | ||
1263 | modname); | ||
1264 | return -EIO; | ||
1265 | } | ||
1266 | |||
1267 | /* Prepare boot-time configuration data and kick-off CPU */ | ||
1268 | sdla_bootcfg(hw, &sfm->info); | ||
1269 | if (sdla_start(hw, sfm->info.startoffs)) { | ||
1270 | printk(KERN_INFO "%s: Damn... Adapter won't start!\n", | ||
1271 | modname); | ||
1272 | return -EIO; | ||
1273 | } | ||
1274 | |||
1275 | /* position DPM window over the mailbox and enable interrupts */ | ||
1276 | if (sdla_mapmem(hw, sfm->info.winoffs) || sdla_inten(hw)) { | ||
1277 | printk(KERN_INFO "%s: adapter hardware failure!\n", | ||
1278 | modname); | ||
1279 | return -EIO; | ||
1280 | } | ||
1281 | hw->fwid = sfm->info.codeid; /* set firmware ID */ | ||
1282 | return 0; | ||
1283 | } | ||
1284 | |||
1285 | /*============================================================================ | ||
1286 | * Initialize SDLA hardware: setup memory window, IRQ, etc. | ||
1287 | */ | ||
1288 | static int sdla_init (sdlahw_t* hw) | ||
1289 | { | ||
1290 | int i; | ||
1291 | |||
1292 | for (i = 0; i < SDLA_MAXIORANGE; ++i) | ||
1293 | hw->regs[i] = 0; | ||
1294 | |||
1295 | switch (hw->type) { | ||
1296 | case SDLA_S502A: return init_s502a(hw); | ||
1297 | case SDLA_S502E: return init_s502e(hw); | ||
1298 | case SDLA_S503: return init_s503(hw); | ||
1299 | case SDLA_S507: return init_s507(hw); | ||
1300 | case SDLA_S508: return init_s508(hw); | ||
1301 | } | ||
1302 | return -EINVAL; | ||
1303 | } | ||
1304 | |||
1305 | /*============================================================================ | ||
1306 | * Test adapter on-board memory. | ||
1307 | * o slide DPM window from the bottom up and test adapter memory segment by | ||
1308 | * segment. | ||
1309 | * Return adapter memory size. | ||
1310 | */ | ||
1311 | static unsigned long sdla_memtest (sdlahw_t* hw) | ||
1312 | { | ||
1313 | unsigned long memsize; | ||
1314 | unsigned winsize; | ||
1315 | |||
1316 | for (memsize = 0, winsize = hw->dpmsize; | ||
1317 | !sdla_mapmem(hw, memsize) && | ||
1318 | (test_memregion(hw->dpmbase, winsize) == winsize) | ||
1319 | ; | ||
1320 | memsize += winsize) | ||
1321 | ; | ||
1322 | hw->memory = memsize; | ||
1323 | return memsize; | ||
1324 | } | ||
1325 | |||
1326 | /*============================================================================ | ||
1327 | * Prepare boot-time firmware configuration data. | ||
1328 | * o position DPM window | ||
1329 | * o initialize configuration data area | ||
1330 | */ | ||
1331 | static int sdla_bootcfg (sdlahw_t* hw, sfm_info_t* sfminfo) | ||
1332 | { | ||
1333 | unsigned char* data; | ||
1334 | |||
1335 | if (!sfminfo->datasize) return 0; /* nothing to do */ | ||
1336 | |||
1337 | if (sdla_mapmem(hw, sfminfo->dataoffs) != 0) | ||
1338 | return -EIO; | ||
1339 | |||
1340 | if(hw->type == SDLA_S514) | ||
1341 | data = (void*)(hw->dpmbase + sfminfo->dataoffs); | ||
1342 | else | ||
1343 | data = (void*)((u8 *)hw->dpmbase + | ||
1344 | (sfminfo->dataoffs - hw->vector)); | ||
1345 | |||
1346 | memset_io (data, 0, sfminfo->datasize); | ||
1347 | |||
1348 | writeb (make_config_byte(hw), &data[0x00]); | ||
1349 | |||
1350 | switch (sfminfo->codeid) { | ||
1351 | case SFID_X25_502: | ||
1352 | case SFID_X25_508: | ||
1353 | writeb (3, &data[0x01]); /* T1 timer */ | ||
1354 | writeb (10, &data[0x03]); /* N2 */ | ||
1355 | writeb (7, &data[0x06]); /* HDLC window size */ | ||
1356 | writeb (1, &data[0x0B]); /* DTE */ | ||
1357 | writeb (2, &data[0x0C]); /* X.25 packet window size */ | ||
1358 | writew (128, &data[0x0D]); /* default X.25 data size */ | ||
1359 | writew (128, &data[0x0F]); /* maximum X.25 data size */ | ||
1360 | break; | ||
1361 | } | ||
1362 | return 0; | ||
1363 | } | ||
1364 | |||
1365 | /*============================================================================ | ||
1366 | * Prepare configuration byte identifying adapter type and CPU clock rate. | ||
1367 | */ | ||
1368 | static unsigned char make_config_byte (sdlahw_t* hw) | ||
1369 | { | ||
1370 | unsigned char byte = 0; | ||
1371 | |||
1372 | switch (hw->pclk) { | ||
1373 | case 5000: byte = 0x01; break; | ||
1374 | case 7200: byte = 0x02; break; | ||
1375 | case 8000: byte = 0x03; break; | ||
1376 | case 10000: byte = 0x04; break; | ||
1377 | case 16000: byte = 0x05; break; | ||
1378 | } | ||
1379 | |||
1380 | switch (hw->type) { | ||
1381 | case SDLA_S502E: byte |= 0x80; break; | ||
1382 | case SDLA_S503: byte |= 0x40; break; | ||
1383 | } | ||
1384 | return byte; | ||
1385 | } | ||
1386 | |||
1387 | /*============================================================================ | ||
1388 | * Start adapter's CPU. | ||
1389 | * o calculate a pointer to adapter's cold boot entry point | ||
1390 | * o position DPM window | ||
1391 | * o place boot instruction (jp addr) at cold boot entry point | ||
1392 | * o start CPU | ||
1393 | */ | ||
1394 | static int sdla_start (sdlahw_t* hw, unsigned addr) | ||
1395 | { | ||
1396 | unsigned port = hw->port; | ||
1397 | unsigned char *bootp; | ||
1398 | int err, tmp, i; | ||
1399 | |||
1400 | if (!port && (hw->type != SDLA_S514)) return -EFAULT; | ||
1401 | |||
1402 | switch (hw->type) { | ||
1403 | case SDLA_S502A: | ||
1404 | bootp = hw->dpmbase; | ||
1405 | bootp += 0x66; | ||
1406 | break; | ||
1407 | |||
1408 | case SDLA_S502E: | ||
1409 | case SDLA_S503: | ||
1410 | case SDLA_S507: | ||
1411 | case SDLA_S508: | ||
1412 | case SDLA_S514: | ||
1413 | bootp = hw->dpmbase; | ||
1414 | break; | ||
1415 | |||
1416 | default: | ||
1417 | return -EINVAL; | ||
1418 | } | ||
1419 | |||
1420 | err = sdla_mapmem(hw, 0); | ||
1421 | if (err) return err; | ||
1422 | |||
1423 | writeb (0xC3, bootp); /* Z80: 'jp' opcode */ | ||
1424 | bootp ++; | ||
1425 | writew (addr, bootp); | ||
1426 | |||
1427 | switch (hw->type) { | ||
1428 | case SDLA_S502A: | ||
1429 | _OUTB(port, 0x10); /* issue NMI to CPU */ | ||
1430 | hw->regs[0] = 0x10; | ||
1431 | break; | ||
1432 | |||
1433 | case SDLA_S502E: | ||
1434 | _OUTB(port + 3, 0x01); /* start CPU */ | ||
1435 | hw->regs[3] = 0x01; | ||
1436 | for (i = 0; i < SDLA_IODELAY; ++i); | ||
1437 | if (_INB(port) & 0x01) { /* verify */ | ||
1438 | /* | ||
1439 | * Enabling CPU changes functionality of the | ||
1440 | * control register, so we have to reset its | ||
1441 | * mirror. | ||
1442 | */ | ||
1443 | _OUTB(port, 0); /* disable interrupts */ | ||
1444 | hw->regs[0] = 0; | ||
1445 | } | ||
1446 | else return -EIO; | ||
1447 | break; | ||
1448 | |||
1449 | case SDLA_S503: | ||
1450 | tmp = hw->regs[0] | 0x09; /* set bits 0 and 3 */ | ||
1451 | _OUTB(port, tmp); | ||
1452 | hw->regs[0] = tmp; /* update mirror */ | ||
1453 | for (i = 0; i < SDLA_IODELAY; ++i); | ||
1454 | if (!(_INB(port) & 0x01)) /* verify */ | ||
1455 | return -EIO; | ||
1456 | break; | ||
1457 | |||
1458 | case SDLA_S507: | ||
1459 | tmp = hw->regs[0] | 0x02; | ||
1460 | _OUTB(port, tmp); | ||
1461 | hw->regs[0] = tmp; /* update mirror */ | ||
1462 | for (i = 0; i < SDLA_IODELAY; ++i); | ||
1463 | if (!(_INB(port) & 0x04)) /* verify */ | ||
1464 | return -EIO; | ||
1465 | break; | ||
1466 | |||
1467 | case SDLA_S508: | ||
1468 | tmp = hw->regs[0] | 0x02; | ||
1469 | _OUTB(port, tmp); | ||
1470 | hw->regs[0] = tmp; /* update mirror */ | ||
1471 | for (i = 0; i < SDLA_IODELAY; ++i); | ||
1472 | if (!(_INB(port + 1) & 0x02)) /* verify */ | ||
1473 | return -EIO; | ||
1474 | break; | ||
1475 | |||
1476 | case SDLA_S514: | ||
1477 | writeb (S514_CPU_START, hw->vector); | ||
1478 | break; | ||
1479 | |||
1480 | default: | ||
1481 | return -EINVAL; | ||
1482 | } | ||
1483 | return 0; | ||
1484 | } | ||
1485 | |||
1486 | /*============================================================================ | ||
1487 | * Initialize S502A adapter. | ||
1488 | */ | ||
1489 | static int init_s502a (sdlahw_t* hw) | ||
1490 | { | ||
1491 | unsigned port = hw->port; | ||
1492 | int tmp, i; | ||
1493 | |||
1494 | if (!detect_s502a(port)) | ||
1495 | return -ENODEV; | ||
1496 | |||
1497 | hw->regs[0] = 0x08; | ||
1498 | hw->regs[1] = 0xFF; | ||
1499 | |||
1500 | /* Verify configuration options */ | ||
1501 | i = get_option_index(s502a_dpmbase_options, virt_to_phys(hw->dpmbase)); | ||
1502 | if (i == 0) | ||
1503 | return -EINVAL; | ||
1504 | |||
1505 | tmp = s502a_hmcr[i - 1]; | ||
1506 | switch (hw->dpmsize) { | ||
1507 | case 0x2000: | ||
1508 | tmp |= 0x01; | ||
1509 | break; | ||
1510 | |||
1511 | case 0x10000L: | ||
1512 | break; | ||
1513 | |||
1514 | default: | ||
1515 | return -EINVAL; | ||
1516 | } | ||
1517 | |||
1518 | /* Setup dual-port memory window (this also enables memory access) */ | ||
1519 | _OUTB(port + 1, tmp); | ||
1520 | hw->regs[1] = tmp; | ||
1521 | hw->regs[0] = 0x08; | ||
1522 | return 0; | ||
1523 | } | ||
1524 | |||
1525 | /*============================================================================ | ||
1526 | * Initialize S502E adapter. | ||
1527 | */ | ||
1528 | static int init_s502e (sdlahw_t* hw) | ||
1529 | { | ||
1530 | unsigned port = hw->port; | ||
1531 | int tmp, i; | ||
1532 | |||
1533 | if (!detect_s502e(port)) | ||
1534 | return -ENODEV; | ||
1535 | |||
1536 | /* Verify configuration options */ | ||
1537 | i = get_option_index(s508_dpmbase_options, virt_to_phys(hw->dpmbase)); | ||
1538 | if (i == 0) | ||
1539 | return -EINVAL; | ||
1540 | |||
1541 | tmp = s502e_hmcr[i - 1]; | ||
1542 | switch (hw->dpmsize) { | ||
1543 | case 0x2000: | ||
1544 | tmp |= 0x01; | ||
1545 | break; | ||
1546 | |||
1547 | case 0x10000L: | ||
1548 | break; | ||
1549 | |||
1550 | default: | ||
1551 | return -EINVAL; | ||
1552 | } | ||
1553 | |||
1554 | /* Setup dual-port memory window */ | ||
1555 | _OUTB(port + 1, tmp); | ||
1556 | hw->regs[1] = tmp; | ||
1557 | |||
1558 | /* Enable memory access */ | ||
1559 | _OUTB(port, 0x02); | ||
1560 | hw->regs[0] = 0x02; | ||
1561 | for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ | ||
1562 | return (_INB(port) & 0x02) ? 0 : -EIO; | ||
1563 | } | ||
1564 | |||
1565 | /*============================================================================ | ||
1566 | * Initialize S503 adapter. | ||
1567 | * --------------------------------------------------------------------------- | ||
1568 | */ | ||
1569 | static int init_s503 (sdlahw_t* hw) | ||
1570 | { | ||
1571 | unsigned port = hw->port; | ||
1572 | int tmp, i; | ||
1573 | |||
1574 | if (!detect_s503(port)) | ||
1575 | return -ENODEV; | ||
1576 | |||
1577 | /* Verify configuration options */ | ||
1578 | i = get_option_index(s508_dpmbase_options, virt_to_phys(hw->dpmbase)); | ||
1579 | if (i == 0) | ||
1580 | return -EINVAL; | ||
1581 | |||
1582 | tmp = s502e_hmcr[i - 1]; | ||
1583 | switch (hw->dpmsize) { | ||
1584 | case 0x2000: | ||
1585 | tmp |= 0x01; | ||
1586 | break; | ||
1587 | |||
1588 | case 0x10000L: | ||
1589 | break; | ||
1590 | |||
1591 | default: | ||
1592 | return -EINVAL; | ||
1593 | } | ||
1594 | |||
1595 | /* Setup dual-port memory window */ | ||
1596 | _OUTB(port + 1, tmp); | ||
1597 | hw->regs[1] = tmp; | ||
1598 | |||
1599 | /* Enable memory access */ | ||
1600 | _OUTB(port, 0x02); | ||
1601 | hw->regs[0] = 0x02; /* update mirror */ | ||
1602 | return 0; | ||
1603 | } | ||
1604 | |||
1605 | /*============================================================================ | ||
1606 | * Initialize S507 adapter. | ||
1607 | */ | ||
1608 | static int init_s507 (sdlahw_t* hw) | ||
1609 | { | ||
1610 | unsigned port = hw->port; | ||
1611 | int tmp, i; | ||
1612 | |||
1613 | if (!detect_s507(port)) | ||
1614 | return -ENODEV; | ||
1615 | |||
1616 | /* Verify configuration options */ | ||
1617 | i = get_option_index(s507_dpmbase_options, virt_to_phys(hw->dpmbase)); | ||
1618 | if (i == 0) | ||
1619 | return -EINVAL; | ||
1620 | |||
1621 | tmp = s507_hmcr[i - 1]; | ||
1622 | switch (hw->dpmsize) { | ||
1623 | case 0x2000: | ||
1624 | tmp |= 0x01; | ||
1625 | break; | ||
1626 | |||
1627 | case 0x10000L: | ||
1628 | break; | ||
1629 | |||
1630 | default: | ||
1631 | return -EINVAL; | ||
1632 | } | ||
1633 | |||
1634 | /* Enable adapter's logic */ | ||
1635 | _OUTB(port, 0x01); | ||
1636 | hw->regs[0] = 0x01; | ||
1637 | for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ | ||
1638 | if (!(_INB(port) & 0x20)) | ||
1639 | return -EIO; | ||
1640 | |||
1641 | /* Setup dual-port memory window */ | ||
1642 | _OUTB(port + 1, tmp); | ||
1643 | hw->regs[1] = tmp; | ||
1644 | |||
1645 | /* Enable memory access */ | ||
1646 | tmp = hw->regs[0] | 0x04; | ||
1647 | if (hw->irq) { | ||
1648 | i = get_option_index(s508_irq_options, hw->irq); | ||
1649 | if (i) tmp |= s507_irqmask[i - 1]; | ||
1650 | } | ||
1651 | _OUTB(port, tmp); | ||
1652 | hw->regs[0] = tmp; /* update mirror */ | ||
1653 | for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ | ||
1654 | return (_INB(port) & 0x08) ? 0 : -EIO; | ||
1655 | } | ||
1656 | |||
1657 | /*============================================================================ | ||
1658 | * Initialize S508 adapter. | ||
1659 | */ | ||
1660 | static int init_s508 (sdlahw_t* hw) | ||
1661 | { | ||
1662 | unsigned port = hw->port; | ||
1663 | int tmp, i; | ||
1664 | |||
1665 | if (!detect_s508(port)) | ||
1666 | return -ENODEV; | ||
1667 | |||
1668 | /* Verify configuration options */ | ||
1669 | i = get_option_index(s508_dpmbase_options, virt_to_phys(hw->dpmbase)); | ||
1670 | if (i == 0) | ||
1671 | return -EINVAL; | ||
1672 | |||
1673 | /* Setup memory configuration */ | ||
1674 | tmp = s508_hmcr[i - 1]; | ||
1675 | _OUTB(port + 1, tmp); | ||
1676 | hw->regs[1] = tmp; | ||
1677 | |||
1678 | /* Enable memory access */ | ||
1679 | _OUTB(port, 0x04); | ||
1680 | hw->regs[0] = 0x04; /* update mirror */ | ||
1681 | for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ | ||
1682 | return (_INB(port + 1) & 0x04) ? 0 : -EIO; | ||
1683 | } | ||
1684 | |||
1685 | /*============================================================================ | ||
1686 | * Detect S502A adapter. | ||
1687 | * Following tests are used to detect S502A adapter: | ||
1688 | * 1. All registers other than status (BASE) should read 0xFF | ||
1689 | * 2. After writing 00001000b to control register, status register should | ||
1690 | * read 01000000b. | ||
1691 | * 3. After writing 0 to control register, status register should still | ||
1692 | * read 01000000b. | ||
1693 | * 4. After writing 00000100b to control register, status register should | ||
1694 | * read 01000100b. | ||
1695 | * Return 1 if detected o.k. or 0 if failed. | ||
1696 | * Note: This test is destructive! Adapter will be left in shutdown | ||
1697 | * state after the test. | ||
1698 | */ | ||
1699 | static int detect_s502a (int port) | ||
1700 | { | ||
1701 | int i, j; | ||
1702 | |||
1703 | if (!get_option_index(s502_port_options, port)) | ||
1704 | return 0; | ||
1705 | |||
1706 | for (j = 1; j < SDLA_MAXIORANGE; ++j) { | ||
1707 | if (_INB(port + j) != 0xFF) | ||
1708 | return 0; | ||
1709 | for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ | ||
1710 | } | ||
1711 | |||
1712 | _OUTB(port, 0x08); /* halt CPU */ | ||
1713 | _OUTB(port, 0x08); | ||
1714 | _OUTB(port, 0x08); | ||
1715 | for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ | ||
1716 | if (_INB(port) != 0x40) | ||
1717 | return 0; | ||
1718 | _OUTB(port, 0x00); | ||
1719 | for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ | ||
1720 | if (_INB(port) != 0x40) | ||
1721 | return 0; | ||
1722 | _OUTB(port, 0x04); | ||
1723 | for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ | ||
1724 | if (_INB(port) != 0x44) | ||
1725 | return 0; | ||
1726 | |||
1727 | /* Reset adapter */ | ||
1728 | _OUTB(port, 0x08); | ||
1729 | _OUTB(port, 0x08); | ||
1730 | _OUTB(port, 0x08); | ||
1731 | _OUTB(port + 1, 0xFF); | ||
1732 | return 1; | ||
1733 | } | ||
1734 | |||
1735 | /*============================================================================ | ||
1736 | * Detect S502E adapter. | ||
1737 | * Following tests are used to verify adapter presence: | ||
1738 | * 1. All registers other than status (BASE) should read 0xFF. | ||
1739 | * 2. After writing 0 to CPU control register (BASE+3), status register | ||
1740 | * (BASE) should read 11111000b. | ||
1741 | * 3. After writing 00000100b to port BASE (set bit 2), status register | ||
1742 | * (BASE) should read 11111100b. | ||
1743 | * Return 1 if detected o.k. or 0 if failed. | ||
1744 | * Note: This test is destructive! Adapter will be left in shutdown | ||
1745 | * state after the test. | ||
1746 | */ | ||
1747 | static int detect_s502e (int port) | ||
1748 | { | ||
1749 | int i, j; | ||
1750 | |||
1751 | if (!get_option_index(s502_port_options, port)) | ||
1752 | return 0; | ||
1753 | for (j = 1; j < SDLA_MAXIORANGE; ++j) { | ||
1754 | if (_INB(port + j) != 0xFF) | ||
1755 | return 0; | ||
1756 | for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ | ||
1757 | } | ||
1758 | |||
1759 | _OUTB(port + 3, 0); /* CPU control reg. */ | ||
1760 | for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ | ||
1761 | if (_INB(port) != 0xF8) /* read status */ | ||
1762 | return 0; | ||
1763 | _OUTB(port, 0x04); /* set bit 2 */ | ||
1764 | for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ | ||
1765 | if (_INB(port) != 0xFC) /* verify */ | ||
1766 | return 0; | ||
1767 | |||
1768 | /* Reset adapter */ | ||
1769 | _OUTB(port, 0); | ||
1770 | return 1; | ||
1771 | } | ||
1772 | |||
1773 | /*============================================================================ | ||
1774 | * Detect s503 adapter. | ||
1775 | * Following tests are used to verify adapter presence: | ||
1776 | * 1. All registers other than status (BASE) should read 0xFF. | ||
1777 | * 2. After writing 0 to control register (BASE), status register (BASE) | ||
1778 | * should read 11110000b. | ||
1779 | * 3. After writing 00000100b (set bit 2) to control register (BASE), | ||
1780 | * status register should read 11110010b. | ||
1781 | * Return 1 if detected o.k. or 0 if failed. | ||
1782 | * Note: This test is destructive! Adapter will be left in shutdown | ||
1783 | * state after the test. | ||
1784 | */ | ||
1785 | static int detect_s503 (int port) | ||
1786 | { | ||
1787 | int i, j; | ||
1788 | |||
1789 | if (!get_option_index(s503_port_options, port)) | ||
1790 | return 0; | ||
1791 | for (j = 1; j < SDLA_MAXIORANGE; ++j) { | ||
1792 | if (_INB(port + j) != 0xFF) | ||
1793 | return 0; | ||
1794 | for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ | ||
1795 | } | ||
1796 | |||
1797 | _OUTB(port, 0); /* reset control reg.*/ | ||
1798 | for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ | ||
1799 | if (_INB(port) != 0xF0) /* read status */ | ||
1800 | return 0; | ||
1801 | _OUTB(port, 0x04); /* set bit 2 */ | ||
1802 | for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ | ||
1803 | if (_INB(port) != 0xF2) /* verify */ | ||
1804 | return 0; | ||
1805 | |||
1806 | /* Reset adapter */ | ||
1807 | _OUTB(port, 0); | ||
1808 | return 1; | ||
1809 | } | ||
1810 | |||
1811 | /*============================================================================ | ||
1812 | * Detect s507 adapter. | ||
1813 | * Following tests are used to detect s507 adapter: | ||
1814 | * 1. All ports should read the same value. | ||
1815 | * 2. After writing 0x00 to control register, status register should read | ||
1816 | * ?011000?b. | ||
1817 | * 3. After writing 0x01 to control register, status register should read | ||
1818 | * ?011001?b. | ||
1819 | * Return 1 if detected o.k. or 0 if failed. | ||
1820 | * Note: This test is destructive! Adapter will be left in shutdown | ||
1821 | * state after the test. | ||
1822 | */ | ||
1823 | static int detect_s507 (int port) | ||
1824 | { | ||
1825 | int tmp, i, j; | ||
1826 | |||
1827 | if (!get_option_index(s508_port_options, port)) | ||
1828 | return 0; | ||
1829 | tmp = _INB(port); | ||
1830 | for (j = 1; j < S507_IORANGE; ++j) { | ||
1831 | if (_INB(port + j) != tmp) | ||
1832 | return 0; | ||
1833 | for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ | ||
1834 | } | ||
1835 | |||
1836 | _OUTB(port, 0x00); | ||
1837 | for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ | ||
1838 | if ((_INB(port) & 0x7E) != 0x30) | ||
1839 | return 0; | ||
1840 | _OUTB(port, 0x01); | ||
1841 | for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ | ||
1842 | if ((_INB(port) & 0x7E) != 0x32) | ||
1843 | return 0; | ||
1844 | |||
1845 | /* Reset adapter */ | ||
1846 | _OUTB(port, 0x00); | ||
1847 | return 1; | ||
1848 | } | ||
1849 | |||
1850 | /*============================================================================ | ||
1851 | * Detect s508 adapter. | ||
1852 | * Following tests are used to detect s508 adapter: | ||
1853 | * 1. After writing 0x00 to control register, status register should read | ||
1854 | * ??000000b. | ||
1855 | * 2. After writing 0x10 to control register, status register should read | ||
1856 | * ??010000b | ||
1857 | * Return 1 if detected o.k. or 0 if failed. | ||
1858 | * Note: This test is destructive! Adapter will be left in shutdown | ||
1859 | * state after the test. | ||
1860 | */ | ||
1861 | static int detect_s508 (int port) | ||
1862 | { | ||
1863 | int i; | ||
1864 | |||
1865 | if (!get_option_index(s508_port_options, port)) | ||
1866 | return 0; | ||
1867 | _OUTB(port, 0x00); | ||
1868 | for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ | ||
1869 | if ((_INB(port + 1) & 0x3F) != 0x00) | ||
1870 | return 0; | ||
1871 | _OUTB(port, 0x10); | ||
1872 | for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ | ||
1873 | if ((_INB(port + 1) & 0x3F) != 0x10) | ||
1874 | return 0; | ||
1875 | |||
1876 | /* Reset adapter */ | ||
1877 | _OUTB(port, 0x00); | ||
1878 | return 1; | ||
1879 | } | ||
1880 | |||
1881 | /*============================================================================ | ||
1882 | * Detect s514 PCI adapter. | ||
1883 | * Return 1 if detected o.k. or 0 if failed. | ||
1884 | * Note: This test is destructive! Adapter will be left in shutdown | ||
1885 | * state after the test. | ||
1886 | */ | ||
1887 | static int detect_s514 (sdlahw_t* hw) | ||
1888 | { | ||
1889 | unsigned char CPU_no, slot_no, auto_slot_cfg; | ||
1890 | int number_S514_cards = 0; | ||
1891 | u32 S514_mem_base_addr = 0; | ||
1892 | u32 ut_u32; | ||
1893 | struct pci_dev *pci_dev; | ||
1894 | |||
1895 | |||
1896 | #ifndef CONFIG_PCI | ||
1897 | printk(KERN_INFO "%s: Linux not compiled for PCI usage!\n", modname); | ||
1898 | return 0; | ||
1899 | #endif | ||
1900 | |||
1901 | /* | ||
1902 | The 'setup()' procedure in 'sdlamain.c' passes the CPU number and the | ||
1903 | slot number defined in 'router.conf' via the 'port' definition. | ||
1904 | */ | ||
1905 | CPU_no = hw->S514_cpu_no[0]; | ||
1906 | slot_no = hw->S514_slot_no; | ||
1907 | auto_slot_cfg = hw->auto_pci_cfg; | ||
1908 | |||
1909 | if (auto_slot_cfg){ | ||
1910 | printk(KERN_INFO "%s: srch... S514 card, CPU %c, Slot=Auto\n", | ||
1911 | modname, CPU_no); | ||
1912 | |||
1913 | }else{ | ||
1914 | printk(KERN_INFO "%s: srch... S514 card, CPU %c, Slot #%d\n", | ||
1915 | modname, CPU_no, slot_no); | ||
1916 | } | ||
1917 | |||
1918 | /* check to see that CPU A or B has been selected in 'router.conf' */ | ||
1919 | switch(CPU_no) { | ||
1920 | case S514_CPU_A: | ||
1921 | case S514_CPU_B: | ||
1922 | break; | ||
1923 | |||
1924 | default: | ||
1925 | printk(KERN_INFO "%s: S514 CPU definition invalid.\n", | ||
1926 | modname); | ||
1927 | printk(KERN_INFO "Must be 'A' or 'B'\n"); | ||
1928 | return 0; | ||
1929 | } | ||
1930 | |||
1931 | number_S514_cards = find_s514_adapter(hw, 0); | ||
1932 | if(!number_S514_cards) | ||
1933 | return 0; | ||
1934 | |||
1935 | /* we are using a single S514 adapter with a slot of 0 so re-read the */ | ||
1936 | /* location of this adapter */ | ||
1937 | if((number_S514_cards == 1) && auto_slot_cfg) { | ||
1938 | number_S514_cards = find_s514_adapter(hw, 1); | ||
1939 | if(!number_S514_cards) { | ||
1940 | printk(KERN_INFO "%s: Error finding PCI card\n", | ||
1941 | modname); | ||
1942 | return 0; | ||
1943 | } | ||
1944 | } | ||
1945 | |||
1946 | pci_dev = hw->pci_dev; | ||
1947 | /* read the physical memory base address */ | ||
1948 | S514_mem_base_addr = (CPU_no == S514_CPU_A) ? | ||
1949 | (pci_dev->resource[1].start) : | ||
1950 | (pci_dev->resource[2].start); | ||
1951 | |||
1952 | printk(KERN_INFO "%s: S514 PCI memory at 0x%X\n", | ||
1953 | modname, S514_mem_base_addr); | ||
1954 | if(!S514_mem_base_addr) { | ||
1955 | if(CPU_no == S514_CPU_B) | ||
1956 | printk(KERN_INFO "%s: CPU #B not present on the card\n", modname); | ||
1957 | else | ||
1958 | printk(KERN_INFO "%s: No PCI memory allocated to card\n", modname); | ||
1959 | return 0; | ||
1960 | } | ||
1961 | |||
1962 | /* enable the PCI memory */ | ||
1963 | pci_read_config_dword(pci_dev, | ||
1964 | (CPU_no == S514_CPU_A) ? PCI_MAP0_DWORD : PCI_MAP1_DWORD, | ||
1965 | &ut_u32); | ||
1966 | pci_write_config_dword(pci_dev, | ||
1967 | (CPU_no == S514_CPU_A) ? PCI_MAP0_DWORD : PCI_MAP1_DWORD, | ||
1968 | (ut_u32 | PCI_MEMORY_ENABLE)); | ||
1969 | |||
1970 | /* check the IRQ allocated and enable IRQ usage */ | ||
1971 | if(!(hw->irq = pci_dev->irq)) { | ||
1972 | printk(KERN_INFO "%s: IRQ not allocated to S514 adapter\n", | ||
1973 | modname); | ||
1974 | return 0; | ||
1975 | } | ||
1976 | |||
1977 | /* BUG FIX : Mar 6 2000 | ||
1978 | * On a initial loading of the card, we must check | ||
1979 | * and clear PCI interrupt bits, due to a reset | ||
1980 | * problem on some other boards. i.e. An interrupt | ||
1981 | * might be pending, even after system bootup, | ||
1982 | * in which case, when starting wanrouter the machine | ||
1983 | * would crash. | ||
1984 | */ | ||
1985 | if (init_pci_slot(hw)) | ||
1986 | return 0; | ||
1987 | |||
1988 | pci_read_config_dword(pci_dev, PCI_INT_CONFIG, &ut_u32); | ||
1989 | ut_u32 |= (CPU_no == S514_CPU_A) ? | ||
1990 | PCI_ENABLE_IRQ_CPU_A : PCI_ENABLE_IRQ_CPU_B; | ||
1991 | pci_write_config_dword(pci_dev, PCI_INT_CONFIG, ut_u32); | ||
1992 | |||
1993 | printk(KERN_INFO "%s: IRQ %d allocated to the S514 card\n", | ||
1994 | modname, hw->irq); | ||
1995 | |||
1996 | /* map the physical PCI memory to virtual memory */ | ||
1997 | hw->dpmbase = ioremap((unsigned long)S514_mem_base_addr, | ||
1998 | (unsigned long)MAX_SIZEOF_S514_MEMORY); | ||
1999 | /* map the physical control register memory to virtual memory */ | ||
2000 | hw->vector = (unsigned long)ioremap( | ||
2001 | (unsigned long)(S514_mem_base_addr + S514_CTRL_REG_BYTE), | ||
2002 | (unsigned long)16); | ||
2003 | |||
2004 | if(!hw->dpmbase || !hw->vector) { | ||
2005 | printk(KERN_INFO "%s: PCI virtual memory allocation failed\n", | ||
2006 | modname); | ||
2007 | return 0; | ||
2008 | } | ||
2009 | |||
2010 | /* halt the adapter */ | ||
2011 | writeb (S514_CPU_HALT, hw->vector); | ||
2012 | |||
2013 | return 1; | ||
2014 | } | ||
2015 | |||
2016 | /*============================================================================ | ||
2017 | * Find the S514 PCI adapter in the PCI bus. | ||
2018 | * Return the number of S514 adapters found (0 if no adapter found). | ||
2019 | */ | ||
2020 | static int find_s514_adapter(sdlahw_t* hw, char find_first_S514_card) | ||
2021 | { | ||
2022 | unsigned char slot_no; | ||
2023 | int number_S514_cards = 0; | ||
2024 | char S514_found_in_slot = 0; | ||
2025 | u16 PCI_subsys_vendor; | ||
2026 | |||
2027 | struct pci_dev *pci_dev = NULL; | ||
2028 | |||
2029 | slot_no = hw->S514_slot_no; | ||
2030 | |||
2031 | while ((pci_dev = pci_find_device(V3_VENDOR_ID, V3_DEVICE_ID, pci_dev)) | ||
2032 | != NULL) { | ||
2033 | |||
2034 | pci_read_config_word(pci_dev, PCI_SUBSYS_VENDOR_WORD, | ||
2035 | &PCI_subsys_vendor); | ||
2036 | |||
2037 | if(PCI_subsys_vendor != SANGOMA_SUBSYS_VENDOR) | ||
2038 | continue; | ||
2039 | |||
2040 | hw->pci_dev = pci_dev; | ||
2041 | |||
2042 | if(find_first_S514_card) | ||
2043 | return(1); | ||
2044 | |||
2045 | number_S514_cards ++; | ||
2046 | |||
2047 | printk(KERN_INFO | ||
2048 | "%s: S514 card found, slot #%d (devfn 0x%X)\n", | ||
2049 | modname, ((pci_dev->devfn >> 3) & PCI_DEV_SLOT_MASK), | ||
2050 | pci_dev->devfn); | ||
2051 | |||
2052 | if (hw->auto_pci_cfg){ | ||
2053 | hw->S514_slot_no = ((pci_dev->devfn >> 3) & PCI_DEV_SLOT_MASK); | ||
2054 | slot_no = hw->S514_slot_no; | ||
2055 | |||
2056 | }else if (((pci_dev->devfn >> 3) & PCI_DEV_SLOT_MASK) == slot_no){ | ||
2057 | S514_found_in_slot = 1; | ||
2058 | break; | ||
2059 | } | ||
2060 | } | ||
2061 | |||
2062 | /* if no S514 adapter has been found, then exit */ | ||
2063 | if (!number_S514_cards) { | ||
2064 | printk(KERN_INFO "%s: Error, no S514 adapters found\n", modname); | ||
2065 | return 0; | ||
2066 | } | ||
2067 | /* if more than one S514 card has been found, then the user must have */ /* defined a slot number so that the correct adapter is used */ | ||
2068 | else if ((number_S514_cards > 1) && hw->auto_pci_cfg) { | ||
2069 | printk(KERN_INFO "%s: Error, PCI Slot autodetect Failed! \n" | ||
2070 | "%s: More than one S514 adapter found.\n" | ||
2071 | "%s: Disable the Autodetect feature and supply\n" | ||
2072 | "%s: the PCISLOT numbers for each card.\n", | ||
2073 | modname,modname,modname,modname); | ||
2074 | return 0; | ||
2075 | } | ||
2076 | /* if the user has specified a slot number and the S514 adapter has */ | ||
2077 | /* not been found in that slot, then exit */ | ||
2078 | else if (!hw->auto_pci_cfg && !S514_found_in_slot) { | ||
2079 | printk(KERN_INFO | ||
2080 | "%s: Error, S514 card not found in specified slot #%d\n", | ||
2081 | modname, slot_no); | ||
2082 | return 0; | ||
2083 | } | ||
2084 | |||
2085 | return (number_S514_cards); | ||
2086 | } | ||
2087 | |||
2088 | |||
2089 | |||
2090 | /******* Miscellaneous ******************************************************/ | ||
2091 | |||
2092 | /*============================================================================ | ||
2093 | * Calibrate SDLA memory access delay. | ||
2094 | * Count number of idle loops made within 1 second and then calculate the | ||
2095 | * number of loops that should be made to achive desired delay. | ||
2096 | */ | ||
2097 | static int calibrate_delay (int mks) | ||
2098 | { | ||
2099 | unsigned int delay; | ||
2100 | unsigned long stop; | ||
2101 | |||
2102 | for (delay = 0, stop = SYSTEM_TICK + HZ; SYSTEM_TICK < stop; ++delay); | ||
2103 | return (delay/(1000000L/mks) + 1); | ||
2104 | } | ||
2105 | |||
2106 | /*============================================================================ | ||
2107 | * Get option's index into the options list. | ||
2108 | * Return option's index (1 .. N) or zero if option is invalid. | ||
2109 | */ | ||
2110 | static int get_option_index (unsigned* optlist, unsigned optval) | ||
2111 | { | ||
2112 | int i; | ||
2113 | |||
2114 | for (i = 1; i <= optlist[0]; ++i) | ||
2115 | if ( optlist[i] == optval) | ||
2116 | return i; | ||
2117 | return 0; | ||
2118 | } | ||
2119 | |||
2120 | /*============================================================================ | ||
2121 | * Check memory region to see if it's available. | ||
2122 | * Return: 0 ok. | ||
2123 | */ | ||
2124 | static unsigned check_memregion (void* ptr, unsigned len) | ||
2125 | { | ||
2126 | volatile unsigned char* p = ptr; | ||
2127 | |||
2128 | for (; len && (readb (p) == 0xFF); --len, ++p) { | ||
2129 | writeb (0, p); /* attempt to write 0 */ | ||
2130 | if (readb(p) != 0xFF) { /* still has to read 0xFF */ | ||
2131 | writeb (0xFF, p);/* restore original value */ | ||
2132 | break; /* not good */ | ||
2133 | } | ||
2134 | } | ||
2135 | |||
2136 | return len; | ||
2137 | } | ||
2138 | |||
2139 | /*============================================================================ | ||
2140 | * Test memory region. | ||
2141 | * Return: size of the region that passed the test. | ||
2142 | * Note: Region size must be multiple of 2 ! | ||
2143 | */ | ||
2144 | static unsigned test_memregion (void* ptr, unsigned len) | ||
2145 | { | ||
2146 | volatile unsigned short* w_ptr; | ||
2147 | unsigned len_w = len >> 1; /* region len in words */ | ||
2148 | unsigned i; | ||
2149 | |||
2150 | for (i = 0, w_ptr = ptr; i < len_w; ++i, ++w_ptr) | ||
2151 | writew (0xAA55, w_ptr); | ||
2152 | |||
2153 | for (i = 0, w_ptr = ptr; i < len_w; ++i, ++w_ptr) | ||
2154 | if (readw (w_ptr) != 0xAA55) { | ||
2155 | len_w = i; | ||
2156 | break; | ||
2157 | } | ||
2158 | |||
2159 | for (i = 0, w_ptr = ptr; i < len_w; ++i, ++w_ptr) | ||
2160 | writew (0x55AA, w_ptr); | ||
2161 | |||
2162 | for (i = 0, w_ptr = ptr; i < len_w; ++i, ++w_ptr) | ||
2163 | if (readw(w_ptr) != 0x55AA) { | ||
2164 | len_w = i; | ||
2165 | break; | ||
2166 | } | ||
2167 | |||
2168 | for (i = 0, w_ptr = ptr; i < len_w; ++i, ++w_ptr) | ||
2169 | writew (0, w_ptr); | ||
2170 | |||
2171 | return len_w << 1; | ||
2172 | } | ||
2173 | |||
2174 | /*============================================================================ | ||
2175 | * Calculate 16-bit CRC using CCITT polynomial. | ||
2176 | */ | ||
2177 | static unsigned short checksum (unsigned char* buf, unsigned len) | ||
2178 | { | ||
2179 | unsigned short crc = 0; | ||
2180 | unsigned mask, flag; | ||
2181 | |||
2182 | for (; len; --len, ++buf) { | ||
2183 | for (mask = 0x80; mask; mask >>= 1) { | ||
2184 | flag = (crc & 0x8000); | ||
2185 | crc <<= 1; | ||
2186 | crc |= ((*buf & mask) ? 1 : 0); | ||
2187 | if (flag) crc ^= 0x1021; | ||
2188 | } | ||
2189 | } | ||
2190 | return crc; | ||
2191 | } | ||
2192 | |||
2193 | static int init_pci_slot(sdlahw_t *hw) | ||
2194 | { | ||
2195 | |||
2196 | u32 int_status; | ||
2197 | int volatile found=0; | ||
2198 | int i=0; | ||
2199 | |||
2200 | /* Check if this is a very first load for a specific | ||
2201 | * pci card. If it is, clear the interrput bits, and | ||
2202 | * set the flag indicating that this card was initialized. | ||
2203 | */ | ||
2204 | |||
2205 | for (i=0; (i<MAX_S514_CARDS) && !found; i++){ | ||
2206 | if (pci_slot_ar[i] == hw->S514_slot_no){ | ||
2207 | found=1; | ||
2208 | break; | ||
2209 | } | ||
2210 | if (pci_slot_ar[i] == 0xFF){ | ||
2211 | break; | ||
2212 | } | ||
2213 | } | ||
2214 | |||
2215 | if (!found){ | ||
2216 | read_S514_int_stat(hw,&int_status); | ||
2217 | S514_intack(hw,int_status); | ||
2218 | if (i == MAX_S514_CARDS){ | ||
2219 | printk(KERN_INFO "%s: Critical Error !!!\n",modname); | ||
2220 | printk(KERN_INFO | ||
2221 | "%s: Number of Sangoma PCI cards exceeded maximum limit.\n", | ||
2222 | modname); | ||
2223 | printk(KERN_INFO "Please contact Sangoma Technologies\n"); | ||
2224 | return 1; | ||
2225 | } | ||
2226 | pci_slot_ar[i] = hw->S514_slot_no; | ||
2227 | } | ||
2228 | return 0; | ||
2229 | } | ||
2230 | |||
2231 | static int pci_probe(sdlahw_t *hw) | ||
2232 | { | ||
2233 | |||
2234 | unsigned char slot_no; | ||
2235 | int number_S514_cards = 0; | ||
2236 | u16 PCI_subsys_vendor; | ||
2237 | u16 PCI_card_type; | ||
2238 | |||
2239 | struct pci_dev *pci_dev = NULL; | ||
2240 | struct pci_bus *bus = NULL; | ||
2241 | |||
2242 | slot_no = 0; | ||
2243 | |||
2244 | while ((pci_dev = pci_find_device(V3_VENDOR_ID, V3_DEVICE_ID, pci_dev)) | ||
2245 | != NULL) { | ||
2246 | |||
2247 | pci_read_config_word(pci_dev, PCI_SUBSYS_VENDOR_WORD, | ||
2248 | &PCI_subsys_vendor); | ||
2249 | |||
2250 | if(PCI_subsys_vendor != SANGOMA_SUBSYS_VENDOR) | ||
2251 | continue; | ||
2252 | |||
2253 | pci_read_config_word(pci_dev, PCI_CARD_TYPE, | ||
2254 | &PCI_card_type); | ||
2255 | |||
2256 | bus = pci_dev->bus; | ||
2257 | |||
2258 | /* A dual cpu card can support up to 4 physical connections, | ||
2259 | * where a single cpu card can support up to 2 physical | ||
2260 | * connections. The FT1 card can only support a single | ||
2261 | * connection, however we cannot distinguish between a Single | ||
2262 | * CPU card and an FT1 card. */ | ||
2263 | if (PCI_card_type == S514_DUAL_CPU){ | ||
2264 | number_S514_cards += 4; | ||
2265 | printk(KERN_INFO | ||
2266 | "wanpipe: S514-PCI card found, cpu(s) 2, bus #%d, slot #%d, irq #%d\n", | ||
2267 | bus->number,((pci_dev->devfn >> 3) & PCI_DEV_SLOT_MASK), | ||
2268 | pci_dev->irq); | ||
2269 | }else{ | ||
2270 | number_S514_cards += 2; | ||
2271 | printk(KERN_INFO | ||
2272 | "wanpipe: S514-PCI card found, cpu(s) 1, bus #%d, slot #%d, irq #%d\n", | ||
2273 | bus->number,((pci_dev->devfn >> 3) & PCI_DEV_SLOT_MASK), | ||
2274 | pci_dev->irq); | ||
2275 | } | ||
2276 | } | ||
2277 | |||
2278 | return number_S514_cards; | ||
2279 | |||
2280 | } | ||
2281 | |||
2282 | |||
2283 | |||
2284 | EXPORT_SYMBOL(wanpipe_hw_probe); | ||
2285 | |||
2286 | unsigned wanpipe_hw_probe(void) | ||
2287 | { | ||
2288 | sdlahw_t hw; | ||
2289 | unsigned* opt = s508_port_options; | ||
2290 | unsigned cardno=0; | ||
2291 | int i; | ||
2292 | |||
2293 | memset(&hw, 0, sizeof(hw)); | ||
2294 | |||
2295 | for (i = 1; i <= opt[0]; i++) { | ||
2296 | if (detect_s508(opt[i])){ | ||
2297 | /* S508 card can support up to two physical links */ | ||
2298 | cardno+=2; | ||
2299 | printk(KERN_INFO "wanpipe: S508-ISA card found, port 0x%x\n",opt[i]); | ||
2300 | } | ||
2301 | } | ||
2302 | |||
2303 | #ifdef CONFIG_PCI | ||
2304 | hw.S514_slot_no = 0; | ||
2305 | cardno += pci_probe(&hw); | ||
2306 | #else | ||
2307 | printk(KERN_INFO "wanpipe: Warning, Kernel not compiled for PCI support!\n"); | ||
2308 | printk(KERN_INFO "wanpipe: PCI Hardware Probe Failed!\n"); | ||
2309 | #endif | ||
2310 | |||
2311 | return cardno; | ||
2312 | } | ||
2313 | |||
2314 | /****** End *****************************************************************/ | ||
diff --git a/drivers/net/wan/sdlamain.c b/drivers/net/wan/sdlamain.c deleted file mode 100644 index 7a8b22a7ea31..000000000000 --- a/drivers/net/wan/sdlamain.c +++ /dev/null | |||
@@ -1,1346 +0,0 @@ | |||
1 | /**************************************************************************** | ||
2 | * sdlamain.c WANPIPE(tm) Multiprotocol WAN Link Driver. Main module. | ||
3 | * | ||
4 | * Author: Nenad Corbic <ncorbic@sangoma.com> | ||
5 | * Gideon Hack | ||
6 | * | ||
7 | * Copyright: (c) 1995-2000 Sangoma Technologies Inc. | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or | ||
10 | * modify it under the terms of the GNU General Public License | ||
11 | * as published by the Free Software Foundation; either version | ||
12 | * 2 of the License, or (at your option) any later version. | ||
13 | * ============================================================================ | ||
14 | * Dec 22, 2000 Nenad Corbic Updated for 2.4.X kernels. | ||
15 | * Removed the polling routine. | ||
16 | * Nov 13, 2000 Nenad Corbic Added hw probing on module load and dynamic | ||
17 | * device allocation. | ||
18 | * Nov 7, 2000 Nenad Corbic Fixed the Multi-Port PPP for kernels | ||
19 | * 2.2.16 and above. | ||
20 | * Aug 2, 2000 Nenad Corbic Block the Multi-Port PPP from running on | ||
21 | * kernels 2.2.16 or greater. The SyncPPP | ||
22 | * has changed. | ||
23 | * Jul 25, 2000 Nenad Corbic Updated the Piggiback support for MultPPPP. | ||
24 | * Jul 13, 2000 Nenad Corbic Added Multi-PPP support. | ||
25 | * Feb 02, 2000 Nenad Corbic Fixed up piggyback probing and selection. | ||
26 | * Sep 23, 1999 Nenad Corbic Added support for SMP | ||
27 | * Sep 13, 1999 Nenad Corbic Each port is treated as a separate device. | ||
28 | * Jun 02, 1999 Gideon Hack Added support for the S514 adapter. | ||
29 | * Updates for Linux 2.2.X kernels. | ||
30 | * Sep 17, 1998 Jaspreet Singh Updated for 2.1.121+ kernel | ||
31 | * Nov 28, 1997 Jaspreet Singh Changed DRV_RELEASE to 1 | ||
32 | * Nov 10, 1997 Jaspreet Singh Changed sti() to restore_flags(); | ||
33 | * Nov 06, 1997 Jaspreet Singh Changed DRV_VERSION to 4 and DRV_RELEASE to 0 | ||
34 | * Oct 20, 1997 Jaspreet Singh Modified sdla_isr routine so that card->in_isr | ||
35 | * assignments are taken out and placed in the | ||
36 | * sdla_ppp.c, sdla_fr.c and sdla_x25.c isr | ||
37 | * routines. Took out 'wandev->tx_int_enabled' and | ||
38 | * replaced it with 'wandev->enable_tx_int'. | ||
39 | * May 29, 1997 Jaspreet Singh Flow Control Problem | ||
40 | * added "wandev->tx_int_enabled=1" line in the | ||
41 | * init module. This line initializes the flag for | ||
42 | * preventing Interrupt disabled with device set to | ||
43 | * busy | ||
44 | * Jan 15, 1997 Gene Kozin Version 3.1.0 | ||
45 | * o added UDP management stuff | ||
46 | * Jan 02, 1997 Gene Kozin Initial version. | ||
47 | *****************************************************************************/ | ||
48 | |||
49 | #include <linux/config.h> /* OS configuration options */ | ||
50 | #include <linux/stddef.h> /* offsetof(), etc. */ | ||
51 | #include <linux/errno.h> /* return codes */ | ||
52 | #include <linux/string.h> /* inline memset(), etc. */ | ||
53 | #include <linux/init.h> | ||
54 | #include <linux/slab.h> /* kmalloc(), kfree() */ | ||
55 | #include <linux/kernel.h> /* printk(), and other useful stuff */ | ||
56 | #include <linux/module.h> /* support for loadable modules */ | ||
57 | #include <linux/ioport.h> /* request_region(), release_region() */ | ||
58 | #include <linux/wanrouter.h> /* WAN router definitions */ | ||
59 | #include <linux/wanpipe.h> /* WANPIPE common user API definitions */ | ||
60 | #include <linux/rcupdate.h> | ||
61 | |||
62 | #include <linux/in.h> | ||
63 | #include <asm/io.h> /* phys_to_virt() */ | ||
64 | #include <linux/pci.h> | ||
65 | #include <linux/sdlapci.h> | ||
66 | #include <linux/if_wanpipe_common.h> | ||
67 | |||
68 | #include <asm/uaccess.h> /* kernel <-> user copy */ | ||
69 | #include <linux/inetdevice.h> | ||
70 | |||
71 | #include <linux/ip.h> | ||
72 | #include <net/route.h> | ||
73 | |||
74 | #define KMEM_SAFETYZONE 8 | ||
75 | |||
76 | |||
77 | #ifndef CONFIG_WANPIPE_FR | ||
78 | #define wpf_init(a,b) (-EPROTONOSUPPORT) | ||
79 | #endif | ||
80 | |||
81 | #ifndef CONFIG_WANPIPE_CHDLC | ||
82 | #define wpc_init(a,b) (-EPROTONOSUPPORT) | ||
83 | #endif | ||
84 | |||
85 | #ifndef CONFIG_WANPIPE_X25 | ||
86 | #define wpx_init(a,b) (-EPROTONOSUPPORT) | ||
87 | #endif | ||
88 | |||
89 | #ifndef CONFIG_WANPIPE_PPP | ||
90 | #define wpp_init(a,b) (-EPROTONOSUPPORT) | ||
91 | #endif | ||
92 | |||
93 | #ifndef CONFIG_WANPIPE_MULTPPP | ||
94 | #define wsppp_init(a,b) (-EPROTONOSUPPORT) | ||
95 | #endif | ||
96 | |||
97 | |||
98 | /***********FOR DEBUGGING PURPOSES********************************************* | ||
99 | static void * dbg_kmalloc(unsigned int size, int prio, int line) { | ||
100 | int i = 0; | ||
101 | void * v = kmalloc(size+sizeof(unsigned int)+2*KMEM_SAFETYZONE*8,prio); | ||
102 | char * c1 = v; | ||
103 | c1 += sizeof(unsigned int); | ||
104 | *((unsigned int *)v) = size; | ||
105 | |||
106 | for (i = 0; i < KMEM_SAFETYZONE; i++) { | ||
107 | c1[0] = 'D'; c1[1] = 'E'; c1[2] = 'A'; c1[3] = 'D'; | ||
108 | c1[4] = 'B'; c1[5] = 'E'; c1[6] = 'E'; c1[7] = 'F'; | ||
109 | c1 += 8; | ||
110 | } | ||
111 | c1 += size; | ||
112 | for (i = 0; i < KMEM_SAFETYZONE; i++) { | ||
113 | c1[0] = 'M'; c1[1] = 'U'; c1[2] = 'N'; c1[3] = 'G'; | ||
114 | c1[4] = 'W'; c1[5] = 'A'; c1[6] = 'L'; c1[7] = 'L'; | ||
115 | c1 += 8; | ||
116 | } | ||
117 | v = ((char *)v) + sizeof(unsigned int) + KMEM_SAFETYZONE*8; | ||
118 | printk(KERN_INFO "line %d kmalloc(%d,%d) = %p\n",line,size,prio,v); | ||
119 | return v; | ||
120 | } | ||
121 | static void dbg_kfree(void * v, int line) { | ||
122 | unsigned int * sp = (unsigned int *)(((char *)v) - (sizeof(unsigned int) + KMEM_SAFETYZONE*8)); | ||
123 | unsigned int size = *sp; | ||
124 | char * c1 = ((char *)v) - KMEM_SAFETYZONE*8; | ||
125 | int i = 0; | ||
126 | for (i = 0; i < KMEM_SAFETYZONE; i++) { | ||
127 | if ( c1[0] != 'D' || c1[1] != 'E' || c1[2] != 'A' || c1[3] != 'D' | ||
128 | || c1[4] != 'B' || c1[5] != 'E' || c1[6] != 'E' || c1[7] != 'F') { | ||
129 | printk(KERN_INFO "kmalloced block at %p has been corrupted (underrun)!\n",v); | ||
130 | printk(KERN_INFO " %4x: %2x %2x %2x %2x %2x %2x %2x %2x\n", i*8, | ||
131 | c1[0],c1[1],c1[2],c1[3],c1[4],c1[5],c1[6],c1[7] ); | ||
132 | } | ||
133 | c1 += 8; | ||
134 | } | ||
135 | c1 += size; | ||
136 | for (i = 0; i < KMEM_SAFETYZONE; i++) { | ||
137 | if ( c1[0] != 'M' || c1[1] != 'U' || c1[2] != 'N' || c1[3] != 'G' | ||
138 | || c1[4] != 'W' || c1[5] != 'A' || c1[6] != 'L' || c1[7] != 'L' | ||
139 | ) { | ||
140 | printk(KERN_INFO "kmalloced block at %p has been corrupted (overrun):\n",v); | ||
141 | printk(KERN_INFO " %4x: %2x %2x %2x %2x %2x %2x %2x %2x\n", i*8, | ||
142 | c1[0],c1[1],c1[2],c1[3],c1[4],c1[5],c1[6],c1[7] ); | ||
143 | } | ||
144 | c1 += 8; | ||
145 | } | ||
146 | printk(KERN_INFO "line %d kfree(%p)\n",line,v); | ||
147 | v = ((char *)v) - (sizeof(unsigned int) + KMEM_SAFETYZONE*8); | ||
148 | kfree(v); | ||
149 | } | ||
150 | |||
151 | #define kmalloc(x,y) dbg_kmalloc(x,y,__LINE__) | ||
152 | #define kfree(x) dbg_kfree(x,__LINE__) | ||
153 | ******************************************************************************/ | ||
154 | |||
155 | |||
156 | |||
157 | /****** Defines & Macros ****************************************************/ | ||
158 | |||
159 | #ifdef _DEBUG_ | ||
160 | #define STATIC | ||
161 | #else | ||
162 | #define STATIC static | ||
163 | #endif | ||
164 | |||
165 | #define DRV_VERSION 5 /* version number */ | ||
166 | #define DRV_RELEASE 0 /* release (minor version) number */ | ||
167 | #define MAX_CARDS 16 /* max number of adapters */ | ||
168 | |||
169 | #ifndef CONFIG_WANPIPE_CARDS /* configurable option */ | ||
170 | #define CONFIG_WANPIPE_CARDS 1 | ||
171 | #endif | ||
172 | |||
173 | #define CMD_OK 0 /* normal firmware return code */ | ||
174 | #define CMD_TIMEOUT 0xFF /* firmware command timed out */ | ||
175 | #define MAX_CMD_RETRY 10 /* max number of firmware retries */ | ||
176 | /****** Function Prototypes *************************************************/ | ||
177 | |||
178 | extern void disable_irq(unsigned int); | ||
179 | extern void enable_irq(unsigned int); | ||
180 | |||
181 | /* WAN link driver entry points */ | ||
182 | static int setup(struct wan_device* wandev, wandev_conf_t* conf); | ||
183 | static int shutdown(struct wan_device* wandev); | ||
184 | static int ioctl(struct wan_device* wandev, unsigned cmd, unsigned long arg); | ||
185 | |||
186 | /* IOCTL handlers */ | ||
187 | static int ioctl_dump (sdla_t* card, sdla_dump_t* u_dump); | ||
188 | static int ioctl_exec (sdla_t* card, sdla_exec_t* u_exec, int); | ||
189 | |||
190 | /* Miscellaneous functions */ | ||
191 | STATIC irqreturn_t sdla_isr (int irq, void* dev_id, struct pt_regs *regs); | ||
192 | static void release_hw (sdla_t *card); | ||
193 | |||
194 | static int check_s508_conflicts (sdla_t* card,wandev_conf_t* conf, int*); | ||
195 | static int check_s514_conflicts (sdla_t* card,wandev_conf_t* conf, int*); | ||
196 | |||
197 | |||
198 | /****** Global Data ********************************************************** | ||
199 | * Note: All data must be explicitly initialized!!! | ||
200 | */ | ||
201 | |||
202 | /* private data */ | ||
203 | static char drvname[] = "wanpipe"; | ||
204 | static char fullname[] = "WANPIPE(tm) Multiprotocol Driver"; | ||
205 | static char copyright[] = "(c) 1995-2000 Sangoma Technologies Inc."; | ||
206 | static int ncards; | ||
207 | static sdla_t* card_array; /* adapter data space */ | ||
208 | |||
209 | /* Wanpipe's own workqueue, used for all API's. | ||
210 | * All protocol specific tasks will be inserted | ||
211 | * into the "wanpipe_wq" workqueue. | ||
212 | |||
213 | * The kernel workqueue mechanism will execute | ||
214 | * all pending tasks in the "wanpipe_wq" workqueue. | ||
215 | */ | ||
216 | |||
217 | struct workqueue_struct *wanpipe_wq; | ||
218 | DECLARE_WORK(wanpipe_work, NULL, NULL); | ||
219 | |||
220 | static int wanpipe_bh_critical; | ||
221 | |||
222 | /******* Kernel Loadable Module Entry Points ********************************/ | ||
223 | |||
224 | /*============================================================================ | ||
225 | * Module 'insert' entry point. | ||
226 | * o print announcement | ||
227 | * o allocate adapter data space | ||
228 | * o initialize static data | ||
229 | * o register all cards with WAN router | ||
230 | * o calibrate SDLA shared memory access delay. | ||
231 | * | ||
232 | * Return: 0 Ok | ||
233 | * < 0 error. | ||
234 | * Context: process | ||
235 | */ | ||
236 | |||
237 | static int __init wanpipe_init(void) | ||
238 | { | ||
239 | int cnt, err = 0; | ||
240 | |||
241 | printk(KERN_INFO "%s v%u.%u %s\n", | ||
242 | fullname, DRV_VERSION, DRV_RELEASE, copyright); | ||
243 | |||
244 | wanpipe_wq = create_workqueue("wanpipe_wq"); | ||
245 | if (!wanpipe_wq) | ||
246 | return -ENOMEM; | ||
247 | |||
248 | /* Probe for wanpipe cards and return the number found */ | ||
249 | printk(KERN_INFO "wanpipe: Probing for WANPIPE hardware.\n"); | ||
250 | ncards = wanpipe_hw_probe(); | ||
251 | if (ncards){ | ||
252 | printk(KERN_INFO "wanpipe: Allocating maximum %i devices: wanpipe%i - wanpipe%i.\n",ncards,1,ncards); | ||
253 | }else{ | ||
254 | printk(KERN_INFO "wanpipe: No S514/S508 cards found, unloading modules!\n"); | ||
255 | destroy_workqueue(wanpipe_wq); | ||
256 | return -ENODEV; | ||
257 | } | ||
258 | |||
259 | /* Verify number of cards and allocate adapter data space */ | ||
260 | card_array = kmalloc(sizeof(sdla_t) * ncards, GFP_KERNEL); | ||
261 | if (card_array == NULL) { | ||
262 | destroy_workqueue(wanpipe_wq); | ||
263 | return -ENOMEM; | ||
264 | } | ||
265 | |||
266 | memset(card_array, 0, sizeof(sdla_t) * ncards); | ||
267 | |||
268 | /* Register adapters with WAN router */ | ||
269 | for (cnt = 0; cnt < ncards; ++ cnt) { | ||
270 | sdla_t* card = &card_array[cnt]; | ||
271 | struct wan_device* wandev = &card->wandev; | ||
272 | |||
273 | card->next = NULL; | ||
274 | sprintf(card->devname, "%s%d", drvname, cnt + 1); | ||
275 | wandev->magic = ROUTER_MAGIC; | ||
276 | wandev->name = card->devname; | ||
277 | wandev->private = card; | ||
278 | wandev->enable_tx_int = 0; | ||
279 | wandev->setup = &setup; | ||
280 | wandev->shutdown = &shutdown; | ||
281 | wandev->ioctl = &ioctl; | ||
282 | err = register_wan_device(wandev); | ||
283 | if (err) { | ||
284 | printk(KERN_INFO | ||
285 | "%s: %s registration failed with error %d!\n", | ||
286 | drvname, card->devname, err); | ||
287 | break; | ||
288 | } | ||
289 | } | ||
290 | if (cnt){ | ||
291 | ncards = cnt; /* adjust actual number of cards */ | ||
292 | }else { | ||
293 | kfree(card_array); | ||
294 | destroy_workqueue(wanpipe_wq); | ||
295 | printk(KERN_INFO "IN Init Module: NO Cards registered\n"); | ||
296 | err = -ENODEV; | ||
297 | } | ||
298 | |||
299 | return err; | ||
300 | } | ||
301 | |||
302 | /*============================================================================ | ||
303 | * Module 'remove' entry point. | ||
304 | * o unregister all adapters from the WAN router | ||
305 | * o release all remaining system resources | ||
306 | */ | ||
307 | static void __exit wanpipe_cleanup(void) | ||
308 | { | ||
309 | int i; | ||
310 | |||
311 | if (!ncards) | ||
312 | return; | ||
313 | |||
314 | for (i = 0; i < ncards; ++i) { | ||
315 | sdla_t* card = &card_array[i]; | ||
316 | unregister_wan_device(card->devname); | ||
317 | } | ||
318 | destroy_workqueue(wanpipe_wq); | ||
319 | kfree(card_array); | ||
320 | |||
321 | printk(KERN_INFO "\nwanpipe: WANPIPE Modules Unloaded.\n"); | ||
322 | } | ||
323 | |||
324 | module_init(wanpipe_init); | ||
325 | module_exit(wanpipe_cleanup); | ||
326 | |||
327 | /******* WAN Device Driver Entry Points *************************************/ | ||
328 | |||
329 | /*============================================================================ | ||
330 | * Setup/configure WAN link driver. | ||
331 | * o check adapter state | ||
332 | * o make sure firmware is present in configuration | ||
333 | * o make sure I/O port and IRQ are specified | ||
334 | * o make sure I/O region is available | ||
335 | * o allocate interrupt vector | ||
336 | * o setup SDLA hardware | ||
337 | * o call appropriate routine to perform protocol-specific initialization | ||
338 | * o mark I/O region as used | ||
339 | * o if this is the first active card, then schedule background task | ||
340 | * | ||
341 | * This function is called when router handles ROUTER_SETUP IOCTL. The | ||
342 | * configuration structure is in kernel memory (including extended data, if | ||
343 | * any). | ||
344 | */ | ||
345 | |||
346 | static int setup(struct wan_device* wandev, wandev_conf_t* conf) | ||
347 | { | ||
348 | sdla_t* card; | ||
349 | int err = 0; | ||
350 | int irq=0; | ||
351 | |||
352 | /* Sanity checks */ | ||
353 | if ((wandev == NULL) || (wandev->private == NULL) || (conf == NULL)){ | ||
354 | printk(KERN_INFO | ||
355 | "%s: Failed Sdlamain Setup wandev %u, card %u, conf %u !\n", | ||
356 | wandev->name, | ||
357 | (unsigned int)wandev,(unsigned int)wandev->private, | ||
358 | (unsigned int)conf); | ||
359 | return -EFAULT; | ||
360 | } | ||
361 | |||
362 | printk(KERN_INFO "%s: Starting WAN Setup\n", wandev->name); | ||
363 | |||
364 | card = wandev->private; | ||
365 | if (wandev->state != WAN_UNCONFIGURED){ | ||
366 | printk(KERN_INFO "%s: failed sdlamain setup, busy!\n", | ||
367 | wandev->name); | ||
368 | return -EBUSY; /* already configured */ | ||
369 | } | ||
370 | |||
371 | printk(KERN_INFO "\nProcessing WAN device %s...\n", wandev->name); | ||
372 | |||
373 | /* Initialize the counters for each wandev | ||
374 | * Used for counting number of times new_if and | ||
375 | * del_if get called. | ||
376 | */ | ||
377 | wandev->del_if_cnt = 0; | ||
378 | wandev->new_if_cnt = 0; | ||
379 | wandev->config_id = conf->config_id; | ||
380 | |||
381 | if (!conf->data_size || (conf->data == NULL)) { | ||
382 | printk(KERN_INFO | ||
383 | "%s: firmware not found in configuration data!\n", | ||
384 | wandev->name); | ||
385 | return -EINVAL; | ||
386 | } | ||
387 | |||
388 | /* Check for resource conflicts and setup the | ||
389 | * card for piggibacking if necessary */ | ||
390 | if(!conf->S514_CPU_no[0]) { | ||
391 | if ((err=check_s508_conflicts(card,conf,&irq)) != 0){ | ||
392 | return err; | ||
393 | } | ||
394 | }else { | ||
395 | if ((err=check_s514_conflicts(card,conf,&irq)) != 0){ | ||
396 | return err; | ||
397 | } | ||
398 | } | ||
399 | |||
400 | /* If the current card has already been configured | ||
401 | * or it's a piggyback card, do not try to allocate | ||
402 | * resources. | ||
403 | */ | ||
404 | if (!card->wandev.piggyback && !card->configured){ | ||
405 | |||
406 | /* Configure hardware, load firmware, etc. */ | ||
407 | memset(&card->hw, 0, sizeof(sdlahw_t)); | ||
408 | |||
409 | /* for an S514 adapter, pass the CPU number and the slot number read */ | ||
410 | /* from 'router.conf' to the 'sdla_setup()' function via the 'port' */ | ||
411 | /* parameter */ | ||
412 | if (conf->S514_CPU_no[0]){ | ||
413 | |||
414 | card->hw.S514_cpu_no[0] = conf->S514_CPU_no[0]; | ||
415 | card->hw.S514_slot_no = conf->PCI_slot_no; | ||
416 | card->hw.auto_pci_cfg = conf->auto_pci_cfg; | ||
417 | |||
418 | if (card->hw.auto_pci_cfg == WANOPT_YES){ | ||
419 | printk(KERN_INFO "%s: Setting CPU to %c and Slot to Auto\n", | ||
420 | card->devname, card->hw.S514_cpu_no[0]); | ||
421 | }else{ | ||
422 | printk(KERN_INFO "%s: Setting CPU to %c and Slot to %i\n", | ||
423 | card->devname, card->hw.S514_cpu_no[0], card->hw.S514_slot_no); | ||
424 | } | ||
425 | |||
426 | }else{ | ||
427 | /* 508 Card io port and irq initialization */ | ||
428 | card->hw.port = conf->ioport; | ||
429 | card->hw.irq = (conf->irq == 9) ? 2 : conf->irq; | ||
430 | } | ||
431 | |||
432 | |||
433 | /* Compute the virtual address of the card in kernel space */ | ||
434 | if(conf->maddr){ | ||
435 | card->hw.dpmbase = phys_to_virt(conf->maddr); | ||
436 | }else{ | ||
437 | card->hw.dpmbase = (void *)conf->maddr; | ||
438 | } | ||
439 | |||
440 | card->hw.dpmsize = SDLA_WINDOWSIZE; | ||
441 | |||
442 | /* set the adapter type if using an S514 adapter */ | ||
443 | card->hw.type = (conf->S514_CPU_no[0]) ? SDLA_S514 : conf->hw_opt[0]; | ||
444 | card->hw.pclk = conf->hw_opt[1]; | ||
445 | |||
446 | err = sdla_setup(&card->hw, conf->data, conf->data_size); | ||
447 | if (err){ | ||
448 | printk(KERN_INFO "%s: Hardware setup Failed %i\n", | ||
449 | card->devname,err); | ||
450 | return err; | ||
451 | } | ||
452 | |||
453 | if(card->hw.type != SDLA_S514) | ||
454 | irq = (conf->irq == 2) ? 9 : conf->irq; /* IRQ2 -> IRQ9 */ | ||
455 | else | ||
456 | irq = card->hw.irq; | ||
457 | |||
458 | /* request an interrupt vector - note that interrupts may be shared */ | ||
459 | /* when using the S514 PCI adapter */ | ||
460 | |||
461 | if(request_irq(irq, sdla_isr, | ||
462 | (card->hw.type == SDLA_S514) ? SA_SHIRQ : 0, | ||
463 | wandev->name, card)){ | ||
464 | |||
465 | printk(KERN_INFO "%s: Can't reserve IRQ %d!\n", wandev->name, irq); | ||
466 | return -EINVAL; | ||
467 | } | ||
468 | |||
469 | }else{ | ||
470 | printk(KERN_INFO "%s: Card Configured %lu or Piggybacking %i!\n", | ||
471 | wandev->name,card->configured,card->wandev.piggyback); | ||
472 | } | ||
473 | |||
474 | |||
475 | if (!card->configured){ | ||
476 | |||
477 | /* Initialize the Spin lock */ | ||
478 | printk(KERN_INFO "%s: Initializing for SMP\n",wandev->name); | ||
479 | |||
480 | /* Piggyback spin lock has already been initialized, | ||
481 | * in check_s514/s508_conflicts() */ | ||
482 | if (!card->wandev.piggyback){ | ||
483 | spin_lock_init(&card->wandev.lock); | ||
484 | } | ||
485 | |||
486 | /* Intialize WAN device data space */ | ||
487 | wandev->irq = irq; | ||
488 | wandev->dma = 0; | ||
489 | if(card->hw.type != SDLA_S514){ | ||
490 | wandev->ioport = card->hw.port; | ||
491 | }else{ | ||
492 | wandev->S514_cpu_no[0] = card->hw.S514_cpu_no[0]; | ||
493 | wandev->S514_slot_no = card->hw.S514_slot_no; | ||
494 | } | ||
495 | wandev->maddr = (unsigned long)card->hw.dpmbase; | ||
496 | wandev->msize = card->hw.dpmsize; | ||
497 | wandev->hw_opt[0] = card->hw.type; | ||
498 | wandev->hw_opt[1] = card->hw.pclk; | ||
499 | wandev->hw_opt[2] = card->hw.memory; | ||
500 | wandev->hw_opt[3] = card->hw.fwid; | ||
501 | } | ||
502 | |||
503 | /* Protocol-specific initialization */ | ||
504 | switch (card->hw.fwid) { | ||
505 | |||
506 | case SFID_X25_502: | ||
507 | case SFID_X25_508: | ||
508 | printk(KERN_INFO "%s: Starting X.25 Protocol Init.\n", | ||
509 | card->devname); | ||
510 | err = wpx_init(card, conf); | ||
511 | break; | ||
512 | case SFID_FR502: | ||
513 | case SFID_FR508: | ||
514 | printk(KERN_INFO "%s: Starting Frame Relay Protocol Init.\n", | ||
515 | card->devname); | ||
516 | err = wpf_init(card, conf); | ||
517 | break; | ||
518 | case SFID_PPP502: | ||
519 | case SFID_PPP508: | ||
520 | printk(KERN_INFO "%s: Starting PPP Protocol Init.\n", | ||
521 | card->devname); | ||
522 | err = wpp_init(card, conf); | ||
523 | break; | ||
524 | |||
525 | case SFID_CHDLC508: | ||
526 | case SFID_CHDLC514: | ||
527 | if (conf->ft1){ | ||
528 | printk(KERN_INFO "%s: Starting FT1 CSU/DSU Config Driver.\n", | ||
529 | card->devname); | ||
530 | err = wpft1_init(card, conf); | ||
531 | break; | ||
532 | |||
533 | }else if (conf->config_id == WANCONFIG_MPPP){ | ||
534 | printk(KERN_INFO "%s: Starting Multi-Port PPP Protocol Init.\n", | ||
535 | card->devname); | ||
536 | err = wsppp_init(card,conf); | ||
537 | break; | ||
538 | |||
539 | }else{ | ||
540 | printk(KERN_INFO "%s: Starting CHDLC Protocol Init.\n", | ||
541 | card->devname); | ||
542 | err = wpc_init(card, conf); | ||
543 | break; | ||
544 | } | ||
545 | default: | ||
546 | printk(KERN_INFO "%s: Error, Firmware is not supported %X %X!\n", | ||
547 | wandev->name,card->hw.fwid,SFID_CHDLC508); | ||
548 | err = -EPROTONOSUPPORT; | ||
549 | } | ||
550 | |||
551 | if (err != 0){ | ||
552 | if (err == -EPROTONOSUPPORT){ | ||
553 | printk(KERN_INFO | ||
554 | "%s: Error, Protocol selected has not been compiled!\n", | ||
555 | card->devname); | ||
556 | printk(KERN_INFO | ||
557 | "%s: Re-configure the kernel and re-build the modules!\n", | ||
558 | card->devname); | ||
559 | } | ||
560 | |||
561 | release_hw(card); | ||
562 | wandev->state = WAN_UNCONFIGURED; | ||
563 | return err; | ||
564 | } | ||
565 | |||
566 | |||
567 | /* Reserve I/O region and schedule background task */ | ||
568 | if(card->hw.type != SDLA_S514 && !card->wandev.piggyback) | ||
569 | if (!request_region(card->hw.port, card->hw.io_range, | ||
570 | wandev->name)) { | ||
571 | printk(KERN_WARNING "port 0x%04x busy\n", card->hw.port); | ||
572 | release_hw(card); | ||
573 | wandev->state = WAN_UNCONFIGURED; | ||
574 | return -EBUSY; | ||
575 | } | ||
576 | |||
577 | /* Only use the polling routine for the X25 protocol */ | ||
578 | |||
579 | card->wandev.critical=0; | ||
580 | return 0; | ||
581 | } | ||
582 | |||
583 | /*================================================================== | ||
584 | * configure_s508_card | ||
585 | * | ||
586 | * For a S508 adapter, check for a possible configuration error in that | ||
587 | * we are loading an adapter in the same IO port as a previously loaded S508 | ||
588 | * card. | ||
589 | */ | ||
590 | |||
591 | static int check_s508_conflicts (sdla_t* card,wandev_conf_t* conf, int *irq) | ||
592 | { | ||
593 | unsigned long smp_flags; | ||
594 | int i; | ||
595 | |||
596 | if (conf->ioport <= 0) { | ||
597 | printk(KERN_INFO | ||
598 | "%s: can't configure without I/O port address!\n", | ||
599 | card->wandev.name); | ||
600 | return -EINVAL; | ||
601 | } | ||
602 | |||
603 | if (conf->irq <= 0) { | ||
604 | printk(KERN_INFO "%s: can't configure without IRQ!\n", | ||
605 | card->wandev.name); | ||
606 | return -EINVAL; | ||
607 | } | ||
608 | |||
609 | if (test_bit(0,&card->configured)) | ||
610 | return 0; | ||
611 | |||
612 | |||
613 | /* Check for already loaded card with the same IO port and IRQ | ||
614 | * If found, copy its hardware configuration and use its | ||
615 | * resources (i.e. piggybacking) | ||
616 | */ | ||
617 | |||
618 | for (i = 0; i < ncards; i++) { | ||
619 | sdla_t *nxt_card = &card_array[i]; | ||
620 | |||
621 | /* Skip the current card ptr */ | ||
622 | if (nxt_card == card) | ||
623 | continue; | ||
624 | |||
625 | |||
626 | /* Find a card that is already configured with the | ||
627 | * same IO Port */ | ||
628 | if ((nxt_card->hw.type == SDLA_S508) && | ||
629 | (nxt_card->hw.port == conf->ioport) && | ||
630 | (nxt_card->next == NULL)){ | ||
631 | |||
632 | /* We found a card the card that has same configuration | ||
633 | * as us. This means, that we must setup this card in | ||
634 | * piggibacking mode. However, only CHDLC and MPPP protocol | ||
635 | * support this setup */ | ||
636 | |||
637 | if ((conf->config_id == WANCONFIG_CHDLC || | ||
638 | conf->config_id == WANCONFIG_MPPP) && | ||
639 | (nxt_card->wandev.config_id == WANCONFIG_CHDLC || | ||
640 | nxt_card->wandev.config_id == WANCONFIG_MPPP)){ | ||
641 | |||
642 | *irq = nxt_card->hw.irq; | ||
643 | memcpy(&card->hw, &nxt_card->hw, sizeof(sdlahw_t)); | ||
644 | |||
645 | /* The master could already be running, we must | ||
646 | * set this as a critical area */ | ||
647 | lock_adapter_irq(&nxt_card->wandev.lock, &smp_flags); | ||
648 | |||
649 | nxt_card->next = card; | ||
650 | card->next = nxt_card; | ||
651 | |||
652 | card->wandev.piggyback = WANOPT_YES; | ||
653 | |||
654 | /* We must initialise the piggiback spin lock here | ||
655 | * since isr will try to lock card->next if it | ||
656 | * exists */ | ||
657 | spin_lock_init(&card->wandev.lock); | ||
658 | |||
659 | unlock_adapter_irq(&nxt_card->wandev.lock, &smp_flags); | ||
660 | break; | ||
661 | }else{ | ||
662 | /* Trying to run piggibacking with a wrong protocol */ | ||
663 | printk(KERN_INFO "%s: ERROR: Resource busy, ioport: 0x%x\n" | ||
664 | "%s: This protocol doesn't support\n" | ||
665 | "%s: multi-port operation!\n", | ||
666 | card->devname,nxt_card->hw.port, | ||
667 | card->devname,card->devname); | ||
668 | return -EEXIST; | ||
669 | } | ||
670 | } | ||
671 | } | ||
672 | |||
673 | |||
674 | /* Make sure I/O port region is available only if we are the | ||
675 | * master device. If we are running in piggybacking mode, | ||
676 | * we will use the resources of the master card. */ | ||
677 | if (!card->wandev.piggyback) { | ||
678 | struct resource *rr = | ||
679 | request_region(conf->ioport, SDLA_MAXIORANGE, "sdlamain"); | ||
680 | release_region(conf->ioport, SDLA_MAXIORANGE); | ||
681 | |||
682 | if (!rr) { | ||
683 | printk(KERN_INFO | ||
684 | "%s: I/O region 0x%X - 0x%X is in use!\n", | ||
685 | card->wandev.name, conf->ioport, | ||
686 | conf->ioport + SDLA_MAXIORANGE - 1); | ||
687 | return -EINVAL; | ||
688 | } | ||
689 | } | ||
690 | |||
691 | return 0; | ||
692 | } | ||
693 | |||
694 | /*================================================================== | ||
695 | * configure_s514_card | ||
696 | * | ||
697 | * For a S514 adapter, check for a possible configuration error in that | ||
698 | * we are loading an adapter in the same slot as a previously loaded S514 | ||
699 | * card. | ||
700 | */ | ||
701 | |||
702 | |||
703 | static int check_s514_conflicts(sdla_t* card,wandev_conf_t* conf, int *irq) | ||
704 | { | ||
705 | unsigned long smp_flags; | ||
706 | int i; | ||
707 | |||
708 | if (test_bit(0,&card->configured)) | ||
709 | return 0; | ||
710 | |||
711 | |||
712 | /* Check for already loaded card with the same IO port and IRQ | ||
713 | * If found, copy its hardware configuration and use its | ||
714 | * resources (i.e. piggybacking) | ||
715 | */ | ||
716 | |||
717 | for (i = 0; i < ncards; i ++) { | ||
718 | |||
719 | sdla_t* nxt_card = &card_array[i]; | ||
720 | if(nxt_card == card) | ||
721 | continue; | ||
722 | |||
723 | if((nxt_card->hw.type == SDLA_S514) && | ||
724 | (nxt_card->hw.S514_slot_no == conf->PCI_slot_no) && | ||
725 | (nxt_card->hw.S514_cpu_no[0] == conf->S514_CPU_no[0])&& | ||
726 | (nxt_card->next == NULL)){ | ||
727 | |||
728 | |||
729 | if ((conf->config_id == WANCONFIG_CHDLC || | ||
730 | conf->config_id == WANCONFIG_MPPP) && | ||
731 | (nxt_card->wandev.config_id == WANCONFIG_CHDLC || | ||
732 | nxt_card->wandev.config_id == WANCONFIG_MPPP)){ | ||
733 | |||
734 | *irq = nxt_card->hw.irq; | ||
735 | memcpy(&card->hw, &nxt_card->hw, sizeof(sdlahw_t)); | ||
736 | |||
737 | /* The master could already be running, we must | ||
738 | * set this as a critical area */ | ||
739 | lock_adapter_irq(&nxt_card->wandev.lock,&smp_flags); | ||
740 | nxt_card->next = card; | ||
741 | card->next = nxt_card; | ||
742 | |||
743 | card->wandev.piggyback = WANOPT_YES; | ||
744 | |||
745 | /* We must initialise the piggiback spin lock here | ||
746 | * since isr will try to lock card->next if it | ||
747 | * exists */ | ||
748 | spin_lock_init(&card->wandev.lock); | ||
749 | |||
750 | unlock_adapter_irq(&nxt_card->wandev.lock,&smp_flags); | ||
751 | |||
752 | }else{ | ||
753 | /* Trying to run piggibacking with a wrong protocol */ | ||
754 | printk(KERN_INFO "%s: ERROR: Resource busy: CPU %c PCISLOT %i\n" | ||
755 | "%s: This protocol doesn't support\n" | ||
756 | "%s: multi-port operation!\n", | ||
757 | card->devname, | ||
758 | conf->S514_CPU_no[0],conf->PCI_slot_no, | ||
759 | card->devname,card->devname); | ||
760 | return -EEXIST; | ||
761 | } | ||
762 | } | ||
763 | } | ||
764 | |||
765 | return 0; | ||
766 | } | ||
767 | |||
768 | |||
769 | |||
770 | /*============================================================================ | ||
771 | * Shut down WAN link driver. | ||
772 | * o shut down adapter hardware | ||
773 | * o release system resources. | ||
774 | * | ||
775 | * This function is called by the router when device is being unregistered or | ||
776 | * when it handles ROUTER_DOWN IOCTL. | ||
777 | */ | ||
778 | static int shutdown(struct wan_device* wandev) | ||
779 | { | ||
780 | sdla_t *card; | ||
781 | int err=0; | ||
782 | |||
783 | /* sanity checks */ | ||
784 | if ((wandev == NULL) || (wandev->private == NULL)){ | ||
785 | return -EFAULT; | ||
786 | } | ||
787 | |||
788 | if (wandev->state == WAN_UNCONFIGURED){ | ||
789 | return 0; | ||
790 | } | ||
791 | |||
792 | card = wandev->private; | ||
793 | |||
794 | if (card->tty_opt){ | ||
795 | if (card->tty_open){ | ||
796 | printk(KERN_INFO | ||
797 | "%s: Shutdown Failed: TTY is still open\n", | ||
798 | card->devname); | ||
799 | return -EBUSY; | ||
800 | } | ||
801 | } | ||
802 | |||
803 | wandev->state = WAN_UNCONFIGURED; | ||
804 | |||
805 | set_bit(PERI_CRIT,(void*)&wandev->critical); | ||
806 | |||
807 | /* In case of piggibacking, make sure that | ||
808 | * we never try to shutdown both devices at the same | ||
809 | * time, because they depend on one another */ | ||
810 | |||
811 | if (card->disable_comm){ | ||
812 | card->disable_comm(card); | ||
813 | } | ||
814 | |||
815 | /* Release Resources */ | ||
816 | release_hw(card); | ||
817 | |||
818 | /* only free the allocated I/O range if not an S514 adapter */ | ||
819 | if (wandev->hw_opt[0] != SDLA_S514 && !card->configured){ | ||
820 | release_region(card->hw.port, card->hw.io_range); | ||
821 | } | ||
822 | |||
823 | if (!card->configured){ | ||
824 | memset(&card->hw, 0, sizeof(sdlahw_t)); | ||
825 | if (card->next){ | ||
826 | memset(&card->next->hw, 0, sizeof(sdlahw_t)); | ||
827 | } | ||
828 | } | ||
829 | |||
830 | |||
831 | clear_bit(PERI_CRIT,(void*)&wandev->critical); | ||
832 | return err; | ||
833 | } | ||
834 | |||
835 | static void release_hw (sdla_t *card) | ||
836 | { | ||
837 | sdla_t *nxt_card; | ||
838 | |||
839 | |||
840 | /* Check if next device exists */ | ||
841 | if (card->next){ | ||
842 | nxt_card = card->next; | ||
843 | /* If next device is down then release resources */ | ||
844 | if (nxt_card->wandev.state == WAN_UNCONFIGURED){ | ||
845 | if (card->wandev.piggyback){ | ||
846 | /* If this device is piggyback then use | ||
847 | * information of the master device | ||
848 | */ | ||
849 | printk(KERN_INFO "%s: Piggyback shutting down\n",card->devname); | ||
850 | sdla_down(&card->next->hw); | ||
851 | free_irq(card->wandev.irq, card->next); | ||
852 | card->configured = 0; | ||
853 | card->next->configured = 0; | ||
854 | card->wandev.piggyback = 0; | ||
855 | }else{ | ||
856 | /* Master device shutting down */ | ||
857 | printk(KERN_INFO "%s: Master shutting down\n",card->devname); | ||
858 | sdla_down(&card->hw); | ||
859 | free_irq(card->wandev.irq, card); | ||
860 | card->configured = 0; | ||
861 | card->next->configured = 0; | ||
862 | } | ||
863 | }else{ | ||
864 | printk(KERN_INFO "%s: Device still running %i\n", | ||
865 | nxt_card->devname,nxt_card->wandev.state); | ||
866 | |||
867 | card->configured = 1; | ||
868 | } | ||
869 | }else{ | ||
870 | printk(KERN_INFO "%s: Master shutting down\n",card->devname); | ||
871 | sdla_down(&card->hw); | ||
872 | free_irq(card->wandev.irq, card); | ||
873 | card->configured = 0; | ||
874 | } | ||
875 | return; | ||
876 | } | ||
877 | |||
878 | |||
879 | /*============================================================================ | ||
880 | * Driver I/O control. | ||
881 | * o verify arguments | ||
882 | * o perform requested action | ||
883 | * | ||
884 | * This function is called when router handles one of the reserved user | ||
885 | * IOCTLs. Note that 'arg' stil points to user address space. | ||
886 | */ | ||
887 | static int ioctl(struct wan_device* wandev, unsigned cmd, unsigned long arg) | ||
888 | { | ||
889 | sdla_t* card; | ||
890 | int err; | ||
891 | |||
892 | /* sanity checks */ | ||
893 | if ((wandev == NULL) || (wandev->private == NULL)) | ||
894 | return -EFAULT; | ||
895 | if (wandev->state == WAN_UNCONFIGURED) | ||
896 | return -ENODEV; | ||
897 | |||
898 | card = wandev->private; | ||
899 | |||
900 | if(card->hw.type != SDLA_S514){ | ||
901 | disable_irq(card->hw.irq); | ||
902 | } | ||
903 | |||
904 | if (test_bit(SEND_CRIT, (void*)&wandev->critical)) { | ||
905 | return -EAGAIN; | ||
906 | } | ||
907 | |||
908 | switch (cmd) { | ||
909 | case WANPIPE_DUMP: | ||
910 | err = ioctl_dump(wandev->private, (void*)arg); | ||
911 | break; | ||
912 | |||
913 | case WANPIPE_EXEC: | ||
914 | err = ioctl_exec(wandev->private, (void*)arg, cmd); | ||
915 | break; | ||
916 | default: | ||
917 | err = -EINVAL; | ||
918 | } | ||
919 | |||
920 | return err; | ||
921 | } | ||
922 | |||
923 | /****** Driver IOCTL Handlers ***********************************************/ | ||
924 | |||
925 | /*============================================================================ | ||
926 | * Dump adapter memory to user buffer. | ||
927 | * o verify request structure | ||
928 | * o copy request structure to kernel data space | ||
929 | * o verify length/offset | ||
930 | * o verify user buffer | ||
931 | * o copy adapter memory image to user buffer | ||
932 | * | ||
933 | * Note: when dumping memory, this routine switches curent dual-port memory | ||
934 | * vector, so care must be taken to avoid racing conditions. | ||
935 | */ | ||
936 | static int ioctl_dump (sdla_t* card, sdla_dump_t* u_dump) | ||
937 | { | ||
938 | sdla_dump_t dump; | ||
939 | unsigned winsize; | ||
940 | unsigned long oldvec; /* DPM window vector */ | ||
941 | unsigned long smp_flags; | ||
942 | int err = 0; | ||
943 | |||
944 | if(copy_from_user((void*)&dump, (void*)u_dump, sizeof(sdla_dump_t))) | ||
945 | return -EFAULT; | ||
946 | |||
947 | if ((dump.magic != WANPIPE_MAGIC) || | ||
948 | (dump.offset + dump.length > card->hw.memory)) | ||
949 | return -EINVAL; | ||
950 | |||
951 | winsize = card->hw.dpmsize; | ||
952 | |||
953 | if(card->hw.type != SDLA_S514) { | ||
954 | |||
955 | lock_adapter_irq(&card->wandev.lock, &smp_flags); | ||
956 | |||
957 | oldvec = card->hw.vector; | ||
958 | while (dump.length) { | ||
959 | /* current offset */ | ||
960 | unsigned pos = dump.offset % winsize; | ||
961 | /* current vector */ | ||
962 | unsigned long vec = dump.offset - pos; | ||
963 | unsigned len = (dump.length > (winsize - pos)) ? | ||
964 | (winsize - pos) : dump.length; | ||
965 | /* relocate window */ | ||
966 | if (sdla_mapmem(&card->hw, vec) != 0) { | ||
967 | err = -EIO; | ||
968 | break; | ||
969 | } | ||
970 | |||
971 | if(copy_to_user((void *)dump.ptr, | ||
972 | (u8 *)card->hw.dpmbase + pos, len)){ | ||
973 | |||
974 | unlock_adapter_irq(&card->wandev.lock, &smp_flags); | ||
975 | return -EFAULT; | ||
976 | } | ||
977 | |||
978 | dump.length -= len; | ||
979 | dump.offset += len; | ||
980 | dump.ptr = (char*)dump.ptr + len; | ||
981 | } | ||
982 | |||
983 | sdla_mapmem(&card->hw, oldvec);/* restore DPM window position */ | ||
984 | unlock_adapter_irq(&card->wandev.lock, &smp_flags); | ||
985 | |||
986 | }else { | ||
987 | |||
988 | if(copy_to_user((void *)dump.ptr, | ||
989 | (u8 *)card->hw.dpmbase + dump.offset, dump.length)){ | ||
990 | return -EFAULT; | ||
991 | } | ||
992 | } | ||
993 | |||
994 | return err; | ||
995 | } | ||
996 | |||
997 | /*============================================================================ | ||
998 | * Execute adapter firmware command. | ||
999 | * o verify request structure | ||
1000 | * o copy request structure to kernel data space | ||
1001 | * o call protocol-specific 'exec' function | ||
1002 | */ | ||
1003 | static int ioctl_exec (sdla_t* card, sdla_exec_t* u_exec, int cmd) | ||
1004 | { | ||
1005 | sdla_exec_t exec; | ||
1006 | int err=0; | ||
1007 | |||
1008 | if (card->exec == NULL && cmd == WANPIPE_EXEC){ | ||
1009 | return -ENODEV; | ||
1010 | } | ||
1011 | |||
1012 | if(copy_from_user((void*)&exec, (void*)u_exec, sizeof(sdla_exec_t))) | ||
1013 | return -EFAULT; | ||
1014 | |||
1015 | if ((exec.magic != WANPIPE_MAGIC) || (exec.cmd == NULL)) | ||
1016 | return -EINVAL; | ||
1017 | |||
1018 | switch (cmd) { | ||
1019 | case WANPIPE_EXEC: | ||
1020 | err = card->exec(card, exec.cmd, exec.data); | ||
1021 | break; | ||
1022 | } | ||
1023 | return err; | ||
1024 | } | ||
1025 | |||
1026 | /******* Miscellaneous ******************************************************/ | ||
1027 | |||
1028 | /*============================================================================ | ||
1029 | * SDLA Interrupt Service Routine. | ||
1030 | * o acknowledge SDLA hardware interrupt. | ||
1031 | * o call protocol-specific interrupt service routine, if any. | ||
1032 | */ | ||
1033 | STATIC irqreturn_t sdla_isr (int irq, void* dev_id, struct pt_regs *regs) | ||
1034 | { | ||
1035 | #define card ((sdla_t*)dev_id) | ||
1036 | |||
1037 | if(card->hw.type == SDLA_S514) { /* handle interrrupt on S514 */ | ||
1038 | u32 int_status; | ||
1039 | unsigned char CPU_no = card->hw.S514_cpu_no[0]; | ||
1040 | unsigned char card_found_for_IRQ; | ||
1041 | u8 IRQ_count = 0; | ||
1042 | |||
1043 | for(;;) { | ||
1044 | |||
1045 | read_S514_int_stat(&card->hw, &int_status); | ||
1046 | |||
1047 | /* check if the interrupt is for this device */ | ||
1048 | if(!((unsigned char)int_status & | ||
1049 | (IRQ_CPU_A | IRQ_CPU_B))) | ||
1050 | return IRQ_HANDLED; | ||
1051 | |||
1052 | /* if the IRQ is for both CPUs on the same adapter, */ | ||
1053 | /* then alter the interrupt status so as to handle */ | ||
1054 | /* one CPU at a time */ | ||
1055 | if(((unsigned char)int_status & (IRQ_CPU_A | IRQ_CPU_B)) | ||
1056 | == (IRQ_CPU_A | IRQ_CPU_B)) { | ||
1057 | int_status &= (CPU_no == S514_CPU_A) ? | ||
1058 | ~IRQ_CPU_B : ~IRQ_CPU_A; | ||
1059 | } | ||
1060 | |||
1061 | card_found_for_IRQ = 0; | ||
1062 | |||
1063 | /* check to see that the CPU number for this device */ | ||
1064 | /* corresponds to the interrupt status read */ | ||
1065 | switch (CPU_no) { | ||
1066 | case S514_CPU_A: | ||
1067 | if((unsigned char)int_status & | ||
1068 | IRQ_CPU_A) | ||
1069 | card_found_for_IRQ = 1; | ||
1070 | break; | ||
1071 | |||
1072 | case S514_CPU_B: | ||
1073 | if((unsigned char)int_status & | ||
1074 | IRQ_CPU_B) | ||
1075 | card_found_for_IRQ = 1; | ||
1076 | break; | ||
1077 | } | ||
1078 | |||
1079 | /* exit if the interrupt is for another CPU on the */ | ||
1080 | /* same IRQ */ | ||
1081 | if(!card_found_for_IRQ) | ||
1082 | return IRQ_HANDLED; | ||
1083 | |||
1084 | if (!card || | ||
1085 | (card->wandev.state == WAN_UNCONFIGURED && !card->configured)){ | ||
1086 | printk(KERN_INFO | ||
1087 | "Received IRQ %d for CPU #%c\n", | ||
1088 | irq, CPU_no); | ||
1089 | printk(KERN_INFO | ||
1090 | "IRQ for unconfigured adapter\n"); | ||
1091 | S514_intack(&card->hw, int_status); | ||
1092 | return IRQ_HANDLED; | ||
1093 | } | ||
1094 | |||
1095 | if (card->in_isr) { | ||
1096 | printk(KERN_INFO | ||
1097 | "%s: interrupt re-entrancy on IRQ %d\n", | ||
1098 | card->devname, card->wandev.irq); | ||
1099 | S514_intack(&card->hw, int_status); | ||
1100 | return IRQ_HANDLED; | ||
1101 | } | ||
1102 | |||
1103 | spin_lock(&card->wandev.lock); | ||
1104 | if (card->next){ | ||
1105 | spin_lock(&card->next->wandev.lock); | ||
1106 | } | ||
1107 | |||
1108 | S514_intack(&card->hw, int_status); | ||
1109 | if (card->isr) | ||
1110 | card->isr(card); | ||
1111 | |||
1112 | if (card->next){ | ||
1113 | spin_unlock(&card->next->wandev.lock); | ||
1114 | } | ||
1115 | spin_unlock(&card->wandev.lock); | ||
1116 | |||
1117 | /* handle a maximum of two interrupts (one for each */ | ||
1118 | /* CPU on the adapter) before returning */ | ||
1119 | if((++ IRQ_count) == 2) | ||
1120 | return IRQ_HANDLED; | ||
1121 | } | ||
1122 | } | ||
1123 | |||
1124 | else { /* handle interrupt on S508 adapter */ | ||
1125 | |||
1126 | if (!card || ((card->wandev.state == WAN_UNCONFIGURED) && !card->configured)) | ||
1127 | return IRQ_HANDLED; | ||
1128 | |||
1129 | if (card->in_isr) { | ||
1130 | printk(KERN_INFO | ||
1131 | "%s: interrupt re-entrancy on IRQ %d!\n", | ||
1132 | card->devname, card->wandev.irq); | ||
1133 | return IRQ_HANDLED; | ||
1134 | } | ||
1135 | |||
1136 | spin_lock(&card->wandev.lock); | ||
1137 | if (card->next){ | ||
1138 | spin_lock(&card->next->wandev.lock); | ||
1139 | } | ||
1140 | |||
1141 | sdla_intack(&card->hw); | ||
1142 | if (card->isr) | ||
1143 | card->isr(card); | ||
1144 | |||
1145 | if (card->next){ | ||
1146 | spin_unlock(&card->next->wandev.lock); | ||
1147 | } | ||
1148 | spin_unlock(&card->wandev.lock); | ||
1149 | |||
1150 | } | ||
1151 | return IRQ_HANDLED; | ||
1152 | #undef card | ||
1153 | } | ||
1154 | |||
1155 | /*============================================================================ | ||
1156 | * This routine is called by the protocol-specific modules when network | ||
1157 | * interface is being open. The only reason we need this, is because we | ||
1158 | * have to call MOD_INC_USE_COUNT, but cannot include 'module.h' where it's | ||
1159 | * defined more than once into the same kernel module. | ||
1160 | */ | ||
1161 | void wanpipe_open (sdla_t* card) | ||
1162 | { | ||
1163 | ++card->open_cnt; | ||
1164 | } | ||
1165 | |||
1166 | /*============================================================================ | ||
1167 | * This routine is called by the protocol-specific modules when network | ||
1168 | * interface is being closed. The only reason we need this, is because we | ||
1169 | * have to call MOD_DEC_USE_COUNT, but cannot include 'module.h' where it's | ||
1170 | * defined more than once into the same kernel module. | ||
1171 | */ | ||
1172 | void wanpipe_close (sdla_t* card) | ||
1173 | { | ||
1174 | --card->open_cnt; | ||
1175 | } | ||
1176 | |||
1177 | /*============================================================================ | ||
1178 | * Set WAN device state. | ||
1179 | */ | ||
1180 | void wanpipe_set_state (sdla_t* card, int state) | ||
1181 | { | ||
1182 | if (card->wandev.state != state) { | ||
1183 | switch (state) { | ||
1184 | case WAN_CONNECTED: | ||
1185 | printk (KERN_INFO "%s: link connected!\n", | ||
1186 | card->devname); | ||
1187 | break; | ||
1188 | |||
1189 | case WAN_CONNECTING: | ||
1190 | printk (KERN_INFO "%s: link connecting...\n", | ||
1191 | card->devname); | ||
1192 | break; | ||
1193 | |||
1194 | case WAN_DISCONNECTED: | ||
1195 | printk (KERN_INFO "%s: link disconnected!\n", | ||
1196 | card->devname); | ||
1197 | break; | ||
1198 | } | ||
1199 | card->wandev.state = state; | ||
1200 | } | ||
1201 | card->state_tick = jiffies; | ||
1202 | } | ||
1203 | |||
1204 | sdla_t * wanpipe_find_card (char *name) | ||
1205 | { | ||
1206 | int cnt; | ||
1207 | for (cnt = 0; cnt < ncards; ++ cnt) { | ||
1208 | sdla_t* card = &card_array[cnt]; | ||
1209 | if (!strcmp(card->devname,name)) | ||
1210 | return card; | ||
1211 | } | ||
1212 | return NULL; | ||
1213 | } | ||
1214 | |||
1215 | sdla_t * wanpipe_find_card_num (int num) | ||
1216 | { | ||
1217 | if (num < 1 || num > ncards) | ||
1218 | return NULL; | ||
1219 | num--; | ||
1220 | return &card_array[num]; | ||
1221 | } | ||
1222 | |||
1223 | /* | ||
1224 | * @work_pointer: work_struct to be done; | ||
1225 | * should already have PREPARE_WORK() or | ||
1226 | * INIT_WORK() done on it by caller; | ||
1227 | */ | ||
1228 | void wanpipe_queue_work (struct work_struct *work_pointer) | ||
1229 | { | ||
1230 | if (test_and_set_bit(1, (void*)&wanpipe_bh_critical)) | ||
1231 | printk(KERN_INFO "CRITICAL IN QUEUING WORK\n"); | ||
1232 | |||
1233 | queue_work(wanpipe_wq, work_pointer); | ||
1234 | clear_bit(1,(void*)&wanpipe_bh_critical); | ||
1235 | } | ||
1236 | |||
1237 | void wakeup_sk_bh(struct net_device *dev) | ||
1238 | { | ||
1239 | wanpipe_common_t *chan = dev->priv; | ||
1240 | |||
1241 | if (test_bit(0,&chan->common_critical)) | ||
1242 | return; | ||
1243 | |||
1244 | if (chan->sk && chan->tx_timer){ | ||
1245 | chan->tx_timer->expires=jiffies+1; | ||
1246 | add_timer(chan->tx_timer); | ||
1247 | } | ||
1248 | } | ||
1249 | |||
1250 | int change_dev_flags(struct net_device *dev, unsigned flags) | ||
1251 | { | ||
1252 | struct ifreq if_info; | ||
1253 | mm_segment_t fs = get_fs(); | ||
1254 | int err; | ||
1255 | |||
1256 | memset(&if_info, 0, sizeof(if_info)); | ||
1257 | strcpy(if_info.ifr_name, dev->name); | ||
1258 | if_info.ifr_flags = flags; | ||
1259 | |||
1260 | set_fs(get_ds()); /* get user space block */ | ||
1261 | err = devinet_ioctl(SIOCSIFFLAGS, &if_info); | ||
1262 | set_fs(fs); | ||
1263 | |||
1264 | return err; | ||
1265 | } | ||
1266 | |||
1267 | unsigned long get_ip_address(struct net_device *dev, int option) | ||
1268 | { | ||
1269 | |||
1270 | struct in_ifaddr *ifaddr; | ||
1271 | struct in_device *in_dev; | ||
1272 | unsigned long addr = 0; | ||
1273 | |||
1274 | rcu_read_lock(); | ||
1275 | if ((in_dev = __in_dev_get_rcu(dev)) == NULL){ | ||
1276 | goto out; | ||
1277 | } | ||
1278 | |||
1279 | if ((ifaddr = in_dev->ifa_list)== NULL ){ | ||
1280 | goto out; | ||
1281 | } | ||
1282 | |||
1283 | switch (option){ | ||
1284 | |||
1285 | case WAN_LOCAL_IP: | ||
1286 | addr = ifaddr->ifa_local; | ||
1287 | break; | ||
1288 | |||
1289 | case WAN_POINTOPOINT_IP: | ||
1290 | addr = ifaddr->ifa_address; | ||
1291 | break; | ||
1292 | |||
1293 | case WAN_NETMASK_IP: | ||
1294 | addr = ifaddr->ifa_mask; | ||
1295 | break; | ||
1296 | |||
1297 | case WAN_BROADCAST_IP: | ||
1298 | addr = ifaddr->ifa_broadcast; | ||
1299 | break; | ||
1300 | default: | ||
1301 | break; | ||
1302 | } | ||
1303 | |||
1304 | out: | ||
1305 | rcu_read_unlock(); | ||
1306 | return addr; | ||
1307 | } | ||
1308 | |||
1309 | void add_gateway(sdla_t *card, struct net_device *dev) | ||
1310 | { | ||
1311 | mm_segment_t oldfs; | ||
1312 | struct rtentry route; | ||
1313 | int res; | ||
1314 | |||
1315 | memset((char*)&route,0,sizeof(struct rtentry)); | ||
1316 | |||
1317 | ((struct sockaddr_in *) | ||
1318 | &(route.rt_dst))->sin_addr.s_addr = 0; | ||
1319 | ((struct sockaddr_in *) | ||
1320 | &(route.rt_dst))->sin_family = AF_INET; | ||
1321 | |||
1322 | ((struct sockaddr_in *) | ||
1323 | &(route.rt_genmask))->sin_addr.s_addr = 0; | ||
1324 | ((struct sockaddr_in *) | ||
1325 | &(route.rt_genmask)) ->sin_family = AF_INET; | ||
1326 | |||
1327 | |||
1328 | route.rt_flags = 0; | ||
1329 | route.rt_dev = dev->name; | ||
1330 | |||
1331 | oldfs = get_fs(); | ||
1332 | set_fs(get_ds()); | ||
1333 | res = ip_rt_ioctl(SIOCADDRT,&route); | ||
1334 | set_fs(oldfs); | ||
1335 | |||
1336 | if (res == 0){ | ||
1337 | printk(KERN_INFO "%s: Gateway added for %s\n", | ||
1338 | card->devname,dev->name); | ||
1339 | } | ||
1340 | |||
1341 | return; | ||
1342 | } | ||
1343 | |||
1344 | MODULE_LICENSE("GPL"); | ||
1345 | |||
1346 | /****** End *********************************************************/ | ||
diff --git a/drivers/net/wan/wanpipe_multppp.c b/drivers/net/wan/wanpipe_multppp.c deleted file mode 100644 index 812a1183c502..000000000000 --- a/drivers/net/wan/wanpipe_multppp.c +++ /dev/null | |||
@@ -1,2358 +0,0 @@ | |||
1 | /***************************************************************************** | ||
2 | * wanpipe_multppp.c Multi-Port PPP driver module. | ||
3 | * | ||
4 | * Authors: Nenad Corbic <ncorbic@sangoma.com> | ||
5 | * | ||
6 | * Copyright: (c) 1995-2001 Sangoma Technologies Inc. | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License | ||
10 | * as published by the Free Software Foundation; either version | ||
11 | * 2 of the License, or (at your option) any later version. | ||
12 | * ============================================================================ | ||
13 | * Dec 15 2000 Updated for 2.4.X kernel | ||
14 | * Nov 15 2000 Fixed the SyncPPP support for kernels 2.2.16 and higher. | ||
15 | * The pppstruct has changed. | ||
16 | * Jul 13 2000 Using the kernel Syncppp module on top of RAW Wanpipe CHDLC | ||
17 | * module. | ||
18 | *****************************************************************************/ | ||
19 | |||
20 | #include <linux/module.h> | ||
21 | #include <linux/kernel.h> /* printk(), and other useful stuff */ | ||
22 | #include <linux/stddef.h> /* offsetof(), etc. */ | ||
23 | #include <linux/errno.h> /* return codes */ | ||
24 | #include <linux/string.h> /* inline memset(), etc. */ | ||
25 | #include <linux/slab.h> /* kmalloc(), kfree() */ | ||
26 | #include <linux/wanrouter.h> /* WAN router definitions */ | ||
27 | #include <linux/wanpipe.h> /* WANPIPE common user API definitions */ | ||
28 | #include <linux/if_arp.h> /* ARPHRD_* defines */ | ||
29 | #include <linux/jiffies.h> /* time_after() macro */ | ||
30 | |||
31 | #include <linux/in.h> /* sockaddr_in */ | ||
32 | #include <linux/inet.h> | ||
33 | #include <linux/if.h> | ||
34 | #include <asm/byteorder.h> /* htons(), etc. */ | ||
35 | #include <linux/sdlapci.h> | ||
36 | #include <asm/io.h> | ||
37 | |||
38 | #include <linux/sdla_chdlc.h> /* CHDLC firmware API definitions */ | ||
39 | #include <linux/sdla_asy.h> /* CHDLC (async) API definitions */ | ||
40 | |||
41 | #include <linux/if_wanpipe_common.h> /* Socket Driver common area */ | ||
42 | #include <linux/if_wanpipe.h> | ||
43 | |||
44 | |||
45 | #include <linux/inetdevice.h> | ||
46 | #include <asm/uaccess.h> | ||
47 | |||
48 | #include <net/syncppp.h> | ||
49 | |||
50 | |||
51 | /****** Defines & Macros ****************************************************/ | ||
52 | |||
53 | #ifdef _DEBUG_ | ||
54 | #define STATIC | ||
55 | #else | ||
56 | #define STATIC static | ||
57 | #endif | ||
58 | |||
59 | /* reasons for enabling the timer interrupt on the adapter */ | ||
60 | #define TMR_INT_ENABLED_UDP 0x01 | ||
61 | #define TMR_INT_ENABLED_UPDATE 0x02 | ||
62 | #define TMR_INT_ENABLED_CONFIG 0x04 | ||
63 | |||
64 | #define CHDLC_DFLT_DATA_LEN 1500 /* default MTU */ | ||
65 | #define CHDLC_HDR_LEN 1 | ||
66 | |||
67 | #define IFF_POINTTOPOINT 0x10 | ||
68 | |||
69 | #define CHDLC_API 0x01 | ||
70 | |||
71 | #define PORT(x) (x == 0 ? "PRIMARY" : "SECONDARY" ) | ||
72 | #define MAX_BH_BUFF 10 | ||
73 | |||
74 | #define CRC_LENGTH 2 | ||
75 | #define PPP_HEADER_LEN 4 | ||
76 | |||
77 | /******Data Structures*****************************************************/ | ||
78 | |||
79 | /* This structure is placed in the private data area of the device structure. | ||
80 | * The card structure used to occupy the private area but now the following | ||
81 | * structure will incorporate the card structure along with CHDLC specific data | ||
82 | */ | ||
83 | |||
84 | typedef struct chdlc_private_area | ||
85 | { | ||
86 | void *if_ptr; /* General Pointer used by SPPP */ | ||
87 | wanpipe_common_t common; | ||
88 | sdla_t *card; | ||
89 | int TracingEnabled; /* For enabling Tracing */ | ||
90 | unsigned long curr_trace_addr; /* Used for Tracing */ | ||
91 | unsigned long start_trace_addr; | ||
92 | unsigned long end_trace_addr; | ||
93 | unsigned long base_addr_trace_buffer; | ||
94 | unsigned long end_addr_trace_buffer; | ||
95 | unsigned short number_trace_elements; | ||
96 | unsigned available_buffer_space; | ||
97 | unsigned long router_start_time; | ||
98 | unsigned char route_status; | ||
99 | unsigned char route_removed; | ||
100 | unsigned long tick_counter; /* For 5s timeout counter */ | ||
101 | unsigned long router_up_time; | ||
102 | u32 IP_address; /* IP addressing */ | ||
103 | u32 IP_netmask; | ||
104 | unsigned char mc; /* Mulitcast support on/off */ | ||
105 | unsigned short udp_pkt_lgth; /* udp packet processing */ | ||
106 | char udp_pkt_src; | ||
107 | char udp_pkt_data[MAX_LGTH_UDP_MGNT_PKT]; | ||
108 | unsigned short timer_int_enabled; | ||
109 | char update_comms_stats; /* updating comms stats */ | ||
110 | |||
111 | //FIXME: add driver stats as per frame relay! | ||
112 | |||
113 | } chdlc_private_area_t; | ||
114 | |||
115 | /* Route Status options */ | ||
116 | #define NO_ROUTE 0x00 | ||
117 | #define ADD_ROUTE 0x01 | ||
118 | #define ROUTE_ADDED 0x02 | ||
119 | #define REMOVE_ROUTE 0x03 | ||
120 | |||
121 | |||
122 | /* variable for keeping track of enabling/disabling FT1 monitor status */ | ||
123 | static int rCount = 0; | ||
124 | |||
125 | /* variable for tracking how many interfaces to open for WANPIPE on the | ||
126 | two ports */ | ||
127 | |||
128 | extern void disable_irq(unsigned int); | ||
129 | extern void enable_irq(unsigned int); | ||
130 | |||
131 | /****** Function Prototypes *************************************************/ | ||
132 | /* WAN link driver entry points. These are called by the WAN router module. */ | ||
133 | static int update(struct wan_device* wandev); | ||
134 | static int new_if(struct wan_device* wandev, struct net_device* dev, | ||
135 | wanif_conf_t* conf); | ||
136 | static int del_if(struct wan_device* wandev, struct net_device* dev); | ||
137 | |||
138 | /* Network device interface */ | ||
139 | static int if_init(struct net_device* dev); | ||
140 | static int if_open(struct net_device* dev); | ||
141 | static int if_close(struct net_device* dev); | ||
142 | static int if_send(struct sk_buff* skb, struct net_device* dev); | ||
143 | static struct net_device_stats* if_stats(struct net_device* dev); | ||
144 | |||
145 | static void if_tx_timeout(struct net_device *dev); | ||
146 | |||
147 | /* CHDLC Firmware interface functions */ | ||
148 | static int chdlc_configure (sdla_t* card, void* data); | ||
149 | static int chdlc_comm_enable (sdla_t* card); | ||
150 | static int chdlc_comm_disable (sdla_t* card); | ||
151 | static int chdlc_read_version (sdla_t* card, char* str); | ||
152 | static int chdlc_set_intr_mode (sdla_t* card, unsigned mode); | ||
153 | static int chdlc_send (sdla_t* card, void* data, unsigned len); | ||
154 | static int chdlc_read_comm_err_stats (sdla_t* card); | ||
155 | static int chdlc_read_op_stats (sdla_t* card); | ||
156 | static int config_chdlc (sdla_t *card); | ||
157 | |||
158 | |||
159 | /* Miscellaneous CHDLC Functions */ | ||
160 | static int set_chdlc_config (sdla_t* card); | ||
161 | static void init_chdlc_tx_rx_buff(sdla_t* card, struct net_device *dev); | ||
162 | static int chdlc_error (sdla_t *card, int err, CHDLC_MAILBOX_STRUCT *mb); | ||
163 | static int process_chdlc_exception(sdla_t *card); | ||
164 | static int process_global_exception(sdla_t *card); | ||
165 | static int update_comms_stats(sdla_t* card, | ||
166 | chdlc_private_area_t* chdlc_priv_area); | ||
167 | static void port_set_state (sdla_t *card, int); | ||
168 | |||
169 | /* Interrupt handlers */ | ||
170 | static void wsppp_isr (sdla_t* card); | ||
171 | static void rx_intr (sdla_t* card); | ||
172 | static void timer_intr(sdla_t *); | ||
173 | |||
174 | /* Miscellaneous functions */ | ||
175 | static int reply_udp( unsigned char *data, unsigned int mbox_len ); | ||
176 | static int intr_test( sdla_t* card); | ||
177 | static int udp_pkt_type( struct sk_buff *skb , sdla_t* card); | ||
178 | static int store_udp_mgmt_pkt(char udp_pkt_src, sdla_t* card, | ||
179 | struct sk_buff *skb, struct net_device* dev, | ||
180 | chdlc_private_area_t* chdlc_priv_area); | ||
181 | static int process_udp_mgmt_pkt(sdla_t* card, struct net_device* dev, | ||
182 | chdlc_private_area_t* chdlc_priv_area); | ||
183 | static unsigned short calc_checksum (char *, int); | ||
184 | static void s508_lock (sdla_t *card, unsigned long *smp_flags); | ||
185 | static void s508_unlock (sdla_t *card, unsigned long *smp_flags); | ||
186 | static void send_ppp_term_request(struct net_device *dev); | ||
187 | |||
188 | |||
189 | static int Intr_test_counter; | ||
190 | /****** Public Functions ****************************************************/ | ||
191 | |||
192 | /*============================================================================ | ||
193 | * Cisco HDLC protocol initialization routine. | ||
194 | * | ||
195 | * This routine is called by the main WANPIPE module during setup. At this | ||
196 | * point adapter is completely initialized and firmware is running. | ||
197 | * o read firmware version (to make sure it's alive) | ||
198 | * o configure adapter | ||
199 | * o initialize protocol-specific fields of the adapter data space. | ||
200 | * | ||
201 | * Return: 0 o.k. | ||
202 | * < 0 failure. | ||
203 | */ | ||
204 | int wsppp_init (sdla_t* card, wandev_conf_t* conf) | ||
205 | { | ||
206 | unsigned char port_num; | ||
207 | int err; | ||
208 | unsigned long max_permitted_baud = 0; | ||
209 | SHARED_MEMORY_INFO_STRUCT *flags; | ||
210 | |||
211 | union | ||
212 | { | ||
213 | char str[80]; | ||
214 | } u; | ||
215 | volatile CHDLC_MAILBOX_STRUCT* mb; | ||
216 | CHDLC_MAILBOX_STRUCT* mb1; | ||
217 | unsigned long timeout; | ||
218 | |||
219 | /* Verify configuration ID */ | ||
220 | if (conf->config_id != WANCONFIG_MPPP) { | ||
221 | printk(KERN_INFO "%s: invalid configuration ID %u!\n", | ||
222 | card->devname, conf->config_id); | ||
223 | return -EINVAL; | ||
224 | } | ||
225 | |||
226 | /* Find out which Port to use */ | ||
227 | if ((conf->comm_port == WANOPT_PRI) || (conf->comm_port == WANOPT_SEC)){ | ||
228 | if (card->next){ | ||
229 | |||
230 | if (conf->comm_port != card->next->u.c.comm_port){ | ||
231 | card->u.c.comm_port = conf->comm_port; | ||
232 | }else{ | ||
233 | printk(KERN_ERR "%s: ERROR - %s port used!\n", | ||
234 | card->wandev.name, PORT(conf->comm_port)); | ||
235 | return -EINVAL; | ||
236 | } | ||
237 | }else{ | ||
238 | card->u.c.comm_port = conf->comm_port; | ||
239 | } | ||
240 | }else{ | ||
241 | printk(KERN_ERR "%s: ERROR - Invalid Port Selected!\n", | ||
242 | card->wandev.name); | ||
243 | return -EINVAL; | ||
244 | } | ||
245 | |||
246 | |||
247 | /* Initialize protocol-specific fields */ | ||
248 | if(card->hw.type != SDLA_S514){ | ||
249 | |||
250 | if (card->u.c.comm_port == WANOPT_PRI){ | ||
251 | card->mbox = (void *) card->hw.dpmbase; | ||
252 | }else{ | ||
253 | card->mbox = (void *) card->hw.dpmbase + | ||
254 | SEC_BASE_ADDR_MB_STRUCT - PRI_BASE_ADDR_MB_STRUCT; | ||
255 | } | ||
256 | }else{ | ||
257 | /* for a S514 adapter, set a pointer to the actual mailbox in the */ | ||
258 | /* allocated virtual memory area */ | ||
259 | if (card->u.c.comm_port == WANOPT_PRI){ | ||
260 | card->mbox = (void *) card->hw.dpmbase + PRI_BASE_ADDR_MB_STRUCT; | ||
261 | }else{ | ||
262 | card->mbox = (void *) card->hw.dpmbase + SEC_BASE_ADDR_MB_STRUCT; | ||
263 | } | ||
264 | } | ||
265 | |||
266 | mb = mb1 = card->mbox; | ||
267 | |||
268 | if (!card->configured){ | ||
269 | |||
270 | /* The board will place an 'I' in the return code to indicate that it is | ||
271 | ready to accept commands. We expect this to be completed in less | ||
272 | than 1 second. */ | ||
273 | |||
274 | timeout = jiffies + 1 * HZ; | ||
275 | while (mb->return_code != 'I') /* Wait 1s for board to initialize */ | ||
276 | if (time_after(jiffies, timeout)) break; | ||
277 | |||
278 | if (mb->return_code != 'I') { | ||
279 | printk(KERN_INFO | ||
280 | "%s: Initialization not completed by adapter\n", | ||
281 | card->devname); | ||
282 | printk(KERN_INFO "Please contact Sangoma representative.\n"); | ||
283 | return -EIO; | ||
284 | } | ||
285 | } | ||
286 | |||
287 | /* Read firmware version. Note that when adapter initializes, it | ||
288 | * clears the mailbox, so it may appear that the first command was | ||
289 | * executed successfully when in fact it was merely erased. To work | ||
290 | * around this, we execute the first command twice. | ||
291 | */ | ||
292 | |||
293 | if (chdlc_read_version(card, u.str)) | ||
294 | return -EIO; | ||
295 | |||
296 | printk(KERN_INFO "%s: Running Raw CHDLC firmware v%s\n" | ||
297 | "%s: for Multi-Port PPP protocol.\n", | ||
298 | card->devname,u.str,card->devname); | ||
299 | |||
300 | card->isr = &wsppp_isr; | ||
301 | card->poll = NULL; | ||
302 | card->exec = NULL; | ||
303 | card->wandev.update = &update; | ||
304 | card->wandev.new_if = &new_if; | ||
305 | card->wandev.del_if = &del_if; | ||
306 | card->wandev.udp_port = conf->udp_port; | ||
307 | |||
308 | card->wandev.new_if_cnt = 0; | ||
309 | |||
310 | /* reset the number of times the 'update()' proc has been called */ | ||
311 | card->u.c.update_call_count = 0; | ||
312 | |||
313 | card->wandev.ttl = conf->ttl; | ||
314 | card->wandev.interface = conf->interface; | ||
315 | |||
316 | if ((card->u.c.comm_port == WANOPT_SEC && conf->interface == WANOPT_V35)&& | ||
317 | card->hw.type != SDLA_S514){ | ||
318 | printk(KERN_INFO "%s: ERROR - V35 Interface not supported on S508 %s port \n", | ||
319 | card->devname, PORT(card->u.c.comm_port)); | ||
320 | return -EIO; | ||
321 | } | ||
322 | |||
323 | |||
324 | card->wandev.clocking = conf->clocking; | ||
325 | |||
326 | port_num = card->u.c.comm_port; | ||
327 | |||
328 | /* Setup Port Bps */ | ||
329 | |||
330 | if(card->wandev.clocking) { | ||
331 | if((port_num == WANOPT_PRI) || card->u.c.receive_only) { | ||
332 | /* For Primary Port 0 */ | ||
333 | max_permitted_baud = | ||
334 | (card->hw.type == SDLA_S514) ? | ||
335 | PRI_MAX_BAUD_RATE_S514 : | ||
336 | PRI_MAX_BAUD_RATE_S508; | ||
337 | } | ||
338 | else if(port_num == WANOPT_SEC) { | ||
339 | /* For Secondary Port 1 */ | ||
340 | max_permitted_baud = | ||
341 | (card->hw.type == SDLA_S514) ? | ||
342 | SEC_MAX_BAUD_RATE_S514 : | ||
343 | SEC_MAX_BAUD_RATE_S508; | ||
344 | } | ||
345 | |||
346 | if(conf->bps > max_permitted_baud) { | ||
347 | conf->bps = max_permitted_baud; | ||
348 | printk(KERN_INFO "%s: Baud too high!\n", | ||
349 | card->wandev.name); | ||
350 | printk(KERN_INFO "%s: Baud rate set to %lu bps\n", | ||
351 | card->wandev.name, max_permitted_baud); | ||
352 | } | ||
353 | |||
354 | card->wandev.bps = conf->bps; | ||
355 | }else{ | ||
356 | card->wandev.bps = 0; | ||
357 | } | ||
358 | |||
359 | /* Setup the Port MTU */ | ||
360 | if((port_num == WANOPT_PRI) || card->u.c.receive_only) { | ||
361 | |||
362 | /* For Primary Port 0 */ | ||
363 | card->wandev.mtu = | ||
364 | (conf->mtu >= MIN_LGTH_CHDLC_DATA_CFG) ? | ||
365 | min_t(unsigned int, conf->mtu, PRI_MAX_NO_DATA_BYTES_IN_FRAME) : | ||
366 | CHDLC_DFLT_DATA_LEN; | ||
367 | } else if(port_num == WANOPT_SEC) { | ||
368 | /* For Secondary Port 1 */ | ||
369 | card->wandev.mtu = | ||
370 | (conf->mtu >= MIN_LGTH_CHDLC_DATA_CFG) ? | ||
371 | min_t(unsigned int, conf->mtu, SEC_MAX_NO_DATA_BYTES_IN_FRAME) : | ||
372 | CHDLC_DFLT_DATA_LEN; | ||
373 | } | ||
374 | |||
375 | /* Add on a PPP Header */ | ||
376 | card->wandev.mtu += PPP_HEADER_LEN; | ||
377 | |||
378 | /* Set up the interrupt status area */ | ||
379 | /* Read the CHDLC Configuration and obtain: | ||
380 | * Ptr to shared memory infor struct | ||
381 | * Use this pointer to calculate the value of card->u.c.flags ! | ||
382 | */ | ||
383 | mb1->buffer_length = 0; | ||
384 | mb1->command = READ_CHDLC_CONFIGURATION; | ||
385 | err = sdla_exec(mb1) ? mb1->return_code : CMD_TIMEOUT; | ||
386 | if(err != COMMAND_OK) { | ||
387 | clear_bit(1, (void*)&card->wandev.critical); | ||
388 | |||
389 | if(card->hw.type != SDLA_S514) | ||
390 | enable_irq(card->hw.irq); | ||
391 | |||
392 | chdlc_error(card, err, mb1); | ||
393 | return -EIO; | ||
394 | } | ||
395 | |||
396 | if(card->hw.type == SDLA_S514){ | ||
397 | card->u.c.flags = (void *)(card->hw.dpmbase + | ||
398 | (((CHDLC_CONFIGURATION_STRUCT *)mb1->data)-> | ||
399 | ptr_shared_mem_info_struct)); | ||
400 | }else{ | ||
401 | card->u.c.flags = (void *)(card->hw.dpmbase + | ||
402 | (((CHDLC_CONFIGURATION_STRUCT *)mb1->data)-> | ||
403 | ptr_shared_mem_info_struct % SDLA_WINDOWSIZE)); | ||
404 | } | ||
405 | |||
406 | flags = card->u.c.flags; | ||
407 | |||
408 | /* This is for the ports link state */ | ||
409 | card->wandev.state = WAN_DUALPORT; | ||
410 | card->u.c.state = WAN_DISCONNECTED; | ||
411 | |||
412 | |||
413 | if (!card->wandev.piggyback){ | ||
414 | err = intr_test(card); | ||
415 | |||
416 | if(err || (Intr_test_counter < MAX_INTR_TEST_COUNTER)) { | ||
417 | printk(KERN_ERR "%s: Interrupt test failed (%i)\n", | ||
418 | card->devname, Intr_test_counter); | ||
419 | printk(KERN_ERR "%s: Please choose another interrupt\n", | ||
420 | card->devname); | ||
421 | return -EIO; | ||
422 | } | ||
423 | |||
424 | printk(KERN_INFO "%s: Interrupt test passed (%i)\n", | ||
425 | card->devname, Intr_test_counter); | ||
426 | } | ||
427 | |||
428 | |||
429 | if (chdlc_set_intr_mode(card, APP_INT_ON_TIMER)){ | ||
430 | printk (KERN_INFO "%s: Failed to set interrupt triggers!\n", | ||
431 | card->devname); | ||
432 | return -EIO; | ||
433 | } | ||
434 | |||
435 | /* Mask the Timer interrupt */ | ||
436 | flags->interrupt_info_struct.interrupt_permission &= | ||
437 | ~APP_INT_ON_TIMER; | ||
438 | |||
439 | printk(KERN_INFO "\n"); | ||
440 | |||
441 | return 0; | ||
442 | } | ||
443 | |||
444 | /******* WAN Device Driver Entry Points *************************************/ | ||
445 | |||
446 | /*============================================================================ | ||
447 | * Update device status & statistics | ||
448 | * This procedure is called when updating the PROC file system and returns | ||
449 | * various communications statistics. These statistics are accumulated from 3 | ||
450 | * different locations: | ||
451 | * 1) The 'if_stats' recorded for the device. | ||
452 | * 2) Communication error statistics on the adapter. | ||
453 | * 3) CHDLC operational statistics on the adapter. | ||
454 | * The board level statistics are read during a timer interrupt. Note that we | ||
455 | * read the error and operational statistics during consecitive timer ticks so | ||
456 | * as to minimize the time that we are inside the interrupt handler. | ||
457 | * | ||
458 | */ | ||
459 | static int update(struct wan_device* wandev) | ||
460 | { | ||
461 | sdla_t* card = wandev->private; | ||
462 | struct net_device* dev; | ||
463 | volatile chdlc_private_area_t* chdlc_priv_area; | ||
464 | SHARED_MEMORY_INFO_STRUCT *flags; | ||
465 | unsigned long timeout; | ||
466 | |||
467 | /* sanity checks */ | ||
468 | if((wandev == NULL) || (wandev->private == NULL)) | ||
469 | return -EFAULT; | ||
470 | |||
471 | if(wandev->state == WAN_UNCONFIGURED) | ||
472 | return -ENODEV; | ||
473 | |||
474 | /* more sanity checks */ | ||
475 | if(!card->u.c.flags) | ||
476 | return -ENODEV; | ||
477 | |||
478 | if((dev=card->wandev.dev) == NULL) | ||
479 | return -ENODEV; | ||
480 | |||
481 | if((chdlc_priv_area=dev->priv) == NULL) | ||
482 | return -ENODEV; | ||
483 | |||
484 | flags = card->u.c.flags; | ||
485 | |||
486 | if(chdlc_priv_area->update_comms_stats){ | ||
487 | return -EAGAIN; | ||
488 | } | ||
489 | |||
490 | /* we will need 2 timer interrupts to complete the */ | ||
491 | /* reading of the statistics */ | ||
492 | chdlc_priv_area->update_comms_stats = 2; | ||
493 | flags->interrupt_info_struct.interrupt_permission |= APP_INT_ON_TIMER; | ||
494 | chdlc_priv_area->timer_int_enabled = TMR_INT_ENABLED_UPDATE; | ||
495 | |||
496 | /* wait a maximum of 1 second for the statistics to be updated */ | ||
497 | timeout = jiffies + 1 * HZ; | ||
498 | for(;;) { | ||
499 | if(chdlc_priv_area->update_comms_stats == 0) | ||
500 | break; | ||
501 | if (time_after(jiffies, timeout)){ | ||
502 | chdlc_priv_area->update_comms_stats = 0; | ||
503 | chdlc_priv_area->timer_int_enabled &= | ||
504 | ~TMR_INT_ENABLED_UPDATE; | ||
505 | return -EAGAIN; | ||
506 | } | ||
507 | } | ||
508 | |||
509 | return 0; | ||
510 | } | ||
511 | |||
512 | |||
513 | /*============================================================================ | ||
514 | * Create new logical channel. | ||
515 | * This routine is called by the router when ROUTER_IFNEW IOCTL is being | ||
516 | * handled. | ||
517 | * o parse media- and hardware-specific configuration | ||
518 | * o make sure that a new channel can be created | ||
519 | * o allocate resources, if necessary | ||
520 | * o prepare network device structure for registaration. | ||
521 | * | ||
522 | * Return: 0 o.k. | ||
523 | * < 0 failure (channel will not be created) | ||
524 | */ | ||
525 | static int new_if(struct wan_device* wandev, struct net_device* pdev, | ||
526 | wanif_conf_t* conf) | ||
527 | { | ||
528 | |||
529 | struct ppp_device *pppdev = (struct ppp_device *)pdev; | ||
530 | struct net_device *dev = NULL; | ||
531 | struct sppp *sp; | ||
532 | sdla_t* card = wandev->private; | ||
533 | chdlc_private_area_t* chdlc_priv_area; | ||
534 | |||
535 | if ((conf->name[0] == '\0') || (strlen(conf->name) > WAN_IFNAME_SZ)) { | ||
536 | printk(KERN_INFO "%s: invalid interface name!\n", | ||
537 | card->devname); | ||
538 | return -EINVAL; | ||
539 | } | ||
540 | |||
541 | /* allocate and initialize private data */ | ||
542 | chdlc_priv_area = kmalloc(sizeof(chdlc_private_area_t), GFP_KERNEL); | ||
543 | |||
544 | if(chdlc_priv_area == NULL) | ||
545 | return -ENOMEM; | ||
546 | |||
547 | memset(chdlc_priv_area, 0, sizeof(chdlc_private_area_t)); | ||
548 | |||
549 | chdlc_priv_area->card = card; | ||
550 | |||
551 | /* initialize data */ | ||
552 | strcpy(card->u.c.if_name, conf->name); | ||
553 | |||
554 | if(card->wandev.new_if_cnt > 0) { | ||
555 | kfree(chdlc_priv_area); | ||
556 | return -EEXIST; | ||
557 | } | ||
558 | |||
559 | card->wandev.new_if_cnt++; | ||
560 | |||
561 | chdlc_priv_area->TracingEnabled = 0; | ||
562 | |||
563 | //We don't need this any more | ||
564 | chdlc_priv_area->route_status = NO_ROUTE; | ||
565 | chdlc_priv_area->route_removed = 0; | ||
566 | |||
567 | printk(KERN_INFO "%s: Firmware running in HDLC STREAMING Mode\n", | ||
568 | wandev->name); | ||
569 | |||
570 | /* Setup wanpipe as a router (WANPIPE) or as an API */ | ||
571 | if( strcmp(conf->usedby, "WANPIPE") == 0) { | ||
572 | printk(KERN_INFO "%s: Driver running in WANPIPE mode!\n", | ||
573 | wandev->name); | ||
574 | card->u.c.usedby = WANPIPE; | ||
575 | } else { | ||
576 | printk(KERN_INFO | ||
577 | "%s: API Mode is not supported for SyncPPP!\n", | ||
578 | wandev->name); | ||
579 | kfree(chdlc_priv_area); | ||
580 | return -EINVAL; | ||
581 | } | ||
582 | |||
583 | /* Get Multicast Information */ | ||
584 | chdlc_priv_area->mc = conf->mc; | ||
585 | |||
586 | |||
587 | chdlc_priv_area->if_ptr = pppdev; | ||
588 | |||
589 | /* prepare network device data space for registration */ | ||
590 | |||
591 | strcpy(dev->name,card->u.c.if_name); | ||
592 | |||
593 | /* Attach PPP protocol layer to pppdev | ||
594 | * The sppp_attach() will initilize the dev structure | ||
595 | * and setup ppp layer protocols. | ||
596 | * All we have to do is to bind in: | ||
597 | * if_open(), if_close(), if_send() and get_stats() functions. | ||
598 | */ | ||
599 | sppp_attach(pppdev); | ||
600 | dev = pppdev->dev; | ||
601 | sp = &pppdev->sppp; | ||
602 | |||
603 | /* Enable PPP Debugging */ | ||
604 | // FIXME Fix this up somehow | ||
605 | //sp->pp_flags |= PP_DEBUG; | ||
606 | sp->pp_flags &= ~PP_CISCO; | ||
607 | |||
608 | dev->init = &if_init; | ||
609 | dev->priv = chdlc_priv_area; | ||
610 | |||
611 | return 0; | ||
612 | } | ||
613 | |||
614 | |||
615 | |||
616 | |||
617 | /*============================================================================ | ||
618 | * Delete logical channel. | ||
619 | */ | ||
620 | static int del_if(struct wan_device* wandev, struct net_device* dev) | ||
621 | { | ||
622 | chdlc_private_area_t *chdlc_priv_area = dev->priv; | ||
623 | sdla_t *card = chdlc_priv_area->card; | ||
624 | unsigned long smp_lock; | ||
625 | |||
626 | /* Detach the PPP layer */ | ||
627 | printk(KERN_INFO "%s: Detaching SyncPPP Module from %s\n", | ||
628 | wandev->name,dev->name); | ||
629 | |||
630 | lock_adapter_irq(&wandev->lock,&smp_lock); | ||
631 | |||
632 | sppp_detach(dev); | ||
633 | chdlc_priv_area->if_ptr=NULL; | ||
634 | |||
635 | chdlc_set_intr_mode(card, 0); | ||
636 | if (card->u.c.comm_enabled) | ||
637 | chdlc_comm_disable(card); | ||
638 | unlock_adapter_irq(&wandev->lock,&smp_lock); | ||
639 | |||
640 | port_set_state(card, WAN_DISCONNECTED); | ||
641 | |||
642 | return 0; | ||
643 | } | ||
644 | |||
645 | |||
646 | /****** Network Device Interface ********************************************/ | ||
647 | |||
648 | /*============================================================================ | ||
649 | * Initialize Linux network interface. | ||
650 | * | ||
651 | * This routine is called only once for each interface, during Linux network | ||
652 | * interface registration. Returning anything but zero will fail interface | ||
653 | * registration. | ||
654 | */ | ||
655 | static int if_init(struct net_device* dev) | ||
656 | { | ||
657 | chdlc_private_area_t* chdlc_priv_area = dev->priv; | ||
658 | sdla_t* card = chdlc_priv_area->card; | ||
659 | struct wan_device* wandev = &card->wandev; | ||
660 | |||
661 | /* NOTE: Most of the dev initialization was | ||
662 | * done in sppp_attach(), called by new_if() | ||
663 | * function. All we have to do here is | ||
664 | * to link four major routines below. | ||
665 | */ | ||
666 | |||
667 | /* Initialize device driver entry points */ | ||
668 | dev->open = &if_open; | ||
669 | dev->stop = &if_close; | ||
670 | dev->hard_start_xmit = &if_send; | ||
671 | dev->get_stats = &if_stats; | ||
672 | dev->tx_timeout = &if_tx_timeout; | ||
673 | dev->watchdog_timeo = TX_TIMEOUT; | ||
674 | |||
675 | |||
676 | /* Initialize hardware parameters */ | ||
677 | dev->irq = wandev->irq; | ||
678 | dev->dma = wandev->dma; | ||
679 | dev->base_addr = wandev->ioport; | ||
680 | dev->mem_start = wandev->maddr; | ||
681 | dev->mem_end = wandev->maddr + wandev->msize - 1; | ||
682 | |||
683 | /* Set transmit buffer queue length | ||
684 | * If we over fill this queue the packets will | ||
685 | * be droped by the kernel. | ||
686 | * sppp_attach() sets this to 10, but | ||
687 | * 100 will give us more room at low speeds. | ||
688 | */ | ||
689 | dev->tx_queue_len = 100; | ||
690 | |||
691 | return 0; | ||
692 | } | ||
693 | |||
694 | |||
695 | /*============================================================================ | ||
696 | * Handle transmit timeout event from netif watchdog | ||
697 | */ | ||
698 | static void if_tx_timeout(struct net_device *dev) | ||
699 | { | ||
700 | chdlc_private_area_t* chan = dev->priv; | ||
701 | sdla_t *card = chan->card; | ||
702 | |||
703 | /* If our device stays busy for at least 5 seconds then we will | ||
704 | * kick start the device by making dev->tbusy = 0. We expect | ||
705 | * that our device never stays busy more than 5 seconds. So this | ||
706 | * is only used as a last resort. | ||
707 | */ | ||
708 | |||
709 | ++card->wandev.stats.collisions; | ||
710 | |||
711 | printk (KERN_INFO "%s: Transmit timed out on %s\n", card->devname,dev->name); | ||
712 | netif_wake_queue (dev); | ||
713 | } | ||
714 | |||
715 | |||
716 | /*============================================================================ | ||
717 | * Open network interface. | ||
718 | * o enable communications and interrupts. | ||
719 | * o prevent module from unloading by incrementing use count | ||
720 | * | ||
721 | * Return 0 if O.k. or errno. | ||
722 | */ | ||
723 | static int if_open(struct net_device* dev) | ||
724 | { | ||
725 | chdlc_private_area_t* chdlc_priv_area = dev->priv; | ||
726 | sdla_t* card = chdlc_priv_area->card; | ||
727 | struct timeval tv; | ||
728 | SHARED_MEMORY_INFO_STRUCT *flags = card->u.c.flags; | ||
729 | |||
730 | /* Only one open per interface is allowed */ | ||
731 | if (netif_running(dev)) | ||
732 | return -EBUSY; | ||
733 | |||
734 | /* Start PPP Layer */ | ||
735 | if (sppp_open(dev)){ | ||
736 | return -EIO; | ||
737 | } | ||
738 | |||
739 | do_gettimeofday(&tv); | ||
740 | chdlc_priv_area->router_start_time = tv.tv_sec; | ||
741 | |||
742 | netif_start_queue(dev); | ||
743 | |||
744 | wanpipe_open(card); | ||
745 | |||
746 | chdlc_priv_area->timer_int_enabled |= TMR_INT_ENABLED_CONFIG; | ||
747 | flags->interrupt_info_struct.interrupt_permission |= APP_INT_ON_TIMER; | ||
748 | return 0; | ||
749 | } | ||
750 | |||
751 | /*============================================================================ | ||
752 | * Close network interface. | ||
753 | * o if this is the last close, then disable communications and interrupts. | ||
754 | * o reset flags. | ||
755 | */ | ||
756 | static int if_close(struct net_device* dev) | ||
757 | { | ||
758 | chdlc_private_area_t* chdlc_priv_area = dev->priv; | ||
759 | sdla_t* card = chdlc_priv_area->card; | ||
760 | |||
761 | /* Stop the PPP Layer */ | ||
762 | sppp_close(dev); | ||
763 | netif_stop_queue(dev); | ||
764 | |||
765 | wanpipe_close(card); | ||
766 | |||
767 | return 0; | ||
768 | } | ||
769 | |||
770 | /*============================================================================ | ||
771 | * Send a packet on a network interface. | ||
772 | * o set tbusy flag (marks start of the transmission) to block a timer-based | ||
773 | * transmit from overlapping. | ||
774 | * o check link state. If link is not up, then drop the packet. | ||
775 | * o execute adapter send command. | ||
776 | * o free socket buffer | ||
777 | * | ||
778 | * Return: 0 complete (socket buffer must be freed) | ||
779 | * non-0 packet may be re-transmitted (tbusy must be set) | ||
780 | * | ||
781 | * Notes: | ||
782 | * 1. This routine is called either by the protocol stack or by the "net | ||
783 | * bottom half" (with interrupts enabled). | ||
784 | * 2. Setting tbusy flag will inhibit further transmit requests from the | ||
785 | * protocol stack and can be used for flow control with protocol layer. | ||
786 | */ | ||
787 | static int if_send(struct sk_buff* skb, struct net_device* dev) | ||
788 | { | ||
789 | chdlc_private_area_t *chdlc_priv_area = dev->priv; | ||
790 | sdla_t *card = chdlc_priv_area->card; | ||
791 | SHARED_MEMORY_INFO_STRUCT *flags = card->u.c.flags; | ||
792 | INTERRUPT_INFORMATION_STRUCT *chdlc_int = &flags->interrupt_info_struct; | ||
793 | int udp_type = 0; | ||
794 | unsigned long smp_flags; | ||
795 | int err=0; | ||
796 | |||
797 | netif_stop_queue(dev); | ||
798 | |||
799 | |||
800 | if (skb == NULL){ | ||
801 | /* If we get here, some higher layer thinks we've missed an | ||
802 | * tx-done interrupt. | ||
803 | */ | ||
804 | printk(KERN_INFO "%s: Received NULL skb buffer! interface %s got kicked!\n", | ||
805 | card->devname, dev->name); | ||
806 | |||
807 | netif_wake_queue(dev); | ||
808 | return 0; | ||
809 | } | ||
810 | |||
811 | if (ntohs(skb->protocol) != htons(PVC_PROT)){ | ||
812 | /* check the udp packet type */ | ||
813 | |||
814 | udp_type = udp_pkt_type(skb, card); | ||
815 | if (udp_type == UDP_CPIPE_TYPE){ | ||
816 | if(store_udp_mgmt_pkt(UDP_PKT_FRM_STACK, card, skb, dev, | ||
817 | chdlc_priv_area)){ | ||
818 | chdlc_int->interrupt_permission |= | ||
819 | APP_INT_ON_TIMER; | ||
820 | } | ||
821 | netif_start_queue(dev); | ||
822 | return 0; | ||
823 | } | ||
824 | } | ||
825 | |||
826 | /* Lock the 508 Card: SMP is supported */ | ||
827 | if(card->hw.type != SDLA_S514){ | ||
828 | s508_lock(card,&smp_flags); | ||
829 | } | ||
830 | |||
831 | if (test_and_set_bit(SEND_CRIT, (void*)&card->wandev.critical)){ | ||
832 | |||
833 | printk(KERN_INFO "%s: Critical in if_send: %lx\n", | ||
834 | card->wandev.name,card->wandev.critical); | ||
835 | ++card->wandev.stats.tx_dropped; | ||
836 | netif_start_queue(dev); | ||
837 | goto if_send_crit_exit; | ||
838 | } | ||
839 | |||
840 | if (card->wandev.state != WAN_CONNECTED){ | ||
841 | ++card->wandev.stats.tx_dropped; | ||
842 | netif_start_queue(dev); | ||
843 | goto if_send_crit_exit; | ||
844 | } | ||
845 | |||
846 | if (chdlc_send(card, skb->data, skb->len)){ | ||
847 | netif_stop_queue(dev); | ||
848 | |||
849 | }else{ | ||
850 | ++card->wandev.stats.tx_packets; | ||
851 | card->wandev.stats.tx_bytes += skb->len; | ||
852 | dev->trans_start = jiffies; | ||
853 | netif_start_queue(dev); | ||
854 | } | ||
855 | |||
856 | if_send_crit_exit: | ||
857 | if (!(err=netif_queue_stopped(dev))){ | ||
858 | dev_kfree_skb_any(skb); | ||
859 | }else{ | ||
860 | chdlc_priv_area->tick_counter = jiffies; | ||
861 | chdlc_int->interrupt_permission |= APP_INT_ON_TX_FRAME; | ||
862 | } | ||
863 | |||
864 | clear_bit(SEND_CRIT, (void*)&card->wandev.critical); | ||
865 | if(card->hw.type != SDLA_S514){ | ||
866 | s508_unlock(card,&smp_flags); | ||
867 | } | ||
868 | |||
869 | return err; | ||
870 | } | ||
871 | |||
872 | |||
873 | /*============================================================================ | ||
874 | * Reply to UDP Management system. | ||
875 | * Return length of reply. | ||
876 | */ | ||
877 | static int reply_udp( unsigned char *data, unsigned int mbox_len ) | ||
878 | { | ||
879 | |||
880 | unsigned short len, udp_length, temp, ip_length; | ||
881 | unsigned long ip_temp; | ||
882 | int even_bound = 0; | ||
883 | chdlc_udp_pkt_t *c_udp_pkt = (chdlc_udp_pkt_t *)data; | ||
884 | |||
885 | /* Set length of packet */ | ||
886 | len = sizeof(ip_pkt_t)+ | ||
887 | sizeof(udp_pkt_t)+ | ||
888 | sizeof(wp_mgmt_t)+ | ||
889 | sizeof(cblock_t)+ | ||
890 | sizeof(trace_info_t)+ | ||
891 | mbox_len; | ||
892 | |||
893 | /* fill in UDP reply */ | ||
894 | c_udp_pkt->wp_mgmt.request_reply = UDPMGMT_REPLY; | ||
895 | |||
896 | /* fill in UDP length */ | ||
897 | udp_length = sizeof(udp_pkt_t)+ | ||
898 | sizeof(wp_mgmt_t)+ | ||
899 | sizeof(cblock_t)+ | ||
900 | sizeof(trace_info_t)+ | ||
901 | mbox_len; | ||
902 | |||
903 | /* put it on an even boundary */ | ||
904 | if ( udp_length & 0x0001 ) { | ||
905 | udp_length += 1; | ||
906 | len += 1; | ||
907 | even_bound = 1; | ||
908 | } | ||
909 | |||
910 | temp = (udp_length<<8)|(udp_length>>8); | ||
911 | c_udp_pkt->udp_pkt.udp_length = temp; | ||
912 | |||
913 | /* swap UDP ports */ | ||
914 | temp = c_udp_pkt->udp_pkt.udp_src_port; | ||
915 | c_udp_pkt->udp_pkt.udp_src_port = | ||
916 | c_udp_pkt->udp_pkt.udp_dst_port; | ||
917 | c_udp_pkt->udp_pkt.udp_dst_port = temp; | ||
918 | |||
919 | /* add UDP pseudo header */ | ||
920 | temp = 0x1100; | ||
921 | *((unsigned short *)(c_udp_pkt->data+mbox_len+even_bound)) = temp; | ||
922 | temp = (udp_length<<8)|(udp_length>>8); | ||
923 | *((unsigned short *)(c_udp_pkt->data+mbox_len+even_bound+2)) = temp; | ||
924 | |||
925 | |||
926 | /* calculate UDP checksum */ | ||
927 | c_udp_pkt->udp_pkt.udp_checksum = 0; | ||
928 | c_udp_pkt->udp_pkt.udp_checksum = calc_checksum(&data[UDP_OFFSET],udp_length+UDP_OFFSET); | ||
929 | |||
930 | /* fill in IP length */ | ||
931 | ip_length = len; | ||
932 | temp = (ip_length<<8)|(ip_length>>8); | ||
933 | c_udp_pkt->ip_pkt.total_length = temp; | ||
934 | |||
935 | /* swap IP addresses */ | ||
936 | ip_temp = c_udp_pkt->ip_pkt.ip_src_address; | ||
937 | c_udp_pkt->ip_pkt.ip_src_address = c_udp_pkt->ip_pkt.ip_dst_address; | ||
938 | c_udp_pkt->ip_pkt.ip_dst_address = ip_temp; | ||
939 | |||
940 | /* fill in IP checksum */ | ||
941 | c_udp_pkt->ip_pkt.hdr_checksum = 0; | ||
942 | c_udp_pkt->ip_pkt.hdr_checksum = calc_checksum(data,sizeof(ip_pkt_t)); | ||
943 | |||
944 | return len; | ||
945 | |||
946 | } /* reply_udp */ | ||
947 | |||
948 | unsigned short calc_checksum (char *data, int len) | ||
949 | { | ||
950 | unsigned short temp; | ||
951 | unsigned long sum=0; | ||
952 | int i; | ||
953 | |||
954 | for( i = 0; i <len; i+=2 ) { | ||
955 | memcpy(&temp,&data[i],2); | ||
956 | sum += (unsigned long)temp; | ||
957 | } | ||
958 | |||
959 | while (sum >> 16 ) { | ||
960 | sum = (sum & 0xffffUL) + (sum >> 16); | ||
961 | } | ||
962 | |||
963 | temp = (unsigned short)sum; | ||
964 | temp = ~temp; | ||
965 | |||
966 | if( temp == 0 ) | ||
967 | temp = 0xffff; | ||
968 | |||
969 | return temp; | ||
970 | } | ||
971 | |||
972 | |||
973 | /*============================================================================ | ||
974 | * Get ethernet-style interface statistics. | ||
975 | * Return a pointer to struct enet_statistics. | ||
976 | */ | ||
977 | static struct net_device_stats* if_stats(struct net_device* dev) | ||
978 | { | ||
979 | sdla_t *my_card; | ||
980 | chdlc_private_area_t* chdlc_priv_area; | ||
981 | |||
982 | /* Shutdown bug fix. In del_if() we kill | ||
983 | * dev->priv pointer. This function, gets | ||
984 | * called after del_if(), thus check | ||
985 | * if pointer has been deleted */ | ||
986 | if ((chdlc_priv_area=dev->priv) == NULL) | ||
987 | return NULL; | ||
988 | |||
989 | my_card = chdlc_priv_area->card; | ||
990 | return &my_card->wandev.stats; | ||
991 | } | ||
992 | |||
993 | |||
994 | /****** Cisco HDLC Firmware Interface Functions *******************************/ | ||
995 | |||
996 | /*============================================================================ | ||
997 | * Read firmware code version. | ||
998 | * Put code version as ASCII string in str. | ||
999 | */ | ||
1000 | static int chdlc_read_version (sdla_t* card, char* str) | ||
1001 | { | ||
1002 | CHDLC_MAILBOX_STRUCT* mb = card->mbox; | ||
1003 | int len; | ||
1004 | char err; | ||
1005 | mb->buffer_length = 0; | ||
1006 | mb->command = READ_CHDLC_CODE_VERSION; | ||
1007 | err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; | ||
1008 | |||
1009 | if(err != COMMAND_OK) { | ||
1010 | chdlc_error(card,err,mb); | ||
1011 | } | ||
1012 | else if (str) { /* is not null */ | ||
1013 | len = mb->buffer_length; | ||
1014 | memcpy(str, mb->data, len); | ||
1015 | str[len] = '\0'; | ||
1016 | } | ||
1017 | return (err); | ||
1018 | } | ||
1019 | |||
1020 | /*----------------------------------------------------------------------------- | ||
1021 | * Configure CHDLC firmware. | ||
1022 | */ | ||
1023 | static int chdlc_configure (sdla_t* card, void* data) | ||
1024 | { | ||
1025 | int err; | ||
1026 | CHDLC_MAILBOX_STRUCT *mailbox = card->mbox; | ||
1027 | int data_length = sizeof(CHDLC_CONFIGURATION_STRUCT); | ||
1028 | |||
1029 | mailbox->buffer_length = data_length; | ||
1030 | memcpy(mailbox->data, data, data_length); | ||
1031 | mailbox->command = SET_CHDLC_CONFIGURATION; | ||
1032 | err = sdla_exec(mailbox) ? mailbox->return_code : CMD_TIMEOUT; | ||
1033 | |||
1034 | if (err != COMMAND_OK) chdlc_error (card, err, mailbox); | ||
1035 | |||
1036 | return err; | ||
1037 | } | ||
1038 | |||
1039 | |||
1040 | /*============================================================================ | ||
1041 | * Set interrupt mode -- HDLC Version. | ||
1042 | */ | ||
1043 | |||
1044 | static int chdlc_set_intr_mode (sdla_t* card, unsigned mode) | ||
1045 | { | ||
1046 | CHDLC_MAILBOX_STRUCT* mb = card->mbox; | ||
1047 | CHDLC_INT_TRIGGERS_STRUCT* int_data = | ||
1048 | (CHDLC_INT_TRIGGERS_STRUCT *)mb->data; | ||
1049 | int err; | ||
1050 | |||
1051 | int_data->CHDLC_interrupt_triggers = mode; | ||
1052 | int_data->IRQ = card->hw.irq; | ||
1053 | int_data->interrupt_timer = 1; | ||
1054 | |||
1055 | mb->buffer_length = sizeof(CHDLC_INT_TRIGGERS_STRUCT); | ||
1056 | mb->command = SET_CHDLC_INTERRUPT_TRIGGERS; | ||
1057 | err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; | ||
1058 | if (err != COMMAND_OK) | ||
1059 | chdlc_error (card, err, mb); | ||
1060 | return err; | ||
1061 | } | ||
1062 | |||
1063 | |||
1064 | /*============================================================================ | ||
1065 | * Enable communications. | ||
1066 | */ | ||
1067 | |||
1068 | static int chdlc_comm_enable (sdla_t* card) | ||
1069 | { | ||
1070 | int err; | ||
1071 | CHDLC_MAILBOX_STRUCT* mb = card->mbox; | ||
1072 | |||
1073 | mb->buffer_length = 0; | ||
1074 | mb->command = ENABLE_CHDLC_COMMUNICATIONS; | ||
1075 | err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; | ||
1076 | if (err != COMMAND_OK) | ||
1077 | chdlc_error(card, err, mb); | ||
1078 | else | ||
1079 | card->u.c.comm_enabled=1; | ||
1080 | |||
1081 | return err; | ||
1082 | } | ||
1083 | |||
1084 | /*============================================================================ | ||
1085 | * Disable communications and Drop the Modem lines (DCD and RTS). | ||
1086 | */ | ||
1087 | static int chdlc_comm_disable (sdla_t* card) | ||
1088 | { | ||
1089 | int err; | ||
1090 | CHDLC_MAILBOX_STRUCT* mb = card->mbox; | ||
1091 | |||
1092 | mb->buffer_length = 0; | ||
1093 | mb->command = DISABLE_CHDLC_COMMUNICATIONS; | ||
1094 | err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; | ||
1095 | if (err != COMMAND_OK) | ||
1096 | chdlc_error(card,err,mb); | ||
1097 | |||
1098 | return err; | ||
1099 | } | ||
1100 | |||
1101 | /*============================================================================ | ||
1102 | * Read communication error statistics. | ||
1103 | */ | ||
1104 | static int chdlc_read_comm_err_stats (sdla_t* card) | ||
1105 | { | ||
1106 | int err; | ||
1107 | CHDLC_MAILBOX_STRUCT* mb = card->mbox; | ||
1108 | |||
1109 | mb->buffer_length = 0; | ||
1110 | mb->command = READ_COMMS_ERROR_STATS; | ||
1111 | err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; | ||
1112 | if (err != COMMAND_OK) | ||
1113 | chdlc_error(card,err,mb); | ||
1114 | return err; | ||
1115 | } | ||
1116 | |||
1117 | |||
1118 | /*============================================================================ | ||
1119 | * Read CHDLC operational statistics. | ||
1120 | */ | ||
1121 | static int chdlc_read_op_stats (sdla_t* card) | ||
1122 | { | ||
1123 | int err; | ||
1124 | CHDLC_MAILBOX_STRUCT* mb = card->mbox; | ||
1125 | |||
1126 | mb->buffer_length = 0; | ||
1127 | mb->command = READ_CHDLC_OPERATIONAL_STATS; | ||
1128 | err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; | ||
1129 | if (err != COMMAND_OK) | ||
1130 | chdlc_error(card,err,mb); | ||
1131 | return err; | ||
1132 | } | ||
1133 | |||
1134 | |||
1135 | /*============================================================================ | ||
1136 | * Update communications error and general packet statistics. | ||
1137 | */ | ||
1138 | static int update_comms_stats(sdla_t* card, | ||
1139 | chdlc_private_area_t* chdlc_priv_area) | ||
1140 | { | ||
1141 | CHDLC_MAILBOX_STRUCT* mb = card->mbox; | ||
1142 | COMMS_ERROR_STATS_STRUCT* err_stats; | ||
1143 | CHDLC_OPERATIONAL_STATS_STRUCT *op_stats; | ||
1144 | |||
1145 | /* on the first timer interrupt, read the comms error statistics */ | ||
1146 | if(chdlc_priv_area->update_comms_stats == 2) { | ||
1147 | if(chdlc_read_comm_err_stats(card)) | ||
1148 | return 1; | ||
1149 | err_stats = (COMMS_ERROR_STATS_STRUCT *)mb->data; | ||
1150 | card->wandev.stats.rx_over_errors = | ||
1151 | err_stats->Rx_overrun_err_count; | ||
1152 | card->wandev.stats.rx_crc_errors = | ||
1153 | err_stats->CRC_err_count; | ||
1154 | card->wandev.stats.rx_frame_errors = | ||
1155 | err_stats->Rx_abort_count; | ||
1156 | card->wandev.stats.rx_fifo_errors = | ||
1157 | err_stats->Rx_dis_pri_bfrs_full_count; | ||
1158 | card->wandev.stats.rx_missed_errors = | ||
1159 | card->wandev.stats.rx_fifo_errors; | ||
1160 | card->wandev.stats.tx_aborted_errors = | ||
1161 | err_stats->sec_Tx_abort_count; | ||
1162 | } | ||
1163 | |||
1164 | /* on the second timer interrupt, read the operational statistics */ | ||
1165 | else { | ||
1166 | if(chdlc_read_op_stats(card)) | ||
1167 | return 1; | ||
1168 | op_stats = (CHDLC_OPERATIONAL_STATS_STRUCT *)mb->data; | ||
1169 | card->wandev.stats.rx_length_errors = | ||
1170 | (op_stats->Rx_Data_discard_short_count + | ||
1171 | op_stats->Rx_Data_discard_long_count); | ||
1172 | } | ||
1173 | |||
1174 | return 0; | ||
1175 | } | ||
1176 | |||
1177 | /*============================================================================ | ||
1178 | * Send packet. | ||
1179 | * Return: 0 - o.k. | ||
1180 | * 1 - no transmit buffers available | ||
1181 | */ | ||
1182 | static int chdlc_send (sdla_t* card, void* data, unsigned len) | ||
1183 | { | ||
1184 | CHDLC_DATA_TX_STATUS_EL_STRUCT *txbuf = card->u.c.txbuf; | ||
1185 | |||
1186 | if (txbuf->opp_flag) | ||
1187 | return 1; | ||
1188 | |||
1189 | sdla_poke(&card->hw, txbuf->ptr_data_bfr, data, len); | ||
1190 | |||
1191 | txbuf->frame_length = len; | ||
1192 | txbuf->opp_flag = 1; /* start transmission */ | ||
1193 | |||
1194 | /* Update transmit buffer control fields */ | ||
1195 | card->u.c.txbuf = ++txbuf; | ||
1196 | |||
1197 | if ((void*)txbuf > card->u.c.txbuf_last) | ||
1198 | card->u.c.txbuf = card->u.c.txbuf_base; | ||
1199 | |||
1200 | return 0; | ||
1201 | } | ||
1202 | |||
1203 | /****** Firmware Error Handler **********************************************/ | ||
1204 | |||
1205 | /*============================================================================ | ||
1206 | * Firmware error handler. | ||
1207 | * This routine is called whenever firmware command returns non-zero | ||
1208 | * return code. | ||
1209 | * | ||
1210 | * Return zero if previous command has to be cancelled. | ||
1211 | */ | ||
1212 | static int chdlc_error (sdla_t *card, int err, CHDLC_MAILBOX_STRUCT *mb) | ||
1213 | { | ||
1214 | unsigned cmd = mb->command; | ||
1215 | |||
1216 | switch (err) { | ||
1217 | |||
1218 | case CMD_TIMEOUT: | ||
1219 | printk(KERN_ERR "%s: command 0x%02X timed out!\n", | ||
1220 | card->devname, cmd); | ||
1221 | break; | ||
1222 | |||
1223 | case S514_BOTH_PORTS_SAME_CLK_MODE: | ||
1224 | if(cmd == SET_CHDLC_CONFIGURATION) { | ||
1225 | printk(KERN_INFO | ||
1226 | "%s: Configure both ports for the same clock source\n", | ||
1227 | card->devname); | ||
1228 | break; | ||
1229 | } | ||
1230 | |||
1231 | default: | ||
1232 | printk(KERN_INFO "%s: command 0x%02X returned 0x%02X!\n", | ||
1233 | card->devname, cmd, err); | ||
1234 | } | ||
1235 | |||
1236 | return 0; | ||
1237 | } | ||
1238 | |||
1239 | /****** Interrupt Handlers **************************************************/ | ||
1240 | |||
1241 | /*============================================================================ | ||
1242 | * Cisco HDLC interrupt service routine. | ||
1243 | */ | ||
1244 | STATIC void wsppp_isr (sdla_t* card) | ||
1245 | { | ||
1246 | struct net_device* dev; | ||
1247 | SHARED_MEMORY_INFO_STRUCT* flags = NULL; | ||
1248 | int i; | ||
1249 | sdla_t *my_card; | ||
1250 | |||
1251 | |||
1252 | /* Check for which port the interrupt has been generated | ||
1253 | * Since Secondary Port is piggybacking on the Primary | ||
1254 | * the check must be done here. | ||
1255 | */ | ||
1256 | |||
1257 | flags = card->u.c.flags; | ||
1258 | if (!flags->interrupt_info_struct.interrupt_type){ | ||
1259 | /* Check for a second port (piggybacking) */ | ||
1260 | if((my_card = card->next)){ | ||
1261 | flags = my_card->u.c.flags; | ||
1262 | if (flags->interrupt_info_struct.interrupt_type){ | ||
1263 | card = my_card; | ||
1264 | card->isr(card); | ||
1265 | return; | ||
1266 | } | ||
1267 | } | ||
1268 | } | ||
1269 | |||
1270 | dev = card->wandev.dev; | ||
1271 | card->in_isr = 1; | ||
1272 | flags = card->u.c.flags; | ||
1273 | |||
1274 | /* If we get an interrupt with no network device, stop the interrupts | ||
1275 | * and issue an error */ | ||
1276 | if ((!dev || !dev->priv) && flags->interrupt_info_struct.interrupt_type != | ||
1277 | COMMAND_COMPLETE_APP_INT_PEND){ | ||
1278 | goto isr_done; | ||
1279 | } | ||
1280 | |||
1281 | |||
1282 | /* if critical due to peripheral operations | ||
1283 | * ie. update() or getstats() then reset the interrupt and | ||
1284 | * wait for the board to retrigger. | ||
1285 | */ | ||
1286 | if(test_bit(PERI_CRIT, (void*)&card->wandev.critical)) { | ||
1287 | flags->interrupt_info_struct. | ||
1288 | interrupt_type = 0; | ||
1289 | goto isr_done; | ||
1290 | } | ||
1291 | |||
1292 | |||
1293 | /* On a 508 Card, if critical due to if_send | ||
1294 | * Major Error !!! | ||
1295 | */ | ||
1296 | if(card->hw.type != SDLA_S514) { | ||
1297 | if(test_bit(0, (void*)&card->wandev.critical)) { | ||
1298 | printk(KERN_INFO "%s: Critical while in ISR: %lx\n", | ||
1299 | card->devname, card->wandev.critical); | ||
1300 | goto isr_done; | ||
1301 | } | ||
1302 | } | ||
1303 | |||
1304 | switch(flags->interrupt_info_struct.interrupt_type) { | ||
1305 | |||
1306 | case RX_APP_INT_PEND: /* 0x01: receive interrupt */ | ||
1307 | rx_intr(card); | ||
1308 | break; | ||
1309 | |||
1310 | case TX_APP_INT_PEND: /* 0x02: transmit interrupt */ | ||
1311 | flags->interrupt_info_struct.interrupt_permission &= | ||
1312 | ~APP_INT_ON_TX_FRAME; | ||
1313 | |||
1314 | netif_wake_queue(dev); | ||
1315 | break; | ||
1316 | |||
1317 | case COMMAND_COMPLETE_APP_INT_PEND:/* 0x04: cmd cplt */ | ||
1318 | ++ Intr_test_counter; | ||
1319 | break; | ||
1320 | |||
1321 | case CHDLC_EXCEP_COND_APP_INT_PEND: /* 0x20 */ | ||
1322 | process_chdlc_exception(card); | ||
1323 | break; | ||
1324 | |||
1325 | case GLOBAL_EXCEP_COND_APP_INT_PEND: | ||
1326 | process_global_exception(card); | ||
1327 | break; | ||
1328 | |||
1329 | case TIMER_APP_INT_PEND: | ||
1330 | timer_intr(card); | ||
1331 | break; | ||
1332 | |||
1333 | default: | ||
1334 | printk(KERN_INFO "%s: spurious interrupt 0x%02X!\n", | ||
1335 | card->devname, | ||
1336 | flags->interrupt_info_struct.interrupt_type); | ||
1337 | printk(KERN_INFO "Code name: "); | ||
1338 | for(i = 0; i < 4; i ++) | ||
1339 | printk(KERN_INFO "%c", | ||
1340 | flags->global_info_struct.codename[i]); | ||
1341 | printk(KERN_INFO "\nCode version: "); | ||
1342 | for(i = 0; i < 4; i ++) | ||
1343 | printk(KERN_INFO "%c", | ||
1344 | flags->global_info_struct.codeversion[i]); | ||
1345 | printk(KERN_INFO "\n"); | ||
1346 | break; | ||
1347 | } | ||
1348 | |||
1349 | isr_done: | ||
1350 | card->in_isr = 0; | ||
1351 | flags->interrupt_info_struct.interrupt_type = 0; | ||
1352 | } | ||
1353 | |||
1354 | /*============================================================================ | ||
1355 | * Receive interrupt handler. | ||
1356 | */ | ||
1357 | static void rx_intr (sdla_t* card) | ||
1358 | { | ||
1359 | struct net_device *dev; | ||
1360 | chdlc_private_area_t *chdlc_priv_area; | ||
1361 | SHARED_MEMORY_INFO_STRUCT *flags = card->u.c.flags; | ||
1362 | CHDLC_DATA_RX_STATUS_EL_STRUCT *rxbuf = card->u.c.rxmb; | ||
1363 | struct sk_buff *skb; | ||
1364 | unsigned len; | ||
1365 | unsigned addr = rxbuf->ptr_data_bfr; | ||
1366 | void *buf; | ||
1367 | int i,udp_type; | ||
1368 | |||
1369 | if (rxbuf->opp_flag != 0x01) { | ||
1370 | printk(KERN_INFO | ||
1371 | "%s: corrupted Rx buffer @ 0x%X, flag = 0x%02X!\n", | ||
1372 | card->devname, (unsigned)rxbuf, rxbuf->opp_flag); | ||
1373 | printk(KERN_INFO "Code name: "); | ||
1374 | for(i = 0; i < 4; i ++) | ||
1375 | printk(KERN_INFO "%c", | ||
1376 | flags->global_info_struct.codename[i]); | ||
1377 | printk(KERN_INFO "\nCode version: "); | ||
1378 | for(i = 0; i < 4; i ++) | ||
1379 | printk(KERN_INFO "%c", | ||
1380 | flags->global_info_struct.codeversion[i]); | ||
1381 | printk(KERN_INFO "\n"); | ||
1382 | |||
1383 | |||
1384 | /* Bug Fix: Mar 6 2000 | ||
1385 | * If we get a corrupted mailbox, it measn that driver | ||
1386 | * is out of sync with the firmware. There is no recovery. | ||
1387 | * If we don't turn off all interrupts for this card | ||
1388 | * the machine will crash. | ||
1389 | */ | ||
1390 | printk(KERN_INFO "%s: Critical router failure ...!!!\n", card->devname); | ||
1391 | printk(KERN_INFO "Please contact Sangoma Technologies !\n"); | ||
1392 | chdlc_set_intr_mode(card,0); | ||
1393 | return; | ||
1394 | } | ||
1395 | |||
1396 | dev = card->wandev.dev; | ||
1397 | |||
1398 | if (!dev){ | ||
1399 | goto rx_exit; | ||
1400 | } | ||
1401 | |||
1402 | if (!netif_running(dev)){ | ||
1403 | goto rx_exit; | ||
1404 | } | ||
1405 | |||
1406 | chdlc_priv_area = dev->priv; | ||
1407 | |||
1408 | if (rxbuf->error_flag){ | ||
1409 | goto rx_exit; | ||
1410 | } | ||
1411 | /* Take off two CRC bytes */ | ||
1412 | |||
1413 | if (rxbuf->frame_length < 7 || rxbuf->frame_length > 1506 ){ | ||
1414 | goto rx_exit; | ||
1415 | } | ||
1416 | |||
1417 | len = rxbuf->frame_length - CRC_LENGTH; | ||
1418 | |||
1419 | /* Allocate socket buffer */ | ||
1420 | skb = dev_alloc_skb(len); | ||
1421 | |||
1422 | if (skb == NULL) { | ||
1423 | if (net_ratelimit()){ | ||
1424 | printk(KERN_INFO "%s: no socket buffers available!\n", | ||
1425 | card->devname); | ||
1426 | } | ||
1427 | ++card->wandev.stats.rx_dropped; | ||
1428 | goto rx_exit; | ||
1429 | } | ||
1430 | |||
1431 | /* Copy data to the socket buffer */ | ||
1432 | if((addr + len) > card->u.c.rx_top + 1) { | ||
1433 | unsigned tmp = card->u.c.rx_top - addr + 1; | ||
1434 | buf = skb_put(skb, tmp); | ||
1435 | sdla_peek(&card->hw, addr, buf, tmp); | ||
1436 | addr = card->u.c.rx_base; | ||
1437 | len -= tmp; | ||
1438 | } | ||
1439 | |||
1440 | buf = skb_put(skb, len); | ||
1441 | sdla_peek(&card->hw, addr, buf, len); | ||
1442 | |||
1443 | skb->protocol = htons(ETH_P_WAN_PPP); | ||
1444 | |||
1445 | card->wandev.stats.rx_packets ++; | ||
1446 | card->wandev.stats.rx_bytes += skb->len; | ||
1447 | udp_type = udp_pkt_type( skb, card ); | ||
1448 | |||
1449 | if(udp_type == UDP_CPIPE_TYPE) { | ||
1450 | if(store_udp_mgmt_pkt(UDP_PKT_FRM_NETWORK, | ||
1451 | card, skb, dev, chdlc_priv_area)) { | ||
1452 | flags->interrupt_info_struct. | ||
1453 | interrupt_permission |= | ||
1454 | APP_INT_ON_TIMER; | ||
1455 | } | ||
1456 | }else{ | ||
1457 | /* Pass it up the protocol stack */ | ||
1458 | skb->dev = dev; | ||
1459 | skb->mac.raw = skb->data; | ||
1460 | netif_rx(skb); | ||
1461 | dev->last_rx = jiffies; | ||
1462 | } | ||
1463 | |||
1464 | rx_exit: | ||
1465 | /* Release buffer element and calculate a pointer to the next one */ | ||
1466 | rxbuf->opp_flag = 0x00; | ||
1467 | card->u.c.rxmb = ++ rxbuf; | ||
1468 | if((void*)rxbuf > card->u.c.rxbuf_last){ | ||
1469 | card->u.c.rxmb = card->u.c.rxbuf_base; | ||
1470 | } | ||
1471 | } | ||
1472 | |||
1473 | /*============================================================================ | ||
1474 | * Timer interrupt handler. | ||
1475 | * The timer interrupt is used for two purposes: | ||
1476 | * 1) Processing udp calls from 'cpipemon'. | ||
1477 | * 2) Reading board-level statistics for updating the proc file system. | ||
1478 | */ | ||
1479 | void timer_intr(sdla_t *card) | ||
1480 | { | ||
1481 | struct net_device* dev; | ||
1482 | chdlc_private_area_t* chdlc_priv_area = NULL; | ||
1483 | SHARED_MEMORY_INFO_STRUCT* flags = NULL; | ||
1484 | |||
1485 | dev = card->wandev.dev; | ||
1486 | chdlc_priv_area = dev->priv; | ||
1487 | |||
1488 | if (chdlc_priv_area->timer_int_enabled & TMR_INT_ENABLED_CONFIG) { | ||
1489 | if (!config_chdlc(card)){ | ||
1490 | chdlc_priv_area->timer_int_enabled &= ~TMR_INT_ENABLED_CONFIG; | ||
1491 | } | ||
1492 | } | ||
1493 | |||
1494 | /* process a udp call if pending */ | ||
1495 | if(chdlc_priv_area->timer_int_enabled & TMR_INT_ENABLED_UDP) { | ||
1496 | process_udp_mgmt_pkt(card, dev, | ||
1497 | chdlc_priv_area); | ||
1498 | chdlc_priv_area->timer_int_enabled &= ~TMR_INT_ENABLED_UDP; | ||
1499 | } | ||
1500 | |||
1501 | |||
1502 | /* read the communications statistics if required */ | ||
1503 | if(chdlc_priv_area->timer_int_enabled & TMR_INT_ENABLED_UPDATE) { | ||
1504 | update_comms_stats(card, chdlc_priv_area); | ||
1505 | if(!(-- chdlc_priv_area->update_comms_stats)) { | ||
1506 | chdlc_priv_area->timer_int_enabled &= | ||
1507 | ~TMR_INT_ENABLED_UPDATE; | ||
1508 | } | ||
1509 | } | ||
1510 | |||
1511 | /* only disable the timer interrupt if there are no udp or statistic */ | ||
1512 | /* updates pending */ | ||
1513 | if(!chdlc_priv_area->timer_int_enabled) { | ||
1514 | flags = card->u.c.flags; | ||
1515 | flags->interrupt_info_struct.interrupt_permission &= | ||
1516 | ~APP_INT_ON_TIMER; | ||
1517 | } | ||
1518 | } | ||
1519 | |||
1520 | /*------------------------------------------------------------------------------ | ||
1521 | Miscellaneous Functions | ||
1522 | - set_chdlc_config() used to set configuration options on the board | ||
1523 | ------------------------------------------------------------------------------*/ | ||
1524 | |||
1525 | static int set_chdlc_config(sdla_t* card) | ||
1526 | { | ||
1527 | |||
1528 | CHDLC_CONFIGURATION_STRUCT cfg; | ||
1529 | |||
1530 | memset(&cfg, 0, sizeof(CHDLC_CONFIGURATION_STRUCT)); | ||
1531 | |||
1532 | if(card->wandev.clocking) | ||
1533 | cfg.baud_rate = card->wandev.bps; | ||
1534 | |||
1535 | cfg.line_config_options = (card->wandev.interface == WANOPT_RS232) ? | ||
1536 | INTERFACE_LEVEL_RS232 : INTERFACE_LEVEL_V35; | ||
1537 | |||
1538 | cfg.modem_config_options = 0; | ||
1539 | //API OPTIONS | ||
1540 | cfg.CHDLC_API_options = DISCARD_RX_ERROR_FRAMES; | ||
1541 | cfg.modem_status_timer = 100; | ||
1542 | cfg.CHDLC_protocol_options = HDLC_STREAMING_MODE; | ||
1543 | cfg.percent_data_buffer_for_Tx = 50; | ||
1544 | cfg.CHDLC_statistics_options = (CHDLC_TX_DATA_BYTE_COUNT_STAT | | ||
1545 | CHDLC_RX_DATA_BYTE_COUNT_STAT); | ||
1546 | cfg.max_CHDLC_data_field_length = card->wandev.mtu; | ||
1547 | |||
1548 | cfg.transmit_keepalive_timer = 0; | ||
1549 | cfg.receive_keepalive_timer = 0; | ||
1550 | cfg.keepalive_error_tolerance = 0; | ||
1551 | cfg.SLARP_request_timer = 0; | ||
1552 | |||
1553 | cfg.IP_address = 0; | ||
1554 | cfg.IP_netmask = 0; | ||
1555 | |||
1556 | return chdlc_configure(card, &cfg); | ||
1557 | } | ||
1558 | |||
1559 | /*============================================================================ | ||
1560 | * Process global exception condition | ||
1561 | */ | ||
1562 | static int process_global_exception(sdla_t *card) | ||
1563 | { | ||
1564 | CHDLC_MAILBOX_STRUCT* mbox = card->mbox; | ||
1565 | int err; | ||
1566 | |||
1567 | mbox->buffer_length = 0; | ||
1568 | mbox->command = READ_GLOBAL_EXCEPTION_CONDITION; | ||
1569 | err = sdla_exec(mbox) ? mbox->return_code : CMD_TIMEOUT; | ||
1570 | |||
1571 | if(err != CMD_TIMEOUT ){ | ||
1572 | |||
1573 | switch(mbox->return_code) { | ||
1574 | |||
1575 | case EXCEP_MODEM_STATUS_CHANGE: | ||
1576 | |||
1577 | printk(KERN_INFO "%s: Modem status change\n", | ||
1578 | card->devname); | ||
1579 | |||
1580 | switch(mbox->data[0] & (DCD_HIGH | CTS_HIGH)) { | ||
1581 | case (DCD_HIGH): | ||
1582 | printk(KERN_INFO "%s: DCD high, CTS low\n",card->devname); | ||
1583 | break; | ||
1584 | case (CTS_HIGH): | ||
1585 | printk(KERN_INFO "%s: DCD low, CTS high\n",card->devname); | ||
1586 | break; | ||
1587 | case ((DCD_HIGH | CTS_HIGH)): | ||
1588 | printk(KERN_INFO "%s: DCD high, CTS high\n",card->devname); | ||
1589 | break; | ||
1590 | default: | ||
1591 | printk(KERN_INFO "%s: DCD low, CTS low\n",card->devname); | ||
1592 | break; | ||
1593 | } | ||
1594 | |||
1595 | if (!(mbox->data[0] & DCD_HIGH) || !(mbox->data[0] & DCD_HIGH)){ | ||
1596 | //printk(KERN_INFO "Sending TERM Request Manually !\n"); | ||
1597 | send_ppp_term_request(card->wandev.dev); | ||
1598 | } | ||
1599 | break; | ||
1600 | |||
1601 | case EXCEP_TRC_DISABLED: | ||
1602 | printk(KERN_INFO "%s: Line trace disabled\n", | ||
1603 | card->devname); | ||
1604 | break; | ||
1605 | |||
1606 | case EXCEP_IRQ_TIMEOUT: | ||
1607 | printk(KERN_INFO "%s: IRQ timeout occurred\n", | ||
1608 | card->devname); | ||
1609 | break; | ||
1610 | |||
1611 | default: | ||
1612 | printk(KERN_INFO "%s: Global exception %x\n", | ||
1613 | card->devname, mbox->return_code); | ||
1614 | break; | ||
1615 | } | ||
1616 | } | ||
1617 | return 0; | ||
1618 | } | ||
1619 | |||
1620 | |||
1621 | /*============================================================================ | ||
1622 | * Process chdlc exception condition | ||
1623 | */ | ||
1624 | static int process_chdlc_exception(sdla_t *card) | ||
1625 | { | ||
1626 | CHDLC_MAILBOX_STRUCT* mb = card->mbox; | ||
1627 | int err; | ||
1628 | |||
1629 | mb->buffer_length = 0; | ||
1630 | mb->command = READ_CHDLC_EXCEPTION_CONDITION; | ||
1631 | err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; | ||
1632 | if(err != CMD_TIMEOUT) { | ||
1633 | |||
1634 | switch (err) { | ||
1635 | |||
1636 | case EXCEP_LINK_ACTIVE: | ||
1637 | port_set_state(card, WAN_CONNECTED); | ||
1638 | break; | ||
1639 | |||
1640 | case EXCEP_LINK_INACTIVE_MODEM: | ||
1641 | port_set_state(card, WAN_DISCONNECTED); | ||
1642 | break; | ||
1643 | |||
1644 | case EXCEP_LOOPBACK_CONDITION: | ||
1645 | printk(KERN_INFO "%s: Loopback Condition Detected.\n", | ||
1646 | card->devname); | ||
1647 | break; | ||
1648 | |||
1649 | case NO_CHDLC_EXCEP_COND_TO_REPORT: | ||
1650 | printk(KERN_INFO "%s: No exceptions reported.\n", | ||
1651 | card->devname); | ||
1652 | break; | ||
1653 | default: | ||
1654 | printk(KERN_INFO "%s: Exception Condition %x!\n", | ||
1655 | card->devname,err); | ||
1656 | break; | ||
1657 | } | ||
1658 | |||
1659 | } | ||
1660 | return 0; | ||
1661 | } | ||
1662 | |||
1663 | |||
1664 | /*============================================================================= | ||
1665 | * Store a UDP management packet for later processing. | ||
1666 | */ | ||
1667 | |||
1668 | static int store_udp_mgmt_pkt(char udp_pkt_src, sdla_t* card, | ||
1669 | struct sk_buff *skb, struct net_device* dev, | ||
1670 | chdlc_private_area_t* chdlc_priv_area ) | ||
1671 | { | ||
1672 | int udp_pkt_stored = 0; | ||
1673 | |||
1674 | if(!chdlc_priv_area->udp_pkt_lgth && | ||
1675 | (skb->len <= MAX_LGTH_UDP_MGNT_PKT)) { | ||
1676 | chdlc_priv_area->udp_pkt_lgth = skb->len; | ||
1677 | chdlc_priv_area->udp_pkt_src = udp_pkt_src; | ||
1678 | memcpy(chdlc_priv_area->udp_pkt_data, skb->data, skb->len); | ||
1679 | chdlc_priv_area->timer_int_enabled = TMR_INT_ENABLED_UDP; | ||
1680 | udp_pkt_stored = 1; | ||
1681 | } | ||
1682 | |||
1683 | if(udp_pkt_src == UDP_PKT_FRM_STACK) | ||
1684 | dev_kfree_skb_any(skb); | ||
1685 | else | ||
1686 | dev_kfree_skb_any(skb); | ||
1687 | |||
1688 | return(udp_pkt_stored); | ||
1689 | } | ||
1690 | |||
1691 | |||
1692 | /*============================================================================= | ||
1693 | * Process UDP management packet. | ||
1694 | */ | ||
1695 | |||
1696 | static int process_udp_mgmt_pkt(sdla_t* card, struct net_device* dev, | ||
1697 | chdlc_private_area_t* chdlc_priv_area ) | ||
1698 | { | ||
1699 | unsigned char *buf; | ||
1700 | unsigned int frames, len; | ||
1701 | struct sk_buff *new_skb; | ||
1702 | unsigned short buffer_length, real_len; | ||
1703 | unsigned long data_ptr; | ||
1704 | unsigned data_length; | ||
1705 | int udp_mgmt_req_valid = 1; | ||
1706 | CHDLC_MAILBOX_STRUCT *mb = card->mbox; | ||
1707 | SHARED_MEMORY_INFO_STRUCT *flags = card->u.c.flags; | ||
1708 | chdlc_udp_pkt_t *chdlc_udp_pkt; | ||
1709 | struct timeval tv; | ||
1710 | int err; | ||
1711 | char ut_char; | ||
1712 | |||
1713 | chdlc_udp_pkt = (chdlc_udp_pkt_t *) chdlc_priv_area->udp_pkt_data; | ||
1714 | |||
1715 | if(chdlc_priv_area->udp_pkt_src == UDP_PKT_FRM_NETWORK) { | ||
1716 | |||
1717 | switch(chdlc_udp_pkt->cblock.command) { | ||
1718 | case READ_GLOBAL_STATISTICS: | ||
1719 | case READ_MODEM_STATUS: | ||
1720 | case READ_CHDLC_LINK_STATUS: | ||
1721 | case CPIPE_ROUTER_UP_TIME: | ||
1722 | case READ_COMMS_ERROR_STATS: | ||
1723 | case READ_CHDLC_OPERATIONAL_STATS: | ||
1724 | |||
1725 | /* These two commands are executed for | ||
1726 | * each request */ | ||
1727 | case READ_CHDLC_CONFIGURATION: | ||
1728 | case READ_CHDLC_CODE_VERSION: | ||
1729 | udp_mgmt_req_valid = 1; | ||
1730 | break; | ||
1731 | default: | ||
1732 | udp_mgmt_req_valid = 0; | ||
1733 | break; | ||
1734 | } | ||
1735 | } | ||
1736 | |||
1737 | if(!udp_mgmt_req_valid) { | ||
1738 | |||
1739 | /* set length to 0 */ | ||
1740 | chdlc_udp_pkt->cblock.buffer_length = 0; | ||
1741 | |||
1742 | /* set return code */ | ||
1743 | chdlc_udp_pkt->cblock.return_code = 0xCD; | ||
1744 | |||
1745 | if (net_ratelimit()){ | ||
1746 | printk(KERN_INFO | ||
1747 | "%s: Warning, Illegal UDP command attempted from network: %x\n", | ||
1748 | card->devname,chdlc_udp_pkt->cblock.command); | ||
1749 | } | ||
1750 | |||
1751 | } else { | ||
1752 | unsigned long trace_status_cfg_addr = 0; | ||
1753 | TRACE_STATUS_EL_CFG_STRUCT trace_cfg_struct; | ||
1754 | TRACE_STATUS_ELEMENT_STRUCT trace_element_struct; | ||
1755 | |||
1756 | switch(chdlc_udp_pkt->cblock.command) { | ||
1757 | |||
1758 | case CPIPE_ENABLE_TRACING: | ||
1759 | if (!chdlc_priv_area->TracingEnabled) { | ||
1760 | |||
1761 | /* OPERATE_DATALINE_MONITOR */ | ||
1762 | |||
1763 | mb->buffer_length = sizeof(LINE_TRACE_CONFIG_STRUCT); | ||
1764 | mb->command = SET_TRACE_CONFIGURATION; | ||
1765 | |||
1766 | ((LINE_TRACE_CONFIG_STRUCT *)mb->data)-> | ||
1767 | trace_config = TRACE_ACTIVE; | ||
1768 | /* Trace delay mode is not used because it slows | ||
1769 | down transfer and results in a standoff situation | ||
1770 | when there is a lot of data */ | ||
1771 | |||
1772 | /* Configure the Trace based on user inputs */ | ||
1773 | ((LINE_TRACE_CONFIG_STRUCT *)mb->data)->trace_config |= | ||
1774 | chdlc_udp_pkt->data[0]; | ||
1775 | |||
1776 | ((LINE_TRACE_CONFIG_STRUCT *)mb->data)-> | ||
1777 | trace_deactivation_timer = 4000; | ||
1778 | |||
1779 | |||
1780 | err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; | ||
1781 | if (err != COMMAND_OK) { | ||
1782 | chdlc_error(card,err,mb); | ||
1783 | card->TracingEnabled = 0; | ||
1784 | chdlc_udp_pkt->cblock.return_code = err; | ||
1785 | mb->buffer_length = 0; | ||
1786 | break; | ||
1787 | } | ||
1788 | |||
1789 | /* Get the base address of the trace element list */ | ||
1790 | mb->buffer_length = 0; | ||
1791 | mb->command = READ_TRACE_CONFIGURATION; | ||
1792 | err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; | ||
1793 | |||
1794 | if (err != COMMAND_OK) { | ||
1795 | chdlc_error(card,err,mb); | ||
1796 | chdlc_priv_area->TracingEnabled = 0; | ||
1797 | chdlc_udp_pkt->cblock.return_code = err; | ||
1798 | mb->buffer_length = 0; | ||
1799 | break; | ||
1800 | } | ||
1801 | |||
1802 | trace_status_cfg_addr =((LINE_TRACE_CONFIG_STRUCT *) | ||
1803 | mb->data) -> ptr_trace_stat_el_cfg_struct; | ||
1804 | |||
1805 | sdla_peek(&card->hw, trace_status_cfg_addr, | ||
1806 | &trace_cfg_struct, sizeof(trace_cfg_struct)); | ||
1807 | |||
1808 | chdlc_priv_area->start_trace_addr = trace_cfg_struct. | ||
1809 | base_addr_trace_status_elements; | ||
1810 | |||
1811 | chdlc_priv_area->number_trace_elements = | ||
1812 | trace_cfg_struct.number_trace_status_elements; | ||
1813 | |||
1814 | chdlc_priv_area->end_trace_addr = (unsigned long) | ||
1815 | ((TRACE_STATUS_ELEMENT_STRUCT *) | ||
1816 | chdlc_priv_area->start_trace_addr + | ||
1817 | (chdlc_priv_area->number_trace_elements - 1)); | ||
1818 | |||
1819 | chdlc_priv_area->base_addr_trace_buffer = | ||
1820 | trace_cfg_struct.base_addr_trace_buffer; | ||
1821 | |||
1822 | chdlc_priv_area->end_addr_trace_buffer = | ||
1823 | trace_cfg_struct.end_addr_trace_buffer; | ||
1824 | |||
1825 | chdlc_priv_area->curr_trace_addr = | ||
1826 | trace_cfg_struct.next_trace_element_to_use; | ||
1827 | |||
1828 | chdlc_priv_area->available_buffer_space = 2000 - | ||
1829 | sizeof(ip_pkt_t) - | ||
1830 | sizeof(udp_pkt_t) - | ||
1831 | sizeof(wp_mgmt_t) - | ||
1832 | sizeof(cblock_t) - | ||
1833 | sizeof(trace_info_t); | ||
1834 | } | ||
1835 | chdlc_udp_pkt->cblock.return_code = COMMAND_OK; | ||
1836 | mb->buffer_length = 0; | ||
1837 | chdlc_priv_area->TracingEnabled = 1; | ||
1838 | break; | ||
1839 | |||
1840 | |||
1841 | case CPIPE_DISABLE_TRACING: | ||
1842 | if (chdlc_priv_area->TracingEnabled) { | ||
1843 | |||
1844 | /* OPERATE_DATALINE_MONITOR */ | ||
1845 | mb->buffer_length = sizeof(LINE_TRACE_CONFIG_STRUCT); | ||
1846 | mb->command = SET_TRACE_CONFIGURATION; | ||
1847 | ((LINE_TRACE_CONFIG_STRUCT *)mb->data)-> | ||
1848 | trace_config = TRACE_INACTIVE; | ||
1849 | err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; | ||
1850 | } | ||
1851 | |||
1852 | chdlc_priv_area->TracingEnabled = 0; | ||
1853 | chdlc_udp_pkt->cblock.return_code = COMMAND_OK; | ||
1854 | mb->buffer_length = 0; | ||
1855 | break; | ||
1856 | |||
1857 | |||
1858 | case CPIPE_GET_TRACE_INFO: | ||
1859 | |||
1860 | if (!chdlc_priv_area->TracingEnabled) { | ||
1861 | chdlc_udp_pkt->cblock.return_code = 1; | ||
1862 | mb->buffer_length = 0; | ||
1863 | break; | ||
1864 | } | ||
1865 | |||
1866 | chdlc_udp_pkt->trace_info.ismoredata = 0x00; | ||
1867 | buffer_length = 0; /* offset of packet already occupied */ | ||
1868 | |||
1869 | for (frames=0; frames < chdlc_priv_area->number_trace_elements; frames++){ | ||
1870 | |||
1871 | trace_pkt_t *trace_pkt = (trace_pkt_t *) | ||
1872 | &chdlc_udp_pkt->data[buffer_length]; | ||
1873 | |||
1874 | sdla_peek(&card->hw, chdlc_priv_area->curr_trace_addr, | ||
1875 | (unsigned char *)&trace_element_struct, | ||
1876 | sizeof(TRACE_STATUS_ELEMENT_STRUCT)); | ||
1877 | |||
1878 | if (trace_element_struct.opp_flag == 0x00) { | ||
1879 | break; | ||
1880 | } | ||
1881 | |||
1882 | /* get pointer to real data */ | ||
1883 | data_ptr = trace_element_struct.ptr_data_bfr; | ||
1884 | |||
1885 | /* See if there is actual data on the trace buffer */ | ||
1886 | if (data_ptr){ | ||
1887 | data_length = trace_element_struct.trace_length; | ||
1888 | }else{ | ||
1889 | data_length = 0; | ||
1890 | chdlc_udp_pkt->trace_info.ismoredata = 0x01; | ||
1891 | } | ||
1892 | |||
1893 | if( (chdlc_priv_area->available_buffer_space - buffer_length) | ||
1894 | < ( sizeof(trace_pkt_t) + data_length) ) { | ||
1895 | |||
1896 | /* indicate there are more frames on board & exit */ | ||
1897 | chdlc_udp_pkt->trace_info.ismoredata = 0x01; | ||
1898 | break; | ||
1899 | } | ||
1900 | |||
1901 | trace_pkt->status = trace_element_struct.trace_type; | ||
1902 | |||
1903 | trace_pkt->time_stamp = | ||
1904 | trace_element_struct.trace_time_stamp; | ||
1905 | |||
1906 | trace_pkt->real_length = | ||
1907 | trace_element_struct.trace_length; | ||
1908 | |||
1909 | /* see if we can fit the frame into the user buffer */ | ||
1910 | real_len = trace_pkt->real_length; | ||
1911 | |||
1912 | if (data_ptr == 0) { | ||
1913 | trace_pkt->data_avail = 0x00; | ||
1914 | } else { | ||
1915 | unsigned tmp = 0; | ||
1916 | |||
1917 | /* get the data from circular buffer | ||
1918 | must check for end of buffer */ | ||
1919 | trace_pkt->data_avail = 0x01; | ||
1920 | |||
1921 | if ((data_ptr + real_len) > | ||
1922 | chdlc_priv_area->end_addr_trace_buffer + 1){ | ||
1923 | |||
1924 | tmp = chdlc_priv_area->end_addr_trace_buffer - data_ptr + 1; | ||
1925 | sdla_peek(&card->hw, data_ptr, | ||
1926 | trace_pkt->data,tmp); | ||
1927 | data_ptr = chdlc_priv_area->base_addr_trace_buffer; | ||
1928 | } | ||
1929 | |||
1930 | sdla_peek(&card->hw, data_ptr, | ||
1931 | &trace_pkt->data[tmp], real_len - tmp); | ||
1932 | } | ||
1933 | |||
1934 | /* zero the opp flag to show we got the frame */ | ||
1935 | ut_char = 0x00; | ||
1936 | sdla_poke(&card->hw, chdlc_priv_area->curr_trace_addr, &ut_char, 1); | ||
1937 | |||
1938 | /* now move onto the next frame */ | ||
1939 | chdlc_priv_area->curr_trace_addr += sizeof(TRACE_STATUS_ELEMENT_STRUCT); | ||
1940 | |||
1941 | /* check if we went over the last address */ | ||
1942 | if ( chdlc_priv_area->curr_trace_addr > chdlc_priv_area->end_trace_addr ) { | ||
1943 | chdlc_priv_area->curr_trace_addr = chdlc_priv_area->start_trace_addr; | ||
1944 | } | ||
1945 | |||
1946 | if(trace_pkt->data_avail == 0x01) { | ||
1947 | buffer_length += real_len - 1; | ||
1948 | } | ||
1949 | |||
1950 | /* for the header */ | ||
1951 | buffer_length += sizeof(trace_pkt_t); | ||
1952 | |||
1953 | } /* For Loop */ | ||
1954 | |||
1955 | if (frames == chdlc_priv_area->number_trace_elements){ | ||
1956 | chdlc_udp_pkt->trace_info.ismoredata = 0x01; | ||
1957 | } | ||
1958 | chdlc_udp_pkt->trace_info.num_frames = frames; | ||
1959 | |||
1960 | mb->buffer_length = buffer_length; | ||
1961 | chdlc_udp_pkt->cblock.buffer_length = buffer_length; | ||
1962 | |||
1963 | chdlc_udp_pkt->cblock.return_code = COMMAND_OK; | ||
1964 | |||
1965 | break; | ||
1966 | |||
1967 | |||
1968 | case CPIPE_FT1_READ_STATUS: | ||
1969 | ((unsigned char *)chdlc_udp_pkt->data )[0] = | ||
1970 | flags->FT1_info_struct.parallel_port_A_input; | ||
1971 | |||
1972 | ((unsigned char *)chdlc_udp_pkt->data )[1] = | ||
1973 | flags->FT1_info_struct.parallel_port_B_input; | ||
1974 | |||
1975 | chdlc_udp_pkt->cblock.return_code = COMMAND_OK; | ||
1976 | mb->buffer_length = 2; | ||
1977 | break; | ||
1978 | |||
1979 | case CPIPE_ROUTER_UP_TIME: | ||
1980 | do_gettimeofday( &tv ); | ||
1981 | chdlc_priv_area->router_up_time = tv.tv_sec - | ||
1982 | chdlc_priv_area->router_start_time; | ||
1983 | *(unsigned long *)&chdlc_udp_pkt->data = | ||
1984 | chdlc_priv_area->router_up_time; | ||
1985 | mb->buffer_length = sizeof(unsigned long); | ||
1986 | break; | ||
1987 | |||
1988 | case FT1_MONITOR_STATUS_CTRL: | ||
1989 | /* Enable FT1 MONITOR STATUS */ | ||
1990 | if ((chdlc_udp_pkt->data[0] & ENABLE_READ_FT1_STATUS) || | ||
1991 | (chdlc_udp_pkt->data[0] & ENABLE_READ_FT1_OP_STATS)) { | ||
1992 | |||
1993 | if( rCount++ != 0 ) { | ||
1994 | chdlc_udp_pkt->cblock. | ||
1995 | return_code = COMMAND_OK; | ||
1996 | mb->buffer_length = 1; | ||
1997 | break; | ||
1998 | } | ||
1999 | } | ||
2000 | |||
2001 | /* Disable FT1 MONITOR STATUS */ | ||
2002 | if( chdlc_udp_pkt->data[0] == 0) { | ||
2003 | |||
2004 | if( --rCount != 0) { | ||
2005 | chdlc_udp_pkt->cblock. | ||
2006 | return_code = COMMAND_OK; | ||
2007 | mb->buffer_length = 1; | ||
2008 | break; | ||
2009 | } | ||
2010 | } | ||
2011 | |||
2012 | default: | ||
2013 | /* it's a board command */ | ||
2014 | mb->command = chdlc_udp_pkt->cblock.command; | ||
2015 | mb->buffer_length = chdlc_udp_pkt->cblock.buffer_length; | ||
2016 | if (mb->buffer_length) { | ||
2017 | memcpy(&mb->data, (unsigned char *) chdlc_udp_pkt-> | ||
2018 | data, mb->buffer_length); | ||
2019 | } | ||
2020 | /* run the command on the board */ | ||
2021 | err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; | ||
2022 | if (err != COMMAND_OK) { | ||
2023 | break; | ||
2024 | } | ||
2025 | |||
2026 | /* copy the result back to our buffer */ | ||
2027 | memcpy(&chdlc_udp_pkt->cblock, mb, sizeof(cblock_t)); | ||
2028 | |||
2029 | if (mb->buffer_length) { | ||
2030 | memcpy(&chdlc_udp_pkt->data, &mb->data, | ||
2031 | mb->buffer_length); | ||
2032 | } | ||
2033 | |||
2034 | } /* end of switch */ | ||
2035 | } /* end of else */ | ||
2036 | |||
2037 | /* Fill UDP TTL */ | ||
2038 | chdlc_udp_pkt->ip_pkt.ttl = card->wandev.ttl; | ||
2039 | |||
2040 | len = reply_udp(chdlc_priv_area->udp_pkt_data, mb->buffer_length); | ||
2041 | |||
2042 | if(chdlc_priv_area->udp_pkt_src == UDP_PKT_FRM_NETWORK) { | ||
2043 | if(!chdlc_send(card, chdlc_priv_area->udp_pkt_data, len)) { | ||
2044 | ++ card->wandev.stats.tx_packets; | ||
2045 | card->wandev.stats.tx_bytes += len; | ||
2046 | } | ||
2047 | } else { | ||
2048 | |||
2049 | /* Pass it up the stack | ||
2050 | Allocate socket buffer */ | ||
2051 | if ((new_skb = dev_alloc_skb(len)) != NULL) { | ||
2052 | /* copy data into new_skb */ | ||
2053 | |||
2054 | buf = skb_put(new_skb, len); | ||
2055 | memcpy(buf, chdlc_priv_area->udp_pkt_data, len); | ||
2056 | |||
2057 | /* Decapsulate pkt and pass it up the protocol stack */ | ||
2058 | new_skb->protocol = htons(ETH_P_IP); | ||
2059 | new_skb->dev = dev; | ||
2060 | new_skb->mac.raw = new_skb->data; | ||
2061 | |||
2062 | netif_rx(new_skb); | ||
2063 | dev->last_rx = jiffies; | ||
2064 | } else { | ||
2065 | |||
2066 | printk(KERN_INFO "%s: no socket buffers available!\n", | ||
2067 | card->devname); | ||
2068 | } | ||
2069 | } | ||
2070 | |||
2071 | chdlc_priv_area->udp_pkt_lgth = 0; | ||
2072 | |||
2073 | return 0; | ||
2074 | } | ||
2075 | |||
2076 | /*============================================================================ | ||
2077 | * Initialize Receive and Transmit Buffers. | ||
2078 | */ | ||
2079 | |||
2080 | static void init_chdlc_tx_rx_buff(sdla_t* card, struct net_device *dev) | ||
2081 | { | ||
2082 | CHDLC_MAILBOX_STRUCT* mb = card->mbox; | ||
2083 | CHDLC_TX_STATUS_EL_CFG_STRUCT *tx_config; | ||
2084 | CHDLC_RX_STATUS_EL_CFG_STRUCT *rx_config; | ||
2085 | char err; | ||
2086 | |||
2087 | mb->buffer_length = 0; | ||
2088 | mb->command = READ_CHDLC_CONFIGURATION; | ||
2089 | err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; | ||
2090 | |||
2091 | if(err != COMMAND_OK) { | ||
2092 | chdlc_error(card,err,mb); | ||
2093 | return; | ||
2094 | } | ||
2095 | |||
2096 | if(card->hw.type == SDLA_S514) { | ||
2097 | tx_config = (CHDLC_TX_STATUS_EL_CFG_STRUCT *)(card->hw.dpmbase + | ||
2098 | (((CHDLC_CONFIGURATION_STRUCT *)mb->data)-> | ||
2099 | ptr_CHDLC_Tx_stat_el_cfg_struct)); | ||
2100 | rx_config = (CHDLC_RX_STATUS_EL_CFG_STRUCT *)(card->hw.dpmbase + | ||
2101 | (((CHDLC_CONFIGURATION_STRUCT *)mb->data)-> | ||
2102 | ptr_CHDLC_Rx_stat_el_cfg_struct)); | ||
2103 | |||
2104 | /* Setup Head and Tails for buffers */ | ||
2105 | card->u.c.txbuf_base = (void *)(card->hw.dpmbase + | ||
2106 | tx_config->base_addr_Tx_status_elements); | ||
2107 | card->u.c.txbuf_last = | ||
2108 | (CHDLC_DATA_TX_STATUS_EL_STRUCT *) | ||
2109 | card->u.c.txbuf_base + | ||
2110 | (tx_config->number_Tx_status_elements - 1); | ||
2111 | |||
2112 | card->u.c.rxbuf_base = (void *)(card->hw.dpmbase + | ||
2113 | rx_config->base_addr_Rx_status_elements); | ||
2114 | card->u.c.rxbuf_last = | ||
2115 | (CHDLC_DATA_RX_STATUS_EL_STRUCT *) | ||
2116 | card->u.c.rxbuf_base + | ||
2117 | (rx_config->number_Rx_status_elements - 1); | ||
2118 | |||
2119 | /* Set up next pointer to be used */ | ||
2120 | card->u.c.txbuf = (void *)(card->hw.dpmbase + | ||
2121 | tx_config->next_Tx_status_element_to_use); | ||
2122 | card->u.c.rxmb = (void *)(card->hw.dpmbase + | ||
2123 | rx_config->next_Rx_status_element_to_use); | ||
2124 | } | ||
2125 | else { | ||
2126 | tx_config = (CHDLC_TX_STATUS_EL_CFG_STRUCT *)(card->hw.dpmbase + | ||
2127 | (((CHDLC_CONFIGURATION_STRUCT *)mb->data)-> | ||
2128 | ptr_CHDLC_Tx_stat_el_cfg_struct % SDLA_WINDOWSIZE)); | ||
2129 | |||
2130 | rx_config = (CHDLC_RX_STATUS_EL_CFG_STRUCT *)(card->hw.dpmbase + | ||
2131 | (((CHDLC_CONFIGURATION_STRUCT *)mb->data)-> | ||
2132 | ptr_CHDLC_Rx_stat_el_cfg_struct % SDLA_WINDOWSIZE)); | ||
2133 | |||
2134 | /* Setup Head and Tails for buffers */ | ||
2135 | card->u.c.txbuf_base = (void *)(card->hw.dpmbase + | ||
2136 | (tx_config->base_addr_Tx_status_elements % SDLA_WINDOWSIZE)); | ||
2137 | card->u.c.txbuf_last = | ||
2138 | (CHDLC_DATA_TX_STATUS_EL_STRUCT *)card->u.c.txbuf_base | ||
2139 | + (tx_config->number_Tx_status_elements - 1); | ||
2140 | card->u.c.rxbuf_base = (void *)(card->hw.dpmbase + | ||
2141 | (rx_config->base_addr_Rx_status_elements % SDLA_WINDOWSIZE)); | ||
2142 | card->u.c.rxbuf_last = | ||
2143 | (CHDLC_DATA_RX_STATUS_EL_STRUCT *)card->u.c.rxbuf_base | ||
2144 | + (rx_config->number_Rx_status_elements - 1); | ||
2145 | |||
2146 | /* Set up next pointer to be used */ | ||
2147 | card->u.c.txbuf = (void *)(card->hw.dpmbase + | ||
2148 | (tx_config->next_Tx_status_element_to_use % SDLA_WINDOWSIZE)); | ||
2149 | card->u.c.rxmb = (void *)(card->hw.dpmbase + | ||
2150 | (rx_config->next_Rx_status_element_to_use % SDLA_WINDOWSIZE)); | ||
2151 | } | ||
2152 | |||
2153 | /* Setup Actual Buffer Start and end addresses */ | ||
2154 | card->u.c.rx_base = rx_config->base_addr_Rx_buffer; | ||
2155 | card->u.c.rx_top = rx_config->end_addr_Rx_buffer; | ||
2156 | |||
2157 | } | ||
2158 | |||
2159 | /*============================================================================= | ||
2160 | * Perform Interrupt Test by running READ_CHDLC_CODE_VERSION command MAX_INTR | ||
2161 | * _TEST_COUNTER times. | ||
2162 | */ | ||
2163 | static int intr_test( sdla_t* card) | ||
2164 | { | ||
2165 | CHDLC_MAILBOX_STRUCT* mb = card->mbox; | ||
2166 | int err,i; | ||
2167 | |||
2168 | Intr_test_counter = 0; | ||
2169 | |||
2170 | /* The critical flag is unset because during initialization (if_open) | ||
2171 | * we want the interrupts to be enabled so that when the wpc_isr is | ||
2172 | * called it does not exit due to critical flag set. | ||
2173 | */ | ||
2174 | |||
2175 | err = chdlc_set_intr_mode(card, APP_INT_ON_COMMAND_COMPLETE); | ||
2176 | |||
2177 | if (err == CMD_OK) { | ||
2178 | for (i = 0; i < MAX_INTR_TEST_COUNTER; i ++) { | ||
2179 | mb->buffer_length = 0; | ||
2180 | mb->command = READ_CHDLC_CODE_VERSION; | ||
2181 | err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; | ||
2182 | } | ||
2183 | } | ||
2184 | else { | ||
2185 | return err; | ||
2186 | } | ||
2187 | |||
2188 | err = chdlc_set_intr_mode(card, 0); | ||
2189 | |||
2190 | if (err != CMD_OK) | ||
2191 | return err; | ||
2192 | |||
2193 | return 0; | ||
2194 | } | ||
2195 | |||
2196 | /*============================================================================== | ||
2197 | * Determine what type of UDP call it is. CPIPEAB ? | ||
2198 | */ | ||
2199 | static int udp_pkt_type(struct sk_buff *skb, sdla_t* card) | ||
2200 | { | ||
2201 | chdlc_udp_pkt_t *chdlc_udp_pkt = (chdlc_udp_pkt_t *)skb->data; | ||
2202 | |||
2203 | if (!strncmp(chdlc_udp_pkt->wp_mgmt.signature,UDPMGMT_SIGNATURE,8) && | ||
2204 | (chdlc_udp_pkt->udp_pkt.udp_dst_port == ntohs(card->wandev.udp_port)) && | ||
2205 | (chdlc_udp_pkt->ip_pkt.protocol == UDPMGMT_UDP_PROTOCOL) && | ||
2206 | (chdlc_udp_pkt->wp_mgmt.request_reply == UDPMGMT_REQUEST)) { | ||
2207 | return UDP_CPIPE_TYPE; | ||
2208 | } | ||
2209 | else return UDP_INVALID_TYPE; | ||
2210 | } | ||
2211 | |||
2212 | /*============================================================================ | ||
2213 | * Set PORT state. | ||
2214 | */ | ||
2215 | static void port_set_state (sdla_t *card, int state) | ||
2216 | { | ||
2217 | struct net_device *dev = card->wandev.dev; | ||
2218 | chdlc_private_area_t *chdlc_priv_area = dev->priv; | ||
2219 | |||
2220 | if (card->u.c.state != state) | ||
2221 | { | ||
2222 | switch (state) | ||
2223 | { | ||
2224 | case WAN_CONNECTED: | ||
2225 | printk (KERN_INFO "%s: HDLC link connected!\n", | ||
2226 | card->devname); | ||
2227 | break; | ||
2228 | |||
2229 | case WAN_CONNECTING: | ||
2230 | printk (KERN_INFO "%s: HDLC link connecting...\n", | ||
2231 | card->devname); | ||
2232 | break; | ||
2233 | |||
2234 | case WAN_DISCONNECTED: | ||
2235 | printk (KERN_INFO "%s: HDLC link disconnected!\n", | ||
2236 | card->devname); | ||
2237 | break; | ||
2238 | } | ||
2239 | |||
2240 | card->wandev.state = card->u.c.state = state; | ||
2241 | chdlc_priv_area->common.state = state; | ||
2242 | } | ||
2243 | } | ||
2244 | |||
2245 | void s508_lock (sdla_t *card, unsigned long *smp_flags) | ||
2246 | { | ||
2247 | spin_lock_irqsave(&card->wandev.lock, *smp_flags); | ||
2248 | if (card->next){ | ||
2249 | /* It is ok to use spin_lock here, since we | ||
2250 | * already turned off interrupts */ | ||
2251 | spin_lock(&card->next->wandev.lock); | ||
2252 | } | ||
2253 | } | ||
2254 | |||
2255 | void s508_unlock (sdla_t *card, unsigned long *smp_flags) | ||
2256 | { | ||
2257 | if (card->next){ | ||
2258 | spin_unlock(&card->next->wandev.lock); | ||
2259 | } | ||
2260 | spin_unlock_irqrestore(&card->wandev.lock, *smp_flags); | ||
2261 | } | ||
2262 | |||
2263 | |||
2264 | |||
2265 | /*=========================================================================== | ||
2266 | * config_chdlc | ||
2267 | * | ||
2268 | * Configure the chdlc protocol and enable communications. | ||
2269 | * | ||
2270 | * The if_open() function binds this function to the poll routine. | ||
2271 | * Therefore, this function will run every time the chdlc interface | ||
2272 | * is brought up. We cannot run this function from the if_open | ||
2273 | * because if_open does not have access to the remote IP address. | ||
2274 | * | ||
2275 | * If the communications are not enabled, proceed to configure | ||
2276 | * the card and enable communications. | ||
2277 | * | ||
2278 | * If the communications are enabled, it means that the interface | ||
2279 | * was shutdown by ether the user or driver. In this case, we | ||
2280 | * have to check that the IP addresses have not changed. If | ||
2281 | * the IP addresses have changed, we have to reconfigure the firmware | ||
2282 | * and update the changed IP addresses. Otherwise, just exit. | ||
2283 | * | ||
2284 | */ | ||
2285 | |||
2286 | static int config_chdlc (sdla_t *card) | ||
2287 | { | ||
2288 | struct net_device *dev = card->wandev.dev; | ||
2289 | SHARED_MEMORY_INFO_STRUCT *flags = card->u.c.flags; | ||
2290 | |||
2291 | if (card->u.c.comm_enabled){ | ||
2292 | chdlc_comm_disable(card); | ||
2293 | port_set_state(card, WAN_DISCONNECTED); | ||
2294 | } | ||
2295 | |||
2296 | if (set_chdlc_config(card)) { | ||
2297 | printk(KERN_INFO "%s: CHDLC Configuration Failed!\n", | ||
2298 | card->devname); | ||
2299 | return 0; | ||
2300 | } | ||
2301 | init_chdlc_tx_rx_buff(card, dev); | ||
2302 | |||
2303 | /* Set interrupt mode and mask */ | ||
2304 | if (chdlc_set_intr_mode(card, APP_INT_ON_RX_FRAME | | ||
2305 | APP_INT_ON_GLOBAL_EXCEP_COND | | ||
2306 | APP_INT_ON_TX_FRAME | | ||
2307 | APP_INT_ON_CHDLC_EXCEP_COND | APP_INT_ON_TIMER)){ | ||
2308 | printk (KERN_INFO "%s: Failed to set interrupt triggers!\n", | ||
2309 | card->devname); | ||
2310 | return 0; | ||
2311 | } | ||
2312 | |||
2313 | |||
2314 | /* Mask the Transmit and Timer interrupt */ | ||
2315 | flags->interrupt_info_struct.interrupt_permission &= | ||
2316 | ~(APP_INT_ON_TX_FRAME | APP_INT_ON_TIMER); | ||
2317 | |||
2318 | |||
2319 | if (chdlc_comm_enable(card) != 0) { | ||
2320 | printk(KERN_INFO "%s: Failed to enable chdlc communications!\n", | ||
2321 | card->devname); | ||
2322 | flags->interrupt_info_struct.interrupt_permission = 0; | ||
2323 | card->u.c.comm_enabled=0; | ||
2324 | chdlc_set_intr_mode(card,0); | ||
2325 | return 0; | ||
2326 | } | ||
2327 | |||
2328 | /* Initialize Rx/Tx buffer control fields */ | ||
2329 | port_set_state(card, WAN_CONNECTING); | ||
2330 | return 0; | ||
2331 | } | ||
2332 | |||
2333 | |||
2334 | static void send_ppp_term_request(struct net_device *dev) | ||
2335 | { | ||
2336 | struct sk_buff *new_skb; | ||
2337 | unsigned char *buf; | ||
2338 | |||
2339 | if ((new_skb = dev_alloc_skb(8)) != NULL) { | ||
2340 | /* copy data into new_skb */ | ||
2341 | |||
2342 | buf = skb_put(new_skb, 8); | ||
2343 | sprintf(buf,"%c%c%c%c%c%c%c%c", 0xFF,0x03,0xC0,0x21,0x05,0x98,0x00,0x07); | ||
2344 | |||
2345 | /* Decapsulate pkt and pass it up the protocol stack */ | ||
2346 | new_skb->protocol = htons(ETH_P_WAN_PPP); | ||
2347 | new_skb->dev = dev; | ||
2348 | new_skb->mac.raw = new_skb->data; | ||
2349 | |||
2350 | netif_rx(new_skb); | ||
2351 | dev->last_rx = jiffies; | ||
2352 | } | ||
2353 | } | ||
2354 | |||
2355 | |||
2356 | MODULE_LICENSE("GPL"); | ||
2357 | |||
2358 | /****** End ****************************************************************/ | ||
diff --git a/include/linux/sdla_asy.h b/include/linux/sdla_asy.h deleted file mode 100644 index f62242537c86..000000000000 --- a/include/linux/sdla_asy.h +++ /dev/null | |||
@@ -1,226 +0,0 @@ | |||
1 | /***************************************************************************** | ||
2 | * sdla_asy.h Header file for the Sangoma S508/S514 asynchronous code API | ||
3 | * | ||
4 | * Author: Gideon Hack | ||
5 | * | ||
6 | * Copyright: (c) 2000 Sangoma Technologies Inc. | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License | ||
10 | * as published by the Free Software Foundation; either version | ||
11 | * 2 of the License, or (at your option) any later version. | ||
12 | * ============================================================================ | ||
13 | * | ||
14 | * Jan 28, 2000 Gideon Hack Initial Version | ||
15 | * | ||
16 | *****************************************************************************/ | ||
17 | |||
18 | |||
19 | #ifndef _WANPIPE_ASYNC_H | ||
20 | #define _WANPIPE_ASYNC_H | ||
21 | |||
22 | /* ---------------------------------------------------------------------------- | ||
23 | * Interface commands | ||
24 | * --------------------------------------------------------------------------*/ | ||
25 | |||
26 | #define SET_ASY_CONFIGURATION 0xE2 /* set the asychronous operational configuration */ | ||
27 | #define READ_ASY_CONFIGURATION 0xE3 /* read the current asychronous operational configuration */ | ||
28 | #define ENABLE_ASY_COMMUNICATIONS 0xE4 /* enable asychronous communications */ | ||
29 | #define DISABLE_ASY_COMMUNICATIONS 0xE5 /* disable asychronous communications */ | ||
30 | #define READ_ASY_OPERATIONAL_STATS 0xE7 /* retrieve the asychronous operational statistics */ | ||
31 | #define FLUSH_ASY_OPERATIONAL_STATS 0xE8 /* flush the asychronous operational statistics */ | ||
32 | #define TRANSMIT_ASY_BREAK_SIGNAL 0xEC /* transmit an asychronous break signal */ | ||
33 | |||
34 | |||
35 | |||
36 | /* ---------------------------------------------------------------------------- | ||
37 | * Return codes from interface commands | ||
38 | * --------------------------------------------------------------------------*/ | ||
39 | |||
40 | #define COMMAND_INVALID_FOR_PORT 0x50 /* the command is invalid for the selected port */ | ||
41 | #define DISABLE_ASY_COMMS_BEFORE_CFG 0xE1 /* communications must be disabled before setting the configuration */ | ||
42 | #define ASY_COMMS_ENABLED 0xE1 /* communications are currently enabled */ | ||
43 | #define ASY_COMMS_DISABLED 0xE1 /* communications are currently disabled */ | ||
44 | #define ASY_CFG_BEFORE_COMMS_ENABLED 0xE2 /* perform a SET_ASY_CONFIGURATION before enabling comms */ | ||
45 | #define LGTH_ASY_CFG_DATA_INVALID 0xE2 /* the length of the passed configuration data is invalid */ | ||
46 | #define INVALID_ASY_CFG_DATA 0xE3 /* the passed configuration data is invalid */ | ||
47 | #define ASY_BREAK_SIGNAL_BUSY 0xEC /* a break signal is being transmitted */ | ||
48 | |||
49 | |||
50 | |||
51 | /* ---------------------------------------------------------------------------- | ||
52 | * Constants for the SET_ASY_CONFIGURATION/READ_ASY_CONFIGURATION command | ||
53 | * --------------------------------------------------------------------------*/ | ||
54 | |||
55 | /* the asynchronous configuration structure */ | ||
56 | typedef struct { | ||
57 | unsigned long baud_rate PACKED; /* the baud rate */ | ||
58 | unsigned short line_config_options PACKED; /* line configuration options */ | ||
59 | unsigned short modem_config_options PACKED; /* modem configuration options */ | ||
60 | unsigned short asy_API_options PACKED; /* asynchronous API options */ | ||
61 | unsigned short asy_protocol_options PACKED; /* asynchronous protocol options */ | ||
62 | unsigned short Tx_bits_per_char PACKED; /* number of bits per tx character */ | ||
63 | unsigned short Rx_bits_per_char PACKED; /* number of bits per received character */ | ||
64 | unsigned short stop_bits PACKED; /* number of stop bits per character */ | ||
65 | unsigned short parity PACKED; /* parity definition */ | ||
66 | unsigned short break_timer PACKED; /* the break signal timer */ | ||
67 | unsigned short asy_Rx_inter_char_timer PACKED; /* the receive inter-character timer */ | ||
68 | unsigned short asy_Rx_complete_length PACKED; /* the receive 'buffer complete' length */ | ||
69 | unsigned short XON_char PACKED; /* the XON character */ | ||
70 | unsigned short XOFF_char PACKED; /* the XOFF character */ | ||
71 | unsigned short asy_statistics_options PACKED; /* async operational stat options */ | ||
72 | unsigned long ptr_shared_mem_info_struct PACKED;/* ptr to the shared memory area information structure */ | ||
73 | unsigned long ptr_asy_Tx_stat_el_cfg_struct PACKED;/* ptr to the transmit status element configuration structure */ | ||
74 | unsigned long ptr_asy_Rx_stat_el_cfg_struct PACKED;/* ptr to the receive status element configuration structure */ | ||
75 | } ASY_CONFIGURATION_STRUCT; | ||
76 | |||
77 | /* permitted minimum and maximum values for setting the asynchronous configuration */ | ||
78 | #define MIN_ASY_BAUD_RATE 50 /* maximum baud rate */ | ||
79 | #define MAX_ASY_BAUD_RATE 250000 /* minimum baud rate */ | ||
80 | #define MIN_ASY_BITS_PER_CHAR 5 /* minimum number of bits per character */ | ||
81 | #define MAX_ASY_BITS_PER_CHAR 8 /* maximum number of bits per character */ | ||
82 | #define MIN_BREAK_TMR_VAL 0 /* minimum break signal timer */ | ||
83 | #define MAX_BREAK_TMR_VAL 5000 /* maximum break signal timer */ | ||
84 | #define MIN_ASY_RX_INTER_CHAR_TMR 0 /* minimum receive inter-character timer */ | ||
85 | #define MAX_ASY_RX_INTER_CHAR_TMR 30000 /* maximum receive inter-character timer */ | ||
86 | #define MIN_ASY_RX_CPLT_LENGTH 0 /* minimum receive 'length complete' value */ | ||
87 | #define MAX_ASY_RX_CPLT_LENGTH 2000 /* maximum receive 'length complete' value */ | ||
88 | |||
89 | /* bit settings for the 'asy_API_options' */ | ||
90 | #define ASY_RX_DATA_TRANSPARENT 0x0001 /* do not strip parity and unused bits from received characters */ | ||
91 | |||
92 | /* bit settings for the 'asy_protocol_options' */ | ||
93 | #define ASY_RTS_HS_FOR_RX 0x0001 /* RTS handshaking is used for reception control */ | ||
94 | #define ASY_XON_XOFF_HS_FOR_RX 0x0002 /* XON/XOFF handshaking is used for reception control */ | ||
95 | #define ASY_XON_XOFF_HS_FOR_TX 0x0004 /* XON/XOFF handshaking is used for transmission control */ | ||
96 | #define ASY_DCD_HS_FOR_TX 0x0008 /* DCD handshaking is used for transmission control */ | ||
97 | #define ASY_CTS_HS_FOR_TX 0x0020 /* CTS handshaking is used for transmission control */ | ||
98 | |||
99 | /* bit settings for the 'stop_bits' definition */ | ||
100 | #define ONE_STOP_BIT 1 /* representation for 1 stop bit */ | ||
101 | #define TWO_STOP_BITS 2 /* representation for 2 stop bits */ | ||
102 | #define ONE_AND_A_HALF_STOP_BITS 3 /* representation for 1.5 stop bits */ | ||
103 | |||
104 | /* bit settings for the 'parity' definition */ | ||
105 | #define NO_PARITY 0 /* representation for no parity */ | ||
106 | #define ODD_PARITY 1 /* representation for odd parity */ | ||
107 | #define EVEN_PARITY 2 /* representation for even parity */ | ||
108 | |||
109 | |||
110 | |||
111 | /* ---------------------------------------------------------------------------- | ||
112 | * Constants for the READ_COMMS_ERROR_STATS command (asynchronous mode) | ||
113 | * --------------------------------------------------------------------------*/ | ||
114 | |||
115 | /* the communications error statistics structure */ | ||
116 | typedef struct { | ||
117 | unsigned short Rx_overrun_err_count PACKED; /* receiver overrun error count */ | ||
118 | unsigned short Rx_parity_err_count PACKED; /* parity errors received count */ | ||
119 | unsigned short Rx_framing_err_count PACKED; /* framing errors received count */ | ||
120 | unsigned short comms_err_stat_reserved_1 PACKED;/* reserved for later use */ | ||
121 | unsigned short comms_err_stat_reserved_2 PACKED;/* reserved for later use */ | ||
122 | unsigned short comms_err_stat_reserved_3 PACKED;/* reserved for later use */ | ||
123 | unsigned short comms_err_stat_reserved_4 PACKED;/* reserved for later use */ | ||
124 | unsigned short comms_err_stat_reserved_5 PACKED;/* reserved for later use */ | ||
125 | unsigned short DCD_state_change_count PACKED; /* DCD state change count */ | ||
126 | unsigned short CTS_state_change_count PACKED; /* CTS state change count */ | ||
127 | } ASY_COMMS_ERROR_STATS_STRUCT; | ||
128 | |||
129 | |||
130 | |||
131 | /* ---------------------------------------------------------------------------- | ||
132 | * Constants for the READ_ASY_OPERATIONAL_STATS command | ||
133 | * --------------------------------------------------------------------------*/ | ||
134 | |||
135 | /* the asynchronous operational statistics structure */ | ||
136 | typedef struct { | ||
137 | |||
138 | /* Data transmission statistics */ | ||
139 | unsigned long Data_blocks_Tx_count PACKED;/* number of blocks transmitted */ | ||
140 | unsigned long Data_bytes_Tx_count PACKED;/* number of bytes transmitted */ | ||
141 | unsigned long Data_Tx_throughput PACKED;/* transmit throughput */ | ||
142 | unsigned long no_ms_for_Data_Tx_thruput_comp PACKED;/* millisecond time used for the Tx throughput computation */ | ||
143 | unsigned long Tx_Data_discard_lgth_err_count PACKED;/* number of Data blocks discarded (length error) */ | ||
144 | unsigned long reserved_Data_frm_Tx_stat1 PACKED;/* reserved for later use */ | ||
145 | unsigned long reserved_Data_frm_Tx_stat2 PACKED;/* reserved for later use */ | ||
146 | unsigned long reserved_Data_frm_Tx_stat3 PACKED;/* reserved for later use */ | ||
147 | |||
148 | /* Data reception statistics */ | ||
149 | unsigned long Data_blocks_Rx_count PACKED;/* number of blocks received */ | ||
150 | unsigned long Data_bytes_Rx_count PACKED;/* number of bytes received */ | ||
151 | unsigned long Data_Rx_throughput PACKED;/* receive throughput */ | ||
152 | unsigned long no_ms_for_Data_Rx_thruput_comp PACKED;/* millisecond time used for the Rx throughput computation */ | ||
153 | unsigned long Rx_Data_bytes_discard_count PACKED;/* received Data bytes discarded */ | ||
154 | unsigned long reserved_Data_frm_Rx_stat1 PACKED;/* reserved for later use */ | ||
155 | |||
156 | /* handshaking protocol statistics */ | ||
157 | unsigned short XON_chars_Tx_count PACKED; /* number of XON characters transmitted */ | ||
158 | unsigned short XOFF_chars_Tx_count PACKED; /* number of XOFF characters transmitted */ | ||
159 | unsigned short XON_chars_Rx_count PACKED; /* number of XON characters received */ | ||
160 | unsigned short XOFF_chars_Rx_count PACKED; /* number of XOFF characters received */ | ||
161 | unsigned short Tx_halt_modem_low_count PACKED; /* number of times Tx halted (modem line low) */ | ||
162 | unsigned short Rx_halt_RTS_low_count PACKED; /* number of times Rx halted by setting RTS low */ | ||
163 | unsigned long reserved_handshaking_stat1 PACKED;/* reserved for later use */ | ||
164 | |||
165 | /* break statistics */ | ||
166 | unsigned short break_Tx_count PACKED; /* number of break sequences transmitted */ | ||
167 | unsigned short break_Rx_count PACKED; /* number of break sequences received */ | ||
168 | unsigned long reserved_break_stat1 PACKED;/* reserved for later use */ | ||
169 | |||
170 | /* miscellaneous statistics */ | ||
171 | unsigned long reserved_misc_stat1 PACKED; /* reserved for later use */ | ||
172 | unsigned long reserved_misc_stat2 PACKED; /* reserved for later use */ | ||
173 | |||
174 | } ASY_OPERATIONAL_STATS_STRUCT; | ||
175 | |||
176 | |||
177 | |||
178 | /* ---------------------------------------------------------------------------- | ||
179 | * Constants for Data transmission | ||
180 | * --------------------------------------------------------------------------*/ | ||
181 | |||
182 | /* the Data block transmit status element configuration structure */ | ||
183 | typedef struct { | ||
184 | unsigned short number_Tx_status_elements PACKED; /* number of transmit status elements */ | ||
185 | unsigned long base_addr_Tx_status_elements PACKED; /* base address of the transmit element list */ | ||
186 | unsigned long next_Tx_status_element_to_use PACKED; /* pointer to the next transmit element to be used */ | ||
187 | } ASY_TX_STATUS_EL_CFG_STRUCT; | ||
188 | |||
189 | |||
190 | /* the Data block transmit status element structure */ | ||
191 | typedef struct { | ||
192 | unsigned char opp_flag PACKED; /* opp flag */ | ||
193 | unsigned short data_length PACKED; /* length of the block to be transmitted */ | ||
194 | unsigned char reserved_1 PACKED; /* reserved for internal use */ | ||
195 | unsigned long reserved_2 PACKED; /* reserved for internal use */ | ||
196 | unsigned long reserved_3 PACKED; /* reserved for internal use */ | ||
197 | unsigned long ptr_data_bfr PACKED; /* pointer to the data area */ | ||
198 | } ASY_DATA_TX_STATUS_EL_STRUCT; | ||
199 | |||
200 | |||
201 | |||
202 | /* ---------------------------------------------------------------------------- | ||
203 | * Constants for Data reception | ||
204 | * --------------------------------------------------------------------------*/ | ||
205 | |||
206 | /* the Data block receive status element configuration structure */ | ||
207 | typedef struct { | ||
208 | unsigned short number_Rx_status_elements PACKED;/* number of receive status elements */ | ||
209 | unsigned long base_addr_Rx_status_elements PACKED;/* base address of the receive element list */ | ||
210 | unsigned long next_Rx_status_element_to_use PACKED;/* pointer to the next receive element to be used */ | ||
211 | unsigned long base_addr_Rx_buffer PACKED;/* base address of the receive data buffer */ | ||
212 | unsigned long end_addr_Rx_buffer PACKED;/* end address of the receive data buffer */ | ||
213 | } ASY_RX_STATUS_EL_CFG_STRUCT; | ||
214 | |||
215 | /* the Data block receive status element structure */ | ||
216 | typedef struct { | ||
217 | unsigned char opp_flag PACKED; /* opp flag */ | ||
218 | unsigned short data_length PACKED; /* length of the received data block */ | ||
219 | unsigned char reserved_1 PACKED; /* reserved for internal use */ | ||
220 | unsigned short time_stamp PACKED; /* receive time stamp (HDLC_STREAMING_MODE) */ | ||
221 | unsigned short data_buffered PACKED; /* the number of data bytes still buffered */ | ||
222 | unsigned long reserved_2 PACKED; /* reserved for internal use */ | ||
223 | unsigned long ptr_data_bfr PACKED; /* pointer to the data area */ | ||
224 | } ASY_DATA_RX_STATUS_EL_STRUCT; | ||
225 | |||
226 | #endif | ||
diff --git a/include/linux/sdla_chdlc.h b/include/linux/sdla_chdlc.h deleted file mode 100644 index d2e35a299034..000000000000 --- a/include/linux/sdla_chdlc.h +++ /dev/null | |||
@@ -1,813 +0,0 @@ | |||
1 | /************************************************************************* | ||
2 | sdla_chdlc.h Sangoma Cisco HDLC firmware API definitions | ||
3 | |||
4 | Author: Gideon Hack | ||
5 | Nenad Corbic <ncorbic@sangoma.com> | ||
6 | |||
7 | Copyright: (c) 1995-2000 Sangoma Technologies Inc. | ||
8 | |||
9 | This program is free software; you can redistribute it and/or | ||
10 | modify it under the term of the GNU General Public License | ||
11 | as published by the Free Software Foundation; either version | ||
12 | 2 of the License, or (at your option) any later version. | ||
13 | |||
14 | =========================================================================== | ||
15 | Oct 04, 1999 Nenad Corbic Updated API support | ||
16 | Jun 02, 1999 Gideon Hack Changes for S514 usage. | ||
17 | Oct 28, 1998 Jaspreet Singh Made changes for Dual Port CHDLC. | ||
18 | Jun 11, 1998 David Fong Initial version. | ||
19 | =========================================================================== | ||
20 | |||
21 | Organization | ||
22 | - Compatibility notes | ||
23 | - Constants defining the shared memory control block (mailbox) | ||
24 | - Interface commands | ||
25 | - Return code from interface commands | ||
26 | - Constants for the commands (structures for casting data) | ||
27 | - UDP Management constants and structures | ||
28 | |||
29 | *************************************************************************/ | ||
30 | |||
31 | #ifndef _SDLA_CHDLC_H | ||
32 | # define _SDLC_CHDLC_H | ||
33 | |||
34 | /*------------------------------------------------------------------------ | ||
35 | Notes: | ||
36 | |||
37 | All structres defined in this file are byte-aligned. | ||
38 | |||
39 | Compiler Platform | ||
40 | ------------------------ | ||
41 | GNU C Linux | ||
42 | |||
43 | ------------------------------------------------------------------------*/ | ||
44 | |||
45 | #ifndef PACKED | ||
46 | #define PACKED __attribute__((packed)) | ||
47 | #endif /* PACKED */ | ||
48 | |||
49 | |||
50 | /* ---------------------------------------------------------------------------- | ||
51 | * Constants defining the shared memory control block (mailbox) | ||
52 | * --------------------------------------------------------------------------*/ | ||
53 | |||
54 | #define PRI_BASE_ADDR_MB_STRUCT 0xE000 /* the base address of the mailbox structure on the adapter */ | ||
55 | #define SEC_BASE_ADDR_MB_STRUCT 0xE800 /* the base address of the mailbox structure on the adapter */ | ||
56 | #define SIZEOF_MB_DATA_BFR 2032 /* the size of the actual mailbox data area */ | ||
57 | #define NUMBER_MB_RESERVED_BYTES 0x0B /* the number of reserved bytes in the mailbox header area */ | ||
58 | |||
59 | |||
60 | #define MIN_LGTH_CHDLC_DATA_CFG 300 /* min length of the CHDLC data field (for configuration purposes) */ | ||
61 | #define PRI_MAX_NO_DATA_BYTES_IN_FRAME 15354 /* PRIMARY - max length of the CHDLC data field */ | ||
62 | |||
63 | typedef struct { | ||
64 | unsigned char opp_flag PACKED; /* the opp flag */ | ||
65 | unsigned char command PACKED; /* the user command */ | ||
66 | unsigned short buffer_length PACKED; /* the data length */ | ||
67 | unsigned char return_code PACKED; /* the return code */ | ||
68 | unsigned char MB_reserved[NUMBER_MB_RESERVED_BYTES] PACKED; /* reserved for later */ | ||
69 | unsigned char data[SIZEOF_MB_DATA_BFR] PACKED; /* the data area */ | ||
70 | } CHDLC_MAILBOX_STRUCT; | ||
71 | |||
72 | typedef struct { | ||
73 | pid_t pid_num PACKED; | ||
74 | CHDLC_MAILBOX_STRUCT cmdarea PACKED; | ||
75 | |||
76 | } CMDBLOCK_STRUCT; | ||
77 | |||
78 | |||
79 | |||
80 | |||
81 | /* ---------------------------------------------------------------------------- | ||
82 | * Interface commands | ||
83 | * --------------------------------------------------------------------------*/ | ||
84 | |||
85 | /* global interface commands */ | ||
86 | #define READ_GLOBAL_EXCEPTION_CONDITION 0x01 | ||
87 | #define SET_GLOBAL_CONFIGURATION 0x02 | ||
88 | #define READ_GLOBAL_CONFIGURATION 0x03 | ||
89 | #define READ_GLOBAL_STATISTICS 0x04 | ||
90 | #define FLUSH_GLOBAL_STATISTICS 0x05 | ||
91 | #define SET_MODEM_STATUS 0x06 /* set status of DTR or RTS */ | ||
92 | #define READ_MODEM_STATUS 0x07 /* read status of CTS and DCD */ | ||
93 | #define READ_COMMS_ERROR_STATS 0x08 | ||
94 | #define FLUSH_COMMS_ERROR_STATS 0x09 | ||
95 | #define SET_TRACE_CONFIGURATION 0x0A /* set the line trace config */ | ||
96 | #define READ_TRACE_CONFIGURATION 0x0B /* read the line trace config */ | ||
97 | #define READ_TRACE_STATISTICS 0x0C /* read the trace statistics */ | ||
98 | #define FLUSH_TRACE_STATISTICS 0x0D /* flush the trace statistics */ | ||
99 | #define FT1_MONITOR_STATUS_CTRL 0x1C /* set the status of the S508/FT1 monitoring */ | ||
100 | #define SET_FT1_CONFIGURATION 0x18 /* set the FT1 configuration */ | ||
101 | #define READ_FT1_CONFIGURATION 0x19 /* read the FT1 configuration */ | ||
102 | #define TRANSMIT_ASYNC_DATA_TO_FT1 0x1A /* output asynchronous data to the FT1 */ | ||
103 | #define RECEIVE_ASYNC_DATA_FROM_FT1 0x1B /* receive asynchronous data from the FT1 */ | ||
104 | #define FT1_MONITOR_STATUS_CTRL 0x1C /* set the status of the FT1 monitoring */ | ||
105 | |||
106 | #define READ_FT1_OPERATIONAL_STATS 0x1D /* read the S508/FT1 operational statistics */ | ||
107 | #define SET_FT1_MODE 0x1E /* set the operational mode of the S508/FT1 module */ | ||
108 | |||
109 | /* CHDLC-level interface commands */ | ||
110 | #define READ_CHDLC_CODE_VERSION 0x20 | ||
111 | #define READ_CHDLC_EXCEPTION_CONDITION 0x21 /* read exception condition from the adapter */ | ||
112 | #define SET_CHDLC_CONFIGURATION 0x22 | ||
113 | #define READ_CHDLC_CONFIGURATION 0x23 | ||
114 | #define ENABLE_CHDLC_COMMUNICATIONS 0x24 | ||
115 | #define DISABLE_CHDLC_COMMUNICATIONS 0x25 | ||
116 | #define READ_CHDLC_LINK_STATUS 0x26 | ||
117 | #define READ_CHDLC_OPERATIONAL_STATS 0x27 | ||
118 | #define FLUSH_CHDLC_OPERATIONAL_STATS 0x28 | ||
119 | #define SET_CHDLC_INTERRUPT_TRIGGERS 0x30 /* set application interrupt triggers */ | ||
120 | #define READ_CHDLC_INTERRUPT_TRIGGERS 0x31 /* read application interrupt trigger configuration */ | ||
121 | |||
122 | /* Special UDP drivers management commands */ | ||
123 | #define CPIPE_ENABLE_TRACING 0x50 | ||
124 | #define CPIPE_DISABLE_TRACING 0x51 | ||
125 | #define CPIPE_GET_TRACE_INFO 0x52 | ||
126 | #define CPIPE_GET_IBA_DATA 0x53 | ||
127 | #define CPIPE_FT1_READ_STATUS 0x54 | ||
128 | #define CPIPE_DRIVER_STAT_IFSEND 0x55 | ||
129 | #define CPIPE_DRIVER_STAT_INTR 0x56 | ||
130 | #define CPIPE_DRIVER_STAT_GEN 0x57 | ||
131 | #define CPIPE_FLUSH_DRIVER_STATS 0x58 | ||
132 | #define CPIPE_ROUTER_UP_TIME 0x59 | ||
133 | |||
134 | /* Driver specific commands for API */ | ||
135 | #define CHDLC_READ_TRACE_DATA 0xE4 /* read trace data */ | ||
136 | #define TRACE_ALL 0x00 | ||
137 | #define TRACE_PROT 0x01 | ||
138 | #define TRACE_DATA 0x02 | ||
139 | |||
140 | #define DISCARD_RX_ERROR_FRAMES 0x0001 | ||
141 | |||
142 | /* ---------------------------------------------------------------------------- | ||
143 | * Return codes from interface commands | ||
144 | * --------------------------------------------------------------------------*/ | ||
145 | |||
146 | #define COMMAND_OK 0x00 | ||
147 | |||
148 | /* return codes from global interface commands */ | ||
149 | #define NO_GLOBAL_EXCEP_COND_TO_REPORT 0x01 /* there is no CHDLC exception condition to report */ | ||
150 | #define LGTH_GLOBAL_CFG_DATA_INVALID 0x01 /* the length of the passed global configuration data is invalid */ | ||
151 | #define LGTH_TRACE_CFG_DATA_INVALID 0x01 /* the length of the passed trace configuration data is invalid */ | ||
152 | #define IRQ_TIMEOUT_VALUE_INVALID 0x02 /* an invalid application IRQ timeout value was selected */ | ||
153 | #define TRACE_CONFIG_INVALID 0x02 /* the passed line trace configuration is invalid */ | ||
154 | #define ADAPTER_OPERATING_FREQ_INVALID 0x03 /* an invalid adapter operating frequency was selected */ | ||
155 | #define TRC_DEAC_TMR_INVALID 0x03 /* the trace deactivation timer is invalid */ | ||
156 | #define S508_FT1_ADPTR_NOT_PRESENT 0x0C /* the S508/FT1 adapter is not present */ | ||
157 | #define INVALID_FT1_STATUS_SELECTION 0x0D /* the S508/FT1 status selection is invalid */ | ||
158 | #define FT1_OP_STATS_NOT_ENABLED 0x0D /* the FT1 operational statistics have not been enabled */ | ||
159 | #define FT1_OP_STATS_NOT_AVAILABLE 0x0E /* the FT1 operational statistics are not currently available */ | ||
160 | #define S508_FT1_MODE_SELECTION_BUSY 0x0E /* the S508/FT1 adapter is busy selecting the operational mode */ | ||
161 | |||
162 | /* return codes from command READ_GLOBAL_EXCEPTION_CONDITION */ | ||
163 | #define EXCEP_MODEM_STATUS_CHANGE 0x10 /* a modem status change occurred */ | ||
164 | #define EXCEP_TRC_DISABLED 0x11 /* the trace has been disabled */ | ||
165 | #define EXCEP_IRQ_TIMEOUT 0x12 /* IRQ timeout */ | ||
166 | |||
167 | /* return codes from CHDLC-level interface commands */ | ||
168 | #define NO_CHDLC_EXCEP_COND_TO_REPORT 0x21 /* there is no CHDLC exception condition to report */ | ||
169 | #define CHDLC_COMMS_DISABLED 0x21 /* communications are not currently enabled */ | ||
170 | #define CHDLC_COMMS_ENABLED 0x21 /* communications are currently enabled */ | ||
171 | #define DISABLE_CHDLC_COMMS_BEFORE_CFG 0x21 /* CHDLC communications must be disabled before setting the configuration */ | ||
172 | #define ENABLE_CHDLC_COMMS_BEFORE_CONN 0x21 /* communications must be enabled before using the CHDLC_CONNECT conmmand */ | ||
173 | #define CHDLC_CFG_BEFORE_COMMS_ENABLED 0x22 /* perform a SET_CHDLC_CONFIGURATION before enabling comms */ | ||
174 | #define LGTH_CHDLC_CFG_DATA_INVALID 0x22 /* the length of the passed CHDLC configuration data is invalid */ | ||
175 | #define LGTH_INT_TRIGGERS_DATA_INVALID 0x22 /* the length of the passed interrupt trigger data is invalid */ | ||
176 | #define INVALID_IRQ_SELECTED 0x23 /* in invalid IRQ was selected in the SET_CHDLC_INTERRUPT_TRIGGERS */ | ||
177 | #define INVALID_CHDLC_CFG_DATA 0x23 /* the passed CHDLC configuration data is invalid */ | ||
178 | #define IRQ_TMR_VALUE_INVALID 0x24 /* an invalid application IRQ timer value was selected */ | ||
179 | #define LARGER_PERCENT_TX_BFR_REQUIRED 0x24 /* a larger Tx buffer percentage is required */ | ||
180 | #define LARGER_PERCENT_RX_BFR_REQUIRED 0x25 /* a larger Rx buffer percentage is required */ | ||
181 | #define S514_BOTH_PORTS_SAME_CLK_MODE 0x26 /* S514 - both ports must have same clock mode */ | ||
182 | #define INVALID_CMND_HDLC_STREAM_MODE 0x4E /* the CHDLC interface command is invalid for HDLC streaming mode */ | ||
183 | #define INVALID_CHDLC_COMMAND 0x4F /* the defined CHDLC interface command is invalid */ | ||
184 | |||
185 | /* return codes from command READ_CHDLC_EXCEPTION_CONDITION */ | ||
186 | #define EXCEP_LINK_ACTIVE 0x30 /* the CHDLC link has become active */ | ||
187 | #define EXCEP_LINK_INACTIVE_MODEM 0x31 /* the CHDLC link has become inactive (modem status) */ | ||
188 | #define EXCEP_LINK_INACTIVE_KPALV 0x32 /* the CHDLC link has become inactive (keepalive status) */ | ||
189 | #define EXCEP_IP_ADDRESS_DISCOVERED 0x33 /* the IP address has been discovered */ | ||
190 | #define EXCEP_LOOPBACK_CONDITION 0x34 /* a loopback condition has occurred */ | ||
191 | |||
192 | |||
193 | /* return code from command CHDLC_SEND_WAIT and CHDLC_SEND_NO_WAIT */ | ||
194 | #define LINK_DISCONNECTED 0x21 | ||
195 | #define NO_TX_BFRS_AVAIL 0x24 | ||
196 | |||
197 | |||
198 | /* ---------------------------------------------------------------------------- | ||
199 | * Constants for the SET_GLOBAL_CONFIGURATION/READ_GLOBAL_CONFIGURATION commands | ||
200 | * --------------------------------------------------------------------------*/ | ||
201 | |||
202 | /* the global configuration structure */ | ||
203 | typedef struct { | ||
204 | unsigned short adapter_config_options PACKED; /* adapter config options */ | ||
205 | unsigned short app_IRQ_timeout PACKED; /* application IRQ timeout */ | ||
206 | unsigned long adapter_operating_frequency PACKED; /* adapter operating frequency */ | ||
207 | } GLOBAL_CONFIGURATION_STRUCT; | ||
208 | |||
209 | /* settings for the 'app_IRQ_timeout' */ | ||
210 | #define MAX_APP_IRQ_TIMEOUT_VALUE 5000 /* the maximum permitted IRQ timeout */ | ||
211 | |||
212 | |||
213 | |||
214 | /* ---------------------------------------------------------------------------- | ||
215 | * Constants for the READ_GLOBAL_STATISTICS command | ||
216 | * --------------------------------------------------------------------------*/ | ||
217 | |||
218 | /* the global statistics structure */ | ||
219 | typedef struct { | ||
220 | unsigned short app_IRQ_timeout_count PACKED; | ||
221 | } GLOBAL_STATS_STRUCT; | ||
222 | |||
223 | |||
224 | |||
225 | /* ---------------------------------------------------------------------------- | ||
226 | * Constants for the READ_COMMS_ERROR_STATS command | ||
227 | * --------------------------------------------------------------------------*/ | ||
228 | |||
229 | /* the communications error statistics structure */ | ||
230 | typedef struct { | ||
231 | unsigned short Rx_overrun_err_count PACKED; | ||
232 | unsigned short CRC_err_count PACKED; /* receiver CRC error count */ | ||
233 | unsigned short Rx_abort_count PACKED; /* abort frames recvd count */ | ||
234 | unsigned short Rx_dis_pri_bfrs_full_count PACKED;/* receiver disabled */ | ||
235 | unsigned short comms_err_stat_reserved_1 PACKED;/* reserved for later */ | ||
236 | unsigned short sec_Tx_abort_msd_Tx_int_count PACKED; /* secondary - abort frames transmitted count (missed Tx interrupt) */ | ||
237 | unsigned short missed_Tx_und_int_count PACKED; /* missed tx underrun interrupt count */ | ||
238 | unsigned short sec_Tx_abort_count PACKED; /*secondary-abort frames tx count */ | ||
239 | unsigned short DCD_state_change_count PACKED; /* DCD state change */ | ||
240 | unsigned short CTS_state_change_count PACKED; /* CTS state change */ | ||
241 | } COMMS_ERROR_STATS_STRUCT; | ||
242 | |||
243 | |||
244 | |||
245 | /* ---------------------------------------------------------------------------- | ||
246 | * Constants used for line tracing | ||
247 | * --------------------------------------------------------------------------*/ | ||
248 | |||
249 | /* the trace configuration structure (SET_TRACE_CONFIGURATION/READ_TRACE_CONFIGURATION commands) */ | ||
250 | typedef struct { | ||
251 | unsigned char trace_config PACKED; /* trace configuration */ | ||
252 | unsigned short trace_deactivation_timer PACKED; /* trace deactivation timer */ | ||
253 | unsigned long ptr_trace_stat_el_cfg_struct PACKED; /* a pointer to the line trace element configuration structure */ | ||
254 | } LINE_TRACE_CONFIG_STRUCT; | ||
255 | |||
256 | /* 'trace_config' bit settings */ | ||
257 | #define TRACE_INACTIVE 0x00 /* trace is inactive */ | ||
258 | #define TRACE_ACTIVE 0x01 /* trace is active */ | ||
259 | #define TRACE_DELAY_MODE 0x04 /* operate the trace in delay mode */ | ||
260 | #define TRACE_DATA_FRAMES 0x08 /* trace Data frames */ | ||
261 | #define TRACE_SLARP_FRAMES 0x10 /* trace SLARP frames */ | ||
262 | #define TRACE_CDP_FRAMES 0x20 /* trace CDP frames */ | ||
263 | |||
264 | /* the line trace status element configuration structure */ | ||
265 | typedef struct { | ||
266 | unsigned short number_trace_status_elements PACKED; /* number of line trace elements */ | ||
267 | unsigned long base_addr_trace_status_elements PACKED; /* base address of the trace element list */ | ||
268 | unsigned long next_trace_element_to_use PACKED; /* pointer to the next trace element to be used */ | ||
269 | unsigned long base_addr_trace_buffer PACKED; /* base address of the trace data buffer */ | ||
270 | unsigned long end_addr_trace_buffer PACKED; /* end address of the trace data buffer */ | ||
271 | } TRACE_STATUS_EL_CFG_STRUCT; | ||
272 | |||
273 | /* the line trace status element structure */ | ||
274 | typedef struct { | ||
275 | unsigned char opp_flag PACKED; /* opp flag */ | ||
276 | unsigned short trace_length PACKED; /* trace length */ | ||
277 | unsigned char trace_type PACKED; /* trace type */ | ||
278 | unsigned short trace_time_stamp PACKED; /* time stamp */ | ||
279 | unsigned short trace_reserved_1 PACKED; /* reserved for later use */ | ||
280 | unsigned long trace_reserved_2 PACKED; /* reserved for later use */ | ||
281 | unsigned long ptr_data_bfr PACKED; /* ptr to the trace data buffer */ | ||
282 | } TRACE_STATUS_ELEMENT_STRUCT; | ||
283 | |||
284 | /* "trace_type" bit settings */ | ||
285 | #define TRACE_INCOMING 0x00 | ||
286 | #define TRACE_OUTGOINGING 0x01 | ||
287 | #define TRACE_INCOMING_ABORTED 0x10 | ||
288 | #define TRACE_INCOMING_CRC_ERROR 0x20 | ||
289 | #define TRACE_INCOMING_OVERRUN_ERROR 0x40 | ||
290 | |||
291 | |||
292 | |||
293 | /* the line trace statistics structure */ | ||
294 | typedef struct { | ||
295 | unsigned long frames_traced_count PACKED; /* number of frames traced */ | ||
296 | unsigned long trc_frms_not_recorded_count PACKED; /* number of trace frames discarded */ | ||
297 | } LINE_TRACE_STATS_STRUCT; | ||
298 | |||
299 | |||
300 | /* ---------------------------------------------------------------------------- | ||
301 | * Constants for the FT1_MONITOR_STATUS_CTRL command | ||
302 | * --------------------------------------------------------------------------*/ | ||
303 | |||
304 | #define DISABLE_FT1_STATUS_STATISTICS 0x00 /* disable the FT1 status and statistics monitoring */ | ||
305 | #define ENABLE_READ_FT1_STATUS 0x01 /* read the FT1 operational status */ | ||
306 | #define ENABLE_READ_FT1_OP_STATS 0x02 /* read the FT1 operational statistics */ | ||
307 | #define FLUSH_FT1_OP_STATS 0x04 /* flush the FT1 operational statistics */ | ||
308 | |||
309 | |||
310 | |||
311 | |||
312 | /* ---------------------------------------------------------------------------- | ||
313 | * Constants for the SET_CHDLC_CONFIGURATION command | ||
314 | * --------------------------------------------------------------------------*/ | ||
315 | |||
316 | /* the CHDLC configuration structure */ | ||
317 | typedef struct { | ||
318 | unsigned long baud_rate PACKED; /* the baud rate */ | ||
319 | unsigned short line_config_options PACKED; /* line configuration options */ | ||
320 | unsigned short modem_config_options PACKED; /* modem configration options */ | ||
321 | unsigned short modem_status_timer PACKED; /* timer for monitoring modem status changes */ | ||
322 | unsigned short CHDLC_API_options PACKED; /* CHDLC API options */ | ||
323 | unsigned short CHDLC_protocol_options PACKED; /* CHDLC protocol options */ | ||
324 | unsigned short percent_data_buffer_for_Tx PACKED; /* percentage data buffering used for Tx */ | ||
325 | unsigned short CHDLC_statistics_options PACKED; /* CHDLC operational statistics options */ | ||
326 | unsigned short max_CHDLC_data_field_length PACKED; /* the maximum length of the CHDLC Data field */ | ||
327 | unsigned short transmit_keepalive_timer PACKED; /* the transmit keepalive timer */ | ||
328 | unsigned short receive_keepalive_timer PACKED; /* the receive keepalive timer */ | ||
329 | unsigned short keepalive_error_tolerance PACKED; /* the receive keepalive error tolerance */ | ||
330 | unsigned short SLARP_request_timer PACKED; /* the SLARP request timer */ | ||
331 | unsigned long IP_address PACKED; /* the IP address */ | ||
332 | unsigned long IP_netmask PACKED; /* the IP netmask */ | ||
333 | unsigned long ptr_shared_mem_info_struct PACKED; /* a pointer to the shared memory area information structure */ | ||
334 | unsigned long ptr_CHDLC_Tx_stat_el_cfg_struct PACKED; /* a pointer to the transmit status element configuration structure */ | ||
335 | unsigned long ptr_CHDLC_Rx_stat_el_cfg_struct PACKED; /* a pointer to the receive status element configuration structure */ | ||
336 | } CHDLC_CONFIGURATION_STRUCT; | ||
337 | |||
338 | /* settings for the 'line_config_options' */ | ||
339 | #define INTERFACE_LEVEL_V35 0x0000 /* V.35 interface level */ | ||
340 | #define INTERFACE_LEVEL_RS232 0x0001 /* RS-232 interface level */ | ||
341 | |||
342 | /* settings for the 'modem_config_options' */ | ||
343 | |||
344 | #define DONT_RAISE_DTR_RTS_ON_EN_COMMS 0x0001 | ||
345 | /* don't automatically raise DTR and RTS when performing an | ||
346 | ENABLE_CHDLC_COMMUNICATIONS command */ | ||
347 | |||
348 | #define DONT_REPORT_CHG_IN_MODEM_STAT 0x0002 | ||
349 | /* don't report changes in modem status to the application */ | ||
350 | |||
351 | |||
352 | /* bit settings for the 'CHDLC_protocol_options' byte */ | ||
353 | |||
354 | #define IGNORE_DCD_FOR_LINK_STAT 0x0001 | ||
355 | /* ignore DCD in determining the CHDLC link status */ | ||
356 | |||
357 | #define IGNORE_CTS_FOR_LINK_STAT 0x0002 | ||
358 | /* ignore CTS in determining the CHDLC link status */ | ||
359 | |||
360 | #define IGNORE_KPALV_FOR_LINK_STAT 0x0004 | ||
361 | /* ignore keepalive frames in determining the CHDLC link status */ | ||
362 | |||
363 | #define SINGLE_TX_BUFFER 0x4000 | ||
364 | /* configure a single transmit buffer */ | ||
365 | |||
366 | #define HDLC_STREAMING_MODE 0x8000 | ||
367 | |||
368 | /* settings for the 'CHDLC_statistics_options' */ | ||
369 | |||
370 | #define CHDLC_TX_DATA_BYTE_COUNT_STAT 0x0001 | ||
371 | /* record the number of Data bytes transmitted */ | ||
372 | |||
373 | #define CHDLC_RX_DATA_BYTE_COUNT_STAT 0x0002 | ||
374 | /* record the number of Data bytes received */ | ||
375 | |||
376 | #define CHDLC_TX_THROUGHPUT_STAT 0x0004 | ||
377 | /* compute the Data frame transmit throughput */ | ||
378 | |||
379 | #define CHDLC_RX_THROUGHPUT_STAT 0x0008 | ||
380 | /* compute the Data frame receive throughput */ | ||
381 | |||
382 | |||
383 | /* permitted minimum and maximum values for setting the CHDLC configuration */ | ||
384 | #define PRI_MAX_BAUD_RATE_S508 2666666 /* PRIMARY - maximum baud rate (S508) */ | ||
385 | #define SEC_MAX_BAUD_RATE_S508 258064 /* SECONDARY - maximum baud rate (S508) */ | ||
386 | #define PRI_MAX_BAUD_RATE_S514 2750000 /* PRIMARY - maximum baud rate (S508) */ | ||
387 | #define SEC_MAX_BAUD_RATE_S514 515625 /* SECONDARY - maximum baud rate (S508) */ | ||
388 | |||
389 | #define MIN_MODEM_TIMER 0 /* minimum modem status timer */ | ||
390 | #define MAX_MODEM_TIMER 5000 /* maximum modem status timer */ | ||
391 | |||
392 | #define SEC_MAX_NO_DATA_BYTES_IN_FRAME 2048 /* SECONDARY - max length of the CHDLC data field */ | ||
393 | |||
394 | #define MIN_Tx_KPALV_TIMER 0 /* minimum transmit keepalive timer */ | ||
395 | #define MAX_Tx_KPALV_TIMER 60000 /* maximum transmit keepalive timer */ | ||
396 | #define DEFAULT_Tx_KPALV_TIMER 10000 /* default transmit keepalive timer */ | ||
397 | |||
398 | #define MIN_Rx_KPALV_TIMER 10 /* minimum receive keepalive timer */ | ||
399 | #define MAX_Rx_KPALV_TIMER 60000 /* maximum receive keepalive timer */ | ||
400 | #define DEFAULT_Rx_KPALV_TIMER 10000 /* default receive keepalive timer */ | ||
401 | |||
402 | #define MIN_KPALV_ERR_TOL 1 /* min kpalv error tolerance count */ | ||
403 | #define MAX_KPALV_ERR_TOL 20 /* max kpalv error tolerance count */ | ||
404 | #define DEFAULT_KPALV_ERR_TOL 3 /* default value */ | ||
405 | |||
406 | #define MIN_SLARP_REQ_TIMER 0 /* min transmit SLARP Request timer */ | ||
407 | #define MAX_SLARP_REQ_TIMER 60000 /* max transmit SLARP Request timer */ | ||
408 | #define DEFAULT_SLARP_REQ_TIMER 0 /* default value -- no SLARP */ | ||
409 | |||
410 | |||
411 | |||
412 | /* ---------------------------------------------------------------------------- | ||
413 | * Constants for the READ_CHDLC_LINK_STATUS command | ||
414 | * --------------------------------------------------------------------------*/ | ||
415 | |||
416 | /* the CHDLC status structure */ | ||
417 | typedef struct { | ||
418 | unsigned char CHDLC_link_status PACKED; /* CHDLC link status */ | ||
419 | unsigned char no_Data_frms_for_app PACKED; /* number of Data frames available for the application */ | ||
420 | unsigned char receiver_status PACKED; /* enabled/disabled */ | ||
421 | unsigned char SLARP_state PACKED; /* internal SLARP state */ | ||
422 | } CHDLC_LINK_STATUS_STRUCT; | ||
423 | |||
424 | /* settings for the 'CHDLC_link_status' variable */ | ||
425 | #define CHDLC_LINK_INACTIVE 0x00 /* the CHDLC link is inactive */ | ||
426 | #define CHDLC_LINK_ACTIVE 0x01 /* the CHDLC link is active */ | ||
427 | |||
428 | |||
429 | |||
430 | /* ---------------------------------------------------------------------------- | ||
431 | * Constants for the READ_CHDLC_OPERATIONAL_STATS command | ||
432 | * --------------------------------------------------------------------------*/ | ||
433 | |||
434 | /* the CHDLC operational statistics structure */ | ||
435 | typedef struct { | ||
436 | |||
437 | /* Data frame transmission statistics */ | ||
438 | unsigned long Data_frames_Tx_count PACKED; /* # of frames transmitted */ | ||
439 | unsigned long Data_bytes_Tx_count PACKED; /* # of bytes transmitted */ | ||
440 | unsigned long Data_Tx_throughput PACKED; /* transmit throughput */ | ||
441 | unsigned long no_ms_for_Data_Tx_thruput_comp PACKED; /* millisecond time used for the Tx throughput computation */ | ||
442 | unsigned long Tx_Data_discard_lgth_err_count PACKED; /* number of Data frames discarded (length error) */ | ||
443 | unsigned long reserved_Data_frm_Tx_stat1 PACKED; /* reserved for later */ | ||
444 | unsigned long reserved_Data_frm_Tx_stat2 PACKED; /* reserved for later */ | ||
445 | unsigned long reserved_Data_frm_Tx_stat3 PACKED; /* reserved for later */ | ||
446 | |||
447 | /* Data frame reception statistics */ | ||
448 | unsigned long Data_frames_Rx_count PACKED; /* number of frames received */ | ||
449 | unsigned long Data_bytes_Rx_count PACKED; /* number of bytes received */ | ||
450 | unsigned long Data_Rx_throughput PACKED; /* receive throughput */ | ||
451 | unsigned long no_ms_for_Data_Rx_thruput_comp PACKED; /* millisecond time used for the Rx throughput computation */ | ||
452 | unsigned long Rx_Data_discard_short_count PACKED; /* received Data frames discarded (too short) */ | ||
453 | unsigned long Rx_Data_discard_long_count PACKED; /* received Data frames discarded (too long) */ | ||
454 | unsigned long Rx_Data_discard_inactive_count PACKED; /* received Data frames discarded (link inactive) */ | ||
455 | unsigned long reserved_Data_frm_Rx_stat1 PACKED; /* reserved for later */ | ||
456 | |||
457 | /* SLARP frame transmission/reception statistics */ | ||
458 | unsigned long CHDLC_SLARP_REQ_Tx_count PACKED; /* number of SLARP Request frames transmitted */ | ||
459 | unsigned long CHDLC_SLARP_REQ_Rx_count PACKED; /* number of SLARP Request frames received */ | ||
460 | unsigned long CHDLC_SLARP_REPLY_Tx_count PACKED; /* number of SLARP Reply frames transmitted */ | ||
461 | unsigned long CHDLC_SLARP_REPLY_Rx_count PACKED; /* number of SLARP Reply frames received */ | ||
462 | unsigned long CHDLC_SLARP_KPALV_Tx_count PACKED; /* number of SLARP keepalive frames transmitted */ | ||
463 | unsigned long CHDLC_SLARP_KPALV_Rx_count PACKED; /* number of SLARP keepalive frames received */ | ||
464 | unsigned long reserved_SLARP_stat1 PACKED; /* reserved for later */ | ||
465 | unsigned long reserved_SLARP_stat2 PACKED; /* reserved for later */ | ||
466 | |||
467 | /* CDP frame transmission/reception statistics */ | ||
468 | unsigned long CHDLC_CDP_Tx_count PACKED; /* number of CDP frames transmitted */ | ||
469 | unsigned long CHDLC_CDP_Rx_count PACKED; /* number of CDP frames received */ | ||
470 | unsigned long reserved_CDP_stat1 PACKED; /* reserved for later */ | ||
471 | unsigned long reserved_CDP_stat2 PACKED; /* reserved for later */ | ||
472 | unsigned long reserved_CDP_stat3 PACKED; /* reserved for later */ | ||
473 | unsigned long reserved_CDP_stat4 PACKED; /* reserved for later */ | ||
474 | unsigned long reserved_CDP_stat5 PACKED; /* reserved for later */ | ||
475 | unsigned long reserved_CDP_stat6 PACKED; /* reserved for later */ | ||
476 | |||
477 | /* Incoming frames with a format error statistics */ | ||
478 | unsigned short Rx_frm_incomp_CHDLC_hdr_count PACKED; /* frames received of with incomplete Cisco HDLC header */ | ||
479 | unsigned short Rx_frms_too_long_count PACKED; /* frames received of excessive length count */ | ||
480 | unsigned short Rx_invalid_CHDLC_addr_count PACKED; /* frames received with an invalid CHDLC address count */ | ||
481 | unsigned short Rx_invalid_CHDLC_ctrl_count PACKED; /* frames received with an invalid CHDLC control field count */ | ||
482 | unsigned short Rx_invalid_CHDLC_type_count PACKED; /* frames received of an invalid CHDLC frame type count */ | ||
483 | unsigned short Rx_SLARP_invalid_code_count PACKED; /* SLARP frame received with an invalid packet code */ | ||
484 | unsigned short Rx_SLARP_Reply_bad_IP_addr PACKED; /* SLARP Reply received - bad IP address */ | ||
485 | unsigned short Rx_SLARP_Reply_bad_netmask PACKED; /* SLARP Reply received - bad netmask */ | ||
486 | unsigned long reserved_frm_format_err1 PACKED; /* reserved for later */ | ||
487 | unsigned long reserved_frm_format_err2 PACKED; /* reserved for later */ | ||
488 | unsigned long reserved_frm_format_err3 PACKED; /* reserved for later */ | ||
489 | unsigned long reserved_frm_format_err4 PACKED; /* reserved for later */ | ||
490 | |||
491 | /* CHDLC timeout/retry statistics */ | ||
492 | unsigned short SLARP_Rx_keepalive_TO_count PACKED; /* timeout count for incoming SLARP frames */ | ||
493 | unsigned short SLARP_Request_TO_count PACKED; /* timeout count for SLARP Request frames */ | ||
494 | unsigned long To_retry_reserved_stat1 PACKED; /* reserved for later */ | ||
495 | unsigned long To_retry_reserved_stat2 PACKED; /* reserved for later */ | ||
496 | unsigned long To_retry_reserved_stat3 PACKED; /* reserved for later */ | ||
497 | |||
498 | /* CHDLC link active/inactive and loopback statistics */ | ||
499 | unsigned short link_active_count PACKED; /* number of times that the link went active */ | ||
500 | unsigned short link_inactive_modem_count PACKED; /* number of times that the link went inactive (modem failure) */ | ||
501 | unsigned short link_inactive_keepalive_count PACKED; /* number of times that the link went inactive (keepalive failure) */ | ||
502 | unsigned short link_looped_count PACKED; /* link looped count */ | ||
503 | unsigned long link_status_reserved_stat1 PACKED; /* reserved for later use */ | ||
504 | unsigned long link_status_reserved_stat2 PACKED; /* reserved for later use */ | ||
505 | |||
506 | /* miscellaneous statistics */ | ||
507 | unsigned long reserved_misc_stat1 PACKED; /* reserved for later */ | ||
508 | unsigned long reserved_misc_stat2 PACKED; /* reserved for later */ | ||
509 | unsigned long reserved_misc_stat3 PACKED; /* reserved for later */ | ||
510 | unsigned long reserved_misc_stat4 PACKED; /* reserved for later */ | ||
511 | |||
512 | } CHDLC_OPERATIONAL_STATS_STRUCT; | ||
513 | |||
514 | |||
515 | |||
516 | /* ---------------------------------------------------------------------------- | ||
517 | * Constants for using application interrupts | ||
518 | * --------------------------------------------------------------------------*/ | ||
519 | |||
520 | /* the structure used for the SET_CHDLC_INTERRUPT_TRIGGERS/READ_CHDLC_INTERRUPT_TRIGGERS command */ | ||
521 | typedef struct { | ||
522 | unsigned char CHDLC_interrupt_triggers PACKED; /* CHDLC interrupt trigger configuration */ | ||
523 | unsigned char IRQ PACKED; /* IRQ to be used */ | ||
524 | unsigned short interrupt_timer PACKED; /* interrupt timer */ | ||
525 | unsigned short misc_interrupt_bits PACKED; /* miscellaneous bits */ | ||
526 | } CHDLC_INT_TRIGGERS_STRUCT; | ||
527 | |||
528 | /* 'CHDLC_interrupt_triggers' bit settings */ | ||
529 | #define APP_INT_ON_RX_FRAME 0x01 /* interrupt on Data frame reception */ | ||
530 | #define APP_INT_ON_TX_FRAME 0x02 /* interrupt when an Data frame may be transmitted */ | ||
531 | #define APP_INT_ON_COMMAND_COMPLETE 0x04 /* interrupt when an interface command is complete */ | ||
532 | #define APP_INT_ON_TIMER 0x08 /* interrupt on a defined millisecond timeout */ | ||
533 | #define APP_INT_ON_GLOBAL_EXCEP_COND 0x10 /* interrupt on a global exception condition */ | ||
534 | #define APP_INT_ON_CHDLC_EXCEP_COND 0x20 /* interrupt on an CHDLC exception condition */ | ||
535 | #define APP_INT_ON_TRACE_DATA_AVAIL 0x80 /* interrupt when trace data is available */ | ||
536 | |||
537 | /* interrupt types indicated at 'interrupt_type' byte of the INTERRUPT_INFORMATION_STRUCT */ | ||
538 | #define NO_APP_INTS_PEND 0x00 /* no interrups are pending */ | ||
539 | #define RX_APP_INT_PEND 0x01 /* a receive interrupt is pending */ | ||
540 | #define TX_APP_INT_PEND 0x02 /* a transmit interrupt is pending */ | ||
541 | #define COMMAND_COMPLETE_APP_INT_PEND 0x04 /* a 'command complete' interrupt is pending */ | ||
542 | #define TIMER_APP_INT_PEND 0x08 /* a timer interrupt is pending */ | ||
543 | #define GLOBAL_EXCEP_COND_APP_INT_PEND 0x10 /* a global exception condition interrupt is pending */ | ||
544 | #define CHDLC_EXCEP_COND_APP_INT_PEND 0x20 /* an CHDLC exception condition interrupt is pending */ | ||
545 | #define TRACE_DATA_AVAIL_APP_INT_PEND 0x80 /* a trace data available interrupt is pending */ | ||
546 | |||
547 | |||
548 | /* modem status changes */ | ||
549 | #define DCD_HIGH 0x08 | ||
550 | #define CTS_HIGH 0x20 | ||
551 | |||
552 | |||
553 | /* ---------------------------------------------------------------------------- | ||
554 | * Constants for Data frame transmission | ||
555 | * --------------------------------------------------------------------------*/ | ||
556 | |||
557 | /* the Data frame transmit status element configuration structure */ | ||
558 | typedef struct { | ||
559 | unsigned short number_Tx_status_elements PACKED; /* number of transmit status elements */ | ||
560 | unsigned long base_addr_Tx_status_elements PACKED; /* base address of the transmit element list */ | ||
561 | unsigned long next_Tx_status_element_to_use PACKED; /* pointer to the next transmit element to be used */ | ||
562 | } CHDLC_TX_STATUS_EL_CFG_STRUCT; | ||
563 | |||
564 | /* the Data frame transmit status element structure */ | ||
565 | typedef struct { | ||
566 | unsigned char opp_flag PACKED; /* opp flag */ | ||
567 | unsigned short frame_length PACKED; /* length of the frame to be transmitted */ | ||
568 | unsigned char reserved_1 PACKED; /* reserved for internal use */ | ||
569 | unsigned long reserved_2 PACKED; /* reserved for internal use */ | ||
570 | unsigned long reserved_3 PACKED; /* reserved for internal use */ | ||
571 | unsigned long ptr_data_bfr PACKED; /* pointer to the data area */ | ||
572 | } CHDLC_DATA_TX_STATUS_EL_STRUCT; | ||
573 | |||
574 | |||
575 | |||
576 | /* ---------------------------------------------------------------------------- | ||
577 | * Constants for Data frame reception | ||
578 | * --------------------------------------------------------------------------*/ | ||
579 | |||
580 | /* the Data frame receive status element configuration structure */ | ||
581 | typedef struct { | ||
582 | unsigned short number_Rx_status_elements PACKED; /* number of receive status elements */ | ||
583 | unsigned long base_addr_Rx_status_elements PACKED; /* base address of the receive element list */ | ||
584 | unsigned long next_Rx_status_element_to_use PACKED; /* pointer to the next receive element to be used */ | ||
585 | unsigned long base_addr_Rx_buffer PACKED; /* base address of the receive data buffer */ | ||
586 | unsigned long end_addr_Rx_buffer PACKED; /* end address of the receive data buffer */ | ||
587 | } CHDLC_RX_STATUS_EL_CFG_STRUCT; | ||
588 | |||
589 | /* the Data frame receive status element structure */ | ||
590 | typedef struct { | ||
591 | unsigned char opp_flag PACKED; /* opp flag */ | ||
592 | unsigned short frame_length PACKED; /* length of the received frame */ | ||
593 | unsigned char error_flag PACKED; /* frame errors (HDLC_STREAMING_MODE)*/ | ||
594 | unsigned short time_stamp PACKED; /* receive time stamp (HDLC_STREAMING_MODE) */ | ||
595 | unsigned long reserved_1 PACKED; /* reserved for internal use */ | ||
596 | unsigned short reserved_2 PACKED; /* reserved for internal use */ | ||
597 | unsigned long ptr_data_bfr PACKED; /* pointer to the data area */ | ||
598 | } CHDLC_DATA_RX_STATUS_EL_STRUCT; | ||
599 | |||
600 | |||
601 | |||
602 | /* ---------------------------------------------------------------------------- | ||
603 | * Constants defining the shared memory information area | ||
604 | * --------------------------------------------------------------------------*/ | ||
605 | |||
606 | /* the global information structure */ | ||
607 | typedef struct { | ||
608 | unsigned char global_status PACKED; /* global status */ | ||
609 | unsigned char modem_status PACKED; /* current modem status */ | ||
610 | unsigned char global_excep_conditions PACKED; /* global exception conditions */ | ||
611 | unsigned char glob_info_reserved[5] PACKED; /* reserved */ | ||
612 | unsigned char codename[4] PACKED; /* Firmware name */ | ||
613 | unsigned char codeversion[4] PACKED; /* Firmware version */ | ||
614 | } GLOBAL_INFORMATION_STRUCT; | ||
615 | |||
616 | /* the CHDLC information structure */ | ||
617 | typedef struct { | ||
618 | unsigned char CHDLC_status PACKED; /* CHDLC status */ | ||
619 | unsigned char CHDLC_excep_conditions PACKED; /* CHDLC exception conditions */ | ||
620 | unsigned char CHDLC_info_reserved[14] PACKED; /* reserved */ | ||
621 | } CHDLC_INFORMATION_STRUCT; | ||
622 | |||
623 | /* the interrupt information structure */ | ||
624 | typedef struct { | ||
625 | unsigned char interrupt_type PACKED; /* type of interrupt triggered */ | ||
626 | unsigned char interrupt_permission PACKED; /* interrupt permission mask */ | ||
627 | unsigned char int_info_reserved[14] PACKED; /* reserved */ | ||
628 | } INTERRUPT_INFORMATION_STRUCT; | ||
629 | |||
630 | /* the S508/FT1 information structure */ | ||
631 | typedef struct { | ||
632 | unsigned char parallel_port_A_input PACKED; /* input - parallel port A */ | ||
633 | unsigned char parallel_port_B_input PACKED; /* input - parallel port B */ | ||
634 | unsigned char FT1_info_reserved[14] PACKED; /* reserved */ | ||
635 | } FT1_INFORMATION_STRUCT; | ||
636 | |||
637 | /* the shared memory area information structure */ | ||
638 | typedef struct { | ||
639 | GLOBAL_INFORMATION_STRUCT global_info_struct PACKED; /* the global information structure */ | ||
640 | CHDLC_INFORMATION_STRUCT CHDLC_info_struct PACKED; /* the CHDLC information structure */ | ||
641 | INTERRUPT_INFORMATION_STRUCT interrupt_info_struct PACKED; /* the interrupt information structure */ | ||
642 | FT1_INFORMATION_STRUCT FT1_info_struct PACKED; /* the S508/FT1 information structure */ | ||
643 | } SHARED_MEMORY_INFO_STRUCT; | ||
644 | |||
645 | /* ---------------------------------------------------------------------------- | ||
646 | * UDP Management constants and structures | ||
647 | * --------------------------------------------------------------------------*/ | ||
648 | |||
649 | /* The embedded control block for UDP mgmt | ||
650 | This is essentially a mailbox structure, without the large data field */ | ||
651 | |||
652 | typedef struct { | ||
653 | unsigned char opp_flag PACKED; /* the opp flag */ | ||
654 | unsigned char command PACKED; /* the user command */ | ||
655 | unsigned short buffer_length PACKED; /* the data length */ | ||
656 | unsigned char return_code PACKED; /* the return code */ | ||
657 | unsigned char MB_reserved[NUMBER_MB_RESERVED_BYTES] PACKED; /* reserved for later */ | ||
658 | } cblock_t; | ||
659 | |||
660 | |||
661 | /* UDP management packet layout (data area of ip packet) */ | ||
662 | /* | ||
663 | typedef struct { | ||
664 | unsigned char signature[8] PACKED; | ||
665 | unsigned char request_reply PACKED; | ||
666 | unsigned char id PACKED; | ||
667 | unsigned char reserved[6] PACKED; | ||
668 | cblock_t cblock PACKED; | ||
669 | unsigned char num_frames PACKED; | ||
670 | unsigned char ismoredata PACKED; | ||
671 | unsigned char data[SIZEOF_MB_DATA_BFR] PACKED; | ||
672 | } udp_management_packet_t; | ||
673 | |||
674 | */ | ||
675 | |||
676 | typedef struct { | ||
677 | unsigned char num_frames PACKED; | ||
678 | unsigned char ismoredata PACKED; | ||
679 | } trace_info_t; | ||
680 | |||
681 | typedef struct { | ||
682 | ip_pkt_t ip_pkt PACKED; | ||
683 | udp_pkt_t udp_pkt PACKED; | ||
684 | wp_mgmt_t wp_mgmt PACKED; | ||
685 | cblock_t cblock PACKED; | ||
686 | trace_info_t trace_info PACKED; | ||
687 | unsigned char data[SIZEOF_MB_DATA_BFR] PACKED; | ||
688 | } chdlc_udp_pkt_t; | ||
689 | |||
690 | typedef struct ft1_exec_cmd{ | ||
691 | unsigned char command PACKED; /* the user command */ | ||
692 | unsigned short buffer_length PACKED; /* the data length */ | ||
693 | unsigned char return_code PACKED; /* the return code */ | ||
694 | unsigned char MB_reserved[NUMBER_MB_RESERVED_BYTES] PACKED; | ||
695 | } ft1_exec_cmd_t; | ||
696 | |||
697 | typedef struct { | ||
698 | unsigned char opp_flag PACKED; | ||
699 | ft1_exec_cmd_t cmd PACKED; | ||
700 | unsigned char data[SIZEOF_MB_DATA_BFR] PACKED; | ||
701 | } ft1_exec_t; | ||
702 | |||
703 | #define UDPMGMT_SIGNATURE "CTPIPEAB" | ||
704 | |||
705 | |||
706 | /* UDP/IP packet (for UDP management) layout */ | ||
707 | /* | ||
708 | typedef struct { | ||
709 | unsigned char reserved[2] PACKED; | ||
710 | unsigned short ip_length PACKED; | ||
711 | unsigned char reserved2[4] PACKED; | ||
712 | unsigned char ip_ttl PACKED; | ||
713 | unsigned char ip_protocol PACKED; | ||
714 | unsigned short ip_checksum PACKED; | ||
715 | unsigned long ip_src_address PACKED; | ||
716 | unsigned long ip_dst_address PACKED; | ||
717 | unsigned short udp_src_port PACKED; | ||
718 | unsigned short udp_dst_port PACKED; | ||
719 | unsigned short udp_length PACKED; | ||
720 | unsigned short udp_checksum PACKED; | ||
721 | udp_management_packet_t um_packet PACKED; | ||
722 | } ip_packet_t; | ||
723 | */ | ||
724 | |||
725 | /* valid ip_protocol for UDP management */ | ||
726 | #define UDPMGMT_UDP_PROTOCOL 0x11 | ||
727 | |||
728 | |||
729 | typedef struct { | ||
730 | unsigned char status PACKED; | ||
731 | unsigned char data_avail PACKED; | ||
732 | unsigned short real_length PACKED; | ||
733 | unsigned short time_stamp PACKED; | ||
734 | unsigned char data[1] PACKED; | ||
735 | } trace_pkt_t; | ||
736 | |||
737 | typedef struct { | ||
738 | unsigned char error_flag PACKED; | ||
739 | unsigned short time_stamp PACKED; | ||
740 | unsigned char reserved[13] PACKED; | ||
741 | } api_rx_hdr_t; | ||
742 | |||
743 | typedef struct { | ||
744 | api_rx_hdr_t api_rx_hdr PACKED; | ||
745 | void * data PACKED; | ||
746 | } api_rx_element_t; | ||
747 | |||
748 | typedef struct { | ||
749 | unsigned char attr PACKED; | ||
750 | unsigned char reserved[15] PACKED; | ||
751 | } api_tx_hdr_t; | ||
752 | |||
753 | typedef struct { | ||
754 | api_tx_hdr_t api_tx_hdr PACKED; | ||
755 | void * data PACKED; | ||
756 | } api_tx_element_t; | ||
757 | |||
758 | /* ---------------------------------------------------------------------------- | ||
759 | * Constants for the SET_FT1_CONFIGURATION/READ_FT1_CONFIGURATION command | ||
760 | * --------------------------------------------------------------------------*/ | ||
761 | |||
762 | /* the FT1 configuration structure */ | ||
763 | typedef struct { | ||
764 | unsigned short framing_mode; | ||
765 | unsigned short encoding_mode; | ||
766 | unsigned short line_build_out; | ||
767 | unsigned short channel_base; | ||
768 | unsigned short baud_rate_kbps; /* the baud rate (in kbps) */ | ||
769 | unsigned short clock_mode; | ||
770 | } ft1_config_t; | ||
771 | |||
772 | /* settings for the 'framing_mode' */ | ||
773 | #define ESF_FRAMING 0x00 /* ESF framing */ | ||
774 | #define D4_FRAMING 0x01 /* D4 framing */ | ||
775 | |||
776 | /* settings for the 'encoding_mode' */ | ||
777 | #define B8ZS_ENCODING 0x00 /* B8ZS encoding */ | ||
778 | #define AMI_ENCODING 0x01 /* AMI encoding */ | ||
779 | |||
780 | /* settings for the 'line_build_out' */ | ||
781 | #define LN_BLD_CSU_0dB_DSX1_0_to_133 0x00 /* set build out to CSU (0db) or DSX-1 (0-133ft) */ | ||
782 | #define LN_BLD_DSX1_133_to_266 0x01 /* set build out DSX-1 (133-266ft) */ | ||
783 | #define LN_BLD_DSX1_266_to_399 0x02 /* set build out DSX-1 (266-399ft) */ | ||
784 | #define LN_BLD_DSX1_399_to_533 0x03 /* set build out DSX-1 (399-533ft) */ | ||
785 | #define LN_BLD_DSX1_533_to_655 0x04 /* set build out DSX-1 (533-655ft) */ | ||
786 | #define LN_BLD_CSU_NEG_7dB 0x05 /* set build out to CSU (-7.5db) */ | ||
787 | #define LN_BLD_CSU_NEG_15dB 0x06 /* set build out to CSU (-15db) */ | ||
788 | #define LN_BLD_CSU_NEG_22dB 0x07 /* set build out to CSU (-22.5db) */ | ||
789 | |||
790 | /* settings for the 'channel_base' */ | ||
791 | #define MIN_CHANNEL_BASE_VALUE 1 /* the minimum permitted channel base value */ | ||
792 | #define MAX_CHANNEL_BASE_VALUE 24 /* the maximum permitted channel base value */ | ||
793 | |||
794 | /* settings for the 'baud_rate_kbps' */ | ||
795 | #define MIN_BAUD_RATE_KBPS 0 /* the minimum permitted baud rate (kbps) */ | ||
796 | #define MAX_BAUD_RATE_KBPS 1536 /* the maximum permitted baud rate (kbps) */ | ||
797 | #define BAUD_RATE_FT1_AUTO_CONFIG 0xFFFF /* the baud rate used to trigger an automatic FT1 configuration */ | ||
798 | |||
799 | /* settings for the 'clock_mode' */ | ||
800 | #define CLOCK_MODE_NORMAL 0x00 /* clock mode set to normal (slave) */ | ||
801 | #define CLOCK_MODE_MASTER 0x01 /* clock mode set to master */ | ||
802 | |||
803 | |||
804 | #define BAUD_RATE_FT1_AUTO_CONFIG 0xFFFF | ||
805 | #define AUTO_FT1_CONFIG_NOT_COMPLETE 0x08 | ||
806 | #define AUTO_FT1_CFG_FAIL_OP_MODE 0x0C | ||
807 | #define AUTO_FT1_CFG_FAIL_INVALID_LINE 0x0D | ||
808 | |||
809 | |||
810 | #ifdef _MSC_ | ||
811 | # pragma pack() | ||
812 | #endif | ||
813 | #endif /* _SDLA_CHDLC_H */ | ||
diff --git a/include/linux/sdla_ppp.h b/include/linux/sdla_ppp.h deleted file mode 100644 index 6f3923179c29..000000000000 --- a/include/linux/sdla_ppp.h +++ /dev/null | |||
@@ -1,575 +0,0 @@ | |||
1 | /***************************************************************************** | ||
2 | * sdla_ppp.h Sangoma PPP firmware API definitions. | ||
3 | * | ||
4 | * Author: Nenad Corbic <ncorbic@sangoma.com> | ||
5 | * | ||
6 | * Copyright: (c) 1995-1997 Sangoma Technologies Inc. | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License | ||
10 | * as published by the Free Software Foundation; either version | ||
11 | * 2 of the License, or (at your option) any later version. | ||
12 | * ============================================================================ | ||
13 | * Feb 24, 2000 Nenad Corbic v2.1.2 | ||
14 | * Jan 06, 1997 Gene Kozin v2.0 | ||
15 | * Apr 11, 1996 Gene Kozin Initial version. | ||
16 | *****************************************************************************/ | ||
17 | #ifndef _SDLA_PPP_H | ||
18 | #define _SDLA_PPP_H | ||
19 | |||
20 | /*---------------------------------------------------------------------------- | ||
21 | * Notes: | ||
22 | * ------ | ||
23 | * 1. All structures defined in this file are byte-alined. | ||
24 | * | ||
25 | * Compiler Platform | ||
26 | * -------- -------- | ||
27 | * GNU C Linux | ||
28 | */ | ||
29 | |||
30 | #ifndef PACKED | ||
31 | # define PACKED __attribute__((packed)) | ||
32 | #endif /* PACKED */ | ||
33 | |||
34 | /* Adapter memory layout and important constants */ | ||
35 | #define PPP508_MB_VECT 0xE000 /* mailbox window vector */ | ||
36 | #define PPP508_MB_OFFS 0 /* mailbox offset */ | ||
37 | #define PPP508_FLG_OFFS 0x1000 /* status flags offset */ | ||
38 | #define PPP508_BUF_OFFS 0x1100 /* buffer info block offset */ | ||
39 | #define PPP514_MB_OFFS 0xE000 /* mailbox offset */ | ||
40 | #define PPP514_FLG_OFFS 0xF000 /* status flags offset */ | ||
41 | #define PPP514_BUF_OFFS 0xF100 /* buffer info block offset */ | ||
42 | |||
43 | #define PPP_MAX_DATA 1008 /* command block data buffer length */ | ||
44 | |||
45 | /****** Data Structures *****************************************************/ | ||
46 | |||
47 | /*---------------------------------------------------------------------------- | ||
48 | * PPP Command Block. | ||
49 | */ | ||
50 | typedef struct ppp_cmd{ | ||
51 | unsigned char command PACKED; /* command code */ | ||
52 | unsigned short length PACKED; /* length of data buffer */ | ||
53 | unsigned char result PACKED; /* return code */ | ||
54 | unsigned char rsrv[11] PACKED; /* reserved for future use */ | ||
55 | } ppp_cmd_t; | ||
56 | |||
57 | typedef struct cblock{ | ||
58 | unsigned char opp_flag PACKED; | ||
59 | unsigned char command PACKED; /* command code */ | ||
60 | unsigned short length PACKED; /* length of data buffer */ | ||
61 | unsigned char result PACKED; /* return code */ | ||
62 | unsigned char rsrv[11] PACKED; /* reserved for future use */ | ||
63 | } cblock_t; | ||
64 | |||
65 | typedef struct ppp_udp_pkt{ | ||
66 | ip_pkt_t ip_pkt PACKED; | ||
67 | udp_pkt_t udp_pkt PACKED; | ||
68 | wp_mgmt_t wp_mgmt PACKED; | ||
69 | cblock_t cblock PACKED; | ||
70 | unsigned char data[MAX_LGTH_UDP_MGNT_PKT] PACKED; | ||
71 | } ppp_udp_pkt_t; | ||
72 | |||
73 | typedef struct { | ||
74 | unsigned char status PACKED; | ||
75 | unsigned char data_avail PACKED; | ||
76 | unsigned short real_length PACKED; | ||
77 | unsigned short time_stamp PACKED; | ||
78 | unsigned char data[1] PACKED; | ||
79 | } trace_pkt_t; | ||
80 | |||
81 | |||
82 | typedef struct { | ||
83 | unsigned char opp_flag PACKED; | ||
84 | unsigned char trace_type PACKED; | ||
85 | unsigned short trace_length PACKED; | ||
86 | unsigned short trace_data_ptr PACKED; | ||
87 | unsigned short trace_time_stamp PACKED; | ||
88 | } trace_element_t; | ||
89 | |||
90 | /* 'command' field defines */ | ||
91 | #define PPP_READ_CODE_VERSION 0x10 /* configuration commands */ | ||
92 | #define PPP_SET_CONFIG 0x05 | ||
93 | #define PPP_READ_CONFIG 0x06 | ||
94 | #define PPP_SET_INTR_FLAGS 0x20 | ||
95 | #define PPP_READ_INTR_FLAGS 0x21 | ||
96 | #define PPP_SET_INBOUND_AUTH 0x30 | ||
97 | #define PPP_SET_OUTBOUND_AUTH 0x31 | ||
98 | #define PPP_GET_CONNECTION_INFO 0x32 | ||
99 | |||
100 | #define PPP_COMM_ENABLE 0x03 /* operational commands */ | ||
101 | #define PPP_COMM_DISABLE 0x04 | ||
102 | #define PPP_SEND_SIGN_FRAME 0x23 | ||
103 | #define PPP_READ_SIGN_RESPONSE 0x24 | ||
104 | #define PPP_DATALINE_MONITOR 0x33 | ||
105 | |||
106 | #define PPP_READ_STATISTICS 0x07 /* statistics commands */ | ||
107 | #define PPP_FLUSH_STATISTICS 0x08 | ||
108 | #define PPP_READ_ERROR_STATS 0x09 | ||
109 | #define PPP_FLUSH_ERROR_STATS 0x0A | ||
110 | #define PPP_READ_PACKET_STATS 0x12 | ||
111 | #define PPP_FLUSH_PACKET_STATS 0x13 | ||
112 | #define PPP_READ_LCP_STATS 0x14 | ||
113 | #define PPP_FLUSH_LCP_STATS 0x15 | ||
114 | #define PPP_READ_LPBK_STATS 0x16 | ||
115 | #define PPP_FLUSH_LPBK_STATS 0x17 | ||
116 | #define PPP_READ_IPCP_STATS 0x18 | ||
117 | #define PPP_FLUSH_IPCP_STATS 0x19 | ||
118 | #define PPP_READ_IPXCP_STATS 0x1A | ||
119 | #define PPP_FLUSH_IPXCP_STATS 0x1B | ||
120 | #define PPP_READ_PAP_STATS 0x1C | ||
121 | #define PPP_FLUSH_PAP_STATS 0x1D | ||
122 | #define PPP_READ_CHAP_STATS 0x1E | ||
123 | #define PPP_FLUSH_CHAP_STATS 0x1F | ||
124 | |||
125 | /* 'result' field defines */ | ||
126 | #define PPPRES_OK 0x00 /* command executed successfully */ | ||
127 | #define PPPRES_INVALID_STATE 0x09 /* invalid command in this context */ | ||
128 | |||
129 | /*---------------------------------------------------------------------------- | ||
130 | * PPP Mailbox. | ||
131 | * This structure is located at offset PPP???_MB_OFFS into PPP???_MB_VECT | ||
132 | */ | ||
133 | typedef struct ppp_mbox | ||
134 | { | ||
135 | unsigned char flag PACKED; /* 00h: command execution flag */ | ||
136 | ppp_cmd_t cmd PACKED; /* 01h: command block */ | ||
137 | unsigned char data[1] PACKED; /* 10h: variable length data buffer */ | ||
138 | } ppp_mbox_t; | ||
139 | |||
140 | /*---------------------------------------------------------------------------- | ||
141 | * PPP Status Flags. | ||
142 | * This structure is located at offset PPP???_FLG_OFFS into | ||
143 | * PPP???_MB_VECT. | ||
144 | */ | ||
145 | typedef struct ppp_flags | ||
146 | { | ||
147 | unsigned char iflag PACKED; /* 00: interrupt flag */ | ||
148 | unsigned char imask PACKED; /* 01: interrupt mask */ | ||
149 | unsigned char resrv PACKED; | ||
150 | unsigned char mstatus PACKED; /* 03: modem status */ | ||
151 | unsigned char lcp_state PACKED; /* 04: LCP state */ | ||
152 | unsigned char ppp_phase PACKED; /* 05: PPP phase */ | ||
153 | unsigned char ip_state PACKED; /* 06: IPCP state */ | ||
154 | unsigned char ipx_state PACKED; /* 07: IPXCP state */ | ||
155 | unsigned char pap_state PACKED; /* 08: PAP state */ | ||
156 | unsigned char chap_state PACKED; /* 09: CHAP state */ | ||
157 | unsigned short disc_cause PACKED; /* 0A: disconnection cause */ | ||
158 | } ppp_flags_t; | ||
159 | |||
160 | /* 'iflag' defines */ | ||
161 | #define PPP_INTR_RXRDY 0x01 /* Rx ready */ | ||
162 | #define PPP_INTR_TXRDY 0x02 /* Tx ready */ | ||
163 | #define PPP_INTR_MODEM 0x04 /* modem status change (DCD, CTS) */ | ||
164 | #define PPP_INTR_CMD 0x08 /* interface command completed */ | ||
165 | #define PPP_INTR_DISC 0x10 /* data link disconnected */ | ||
166 | #define PPP_INTR_OPEN 0x20 /* data link open */ | ||
167 | #define PPP_INTR_DROP_DTR 0x40 /* DTR drop timeout expired */ | ||
168 | #define PPP_INTR_TIMER 0x80 /* timer interrupt */ | ||
169 | |||
170 | |||
171 | /* 'mstatus' defines */ | ||
172 | #define PPP_MDM_DCD 0x08 /* mdm_status: DCD */ | ||
173 | #define PPP_MDM_CTS 0x20 /* mdm_status: CTS */ | ||
174 | |||
175 | /* 'disc_cause' defines */ | ||
176 | #define PPP_LOCAL_TERMINATION 0x0001 /* Local Request by PPP termination phase */ | ||
177 | #define PPP_DCD_CTS_DROP 0x0002 /* DCD and/or CTS dropped. Link down */ | ||
178 | #define PPP_REMOTE_TERMINATION 0x0800 /* Remote Request by PPP termination phase */ | ||
179 | |||
180 | /* 'misc_config_bits' defines */ | ||
181 | #define DONT_RE_TX_ABORTED_I_FRAMES 0x01 | ||
182 | #define TX_FRM_BYTE_COUNT_STATS 0x02 | ||
183 | #define RX_FRM_BYTE_COUNT_STATS 0x04 | ||
184 | #define TIME_STAMP_IN_RX_FRAMES 0x08 | ||
185 | #define NON_STD_ADPTR_FREQ 0x10 | ||
186 | #define INTERFACE_LEVEL_RS232 0x20 | ||
187 | #define AUTO_LINK_RECOVERY 0x100 | ||
188 | #define DONT_TERMINATE_LNK_MAX_CONFIG 0x200 | ||
189 | |||
190 | /* 'authentication options' defines */ | ||
191 | #define NO_AUTHENTICATION 0x00 | ||
192 | #define INBOUND_AUTH 0x80 | ||
193 | #define PAP_AUTH 0x01 | ||
194 | #define CHAP_AUTH 0x02 | ||
195 | |||
196 | /* 'ip options' defines */ | ||
197 | #define L_AND_R_IP_NO_ASSIG 0x00 | ||
198 | #define L_IP_LOCAL_ASSIG 0x01 | ||
199 | #define L_IP_REMOTE_ASSIG 0x02 | ||
200 | #define R_IP_LOCAL_ASSIG 0x04 | ||
201 | #define R_IP_REMOTE_ASSIG 0x08 | ||
202 | #define ENABLE_IP 0x80 | ||
203 | |||
204 | /* 'ipx options' defines */ | ||
205 | #define ROUTING_PROT_DEFAULT 0x20 | ||
206 | #define ENABLE_IPX 0x80 | ||
207 | #define DISABLE_IPX 0x00 | ||
208 | |||
209 | /*---------------------------------------------------------------------------- | ||
210 | * PPP Buffer Info. | ||
211 | * This structure is located at offset PPP508_BUF_OFFS into | ||
212 | * PPP508_MB_VECT. | ||
213 | */ | ||
214 | typedef struct ppp508_buf_info | ||
215 | { | ||
216 | unsigned short txb_num PACKED; /* 00: number of transmit buffers */ | ||
217 | unsigned long txb_ptr PACKED; /* 02: pointer to the buffer ctl. */ | ||
218 | unsigned long txb_nxt PACKED; | ||
219 | unsigned char rsrv1[22] PACKED; | ||
220 | unsigned short rxb_num PACKED; /* 20: number of receive buffers */ | ||
221 | unsigned long rxb_ptr PACKED; /* 22: pointer to the buffer ctl. */ | ||
222 | unsigned long rxb1_ptr PACKED; /* 26: pointer to the first buf.ctl. */ | ||
223 | unsigned long rxb_base PACKED; /* 2A: pointer to the buffer base */ | ||
224 | unsigned char rsrv2[2] PACKED; | ||
225 | unsigned long rxb_end PACKED; /* 30: pointer to the buffer end */ | ||
226 | } ppp508_buf_info_t; | ||
227 | |||
228 | /*---------------------------------------------------------------------------- | ||
229 | * Transmit/Receive Buffer Control Block. | ||
230 | */ | ||
231 | typedef struct ppp_buf_ctl | ||
232 | { | ||
233 | unsigned char flag PACKED; /* 00: 'buffer ready' flag */ | ||
234 | unsigned short length PACKED; /* 01: length of data */ | ||
235 | unsigned char reserved1[1] PACKED; /* 03: */ | ||
236 | unsigned char proto PACKED; /* 04: protocol */ | ||
237 | unsigned short timestamp PACKED; /* 05: time stamp (Rx only) */ | ||
238 | unsigned char reserved2[5] PACKED; /* 07: */ | ||
239 | union | ||
240 | { | ||
241 | unsigned short o_p[2]; /* 1C: buffer offset & page (S502) */ | ||
242 | unsigned long ptr; /* 1C: buffer pointer (S508) */ | ||
243 | } buf PACKED; | ||
244 | } ppp_buf_ctl_t; | ||
245 | |||
246 | /*---------------------------------------------------------------------------- | ||
247 | * S508 Adapter Configuration Block (passed to the PPP_SET_CONFIG command). | ||
248 | */ | ||
249 | typedef struct ppp508_conf | ||
250 | { | ||
251 | unsigned long line_speed PACKED; /* 00: baud rate, bps */ | ||
252 | unsigned short txbuf_percent PACKED; /* 04: % of Tx buffer */ | ||
253 | unsigned short conf_flags PACKED; /* 06: configuration bits */ | ||
254 | unsigned short mtu_local PACKED; /* 08: local MTU */ | ||
255 | unsigned short mtu_remote PACKED; /* 0A: remote MTU */ | ||
256 | unsigned short restart_tmr PACKED; /* 0C: restart timer */ | ||
257 | unsigned short auth_rsrt_tmr PACKED; /* 0E: authentication timer */ | ||
258 | unsigned short auth_wait_tmr PACKED; /* 10: authentication timer */ | ||
259 | unsigned short mdm_fail_tmr PACKED; /* 12: modem failure timer */ | ||
260 | unsigned short dtr_drop_tmr PACKED; /* 14: DTR drop timer */ | ||
261 | unsigned short connect_tmout PACKED; /* 16: connection timeout */ | ||
262 | unsigned short conf_retry PACKED; /* 18: max. retry */ | ||
263 | unsigned short term_retry PACKED; /* 1A: max. retry */ | ||
264 | unsigned short fail_retry PACKED; /* 1C: max. retry */ | ||
265 | unsigned short auth_retry PACKED; /* 1E: max. retry */ | ||
266 | unsigned char auth_options PACKED; /* 20: authentication opt. */ | ||
267 | unsigned char ip_options PACKED; /* 21: IP options */ | ||
268 | unsigned long ip_local PACKED; /* 22: local IP address */ | ||
269 | unsigned long ip_remote PACKED; /* 26: remote IP address */ | ||
270 | unsigned char ipx_options PACKED; /* 2A: IPX options */ | ||
271 | unsigned char ipx_netno[4] PACKED; /* 2B: IPX net number */ | ||
272 | unsigned char ipx_local[6] PACKED; /* 2F: local IPX node number*/ | ||
273 | unsigned char ipx_remote[6] PACKED; /* 35: remote IPX node num.*/ | ||
274 | unsigned char ipx_router[48] PACKED; /* 3B: IPX router name*/ | ||
275 | unsigned long alt_cpu_clock PACKED; /* 6B: */ | ||
276 | } ppp508_conf_t; | ||
277 | |||
278 | /*---------------------------------------------------------------------------- | ||
279 | * S508 Adapter Read Connection Information Block | ||
280 | * Returned by the PPP_GET_CONNECTION_INFO command | ||
281 | */ | ||
282 | typedef struct ppp508_connect_info | ||
283 | { | ||
284 | unsigned short mru PACKED; /* 00-01 Remote Max Rec' Unit */ | ||
285 | unsigned char ip_options PACKED; /* 02: Negotiated ip options */ | ||
286 | unsigned long ip_local PACKED; /* 03-06: local IP address */ | ||
287 | unsigned long ip_remote PACKED; /* 07-0A: remote IP address */ | ||
288 | unsigned char ipx_options PACKED; /* 0B: Negotiated ipx options */ | ||
289 | unsigned char ipx_netno[4] PACKED; /* 0C-0F: IPX net number */ | ||
290 | unsigned char ipx_local[6] PACKED; /* 10-1F: local IPX node # */ | ||
291 | unsigned char ipx_remote[6] PACKED; /* 16-1B: remote IPX node # */ | ||
292 | unsigned char ipx_router[48] PACKED; /* 1C-4B: IPX router name */ | ||
293 | unsigned char auth_status PACKED; /* 4C: Authentication Status */ | ||
294 | unsigned char inbd_auth_peerID[1] PACKED; /* 4D: variable length inbound authenticated peer ID */ | ||
295 | } ppp508_connect_info_t; | ||
296 | |||
297 | /* 'line_speed' field */ | ||
298 | #define PPP_BITRATE_1200 0x01 | ||
299 | #define PPP_BITRATE_2400 0x02 | ||
300 | #define PPP_BITRATE_4800 0x03 | ||
301 | #define PPP_BITRATE_9600 0x04 | ||
302 | #define PPP_BITRATE_19200 0x05 | ||
303 | #define PPP_BITRATE_38400 0x06 | ||
304 | #define PPP_BITRATE_45000 0x07 | ||
305 | #define PPP_BITRATE_56000 0x08 | ||
306 | #define PPP_BITRATE_64000 0x09 | ||
307 | #define PPP_BITRATE_74000 0x0A | ||
308 | #define PPP_BITRATE_112000 0x0B | ||
309 | #define PPP_BITRATE_128000 0x0C | ||
310 | #define PPP_BITRATE_156000 0x0D | ||
311 | |||
312 | /* Defines for the 'conf_flags' field */ | ||
313 | #define PPP_IGNORE_TX_ABORT 0x01 /* don't re-transmit aborted frames */ | ||
314 | #define PPP_ENABLE_TX_STATS 0x02 /* enable Tx statistics */ | ||
315 | #define PPP_ENABLE_RX_STATS 0x04 /* enable Rx statistics */ | ||
316 | #define PPP_ENABLE_TIMESTAMP 0x08 /* enable timestamp */ | ||
317 | |||
318 | /* 'ip_options' defines */ | ||
319 | #define PPP_LOCAL_IP_LOCAL 0x01 | ||
320 | #define PPP_LOCAL_IP_REMOTE 0x02 | ||
321 | #define PPP_REMOTE_IP_LOCAL 0x04 | ||
322 | #define PPP_REMOTE_IP_REMOTE 0x08 | ||
323 | |||
324 | /* 'ipx_options' defines */ | ||
325 | #define PPP_REMOTE_IPX_NETNO 0x01 | ||
326 | #define PPP_REMOTE_IPX_LOCAL 0x02 | ||
327 | #define PPP_REMOTE_IPX_REMOTE 0x04 | ||
328 | #define PPP_IPX_ROUTE_RIP_SAP 0x08 | ||
329 | #define PPP_IPX_ROUTE_NLSP 0x10 | ||
330 | #define PPP_IPX_ROUTE_DEFAULT 0x20 | ||
331 | #define PPP_IPX_CONF_COMPLETE 0x40 | ||
332 | #define PPP_IPX_ENABLE 0x80 | ||
333 | |||
334 | /*---------------------------------------------------------------------------- | ||
335 | * S508 Adapter Configuration Block (returned by the PPP_READ_CONFIG command). | ||
336 | */ | ||
337 | typedef struct ppp508_get_conf | ||
338 | { | ||
339 | unsigned long bps PACKED; /* 00: baud rate, bps */ | ||
340 | ppp508_conf_t conf PACKED; /* 04: requested config. */ | ||
341 | unsigned short txb_num PACKED; /* 6F: number of Tx buffers */ | ||
342 | unsigned short rxb_num PACKED; /* 71: number of Rx buffers */ | ||
343 | } ppp508_get_conf_t; | ||
344 | |||
345 | /*---------------------------------------------------------------------------- | ||
346 | * S508 Operational Statistics (returned by the PPP_READ_STATISTIC command). | ||
347 | */ | ||
348 | typedef struct ppp508_stats | ||
349 | { | ||
350 | unsigned short reserved1 PACKED; /* 00: */ | ||
351 | unsigned short rx_bad_len PACKED; /* 02: */ | ||
352 | unsigned short reserved2 PACKED; /* 04: */ | ||
353 | unsigned long tx_frames PACKED; /* 06: */ | ||
354 | unsigned long tx_bytes PACKED; /* 0A: */ | ||
355 | unsigned long rx_frames PACKED; /* 0E: */ | ||
356 | unsigned long rx_bytes PACKED; /* 12: */ | ||
357 | } ppp508_stats_t; | ||
358 | |||
359 | /*---------------------------------------------------------------------------- | ||
360 | * Adapter Error Statistics (returned by the PPP_READ_ERROR_STATS command). | ||
361 | */ | ||
362 | typedef struct ppp_err_stats | ||
363 | { | ||
364 | unsigned char rx_overrun PACKED; /* 00: Rx overrun errors */ | ||
365 | unsigned char rx_bad_crc PACKED; /* 01: Rx CRC errors */ | ||
366 | unsigned char rx_abort PACKED; /* 02: Rx aborted frames */ | ||
367 | unsigned char rx_lost PACKED; /* 03: Rx frames lost */ | ||
368 | unsigned char tx_abort PACKED; /* 04: Tx aborted frames */ | ||
369 | unsigned char tx_underrun PACKED; /* 05: Tx underrun errors */ | ||
370 | unsigned char tx_missed_intr PACKED; /* 06: Tx underruns missed */ | ||
371 | unsigned char reserved PACKED; /* 07: Tx underruns missed */ | ||
372 | unsigned char dcd_trans PACKED; /* 08: DCD transitions */ | ||
373 | unsigned char cts_trans PACKED; /* 09: CTS transitions */ | ||
374 | } ppp_err_stats_t; | ||
375 | |||
376 | /*---------------------------------------------------------------------------- | ||
377 | * Packet Statistics (returned by the PPP_READ_PACKET_STATS command). | ||
378 | */ | ||
379 | typedef struct ppp_pkt_stats | ||
380 | { | ||
381 | unsigned short rx_bad_header PACKED; /* 00: */ | ||
382 | unsigned short rx_prot_unknwn PACKED; /* 02: */ | ||
383 | unsigned short rx_too_large PACKED; /* 04: */ | ||
384 | unsigned short rx_lcp PACKED; /* 06: */ | ||
385 | unsigned short tx_lcp PACKED; /* 08: */ | ||
386 | unsigned short rx_ipcp PACKED; /* 0A: */ | ||
387 | unsigned short tx_ipcp PACKED; /* 0C: */ | ||
388 | unsigned short rx_ipxcp PACKED; /* 0E: */ | ||
389 | unsigned short tx_ipxcp PACKED; /* 10: */ | ||
390 | unsigned short rx_pap PACKED; /* 12: */ | ||
391 | unsigned short tx_pap PACKED; /* 14: */ | ||
392 | unsigned short rx_chap PACKED; /* 16: */ | ||
393 | unsigned short tx_chap PACKED; /* 18: */ | ||
394 | unsigned short rx_lqr PACKED; /* 1A: */ | ||
395 | unsigned short tx_lqr PACKED; /* 1C: */ | ||
396 | unsigned short rx_ip PACKED; /* 1E: */ | ||
397 | unsigned short tx_ip PACKED; /* 20: */ | ||
398 | unsigned short rx_ipx PACKED; /* 22: */ | ||
399 | unsigned short tx_ipx PACKED; /* 24: */ | ||
400 | } ppp_pkt_stats_t; | ||
401 | |||
402 | /*---------------------------------------------------------------------------- | ||
403 | * LCP Statistics (returned by the PPP_READ_LCP_STATS command). | ||
404 | */ | ||
405 | typedef struct ppp_lcp_stats | ||
406 | { | ||
407 | unsigned short rx_unknown PACKED; /* 00: unknown LCP type */ | ||
408 | unsigned short rx_conf_rqst PACKED; /* 02: Configure-Request */ | ||
409 | unsigned short rx_conf_ack PACKED; /* 04: Configure-Ack */ | ||
410 | unsigned short rx_conf_nak PACKED; /* 06: Configure-Nak */ | ||
411 | unsigned short rx_conf_rej PACKED; /* 08: Configure-Reject */ | ||
412 | unsigned short rx_term_rqst PACKED; /* 0A: Terminate-Request */ | ||
413 | unsigned short rx_term_ack PACKED; /* 0C: Terminate-Ack */ | ||
414 | unsigned short rx_code_rej PACKED; /* 0E: Code-Reject */ | ||
415 | unsigned short rx_proto_rej PACKED; /* 10: Protocol-Reject */ | ||
416 | unsigned short rx_echo_rqst PACKED; /* 12: Echo-Request */ | ||
417 | unsigned short rx_echo_reply PACKED; /* 14: Echo-Reply */ | ||
418 | unsigned short rx_disc_rqst PACKED; /* 16: Discard-Request */ | ||
419 | unsigned short tx_conf_rqst PACKED; /* 18: Configure-Request */ | ||
420 | unsigned short tx_conf_ack PACKED; /* 1A: Configure-Ack */ | ||
421 | unsigned short tx_conf_nak PACKED; /* 1C: Configure-Nak */ | ||
422 | unsigned short tx_conf_rej PACKED; /* 1E: Configure-Reject */ | ||
423 | unsigned short tx_term_rqst PACKED; /* 20: Terminate-Request */ | ||
424 | unsigned short tx_term_ack PACKED; /* 22: Terminate-Ack */ | ||
425 | unsigned short tx_code_rej PACKED; /* 24: Code-Reject */ | ||
426 | unsigned short tx_proto_rej PACKED; /* 26: Protocol-Reject */ | ||
427 | unsigned short tx_echo_rqst PACKED; /* 28: Echo-Request */ | ||
428 | unsigned short tx_echo_reply PACKED; /* 2A: Echo-Reply */ | ||
429 | unsigned short tx_disc_rqst PACKED; /* 2E: Discard-Request */ | ||
430 | unsigned short rx_too_large PACKED; /* 30: packets too large */ | ||
431 | unsigned short rx_ack_inval PACKED; /* 32: invalid Conf-Ack */ | ||
432 | unsigned short rx_rej_inval PACKED; /* 34: invalid Conf-Reject */ | ||
433 | unsigned short rx_rej_badid PACKED; /* 36: Conf-Reject w/bad ID */ | ||
434 | } ppp_lcp_stats_t; | ||
435 | |||
436 | /*---------------------------------------------------------------------------- | ||
437 | * Loopback Error Statistics (returned by the PPP_READ_LPBK_STATS command). | ||
438 | */ | ||
439 | typedef struct ppp_lpbk_stats | ||
440 | { | ||
441 | unsigned short conf_magic PACKED; /* 00: */ | ||
442 | unsigned short loc_echo_rqst PACKED; /* 02: */ | ||
443 | unsigned short rem_echo_rqst PACKED; /* 04: */ | ||
444 | unsigned short loc_echo_reply PACKED; /* 06: */ | ||
445 | unsigned short rem_echo_reply PACKED; /* 08: */ | ||
446 | unsigned short loc_disc_rqst PACKED; /* 0A: */ | ||
447 | unsigned short rem_disc_rqst PACKED; /* 0C: */ | ||
448 | unsigned short echo_tx_collsn PACKED; /* 0E: */ | ||
449 | unsigned short echo_rx_collsn PACKED; /* 10: */ | ||
450 | } ppp_lpbk_stats_t; | ||
451 | |||
452 | /*---------------------------------------------------------------------------- | ||
453 | * Protocol Statistics (returned by the PPP_READ_IPCP_STATS and | ||
454 | * PPP_READ_IPXCP_STATS commands). | ||
455 | */ | ||
456 | typedef struct ppp_prot_stats | ||
457 | { | ||
458 | unsigned short rx_unknown PACKED; /* 00: unknown type */ | ||
459 | unsigned short rx_conf_rqst PACKED; /* 02: Configure-Request */ | ||
460 | unsigned short rx_conf_ack PACKED; /* 04: Configure-Ack */ | ||
461 | unsigned short rx_conf_nak PACKED; /* 06: Configure-Nak */ | ||
462 | unsigned short rx_conf_rej PACKED; /* 08: Configure-Reject */ | ||
463 | unsigned short rx_term_rqst PACKED; /* 0A: Terminate-Request */ | ||
464 | unsigned short rx_term_ack PACKED; /* 0C: Terminate-Ack */ | ||
465 | unsigned short rx_code_rej PACKED; /* 0E: Code-Reject */ | ||
466 | unsigned short reserved PACKED; /* 10: */ | ||
467 | unsigned short tx_conf_rqst PACKED; /* 12: Configure-Request */ | ||
468 | unsigned short tx_conf_ack PACKED; /* 14: Configure-Ack */ | ||
469 | unsigned short tx_conf_nak PACKED; /* 16: Configure-Nak */ | ||
470 | unsigned short tx_conf_rej PACKED; /* 18: Configure-Reject */ | ||
471 | unsigned short tx_term_rqst PACKED; /* 1A: Terminate-Request */ | ||
472 | unsigned short tx_term_ack PACKED; /* 1C: Terminate-Ack */ | ||
473 | unsigned short tx_code_rej PACKED; /* 1E: Code-Reject */ | ||
474 | unsigned short rx_too_large PACKED; /* 20: packets too large */ | ||
475 | unsigned short rx_ack_inval PACKED; /* 22: invalid Conf-Ack */ | ||
476 | unsigned short rx_rej_inval PACKED; /* 24: invalid Conf-Reject */ | ||
477 | unsigned short rx_rej_badid PACKED; /* 26: Conf-Reject w/bad ID */ | ||
478 | } ppp_prot_stats_t; | ||
479 | |||
480 | /*---------------------------------------------------------------------------- | ||
481 | * PAP Statistics (returned by the PPP_READ_PAP_STATS command). | ||
482 | */ | ||
483 | typedef struct ppp_pap_stats | ||
484 | { | ||
485 | unsigned short rx_unknown PACKED; /* 00: unknown type */ | ||
486 | unsigned short rx_auth_rqst PACKED; /* 02: Authenticate-Request */ | ||
487 | unsigned short rx_auth_ack PACKED; /* 04: Authenticate-Ack */ | ||
488 | unsigned short rx_auth_nak PACKED; /* 06: Authenticate-Nak */ | ||
489 | unsigned short reserved PACKED; /* 08: */ | ||
490 | unsigned short tx_auth_rqst PACKED; /* 0A: Authenticate-Request */ | ||
491 | unsigned short tx_auth_ack PACKED; /* 0C: Authenticate-Ack */ | ||
492 | unsigned short tx_auth_nak PACKED; /* 0E: Authenticate-Nak */ | ||
493 | unsigned short rx_too_large PACKED; /* 10: packets too large */ | ||
494 | unsigned short rx_bad_peerid PACKED; /* 12: invalid peer ID */ | ||
495 | unsigned short rx_bad_passwd PACKED; /* 14: invalid password */ | ||
496 | } ppp_pap_stats_t; | ||
497 | |||
498 | /*---------------------------------------------------------------------------- | ||
499 | * CHAP Statistics (returned by the PPP_READ_CHAP_STATS command). | ||
500 | */ | ||
501 | typedef struct ppp_chap_stats | ||
502 | { | ||
503 | unsigned short rx_unknown PACKED; /* 00: unknown type */ | ||
504 | unsigned short rx_challenge PACKED; /* 02: Authenticate-Request */ | ||
505 | unsigned short rx_response PACKED; /* 04: Authenticate-Ack */ | ||
506 | unsigned short rx_success PACKED; /* 06: Authenticate-Nak */ | ||
507 | unsigned short rx_failure PACKED; /* 08: Authenticate-Nak */ | ||
508 | unsigned short reserved PACKED; /* 0A: */ | ||
509 | unsigned short tx_challenge PACKED; /* 0C: Authenticate-Request */ | ||
510 | unsigned short tx_response PACKED; /* 0E: Authenticate-Ack */ | ||
511 | unsigned short tx_success PACKED; /* 10: Authenticate-Nak */ | ||
512 | unsigned short tx_failure PACKED; /* 12: Authenticate-Nak */ | ||
513 | unsigned short rx_too_large PACKED; /* 14: packets too large */ | ||
514 | unsigned short rx_bad_peerid PACKED; /* 16: invalid peer ID */ | ||
515 | unsigned short rx_bad_passwd PACKED; /* 18: invalid password */ | ||
516 | unsigned short rx_bad_md5 PACKED; /* 1A: invalid MD5 format */ | ||
517 | unsigned short rx_bad_resp PACKED; /* 1C: invalid response */ | ||
518 | } ppp_chap_stats_t; | ||
519 | |||
520 | /*---------------------------------------------------------------------------- | ||
521 | * Connection Information (returned by the PPP_GET_CONNECTION_INFO command). | ||
522 | */ | ||
523 | typedef struct ppp_conn_info | ||
524 | { | ||
525 | unsigned short remote_mru PACKED; /* 00: */ | ||
526 | unsigned char ip_options PACKED; /* 02: */ | ||
527 | unsigned char ip_local[4] PACKED; /* 03: */ | ||
528 | unsigned char ip_remote[4] PACKED; /* 07: */ | ||
529 | unsigned char ipx_options PACKED; /* 0B: */ | ||
530 | unsigned char ipx_network[4] PACKED; /* 0C: */ | ||
531 | unsigned char ipx_local[6] PACKED; /* 10: */ | ||
532 | unsigned char ipx_remote[6] PACKED; /* 16: */ | ||
533 | unsigned char ipx_router[48] PACKED; /* 1C: */ | ||
534 | unsigned char auth_status PACKED; /* 4C: */ | ||
535 | unsigned char peer_id[0] PACKED; /* 4D: */ | ||
536 | } ppp_conn_info_t; | ||
537 | |||
538 | /* Data structure for SET_TRIGGER_INTR command | ||
539 | */ | ||
540 | |||
541 | typedef struct ppp_intr_info{ | ||
542 | unsigned char i_enable PACKED; /* 0 Interrupt enable bits */ | ||
543 | unsigned char irq PACKED; /* 1 Irq number */ | ||
544 | unsigned short timer_len PACKED; /* 2 Timer delay */ | ||
545 | } ppp_intr_info_t; | ||
546 | |||
547 | |||
548 | #define FT1_MONITOR_STATUS_CTRL 0x80 | ||
549 | #define SET_FT1_MODE 0x81 | ||
550 | |||
551 | |||
552 | |||
553 | /* Special UDP drivers management commands */ | ||
554 | #define PPIPE_ENABLE_TRACING 0x20 | ||
555 | #define PPIPE_DISABLE_TRACING 0x21 | ||
556 | #define PPIPE_GET_TRACE_INFO 0x22 | ||
557 | #define PPIPE_GET_IBA_DATA 0x23 | ||
558 | #define PPIPE_KILL_BOARD 0x24 | ||
559 | #define PPIPE_FT1_READ_STATUS 0x25 | ||
560 | #define PPIPE_DRIVER_STAT_IFSEND 0x26 | ||
561 | #define PPIPE_DRIVER_STAT_INTR 0x27 | ||
562 | #define PPIPE_DRIVER_STAT_GEN 0x28 | ||
563 | #define PPIPE_FLUSH_DRIVER_STATS 0x29 | ||
564 | #define PPIPE_ROUTER_UP_TIME 0x30 | ||
565 | |||
566 | #define DISABLE_TRACING 0x00 | ||
567 | #define TRACE_SIGNALLING_FRAMES 0x01 | ||
568 | #define TRACE_DATA_FRAMES 0x02 | ||
569 | |||
570 | |||
571 | |||
572 | #ifdef _MSC_ | ||
573 | # pragma pack() | ||
574 | #endif | ||
575 | #endif /* _SDLA_PPP_H */ | ||
diff --git a/include/linux/sdla_x25.h b/include/linux/sdla_x25.h deleted file mode 100644 index 57db980e27ad..000000000000 --- a/include/linux/sdla_x25.h +++ /dev/null | |||
@@ -1,772 +0,0 @@ | |||
1 | /***************************************************************************** | ||
2 | * sdla_x25.h Sangoma X.25 firmware API definitions. | ||
3 | * | ||
4 | * Author: Nenad Corbic <ncorbic@sangoma.com> | ||
5 | * | ||
6 | * Copyright: (c) 1995-2000 Sangoma Technologies Inc. | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License | ||
10 | * as published by the Free Software Foundation; either version | ||
11 | 2 of the License, or (at your option) any later version. | ||
12 | * ============================================================================ | ||
13 | * Feb 28, 2000 Nenad Corbic Updated for socket based x25api | ||
14 | * Dec 13, 1996 Gene Kozin Initial version | ||
15 | *****************************************************************************/ | ||
16 | #ifndef _SDLA_X25_H | ||
17 | #define _SDLA_X25_H | ||
18 | |||
19 | /*---------------------------------------------------------------------------- | ||
20 | * Notes: | ||
21 | * ------ | ||
22 | * 1. All structures defined in this file are byte-alined. | ||
23 | * Compiler Platform | ||
24 | * -------- -------- | ||
25 | * GNU C Linux | ||
26 | * | ||
27 | */ | ||
28 | |||
29 | #ifndef PACKED | ||
30 | # define PACKED __attribute__((packed)) | ||
31 | #endif /* PACKED */ | ||
32 | |||
33 | /****** CONSTANTS DEFINITIONS ***********************************************/ | ||
34 | |||
35 | #define X25_MAX_CHAN 255 /* max number of open X.25 circuits */ | ||
36 | #define X25_MAX_DATA 1024 /* max length of X.25 data buffer */ | ||
37 | /* | ||
38 | * X.25 shared memory layout. | ||
39 | */ | ||
40 | #define X25_MBOX_OFFS 0x16B0 /* general mailbox block */ | ||
41 | #define X25_RXMBOX_OFFS 0x1AD0 /* receive mailbox */ | ||
42 | #define X25_STATUS_OFFS 0x1EF0 /* X.25 status structure */ | ||
43 | #define X25_MB_VECTOR 0xE000 /* S514 mailbox window vecotr */ | ||
44 | #define X25_MISC_HDLC_BITS 0x1F00 /*X.25 miscallaneous HDLC bits */ | ||
45 | |||
46 | /* code levels */ | ||
47 | #define HDLC_LEVEL 0x01 | ||
48 | #define X25_LEVEL 0x02 | ||
49 | #define X25_AND_HDLC_LEVEL 0x03 | ||
50 | #define DO_HDLC_LEVEL_ERROR_CHECKING 0x04 | ||
51 | |||
52 | /****** DATA STRUCTURES *****************************************************/ | ||
53 | |||
54 | /*---------------------------------------------------------------------------- | ||
55 | * X.25 Command Block. | ||
56 | */ | ||
57 | typedef struct X25Cmd | ||
58 | { | ||
59 | unsigned char command PACKED; /* command code */ | ||
60 | unsigned short length PACKED; /* transfer data length */ | ||
61 | unsigned char result PACKED; /* return code */ | ||
62 | unsigned char pf PACKED; /* P/F bit */ | ||
63 | unsigned short lcn PACKED; /* logical channel */ | ||
64 | unsigned char qdm PACKED; /* Q/D/M bits */ | ||
65 | unsigned char cause PACKED; /* cause field */ | ||
66 | unsigned char diagn PACKED; /* diagnostics */ | ||
67 | unsigned char pktType PACKED; /* packet type */ | ||
68 | unsigned char resrv[4] PACKED; /* reserved */ | ||
69 | } TX25Cmd; | ||
70 | |||
71 | /* | ||
72 | * Defines for the 'command' field. | ||
73 | */ | ||
74 | /*----- General commands --------------*/ | ||
75 | #define X25_SET_GLOBAL_VARS 0x0B /* set global variables */ | ||
76 | #define X25_READ_MODEM_STATUS 0x0C /* read modem status */ | ||
77 | #define X25_READ_CODE_VERSION 0x15 /* read firmware version number */ | ||
78 | #define X25_TRACE_CONFIGURE 0x14 /* configure trace facility */ | ||
79 | #define X25_READ_TRACE_DATA 0x16 /* read trace data */ | ||
80 | #define X25_SET_INTERRUPT_MODE 0x17 /* set interrupt generation mode */ | ||
81 | #define X25_READ_INTERRUPT_MODE 0x18 /* read interrupt generation mode */ | ||
82 | /*----- HDLC-level commands -----------*/ | ||
83 | #define X25_HDLC_LINK_CONFIGURE 0x01 /* configure HDLC link level */ | ||
84 | #define X25_HDLC_LINK_OPEN 0x02 /* open HDLC link */ | ||
85 | #define X25_HDLC_LINK_CLOSE 0x03 /* close HDLC link */ | ||
86 | #define X25_HDLC_LINK_SETUP 0x04 /* set up HDLC link */ | ||
87 | #define X25_HDLC_LINK_DISC 0x05 /* disconnect DHLC link */ | ||
88 | #define X25_HDLC_LINK_STATUS 0x06 /* read DHLC link status */ | ||
89 | #define X25_HDLC_READ_STATS 0x07 /* read operational statistics */ | ||
90 | #define X25_HDLC_FLUSH_STATS 0x08 /* flush operational statistics */ | ||
91 | #define X25_HDLC_READ_COMM_ERR 0x09 /* read error statistics */ | ||
92 | #define X25_HDLC_FLUSH_COMM_ERR 0x0A /* flush error statistics */ | ||
93 | #define X25_HDLC_FLUSH_BUFFERS 0x0D /* flush HDLC-level data buffers */ | ||
94 | #define X25_HDLC_SPRVS_CNT_STAT 0x0F /* read surervisory count status */ | ||
95 | #define X25_HDLC_SEND_UI_FRAME 0x10 /* send unnumbered information frame */ | ||
96 | #define X25_HDLC_WRITE 0x11 /* send HDLC information frame */ | ||
97 | #define X25_HDLC_READ 0x21 /* read HDLC information frame */ | ||
98 | #define X25_HDLC_READ_CONFIG 0x12 /* read HDLC configuration */ | ||
99 | #define X25_HDLC_SET_CONFIG 0x13 /* set HDLC configuration */ | ||
100 | #define SET_PROTOCOL_LEVEL 0x1F /* set protocol level */ | ||
101 | /*----- X.25-level commands -----------*/ | ||
102 | #define X25_READ 0x22 /* read X.25 packet */ | ||
103 | #define X25_WRITE 0x23 /* send X.25 packet */ | ||
104 | #define X25_PLACE_CALL 0x30 /* place a call on SVC */ | ||
105 | #define X25_ACCEPT_CALL 0x31 /* accept incomming call */ | ||
106 | #define X25_CLEAR_CALL 0x32 /* clear call */ | ||
107 | #define X25_CLEAR_CONFRM 0x33 /* send clear confirmation packet */ | ||
108 | #define X25_RESET 0x34 /* send reset request packet */ | ||
109 | #define X25_RESET_CONFRM 0x35 /* send reset confirmation packet */ | ||
110 | #define X25_RESTART 0x36 /* send restart request packet */ | ||
111 | #define X25_RESTART_CONFRM 0x37 /* send restart confirmation packet */ | ||
112 | #define X25_INTERRUPT 0x38 /* send interrupt request packet */ | ||
113 | #define X25_INTERRUPT_CONFRM 0x39 /* send interrupt confirmation pkt */ | ||
114 | #define X25_REGISTRATION_RQST 0x3A /* send registration request packet */ | ||
115 | #define X25_REGISTRATION_CONFRM 0x3B /* send registration confirmation */ | ||
116 | #define X25_IS_DATA_AVAILABLE 0x40 /* querry receive queue */ | ||
117 | #define X25_INCOMMING_CALL_CTL 0x41 /* select incomming call options */ | ||
118 | #define X25_CONFIGURE_PVC 0x42 /* configure PVC */ | ||
119 | #define X25_GET_ACTIVE_CHANNELS 0x43 /* get a list of active circuits */ | ||
120 | #define X25_READ_CHANNEL_CONFIG 0x44 /* read virt. circuit configuration */ | ||
121 | #define X25_FLUSH_DATA_BUFFERS 0x45 /* flush X.25-level data buffers */ | ||
122 | #define X25_READ_HISTORY_TABLE 0x46 /* read asynchronous event log */ | ||
123 | #define X25_HISTORY_TABLE_CTL 0x47 /* control asynchronous event log */ | ||
124 | #define X25_GET_TX_D_BIT_STATUS 0x48 /* is packet with D-bit acknowleged */ | ||
125 | #define X25_READ_STATISTICS 0x49 /* read X.25-level statistics */ | ||
126 | #define X25_FLUSH_STATISTICS 0x4A /* flush X.25-level statistics */ | ||
127 | #define X25_READ_CONFIGURATION 0x50 /* read HDLC & X.25 configuration */ | ||
128 | #define X25_SET_CONFIGURATION 0x51 /* set HDLC & X.25 configuration */ | ||
129 | |||
130 | /* | ||
131 | * Defines for the 'result' field. | ||
132 | */ | ||
133 | /*----- General results ---------------*/ | ||
134 | #define X25RES_OK 0x00 | ||
135 | #define X25RES_ERROR 0x01 | ||
136 | #define X25RES_LINK_NOT_IN_ABM 0x02 /* link is not in ABM mode */ | ||
137 | #define X25RES_LINK_CLOSED 0x03 | ||
138 | #define X25RES_INVAL_LENGTH 0x04 | ||
139 | #define X25RES_INVAL_CMD 0x05 | ||
140 | #define X25RES_UNNUMBERED_FRAME 0x06 /* unnunbered frame received */ | ||
141 | #define X25RES_FRM_REJECT_MODE 0x07 /* link is in Frame Reject mode */ | ||
142 | #define X25RES_MODEM_FAILURE 0x08 /* DCD and/or CTS dropped */ | ||
143 | #define X25RES_N2_RETRY_LIMIT 0x09 /* N2 retry limit has been exceeded */ | ||
144 | #define X25RES_INVAL_LCN 0x30 /* invalid logical channel number */ | ||
145 | #define X25RES_INVAL_STATE 0x31 /* channel is not in data xfer mode */ | ||
146 | #define X25RES_INVAL_DATA_LEN 0x32 /* invalid data length */ | ||
147 | #define X25RES_NOT_READY 0x33 /* no data available / buffers full */ | ||
148 | #define X25RES_NETWORK_DOWN 0x34 | ||
149 | #define X25RES_CHANNEL_IN_USE 0x35 /* there is data queued on this LCN */ | ||
150 | #define X25RES_REGST_NOT_SUPPRT 0x36 /* registration not supported */ | ||
151 | #define X25RES_INVAL_FORMAT 0x37 /* invalid packet format */ | ||
152 | #define X25RES_D_BIT_NOT_SUPPRT 0x38 /* D-bit pragmatics not supported */ | ||
153 | #define X25RES_FACIL_NOT_SUPPRT 0x39 /* Call facility not supported */ | ||
154 | #define X25RES_INVAL_CALL_ARG 0x3A /* errorneous call arguments */ | ||
155 | #define X25RES_INVAL_CALL_DATA 0x3B /* errorneous call user data */ | ||
156 | #define X25RES_ASYNC_PACKET 0x40 /* asynchronous packet received */ | ||
157 | #define X25RES_PROTO_VIOLATION 0x41 /* protocol violation occurred */ | ||
158 | #define X25RES_PKT_TIMEOUT 0x42 /* X.25 packet time out */ | ||
159 | #define X25RES_PKT_RETRY_LIMIT 0x43 /* X.25 packet retry limit exceeded */ | ||
160 | /*----- Command-dependent results -----*/ | ||
161 | #define X25RES_LINK_DISC 0x00 /* HDLC_LINK_STATUS */ | ||
162 | #define X25RES_LINK_IN_ABM 0x01 /* HDLC_LINK_STATUS */ | ||
163 | #define X25RES_NO_DATA 0x01 /* HDLC_READ/READ_TRACE_DATA*/ | ||
164 | #define X25RES_TRACE_INACTIVE 0x02 /* READ_TRACE_DATA */ | ||
165 | #define X25RES_LINK_IS_OPEN 0x01 /* HDLC_LINK_OPEN */ | ||
166 | #define X25RES_LINK_IS_DISC 0x02 /* HDLC_LINK_DISC */ | ||
167 | #define X25RES_LINK_IS_CLOSED 0x03 /* HDLC_LINK_CLOSE */ | ||
168 | #define X25RES_INVAL_PARAM 0x31 /* INCOMMING_CALL_CTL */ | ||
169 | #define X25RES_INVAL_CONFIG 0x35 /* REGISTR_RQST/CONFRM */ | ||
170 | |||
171 | /* | ||
172 | * Defines for the 'qdm_bits' field. | ||
173 | */ | ||
174 | #define X25CMD_Q_BIT_MASK 0x04 | ||
175 | #define X25CMD_D_BIT_MASK 0x02 | ||
176 | #define X25CMD_M_BIT_MASK 0x01 | ||
177 | |||
178 | /* | ||
179 | * Defines for the 'pkt_type' field. | ||
180 | */ | ||
181 | /*----- Asynchronous events ------*/ | ||
182 | #define ASE_CLEAR_RQST 0x02 | ||
183 | #define ASE_RESET_RQST 0x04 | ||
184 | #define ASE_RESTART_RQST 0x08 | ||
185 | #define ASE_INTERRUPT 0x10 | ||
186 | #define ASE_DTE_REGISTR_RQST 0x20 | ||
187 | #define ASE_CALL_RQST 0x30 | ||
188 | #define ASE_CALL_ACCEPTED 0x31 | ||
189 | #define ASE_CLEAR_CONFRM 0x32 | ||
190 | #define ASE_RESET_CONFRM 0x33 | ||
191 | #define ASE_RESTART_CONFRM 0x34 | ||
192 | #define ASE_INTERRUPT_CONFRM 0x35 | ||
193 | #define ASE_DCE_REGISTR_CONFRM 0x36 | ||
194 | #define ASE_DIAGNOSTIC 0x37 | ||
195 | #define ASE_CALL_AUTO_CLEAR 0x38 | ||
196 | #define AUTO_RESPONSE_FLAG 0x80 | ||
197 | /*----- Time-Out events ----------*/ | ||
198 | #define TOE_RESTART_RQST 0x03 | ||
199 | #define TOE_CALL_RQST 0x05 | ||
200 | #define TOE_CLEAR_RQST 0x08 | ||
201 | #define TOE_RESET_RQST 0x0A | ||
202 | /*----- Protocol Violation events */ | ||
203 | #define PVE_CLEAR_RQST 0x32 | ||
204 | #define PVE_RESET_RQST 0x33 | ||
205 | #define PVE_RESTART_RQST 0x34 | ||
206 | #define PVE_DIAGNOSTIC 0x37 | ||
207 | |||
208 | #define INTR_ON_RX_FRAME 0x01 | ||
209 | #define INTR_ON_TX_FRAME 0x02 | ||
210 | #define INTR_ON_MODEM_STATUS_CHANGE 0x04 | ||
211 | #define INTR_ON_COMMAND_COMPLETE 0x08 | ||
212 | #define INTR_ON_X25_ASY_TRANSACTION 0x10 | ||
213 | #define INTR_ON_TIMER 0x40 | ||
214 | #define DIRECT_RX_INTR_USAGE 0x80 | ||
215 | |||
216 | #define NO_INTR_PENDING 0x00 | ||
217 | #define RX_INTR_PENDING 0x01 | ||
218 | #define TX_INTR_PENDING 0x02 | ||
219 | #define MODEM_INTR_PENDING 0x04 | ||
220 | #define COMMAND_COMPLETE_INTR_PENDING 0x08 | ||
221 | #define X25_ASY_TRANS_INTR_PENDING 0x10 | ||
222 | #define TIMER_INTR_PENDING 0x40 | ||
223 | |||
224 | /*---------------------------------------------------------------------------- | ||
225 | * X.25 Mailbox. | ||
226 | * This structure is located at offsets X25_MBOX_OFFS and X25_RXMBOX_OFFS | ||
227 | * into shared memory window. | ||
228 | */ | ||
229 | typedef struct X25Mbox | ||
230 | { | ||
231 | unsigned char opflag PACKED; /* 00h: execution flag */ | ||
232 | TX25Cmd cmd PACKED; /* 01h: command block */ | ||
233 | unsigned char data[1] PACKED; /* 10h: data buffer */ | ||
234 | } TX25Mbox; | ||
235 | |||
236 | /*---------------------------------------------------------------------------- | ||
237 | * X.25 Time Stamp Structure. | ||
238 | */ | ||
239 | typedef struct X25TimeStamp | ||
240 | { | ||
241 | unsigned char month PACKED; | ||
242 | unsigned char date PACKED; | ||
243 | unsigned char sec PACKED; | ||
244 | unsigned char min PACKED; | ||
245 | unsigned char hour PACKED; | ||
246 | } TX25TimeStamp; | ||
247 | |||
248 | /*---------------------------------------------------------------------------- | ||
249 | * X.25 Status Block. | ||
250 | * This structure is located at offset X25_STATUS_OFF into shared memory | ||
251 | * window. | ||
252 | */ | ||
253 | typedef struct X25Status | ||
254 | { | ||
255 | unsigned short pvc_map PACKED; /* 00h: PVC map */ | ||
256 | unsigned short icc_map PACKED; /* 02h: Incomming Chan. map */ | ||
257 | unsigned short twc_map PACKED; /* 04h: Two-way Cnan. map */ | ||
258 | unsigned short ogc_map PACKED; /* 06h: Outgoing Chan. map */ | ||
259 | TX25TimeStamp tstamp PACKED; /* 08h: timestamp (BCD) */ | ||
260 | unsigned char iflags PACKED; /* 0Dh: interrupt flags */ | ||
261 | unsigned char imask PACKED; /* 0Eh: interrupt mask */ | ||
262 | unsigned char resrv PACKED; /* 0Eh: */ | ||
263 | unsigned char gflags PACKED; /* 10h: misc. HDLC/X25 flags */ | ||
264 | unsigned char cflags[X25_MAX_CHAN] PACKED; /* channel status bytes */ | ||
265 | } TX25Status; | ||
266 | |||
267 | /* | ||
268 | * Bitmasks for the 'iflags' field. | ||
269 | */ | ||
270 | #define X25_RX_INTR 0x01 /* receive interrupt */ | ||
271 | #define X25_TX_INTR 0x02 /* transmit interrupt */ | ||
272 | #define X25_MODEM_INTR 0x04 /* modem status interrupt (CTS/DCD) */ | ||
273 | #define X25_EVENT_INTR 0x10 /* asyncronous event encountered */ | ||
274 | #define X25_CMD_INTR 0x08 /* interface command complete */ | ||
275 | |||
276 | /* | ||
277 | * Bitmasks for the 'gflags' field. | ||
278 | */ | ||
279 | #define X25_HDLC_ABM 0x01 /* HDLC is in ABM mode */ | ||
280 | #define X25_RX_READY 0x02 /* X.25 data available */ | ||
281 | #define X25_TRACE_READY 0x08 /* trace data available */ | ||
282 | #define X25_EVENT_IND 0x20 /* asynchronous event indicator */ | ||
283 | #define X25_TX_READY 0x40 /* space is available in Tx buf.*/ | ||
284 | |||
285 | /* | ||
286 | * Bitmasks for the 'cflags' field. | ||
287 | */ | ||
288 | #define X25_XFER_MODE 0x80 /* channel is in data transfer mode */ | ||
289 | #define X25_TXWIN_OPEN 0x40 /* transmit window open */ | ||
290 | #define X25_RXBUF_MASK 0x3F /* number of data buffers available */ | ||
291 | |||
292 | /***************************************************************************** | ||
293 | * Following definitions structurize contents of the TX25Mbox.data field for | ||
294 | * different X.25 interface commands. | ||
295 | ****************************************************************************/ | ||
296 | |||
297 | /* --------------------------------------------------------------------------- | ||
298 | * X25_SET_GLOBAL_VARS Command. | ||
299 | */ | ||
300 | typedef struct X25GlobalVars | ||
301 | { | ||
302 | unsigned char resrv PACKED; /* 00h: reserved */ | ||
303 | unsigned char dtrCtl PACKED; /* 01h: DTR control code */ | ||
304 | unsigned char resErr PACKED; /* 01h: '1' - reset modem error */ | ||
305 | } TX25GlobalVars; | ||
306 | |||
307 | /* | ||
308 | * Defines for the 'dtrCtl' field. | ||
309 | */ | ||
310 | #define X25_RAISE_DTR 0x01 | ||
311 | #define X25_DROP_DTR 0x02 | ||
312 | |||
313 | /* --------------------------------------------------------------------------- | ||
314 | * X25_READ_MODEM_STATUS Command. | ||
315 | */ | ||
316 | typedef struct X25ModemStatus | ||
317 | { | ||
318 | unsigned char status PACKED; /* 00h: modem status */ | ||
319 | } TX25ModemStatus; | ||
320 | |||
321 | /* | ||
322 | * Defines for the 'status' field. | ||
323 | */ | ||
324 | #define X25_CTS_MASK 0x20 | ||
325 | #define X25_DCD_MASK 0x08 | ||
326 | |||
327 | /* --------------------------------------------------------------------------- | ||
328 | * X25_HDLC_LINK_STATUS Command. | ||
329 | */ | ||
330 | typedef struct X25LinkStatus | ||
331 | { | ||
332 | unsigned char txQueued PACKED; /* 00h: queued Tx I-frames*/ | ||
333 | unsigned char rxQueued PACKED; /* 01h: queued Rx I-frames*/ | ||
334 | unsigned char station PACKED; /* 02h: DTE/DCE config. */ | ||
335 | unsigned char reserved PACKED; /* 03h: reserved */ | ||
336 | unsigned char sfTally PACKED; /* 04h: supervisory frame tally */ | ||
337 | } TX25LinkStatus; | ||
338 | |||
339 | /* | ||
340 | * Defines for the 'station' field. | ||
341 | */ | ||
342 | #define X25_STATION_DTE 0x01 /* station configured as DTE */ | ||
343 | #define X25_STATION_DCE 0x02 /* station configured as DCE */ | ||
344 | |||
345 | /* --------------------------------------------------------------------------- | ||
346 | * X25_HDLC_READ_STATS Command. | ||
347 | */ | ||
348 | typedef struct HdlcStats | ||
349 | { /* a number of ... */ | ||
350 | unsigned short rxIFrames PACKED; /* 00h: ready Rx I-frames */ | ||
351 | unsigned short rxNoseq PACKED; /* 02h: frms out-of-sequence */ | ||
352 | unsigned short rxNodata PACKED; /* 04h: I-frms without data */ | ||
353 | unsigned short rxDiscarded PACKED; /* 06h: discarded frames */ | ||
354 | unsigned short rxTooLong PACKED; /* 08h: frames too long */ | ||
355 | unsigned short rxBadAddr PACKED; /* 0Ah: frms with inval.addr*/ | ||
356 | unsigned short txAcked PACKED; /* 0Ch: acknowledged I-frms */ | ||
357 | unsigned short txRetransm PACKED; /* 0Eh: re-transmit. I-frms */ | ||
358 | unsigned short t1Timeout PACKED; /* 10h: T1 timeouts */ | ||
359 | unsigned short rxSABM PACKED; /* 12h: received SABM frames */ | ||
360 | unsigned short rxDISC PACKED; /* 14h: received DISC frames */ | ||
361 | unsigned short rxDM PACKED; /* 16h: received DM frames */ | ||
362 | unsigned short rxFRMR PACKED; /* 18h: FRMR frames received */ | ||
363 | unsigned short txSABM PACKED; /* 1Ah: transm. SABM frames*/ | ||
364 | unsigned short txDISC PACKED; /* 1Ch: transm. DISC frames*/ | ||
365 | unsigned short txDM PACKED; /* 1Eh: transm. DM frames */ | ||
366 | unsigned short txFRMR PACKED; /* 20h: transm. FRMR frames*/ | ||
367 | } THdlcStats; | ||
368 | |||
369 | /* --------------------------------------------------------------------------- | ||
370 | * X25_HDLC_READ_COMM_ERR Command. | ||
371 | */ | ||
372 | typedef struct HdlcCommErr | ||
373 | { /* a number of ... */ | ||
374 | unsigned char rxOverrun PACKED; /* 00h: Rx overrun errors */ | ||
375 | unsigned char rxBadCrc PACKED; /* 01h: Rx CRC errors */ | ||
376 | unsigned char rxAborted PACKED; /* 02h: Rx aborted frames */ | ||
377 | unsigned char rxDropped PACKED; /* 03h: frames lost */ | ||
378 | unsigned char txAborted PACKED; /* 04h: Tx aborted frames */ | ||
379 | unsigned char txUnderrun PACKED; /* 05h: Tx underrun errors */ | ||
380 | unsigned char txMissIntr PACKED; /* 06h: missed underrun ints */ | ||
381 | unsigned char reserved PACKED; /* 07h: reserved */ | ||
382 | unsigned char droppedDCD PACKED; /* 08h: times DCD dropped */ | ||
383 | unsigned char droppedCTS PACKED; /* 09h: times CTS dropped */ | ||
384 | } THdlcCommErr; | ||
385 | |||
386 | /* --------------------------------------------------------------------------- | ||
387 | * X25_SET_CONFIGURATION & X25_READ_CONFIGURATION Commands. | ||
388 | */ | ||
389 | typedef struct X25Config | ||
390 | { | ||
391 | unsigned char baudRate PACKED; /* 00h: */ | ||
392 | unsigned char t1 PACKED; /* 01h: */ | ||
393 | unsigned char t2 PACKED; /* 02h: */ | ||
394 | unsigned char n2 PACKED; /* 03h: */ | ||
395 | unsigned short hdlcMTU PACKED; /* 04h: */ | ||
396 | unsigned char hdlcWindow PACKED; /* 06h: */ | ||
397 | unsigned char t4 PACKED; /* 07h: */ | ||
398 | unsigned char autoModem PACKED; /* 08h: */ | ||
399 | unsigned char autoHdlc PACKED; /* 09h: */ | ||
400 | unsigned char hdlcOptions PACKED; /* 0Ah: */ | ||
401 | unsigned char station PACKED; /* 0Bh: */ | ||
402 | unsigned char pktWindow PACKED; /* 0Ch: */ | ||
403 | unsigned short defPktSize PACKED; /* 0Dh: */ | ||
404 | unsigned short pktMTU PACKED; /* 0Fh: */ | ||
405 | unsigned short loPVC PACKED; /* 11h: */ | ||
406 | unsigned short hiPVC PACKED; /* 13h: */ | ||
407 | unsigned short loIncommingSVC PACKED; /* 15h: */ | ||
408 | unsigned short hiIncommingSVC PACKED; /* 17h: */ | ||
409 | unsigned short loTwoWaySVC PACKED; /* 19h: */ | ||
410 | unsigned short hiTwoWaySVC PACKED; /* 1Bh: */ | ||
411 | unsigned short loOutgoingSVC PACKED; /* 1Dh: */ | ||
412 | unsigned short hiOutgoingSVC PACKED; /* 1Fh: */ | ||
413 | unsigned short options PACKED; /* 21h: */ | ||
414 | unsigned char responseOpt PACKED; /* 23h: */ | ||
415 | unsigned short facil1 PACKED; /* 24h: */ | ||
416 | unsigned short facil2 PACKED; /* 26h: */ | ||
417 | unsigned short ccittFacil PACKED; /* 28h: */ | ||
418 | unsigned short otherFacil PACKED; /* 2Ah: */ | ||
419 | unsigned short ccittCompat PACKED; /* 2Ch: */ | ||
420 | unsigned char t10t20 PACKED; /* 2Eh: */ | ||
421 | unsigned char t11t21 PACKED; /* 2Fh: */ | ||
422 | unsigned char t12t22 PACKED; /* 30h: */ | ||
423 | unsigned char t13t23 PACKED; /* 31h: */ | ||
424 | unsigned char t16t26 PACKED; /* 32H: */ | ||
425 | unsigned char t28 PACKED; /* 33h: */ | ||
426 | unsigned char r10r20 PACKED; /* 34h: */ | ||
427 | unsigned char r12r22 PACKED; /* 35h: */ | ||
428 | unsigned char r13r23 PACKED; /* 36h: */ | ||
429 | } TX25Config; | ||
430 | |||
431 | /* --------------------------------------------------------------------------- | ||
432 | * X25_READ_CHANNEL_CONFIG Command. | ||
433 | */ | ||
434 | typedef struct X25ChanAlloc /*----- Channel allocation -*/ | ||
435 | { | ||
436 | unsigned short loPVC PACKED; /* 00h: lowest PVC number */ | ||
437 | unsigned short hiPVC PACKED; /* 02h: highest PVC number */ | ||
438 | unsigned short loIncommingSVC PACKED; /* 04h: lowest incoming SVC */ | ||
439 | unsigned short hiIncommingSVC PACKED; /* 06h: highest incoming SVC */ | ||
440 | unsigned short loTwoWaySVC PACKED; /* 08h: lowest two-way SVC */ | ||
441 | unsigned short hiTwoWaySVC PACKED; /* 0Ah: highest two-way SVC */ | ||
442 | unsigned short loOutgoingSVC PACKED; /* 0Ch: lowest outgoing SVC */ | ||
443 | unsigned short hiOutgoingSVC PACKED; /* 0Eh: highest outgoing SVC */ | ||
444 | } TX25ChanAlloc; | ||
445 | |||
446 | typedef struct X25ChanCfg /*------ Channel configuration -----*/ | ||
447 | { | ||
448 | unsigned char type PACKED; /* 00h: channel type */ | ||
449 | unsigned char txConf PACKED; /* 01h: Tx packet and window sizes */ | ||
450 | unsigned char rxConf PACKED; /* 01h: Rx packet and window sizes */ | ||
451 | } TX25ChanCfg; | ||
452 | |||
453 | /* | ||
454 | * Defines for the 'type' field. | ||
455 | */ | ||
456 | #define X25_PVC 0x01 /* PVC */ | ||
457 | #define X25_SVC_IN 0x03 /* Incoming SVC */ | ||
458 | #define X25_SVC_TWOWAY 0x07 /* Two-way SVC */ | ||
459 | #define X25_SVC_OUT 0x0B /* Outgoing SVC */ | ||
460 | |||
461 | /*---------------------------------------------------------------------------- | ||
462 | * X25_READ_STATISTICS Command. | ||
463 | */ | ||
464 | typedef struct X25Stats | ||
465 | { /* number of packets Tx/Rx'ed */ | ||
466 | unsigned short txRestartRqst PACKED; /* 00h: Restart Request */ | ||
467 | unsigned short rxRestartRqst PACKED; /* 02h: Restart Request */ | ||
468 | unsigned short txRestartConf PACKED; /* 04h: Restart Confirmation */ | ||
469 | unsigned short rxRestartConf PACKED; /* 06h: Restart Confirmation */ | ||
470 | unsigned short txResetRqst PACKED; /* 08h: Reset Request */ | ||
471 | unsigned short rxResetRqst PACKED; /* 0Ah: Reset Request */ | ||
472 | unsigned short txResetConf PACKED; /* 0Ch: Reset Confirmation */ | ||
473 | unsigned short rxResetConf PACKED; /* 0Eh: Reset Confirmation */ | ||
474 | unsigned short txCallRequest PACKED; /* 10h: Call Request */ | ||
475 | unsigned short rxCallRequest PACKED; /* 12h: Call Request */ | ||
476 | unsigned short txCallAccept PACKED; /* 14h: Call Accept */ | ||
477 | unsigned short rxCallAccept PACKED; /* 16h: Call Accept */ | ||
478 | unsigned short txClearRqst PACKED; /* 18h: Clear Request */ | ||
479 | unsigned short rxClearRqst PACKED; /* 1Ah: Clear Request */ | ||
480 | unsigned short txClearConf PACKED; /* 1Ch: Clear Confirmation */ | ||
481 | unsigned short rxClearConf PACKED; /* 1Eh: Clear Confirmation */ | ||
482 | unsigned short txDiagnostic PACKED; /* 20h: Diagnostic */ | ||
483 | unsigned short rxDiagnostic PACKED; /* 22h: Diagnostic */ | ||
484 | unsigned short txRegRqst PACKED; /* 24h: Registration Request */ | ||
485 | unsigned short rxRegRqst PACKED; /* 26h: Registration Request */ | ||
486 | unsigned short txRegConf PACKED; /* 28h: Registration Confirm.*/ | ||
487 | unsigned short rxRegConf PACKED; /* 2Ah: Registration Confirm.*/ | ||
488 | unsigned short txInterrupt PACKED; /* 2Ch: Interrupt */ | ||
489 | unsigned short rxInterrupt PACKED; /* 2Eh: Interrupt */ | ||
490 | unsigned short txIntrConf PACKED; /* 30h: Interrupt Confirm. */ | ||
491 | unsigned short rxIntrConf PACKED; /* 32h: Interrupt Confirm. */ | ||
492 | unsigned short txData PACKED; /* 34h: Data */ | ||
493 | unsigned short rxData PACKED; /* 36h: Data */ | ||
494 | unsigned short txRR PACKED; /* 38h: RR */ | ||
495 | unsigned short rxRR PACKED; /* 3Ah: RR */ | ||
496 | unsigned short txRNR PACKED; /* 3Ch: RNR */ | ||
497 | unsigned short rxRNR PACKED; /* 3Eh: RNR */ | ||
498 | } TX25Stats; | ||
499 | |||
500 | /*---------------------------------------------------------------------------- | ||
501 | * X25_READ_HISTORY_TABLE Command. | ||
502 | */ | ||
503 | typedef struct X25EventLog | ||
504 | { | ||
505 | unsigned char type PACKED; /* 00h: transaction type */ | ||
506 | unsigned short lcn PACKED; /* 01h: logical channel num */ | ||
507 | unsigned char packet PACKED; /* 03h: async packet type */ | ||
508 | unsigned char cause PACKED; /* 04h: X.25 cause field */ | ||
509 | unsigned char diag PACKED; /* 05h: X.25 diag field */ | ||
510 | TX25TimeStamp ts PACKED; /* 06h: time stamp */ | ||
511 | } TX25EventLog; | ||
512 | |||
513 | /* | ||
514 | * Defines for the 'type' field. | ||
515 | */ | ||
516 | #define X25LOG_INCOMMING 0x00 | ||
517 | #define X25LOG_APPLICATION 0x01 | ||
518 | #define X25LOG_AUTOMATIC 0x02 | ||
519 | #define X25LOG_ERROR 0x04 | ||
520 | #define X25LOG_TIMEOUT 0x08 | ||
521 | #define X25LOG_RECOVERY 0x10 | ||
522 | |||
523 | /* | ||
524 | * Defines for the 'packet' field. | ||
525 | */ | ||
526 | #define X25LOG_CALL_RQST 0x0B | ||
527 | #define X25LOG_CALL_ACCEPTED 0x0F | ||
528 | #define X25LOG_CLEAR_RQST 0x13 | ||
529 | #define X25LOG_CLEAR_CONFRM 0x17 | ||
530 | #define X25LOG_RESET_RQST 0x1B | ||
531 | #define X25LOG_RESET_CONFRM 0x1F | ||
532 | #define X25LOG_RESTART_RQST 0xFB | ||
533 | #define X25LOG_RESTART_COMFRM 0xFF | ||
534 | #define X25LOG_DIAGNOSTIC 0xF1 | ||
535 | #define X25LOG_DTE_REG_RQST 0xF3 | ||
536 | #define X25LOG_DTE_REG_COMFRM 0xF7 | ||
537 | |||
538 | /* --------------------------------------------------------------------------- | ||
539 | * X25_TRACE_CONFIGURE Command. | ||
540 | */ | ||
541 | typedef struct X25TraceCfg | ||
542 | { | ||
543 | unsigned char flags PACKED; /* 00h: trace configuration flags */ | ||
544 | unsigned char timeout PACKED; /* 01h: timeout for trace delay mode*/ | ||
545 | } TX25TraceCfg; | ||
546 | |||
547 | /* | ||
548 | * Defines for the 'flags' field. | ||
549 | */ | ||
550 | #define X25_TRC_ENABLE 0x01 /* bit0: '1' - trace enabled */ | ||
551 | #define X25_TRC_TIMESTAMP 0x02 /* bit1: '1' - time stamping enabled*/ | ||
552 | #define X25_TRC_DELAY 0x04 /* bit2: '1' - trace delay enabled */ | ||
553 | #define X25_TRC_DATA 0x08 /* bit3: '1' - trace data packets */ | ||
554 | #define X25_TRC_SUPERVISORY 0x10 /* bit4: '1' - trace suprvisory pkts*/ | ||
555 | #define X25_TRC_ASYNCHRONOUS 0x20 /* bit5: '1' - trace asynch. packets*/ | ||
556 | #define X25_TRC_HDLC 0x40 /* bit6: '1' - trace all packets */ | ||
557 | #define X25_TRC_READ 0x80 /* bit7: '1' - get current config. */ | ||
558 | |||
559 | /* --------------------------------------------------------------------------- | ||
560 | * X25_READ_TRACE_DATA Command. | ||
561 | */ | ||
562 | typedef struct X25Trace /*----- Trace data structure -------*/ | ||
563 | { | ||
564 | unsigned short length PACKED; /* 00h: trace data length */ | ||
565 | unsigned char type PACKED; /* 02h: trace type */ | ||
566 | unsigned char lost_cnt PACKED; /* 03h: N of traces lost */ | ||
567 | TX25TimeStamp tstamp PACKED; /* 04h: mon/date/sec/min/hour */ | ||
568 | unsigned short millisec PACKED; /* 09h: ms time stamp */ | ||
569 | unsigned char data[0] PACKED; /* 0Bh: traced frame */ | ||
570 | } TX25Trace; | ||
571 | |||
572 | /* | ||
573 | * Defines for the 'type' field. | ||
574 | */ | ||
575 | #define X25_TRC_TYPE_MASK 0x0F /* bits 0..3: trace type */ | ||
576 | #define X25_TRC_TYPE_RX_FRAME 0x00 /* received frame trace */ | ||
577 | #define X25_TRC_TYPE_TX_FRAME 0x01 /* transmitted frame */ | ||
578 | #define X25_TRC_TYPE_ERR_FRAME 0x02 /* error frame */ | ||
579 | |||
580 | #define X25_TRC_ERROR_MASK 0xF0 /* bits 4..7: error code */ | ||
581 | #define X25_TRCERR_RX_ABORT 0x10 /* receive abort error */ | ||
582 | #define X25_TRCERR_RX_BADCRC 0x20 /* receive CRC error */ | ||
583 | #define X25_TRCERR_RX_OVERRUN 0x30 /* receiver overrun error */ | ||
584 | #define X25_TRCERR_RX_TOO_LONG 0x40 /* excessive frame length error */ | ||
585 | #define X25_TRCERR_TX_ABORT 0x70 /* aborted frame transmittion error */ | ||
586 | #define X25_TRCERR_TX_UNDERRUN 0x80 /* transmit underrun error */ | ||
587 | |||
588 | /***************************************************************************** | ||
589 | * Following definitions describe HDLC frame and X.25 packet formats. | ||
590 | ****************************************************************************/ | ||
591 | |||
592 | typedef struct HDLCFrame /*----- DHLC Frame Format ----------*/ | ||
593 | { | ||
594 | unsigned char addr PACKED; /* address field */ | ||
595 | unsigned char cntl PACKED; /* control field */ | ||
596 | unsigned char data[0] PACKED; | ||
597 | } THDLCFrame; | ||
598 | |||
599 | typedef struct X25Pkt /*----- X.25 Paket Format ----------*/ | ||
600 | { | ||
601 | unsigned char lcn_hi PACKED; /* 4 MSB of Logical Channel Number */ | ||
602 | unsigned char lcn_lo PACKED; /* 8 LSB of Logical Channel Number */ | ||
603 | unsigned char type PACKED; | ||
604 | unsigned char data[0] PACKED; | ||
605 | } TX25Pkt; | ||
606 | |||
607 | /* | ||
608 | * Defines for the 'lcn_hi' field. | ||
609 | */ | ||
610 | #define X25_Q_BIT_MASK 0x80 /* Data Qualifier Bit mask */ | ||
611 | #define X25_D_BIT_MASK 0x40 /* Delivery Confirmation Bit mask */ | ||
612 | #define X25_M_BITS_MASK 0x30 /* Modulo Bits mask */ | ||
613 | #define X25_LCN_MSB_MASK 0x0F /* LCN most significant bits mask */ | ||
614 | |||
615 | /* | ||
616 | * Defines for the 'type' field. | ||
617 | */ | ||
618 | #define X25PKT_DATA 0x01 /* Data packet mask */ | ||
619 | #define X25PKT_SUPERVISORY 0x02 /* Supervisory packet mask */ | ||
620 | #define X25PKT_CALL_RQST 0x0B /* Call Request/Incoming */ | ||
621 | #define X25PKT_CALL_ACCEPTED 0x0F /* Call Accepted/Connected */ | ||
622 | #define X25PKT_CLEAR_RQST 0x13 /* Clear Request/Indication */ | ||
623 | #define X25PKT_CLEAR_CONFRM 0x17 /* Clear Confirmation */ | ||
624 | #define X25PKT_RESET_RQST 0x1B /* Reset Request/Indication */ | ||
625 | #define X25PKT_RESET_CONFRM 0x1F /* Reset Confirmation */ | ||
626 | #define X25PKT_RESTART_RQST 0xFB /* Restart Request/Indication */ | ||
627 | #define X25PKT_RESTART_CONFRM 0xFF /* Restart Confirmation */ | ||
628 | #define X25PKT_INTERRUPT 0x23 /* Interrupt */ | ||
629 | #define X25PKT_INTERRUPT_CONFRM 0x27 /* Interrupt Confirmation */ | ||
630 | #define X25PKT_DIAGNOSTIC 0xF1 /* Diagnostic */ | ||
631 | #define X25PKT_REGISTR_RQST 0xF3 /* Registration Request */ | ||
632 | #define X25PKT_REGISTR_CONFRM 0xF7 /* Registration Confirmation */ | ||
633 | #define X25PKT_RR_MASKED 0x01 /* Receive Ready packet after masking */ | ||
634 | #define X25PKT_RNR_MASKED 0x05 /* Receive Not Ready after masking */ | ||
635 | |||
636 | |||
637 | typedef struct { | ||
638 | TX25Cmd cmd PACKED; | ||
639 | char data[X25_MAX_DATA] PACKED; | ||
640 | } mbox_cmd_t; | ||
641 | |||
642 | |||
643 | typedef struct { | ||
644 | unsigned char qdm PACKED; /* Q/D/M bits */ | ||
645 | unsigned char cause PACKED; /* cause field */ | ||
646 | unsigned char diagn PACKED; /* diagnostics */ | ||
647 | unsigned char pktType PACKED; | ||
648 | unsigned short length PACKED; | ||
649 | unsigned char result PACKED; | ||
650 | unsigned short lcn PACKED; | ||
651 | char reserved[7] PACKED; | ||
652 | }x25api_hdr_t; | ||
653 | |||
654 | |||
655 | typedef struct { | ||
656 | x25api_hdr_t hdr PACKED; | ||
657 | char data[X25_MAX_DATA] PACKED; | ||
658 | }x25api_t; | ||
659 | |||
660 | |||
661 | /* | ||
662 | * XPIPEMON Definitions | ||
663 | */ | ||
664 | |||
665 | /* valid ip_protocol for UDP management */ | ||
666 | #define UDPMGMT_UDP_PROTOCOL 0x11 | ||
667 | #define UDPMGMT_XPIPE_SIGNATURE "XLINK8ND" | ||
668 | #define UDPMGMT_DRVRSTATS_SIGNATURE "DRVSTATS" | ||
669 | |||
670 | /* values for request/reply byte */ | ||
671 | #define UDPMGMT_REQUEST 0x01 | ||
672 | #define UDPMGMT_REPLY 0x02 | ||
673 | #define UDP_OFFSET 12 | ||
674 | |||
675 | |||
676 | typedef struct { | ||
677 | unsigned char opp_flag PACKED; /* the opp flag */ | ||
678 | unsigned char command PACKED; /* command code */ | ||
679 | unsigned short length PACKED; /* transfer data length */ | ||
680 | unsigned char result PACKED; /* return code */ | ||
681 | unsigned char pf PACKED; /* P/F bit */ | ||
682 | unsigned short lcn PACKED; /* logical channel */ | ||
683 | unsigned char qdm PACKED; /* Q/D/M bits */ | ||
684 | unsigned char cause PACKED; /* cause field */ | ||
685 | unsigned char diagn PACKED; /* diagnostics */ | ||
686 | unsigned char pktType PACKED; /* packet type */ | ||
687 | unsigned char resrv[4] PACKED; /* reserved */ | ||
688 | } cblock_t; | ||
689 | |||
690 | typedef struct { | ||
691 | ip_pkt_t ip_pkt PACKED; | ||
692 | udp_pkt_t udp_pkt PACKED; | ||
693 | wp_mgmt_t wp_mgmt PACKED; | ||
694 | cblock_t cblock PACKED; | ||
695 | unsigned char data[4080] PACKED; | ||
696 | } x25_udp_pkt_t; | ||
697 | |||
698 | |||
699 | typedef struct read_hdlc_stat { | ||
700 | unsigned short inf_frames_rx_ok PACKED; | ||
701 | unsigned short inf_frames_rx_out_of_seq PACKED; | ||
702 | unsigned short inf_frames_rx_no_data PACKED; | ||
703 | unsigned short inf_frames_rx_dropped PACKED; | ||
704 | unsigned short inf_frames_rx_data_too_long PACKED; | ||
705 | unsigned short inf_frames_rx_invalid_addr PACKED; | ||
706 | unsigned short inf_frames_tx_ok PACKED; | ||
707 | unsigned short inf_frames_tx_retransmit PACKED; | ||
708 | unsigned short T1_timeouts PACKED; | ||
709 | unsigned short SABM_frames_rx PACKED; | ||
710 | unsigned short DISC_frames_rx PACKED; | ||
711 | unsigned short DM_frames_rx PACKED; | ||
712 | unsigned short FRMR_frames_rx PACKED; | ||
713 | unsigned short SABM_frames_tx PACKED; | ||
714 | unsigned short DISC_frames_tx PACKED; | ||
715 | unsigned short DM_frames_tx PACKED; | ||
716 | unsigned short FRMR_frames_tx PACKED; | ||
717 | } read_hdlc_stat_t; | ||
718 | |||
719 | typedef struct read_comms_err_stats{ | ||
720 | unsigned char overrun_err_rx PACKED; | ||
721 | unsigned char CRC_err PACKED; | ||
722 | unsigned char abort_frames_rx PACKED; | ||
723 | unsigned char frames_dropped_buf_full PACKED; | ||
724 | unsigned char abort_frames_tx PACKED; | ||
725 | unsigned char transmit_underruns PACKED; | ||
726 | unsigned char missed_tx_underruns_intr PACKED; | ||
727 | unsigned char reserved PACKED; | ||
728 | unsigned char DCD_drop PACKED; | ||
729 | unsigned char CTS_drop PACKED; | ||
730 | } read_comms_err_stats_t; | ||
731 | |||
732 | typedef struct trace_data { | ||
733 | unsigned short length PACKED; | ||
734 | unsigned char type PACKED; | ||
735 | unsigned char trace_dropped PACKED; | ||
736 | unsigned char reserved[5] PACKED; | ||
737 | unsigned short timestamp PACKED; | ||
738 | unsigned char data PACKED; | ||
739 | } trace_data_t; | ||
740 | |||
741 | enum {UDP_XPIPE_TYPE}; | ||
742 | |||
743 | #define XPIPE_ENABLE_TRACING 0x14 | ||
744 | #define XPIPE_DISABLE_TRACING 0x14 | ||
745 | #define XPIPE_GET_TRACE_INFO 0x16 | ||
746 | #define XPIPE_FT1_READ_STATUS 0x74 | ||
747 | #define XPIPE_DRIVER_STAT_IFSEND 0x75 | ||
748 | #define XPIPE_DRIVER_STAT_INTR 0x76 | ||
749 | #define XPIPE_DRIVER_STAT_GEN 0x77 | ||
750 | #define XPIPE_FLUSH_DRIVER_STATS 0x78 | ||
751 | #define XPIPE_ROUTER_UP_TIME 0x79 | ||
752 | #define XPIPE_SET_FT1_MODE 0x81 | ||
753 | #define XPIPE_FT1_STATUS_CTRL 0x80 | ||
754 | |||
755 | |||
756 | /* error messages */ | ||
757 | #define NO_BUFFS_OR_CLOSED_WIN 0x33 | ||
758 | #define DATA_LENGTH_TOO_BIG 0x32 | ||
759 | #define NO_DATA_AVAILABLE 0x33 | ||
760 | #define Z80_TIMEOUT_ERROR 0x0a | ||
761 | #define NO_BUFFS 0x08 | ||
762 | |||
763 | |||
764 | /* Trace options */ | ||
765 | #define TRACE_DEFAULT 0x03 | ||
766 | #define TRACE_SUPERVISOR_FRMS 0x10 | ||
767 | #define TRACE_ASYNC_FRMS 0x20 | ||
768 | #define TRACE_ALL_HDLC_FRMS 0x40 | ||
769 | #define TRACE_DATA_FRMS 0x08 | ||
770 | |||
771 | |||
772 | #endif /* _SDLA_X25_H */ | ||
diff --git a/include/linux/sdladrv.h b/include/linux/sdladrv.h deleted file mode 100644 index c85e103d5e7b..000000000000 --- a/include/linux/sdladrv.h +++ /dev/null | |||
@@ -1,66 +0,0 @@ | |||
1 | /***************************************************************************** | ||
2 | * sdladrv.h SDLA Support Module. Kernel API Definitions. | ||
3 | * | ||
4 | * Author: Gideon Hack | ||
5 | * | ||
6 | * Copyright: (c) 1995-2000 Sangoma Technologies Inc. | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License | ||
10 | * as published by the Free Software Foundation; either version | ||
11 | * 2 of the License, or (at your option) any later version. | ||
12 | * ============================================================================ | ||
13 | * Jun 02, 1999 Gideon Hack Added support for the S514 PCI adapter. | ||
14 | * Dec 11, 1996 Gene Kozin Complete overhaul. | ||
15 | * Oct 17, 1996 Gene Kozin Minor bug fixes. | ||
16 | * Jun 12, 1996 Gene Kozin Added support for S503 card. | ||
17 | * Dec 06, 1995 Gene Kozin Initial version. | ||
18 | *****************************************************************************/ | ||
19 | #ifndef _SDLADRV_H | ||
20 | #define _SDLADRV_H | ||
21 | |||
22 | |||
23 | #define SDLA_MAXIORANGE 4 /* maximum I/O port range */ | ||
24 | #define SDLA_WINDOWSIZE 0x2000 /* default dual-port memory window size */ | ||
25 | /****** Data Structures *****************************************************/ | ||
26 | |||
27 | /*---------------------------------------------------------------------------- | ||
28 | * Adapter hardware configuration. Pointer to this structure is passed to all | ||
29 | * APIs. | ||
30 | */ | ||
31 | typedef struct sdlahw | ||
32 | { | ||
33 | unsigned type; /* adapter type */ | ||
34 | unsigned fwid; /* firmware ID */ | ||
35 | unsigned port; /* adapter I/O port base */ | ||
36 | int irq; /* interrupt request level */ | ||
37 | char S514_cpu_no[1]; /* PCI CPU Number */ | ||
38 | unsigned char S514_slot_no; /* PCI Slot Number */ | ||
39 | char auto_pci_cfg; /* Autodetect PCI Slot */ | ||
40 | struct pci_dev *pci_dev; /* PCI device */ | ||
41 | void * dpmbase; /* dual-port memory base */ | ||
42 | unsigned dpmsize; /* dual-port memory size */ | ||
43 | unsigned pclk; /* CPU clock rate, kHz */ | ||
44 | unsigned long memory; /* memory size */ | ||
45 | unsigned long vector; /* local offset of the DPM window */ | ||
46 | unsigned io_range; /* I/O port range */ | ||
47 | unsigned char regs[SDLA_MAXIORANGE]; /* was written to registers */ | ||
48 | unsigned reserved[5]; | ||
49 | } sdlahw_t; | ||
50 | |||
51 | /****** Function Prototypes *************************************************/ | ||
52 | |||
53 | extern int sdla_setup (sdlahw_t* hw, void* sfm, unsigned len); | ||
54 | extern int sdla_down (sdlahw_t* hw); | ||
55 | extern void S514_intack (sdlahw_t* hw, u32 int_status); | ||
56 | extern void read_S514_int_stat (sdlahw_t* hw, u32* int_status); | ||
57 | extern int sdla_mapmem (sdlahw_t* hw, unsigned long addr); | ||
58 | extern int sdla_peek (sdlahw_t* hw, unsigned long addr, void* buf, | ||
59 | unsigned len); | ||
60 | extern int sdla_poke (sdlahw_t* hw, unsigned long addr, void* buf, | ||
61 | unsigned len); | ||
62 | extern int sdla_exec (void* opflag); | ||
63 | |||
64 | extern unsigned wanpipe_hw_probe(void); | ||
65 | |||
66 | #endif /* _SDLADRV_H */ | ||
diff --git a/include/linux/sdlapci.h b/include/linux/sdlapci.h deleted file mode 100644 index 6f7c904f188d..000000000000 --- a/include/linux/sdlapci.h +++ /dev/null | |||
@@ -1,72 +0,0 @@ | |||
1 | /***************************************************************************** | ||
2 | * sdlapci.h WANPIPE(tm) Multiprotocol WAN Link Driver. | ||
3 | * Definitions for the SDLA PCI adapter. | ||
4 | * | ||
5 | * Author: Gideon Hack <ghack@sangoma.com> | ||
6 | * | ||
7 | * Copyright: (c) 1999-2000 Sangoma Technologies Inc. | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or | ||
10 | * modify it under the terms of the GNU General Public License | ||
11 | * as published by the Free Software Foundation; either version | ||
12 | * 2 of the License, or (at your option) any later version. | ||
13 | * ============================================================================ | ||
14 | * Jun 02, 1999 Gideon Hack Initial version. | ||
15 | *****************************************************************************/ | ||
16 | #ifndef _SDLAPCI_H | ||
17 | #define _SDLAPCI_H | ||
18 | |||
19 | /****** Defines *************************************************************/ | ||
20 | |||
21 | /* Definitions for identifying and finding S514 PCI adapters */ | ||
22 | #define V3_VENDOR_ID 0x11B0 /* V3 vendor ID number */ | ||
23 | #define V3_DEVICE_ID 0x0002 /* V3 device ID number */ | ||
24 | #define SANGOMA_SUBSYS_VENDOR 0x4753 /* ID for Sangoma */ | ||
25 | #define PCI_DEV_SLOT_MASK 0x1F /* mask for slot numbering */ | ||
26 | #define PCI_IRQ_NOT_ALLOCATED 0xFF /* interrupt line for no IRQ */ | ||
27 | |||
28 | /* Local PCI register offsets */ | ||
29 | #define PCI_VENDOR_ID_WORD 0x00 /* vendor ID */ | ||
30 | #define PCI_IO_BASE_DWORD 0x10 /* IO base */ | ||
31 | #define PCI_MEM_BASE0_DWORD 0x14 /* memory base - apperture 0 */ | ||
32 | #define PCI_MEM_BASE1_DWORD 0x18 /* memory base - apperture 1 */ | ||
33 | #define PCI_SUBSYS_VENDOR_WORD 0x2C /* subsystem vendor ID */ | ||
34 | #define PCI_INT_LINE_BYTE 0x3C /* interrupt line */ | ||
35 | #define PCI_INT_PIN_BYTE 0x3D /* interrupt pin */ | ||
36 | #define PCI_MAP0_DWORD 0x40 /* PCI to local bus address 0 */ | ||
37 | #define PCI_MAP1_DWORD 0x44 /* PCI to local bus address 1 */ | ||
38 | #define PCI_INT_STATUS 0x48 /* interrupt status */ | ||
39 | #define PCI_INT_CONFIG 0x4C /* interrupt configuration */ | ||
40 | |||
41 | /* Local PCI register usage */ | ||
42 | #define PCI_MEMORY_ENABLE 0x00000003 /* enable PCI memory */ | ||
43 | #define PCI_CPU_A_MEM_DISABLE 0x00000002 /* disable CPU A memory */ | ||
44 | #define PCI_CPU_B_MEM_DISABLE 0x00100002 /* disable CPU B memory */ | ||
45 | #define PCI_ENABLE_IRQ_CPU_A 0x005A0004 /* enable IRQ for CPU A */ | ||
46 | #define PCI_ENABLE_IRQ_CPU_B 0x005A0008 /* enable IRQ for CPU B */ | ||
47 | #define PCI_DISABLE_IRQ_CPU_A 0x00000004 /* disable IRQ for CPU A */ | ||
48 | #define PCI_DISABLE_IRQ_CPU_B 0x00000008 /* disable IRQ for CPU B */ | ||
49 | |||
50 | /* Setting for the Interrupt Status register */ | ||
51 | #define IRQ_CPU_A 0x04 /* IRQ for CPU A */ | ||
52 | #define IRQ_CPU_B 0x08 /* IRQ for CPU B */ | ||
53 | |||
54 | /* The maximum size of the S514 memory */ | ||
55 | #define MAX_SIZEOF_S514_MEMORY (256 * 1024) | ||
56 | |||
57 | /* S514 control register offsets within the memory address space */ | ||
58 | #define S514_CTRL_REG_BYTE 0x80000 | ||
59 | |||
60 | /* S514 adapter control bytes */ | ||
61 | #define S514_CPU_HALT 0x00 | ||
62 | #define S514_CPU_START 0x01 | ||
63 | |||
64 | /* The maximum number of S514 adapters supported */ | ||
65 | #define MAX_S514_CARDS 20 | ||
66 | |||
67 | #define PCI_CARD_TYPE 0x2E | ||
68 | #define S514_DUAL_CPU 0x12 | ||
69 | #define S514_SINGLE_CPU 0x11 | ||
70 | |||
71 | #endif /* _SDLAPCI_H */ | ||
72 | |||
diff --git a/include/linux/sdlasfm.h b/include/linux/sdlasfm.h deleted file mode 100644 index 94aaa8ada667..000000000000 --- a/include/linux/sdlasfm.h +++ /dev/null | |||
@@ -1,104 +0,0 @@ | |||
1 | /***************************************************************************** | ||
2 | * sdlasfm.h WANPIPE(tm) Multiprotocol WAN Link Driver. | ||
3 | * Definitions for the SDLA Firmware Module (SFM). | ||
4 | * | ||
5 | * Author: Gideon Hack | ||
6 | * | ||
7 | * Copyright: (c) 1995-1999 Sangoma Technologies Inc. | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or | ||
10 | * modify it under the terms of the GNU General Public License | ||
11 | * as published by the Free Software Foundation; either version | ||
12 | * 2 of the License, or (at your option) any later version. | ||
13 | * ============================================================================ | ||
14 | * Jun 02, 1999 Gideon Hack Added support for the S514 adapter. | ||
15 | * Dec 11, 1996 Gene Kozin Cosmetic changes | ||
16 | * Apr 16, 1996 Gene Kozin Changed adapter & firmware IDs. Version 2 | ||
17 | * Dec 15, 1995 Gene Kozin Structures chaned | ||
18 | * Nov 09, 1995 Gene Kozin Initial version. | ||
19 | *****************************************************************************/ | ||
20 | #ifndef _SDLASFM_H | ||
21 | #define _SDLASFM_H | ||
22 | |||
23 | /****** Defines *************************************************************/ | ||
24 | |||
25 | #define SFM_VERSION 2 | ||
26 | #define SFM_SIGNATURE "SFM - Sangoma SDLA Firmware Module" | ||
27 | |||
28 | /* min/max */ | ||
29 | #define SFM_IMAGE_SIZE 0x8000 /* max size of SDLA code image file */ | ||
30 | #define SFM_DESCR_LEN 256 /* max length of description string */ | ||
31 | #define SFM_MAX_SDLA 16 /* max number of compatible adapters */ | ||
32 | |||
33 | /* Adapter types */ | ||
34 | #define SDLA_S502A 5020 | ||
35 | #define SDLA_S502E 5021 | ||
36 | #define SDLA_S503 5030 | ||
37 | #define SDLA_S508 5080 | ||
38 | #define SDLA_S507 5070 | ||
39 | #define SDLA_S509 5090 | ||
40 | #define SDLA_S514 5140 | ||
41 | |||
42 | /* S514 PCI adapter CPU numbers */ | ||
43 | #define S514_CPU_A 'A' | ||
44 | #define S514_CPU_B 'B' | ||
45 | |||
46 | |||
47 | /* Firmware identification numbers: | ||
48 | * 0 .. 999 Test & Diagnostics | ||
49 | * 1000 .. 1999 Streaming HDLC | ||
50 | * 2000 .. 2999 Bisync | ||
51 | * 3000 .. 3999 SDLC | ||
52 | * 4000 .. 4999 HDLC | ||
53 | * 5000 .. 5999 X.25 | ||
54 | * 6000 .. 6999 Frame Relay | ||
55 | * 7000 .. 7999 PPP | ||
56 | * 8000 .. 8999 Cisco HDLC | ||
57 | */ | ||
58 | #define SFID_CALIB502 200 | ||
59 | #define SFID_STRM502 1200 | ||
60 | #define SFID_STRM508 1800 | ||
61 | #define SFID_BSC502 2200 | ||
62 | #define SFID_SDLC502 3200 | ||
63 | #define SFID_HDLC502 4200 | ||
64 | #define SFID_HDLC508 4800 | ||
65 | #define SFID_X25_502 5200 | ||
66 | #define SFID_X25_508 5800 | ||
67 | #define SFID_FR502 6200 | ||
68 | #define SFID_FR508 6800 | ||
69 | #define SFID_PPP502 7200 | ||
70 | #define SFID_PPP508 7800 | ||
71 | #define SFID_PPP514 7140 | ||
72 | #define SFID_CHDLC508 8800 | ||
73 | #define SFID_CHDLC514 8140 | ||
74 | |||
75 | /****** Data Types **********************************************************/ | ||
76 | |||
77 | typedef struct sfm_info /* firmware module information */ | ||
78 | { | ||
79 | unsigned short codeid; /* firmware ID */ | ||
80 | unsigned short version; /* firmaware version number */ | ||
81 | unsigned short adapter[SFM_MAX_SDLA]; /* compatible adapter types */ | ||
82 | unsigned long memsize; /* minimum memory size */ | ||
83 | unsigned short reserved[2]; /* reserved */ | ||
84 | unsigned short startoffs; /* entry point offset */ | ||
85 | unsigned short winoffs; /* dual-port memory window offset */ | ||
86 | unsigned short codeoffs; /* code load offset */ | ||
87 | unsigned short codesize; /* code size */ | ||
88 | unsigned short dataoffs; /* configuration data load offset */ | ||
89 | unsigned short datasize; /* configuration data size */ | ||
90 | } sfm_info_t; | ||
91 | |||
92 | typedef struct sfm /* SDLA firmware file structire */ | ||
93 | { | ||
94 | char signature[80]; /* SFM file signature */ | ||
95 | unsigned short version; /* file format version */ | ||
96 | unsigned short checksum; /* info + image */ | ||
97 | unsigned short reserved[6]; /* reserved */ | ||
98 | char descr[SFM_DESCR_LEN]; /* description string */ | ||
99 | sfm_info_t info; /* firmware module info */ | ||
100 | unsigned char image[1]; /* code image (variable size) */ | ||
101 | } sfm_t; | ||
102 | |||
103 | #endif /* _SDLASFM_H */ | ||
104 | |||
diff --git a/include/linux/wanpipe.h b/include/linux/wanpipe.h deleted file mode 100644 index dae9860091dd..000000000000 --- a/include/linux/wanpipe.h +++ /dev/null | |||
@@ -1,483 +0,0 @@ | |||
1 | /***************************************************************************** | ||
2 | * wanpipe.h WANPIPE(tm) Multiprotocol WAN Link Driver. | ||
3 | * User-level API definitions. | ||
4 | * | ||
5 | * Author: Nenad Corbic <ncorbic@sangoma.com> | ||
6 | * Gideon Hack | ||
7 | * | ||
8 | * Copyright: (c) 1995-2000 Sangoma Technologies Inc. | ||
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 | * Nov 3, 2000 Nenad Corbic Added config_id to sdla_t structure. | ||
16 | * Used to determine the protocol running. | ||
17 | * Jul 13, 2000 Nenad Corbic Added SyncPPP Support | ||
18 | * Feb 24, 2000 Nenad Corbic Added support for x25api driver | ||
19 | * Oct 04, 1999 Nenad Corbic New CHDLC and FRAME RELAY code, SMP support | ||
20 | * Jun 02, 1999 Gideon Hack Added 'update_call_count' for Cisco HDLC | ||
21 | * support | ||
22 | * Jun 26, 1998 David Fong Added 'ip_mode' in sdla_t.u.p for dynamic IP | ||
23 | * routing mode configuration | ||
24 | * Jun 12, 1998 David Fong Added Cisco HDLC union member in sdla_t | ||
25 | * Dec 08, 1997 Jaspreet Singh Added 'authenticator' in union of 'sdla_t' | ||
26 | * Nov 26, 1997 Jaspreet Singh Added 'load_sharing' structure. Also added | ||
27 | * 'devs_struct','dev_to_devtint_next' to 'sdla_t' | ||
28 | * Nov 24, 1997 Jaspreet Singh Added 'irq_dis_if_send_count', | ||
29 | * 'irq_dis_poll_count' to 'sdla_t'. | ||
30 | * Nov 06, 1997 Jaspreet Singh Added a define called 'INTR_TEST_MODE' | ||
31 | * Oct 20, 1997 Jaspreet Singh Added 'buff_intr_mode_unbusy' and | ||
32 | * 'dlci_intr_mode_unbusy' to 'sdla_t' | ||
33 | * Oct 18, 1997 Jaspreet Singh Added structure to maintain global driver | ||
34 | * statistics. | ||
35 | * Jan 15, 1997 Gene Kozin Version 3.1.0 | ||
36 | * o added UDP management stuff | ||
37 | * Jan 02, 1997 Gene Kozin Version 3.0.0 | ||
38 | *****************************************************************************/ | ||
39 | #ifndef _WANPIPE_H | ||
40 | #define _WANPIPE_H | ||
41 | |||
42 | #include <linux/wanrouter.h> | ||
43 | |||
44 | /* Defines */ | ||
45 | |||
46 | #ifndef PACKED | ||
47 | #define PACKED __attribute__((packed)) | ||
48 | #endif | ||
49 | |||
50 | #define WANPIPE_MAGIC 0x414C4453L /* signature: 'SDLA' reversed */ | ||
51 | |||
52 | /* IOCTL numbers (up to 16) */ | ||
53 | #define WANPIPE_DUMP (ROUTER_USER+0) /* dump adapter's memory */ | ||
54 | #define WANPIPE_EXEC (ROUTER_USER+1) /* execute firmware command */ | ||
55 | |||
56 | #define TRACE_ALL 0x00 | ||
57 | #define TRACE_PROT 0x01 | ||
58 | #define TRACE_DATA 0x02 | ||
59 | |||
60 | /* values for request/reply byte */ | ||
61 | #define UDPMGMT_REQUEST 0x01 | ||
62 | #define UDPMGMT_REPLY 0x02 | ||
63 | #define UDP_OFFSET 12 | ||
64 | |||
65 | #define MAX_CMD_BUFF 10 | ||
66 | #define MAX_X25_LCN 255 /* Maximum number of x25 channels */ | ||
67 | #define MAX_LCN_NUM 4095 /* Maximum lcn number */ | ||
68 | #define MAX_FT1_RETRY 100 | ||
69 | |||
70 | #ifndef AF_WANPIPE | ||
71 | #define AF_WANPIPE 25 | ||
72 | #ifndef PF_WANPIPE | ||
73 | #define PF_WANPIPE AF_WANPIPE | ||
74 | #endif | ||
75 | #endif | ||
76 | |||
77 | |||
78 | #define TX_TIMEOUT 5*HZ | ||
79 | |||
80 | /* General Critical Flags */ | ||
81 | #define SEND_CRIT 0x00 | ||
82 | #define PERI_CRIT 0x01 | ||
83 | |||
84 | /* Chdlc and PPP polling critical flag */ | ||
85 | #define POLL_CRIT 0x03 | ||
86 | |||
87 | /* Frame Relay Tx IRQ send critical flag */ | ||
88 | #define SEND_TXIRQ_CRIT 0x02 | ||
89 | |||
90 | /* Frame Relay ARP critical flag */ | ||
91 | #define ARP_CRIT 0x03 | ||
92 | |||
93 | /* Bit maps for dynamic interface configuration | ||
94 | * DYN_OPT_ON : turns this option on/off | ||
95 | * DEV_DOWN : device was shutdown by the driver not | ||
96 | * by user | ||
97 | */ | ||
98 | #define DYN_OPT_ON 0x00 | ||
99 | #define DEV_DOWN 0x01 | ||
100 | |||
101 | /* | ||
102 | * Data structures for IOCTL calls. | ||
103 | */ | ||
104 | |||
105 | typedef struct sdla_dump /* WANPIPE_DUMP */ | ||
106 | { | ||
107 | unsigned long magic; /* for verification */ | ||
108 | unsigned long offset; /* absolute adapter memory address */ | ||
109 | unsigned long length; /* block length */ | ||
110 | void* ptr; /* -> buffer */ | ||
111 | } sdla_dump_t; | ||
112 | |||
113 | typedef struct sdla_exec /* WANPIPE_EXEC */ | ||
114 | { | ||
115 | unsigned long magic; /* for verification */ | ||
116 | void* cmd; /* -> command structure */ | ||
117 | void* data; /* -> data buffer */ | ||
118 | } sdla_exec_t; | ||
119 | |||
120 | /* UDP management stuff */ | ||
121 | |||
122 | typedef struct wum_header | ||
123 | { | ||
124 | unsigned char signature[8]; /* 00h: signature */ | ||
125 | unsigned char type; /* 08h: request/reply */ | ||
126 | unsigned char command; /* 09h: commnand */ | ||
127 | unsigned char reserved[6]; /* 0Ah: reserved */ | ||
128 | } wum_header_t; | ||
129 | |||
130 | /************************************************************************* | ||
131 | Data Structure for global statistics | ||
132 | *************************************************************************/ | ||
133 | |||
134 | typedef struct global_stats | ||
135 | { | ||
136 | unsigned long isr_entry; | ||
137 | unsigned long isr_already_critical; | ||
138 | unsigned long isr_rx; | ||
139 | unsigned long isr_tx; | ||
140 | unsigned long isr_intr_test; | ||
141 | unsigned long isr_spurious; | ||
142 | unsigned long isr_enable_tx_int; | ||
143 | unsigned long rx_intr_corrupt_rx_bfr; | ||
144 | unsigned long rx_intr_on_orphaned_DLCI; | ||
145 | unsigned long rx_intr_dev_not_started; | ||
146 | unsigned long tx_intr_dev_not_started; | ||
147 | unsigned long poll_entry; | ||
148 | unsigned long poll_already_critical; | ||
149 | unsigned long poll_processed; | ||
150 | unsigned long poll_tbusy_bad_status; | ||
151 | unsigned long poll_host_disable_irq; | ||
152 | unsigned long poll_host_enable_irq; | ||
153 | |||
154 | } global_stats_t; | ||
155 | |||
156 | |||
157 | typedef struct{ | ||
158 | unsigned short udp_src_port PACKED; | ||
159 | unsigned short udp_dst_port PACKED; | ||
160 | unsigned short udp_length PACKED; | ||
161 | unsigned short udp_checksum PACKED; | ||
162 | } udp_pkt_t; | ||
163 | |||
164 | |||
165 | typedef struct { | ||
166 | unsigned char ver_inet_hdr_length PACKED; | ||
167 | unsigned char service_type PACKED; | ||
168 | unsigned short total_length PACKED; | ||
169 | unsigned short identifier PACKED; | ||
170 | unsigned short flags_frag_offset PACKED; | ||
171 | unsigned char ttl PACKED; | ||
172 | unsigned char protocol PACKED; | ||
173 | unsigned short hdr_checksum PACKED; | ||
174 | unsigned long ip_src_address PACKED; | ||
175 | unsigned long ip_dst_address PACKED; | ||
176 | } ip_pkt_t; | ||
177 | |||
178 | |||
179 | typedef struct { | ||
180 | unsigned char signature[8] PACKED; | ||
181 | unsigned char request_reply PACKED; | ||
182 | unsigned char id PACKED; | ||
183 | unsigned char reserved[6] PACKED; | ||
184 | } wp_mgmt_t; | ||
185 | |||
186 | /************************************************************************* | ||
187 | Data Structure for if_send statistics | ||
188 | *************************************************************************/ | ||
189 | typedef struct if_send_stat{ | ||
190 | unsigned long if_send_entry; | ||
191 | unsigned long if_send_skb_null; | ||
192 | unsigned long if_send_broadcast; | ||
193 | unsigned long if_send_multicast; | ||
194 | unsigned long if_send_critical_ISR; | ||
195 | unsigned long if_send_critical_non_ISR; | ||
196 | unsigned long if_send_tbusy; | ||
197 | unsigned long if_send_tbusy_timeout; | ||
198 | unsigned long if_send_PIPE_request; | ||
199 | unsigned long if_send_wan_disconnected; | ||
200 | unsigned long if_send_dlci_disconnected; | ||
201 | unsigned long if_send_no_bfrs; | ||
202 | unsigned long if_send_adptr_bfrs_full; | ||
203 | unsigned long if_send_bfr_passed_to_adptr; | ||
204 | unsigned long if_send_protocol_error; | ||
205 | unsigned long if_send_bfr_not_passed_to_adptr; | ||
206 | unsigned long if_send_tx_int_enabled; | ||
207 | unsigned long if_send_consec_send_fail; | ||
208 | } if_send_stat_t; | ||
209 | |||
210 | typedef struct rx_intr_stat{ | ||
211 | unsigned long rx_intr_no_socket; | ||
212 | unsigned long rx_intr_dev_not_started; | ||
213 | unsigned long rx_intr_PIPE_request; | ||
214 | unsigned long rx_intr_bfr_not_passed_to_stack; | ||
215 | unsigned long rx_intr_bfr_passed_to_stack; | ||
216 | } rx_intr_stat_t; | ||
217 | |||
218 | typedef struct pipe_mgmt_stat{ | ||
219 | unsigned long UDP_PIPE_mgmt_kmalloc_err; | ||
220 | unsigned long UDP_PIPE_mgmt_direction_err; | ||
221 | unsigned long UDP_PIPE_mgmt_adptr_type_err; | ||
222 | unsigned long UDP_PIPE_mgmt_adptr_cmnd_OK; | ||
223 | unsigned long UDP_PIPE_mgmt_adptr_cmnd_timeout; | ||
224 | unsigned long UDP_PIPE_mgmt_adptr_send_passed; | ||
225 | unsigned long UDP_PIPE_mgmt_adptr_send_failed; | ||
226 | unsigned long UDP_PIPE_mgmt_not_passed_to_stack; | ||
227 | unsigned long UDP_PIPE_mgmt_passed_to_stack; | ||
228 | unsigned long UDP_PIPE_mgmt_no_socket; | ||
229 | unsigned long UDP_PIPE_mgmt_passed_to_adptr; | ||
230 | } pipe_mgmt_stat_t; | ||
231 | |||
232 | |||
233 | typedef struct { | ||
234 | struct sk_buff *skb; | ||
235 | } bh_data_t, cmd_data_t; | ||
236 | |||
237 | #define MAX_LGTH_UDP_MGNT_PKT 2000 | ||
238 | |||
239 | |||
240 | /* This is used for interrupt testing */ | ||
241 | #define INTR_TEST_MODE 0x02 | ||
242 | |||
243 | #define WUM_SIGNATURE_L 0x50495046 | ||
244 | #define WUM_SIGNATURE_H 0x444E3845 | ||
245 | |||
246 | #define WUM_KILL 0x50 | ||
247 | #define WUM_EXEC 0x51 | ||
248 | |||
249 | #define WANPIPE 0x00 | ||
250 | #define API 0x01 | ||
251 | #define BRIDGE 0x02 | ||
252 | #define BRIDGE_NODE 0x03 | ||
253 | |||
254 | #ifdef __KERNEL__ | ||
255 | /****** Kernel Interface ****************************************************/ | ||
256 | |||
257 | #include <linux/sdladrv.h> /* SDLA support module API definitions */ | ||
258 | #include <linux/sdlasfm.h> /* SDLA firmware module definitions */ | ||
259 | #include <linux/workqueue.h> | ||
260 | #include <linux/serial.h> | ||
261 | #include <linux/serialP.h> | ||
262 | #include <linux/serial_reg.h> | ||
263 | #include <asm/serial.h> | ||
264 | #include <linux/tty.h> | ||
265 | #include <linux/tty_driver.h> | ||
266 | #include <linux/tty_flip.h> | ||
267 | |||
268 | /****** Data Structures *****************************************************/ | ||
269 | |||
270 | /* Adapter Data Space. | ||
271 | * This structure is needed because we handle multiple cards, otherwise | ||
272 | * static data would do it. | ||
273 | */ | ||
274 | typedef struct sdla | ||
275 | { | ||
276 | char devname[WAN_DRVNAME_SZ+1]; /* card name */ | ||
277 | sdlahw_t hw; /* hardware configuration */ | ||
278 | struct wan_device wandev; /* WAN device data space */ | ||
279 | |||
280 | unsigned open_cnt; /* number of open interfaces */ | ||
281 | unsigned long state_tick; /* link state timestamp */ | ||
282 | unsigned intr_mode; /* Type of Interrupt Mode */ | ||
283 | char in_isr; /* interrupt-in-service flag */ | ||
284 | char buff_int_mode_unbusy; /* flag for carrying out dev_tint */ | ||
285 | char dlci_int_mode_unbusy; /* flag for carrying out dev_tint */ | ||
286 | long configured; /* flag for previous configurations */ | ||
287 | |||
288 | unsigned short irq_dis_if_send_count; /* Disabling irqs in if_send*/ | ||
289 | unsigned short irq_dis_poll_count; /* Disabling irqs in poll routine*/ | ||
290 | unsigned short force_enable_irq; | ||
291 | char TracingEnabled; /* flag for enabling trace */ | ||
292 | global_stats_t statistics; /* global statistics */ | ||
293 | void* mbox; /* -> mailbox */ | ||
294 | void* rxmb; /* -> receive mailbox */ | ||
295 | void* flags; /* -> adapter status flags */ | ||
296 | void (*isr)(struct sdla* card); /* interrupt service routine */ | ||
297 | void (*poll)(struct sdla* card); /* polling routine */ | ||
298 | int (*exec)(struct sdla* card, void* u_cmd, void* u_data); | ||
299 | /* Used by the listen() system call */ | ||
300 | /* Wanpipe Socket Interface */ | ||
301 | int (*func) (struct sk_buff *, struct sock *); | ||
302 | struct sock *sk; | ||
303 | |||
304 | /* Shutdown function */ | ||
305 | void (*disable_comm) (struct sdla *card); | ||
306 | |||
307 | /* Secondary Port Device: Piggibacking */ | ||
308 | struct sdla *next; | ||
309 | |||
310 | /* TTY driver variables */ | ||
311 | unsigned char tty_opt; | ||
312 | struct tty_struct *tty; | ||
313 | unsigned int tty_minor; | ||
314 | unsigned int tty_open; | ||
315 | unsigned char *tty_buf; | ||
316 | unsigned char *tty_rx; | ||
317 | struct work_struct tty_work; | ||
318 | |||
319 | union | ||
320 | { | ||
321 | struct | ||
322 | { /****** X.25 specific data **********/ | ||
323 | u32 lo_pvc; | ||
324 | u32 hi_pvc; | ||
325 | u32 lo_svc; | ||
326 | u32 hi_svc; | ||
327 | struct net_device *svc_to_dev_map[MAX_X25_LCN]; | ||
328 | struct net_device *pvc_to_dev_map[MAX_X25_LCN]; | ||
329 | struct net_device *tx_dev; | ||
330 | struct net_device *cmd_dev; | ||
331 | u32 no_dev; | ||
332 | volatile u8 *hdlc_buf_status; | ||
333 | u32 tx_interrupts_pending; | ||
334 | u16 timer_int_enabled; | ||
335 | struct net_device *poll_device; | ||
336 | atomic_t command_busy; | ||
337 | |||
338 | u16 udp_pkt_lgth; | ||
339 | u32 udp_type; | ||
340 | u8 udp_pkt_src; | ||
341 | u32 udp_lcn; | ||
342 | struct net_device *udp_dev; | ||
343 | s8 udp_pkt_data[MAX_LGTH_UDP_MGNT_PKT]; | ||
344 | |||
345 | u8 LAPB_hdlc; /* Option to turn off X25 and run only LAPB */ | ||
346 | u8 logging; /* Option to log call messages */ | ||
347 | u8 oob_on_modem; /* Option to send modem status to the api */ | ||
348 | u16 num_of_ch; /* Number of channels configured by the user */ | ||
349 | |||
350 | struct work_struct x25_poll_work; | ||
351 | struct timer_list x25_timer; | ||
352 | } x; | ||
353 | struct | ||
354 | { /****** frame relay specific data ***/ | ||
355 | void* rxmb_base; /* -> first Rx buffer */ | ||
356 | void* rxmb_last; /* -> last Rx buffer */ | ||
357 | unsigned rx_base; /* S508 receive buffer base */ | ||
358 | unsigned rx_top; /* S508 receive buffer end */ | ||
359 | unsigned short node_dlci[100]; | ||
360 | unsigned short dlci_num; | ||
361 | struct net_device *dlci_to_dev_map[991 + 1]; | ||
362 | unsigned tx_interrupts_pending; | ||
363 | unsigned short timer_int_enabled; | ||
364 | unsigned short udp_pkt_lgth; | ||
365 | int udp_type; | ||
366 | char udp_pkt_src; | ||
367 | unsigned udp_dlci; | ||
368 | char udp_pkt_data[MAX_LGTH_UDP_MGNT_PKT]; | ||
369 | void* trc_el_base; /* first trace element */ | ||
370 | void* trc_el_last; /* last trace element */ | ||
371 | void *curr_trc_el; /* current trace element */ | ||
372 | unsigned short trc_bfr_space; /* trace buffer space */ | ||
373 | unsigned char update_comms_stats; | ||
374 | struct net_device *arp_dev; | ||
375 | spinlock_t if_send_lock; | ||
376 | } f; | ||
377 | struct /****** PPP-specific data ***********/ | ||
378 | { | ||
379 | char if_name[WAN_IFNAME_SZ+1]; /* interface name */ | ||
380 | void* txbuf; /* -> current Tx buffer */ | ||
381 | void* txbuf_base; /* -> first Tx buffer */ | ||
382 | void* txbuf_last; /* -> last Tx buffer */ | ||
383 | void* rxbuf_base; /* -> first Rx buffer */ | ||
384 | void* rxbuf_last; /* -> last Rx buffer */ | ||
385 | unsigned rx_base; /* S508 receive buffer base */ | ||
386 | unsigned rx_top; /* S508 receive buffer end */ | ||
387 | char ip_mode; /* STATIC/HOST/PEER IP Mode */ | ||
388 | char authenticator; /* Authenticator for PAP/CHAP */ | ||
389 | unsigned char comm_enabled; /* Is comm enabled or not */ | ||
390 | unsigned char peer_route; /* Process Peer Route */ | ||
391 | unsigned long *txbuf_next; /* Next Tx buffer to use */ | ||
392 | unsigned long *rxbuf_next; /* Next Rx buffer to use */ | ||
393 | } p; | ||
394 | struct /* Cisco HDLC-specific data */ | ||
395 | { | ||
396 | char if_name[WAN_IFNAME_SZ+1]; /* interface name */ | ||
397 | unsigned char comm_port;/* Communication Port O or 1 */ | ||
398 | unsigned char usedby; /* Used by WANPIPE or API */ | ||
399 | void* rxmb; /* Receive mail box */ | ||
400 | void* flags; /* flags */ | ||
401 | void* tx_status; /* Tx status element */ | ||
402 | void* rx_status; /* Rx status element */ | ||
403 | void* txbuf; /* -> current Tx buffer */ | ||
404 | void* txbuf_base; /* -> first Tx buffer */ | ||
405 | void* txbuf_last; /* -> last Tx buffer */ | ||
406 | void* rxbuf_base; /* -> first Rx buffer */ | ||
407 | void* rxbuf_last; /* -> last Rx buffer */ | ||
408 | unsigned rx_base; /* S508 receive buffer base */ | ||
409 | unsigned rx_top; /* S508 receive buffer end */ | ||
410 | unsigned char receive_only; /* high speed receivers */ | ||
411 | unsigned short protocol_options; | ||
412 | unsigned short kpalv_tx; /* Tx kpalv timer */ | ||
413 | unsigned short kpalv_rx; /* Rx kpalv timer */ | ||
414 | unsigned short kpalv_err; /* Error tolerance */ | ||
415 | unsigned short slarp_timer; /* SLARP req timer */ | ||
416 | unsigned state; /* state of the link */ | ||
417 | unsigned char api_status; | ||
418 | unsigned char update_call_count; | ||
419 | unsigned short api_options; /* for async config */ | ||
420 | unsigned char async_mode; | ||
421 | unsigned short tx_bits_per_char; | ||
422 | unsigned short rx_bits_per_char; | ||
423 | unsigned short stop_bits; | ||
424 | unsigned short parity; | ||
425 | unsigned short break_timer; | ||
426 | unsigned short inter_char_timer; | ||
427 | unsigned short rx_complete_length; | ||
428 | unsigned short xon_char; | ||
429 | unsigned short xoff_char; | ||
430 | unsigned char comm_enabled; /* Is comm enabled or not */ | ||
431 | unsigned char backup; | ||
432 | } c; | ||
433 | struct | ||
434 | { | ||
435 | void* tx_status; /* Tx status element */ | ||
436 | void* rx_status; /* Rx status element */ | ||
437 | void* trace_status; /* Trace status element */ | ||
438 | void* txbuf; /* -> current Tx buffer */ | ||
439 | void* txbuf_base; /* -> first Tx buffer */ | ||
440 | void* txbuf_last; /* -> last Tx buffer */ | ||
441 | void* rxbuf_base; /* -> first Rx buffer */ | ||
442 | void* rxbuf_last; /* -> last Rx buffer */ | ||
443 | void* tracebuf; /* -> current Trace buffer */ | ||
444 | void* tracebuf_base; /* -> current Trace buffer */ | ||
445 | void* tracebuf_last; /* -> current Trace buffer */ | ||
446 | unsigned rx_base; /* receive buffer base */ | ||
447 | unsigned rx_end; /* receive buffer end */ | ||
448 | unsigned trace_base; /* trace buffer base */ | ||
449 | unsigned trace_end; /* trace buffer end */ | ||
450 | |||
451 | } h; | ||
452 | } u; | ||
453 | } sdla_t; | ||
454 | |||
455 | /****** Public Functions ****************************************************/ | ||
456 | |||
457 | void wanpipe_open (sdla_t* card); /* wpmain.c */ | ||
458 | void wanpipe_close (sdla_t* card); /* wpmain.c */ | ||
459 | void wanpipe_set_state (sdla_t* card, int state); /* wpmain.c */ | ||
460 | |||
461 | int wpx_init (sdla_t* card, wandev_conf_t* conf); /* wpx.c */ | ||
462 | int wpf_init (sdla_t* card, wandev_conf_t* conf); /* wpf.c */ | ||
463 | int wpp_init (sdla_t* card, wandev_conf_t* conf); /* wpp.c */ | ||
464 | int wpc_init (sdla_t* card, wandev_conf_t* conf); /* Cisco HDLC */ | ||
465 | int bsc_init (sdla_t* card, wandev_conf_t* conf); /* BSC streaming */ | ||
466 | int hdlc_init(sdla_t* card, wandev_conf_t* conf); /* HDLC support */ | ||
467 | int wpft1_init (sdla_t* card, wandev_conf_t* conf); /* FT1 Config support */ | ||
468 | int wsppp_init (sdla_t* card, wandev_conf_t* conf); /* Sync PPP on top of RAW CHDLC */ | ||
469 | |||
470 | extern sdla_t * wanpipe_find_card(char *); | ||
471 | extern sdla_t * wanpipe_find_card_num (int); | ||
472 | |||
473 | extern void wanpipe_queue_work (struct work_struct *); | ||
474 | extern void wanpipe_mark_bh (void); | ||
475 | extern void wakeup_sk_bh(struct net_device *dev); | ||
476 | extern int change_dev_flags(struct net_device *dev, unsigned flags); | ||
477 | extern unsigned long get_ip_address(struct net_device *dev, int option); | ||
478 | extern void add_gateway(sdla_t *card, struct net_device *dev); | ||
479 | |||
480 | |||
481 | #endif /* __KERNEL__ */ | ||
482 | #endif /* _WANPIPE_H */ | ||
483 | |||
diff --git a/net/wanrouter/af_wanpipe.c b/net/wanrouter/af_wanpipe.c index 8b9bf4a763b5..b1265187b4a8 100644 --- a/net/wanrouter/af_wanpipe.c +++ b/net/wanrouter/af_wanpipe.c | |||
@@ -55,12 +55,10 @@ | |||
55 | #include <asm/uaccess.h> | 55 | #include <asm/uaccess.h> |
56 | #include <linux/module.h> | 56 | #include <linux/module.h> |
57 | #include <linux/init.h> | 57 | #include <linux/init.h> |
58 | #include <linux/wanpipe.h> | ||
59 | #include <linux/if_wanpipe.h> | 58 | #include <linux/if_wanpipe.h> |
60 | #include <linux/pkt_sched.h> | 59 | #include <linux/pkt_sched.h> |
61 | #include <linux/tcp_states.h> | 60 | #include <linux/tcp_states.h> |
62 | #include <linux/if_wanpipe_common.h> | 61 | #include <linux/if_wanpipe_common.h> |
63 | #include <linux/sdla_x25.h> | ||
64 | 62 | ||
65 | #ifdef CONFIG_INET | 63 | #ifdef CONFIG_INET |
66 | #include <net/inet_common.h> | 64 | #include <net/inet_common.h> |