diff options
Diffstat (limited to 'drivers/net/wan/sdla_fr.c')
-rw-r--r-- | drivers/net/wan/sdla_fr.c | 5061 |
1 files changed, 0 insertions, 5061 deletions
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 *****************************************************************/ | ||