diff options
Diffstat (limited to 'drivers/net/wan/sdla_fr.c')
-rw-r--r-- | drivers/net/wan/sdla_fr.c | 5068 |
1 files changed, 5068 insertions, 0 deletions
diff --git a/drivers/net/wan/sdla_fr.c b/drivers/net/wan/sdla_fr.c new file mode 100644 index 000000000000..2efccb0554c0 --- /dev/null +++ b/drivers/net/wan/sdla_fr.c | |||
@@ -0,0 +1,5068 @@ | |||
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 <asm/errno.h> | ||
156 | |||
157 | #include <linux/ip.h> | ||
158 | #include <linux/if.h> | ||
159 | |||
160 | #include <linux/if_wanpipe_common.h> /* Wanpipe Socket */ | ||
161 | #include <linux/if_wanpipe.h> | ||
162 | |||
163 | #include <linux/sdla_fr.h> /* frame relay firmware API definitions */ | ||
164 | |||
165 | #include <asm/uaccess.h> | ||
166 | #include <linux/inetdevice.h> | ||
167 | #include <linux/netdevice.h> | ||
168 | |||
169 | #include <net/route.h> /* Dynamic Route Creation */ | ||
170 | #include <linux/etherdevice.h> /* eth_type_trans() used for bridging */ | ||
171 | #include <linux/random.h> | ||
172 | |||
173 | /****** Defines & Macros ****************************************************/ | ||
174 | |||
175 | #define MAX_CMD_RETRY 10 /* max number of firmware retries */ | ||
176 | |||
177 | #define FR_HEADER_LEN 8 /* max encapsulation header size */ | ||
178 | #define FR_CHANNEL_MTU 1500 /* unfragmented logical channel MTU */ | ||
179 | |||
180 | /* Q.922 frame types */ | ||
181 | #define Q922_UI 0x03 /* Unnumbered Info frame */ | ||
182 | #define Q922_XID 0xAF | ||
183 | |||
184 | /* DLCI configured or not */ | ||
185 | #define DLCI_NOT_CONFIGURED 0x00 | ||
186 | #define DLCI_CONFIG_PENDING 0x01 | ||
187 | #define DLCI_CONFIGURED 0x02 | ||
188 | |||
189 | /* CIR enabled or not */ | ||
190 | #define CIR_ENABLED 0x00 | ||
191 | #define CIR_DISABLED 0x01 | ||
192 | |||
193 | #define FRAME_RELAY_API 1 | ||
194 | #define MAX_BH_BUFF 10 | ||
195 | |||
196 | /* For handle_IPXWAN() */ | ||
197 | #define CVHexToAscii(b) (((unsigned char)(b) > (unsigned char)9) ? ((unsigned char)'A' + ((unsigned char)(b) - (unsigned char)10)) : ((unsigned char)'0' + (unsigned char)(b))) | ||
198 | |||
199 | /****** Data Structures *****************************************************/ | ||
200 | |||
201 | /* This is an extention of the 'struct device' we create for each network | ||
202 | * interface to keep the rest of channel-specific data. | ||
203 | */ | ||
204 | typedef struct fr_channel | ||
205 | { | ||
206 | wanpipe_common_t common; | ||
207 | char name[WAN_IFNAME_SZ+1]; /* interface name, ASCIIZ */ | ||
208 | unsigned dlci_configured ; /* check whether configured or not */ | ||
209 | unsigned cir_status; /* check whether CIR enabled or not */ | ||
210 | unsigned dlci; /* logical channel number */ | ||
211 | unsigned cir; /* committed information rate */ | ||
212 | unsigned bc; /* committed burst size */ | ||
213 | unsigned be; /* excess burst size */ | ||
214 | unsigned mc; /* multicast support on or off */ | ||
215 | unsigned tx_int_status; /* Transmit Interrupt Status */ | ||
216 | unsigned short pkt_length; /* Packet Length */ | ||
217 | unsigned long router_start_time;/* Router start time in seconds */ | ||
218 | unsigned long tick_counter; /* counter for transmit time out */ | ||
219 | char dev_pending_devtint; /* interface pending dev_tint() */ | ||
220 | void *dlci_int_interface; /* pointer to the DLCI Interface */ | ||
221 | unsigned long IB_addr; /* physical address of Interface Byte */ | ||
222 | unsigned long state_tick; /* time of the last state change */ | ||
223 | unsigned char enable_IPX; /* Enable/Disable the use of IPX */ | ||
224 | unsigned long network_number; /* Internal Network Number for IPX*/ | ||
225 | sdla_t *card; /* -> owner */ | ||
226 | unsigned route_flag; /* Add/Rem dest addr in route tables */ | ||
227 | unsigned inarp; /* Inverse Arp Request status */ | ||
228 | long inarp_ready; /* Ready to send requests */ | ||
229 | int inarp_interval; /* Time between InArp Requests */ | ||
230 | unsigned long inarp_tick; /* InArp jiffies tick counter */ | ||
231 | long interface_down; /* Bring interface down on disconnect */ | ||
232 | struct net_device_stats ifstats; /* interface statistics */ | ||
233 | if_send_stat_t drvstats_if_send; | ||
234 | rx_intr_stat_t drvstats_rx_intr; | ||
235 | pipe_mgmt_stat_t drvstats_gen; | ||
236 | unsigned long router_up_time; | ||
237 | |||
238 | unsigned short transmit_length; | ||
239 | struct sk_buff *delay_skb; | ||
240 | |||
241 | bh_data_t *bh_head; /* Circular buffer for chdlc_bh */ | ||
242 | unsigned long tq_working; | ||
243 | volatile int bh_write; | ||
244 | volatile int bh_read; | ||
245 | atomic_t bh_buff_used; | ||
246 | |||
247 | /* Polling task queue. Each interface | ||
248 | * has its own task queue, which is used | ||
249 | * to defer events from the interrupt */ | ||
250 | struct work_struct fr_poll_work; | ||
251 | struct timer_list fr_arp_timer; | ||
252 | |||
253 | u32 ip_local; | ||
254 | u32 ip_remote; | ||
255 | long config_dlci; | ||
256 | long unconfig_dlci; | ||
257 | |||
258 | /* Whether this interface should be setup as a gateway. | ||
259 | * Used by dynamic route setup code */ | ||
260 | u8 gateway; | ||
261 | |||
262 | /* True interface type */ | ||
263 | u8 true_if_encoding; | ||
264 | u8 fr_header[FR_HEADER_LEN]; | ||
265 | char fr_header_len; | ||
266 | |||
267 | } fr_channel_t; | ||
268 | |||
269 | /* Route Flag options */ | ||
270 | #define NO_ROUTE 0x00 | ||
271 | #define ADD_ROUTE 0x01 | ||
272 | #define ROUTE_ADDED 0x02 | ||
273 | #define REMOVE_ROUTE 0x03 | ||
274 | #define ARP_REQ 0x04 | ||
275 | |||
276 | /* inarp options */ | ||
277 | #define INARP_NONE 0x00 | ||
278 | #define INARP_REQUEST 0x01 | ||
279 | #define INARP_CONFIGURED 0x02 | ||
280 | |||
281 | /* reasons for enabling the timer interrupt on the adapter */ | ||
282 | #define TMR_INT_ENABLED_UDP 0x01 | ||
283 | #define TMR_INT_ENABLED_UPDATE 0x02 | ||
284 | #define TMR_INT_ENABLED_ARP 0x04 | ||
285 | #define TMR_INT_ENABLED_UPDATE_STATE 0x08 | ||
286 | #define TMR_INT_ENABLED_CONFIG 0x10 | ||
287 | #define TMR_INT_ENABLED_UNCONFIG 0x20 | ||
288 | |||
289 | |||
290 | typedef struct dlci_status | ||
291 | { | ||
292 | unsigned short dlci PACKED; | ||
293 | unsigned char state PACKED; | ||
294 | } dlci_status_t; | ||
295 | |||
296 | typedef struct dlci_IB_mapping | ||
297 | { | ||
298 | unsigned short dlci PACKED; | ||
299 | unsigned long addr_value PACKED; | ||
300 | } dlci_IB_mapping_t; | ||
301 | |||
302 | /* This structure is used for DLCI list Tx interrupt mode. It is used to | ||
303 | enable interrupt bit and set the packet length for transmission | ||
304 | */ | ||
305 | typedef struct fr_dlci_interface | ||
306 | { | ||
307 | unsigned char gen_interrupt PACKED; | ||
308 | unsigned short packet_length PACKED; | ||
309 | unsigned char reserved PACKED; | ||
310 | } fr_dlci_interface_t; | ||
311 | |||
312 | /* variable for keeping track of enabling/disabling FT1 monitor status */ | ||
313 | static int rCount = 0; | ||
314 | |||
315 | extern void disable_irq(unsigned int); | ||
316 | extern void enable_irq(unsigned int); | ||
317 | |||
318 | /* variable for keeping track of number of interrupts generated during | ||
319 | * interrupt test routine | ||
320 | */ | ||
321 | static int Intr_test_counter; | ||
322 | |||
323 | /****** Function Prototypes *************************************************/ | ||
324 | |||
325 | /* WAN link driver entry points. These are called by the WAN router module. */ | ||
326 | static int update(struct wan_device *wandev); | ||
327 | static int new_if(struct wan_device *wandev, struct net_device *dev, | ||
328 | wanif_conf_t *conf); | ||
329 | static int del_if(struct wan_device *wandev, struct net_device *dev); | ||
330 | static void disable_comm (sdla_t *card); | ||
331 | |||
332 | /* WANPIPE-specific entry points */ | ||
333 | static int wpf_exec(struct sdla *card, void *u_cmd, void *u_data); | ||
334 | |||
335 | /* Network device interface */ | ||
336 | static int if_init(struct net_device *dev); | ||
337 | static int if_open(struct net_device *dev); | ||
338 | static int if_close(struct net_device *dev); | ||
339 | |||
340 | static void if_tx_timeout(struct net_device *dev); | ||
341 | |||
342 | static int if_rebuild_hdr (struct sk_buff *skb); | ||
343 | |||
344 | static int if_send(struct sk_buff *skb, struct net_device *dev); | ||
345 | static int chk_bcast_mcast_addr(sdla_t *card, struct net_device* dev, | ||
346 | struct sk_buff *skb); | ||
347 | static struct net_device_stats *if_stats(struct net_device *dev); | ||
348 | |||
349 | /* Interrupt handlers */ | ||
350 | static void fr_isr(sdla_t *card); | ||
351 | static void rx_intr(sdla_t *card); | ||
352 | static void tx_intr(sdla_t *card); | ||
353 | static void timer_intr(sdla_t *card); | ||
354 | static void spur_intr(sdla_t *card); | ||
355 | |||
356 | /* Frame relay firmware interface functions */ | ||
357 | static int fr_read_version(sdla_t *card, char *str); | ||
358 | static int fr_configure(sdla_t *card, fr_conf_t *conf); | ||
359 | static int fr_dlci_configure(sdla_t *card, fr_dlc_conf_t *conf, unsigned dlci); | ||
360 | static int fr_init_dlci (sdla_t *card, fr_channel_t *chan); | ||
361 | static int fr_set_intr_mode (sdla_t *card, unsigned mode, unsigned mtu, unsigned short timeout); | ||
362 | static int fr_comm_enable(sdla_t *card); | ||
363 | static void fr_comm_disable(sdla_t *card); | ||
364 | static int fr_get_err_stats(sdla_t *card); | ||
365 | static int fr_get_stats(sdla_t *card); | ||
366 | static int fr_add_dlci(sdla_t *card, int dlci); | ||
367 | static int fr_activate_dlci(sdla_t *card, int dlci); | ||
368 | static int fr_delete_dlci (sdla_t* card, int dlci); | ||
369 | static int fr_issue_isf(sdla_t *card, int isf); | ||
370 | static int fr_send(sdla_t *card, int dlci, unsigned char attr, int len, | ||
371 | void *buf); | ||
372 | static int fr_send_data_header(sdla_t *card, int dlci, unsigned char attr, int len, | ||
373 | void *buf,unsigned char hdr_len); | ||
374 | static unsigned int fr_send_hdr(sdla_t *card, int dlci, unsigned int offset); | ||
375 | |||
376 | static int check_dlci_config (sdla_t *card, fr_channel_t *chan); | ||
377 | static void initialize_rx_tx_buffers (sdla_t *card); | ||
378 | |||
379 | |||
380 | /* Firmware asynchronous event handlers */ | ||
381 | static int fr_event(sdla_t *card, int event, fr_mbox_t *mbox); | ||
382 | static int fr_modem_failure(sdla_t *card, fr_mbox_t *mbox); | ||
383 | static int fr_dlci_change(sdla_t *card, fr_mbox_t *mbox); | ||
384 | |||
385 | /* Miscellaneous functions */ | ||
386 | static int update_chan_state(struct net_device *dev); | ||
387 | static void set_chan_state(struct net_device *dev, int state); | ||
388 | static struct net_device *find_channel(sdla_t *card, unsigned dlci); | ||
389 | static int is_tx_ready(sdla_t *card, fr_channel_t *chan); | ||
390 | static unsigned int dec_to_uint(unsigned char *str, int len); | ||
391 | static int reply_udp( unsigned char *data, unsigned int mbox_len ); | ||
392 | |||
393 | static int intr_test( sdla_t* card ); | ||
394 | static void init_chan_statistics( fr_channel_t* chan ); | ||
395 | static void init_global_statistics( sdla_t* card ); | ||
396 | static void read_DLCI_IB_mapping( sdla_t* card, fr_channel_t* chan ); | ||
397 | static int setup_for_delayed_transmit(struct net_device* dev, | ||
398 | struct sk_buff *skb); | ||
399 | |||
400 | struct net_device *move_dev_to_next(sdla_t *card, struct net_device *dev); | ||
401 | static int check_tx_status(sdla_t *card, struct net_device *dev); | ||
402 | |||
403 | /* Frame Relay Socket API */ | ||
404 | static void trigger_fr_bh (fr_channel_t *); | ||
405 | static void fr_bh(struct net_device *dev); | ||
406 | static int fr_bh_cleanup(struct net_device *dev); | ||
407 | static int bh_enqueue(struct net_device *dev, struct sk_buff *skb); | ||
408 | |||
409 | static void trigger_fr_poll(struct net_device *dev); | ||
410 | static void fr_poll(struct net_device *dev); | ||
411 | //static void add_gateway(struct net_device *dev); | ||
412 | |||
413 | static void trigger_unconfig_fr(struct net_device *dev); | ||
414 | static void unconfig_fr (sdla_t *); | ||
415 | |||
416 | static void trigger_config_fr (sdla_t *); | ||
417 | static void config_fr (sdla_t *); | ||
418 | |||
419 | |||
420 | /* Inverse ARP and Dynamic routing functions */ | ||
421 | int process_ARP(arphdr_1490_t *ArpPacket, sdla_t *card, struct net_device *dev); | ||
422 | int is_arp(void *buf); | ||
423 | int send_inarp_request(sdla_t *card, struct net_device *dev); | ||
424 | |||
425 | static void trigger_fr_arp(struct net_device *dev); | ||
426 | static void fr_arp (unsigned long data); | ||
427 | |||
428 | |||
429 | /* Udp management functions */ | ||
430 | static int process_udp_mgmt_pkt(sdla_t *card); | ||
431 | static int udp_pkt_type( struct sk_buff *skb, sdla_t *card ); | ||
432 | static int store_udp_mgmt_pkt(int udp_type, char udp_pkt_src, sdla_t* card, | ||
433 | struct sk_buff *skb, int dlci); | ||
434 | |||
435 | /* IPX functions */ | ||
436 | static void switch_net_numbers(unsigned char *sendpacket, | ||
437 | unsigned long network_number, unsigned char incoming); | ||
438 | |||
439 | static int handle_IPXWAN(unsigned char *sendpacket, char *devname, | ||
440 | unsigned char enable_IPX, unsigned long network_number); | ||
441 | |||
442 | /* Lock Functions: SMP supported */ | ||
443 | void s508_s514_unlock(sdla_t *card, unsigned long *smp_flags); | ||
444 | void s508_s514_lock(sdla_t *card, unsigned long *smp_flags); | ||
445 | |||
446 | unsigned short calc_checksum (char *, int); | ||
447 | static int setup_fr_header(struct sk_buff** skb, | ||
448 | struct net_device* dev, char op_mode); | ||
449 | |||
450 | |||
451 | /****** Public Functions ****************************************************/ | ||
452 | |||
453 | /*============================================================================ | ||
454 | * Frame relay protocol initialization routine. | ||
455 | * | ||
456 | * This routine is called by the main WANPIPE module during setup. At this | ||
457 | * point adapter is completely initialized and firmware is running. | ||
458 | * o read firmware version (to make sure it's alive) | ||
459 | * o configure adapter | ||
460 | * o initialize protocol-specific fields of the adapter data space. | ||
461 | * | ||
462 | * Return: 0 o.k. | ||
463 | * < 0 failure. | ||
464 | */ | ||
465 | int wpf_init(sdla_t *card, wandev_conf_t *conf) | ||
466 | { | ||
467 | |||
468 | int err; | ||
469 | fr508_flags_t* flags; | ||
470 | |||
471 | union | ||
472 | { | ||
473 | char str[80]; | ||
474 | fr_conf_t cfg; | ||
475 | } u; | ||
476 | |||
477 | fr_buf_info_t* buf_info; | ||
478 | int i; | ||
479 | |||
480 | |||
481 | printk(KERN_INFO "\n"); | ||
482 | |||
483 | /* Verify configuration ID */ | ||
484 | if (conf->config_id != WANCONFIG_FR) { | ||
485 | |||
486 | printk(KERN_INFO "%s: invalid configuration ID %u!\n", | ||
487 | card->devname, conf->config_id); | ||
488 | return -EINVAL; | ||
489 | |||
490 | } | ||
491 | |||
492 | /* Initialize protocol-specific fields of adapter data space */ | ||
493 | switch (card->hw.fwid) { | ||
494 | |||
495 | case SFID_FR508: | ||
496 | card->mbox = (void*)(card->hw.dpmbase + | ||
497 | FR508_MBOX_OFFS); | ||
498 | card->flags = (void*)(card->hw.dpmbase + | ||
499 | FR508_FLAG_OFFS); | ||
500 | if(card->hw.type == SDLA_S514) { | ||
501 | card->mbox += FR_MB_VECTOR; | ||
502 | card->flags += FR_MB_VECTOR; | ||
503 | } | ||
504 | card->isr = &fr_isr; | ||
505 | break; | ||
506 | |||
507 | default: | ||
508 | return -EINVAL; | ||
509 | } | ||
510 | |||
511 | flags = card->flags; | ||
512 | |||
513 | /* Read firmware version. Note that when adapter initializes, it | ||
514 | * clears the mailbox, so it may appear that the first command was | ||
515 | * executed successfully when in fact it was merely erased. To work | ||
516 | * around this, we execute the first command twice. | ||
517 | */ | ||
518 | |||
519 | if (fr_read_version(card, NULL) || fr_read_version(card, u.str)) | ||
520 | return -EIO; | ||
521 | |||
522 | printk(KERN_INFO "%s: running frame relay firmware v%s\n", | ||
523 | card->devname, u.str); | ||
524 | |||
525 | /* Adjust configuration */ | ||
526 | conf->mtu += FR_HEADER_LEN; | ||
527 | conf->mtu = (conf->mtu >= MIN_LGTH_FR_DATA_CFG) ? | ||
528 | min_t(unsigned int, conf->mtu, FR_MAX_NO_DATA_BYTES_IN_FRAME) : | ||
529 | FR_CHANNEL_MTU + FR_HEADER_LEN; | ||
530 | |||
531 | conf->bps = min_t(unsigned int, conf->bps, 2048000); | ||
532 | |||
533 | /* Initialze the configuration structure sent to the board to zero */ | ||
534 | memset(&u.cfg, 0, sizeof(u.cfg)); | ||
535 | |||
536 | memset(card->u.f.dlci_to_dev_map, 0, sizeof(card->u.f.dlci_to_dev_map)); | ||
537 | |||
538 | /* Configure adapter firmware */ | ||
539 | |||
540 | u.cfg.mtu = conf->mtu; | ||
541 | u.cfg.kbps = conf->bps / 1000; | ||
542 | |||
543 | u.cfg.cir_fwd = u.cfg.cir_bwd = 16; | ||
544 | u.cfg.bc_fwd = u.cfg.bc_bwd = 16; | ||
545 | |||
546 | u.cfg.options = 0x0000; | ||
547 | printk(KERN_INFO "%s: Global CIR enabled by Default\n", card->devname); | ||
548 | |||
549 | switch (conf->u.fr.signalling) { | ||
550 | |||
551 | case WANOPT_FR_ANSI: | ||
552 | u.cfg.options = 0x0000; | ||
553 | break; | ||
554 | |||
555 | case WANOPT_FR_Q933: | ||
556 | u.cfg.options |= 0x0200; | ||
557 | break; | ||
558 | |||
559 | case WANOPT_FR_LMI: | ||
560 | u.cfg.options |= 0x0400; | ||
561 | break; | ||
562 | |||
563 | case WANOPT_NO: | ||
564 | u.cfg.options |= 0x0800; | ||
565 | break; | ||
566 | default: | ||
567 | printk(KERN_INFO "%s: Illegal Signalling option\n", | ||
568 | card->wandev.name); | ||
569 | return -EINVAL; | ||
570 | } | ||
571 | |||
572 | |||
573 | card->wandev.signalling = conf->u.fr.signalling; | ||
574 | |||
575 | if (conf->station == WANOPT_CPE) { | ||
576 | |||
577 | |||
578 | if (conf->u.fr.signalling == WANOPT_NO){ | ||
579 | printk(KERN_INFO | ||
580 | "%s: ERROR - For NO signalling, station must be set to Node!", | ||
581 | card->devname); | ||
582 | return -EINVAL; | ||
583 | } | ||
584 | |||
585 | u.cfg.station = 0; | ||
586 | u.cfg.options |= 0x8000; /* auto config DLCI */ | ||
587 | card->u.f.dlci_num = 0; | ||
588 | |||
589 | } else { | ||
590 | |||
591 | u.cfg.station = 1; /* switch emulation mode */ | ||
592 | |||
593 | /* For switch emulation we have to create a list of dlci(s) | ||
594 | * that will be sent to be global SET_DLCI_CONFIGURATION | ||
595 | * command in fr_configure() routine. | ||
596 | */ | ||
597 | |||
598 | card->u.f.dlci_num = min_t(unsigned int, max_t(unsigned int, conf->u.fr.dlci_num, 1), 100); | ||
599 | |||
600 | for ( i = 0; i < card->u.f.dlci_num; i++) { | ||
601 | |||
602 | card->u.f.node_dlci[i] = (unsigned short) | ||
603 | conf->u.fr.dlci[i] ? conf->u.fr.dlci[i] : 16; | ||
604 | |||
605 | } | ||
606 | } | ||
607 | |||
608 | if (conf->clocking == WANOPT_INTERNAL) | ||
609 | u.cfg.port |= 0x0001; | ||
610 | |||
611 | if (conf->interface == WANOPT_RS232) | ||
612 | u.cfg.port |= 0x0002; | ||
613 | |||
614 | if (conf->u.fr.t391) | ||
615 | u.cfg.t391 = min_t(unsigned int, conf->u.fr.t391, 30); | ||
616 | else | ||
617 | u.cfg.t391 = 5; | ||
618 | |||
619 | if (conf->u.fr.t392) | ||
620 | u.cfg.t392 = min_t(unsigned int, conf->u.fr.t392, 30); | ||
621 | else | ||
622 | u.cfg.t392 = 15; | ||
623 | |||
624 | if (conf->u.fr.n391) | ||
625 | u.cfg.n391 = min_t(unsigned int, conf->u.fr.n391, 255); | ||
626 | else | ||
627 | u.cfg.n391 = 2; | ||
628 | |||
629 | if (conf->u.fr.n392) | ||
630 | u.cfg.n392 = min_t(unsigned int, conf->u.fr.n392, 10); | ||
631 | else | ||
632 | u.cfg.n392 = 3; | ||
633 | |||
634 | if (conf->u.fr.n393) | ||
635 | u.cfg.n393 = min_t(unsigned int, conf->u.fr.n393, 10); | ||
636 | else | ||
637 | u.cfg.n393 = 4; | ||
638 | |||
639 | if (fr_configure(card, &u.cfg)) | ||
640 | return -EIO; | ||
641 | |||
642 | if (card->hw.type == SDLA_S514) { | ||
643 | |||
644 | buf_info = (void*)(card->hw.dpmbase + FR_MB_VECTOR + | ||
645 | FR508_RXBC_OFFS); | ||
646 | |||
647 | card->rxmb = (void*)(buf_info->rse_next + card->hw.dpmbase); | ||
648 | |||
649 | card->u.f.rxmb_base = | ||
650 | (void*)(buf_info->rse_base + card->hw.dpmbase); | ||
651 | |||
652 | card->u.f.rxmb_last = | ||
653 | (void*)(buf_info->rse_base + | ||
654 | (buf_info->rse_num - 1) * sizeof(fr_rx_buf_ctl_t) + | ||
655 | card->hw.dpmbase); | ||
656 | }else{ | ||
657 | buf_info = (void*)(card->hw.dpmbase + FR508_RXBC_OFFS); | ||
658 | |||
659 | card->rxmb = (void*)(buf_info->rse_next - | ||
660 | FR_MB_VECTOR + card->hw.dpmbase); | ||
661 | |||
662 | card->u.f.rxmb_base = | ||
663 | (void*)(buf_info->rse_base - | ||
664 | FR_MB_VECTOR + card->hw.dpmbase); | ||
665 | |||
666 | card->u.f.rxmb_last = | ||
667 | (void*)(buf_info->rse_base + | ||
668 | (buf_info->rse_num - 1) * sizeof(fr_rx_buf_ctl_t) - | ||
669 | FR_MB_VECTOR + card->hw.dpmbase); | ||
670 | } | ||
671 | |||
672 | card->u.f.rx_base = buf_info->buf_base; | ||
673 | card->u.f.rx_top = buf_info->buf_top; | ||
674 | |||
675 | card->u.f.tx_interrupts_pending = 0; | ||
676 | |||
677 | card->wandev.mtu = conf->mtu; | ||
678 | card->wandev.bps = conf->bps; | ||
679 | card->wandev.interface = conf->interface; | ||
680 | card->wandev.clocking = conf->clocking; | ||
681 | card->wandev.station = conf->station; | ||
682 | card->poll = NULL; | ||
683 | card->exec = &wpf_exec; | ||
684 | card->wandev.update = &update; | ||
685 | card->wandev.new_if = &new_if; | ||
686 | card->wandev.del_if = &del_if; | ||
687 | card->wandev.state = WAN_DISCONNECTED; | ||
688 | card->wandev.ttl = conf->ttl; | ||
689 | card->wandev.udp_port = conf->udp_port; | ||
690 | card->disable_comm = &disable_comm; | ||
691 | card->u.f.arp_dev = NULL; | ||
692 | |||
693 | /* Intialize global statistics for a card */ | ||
694 | init_global_statistics( card ); | ||
695 | |||
696 | card->TracingEnabled = 0; | ||
697 | |||
698 | /* Interrupt Test */ | ||
699 | Intr_test_counter = 0; | ||
700 | card->intr_mode = INTR_TEST_MODE; | ||
701 | err = intr_test( card ); | ||
702 | |||
703 | printk(KERN_INFO "%s: End of Interrupt Test rc=0x%x count=%i\n", | ||
704 | card->devname,err,Intr_test_counter); | ||
705 | |||
706 | if (err || (Intr_test_counter < MAX_INTR_TEST_COUNTER)) { | ||
707 | printk(KERN_ERR "%s: Interrupt Test Failed, Counter: %i\n", | ||
708 | card->devname, Intr_test_counter); | ||
709 | printk(KERN_ERR "Please choose another interrupt\n"); | ||
710 | err = -EIO; | ||
711 | return err; | ||
712 | } | ||
713 | |||
714 | printk(KERN_INFO "%s: Interrupt Test Passed, Counter: %i\n", | ||
715 | card->devname, Intr_test_counter); | ||
716 | |||
717 | |||
718 | /* Apr 28 2000. Nenad Corbic | ||
719 | * Enable commnunications here, not in if_open or new_if, since | ||
720 | * interfaces come down when the link is disconnected. | ||
721 | */ | ||
722 | |||
723 | /* If you enable comms and then set ints, you get a Tx int as you | ||
724 | * perform the SET_INT_TRIGGERS command. So, we only set int | ||
725 | * triggers and then adjust the interrupt mask (to disable Tx ints) | ||
726 | * before enabling comms. | ||
727 | */ | ||
728 | if (fr_set_intr_mode(card, (FR_INTR_RXRDY | FR_INTR_TXRDY | | ||
729 | FR_INTR_DLC | FR_INTR_TIMER | FR_INTR_TX_MULT_DLCIs) , | ||
730 | card->wandev.mtu, 0)) { | ||
731 | return -EIO; | ||
732 | } | ||
733 | |||
734 | flags->imask &= ~(FR_INTR_TXRDY | FR_INTR_TIMER); | ||
735 | |||
736 | if (fr_comm_enable(card)) { | ||
737 | return -EIO; | ||
738 | } | ||
739 | wanpipe_set_state(card, WAN_CONNECTED); | ||
740 | spin_lock_init(&card->u.f.if_send_lock); | ||
741 | |||
742 | printk(KERN_INFO "\n"); | ||
743 | |||
744 | return 0; | ||
745 | } | ||
746 | |||
747 | /******* WAN Device Driver Entry Points *************************************/ | ||
748 | |||
749 | /*============================================================================ | ||
750 | * Update device status & statistics. | ||
751 | */ | ||
752 | static int update(struct wan_device* wandev) | ||
753 | { | ||
754 | volatile sdla_t* card; | ||
755 | unsigned long timeout; | ||
756 | fr508_flags_t* flags; | ||
757 | |||
758 | /* sanity checks */ | ||
759 | if ((wandev == NULL) || (wandev->private == NULL)) | ||
760 | return -EFAULT; | ||
761 | |||
762 | if (wandev->state == WAN_UNCONFIGURED) | ||
763 | return -ENODEV; | ||
764 | |||
765 | card = wandev->private; | ||
766 | flags = card->flags; | ||
767 | |||
768 | |||
769 | card->u.f.update_comms_stats = 1; | ||
770 | card->u.f.timer_int_enabled |= TMR_INT_ENABLED_UPDATE; | ||
771 | flags->imask |= FR_INTR_TIMER; | ||
772 | timeout = jiffies; | ||
773 | for(;;) { | ||
774 | if(card->u.f.update_comms_stats == 0) | ||
775 | break; | ||
776 | if ((jiffies - timeout) > (1 * HZ)){ | ||
777 | card->u.f.update_comms_stats = 0; | ||
778 | return -EAGAIN; | ||
779 | } | ||
780 | } | ||
781 | |||
782 | return 0; | ||
783 | } | ||
784 | |||
785 | /*============================================================================ | ||
786 | * Create new logical channel. | ||
787 | * This routine is called by the router when ROUTER_IFNEW IOCTL is being | ||
788 | * handled. | ||
789 | * o parse media- and hardware-specific configuration | ||
790 | * o make sure that a new channel can be created | ||
791 | * o allocate resources, if necessary | ||
792 | * o prepare network device structure for registaration. | ||
793 | * | ||
794 | * Return: 0 o.k. | ||
795 | * < 0 failure (channel will not be created) | ||
796 | */ | ||
797 | static int new_if(struct wan_device* wandev, struct net_device* dev, | ||
798 | wanif_conf_t* conf) | ||
799 | { | ||
800 | sdla_t* card = wandev->private; | ||
801 | fr_channel_t* chan; | ||
802 | int dlci = 0; | ||
803 | int err = 0; | ||
804 | |||
805 | |||
806 | if ((conf->name[0] == '\0') || (strlen(conf->name) > WAN_IFNAME_SZ)) { | ||
807 | |||
808 | printk(KERN_INFO "%s: Invalid interface name!\n", | ||
809 | card->devname); | ||
810 | return -EINVAL; | ||
811 | } | ||
812 | |||
813 | /* allocate and initialize private data */ | ||
814 | chan = kmalloc(sizeof(fr_channel_t), GFP_KERNEL); | ||
815 | |||
816 | if (chan == NULL) | ||
817 | return -ENOMEM; | ||
818 | |||
819 | memset(chan, 0, sizeof(fr_channel_t)); | ||
820 | strcpy(chan->name, conf->name); | ||
821 | chan->card = card; | ||
822 | |||
823 | /* verify media address */ | ||
824 | if (is_digit(conf->addr[0])) { | ||
825 | |||
826 | dlci = dec_to_uint(conf->addr, 0); | ||
827 | |||
828 | if (dlci && (dlci <= HIGHEST_VALID_DLCI)) { | ||
829 | |||
830 | chan->dlci = dlci; | ||
831 | |||
832 | } else { | ||
833 | |||
834 | printk(KERN_ERR | ||
835 | "%s: Invalid DLCI %u on interface %s!\n", | ||
836 | wandev->name, dlci, chan->name); | ||
837 | err = -EINVAL; | ||
838 | } | ||
839 | |||
840 | } else { | ||
841 | printk(KERN_ERR | ||
842 | "%s: Invalid media address on interface %s!\n", | ||
843 | wandev->name, chan->name); | ||
844 | err = -EINVAL; | ||
845 | } | ||
846 | |||
847 | if ((chan->true_if_encoding = conf->true_if_encoding) == WANOPT_YES){ | ||
848 | printk(KERN_INFO | ||
849 | "%s: Enabling, true interface type encoding.\n", | ||
850 | card->devname); | ||
851 | } | ||
852 | |||
853 | |||
854 | |||
855 | /* Setup wanpipe as a router (WANPIPE) even if it is | ||
856 | * a bridged DLCI, or as an API | ||
857 | */ | ||
858 | if (strcmp(conf->usedby, "WANPIPE") == 0 || | ||
859 | strcmp(conf->usedby, "BRIDGE") == 0 || | ||
860 | strcmp(conf->usedby, "BRIDGE_N") == 0){ | ||
861 | |||
862 | if(strcmp(conf->usedby, "WANPIPE") == 0){ | ||
863 | chan->common.usedby = WANPIPE; | ||
864 | |||
865 | printk(KERN_INFO "%s: Running in WANPIPE mode.\n", | ||
866 | card->devname); | ||
867 | |||
868 | }else if(strcmp(conf->usedby, "BRIDGE") == 0){ | ||
869 | |||
870 | chan->common.usedby = BRIDGE; | ||
871 | |||
872 | printk(KERN_INFO "%s: Running in WANPIPE (BRIDGE) mode.\n", | ||
873 | card->devname); | ||
874 | }else if( strcmp(conf->usedby, "BRIDGE_N") == 0 ){ | ||
875 | |||
876 | chan->common.usedby = BRIDGE_NODE; | ||
877 | |||
878 | printk(KERN_INFO "%s: Running in WANPIPE (BRIDGE_NODE) mode.\n", | ||
879 | card->devname); | ||
880 | } | ||
881 | |||
882 | if (!err){ | ||
883 | /* Dynamic interface configuration option. | ||
884 | * On disconnect, if the options is selected, | ||
885 | * the interface will be brought down */ | ||
886 | if (conf->if_down == WANOPT_YES){ | ||
887 | set_bit(DYN_OPT_ON,&chan->interface_down); | ||
888 | printk(KERN_INFO | ||
889 | "%s: Dynamic interface configuration enabled.\n", | ||
890 | card->devname); | ||
891 | } | ||
892 | } | ||
893 | |||
894 | } else if(strcmp(conf->usedby, "API") == 0){ | ||
895 | |||
896 | chan->common.usedby = API; | ||
897 | printk(KERN_INFO "%s: Running in API mode.\n", | ||
898 | wandev->name); | ||
899 | } | ||
900 | |||
901 | if (err) { | ||
902 | |||
903 | kfree(chan); | ||
904 | return err; | ||
905 | } | ||
906 | |||
907 | /* place cir,be,bc and other channel specific information into the | ||
908 | * chan structure | ||
909 | */ | ||
910 | if (conf->cir) { | ||
911 | |||
912 | chan->cir = max_t(unsigned int, 1, | ||
913 | min_t(unsigned int, conf->cir, 512)); | ||
914 | chan->cir_status = CIR_ENABLED; | ||
915 | |||
916 | |||
917 | /* If CIR is enabled, force BC to equal CIR | ||
918 | * this solves number of potential problems if CIR is | ||
919 | * set and BC is not | ||
920 | */ | ||
921 | chan->bc = chan->cir; | ||
922 | |||
923 | if (conf->be){ | ||
924 | chan->be = max_t(unsigned int, | ||
925 | 0, min_t(unsigned int, conf->be, 511)); | ||
926 | }else{ | ||
927 | conf->be = 0; | ||
928 | } | ||
929 | |||
930 | printk (KERN_INFO "%s: CIR enabled for DLCI %i \n", | ||
931 | wandev->name,chan->dlci); | ||
932 | printk (KERN_INFO "%s: CIR = %i ; BC = %i ; BE = %i\n", | ||
933 | wandev->name,chan->cir,chan->bc,chan->be); | ||
934 | |||
935 | |||
936 | }else{ | ||
937 | chan->cir_status = CIR_DISABLED; | ||
938 | printk (KERN_INFO "%s: CIR disabled for DLCI %i\n", | ||
939 | wandev->name,chan->dlci); | ||
940 | } | ||
941 | |||
942 | chan->mc = conf->mc; | ||
943 | |||
944 | if (conf->inarp == WANOPT_YES){ | ||
945 | printk(KERN_INFO "%s: Inverse ARP Support Enabled\n",card->devname); | ||
946 | chan->inarp = conf->inarp ? INARP_REQUEST : INARP_NONE; | ||
947 | chan->inarp_interval = conf->inarp_interval ? conf->inarp_interval : 10; | ||
948 | }else{ | ||
949 | printk(KERN_INFO "%s: Inverse ARP Support Disabled\n",card->devname); | ||
950 | chan->inarp = INARP_NONE; | ||
951 | chan->inarp_interval = 10; | ||
952 | } | ||
953 | |||
954 | |||
955 | chan->dlci_configured = DLCI_NOT_CONFIGURED; | ||
956 | |||
957 | |||
958 | /*FIXME: IPX disabled in this WANPIPE version */ | ||
959 | if (conf->enable_IPX == WANOPT_YES){ | ||
960 | printk(KERN_INFO "%s: ERROR - This version of WANPIPE doesn't support IPX\n", | ||
961 | card->devname); | ||
962 | kfree(chan); | ||
963 | return -EINVAL; | ||
964 | }else{ | ||
965 | chan->enable_IPX = WANOPT_NO; | ||
966 | } | ||
967 | |||
968 | if (conf->network_number){ | ||
969 | chan->network_number = conf->network_number; | ||
970 | }else{ | ||
971 | chan->network_number = 0xDEADBEEF; | ||
972 | } | ||
973 | |||
974 | chan->route_flag = NO_ROUTE; | ||
975 | |||
976 | init_chan_statistics(chan); | ||
977 | |||
978 | chan->transmit_length = 0; | ||
979 | |||
980 | /* prepare network device data space for registration */ | ||
981 | strcpy(dev->name,chan->name); | ||
982 | |||
983 | dev->init = &if_init; | ||
984 | dev->priv = chan; | ||
985 | |||
986 | /* Initialize FR Polling Task Queue | ||
987 | * We need a poll routine for each network | ||
988 | * interface. | ||
989 | */ | ||
990 | INIT_WORK(&chan->fr_poll_work, (void *)fr_poll, dev); | ||
991 | |||
992 | init_timer(&chan->fr_arp_timer); | ||
993 | chan->fr_arp_timer.data=(unsigned long)dev; | ||
994 | chan->fr_arp_timer.function = fr_arp; | ||
995 | |||
996 | wandev->new_if_cnt++; | ||
997 | |||
998 | /* Tells us that if this interface is a | ||
999 | * gateway or not */ | ||
1000 | if ((chan->gateway = conf->gateway) == WANOPT_YES){ | ||
1001 | printk(KERN_INFO "%s: Interface %s is set as a gateway.\n", | ||
1002 | card->devname,dev->name); | ||
1003 | } | ||
1004 | |||
1005 | /* M. Grant Patch Apr 28 2000 | ||
1006 | * Disallow duplicate dlci configurations. */ | ||
1007 | if (card->u.f.dlci_to_dev_map[chan->dlci] != NULL) { | ||
1008 | kfree(chan); | ||
1009 | return -EBUSY; | ||
1010 | } | ||
1011 | |||
1012 | /* Configure this dlci at a later date, when | ||
1013 | * the interface comes up. i.e. when if_open() | ||
1014 | * executes */ | ||
1015 | set_bit(0,&chan->config_dlci); | ||
1016 | |||
1017 | printk(KERN_INFO "\n"); | ||
1018 | |||
1019 | return 0; | ||
1020 | } | ||
1021 | |||
1022 | /*============================================================================ | ||
1023 | * Delete logical channel. | ||
1024 | */ | ||
1025 | static int del_if(struct wan_device* wandev, struct net_device* dev) | ||
1026 | { | ||
1027 | fr_channel_t* chan = dev->priv; | ||
1028 | unsigned long smp_flags=0; | ||
1029 | |||
1030 | /* This interface is dead, make sure the | ||
1031 | * ARP timer is stopped */ | ||
1032 | del_timer(&chan->fr_arp_timer); | ||
1033 | |||
1034 | /* If we are a NODE, we must unconfigure this DLCI | ||
1035 | * Trigger an unconfigure command that will | ||
1036 | * be executed in timer interrupt. We must wait | ||
1037 | * for the command to complete. */ | ||
1038 | trigger_unconfig_fr(dev); | ||
1039 | |||
1040 | lock_adapter_irq(&wandev->lock, &smp_flags); | ||
1041 | wandev->new_if_cnt--; | ||
1042 | unlock_adapter_irq(&wandev->lock, &smp_flags); | ||
1043 | |||
1044 | return 0; | ||
1045 | } | ||
1046 | |||
1047 | |||
1048 | /*===================================================================== | ||
1049 | * disable_comm | ||
1050 | * | ||
1051 | * Description: | ||
1052 | * Disable communications. | ||
1053 | * This code runs in shutdown (sdlamain.c) | ||
1054 | * under critical flag. Therefore it is not | ||
1055 | * necessary to set a critical flag here | ||
1056 | * | ||
1057 | * Usage: | ||
1058 | * Commnunications are disabled only on a card | ||
1059 | * shutdown. | ||
1060 | */ | ||
1061 | |||
1062 | static void disable_comm (sdla_t *card) | ||
1063 | { | ||
1064 | printk(KERN_INFO "%s: Disabling Communications!\n", | ||
1065 | card->devname); | ||
1066 | fr_comm_disable(card); | ||
1067 | } | ||
1068 | |||
1069 | /****** WANPIPE-specific entry points ***************************************/ | ||
1070 | |||
1071 | /*============================================================================ | ||
1072 | * Execute adapter interface command. | ||
1073 | */ | ||
1074 | static int wpf_exec (struct sdla* card, void* u_cmd, void* u_data) | ||
1075 | { | ||
1076 | fr_mbox_t* mbox = card->mbox; | ||
1077 | int retry = MAX_CMD_RETRY; | ||
1078 | int err, len; | ||
1079 | fr_cmd_t cmd; | ||
1080 | |||
1081 | if(copy_from_user((void*)&cmd, u_cmd, sizeof(cmd))) | ||
1082 | return -EFAULT; | ||
1083 | |||
1084 | /* execute command */ | ||
1085 | do | ||
1086 | { | ||
1087 | memcpy(&mbox->cmd, &cmd, sizeof(cmd)); | ||
1088 | |||
1089 | if (cmd.length){ | ||
1090 | if( copy_from_user((void*)&mbox->data, u_data, cmd.length)) | ||
1091 | return -EFAULT; | ||
1092 | } | ||
1093 | |||
1094 | if (sdla_exec(mbox)) | ||
1095 | err = mbox->cmd.result; | ||
1096 | |||
1097 | else return -EIO; | ||
1098 | |||
1099 | } while (err && retry-- && fr_event(card, err, mbox)); | ||
1100 | |||
1101 | /* return result */ | ||
1102 | if (copy_to_user(u_cmd, (void*)&mbox->cmd, sizeof(fr_cmd_t))) | ||
1103 | return -EFAULT; | ||
1104 | |||
1105 | len = mbox->cmd.length; | ||
1106 | |||
1107 | if (len && u_data && !copy_to_user(u_data, (void*)&mbox->data, len)) | ||
1108 | return -EFAULT; | ||
1109 | return 0; | ||
1110 | } | ||
1111 | |||
1112 | /****** Network Device Interface ********************************************/ | ||
1113 | |||
1114 | /*============================================================================ | ||
1115 | * Initialize Linux network interface. | ||
1116 | * | ||
1117 | * This routine is called only once for each interface, during Linux network | ||
1118 | * interface registration. Returning anything but zero will fail interface | ||
1119 | * registration. | ||
1120 | */ | ||
1121 | static int if_init(struct net_device* dev) | ||
1122 | { | ||
1123 | fr_channel_t* chan = dev->priv; | ||
1124 | sdla_t* card = chan->card; | ||
1125 | struct wan_device* wandev = &card->wandev; | ||
1126 | |||
1127 | /* Initialize device driver entry points */ | ||
1128 | dev->open = &if_open; | ||
1129 | dev->stop = &if_close; | ||
1130 | dev->hard_header = NULL; | ||
1131 | dev->rebuild_header = &if_rebuild_hdr; | ||
1132 | dev->hard_start_xmit = &if_send; | ||
1133 | dev->get_stats = &if_stats; | ||
1134 | dev->tx_timeout = &if_tx_timeout; | ||
1135 | dev->watchdog_timeo = TX_TIMEOUT; | ||
1136 | |||
1137 | if (chan->common.usedby == WANPIPE || chan->common.usedby == API){ | ||
1138 | |||
1139 | /* Initialize media-specific parameters */ | ||
1140 | if (chan->true_if_encoding){ | ||
1141 | dev->type = ARPHRD_DLCI; /* This breaks tcpdump */ | ||
1142 | }else{ | ||
1143 | dev->type = ARPHRD_PPP; /* ARP h/w type */ | ||
1144 | } | ||
1145 | |||
1146 | dev->flags |= IFF_POINTOPOINT; | ||
1147 | dev->flags |= IFF_NOARP; | ||
1148 | |||
1149 | /* Enable Multicast addressing */ | ||
1150 | if (chan->mc == WANOPT_YES){ | ||
1151 | dev->flags |= IFF_MULTICAST; | ||
1152 | } | ||
1153 | |||
1154 | dev->mtu = wandev->mtu - FR_HEADER_LEN; | ||
1155 | /* For an API, the maximum number of bytes that the stack will pass | ||
1156 | to the driver is (dev->mtu + dev->hard_header_len). So, adjust the | ||
1157 | mtu so that a frame of maximum size can be transmitted by the API. | ||
1158 | */ | ||
1159 | if(chan->common.usedby == API) { | ||
1160 | dev->mtu += (sizeof(api_tx_hdr_t) - FR_HEADER_LEN); | ||
1161 | } | ||
1162 | |||
1163 | dev->hard_header_len = FR_HEADER_LEN;/* media header length */ | ||
1164 | dev->addr_len = 2; /* hardware address length */ | ||
1165 | *(unsigned short*)dev->dev_addr = htons(chan->dlci); | ||
1166 | |||
1167 | /* Set transmit buffer queue length */ | ||
1168 | dev->tx_queue_len = 100; | ||
1169 | |||
1170 | }else{ | ||
1171 | |||
1172 | /* Setup the interface for Bridging */ | ||
1173 | int hw_addr=0; | ||
1174 | ether_setup(dev); | ||
1175 | |||
1176 | /* Use a random number to generate the MAC address */ | ||
1177 | memcpy(dev->dev_addr, "\xFE\xFC\x00\x00\x00\x00", 6); | ||
1178 | get_random_bytes(&hw_addr, sizeof(hw_addr)); | ||
1179 | *(int *)(dev->dev_addr + 2) += hw_addr; | ||
1180 | } | ||
1181 | |||
1182 | /* Initialize hardware parameters (just for reference) */ | ||
1183 | dev->irq = wandev->irq; | ||
1184 | dev->dma = wandev->dma; | ||
1185 | dev->base_addr = wandev->ioport; | ||
1186 | dev->mem_start = wandev->maddr; | ||
1187 | dev->mem_end = wandev->maddr + wandev->msize - 1; | ||
1188 | SET_MODULE_OWNER(dev); | ||
1189 | |||
1190 | return 0; | ||
1191 | } | ||
1192 | |||
1193 | /*============================================================================ | ||
1194 | * Open network interface. | ||
1195 | * o if this is the first open, then enable communications and interrupts. | ||
1196 | * o prevent module from unloading by incrementing use count | ||
1197 | * | ||
1198 | * Return 0 if O.k. or errno. | ||
1199 | */ | ||
1200 | static int if_open(struct net_device* dev) | ||
1201 | { | ||
1202 | fr_channel_t* chan = dev->priv; | ||
1203 | sdla_t* card = chan->card; | ||
1204 | int err = 0; | ||
1205 | struct timeval tv; | ||
1206 | |||
1207 | if (netif_running(dev)) | ||
1208 | return -EBUSY; | ||
1209 | |||
1210 | /* Initialize the task queue */ | ||
1211 | chan->tq_working=0; | ||
1212 | |||
1213 | INIT_WORK(&chan->common.wanpipe_work, (void *)fr_bh, dev); | ||
1214 | |||
1215 | /* Allocate and initialize BH circular buffer */ | ||
1216 | chan->bh_head = kmalloc((sizeof(bh_data_t)*MAX_BH_BUFF),GFP_ATOMIC); | ||
1217 | memset(chan->bh_head,0,(sizeof(bh_data_t)*MAX_BH_BUFF)); | ||
1218 | atomic_set(&chan->bh_buff_used, 0); | ||
1219 | |||
1220 | netif_start_queue(dev); | ||
1221 | |||
1222 | wanpipe_open(card); | ||
1223 | do_gettimeofday( &tv ); | ||
1224 | chan->router_start_time = tv.tv_sec; | ||
1225 | |||
1226 | if (test_bit(0,&chan->config_dlci)){ | ||
1227 | trigger_config_fr (card); | ||
1228 | }else if (chan->inarp == INARP_REQUEST){ | ||
1229 | trigger_fr_arp(dev); | ||
1230 | } | ||
1231 | |||
1232 | return err; | ||
1233 | } | ||
1234 | |||
1235 | /*============================================================================ | ||
1236 | * Close network interface. | ||
1237 | * o if this is the last open, then disable communications and interrupts. | ||
1238 | * o reset flags. | ||
1239 | */ | ||
1240 | static int if_close(struct net_device* dev) | ||
1241 | { | ||
1242 | fr_channel_t* chan = dev->priv; | ||
1243 | sdla_t* card = chan->card; | ||
1244 | |||
1245 | if (chan->inarp == INARP_CONFIGURED) { | ||
1246 | chan->inarp = INARP_REQUEST; | ||
1247 | } | ||
1248 | |||
1249 | netif_stop_queue(dev); | ||
1250 | wanpipe_close(card); | ||
1251 | |||
1252 | return 0; | ||
1253 | } | ||
1254 | |||
1255 | /*============================================================================ | ||
1256 | * Re-build media header. | ||
1257 | * | ||
1258 | * Return: 1 physical address resolved. | ||
1259 | * 0 physical address not resolved | ||
1260 | */ | ||
1261 | static int if_rebuild_hdr (struct sk_buff* skb) | ||
1262 | { | ||
1263 | struct net_device *dev = skb->dev; | ||
1264 | fr_channel_t* chan = dev->priv; | ||
1265 | sdla_t* card = chan->card; | ||
1266 | |||
1267 | printk(KERN_INFO "%s: rebuild_header() called for interface %s!\n", | ||
1268 | card->devname, dev->name); | ||
1269 | return 1; | ||
1270 | } | ||
1271 | |||
1272 | /*============================================================================ | ||
1273 | * Handle transmit timeout event from netif watchdog | ||
1274 | */ | ||
1275 | static void if_tx_timeout(struct net_device *dev) | ||
1276 | { | ||
1277 | fr_channel_t* chan = dev->priv; | ||
1278 | sdla_t *card = chan->card; | ||
1279 | |||
1280 | /* If our device stays busy for at least 5 seconds then we will | ||
1281 | * kick start the device by making dev->tbusy = 0. We expect | ||
1282 | * that our device never stays busy more than 5 seconds. So this | ||
1283 | * is only used as a last resort. | ||
1284 | */ | ||
1285 | |||
1286 | chan->drvstats_if_send.if_send_tbusy++; | ||
1287 | ++chan->ifstats.collisions; | ||
1288 | |||
1289 | printk (KERN_INFO "%s: Transmit timed out on %s\n", | ||
1290 | card->devname, dev->name); | ||
1291 | chan->drvstats_if_send.if_send_tbusy_timeout++; | ||
1292 | netif_wake_queue (dev); | ||
1293 | |||
1294 | } | ||
1295 | |||
1296 | |||
1297 | /*============================================================================ | ||
1298 | * Send a packet on a network interface. | ||
1299 | * o set tbusy flag (marks start of the transmission) to block a timer-based | ||
1300 | * transmit from overlapping. | ||
1301 | * o set critical flag when accessing board. | ||
1302 | * o check link state. If link is not up, then drop the packet. | ||
1303 | * o check channel status. If it's down then initiate a call. | ||
1304 | * o pass a packet to corresponding WAN device. | ||
1305 | * o free socket buffer | ||
1306 | * | ||
1307 | * Return: 0 complete (socket buffer must be freed) | ||
1308 | * non-0 packet may be re-transmitted (tbusy must be set) | ||
1309 | * | ||
1310 | * Notes: | ||
1311 | * 1. This routine is called either by the protocol stack or by the "net | ||
1312 | * bottom half" (with interrupts enabled). | ||
1313 | * | ||
1314 | * 2. Using netif_start_queue() and netif_stop_queue() | ||
1315 | * will inhibit further transmit requests from the protocol stack | ||
1316 | * and can be used for flow control with protocol layer. | ||
1317 | */ | ||
1318 | static int if_send(struct sk_buff* skb, struct net_device* dev) | ||
1319 | { | ||
1320 | fr_channel_t* chan = dev->priv; | ||
1321 | sdla_t* card = chan->card; | ||
1322 | int err; | ||
1323 | unsigned char *sendpacket; | ||
1324 | fr508_flags_t* adptr_flags = card->flags; | ||
1325 | int udp_type; | ||
1326 | long delay_tx_queued = 0; | ||
1327 | unsigned long smp_flags=0; | ||
1328 | unsigned char attr = 0; | ||
1329 | |||
1330 | chan->drvstats_if_send.if_send_entry++; | ||
1331 | |||
1332 | netif_stop_queue(dev); | ||
1333 | |||
1334 | if (skb == NULL) { | ||
1335 | /* if we get here, some higher layer thinks we've missed an | ||
1336 | * tx-done interrupt. | ||
1337 | */ | ||
1338 | printk(KERN_INFO "%s: interface %s got kicked!\n", | ||
1339 | card->devname, dev->name); | ||
1340 | chan->drvstats_if_send.if_send_skb_null ++; | ||
1341 | |||
1342 | netif_wake_queue(dev); | ||
1343 | return 0; | ||
1344 | } | ||
1345 | |||
1346 | /* If a peripheral task is running just drop packets */ | ||
1347 | if (test_bit(PERI_CRIT, &card->wandev.critical)){ | ||
1348 | |||
1349 | printk(KERN_INFO "%s: Critical in if_send(): Peripheral running!\n", | ||
1350 | card->devname); | ||
1351 | |||
1352 | dev_kfree_skb_any(skb); | ||
1353 | netif_start_queue(dev); | ||
1354 | return 0; | ||
1355 | } | ||
1356 | |||
1357 | /* We must set the 'tbusy' flag if we already have a packet queued for | ||
1358 | transmission in the transmit interrupt handler. However, we must | ||
1359 | ensure that the transmit interrupt does not reset the 'tbusy' flag | ||
1360 | just before we set it, as this will result in a "transmit timeout". | ||
1361 | */ | ||
1362 | set_bit(SEND_TXIRQ_CRIT, (void*)&card->wandev.critical); | ||
1363 | if(chan->transmit_length) { | ||
1364 | netif_stop_queue(dev); | ||
1365 | chan->tick_counter = jiffies; | ||
1366 | clear_bit(SEND_TXIRQ_CRIT, (void*)&card->wandev.critical); | ||
1367 | return 1; | ||
1368 | } | ||
1369 | clear_bit(SEND_TXIRQ_CRIT, (void*)&card->wandev.critical); | ||
1370 | |||
1371 | /* Move the if_header() code to here. By inserting frame | ||
1372 | * relay header in if_header() we would break the | ||
1373 | * tcpdump and other packet sniffers */ | ||
1374 | chan->fr_header_len = setup_fr_header(&skb,dev,chan->common.usedby); | ||
1375 | if (chan->fr_header_len < 0 ){ | ||
1376 | ++chan->ifstats.tx_dropped; | ||
1377 | ++card->wandev.stats.tx_dropped; | ||
1378 | |||
1379 | dev_kfree_skb_any(skb); | ||
1380 | netif_start_queue(dev); | ||
1381 | return 0; | ||
1382 | } | ||
1383 | |||
1384 | sendpacket = skb->data; | ||
1385 | |||
1386 | udp_type = udp_pkt_type(skb, card); | ||
1387 | |||
1388 | if(udp_type != UDP_INVALID_TYPE) { | ||
1389 | if(store_udp_mgmt_pkt(udp_type, UDP_PKT_FRM_STACK, card, skb, | ||
1390 | chan->dlci)) { | ||
1391 | adptr_flags->imask |= FR_INTR_TIMER; | ||
1392 | if (udp_type == UDP_FPIPE_TYPE){ | ||
1393 | chan->drvstats_if_send. | ||
1394 | if_send_PIPE_request ++; | ||
1395 | } | ||
1396 | } | ||
1397 | netif_start_queue(dev); | ||
1398 | return 0; | ||
1399 | } | ||
1400 | |||
1401 | //FIXME: can we do better than sendpacket[2]? | ||
1402 | if ((chan->common.usedby == WANPIPE) && (sendpacket[2] == 0x45)) { | ||
1403 | |||
1404 | /* check to see if the source IP address is a broadcast or */ | ||
1405 | /* multicast IP address */ | ||
1406 | if(chk_bcast_mcast_addr(card, dev, skb)){ | ||
1407 | ++chan->ifstats.tx_dropped; | ||
1408 | ++card->wandev.stats.tx_dropped; | ||
1409 | dev_kfree_skb_any(skb); | ||
1410 | netif_start_queue(dev); | ||
1411 | return 0; | ||
1412 | } | ||
1413 | } | ||
1414 | |||
1415 | |||
1416 | /* Lock the S514/S508 card: SMP Supported */ | ||
1417 | s508_s514_lock(card,&smp_flags); | ||
1418 | |||
1419 | if (test_and_set_bit(SEND_CRIT, (void*)&card->wandev.critical)) { | ||
1420 | |||
1421 | chan->drvstats_if_send.if_send_critical_non_ISR ++; | ||
1422 | chan->ifstats.tx_dropped ++; | ||
1423 | printk(KERN_INFO "%s Critical in IF_SEND: if_send() already running!\n", | ||
1424 | card->devname); | ||
1425 | goto if_send_start_and_exit; | ||
1426 | } | ||
1427 | |||
1428 | /* API packet check: minimum packet size must be greater than | ||
1429 | * 16 byte API header */ | ||
1430 | if((chan->common.usedby == API) && (skb->len <= sizeof(api_tx_hdr_t))) { | ||
1431 | ++chan->ifstats.tx_dropped; | ||
1432 | ++card->wandev.stats.tx_dropped; | ||
1433 | |||
1434 | |||
1435 | goto if_send_start_and_exit; | ||
1436 | |||
1437 | }else{ | ||
1438 | /* During API transmission, get rid of the API header */ | ||
1439 | if (chan->common.usedby == API) { | ||
1440 | api_tx_hdr_t* api_tx_hdr; | ||
1441 | api_tx_hdr = (api_tx_hdr_t*)&skb->data[0x00]; | ||
1442 | attr = api_tx_hdr->attr; | ||
1443 | skb_pull(skb,sizeof(api_tx_hdr_t)); | ||
1444 | } | ||
1445 | } | ||
1446 | |||
1447 | if (card->wandev.state != WAN_CONNECTED) { | ||
1448 | chan->drvstats_if_send.if_send_wan_disconnected ++; | ||
1449 | ++chan->ifstats.tx_dropped; | ||
1450 | ++card->wandev.stats.tx_dropped; | ||
1451 | |||
1452 | } else if (chan->common.state != WAN_CONNECTED) { | ||
1453 | chan->drvstats_if_send.if_send_dlci_disconnected ++; | ||
1454 | |||
1455 | /* Update the DLCI state in timer interrupt */ | ||
1456 | card->u.f.timer_int_enabled |= TMR_INT_ENABLED_UPDATE_STATE; | ||
1457 | adptr_flags->imask |= FR_INTR_TIMER; | ||
1458 | |||
1459 | ++chan->ifstats.tx_dropped; | ||
1460 | ++card->wandev.stats.tx_dropped; | ||
1461 | |||
1462 | } else if (!is_tx_ready(card, chan)) { | ||
1463 | /* No tx buffers available, store for delayed transmit */ | ||
1464 | if (!setup_for_delayed_transmit(dev, skb)){ | ||
1465 | set_bit(1,&delay_tx_queued); | ||
1466 | } | ||
1467 | chan->drvstats_if_send.if_send_no_bfrs++; | ||
1468 | |||
1469 | } else if (!skb->protocol) { | ||
1470 | /* No protocols drop packet */ | ||
1471 | chan->drvstats_if_send.if_send_protocol_error ++; | ||
1472 | ++card->wandev.stats.tx_errors; | ||
1473 | |||
1474 | } else if (test_bit(ARP_CRIT,&card->wandev.critical)){ | ||
1475 | /* We are trying to send an ARP Packet, block IP data until | ||
1476 | * ARP is sent */ | ||
1477 | ++chan->ifstats.tx_dropped; | ||
1478 | ++card->wandev.stats.tx_dropped; | ||
1479 | |||
1480 | } else { | ||
1481 | //FIXME: IPX is not implemented in this version of Frame Relay ? | ||
1482 | if((chan->common.usedby == WANPIPE) && | ||
1483 | sendpacket[1] == 0x00 && | ||
1484 | sendpacket[2] == 0x80 && | ||
1485 | sendpacket[6] == 0x81 && | ||
1486 | sendpacket[7] == 0x37) { | ||
1487 | |||
1488 | if( chan->enable_IPX ) { | ||
1489 | switch_net_numbers(sendpacket, | ||
1490 | chan->network_number, 0); | ||
1491 | } else { | ||
1492 | //FIXME: Take this out when IPX is fixed | ||
1493 | printk(KERN_INFO | ||
1494 | "%s: WARNING: Unsupported IPX data in send, packet dropped\n", | ||
1495 | card->devname); | ||
1496 | } | ||
1497 | |||
1498 | }else{ | ||
1499 | err = fr_send_data_header(card, chan->dlci, attr, skb->len, skb->data, chan->fr_header_len); | ||
1500 | if (err) { | ||
1501 | switch(err) { | ||
1502 | case FRRES_CIR_OVERFLOW: | ||
1503 | case FRRES_BUFFER_OVERFLOW: | ||
1504 | if (!setup_for_delayed_transmit(dev, skb)){ | ||
1505 | set_bit(1,&delay_tx_queued); | ||
1506 | } | ||
1507 | chan->drvstats_if_send. | ||
1508 | if_send_adptr_bfrs_full ++; | ||
1509 | break; | ||
1510 | |||
1511 | case FRRES_TOO_LONG: | ||
1512 | if (net_ratelimit()){ | ||
1513 | printk(KERN_INFO | ||
1514 | "%s: Error: Frame too long, transmission failed %i\n", | ||
1515 | card->devname, (unsigned int)skb->len); | ||
1516 | } | ||
1517 | /* Drop down to default */ | ||
1518 | default: | ||
1519 | chan->drvstats_if_send. | ||
1520 | if_send_dlci_disconnected ++; | ||
1521 | ++chan->ifstats.tx_dropped; | ||
1522 | ++card->wandev.stats.tx_dropped; | ||
1523 | break; | ||
1524 | } | ||
1525 | } else { | ||
1526 | chan->drvstats_if_send. | ||
1527 | if_send_bfr_passed_to_adptr++; | ||
1528 | ++chan->ifstats.tx_packets; | ||
1529 | ++card->wandev.stats.tx_packets; | ||
1530 | |||
1531 | chan->ifstats.tx_bytes += skb->len; | ||
1532 | card->wandev.stats.tx_bytes += skb->len; | ||
1533 | dev->trans_start = jiffies; | ||
1534 | } | ||
1535 | } | ||
1536 | } | ||
1537 | |||
1538 | if_send_start_and_exit: | ||
1539 | |||
1540 | netif_start_queue(dev); | ||
1541 | |||
1542 | /* If we queued the packet for transmission, we must not | ||
1543 | * deallocate it. The packet is unlinked from the IP stack | ||
1544 | * not copied. Therefore, we must keep the original packet */ | ||
1545 | if (!test_bit(1,&delay_tx_queued)) { | ||
1546 | dev_kfree_skb_any(skb); | ||
1547 | }else{ | ||
1548 | adptr_flags->imask |= FR_INTR_TXRDY; | ||
1549 | card->u.f.tx_interrupts_pending ++; | ||
1550 | } | ||
1551 | |||
1552 | clear_bit(SEND_CRIT, (void*)&card->wandev.critical); | ||
1553 | |||
1554 | s508_s514_unlock(card,&smp_flags); | ||
1555 | |||
1556 | return 0; | ||
1557 | } | ||
1558 | |||
1559 | |||
1560 | |||
1561 | /*============================================================================ | ||
1562 | * Setup so that a frame can be transmitted on the occurrence of a transmit | ||
1563 | * interrupt. | ||
1564 | */ | ||
1565 | static int setup_for_delayed_transmit(struct net_device* dev, | ||
1566 | struct sk_buff *skb) | ||
1567 | { | ||
1568 | fr_channel_t* chan = dev->priv; | ||
1569 | sdla_t* card = chan->card; | ||
1570 | fr_dlci_interface_t* dlci_interface; | ||
1571 | int len = skb->len; | ||
1572 | |||
1573 | /* Check that the dlci is properly configured, | ||
1574 | * before using tx interrupt */ | ||
1575 | if (!chan->dlci_int_interface){ | ||
1576 | if (net_ratelimit()){ | ||
1577 | printk(KERN_INFO | ||
1578 | "%s: ERROR on DLCI %i: Not configured properly !\n", | ||
1579 | card->devname, chan->dlci); | ||
1580 | printk(KERN_INFO "%s: Please contact Sangoma Technologies\n", | ||
1581 | card->devname); | ||
1582 | } | ||
1583 | return 1; | ||
1584 | } | ||
1585 | |||
1586 | dlci_interface = chan->dlci_int_interface; | ||
1587 | |||
1588 | if(chan->transmit_length) { | ||
1589 | printk(KERN_INFO "%s: Big mess in setup_for_del...\n", | ||
1590 | card->devname); | ||
1591 | return 1; | ||
1592 | } | ||
1593 | |||
1594 | if(len > FR_MAX_NO_DATA_BYTES_IN_FRAME) { | ||
1595 | //FIXME: increment some statistic */ | ||
1596 | return 1; | ||
1597 | } | ||
1598 | |||
1599 | skb_unlink(skb); | ||
1600 | |||
1601 | chan->transmit_length = len; | ||
1602 | chan->delay_skb = skb; | ||
1603 | |||
1604 | dlci_interface->gen_interrupt |= FR_INTR_TXRDY; | ||
1605 | dlci_interface->packet_length = len; | ||
1606 | |||
1607 | /* Turn on TX interrupt at the end of if_send */ | ||
1608 | return 0; | ||
1609 | } | ||
1610 | |||
1611 | |||
1612 | /*============================================================================ | ||
1613 | * Check to see if the packet to be transmitted contains a broadcast or | ||
1614 | * multicast source IP address. | ||
1615 | * Return 0 if not broadcast/multicast address, otherwise return 1. | ||
1616 | */ | ||
1617 | |||
1618 | static int chk_bcast_mcast_addr(sdla_t *card, struct net_device* dev, | ||
1619 | struct sk_buff *skb) | ||
1620 | { | ||
1621 | u32 src_ip_addr; | ||
1622 | u32 broadcast_ip_addr = 0; | ||
1623 | struct in_device *in_dev; | ||
1624 | fr_channel_t* chan = dev->priv; | ||
1625 | |||
1626 | /* read the IP source address from the outgoing packet */ | ||
1627 | src_ip_addr = *(u32 *)(skb->data + 14); | ||
1628 | |||
1629 | /* read the IP broadcast address for the device */ | ||
1630 | in_dev = dev->ip_ptr; | ||
1631 | if(in_dev != NULL) { | ||
1632 | struct in_ifaddr *ifa= in_dev->ifa_list; | ||
1633 | if(ifa != NULL) | ||
1634 | broadcast_ip_addr = ifa->ifa_broadcast; | ||
1635 | else | ||
1636 | return 0; | ||
1637 | } | ||
1638 | |||
1639 | /* check if the IP Source Address is a Broadcast address */ | ||
1640 | if((dev->flags & IFF_BROADCAST) && (src_ip_addr == broadcast_ip_addr)) { | ||
1641 | printk(KERN_INFO | ||
1642 | "%s: Broadcast Source Address silently discarded\n", | ||
1643 | card->devname); | ||
1644 | return 1; | ||
1645 | } | ||
1646 | |||
1647 | /* check if the IP Source Address is a Multicast address */ | ||
1648 | if((chan->mc == WANOPT_NO) && (ntohl(src_ip_addr) >= 0xE0000001) && | ||
1649 | (ntohl(src_ip_addr) <= 0xFFFFFFFE)) { | ||
1650 | printk(KERN_INFO | ||
1651 | "%s: Multicast Source Address silently discarded\n", | ||
1652 | card->devname); | ||
1653 | return 1; | ||
1654 | } | ||
1655 | |||
1656 | return 0; | ||
1657 | } | ||
1658 | |||
1659 | /*============================================================================ | ||
1660 | * Reply to UDP Management system. | ||
1661 | * Return nothing. | ||
1662 | */ | ||
1663 | static int reply_udp( unsigned char *data, unsigned int mbox_len ) | ||
1664 | { | ||
1665 | unsigned short len, udp_length, temp, ip_length; | ||
1666 | unsigned long ip_temp; | ||
1667 | int even_bound = 0; | ||
1668 | |||
1669 | |||
1670 | fr_udp_pkt_t *fr_udp_pkt = (fr_udp_pkt_t *)data; | ||
1671 | |||
1672 | /* Set length of packet */ | ||
1673 | len = //sizeof(fr_encap_hdr_t)+ | ||
1674 | sizeof(ip_pkt_t)+ | ||
1675 | sizeof(udp_pkt_t)+ | ||
1676 | sizeof(wp_mgmt_t)+ | ||
1677 | sizeof(cblock_t)+ | ||
1678 | mbox_len; | ||
1679 | |||
1680 | |||
1681 | /* fill in UDP reply */ | ||
1682 | fr_udp_pkt->wp_mgmt.request_reply = UDPMGMT_REPLY; | ||
1683 | |||
1684 | /* fill in UDP length */ | ||
1685 | udp_length = sizeof(udp_pkt_t)+ | ||
1686 | sizeof(wp_mgmt_t)+ | ||
1687 | sizeof(cblock_t)+ | ||
1688 | mbox_len; | ||
1689 | |||
1690 | |||
1691 | /* put it on an even boundary */ | ||
1692 | if ( udp_length & 0x0001 ) { | ||
1693 | udp_length += 1; | ||
1694 | len += 1; | ||
1695 | even_bound = 1; | ||
1696 | } | ||
1697 | |||
1698 | temp = (udp_length<<8)|(udp_length>>8); | ||
1699 | fr_udp_pkt->udp_pkt.udp_length = temp; | ||
1700 | |||
1701 | /* swap UDP ports */ | ||
1702 | temp = fr_udp_pkt->udp_pkt.udp_src_port; | ||
1703 | fr_udp_pkt->udp_pkt.udp_src_port = | ||
1704 | fr_udp_pkt->udp_pkt.udp_dst_port; | ||
1705 | fr_udp_pkt->udp_pkt.udp_dst_port = temp; | ||
1706 | |||
1707 | |||
1708 | |||
1709 | /* add UDP pseudo header */ | ||
1710 | temp = 0x1100; | ||
1711 | *((unsigned short *) | ||
1712 | (fr_udp_pkt->data+mbox_len+even_bound)) = temp; | ||
1713 | temp = (udp_length<<8)|(udp_length>>8); | ||
1714 | *((unsigned short *) | ||
1715 | (fr_udp_pkt->data+mbox_len+even_bound+2)) = temp; | ||
1716 | |||
1717 | /* calculate UDP checksum */ | ||
1718 | fr_udp_pkt->udp_pkt.udp_checksum = 0; | ||
1719 | |||
1720 | fr_udp_pkt->udp_pkt.udp_checksum = | ||
1721 | calc_checksum(&data[UDP_OFFSET/*+sizeof(fr_encap_hdr_t)*/], | ||
1722 | udp_length+UDP_OFFSET); | ||
1723 | |||
1724 | /* fill in IP length */ | ||
1725 | ip_length = udp_length + sizeof(ip_pkt_t); | ||
1726 | temp = (ip_length<<8)|(ip_length>>8); | ||
1727 | fr_udp_pkt->ip_pkt.total_length = temp; | ||
1728 | |||
1729 | /* swap IP addresses */ | ||
1730 | ip_temp = fr_udp_pkt->ip_pkt.ip_src_address; | ||
1731 | fr_udp_pkt->ip_pkt.ip_src_address = | ||
1732 | fr_udp_pkt->ip_pkt.ip_dst_address; | ||
1733 | fr_udp_pkt->ip_pkt.ip_dst_address = ip_temp; | ||
1734 | |||
1735 | |||
1736 | /* fill in IP checksum */ | ||
1737 | fr_udp_pkt->ip_pkt.hdr_checksum = 0; | ||
1738 | fr_udp_pkt->ip_pkt.hdr_checksum = | ||
1739 | calc_checksum(&data[/*sizeof(fr_encap_hdr_t)*/0], | ||
1740 | sizeof(ip_pkt_t)); | ||
1741 | |||
1742 | return len; | ||
1743 | } /* reply_udp */ | ||
1744 | |||
1745 | unsigned short calc_checksum (char *data, int len) | ||
1746 | { | ||
1747 | unsigned short temp; | ||
1748 | unsigned long sum=0; | ||
1749 | int i; | ||
1750 | |||
1751 | for( i = 0; i <len; i+=2 ) { | ||
1752 | memcpy(&temp,&data[i],2); | ||
1753 | sum += (unsigned long)temp; | ||
1754 | } | ||
1755 | |||
1756 | while (sum >> 16 ) { | ||
1757 | sum = (sum & 0xffffUL) + (sum >> 16); | ||
1758 | } | ||
1759 | |||
1760 | temp = (unsigned short)sum; | ||
1761 | temp = ~temp; | ||
1762 | |||
1763 | if( temp == 0 ) | ||
1764 | temp = 0xffff; | ||
1765 | |||
1766 | return temp; | ||
1767 | } | ||
1768 | |||
1769 | /* | ||
1770 | If incoming is 0 (outgoing)- if the net numbers is ours make it 0 | ||
1771 | if incoming is 1 - if the net number is 0 make it ours | ||
1772 | |||
1773 | */ | ||
1774 | static void switch_net_numbers(unsigned char *sendpacket, unsigned long network_number, unsigned char incoming) | ||
1775 | { | ||
1776 | unsigned long pnetwork_number; | ||
1777 | |||
1778 | pnetwork_number = (unsigned long)((sendpacket[14] << 24) + | ||
1779 | (sendpacket[15] << 16) + (sendpacket[16] << 8) + | ||
1780 | sendpacket[17]); | ||
1781 | |||
1782 | if (!incoming) { | ||
1783 | /* If the destination network number is ours, make it 0 */ | ||
1784 | if( pnetwork_number == network_number) { | ||
1785 | sendpacket[14] = sendpacket[15] = sendpacket[16] = | ||
1786 | sendpacket[17] = 0x00; | ||
1787 | } | ||
1788 | } else { | ||
1789 | /* If the incoming network is 0, make it ours */ | ||
1790 | if( pnetwork_number == 0) { | ||
1791 | sendpacket[14] = (unsigned char)(network_number >> 24); | ||
1792 | sendpacket[15] = (unsigned char)((network_number & | ||
1793 | 0x00FF0000) >> 16); | ||
1794 | sendpacket[16] = (unsigned char)((network_number & | ||
1795 | 0x0000FF00) >> 8); | ||
1796 | sendpacket[17] = (unsigned char)(network_number & | ||
1797 | 0x000000FF); | ||
1798 | } | ||
1799 | } | ||
1800 | |||
1801 | |||
1802 | pnetwork_number = (unsigned long)((sendpacket[26] << 24) + | ||
1803 | (sendpacket[27] << 16) + (sendpacket[28] << 8) + | ||
1804 | sendpacket[29]); | ||
1805 | |||
1806 | if( !incoming ) { | ||
1807 | /* If the source network is ours, make it 0 */ | ||
1808 | if( pnetwork_number == network_number) { | ||
1809 | sendpacket[26] = sendpacket[27] = sendpacket[28] = | ||
1810 | sendpacket[29] = 0x00; | ||
1811 | } | ||
1812 | } else { | ||
1813 | /* If the source network is 0, make it ours */ | ||
1814 | if( pnetwork_number == 0 ) { | ||
1815 | sendpacket[26] = (unsigned char)(network_number >> 24); | ||
1816 | sendpacket[27] = (unsigned char)((network_number & | ||
1817 | 0x00FF0000) >> 16); | ||
1818 | sendpacket[28] = (unsigned char)((network_number & | ||
1819 | 0x0000FF00) >> 8); | ||
1820 | sendpacket[29] = (unsigned char)(network_number & | ||
1821 | 0x000000FF); | ||
1822 | } | ||
1823 | } | ||
1824 | } /* switch_net_numbers */ | ||
1825 | |||
1826 | /*============================================================================ | ||
1827 | * Get ethernet-style interface statistics. | ||
1828 | * Return a pointer to struct enet_statistics. | ||
1829 | */ | ||
1830 | static struct net_device_stats *if_stats(struct net_device *dev) | ||
1831 | { | ||
1832 | fr_channel_t* chan = dev->priv; | ||
1833 | |||
1834 | if(chan == NULL) | ||
1835 | return NULL; | ||
1836 | |||
1837 | return &chan->ifstats; | ||
1838 | } | ||
1839 | |||
1840 | /****** Interrupt Handlers **************************************************/ | ||
1841 | |||
1842 | /*============================================================================ | ||
1843 | * fr_isr: S508 frame relay interrupt service routine. | ||
1844 | * | ||
1845 | * Description: | ||
1846 | * Frame relay main interrupt service route. This | ||
1847 | * function check the interrupt type and takes | ||
1848 | * the appropriate action. | ||
1849 | */ | ||
1850 | static void fr_isr (sdla_t* card) | ||
1851 | { | ||
1852 | fr508_flags_t* flags = card->flags; | ||
1853 | char *ptr = &flags->iflag; | ||
1854 | int i,err; | ||
1855 | fr_mbox_t* mbox = card->mbox; | ||
1856 | |||
1857 | /* This flag prevents nesting of interrupts. See sdla_isr() routine | ||
1858 | * in sdlamain.c. */ | ||
1859 | card->in_isr = 1; | ||
1860 | |||
1861 | ++card->statistics.isr_entry; | ||
1862 | |||
1863 | |||
1864 | /* All peripheral (configuraiton, re-configuration) events | ||
1865 | * take presidence over the ISR. Thus, retrigger */ | ||
1866 | if (test_bit(PERI_CRIT, (void*)&card->wandev.critical)) { | ||
1867 | ++card->statistics.isr_already_critical; | ||
1868 | goto fr_isr_exit; | ||
1869 | } | ||
1870 | |||
1871 | if(card->hw.type != SDLA_S514) { | ||
1872 | if (test_bit(SEND_CRIT, (void*)&card->wandev.critical)) { | ||
1873 | printk(KERN_INFO "%s: Critical while in ISR: If Send Running!\n", | ||
1874 | card->devname); | ||
1875 | ++card->statistics.isr_already_critical; | ||
1876 | goto fr_isr_exit; | ||
1877 | } | ||
1878 | } | ||
1879 | |||
1880 | switch (flags->iflag) { | ||
1881 | |||
1882 | case FR_INTR_RXRDY: /* receive interrupt */ | ||
1883 | ++card->statistics.isr_rx; | ||
1884 | rx_intr(card); | ||
1885 | break; | ||
1886 | |||
1887 | |||
1888 | case FR_INTR_TXRDY: /* transmit interrupt */ | ||
1889 | ++ card->statistics.isr_tx; | ||
1890 | tx_intr(card); | ||
1891 | break; | ||
1892 | |||
1893 | case FR_INTR_READY: | ||
1894 | Intr_test_counter++; | ||
1895 | ++card->statistics.isr_intr_test; | ||
1896 | break; | ||
1897 | |||
1898 | case FR_INTR_DLC: /* Event interrupt occurred */ | ||
1899 | mbox->cmd.command = FR_READ_STATUS; | ||
1900 | mbox->cmd.length = 0; | ||
1901 | err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; | ||
1902 | if (err) | ||
1903 | fr_event(card, err, mbox); | ||
1904 | break; | ||
1905 | |||
1906 | case FR_INTR_TIMER: /* Timer interrupt */ | ||
1907 | timer_intr(card); | ||
1908 | break; | ||
1909 | |||
1910 | default: | ||
1911 | ++card->statistics.isr_spurious; | ||
1912 | spur_intr(card); | ||
1913 | printk(KERN_INFO "%s: Interrupt Type 0x%02X!\n", | ||
1914 | card->devname, flags->iflag); | ||
1915 | |||
1916 | printk(KERN_INFO "%s: ID Bytes = ",card->devname); | ||
1917 | for(i = 0; i < 8; i ++) | ||
1918 | printk(KERN_INFO "0x%02X ", *(ptr + 0x28 + i)); | ||
1919 | printk(KERN_INFO "\n"); | ||
1920 | |||
1921 | break; | ||
1922 | } | ||
1923 | |||
1924 | fr_isr_exit: | ||
1925 | |||
1926 | card->in_isr = 0; | ||
1927 | flags->iflag = 0; | ||
1928 | return; | ||
1929 | } | ||
1930 | |||
1931 | |||
1932 | |||
1933 | /*=========================================================== | ||
1934 | * rx_intr Receive interrupt handler. | ||
1935 | * | ||
1936 | * Description | ||
1937 | * Upon receiveing an interrupt: | ||
1938 | * 1. Check that the firmware is in sync with | ||
1939 | * the driver. | ||
1940 | * 2. Find an appropriate network interface | ||
1941 | * based on the received dlci number. | ||
1942 | * 3. Check that the netowrk interface exists | ||
1943 | * and that it's setup properly. | ||
1944 | * 4. Copy the data into an skb buffer. | ||
1945 | * 5. Check the packet type and take | ||
1946 | * appropriate acton: UPD, API, ARP or Data. | ||
1947 | */ | ||
1948 | |||
1949 | static void rx_intr (sdla_t* card) | ||
1950 | { | ||
1951 | fr_rx_buf_ctl_t* frbuf = card->rxmb; | ||
1952 | fr508_flags_t* flags = card->flags; | ||
1953 | fr_channel_t* chan; | ||
1954 | char *ptr = &flags->iflag; | ||
1955 | struct sk_buff* skb; | ||
1956 | struct net_device* dev; | ||
1957 | void* buf; | ||
1958 | unsigned dlci, len, offs, len_incl_hdr; | ||
1959 | int i, udp_type; | ||
1960 | |||
1961 | |||
1962 | /* Check that firmware buffers are in sync */ | ||
1963 | if (frbuf->flag != 0x01) { | ||
1964 | |||
1965 | printk(KERN_INFO | ||
1966 | "%s: corrupted Rx buffer @ 0x%X, flag = 0x%02X!\n", | ||
1967 | card->devname, (unsigned)frbuf, frbuf->flag); | ||
1968 | |||
1969 | printk(KERN_INFO "%s: ID Bytes = ",card->devname); | ||
1970 | for(i = 0; i < 8; i ++) | ||
1971 | printk(KERN_INFO "0x%02X ", *(ptr + 0x28 + i)); | ||
1972 | printk(KERN_INFO "\n"); | ||
1973 | |||
1974 | ++card->statistics.rx_intr_corrupt_rx_bfr; | ||
1975 | |||
1976 | /* Bug Fix: Mar 6 2000 | ||
1977 | * If we get a corrupted mailbox, it means that driver | ||
1978 | * is out of sync with the firmware. There is no recovery. | ||
1979 | * If we don't turn off all interrupts for this card | ||
1980 | * the machine will crash. | ||
1981 | */ | ||
1982 | printk(KERN_INFO "%s: Critical router failure ...!!!\n", card->devname); | ||
1983 | printk(KERN_INFO "Please contact Sangoma Technologies !\n"); | ||
1984 | fr_set_intr_mode(card, 0, 0, 0); | ||
1985 | return; | ||
1986 | } | ||
1987 | |||
1988 | len = frbuf->length; | ||
1989 | dlci = frbuf->dlci; | ||
1990 | offs = frbuf->offset; | ||
1991 | |||
1992 | /* Find the network interface for this packet */ | ||
1993 | dev = find_channel(card, dlci); | ||
1994 | |||
1995 | |||
1996 | /* Check that the network interface is active and | ||
1997 | * properly setup */ | ||
1998 | if (dev == NULL) { | ||
1999 | if( net_ratelimit()) { | ||
2000 | printk(KERN_INFO "%s: received data on unconfigured DLCI %d!\n", | ||
2001 | card->devname, dlci); | ||
2002 | } | ||
2003 | ++card->statistics.rx_intr_on_orphaned_DLCI; | ||
2004 | ++card->wandev.stats.rx_dropped; | ||
2005 | goto rx_done; | ||
2006 | } | ||
2007 | |||
2008 | if ((chan = dev->priv) == NULL){ | ||
2009 | if( net_ratelimit()) { | ||
2010 | printk(KERN_INFO "%s: received data on unconfigured DLCI %d!\n", | ||
2011 | card->devname, dlci); | ||
2012 | } | ||
2013 | ++card->statistics.rx_intr_on_orphaned_DLCI; | ||
2014 | ++card->wandev.stats.rx_dropped; | ||
2015 | goto rx_done; | ||
2016 | } | ||
2017 | |||
2018 | skb = dev_alloc_skb(len); | ||
2019 | |||
2020 | if (!netif_running(dev) || (skb == NULL)){ | ||
2021 | |||
2022 | ++chan->ifstats.rx_dropped; | ||
2023 | |||
2024 | if(skb == NULL) { | ||
2025 | if (net_ratelimit()) { | ||
2026 | printk(KERN_INFO | ||
2027 | "%s: no socket buffers available!\n", | ||
2028 | card->devname); | ||
2029 | } | ||
2030 | chan->drvstats_rx_intr.rx_intr_no_socket ++; | ||
2031 | } | ||
2032 | |||
2033 | if (!netif_running(dev)){ | ||
2034 | chan->drvstats_rx_intr. | ||
2035 | rx_intr_dev_not_started ++; | ||
2036 | if (skb){ | ||
2037 | dev_kfree_skb_any(skb); | ||
2038 | } | ||
2039 | } | ||
2040 | goto rx_done; | ||
2041 | } | ||
2042 | |||
2043 | /* Copy data from the board into the socket buffer */ | ||
2044 | if ((offs + len) > card->u.f.rx_top + 1) { | ||
2045 | unsigned tmp = card->u.f.rx_top - offs + 1; | ||
2046 | |||
2047 | buf = skb_put(skb, tmp); | ||
2048 | sdla_peek(&card->hw, offs, buf, tmp); | ||
2049 | offs = card->u.f.rx_base; | ||
2050 | len -= tmp; | ||
2051 | } | ||
2052 | |||
2053 | buf = skb_put(skb, len); | ||
2054 | sdla_peek(&card->hw, offs, buf, len); | ||
2055 | |||
2056 | |||
2057 | /* We got the packet from the bard. | ||
2058 | * Check the packet type and take appropriate action */ | ||
2059 | |||
2060 | udp_type = udp_pkt_type( skb, card ); | ||
2061 | |||
2062 | if(udp_type != UDP_INVALID_TYPE) { | ||
2063 | |||
2064 | /* UDP Debug packet received, store the | ||
2065 | * packet and handle it in timer interrupt */ | ||
2066 | |||
2067 | skb_pull(skb, 1); | ||
2068 | if (wanrouter_type_trans(skb, dev)){ | ||
2069 | if(store_udp_mgmt_pkt(udp_type,UDP_PKT_FRM_NETWORK,card,skb,dlci)){ | ||
2070 | |||
2071 | flags->imask |= FR_INTR_TIMER; | ||
2072 | |||
2073 | if (udp_type == UDP_FPIPE_TYPE){ | ||
2074 | ++chan->drvstats_rx_intr.rx_intr_PIPE_request; | ||
2075 | } | ||
2076 | } | ||
2077 | } | ||
2078 | |||
2079 | }else if (chan->common.usedby == API) { | ||
2080 | |||
2081 | /* We are in API mode. | ||
2082 | * Add an API header to the RAW packet | ||
2083 | * and queue it into a circular buffer. | ||
2084 | * Then kick the fr_bh() bottom half handler */ | ||
2085 | |||
2086 | api_rx_hdr_t* api_rx_hdr; | ||
2087 | chan->drvstats_rx_intr.rx_intr_bfr_passed_to_stack ++; | ||
2088 | chan->ifstats.rx_packets ++; | ||
2089 | card->wandev.stats.rx_packets ++; | ||
2090 | |||
2091 | chan->ifstats.rx_bytes += skb->len; | ||
2092 | card->wandev.stats.rx_bytes += skb->len; | ||
2093 | |||
2094 | skb_push(skb, sizeof(api_rx_hdr_t)); | ||
2095 | api_rx_hdr = (api_rx_hdr_t*)&skb->data[0x00]; | ||
2096 | api_rx_hdr->attr = frbuf->attr; | ||
2097 | api_rx_hdr->time_stamp = frbuf->tmstamp; | ||
2098 | |||
2099 | skb->protocol = htons(ETH_P_IP); | ||
2100 | skb->mac.raw = skb->data; | ||
2101 | skb->dev = dev; | ||
2102 | skb->pkt_type = WAN_PACKET_DATA; | ||
2103 | |||
2104 | bh_enqueue(dev, skb); | ||
2105 | |||
2106 | trigger_fr_bh(chan); | ||
2107 | |||
2108 | }else if (handle_IPXWAN(skb->data,chan->name,chan->enable_IPX, chan->network_number)){ | ||
2109 | |||
2110 | //FIXME: Frame Relay IPX is not supported, Yet ! | ||
2111 | //if (chan->enable_IPX) { | ||
2112 | // fr_send(card, dlci, 0, skb->len,skb->data); | ||
2113 | //} | ||
2114 | dev_kfree_skb_any(skb); | ||
2115 | |||
2116 | } else if (is_arp(skb->data)) { | ||
2117 | |||
2118 | /* ARP support enabled Mar 16 2000 | ||
2119 | * Process incoming ARP reply/request, setup | ||
2120 | * dynamic routes. */ | ||
2121 | |||
2122 | if (process_ARP((arphdr_1490_t *)skb->data, card, dev)) { | ||
2123 | if (net_ratelimit()){ | ||
2124 | printk (KERN_INFO | ||
2125 | "%s: Error processing ARP Packet.\n", | ||
2126 | card->devname); | ||
2127 | } | ||
2128 | } | ||
2129 | dev_kfree_skb_any(skb); | ||
2130 | |||
2131 | } else if (skb->data[0] != 0x03) { | ||
2132 | |||
2133 | if (net_ratelimit()) { | ||
2134 | printk(KERN_INFO "%s: Non IETF packet discarded.\n", | ||
2135 | card->devname); | ||
2136 | } | ||
2137 | dev_kfree_skb_any(skb); | ||
2138 | |||
2139 | } else { | ||
2140 | |||
2141 | len_incl_hdr = skb->len; | ||
2142 | /* Decapsulate packet and pass it up the | ||
2143 | protocol stack */ | ||
2144 | skb->dev = dev; | ||
2145 | |||
2146 | if (chan->common.usedby == BRIDGE || chan->common.usedby == BRIDGE_NODE){ | ||
2147 | |||
2148 | /* Make sure it's an Ethernet frame, otherwise drop it */ | ||
2149 | if (!memcmp(skb->data, "\x03\x00\x80\x00\x80\xC2\x00\x07", 8)) { | ||
2150 | skb_pull(skb, 8); | ||
2151 | skb->protocol=eth_type_trans(skb,dev); | ||
2152 | }else{ | ||
2153 | ++chan->drvstats_rx_intr.rx_intr_bfr_not_passed_to_stack; | ||
2154 | ++chan->ifstats.rx_errors; | ||
2155 | ++card->wandev.stats.rx_errors; | ||
2156 | goto rx_done; | ||
2157 | } | ||
2158 | }else{ | ||
2159 | |||
2160 | /* remove hardware header */ | ||
2161 | buf = skb_pull(skb, 1); | ||
2162 | |||
2163 | if (!wanrouter_type_trans(skb, dev)) { | ||
2164 | |||
2165 | /* can't decapsulate packet */ | ||
2166 | dev_kfree_skb_any(skb); | ||
2167 | |||
2168 | ++chan->drvstats_rx_intr.rx_intr_bfr_not_passed_to_stack; | ||
2169 | ++chan->ifstats.rx_errors; | ||
2170 | ++card->wandev.stats.rx_errors; | ||
2171 | goto rx_done; | ||
2172 | } | ||
2173 | skb->mac.raw = skb->data; | ||
2174 | } | ||
2175 | |||
2176 | |||
2177 | /* Send a packet up the IP stack */ | ||
2178 | skb->dev->last_rx = jiffies; | ||
2179 | netif_rx(skb); | ||
2180 | ++chan->drvstats_rx_intr.rx_intr_bfr_passed_to_stack; | ||
2181 | ++chan->ifstats.rx_packets; | ||
2182 | ++card->wandev.stats.rx_packets; | ||
2183 | |||
2184 | chan->ifstats.rx_bytes += len_incl_hdr; | ||
2185 | card->wandev.stats.rx_bytes += len_incl_hdr; | ||
2186 | } | ||
2187 | |||
2188 | rx_done: | ||
2189 | |||
2190 | /* Release buffer element and calculate a pointer to the next one */ | ||
2191 | frbuf->flag = 0; | ||
2192 | card->rxmb = ++frbuf; | ||
2193 | if ((void*)frbuf > card->u.f.rxmb_last) | ||
2194 | card->rxmb = card->u.f.rxmb_base; | ||
2195 | |||
2196 | } | ||
2197 | |||
2198 | /*================================================================== | ||
2199 | * tx_intr: Transmit interrupt handler. | ||
2200 | * | ||
2201 | * Rationale: | ||
2202 | * If the board is busy transmitting, if_send() will | ||
2203 | * buffers a single packet and turn on | ||
2204 | * the tx interrupt. Tx interrupt will be called | ||
2205 | * by the board, once the firmware can send more | ||
2206 | * data. Thus, no polling is required. | ||
2207 | * | ||
2208 | * Description: | ||
2209 | * Tx interrupt is called for each | ||
2210 | * configured dlci channel. Thus: | ||
2211 | * 1. Obtain the netowrk interface based on the | ||
2212 | * dlci number. | ||
2213 | * 2. Check that network interface is up and | ||
2214 | * properly setup. | ||
2215 | * 3. Check for a buffered packet. | ||
2216 | * 4. Transmit the packet. | ||
2217 | * 5. If we are in WANPIPE mode, mark the | ||
2218 | * NET_BH handler. | ||
2219 | * 6. If we are in API mode, kick | ||
2220 | * the AF_WANPIPE socket for more data. | ||
2221 | * | ||
2222 | */ | ||
2223 | static void tx_intr(sdla_t *card) | ||
2224 | { | ||
2225 | fr508_flags_t* flags = card->flags; | ||
2226 | fr_tx_buf_ctl_t* bctl; | ||
2227 | struct net_device* dev; | ||
2228 | fr_channel_t* chan; | ||
2229 | |||
2230 | if(card->hw.type == SDLA_S514){ | ||
2231 | bctl = (void*)(flags->tse_offs + card->hw.dpmbase); | ||
2232 | }else{ | ||
2233 | bctl = (void*)(flags->tse_offs - FR_MB_VECTOR + | ||
2234 | card->hw.dpmbase); | ||
2235 | } | ||
2236 | |||
2237 | /* Find the structure and make it unbusy */ | ||
2238 | dev = find_channel(card, flags->dlci); | ||
2239 | if (dev == NULL){ | ||
2240 | printk(KERN_INFO "NO DEV IN TX Interrupt\n"); | ||
2241 | goto end_of_tx_intr; | ||
2242 | } | ||
2243 | |||
2244 | if ((chan = dev->priv) == NULL){ | ||
2245 | printk(KERN_INFO "NO CHAN IN TX Interrupt\n"); | ||
2246 | goto end_of_tx_intr; | ||
2247 | } | ||
2248 | |||
2249 | if(!chan->transmit_length || !chan->delay_skb) { | ||
2250 | printk(KERN_INFO "%s: tx int error - transmit length zero\n", | ||
2251 | card->wandev.name); | ||
2252 | goto end_of_tx_intr; | ||
2253 | } | ||
2254 | |||
2255 | /* If the 'if_send()' procedure is currently checking the 'tbusy' | ||
2256 | status, then we cannot transmit. Instead, we configure the microcode | ||
2257 | so as to re-issue this transmit interrupt at a later stage. | ||
2258 | */ | ||
2259 | if (test_bit(SEND_TXIRQ_CRIT, (void*)&card->wandev.critical)) { | ||
2260 | |||
2261 | fr_dlci_interface_t* dlci_interface = chan->dlci_int_interface; | ||
2262 | bctl->flag = 0xA0; | ||
2263 | dlci_interface->gen_interrupt |= FR_INTR_TXRDY; | ||
2264 | return; | ||
2265 | |||
2266 | }else{ | ||
2267 | bctl->dlci = flags->dlci; | ||
2268 | bctl->length = chan->transmit_length+chan->fr_header_len; | ||
2269 | sdla_poke(&card->hw, | ||
2270 | fr_send_hdr(card,bctl->dlci,bctl->offset), | ||
2271 | chan->delay_skb->data, | ||
2272 | chan->delay_skb->len); | ||
2273 | bctl->flag = 0xC0; | ||
2274 | |||
2275 | ++chan->ifstats.tx_packets; | ||
2276 | ++card->wandev.stats.tx_packets; | ||
2277 | chan->ifstats.tx_bytes += chan->transmit_length; | ||
2278 | card->wandev.stats.tx_bytes += chan->transmit_length; | ||
2279 | |||
2280 | /* We must free an sk buffer, which we used | ||
2281 | * for delayed transmission; Otherwise, the sock | ||
2282 | * will run out of memory */ | ||
2283 | dev_kfree_skb_any(chan->delay_skb); | ||
2284 | |||
2285 | chan->delay_skb = NULL; | ||
2286 | chan->transmit_length = 0; | ||
2287 | |||
2288 | dev->trans_start = jiffies; | ||
2289 | |||
2290 | if (netif_queue_stopped(dev)){ | ||
2291 | /* If using API, than wakeup socket BH handler */ | ||
2292 | if (chan->common.usedby == API){ | ||
2293 | netif_start_queue(dev); | ||
2294 | wakeup_sk_bh(dev); | ||
2295 | }else{ | ||
2296 | netif_wake_queue(dev); | ||
2297 | } | ||
2298 | } | ||
2299 | } | ||
2300 | |||
2301 | end_of_tx_intr: | ||
2302 | |||
2303 | /* if any other interfaces have transmit interrupts pending, | ||
2304 | * do not disable the global transmit interrupt */ | ||
2305 | if(!(-- card->u.f.tx_interrupts_pending)) | ||
2306 | flags->imask &= ~FR_INTR_TXRDY; | ||
2307 | |||
2308 | |||
2309 | } | ||
2310 | |||
2311 | |||
2312 | /*============================================================================ | ||
2313 | * timer_intr: Timer interrupt handler. | ||
2314 | * | ||
2315 | * Rationale: | ||
2316 | * All commans must be executed within the timer | ||
2317 | * interrupt since no two commands should execute | ||
2318 | * at the same time. | ||
2319 | * | ||
2320 | * Description: | ||
2321 | * The timer interrupt is used to: | ||
2322 | * 1. Processing udp calls from 'fpipemon'. | ||
2323 | * 2. Processing update calls from /proc file system | ||
2324 | * 3. Reading board-level statistics for | ||
2325 | * updating the proc file system. | ||
2326 | * 4. Sending inverse ARP request packets. | ||
2327 | * 5. Configure a dlci/channel. | ||
2328 | * 6. Unconfigure a dlci/channel. (Node only) | ||
2329 | */ | ||
2330 | |||
2331 | static void timer_intr(sdla_t *card) | ||
2332 | { | ||
2333 | fr508_flags_t* flags = card->flags; | ||
2334 | |||
2335 | /* UDP Debuging: fpipemon call */ | ||
2336 | if (card->u.f.timer_int_enabled & TMR_INT_ENABLED_UDP) { | ||
2337 | if(card->u.f.udp_type == UDP_FPIPE_TYPE) { | ||
2338 | if(process_udp_mgmt_pkt(card)) { | ||
2339 | card->u.f.timer_int_enabled &= | ||
2340 | ~TMR_INT_ENABLED_UDP; | ||
2341 | } | ||
2342 | } | ||
2343 | } | ||
2344 | |||
2345 | /* /proc update call : triggered from update() */ | ||
2346 | if (card->u.f.timer_int_enabled & TMR_INT_ENABLED_UPDATE) { | ||
2347 | fr_get_err_stats(card); | ||
2348 | fr_get_stats(card); | ||
2349 | card->u.f.update_comms_stats = 0; | ||
2350 | card->u.f.timer_int_enabled &= ~TMR_INT_ENABLED_UPDATE; | ||
2351 | } | ||
2352 | |||
2353 | /* Update the channel state call. This is call is | ||
2354 | * triggered by if_send() function */ | ||
2355 | if (card->u.f.timer_int_enabled & TMR_INT_ENABLED_UPDATE_STATE){ | ||
2356 | struct net_device *dev; | ||
2357 | if (card->wandev.state == WAN_CONNECTED){ | ||
2358 | for (dev = card->wandev.dev; dev; | ||
2359 | dev = *((struct net_device **)dev->priv)){ | ||
2360 | fr_channel_t *chan = dev->priv; | ||
2361 | if (chan->common.state != WAN_CONNECTED){ | ||
2362 | update_chan_state(dev); | ||
2363 | } | ||
2364 | } | ||
2365 | } | ||
2366 | card->u.f.timer_int_enabled &= ~TMR_INT_ENABLED_UPDATE_STATE; | ||
2367 | } | ||
2368 | |||
2369 | /* configure a dlci/channel */ | ||
2370 | if (card->u.f.timer_int_enabled & TMR_INT_ENABLED_CONFIG){ | ||
2371 | config_fr(card); | ||
2372 | card->u.f.timer_int_enabled &= ~TMR_INT_ENABLED_CONFIG; | ||
2373 | } | ||
2374 | |||
2375 | /* unconfigure a dlci/channel */ | ||
2376 | if (card->u.f.timer_int_enabled & TMR_INT_ENABLED_UNCONFIG){ | ||
2377 | unconfig_fr(card); | ||
2378 | card->u.f.timer_int_enabled &= ~TMR_INT_ENABLED_UNCONFIG; | ||
2379 | } | ||
2380 | |||
2381 | |||
2382 | /* Transmit ARP packets */ | ||
2383 | if (card->u.f.timer_int_enabled & TMR_INT_ENABLED_ARP){ | ||
2384 | int i=0; | ||
2385 | struct net_device *dev; | ||
2386 | |||
2387 | if (card->u.f.arp_dev == NULL) | ||
2388 | card->u.f.arp_dev = card->wandev.dev; | ||
2389 | |||
2390 | dev = card->u.f.arp_dev; | ||
2391 | |||
2392 | for (;;){ | ||
2393 | |||
2394 | fr_channel_t *chan = dev->priv; | ||
2395 | |||
2396 | /* If the interface is brought down cancel sending In-ARPs */ | ||
2397 | if (!(dev->flags&IFF_UP)){ | ||
2398 | clear_bit(0,&chan->inarp_ready); | ||
2399 | } | ||
2400 | |||
2401 | if (test_bit(0,&chan->inarp_ready)){ | ||
2402 | |||
2403 | if (check_tx_status(card,dev)){ | ||
2404 | set_bit(ARP_CRIT,&card->wandev.critical); | ||
2405 | break; | ||
2406 | } | ||
2407 | |||
2408 | if (!send_inarp_request(card,dev)){ | ||
2409 | trigger_fr_arp(dev); | ||
2410 | chan->inarp_tick = jiffies; | ||
2411 | } | ||
2412 | |||
2413 | clear_bit(0,&chan->inarp_ready); | ||
2414 | dev = move_dev_to_next(card,dev); | ||
2415 | break; | ||
2416 | } | ||
2417 | dev = move_dev_to_next(card,dev); | ||
2418 | |||
2419 | if (++i == card->wandev.new_if_cnt){ | ||
2420 | card->u.f.timer_int_enabled &= ~TMR_INT_ENABLED_ARP; | ||
2421 | break; | ||
2422 | } | ||
2423 | } | ||
2424 | card->u.f.arp_dev = dev; | ||
2425 | } | ||
2426 | |||
2427 | if(!card->u.f.timer_int_enabled) | ||
2428 | flags->imask &= ~FR_INTR_TIMER; | ||
2429 | } | ||
2430 | |||
2431 | |||
2432 | /*============================================================================ | ||
2433 | * spur_intr: Spurious interrupt handler. | ||
2434 | * | ||
2435 | * Description: | ||
2436 | * We don't know this interrupt. | ||
2437 | * Print a warning. | ||
2438 | */ | ||
2439 | |||
2440 | static void spur_intr (sdla_t* card) | ||
2441 | { | ||
2442 | if (net_ratelimit()){ | ||
2443 | printk(KERN_INFO "%s: spurious interrupt!\n", card->devname); | ||
2444 | } | ||
2445 | } | ||
2446 | |||
2447 | |||
2448 | //FIXME: Fix the IPX in next version | ||
2449 | /*=========================================================================== | ||
2450 | * Return 0 for non-IPXWAN packet | ||
2451 | * 1 for IPXWAN packet or IPX is not enabled! | ||
2452 | * FIXME: Use a IPX structure here not offsets | ||
2453 | */ | ||
2454 | static int handle_IPXWAN(unsigned char *sendpacket, | ||
2455 | char *devname, unsigned char enable_IPX, | ||
2456 | unsigned long network_number) | ||
2457 | { | ||
2458 | int i; | ||
2459 | |||
2460 | if( sendpacket[1] == 0x00 && sendpacket[2] == 0x80 && | ||
2461 | sendpacket[6] == 0x81 && sendpacket[7] == 0x37) { | ||
2462 | |||
2463 | /* It's an IPX packet */ | ||
2464 | if (!enable_IPX){ | ||
2465 | /* Return 1 so we don't pass it up the stack. */ | ||
2466 | //FIXME: Take this out when IPX is fixed | ||
2467 | if (net_ratelimit()){ | ||
2468 | printk (KERN_INFO | ||
2469 | "%s: WARNING: Unsupported IPX packet received and dropped\n", | ||
2470 | devname); | ||
2471 | } | ||
2472 | return 1; | ||
2473 | } | ||
2474 | } else { | ||
2475 | /* It's not IPX so return and pass it up the stack. */ | ||
2476 | return 0; | ||
2477 | } | ||
2478 | |||
2479 | if( sendpacket[24] == 0x90 && sendpacket[25] == 0x04){ | ||
2480 | /* It's IPXWAN */ | ||
2481 | |||
2482 | if( sendpacket[10] == 0x02 && sendpacket[42] == 0x00){ | ||
2483 | |||
2484 | /* It's a timer request packet */ | ||
2485 | printk(KERN_INFO "%s: Received IPXWAN Timer Request packet\n", | ||
2486 | devname); | ||
2487 | |||
2488 | /* Go through the routing options and answer no to every | ||
2489 | * option except Unnumbered RIP/SAP | ||
2490 | */ | ||
2491 | for(i = 49; sendpacket[i] == 0x00; i += 5){ | ||
2492 | /* 0x02 is the option for Unnumbered RIP/SAP */ | ||
2493 | if( sendpacket[i + 4] != 0x02){ | ||
2494 | sendpacket[i + 1] = 0; | ||
2495 | } | ||
2496 | } | ||
2497 | |||
2498 | /* Skip over the extended Node ID option */ | ||
2499 | if( sendpacket[i] == 0x04 ){ | ||
2500 | i += 8; | ||
2501 | } | ||
2502 | |||
2503 | /* We also want to turn off all header compression opt. | ||
2504 | */ | ||
2505 | for(; sendpacket[i] == 0x80 ;){ | ||
2506 | sendpacket[i + 1] = 0; | ||
2507 | i += (sendpacket[i + 2] << 8) + (sendpacket[i + 3]) + 4; | ||
2508 | } | ||
2509 | |||
2510 | /* Set the packet type to timer response */ | ||
2511 | sendpacket[42] = 0x01; | ||
2512 | |||
2513 | printk(KERN_INFO "%s: Sending IPXWAN Timer Response\n", | ||
2514 | devname); | ||
2515 | |||
2516 | } else if( sendpacket[42] == 0x02 ){ | ||
2517 | |||
2518 | /* This is an information request packet */ | ||
2519 | printk(KERN_INFO | ||
2520 | "%s: Received IPXWAN Information Request packet\n", | ||
2521 | devname); | ||
2522 | |||
2523 | /* Set the packet type to information response */ | ||
2524 | sendpacket[42] = 0x03; | ||
2525 | |||
2526 | /* Set the router name */ | ||
2527 | sendpacket[59] = 'F'; | ||
2528 | sendpacket[60] = 'P'; | ||
2529 | sendpacket[61] = 'I'; | ||
2530 | sendpacket[62] = 'P'; | ||
2531 | sendpacket[63] = 'E'; | ||
2532 | sendpacket[64] = '-'; | ||
2533 | sendpacket[65] = CVHexToAscii(network_number >> 28); | ||
2534 | sendpacket[66] = CVHexToAscii((network_number & 0x0F000000)>> 24); | ||
2535 | sendpacket[67] = CVHexToAscii((network_number & 0x00F00000)>> 20); | ||
2536 | sendpacket[68] = CVHexToAscii((network_number & 0x000F0000)>> 16); | ||
2537 | sendpacket[69] = CVHexToAscii((network_number & 0x0000F000)>> 12); | ||
2538 | sendpacket[70] = CVHexToAscii((network_number & 0x00000F00)>> 8); | ||
2539 | sendpacket[71] = CVHexToAscii((network_number & 0x000000F0)>> 4); | ||
2540 | sendpacket[72] = CVHexToAscii(network_number & 0x0000000F); | ||
2541 | for(i = 73; i < 107; i+= 1) | ||
2542 | { | ||
2543 | sendpacket[i] = 0; | ||
2544 | } | ||
2545 | |||
2546 | printk(KERN_INFO "%s: Sending IPXWAN Information Response packet\n", | ||
2547 | devname); | ||
2548 | } else { | ||
2549 | |||
2550 | printk(KERN_INFO "%s: Unknown IPXWAN packet!\n",devname); | ||
2551 | return 0; | ||
2552 | } | ||
2553 | |||
2554 | /* Set the WNodeID to our network address */ | ||
2555 | sendpacket[43] = (unsigned char)(network_number >> 24); | ||
2556 | sendpacket[44] = (unsigned char)((network_number & 0x00FF0000) >> 16); | ||
2557 | sendpacket[45] = (unsigned char)((network_number & 0x0000FF00) >> 8); | ||
2558 | sendpacket[46] = (unsigned char)(network_number & 0x000000FF); | ||
2559 | |||
2560 | return 1; | ||
2561 | } | ||
2562 | |||
2563 | /* If we get here, it's an IPX-data packet so it'll get passed up the | ||
2564 | * stack. | ||
2565 | * switch the network numbers | ||
2566 | */ | ||
2567 | switch_net_numbers(sendpacket, network_number ,1); | ||
2568 | return 0; | ||
2569 | } | ||
2570 | /*============================================================================ | ||
2571 | * process_route | ||
2572 | * | ||
2573 | * Rationale: | ||
2574 | * If the interface goes down, or we receive an ARP request, | ||
2575 | * we have to change the network interface ip addresses. | ||
2576 | * This cannot be done within the interrupt. | ||
2577 | * | ||
2578 | * Description: | ||
2579 | * | ||
2580 | * This routine is called as a polling routine to dynamically | ||
2581 | * add/delete routes negotiated by inverse ARP. It is in this | ||
2582 | * "task" because we don't want routes to be added while in | ||
2583 | * interrupt context. | ||
2584 | * | ||
2585 | * Usage: | ||
2586 | * This function is called by fr_poll() polling funtion. | ||
2587 | */ | ||
2588 | |||
2589 | static void process_route(struct net_device *dev) | ||
2590 | { | ||
2591 | fr_channel_t *chan = dev->priv; | ||
2592 | sdla_t *card = chan->card; | ||
2593 | |||
2594 | struct ifreq if_info; | ||
2595 | struct sockaddr_in *if_data; | ||
2596 | mm_segment_t fs = get_fs(); | ||
2597 | u32 ip_tmp; | ||
2598 | int err; | ||
2599 | |||
2600 | |||
2601 | switch(chan->route_flag){ | ||
2602 | |||
2603 | case ADD_ROUTE: | ||
2604 | |||
2605 | /* Set remote addresses */ | ||
2606 | memset(&if_info, 0, sizeof(if_info)); | ||
2607 | strcpy(if_info.ifr_name, dev->name); | ||
2608 | |||
2609 | set_fs(get_ds()); /* get user space block */ | ||
2610 | |||
2611 | if_data = (struct sockaddr_in *)&if_info.ifr_dstaddr; | ||
2612 | if_data->sin_addr.s_addr = chan->ip_remote; | ||
2613 | if_data->sin_family = AF_INET; | ||
2614 | err = devinet_ioctl( SIOCSIFDSTADDR, &if_info ); | ||
2615 | |||
2616 | set_fs(fs); /* restore old block */ | ||
2617 | |||
2618 | if (err) { | ||
2619 | printk(KERN_INFO | ||
2620 | "%s: Route Add failed. Error: %d\n", | ||
2621 | card->devname,err); | ||
2622 | printk(KERN_INFO "%s: Address: %u.%u.%u.%u\n", | ||
2623 | chan->name, NIPQUAD(chan->ip_remote)); | ||
2624 | |||
2625 | }else { | ||
2626 | printk(KERN_INFO "%s: Route Added Successfully: %u.%u.%u.%u\n", | ||
2627 | card->devname,NIPQUAD(chan->ip_remote)); | ||
2628 | chan->route_flag = ROUTE_ADDED; | ||
2629 | } | ||
2630 | break; | ||
2631 | |||
2632 | case REMOVE_ROUTE: | ||
2633 | |||
2634 | /* Set remote addresses */ | ||
2635 | memset(&if_info, 0, sizeof(if_info)); | ||
2636 | strcpy(if_info.ifr_name, dev->name); | ||
2637 | |||
2638 | ip_tmp = get_ip_address(dev,WAN_POINTOPOINT_IP); | ||
2639 | |||
2640 | set_fs(get_ds()); /* get user space block */ | ||
2641 | |||
2642 | if_data = (struct sockaddr_in *)&if_info.ifr_dstaddr; | ||
2643 | if_data->sin_addr.s_addr = 0; | ||
2644 | if_data->sin_family = AF_INET; | ||
2645 | err = devinet_ioctl( SIOCSIFDSTADDR, &if_info ); | ||
2646 | |||
2647 | set_fs(fs); | ||
2648 | |||
2649 | if (err) { | ||
2650 | printk(KERN_INFO | ||
2651 | "%s: Deleting of route failed. Error: %d\n", | ||
2652 | card->devname,err); | ||
2653 | printk(KERN_INFO "%s: Address: %u.%u.%u.%u\n", | ||
2654 | dev->name,NIPQUAD(chan->ip_remote) ); | ||
2655 | |||
2656 | } else { | ||
2657 | printk(KERN_INFO "%s: Route Removed Sucessfuly: %u.%u.%u.%u\n", | ||
2658 | card->devname,NIPQUAD(ip_tmp)); | ||
2659 | chan->route_flag = NO_ROUTE; | ||
2660 | } | ||
2661 | break; | ||
2662 | |||
2663 | } /* Case Statement */ | ||
2664 | |||
2665 | } | ||
2666 | |||
2667 | |||
2668 | |||
2669 | /****** Frame Relay Firmware-Specific Functions *****************************/ | ||
2670 | |||
2671 | /*============================================================================ | ||
2672 | * Read firmware code version. | ||
2673 | * o fill string str with firmware version info. | ||
2674 | */ | ||
2675 | static int fr_read_version (sdla_t* card, char* str) | ||
2676 | { | ||
2677 | fr_mbox_t* mbox = card->mbox; | ||
2678 | int retry = MAX_CMD_RETRY; | ||
2679 | int err; | ||
2680 | |||
2681 | do | ||
2682 | { | ||
2683 | mbox->cmd.command = FR_READ_CODE_VERSION; | ||
2684 | mbox->cmd.length = 0; | ||
2685 | err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; | ||
2686 | } while (err && retry-- && fr_event(card, err, mbox)); | ||
2687 | |||
2688 | if (!err && str) { | ||
2689 | int len = mbox->cmd.length; | ||
2690 | memcpy(str, mbox->data, len); | ||
2691 | str[len] = '\0'; | ||
2692 | } | ||
2693 | return err; | ||
2694 | } | ||
2695 | |||
2696 | /*============================================================================ | ||
2697 | * Set global configuration. | ||
2698 | */ | ||
2699 | static int fr_configure (sdla_t* card, fr_conf_t *conf) | ||
2700 | { | ||
2701 | fr_mbox_t* mbox = card->mbox; | ||
2702 | int retry = MAX_CMD_RETRY; | ||
2703 | int dlci_num = card->u.f.dlci_num; | ||
2704 | int err, i; | ||
2705 | |||
2706 | do | ||
2707 | { | ||
2708 | memcpy(mbox->data, conf, sizeof(fr_conf_t)); | ||
2709 | |||
2710 | if (dlci_num) for (i = 0; i < dlci_num; ++i) | ||
2711 | ((fr_conf_t*)mbox->data)->dlci[i] = | ||
2712 | card->u.f.node_dlci[i]; | ||
2713 | |||
2714 | mbox->cmd.command = FR_SET_CONFIG; | ||
2715 | mbox->cmd.length = | ||
2716 | sizeof(fr_conf_t) + dlci_num * sizeof(short); | ||
2717 | |||
2718 | err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; | ||
2719 | |||
2720 | } while (err && retry-- && fr_event(card, err, mbox)); | ||
2721 | |||
2722 | /*NC Oct 12 2000 */ | ||
2723 | if (err != CMD_OK){ | ||
2724 | printk(KERN_ERR "%s: Frame Relay Configuration Failed: rc=0x%x\n", | ||
2725 | card->devname,err); | ||
2726 | } | ||
2727 | |||
2728 | return err; | ||
2729 | } | ||
2730 | |||
2731 | /*============================================================================ | ||
2732 | * Set DLCI configuration. | ||
2733 | */ | ||
2734 | static int fr_dlci_configure (sdla_t* card, fr_dlc_conf_t *conf, unsigned dlci) | ||
2735 | { | ||
2736 | fr_mbox_t* mbox = card->mbox; | ||
2737 | int retry = MAX_CMD_RETRY; | ||
2738 | int err; | ||
2739 | |||
2740 | do | ||
2741 | { | ||
2742 | memcpy(mbox->data, conf, sizeof(fr_dlc_conf_t)); | ||
2743 | mbox->cmd.dlci = (unsigned short) dlci; | ||
2744 | mbox->cmd.command = FR_SET_CONFIG; | ||
2745 | mbox->cmd.length = sizeof(fr_dlc_conf_t); | ||
2746 | err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; | ||
2747 | } while (err && retry--); | ||
2748 | |||
2749 | return err; | ||
2750 | } | ||
2751 | /*============================================================================ | ||
2752 | * Set interrupt mode. | ||
2753 | */ | ||
2754 | static int fr_set_intr_mode (sdla_t* card, unsigned mode, unsigned mtu, | ||
2755 | unsigned short timeout) | ||
2756 | { | ||
2757 | fr_mbox_t* mbox = card->mbox; | ||
2758 | fr508_intr_ctl_t* ictl = (void*)mbox->data; | ||
2759 | int retry = MAX_CMD_RETRY; | ||
2760 | int err; | ||
2761 | |||
2762 | do | ||
2763 | { | ||
2764 | memset(ictl, 0, sizeof(fr508_intr_ctl_t)); | ||
2765 | ictl->mode = mode; | ||
2766 | ictl->tx_len = mtu; | ||
2767 | ictl->irq = card->hw.irq; | ||
2768 | |||
2769 | /* indicate timeout on timer */ | ||
2770 | if (mode & 0x20) ictl->timeout = timeout; | ||
2771 | |||
2772 | mbox->cmd.length = sizeof(fr508_intr_ctl_t); | ||
2773 | mbox->cmd.command = FR_SET_INTR_MODE; | ||
2774 | err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; | ||
2775 | |||
2776 | } while (err && retry-- && fr_event(card, err, mbox)); | ||
2777 | |||
2778 | return err; | ||
2779 | } | ||
2780 | |||
2781 | /*============================================================================ | ||
2782 | * Enable communications. | ||
2783 | */ | ||
2784 | static int fr_comm_enable (sdla_t* card) | ||
2785 | { | ||
2786 | fr_mbox_t* mbox = card->mbox; | ||
2787 | int retry = MAX_CMD_RETRY; | ||
2788 | int err; | ||
2789 | |||
2790 | do | ||
2791 | { | ||
2792 | mbox->cmd.command = FR_COMM_ENABLE; | ||
2793 | mbox->cmd.length = 0; | ||
2794 | err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; | ||
2795 | } while (err && retry-- && fr_event(card, err, mbox)); | ||
2796 | |||
2797 | return err; | ||
2798 | } | ||
2799 | |||
2800 | /*============================================================================ | ||
2801 | * fr_comm_disable | ||
2802 | * | ||
2803 | * Warning: This functin is called by the shutdown() procedure. It is void | ||
2804 | * since dev->priv are has already been deallocated and no | ||
2805 | * error checking is possible using fr_event() function. | ||
2806 | */ | ||
2807 | static void fr_comm_disable (sdla_t* card) | ||
2808 | { | ||
2809 | fr_mbox_t* mbox = card->mbox; | ||
2810 | int retry = MAX_CMD_RETRY; | ||
2811 | int err; | ||
2812 | |||
2813 | do { | ||
2814 | mbox->cmd.command = FR_SET_MODEM_STATUS; | ||
2815 | mbox->cmd.length = 1; | ||
2816 | mbox->data[0] = 0; | ||
2817 | err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; | ||
2818 | } while (err && retry--); | ||
2819 | |||
2820 | retry = MAX_CMD_RETRY; | ||
2821 | |||
2822 | do | ||
2823 | { | ||
2824 | mbox->cmd.command = FR_COMM_DISABLE; | ||
2825 | mbox->cmd.length = 0; | ||
2826 | err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; | ||
2827 | } while (err && retry--); | ||
2828 | |||
2829 | return; | ||
2830 | } | ||
2831 | |||
2832 | |||
2833 | |||
2834 | /*============================================================================ | ||
2835 | * Get communications error statistics. | ||
2836 | */ | ||
2837 | static int fr_get_err_stats (sdla_t* card) | ||
2838 | { | ||
2839 | fr_mbox_t* mbox = card->mbox; | ||
2840 | int retry = MAX_CMD_RETRY; | ||
2841 | int err; | ||
2842 | |||
2843 | |||
2844 | do | ||
2845 | { | ||
2846 | mbox->cmd.command = FR_READ_ERROR_STATS; | ||
2847 | mbox->cmd.length = 0; | ||
2848 | mbox->cmd.dlci = 0; | ||
2849 | err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; | ||
2850 | } while (err && retry-- && fr_event(card, err, mbox)); | ||
2851 | |||
2852 | if (!err) { | ||
2853 | fr_comm_stat_t* stats = (void*)mbox->data; | ||
2854 | card->wandev.stats.rx_over_errors = stats->rx_overruns; | ||
2855 | card->wandev.stats.rx_crc_errors = stats->rx_bad_crc; | ||
2856 | card->wandev.stats.rx_missed_errors = stats->rx_aborts; | ||
2857 | card->wandev.stats.rx_length_errors = stats->rx_too_long; | ||
2858 | card->wandev.stats.tx_aborted_errors = stats->tx_aborts; | ||
2859 | |||
2860 | } | ||
2861 | |||
2862 | return err; | ||
2863 | } | ||
2864 | |||
2865 | /*============================================================================ | ||
2866 | * Get statistics. | ||
2867 | */ | ||
2868 | static int fr_get_stats (sdla_t* card) | ||
2869 | { | ||
2870 | fr_mbox_t* mbox = card->mbox; | ||
2871 | int retry = MAX_CMD_RETRY; | ||
2872 | int err; | ||
2873 | |||
2874 | |||
2875 | do | ||
2876 | { | ||
2877 | mbox->cmd.command = FR_READ_STATISTICS; | ||
2878 | mbox->cmd.length = 0; | ||
2879 | mbox->cmd.dlci = 0; | ||
2880 | err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; | ||
2881 | } while (err && retry-- && fr_event(card, err, mbox)); | ||
2882 | |||
2883 | if (!err) { | ||
2884 | fr_link_stat_t* stats = (void*)mbox->data; | ||
2885 | card->wandev.stats.rx_frame_errors = stats->rx_bad_format; | ||
2886 | card->wandev.stats.rx_dropped = | ||
2887 | stats->rx_dropped + stats->rx_dropped2; | ||
2888 | } | ||
2889 | |||
2890 | return err; | ||
2891 | } | ||
2892 | |||
2893 | /*============================================================================ | ||
2894 | * Add DLCI(s) (Access Node only!). | ||
2895 | * This routine will perform the ADD_DLCIs command for the specified DLCI. | ||
2896 | */ | ||
2897 | static int fr_add_dlci (sdla_t* card, int dlci) | ||
2898 | { | ||
2899 | fr_mbox_t* mbox = card->mbox; | ||
2900 | int retry = MAX_CMD_RETRY; | ||
2901 | int err; | ||
2902 | |||
2903 | do | ||
2904 | { | ||
2905 | unsigned short* dlci_list = (void*)mbox->data; | ||
2906 | |||
2907 | mbox->cmd.length = sizeof(short); | ||
2908 | dlci_list[0] = dlci; | ||
2909 | mbox->cmd.command = FR_ADD_DLCI; | ||
2910 | err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; | ||
2911 | |||
2912 | } while (err && retry-- && fr_event(card, err, mbox)); | ||
2913 | |||
2914 | return err; | ||
2915 | } | ||
2916 | |||
2917 | /*============================================================================ | ||
2918 | * Activate DLCI(s) (Access Node only!). | ||
2919 | * This routine will perform the ACTIVATE_DLCIs command with a DLCI number. | ||
2920 | */ | ||
2921 | static int fr_activate_dlci (sdla_t* card, int dlci) | ||
2922 | { | ||
2923 | fr_mbox_t* mbox = card->mbox; | ||
2924 | int retry = MAX_CMD_RETRY; | ||
2925 | int err; | ||
2926 | |||
2927 | do | ||
2928 | { | ||
2929 | unsigned short* dlci_list = (void*)mbox->data; | ||
2930 | |||
2931 | mbox->cmd.length = sizeof(short); | ||
2932 | dlci_list[0] = dlci; | ||
2933 | mbox->cmd.command = FR_ACTIVATE_DLCI; | ||
2934 | err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; | ||
2935 | |||
2936 | } while (err && retry-- && fr_event(card, err, mbox)); | ||
2937 | |||
2938 | return err; | ||
2939 | } | ||
2940 | |||
2941 | /*============================================================================ | ||
2942 | * Delete DLCI(s) (Access Node only!). | ||
2943 | * This routine will perform the DELETE_DLCIs command with a DLCI number. | ||
2944 | */ | ||
2945 | static int fr_delete_dlci (sdla_t* card, int dlci) | ||
2946 | { | ||
2947 | fr_mbox_t* mbox = card->mbox; | ||
2948 | int retry = MAX_CMD_RETRY; | ||
2949 | int err; | ||
2950 | |||
2951 | do | ||
2952 | { | ||
2953 | unsigned short* dlci_list = (void*)mbox->data; | ||
2954 | |||
2955 | mbox->cmd.length = sizeof(short); | ||
2956 | dlci_list[0] = dlci; | ||
2957 | mbox->cmd.command = FR_DELETE_DLCI; | ||
2958 | err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; | ||
2959 | |||
2960 | } while (err && retry-- && fr_event(card, err, mbox)); | ||
2961 | |||
2962 | return err; | ||
2963 | } | ||
2964 | |||
2965 | |||
2966 | |||
2967 | /*============================================================================ | ||
2968 | * Issue in-channel signalling frame. | ||
2969 | */ | ||
2970 | static int fr_issue_isf (sdla_t* card, int isf) | ||
2971 | { | ||
2972 | fr_mbox_t* mbox = card->mbox; | ||
2973 | int retry = MAX_CMD_RETRY; | ||
2974 | int err; | ||
2975 | |||
2976 | do | ||
2977 | { | ||
2978 | mbox->data[0] = isf; | ||
2979 | mbox->cmd.length = 1; | ||
2980 | mbox->cmd.command = FR_ISSUE_IS_FRAME; | ||
2981 | err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; | ||
2982 | } while (err && retry-- && fr_event(card, err, mbox)); | ||
2983 | |||
2984 | return err; | ||
2985 | } | ||
2986 | |||
2987 | |||
2988 | static unsigned int fr_send_hdr (sdla_t*card, int dlci, unsigned int offset) | ||
2989 | { | ||
2990 | struct net_device *dev = find_channel(card,dlci); | ||
2991 | fr_channel_t *chan; | ||
2992 | |||
2993 | if (!dev || !(chan=dev->priv)) | ||
2994 | return offset; | ||
2995 | |||
2996 | if (chan->fr_header_len){ | ||
2997 | sdla_poke(&card->hw, offset, chan->fr_header, chan->fr_header_len); | ||
2998 | } | ||
2999 | |||
3000 | return offset+chan->fr_header_len; | ||
3001 | } | ||
3002 | |||
3003 | /*============================================================================ | ||
3004 | * Send a frame on a selected DLCI. | ||
3005 | */ | ||
3006 | static int fr_send_data_header (sdla_t* card, int dlci, unsigned char attr, int len, | ||
3007 | void *buf, unsigned char hdr_len) | ||
3008 | { | ||
3009 | fr_mbox_t* mbox = card->mbox + 0x800; | ||
3010 | int retry = MAX_CMD_RETRY; | ||
3011 | int err; | ||
3012 | |||
3013 | do | ||
3014 | { | ||
3015 | mbox->cmd.dlci = dlci; | ||
3016 | mbox->cmd.attr = attr; | ||
3017 | mbox->cmd.length = len+hdr_len; | ||
3018 | mbox->cmd.command = FR_WRITE; | ||
3019 | err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; | ||
3020 | } while (err && retry-- && fr_event(card, err, mbox)); | ||
3021 | |||
3022 | if (!err) { | ||
3023 | fr_tx_buf_ctl_t* frbuf; | ||
3024 | |||
3025 | if(card->hw.type == SDLA_S514) | ||
3026 | frbuf = (void*)(*(unsigned long*)mbox->data + | ||
3027 | card->hw.dpmbase); | ||
3028 | else | ||
3029 | frbuf = (void*)(*(unsigned long*)mbox->data - | ||
3030 | FR_MB_VECTOR + card->hw.dpmbase); | ||
3031 | |||
3032 | sdla_poke(&card->hw, fr_send_hdr(card,dlci,frbuf->offset), buf, len); | ||
3033 | frbuf->flag = 0x01; | ||
3034 | } | ||
3035 | |||
3036 | return err; | ||
3037 | } | ||
3038 | |||
3039 | static int fr_send (sdla_t* card, int dlci, unsigned char attr, int len, | ||
3040 | void *buf) | ||
3041 | { | ||
3042 | fr_mbox_t* mbox = card->mbox + 0x800; | ||
3043 | int retry = MAX_CMD_RETRY; | ||
3044 | int err; | ||
3045 | |||
3046 | do | ||
3047 | { | ||
3048 | mbox->cmd.dlci = dlci; | ||
3049 | mbox->cmd.attr = attr; | ||
3050 | mbox->cmd.length = len; | ||
3051 | mbox->cmd.command = FR_WRITE; | ||
3052 | err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; | ||
3053 | } while (err && retry-- && fr_event(card, err, mbox)); | ||
3054 | |||
3055 | if (!err) { | ||
3056 | fr_tx_buf_ctl_t* frbuf; | ||
3057 | |||
3058 | if(card->hw.type == SDLA_S514) | ||
3059 | frbuf = (void*)(*(unsigned long*)mbox->data + | ||
3060 | card->hw.dpmbase); | ||
3061 | else | ||
3062 | frbuf = (void*)(*(unsigned long*)mbox->data - | ||
3063 | FR_MB_VECTOR + card->hw.dpmbase); | ||
3064 | |||
3065 | sdla_poke(&card->hw, frbuf->offset, buf, len); | ||
3066 | frbuf->flag = 0x01; | ||
3067 | } | ||
3068 | |||
3069 | return err; | ||
3070 | } | ||
3071 | |||
3072 | |||
3073 | /****** Firmware Asynchronous Event Handlers ********************************/ | ||
3074 | |||
3075 | /*============================================================================ | ||
3076 | * Main asyncronous event/error handler. | ||
3077 | * This routine is called whenever firmware command returns non-zero | ||
3078 | * return code. | ||
3079 | * | ||
3080 | * Return zero if previous command has to be cancelled. | ||
3081 | */ | ||
3082 | static int fr_event (sdla_t *card, int event, fr_mbox_t* mbox) | ||
3083 | { | ||
3084 | fr508_flags_t* flags = card->flags; | ||
3085 | char *ptr = &flags->iflag; | ||
3086 | int i; | ||
3087 | |||
3088 | switch (event) { | ||
3089 | |||
3090 | case FRRES_MODEM_FAILURE: | ||
3091 | return fr_modem_failure(card, mbox); | ||
3092 | |||
3093 | case FRRES_CHANNEL_DOWN: { | ||
3094 | struct net_device *dev; | ||
3095 | |||
3096 | /* Remove all routes from associated DLCI's */ | ||
3097 | for (dev = card->wandev.dev; dev; | ||
3098 | dev = *((struct net_device **)dev->priv)) { | ||
3099 | fr_channel_t *chan = dev->priv; | ||
3100 | if (chan->route_flag == ROUTE_ADDED) { | ||
3101 | chan->route_flag = REMOVE_ROUTE; | ||
3102 | } | ||
3103 | |||
3104 | if (chan->inarp == INARP_CONFIGURED) { | ||
3105 | chan->inarp = INARP_REQUEST; | ||
3106 | } | ||
3107 | |||
3108 | /* If the link becomes disconnected then, | ||
3109 | * all channels will be disconnected | ||
3110 | * as well. | ||
3111 | */ | ||
3112 | set_chan_state(dev,WAN_DISCONNECTED); | ||
3113 | } | ||
3114 | |||
3115 | wanpipe_set_state(card, WAN_DISCONNECTED); | ||
3116 | return 1; | ||
3117 | } | ||
3118 | |||
3119 | case FRRES_CHANNEL_UP: { | ||
3120 | struct net_device *dev; | ||
3121 | |||
3122 | /* FIXME: Only startup devices that are on the list */ | ||
3123 | |||
3124 | for (dev = card->wandev.dev; dev; | ||
3125 | dev = *((struct net_device **)dev->priv)) { | ||
3126 | |||
3127 | set_chan_state(dev,WAN_CONNECTED); | ||
3128 | } | ||
3129 | |||
3130 | wanpipe_set_state(card, WAN_CONNECTED); | ||
3131 | return 1; | ||
3132 | } | ||
3133 | |||
3134 | case FRRES_DLCI_CHANGE: | ||
3135 | return fr_dlci_change(card, mbox); | ||
3136 | |||
3137 | case FRRES_DLCI_MISMATCH: | ||
3138 | printk(KERN_INFO "%s: DLCI list mismatch!\n", | ||
3139 | card->devname); | ||
3140 | return 1; | ||
3141 | |||
3142 | case CMD_TIMEOUT: | ||
3143 | printk(KERN_ERR "%s: command 0x%02X timed out!\n", | ||
3144 | card->devname, mbox->cmd.command); | ||
3145 | printk(KERN_INFO "%s: ID Bytes = ",card->devname); | ||
3146 | for(i = 0; i < 8; i ++) | ||
3147 | printk(KERN_INFO "0x%02X ", *(ptr + 0x18 + i)); | ||
3148 | printk(KERN_INFO "\n"); | ||
3149 | |||
3150 | break; | ||
3151 | |||
3152 | case FRRES_DLCI_INACTIVE: | ||
3153 | break; | ||
3154 | |||
3155 | case FRRES_CIR_OVERFLOW: | ||
3156 | break; | ||
3157 | |||
3158 | case FRRES_BUFFER_OVERFLOW: | ||
3159 | break; | ||
3160 | |||
3161 | default: | ||
3162 | printk(KERN_INFO "%s: command 0x%02X returned 0x%02X!\n" | ||
3163 | , card->devname, mbox->cmd.command, event); | ||
3164 | } | ||
3165 | |||
3166 | return 0; | ||
3167 | } | ||
3168 | |||
3169 | /*============================================================================ | ||
3170 | * Handle modem error. | ||
3171 | * | ||
3172 | * Return zero if previous command has to be cancelled. | ||
3173 | */ | ||
3174 | static int fr_modem_failure (sdla_t *card, fr_mbox_t* mbox) | ||
3175 | { | ||
3176 | printk(KERN_INFO "%s: physical link down! (modem error 0x%02X)\n", | ||
3177 | card->devname, mbox->data[0]); | ||
3178 | |||
3179 | switch (mbox->cmd.command){ | ||
3180 | case FR_WRITE: | ||
3181 | |||
3182 | case FR_READ: | ||
3183 | return 0; | ||
3184 | } | ||
3185 | |||
3186 | return 1; | ||
3187 | } | ||
3188 | |||
3189 | /*============================================================================ | ||
3190 | * Handle DLCI status change. | ||
3191 | * | ||
3192 | * Return zero if previous command has to be cancelled. | ||
3193 | */ | ||
3194 | static int fr_dlci_change (sdla_t *card, fr_mbox_t* mbox) | ||
3195 | { | ||
3196 | dlci_status_t* status = (void*)mbox->data; | ||
3197 | int cnt = mbox->cmd.length / sizeof(dlci_status_t); | ||
3198 | fr_channel_t *chan; | ||
3199 | struct net_device* dev2; | ||
3200 | |||
3201 | |||
3202 | for (; cnt; --cnt, ++status) { | ||
3203 | |||
3204 | unsigned short dlci= status->dlci; | ||
3205 | struct net_device* dev = find_channel(card, dlci); | ||
3206 | |||
3207 | if (dev == NULL){ | ||
3208 | printk(KERN_INFO | ||
3209 | "%s: CPE contains unconfigured DLCI= %d\n", | ||
3210 | card->devname, dlci); | ||
3211 | |||
3212 | printk(KERN_INFO | ||
3213 | "%s: unconfigured DLCI %d reported by network\n" | ||
3214 | , card->devname, dlci); | ||
3215 | |||
3216 | }else{ | ||
3217 | if (status->state == FR_LINK_INOPER) { | ||
3218 | printk(KERN_INFO | ||
3219 | "%s: DLCI %u is inactive!\n", | ||
3220 | card->devname, dlci); | ||
3221 | |||
3222 | if (dev && netif_running(dev)) | ||
3223 | set_chan_state(dev, WAN_DISCONNECTED); | ||
3224 | } | ||
3225 | |||
3226 | if (status->state & FR_DLCI_DELETED) { | ||
3227 | |||
3228 | printk(KERN_INFO | ||
3229 | "%s: DLCI %u has been deleted!\n", | ||
3230 | card->devname, dlci); | ||
3231 | |||
3232 | if (dev && netif_running(dev)){ | ||
3233 | |||
3234 | fr_channel_t *chan = dev->priv; | ||
3235 | |||
3236 | if (chan->route_flag == ROUTE_ADDED) { | ||
3237 | chan->route_flag = REMOVE_ROUTE; | ||
3238 | /* The state change will trigger | ||
3239 | * the fr polling routine */ | ||
3240 | } | ||
3241 | |||
3242 | if (chan->inarp == INARP_CONFIGURED) { | ||
3243 | chan->inarp = INARP_REQUEST; | ||
3244 | } | ||
3245 | |||
3246 | set_chan_state(dev, WAN_DISCONNECTED); | ||
3247 | } | ||
3248 | |||
3249 | } else if (status->state & FR_DLCI_ACTIVE) { | ||
3250 | |||
3251 | chan = dev->priv; | ||
3252 | |||
3253 | /* This flag is used for configuring specific | ||
3254 | DLCI(s) when they become active. | ||
3255 | */ | ||
3256 | chan->dlci_configured = DLCI_CONFIG_PENDING; | ||
3257 | |||
3258 | set_chan_state(dev, WAN_CONNECTED); | ||
3259 | |||
3260 | } | ||
3261 | } | ||
3262 | } | ||
3263 | |||
3264 | for (dev2 = card->wandev.dev; dev2; | ||
3265 | dev2 = *((struct net_device **)dev2->priv)){ | ||
3266 | |||
3267 | chan = dev2->priv; | ||
3268 | |||
3269 | if (chan->dlci_configured == DLCI_CONFIG_PENDING) { | ||
3270 | if (fr_init_dlci(card, chan)){ | ||
3271 | return 1; | ||
3272 | } | ||
3273 | } | ||
3274 | |||
3275 | } | ||
3276 | return 1; | ||
3277 | } | ||
3278 | |||
3279 | |||
3280 | static int fr_init_dlci (sdla_t *card, fr_channel_t *chan) | ||
3281 | { | ||
3282 | fr_dlc_conf_t cfg; | ||
3283 | |||
3284 | memset(&cfg, 0, sizeof(cfg)); | ||
3285 | |||
3286 | if ( chan->cir_status == CIR_DISABLED) { | ||
3287 | |||
3288 | cfg.cir_fwd = cfg.cir_bwd = 16; | ||
3289 | cfg.bc_fwd = cfg.bc_bwd = 16; | ||
3290 | cfg.conf_flags = 0x0001; | ||
3291 | |||
3292 | }else if (chan->cir_status == CIR_ENABLED) { | ||
3293 | |||
3294 | cfg.cir_fwd = cfg.cir_bwd = chan->cir; | ||
3295 | cfg.bc_fwd = cfg.bc_bwd = chan->bc; | ||
3296 | cfg.be_fwd = cfg.be_bwd = chan->be; | ||
3297 | cfg.conf_flags = 0x0000; | ||
3298 | } | ||
3299 | |||
3300 | if (fr_dlci_configure( card, &cfg , chan->dlci)){ | ||
3301 | printk(KERN_INFO | ||
3302 | "%s: DLCI Configure failed for %d\n", | ||
3303 | card->devname, chan->dlci); | ||
3304 | return 1; | ||
3305 | } | ||
3306 | |||
3307 | chan->dlci_configured = DLCI_CONFIGURED; | ||
3308 | |||
3309 | /* Read the interface byte mapping into the channel | ||
3310 | * structure. | ||
3311 | */ | ||
3312 | read_DLCI_IB_mapping( card, chan ); | ||
3313 | |||
3314 | return 0; | ||
3315 | } | ||
3316 | /******* Miscellaneous ******************************************************/ | ||
3317 | |||
3318 | /*============================================================================ | ||
3319 | * Update channel state. | ||
3320 | */ | ||
3321 | static int update_chan_state(struct net_device* dev) | ||
3322 | { | ||
3323 | fr_channel_t* chan = dev->priv; | ||
3324 | sdla_t* card = chan->card; | ||
3325 | fr_mbox_t* mbox = card->mbox; | ||
3326 | int retry = MAX_CMD_RETRY; | ||
3327 | int err; | ||
3328 | |||
3329 | do | ||
3330 | { | ||
3331 | mbox->cmd.command = FR_LIST_ACTIVE_DLCI; | ||
3332 | mbox->cmd.length = 0; | ||
3333 | err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; | ||
3334 | } while (err && retry-- && fr_event(card, err, mbox)); | ||
3335 | |||
3336 | if (!err) { | ||
3337 | |||
3338 | unsigned short* list = (void*)mbox->data; | ||
3339 | int cnt = mbox->cmd.length / sizeof(short); | ||
3340 | |||
3341 | err=1; | ||
3342 | |||
3343 | for (; cnt; --cnt, ++list) { | ||
3344 | |||
3345 | if (*list == chan->dlci) { | ||
3346 | set_chan_state(dev, WAN_CONNECTED); | ||
3347 | |||
3348 | |||
3349 | /* May 23 2000. NC | ||
3350 | * When a dlci is added or restarted, | ||
3351 | * the dlci_int_interface pointer must | ||
3352 | * be reinitialized. */ | ||
3353 | if (!chan->dlci_int_interface){ | ||
3354 | err=fr_init_dlci (card,chan); | ||
3355 | } | ||
3356 | break; | ||
3357 | } | ||
3358 | } | ||
3359 | } | ||
3360 | |||
3361 | return err; | ||
3362 | } | ||
3363 | |||
3364 | /*============================================================================ | ||
3365 | * Set channel state. | ||
3366 | */ | ||
3367 | static void set_chan_state(struct net_device* dev, int state) | ||
3368 | { | ||
3369 | fr_channel_t* chan = dev->priv; | ||
3370 | sdla_t* card = chan->card; | ||
3371 | |||
3372 | if (chan->common.state != state) { | ||
3373 | |||
3374 | switch (state) { | ||
3375 | |||
3376 | case WAN_CONNECTED: | ||
3377 | printk(KERN_INFO | ||
3378 | "%s: Interface %s: DLCI %d connected\n", | ||
3379 | card->devname, dev->name, chan->dlci); | ||
3380 | |||
3381 | /* If the interface was previoulsy down, | ||
3382 | * bring it up, since the channel is active */ | ||
3383 | |||
3384 | trigger_fr_poll (dev); | ||
3385 | trigger_fr_arp (dev); | ||
3386 | break; | ||
3387 | |||
3388 | case WAN_CONNECTING: | ||
3389 | printk(KERN_INFO | ||
3390 | "%s: Interface %s: DLCI %d connecting\n", | ||
3391 | card->devname, dev->name, chan->dlci); | ||
3392 | break; | ||
3393 | |||
3394 | case WAN_DISCONNECTED: | ||
3395 | printk (KERN_INFO | ||
3396 | "%s: Interface %s: DLCI %d disconnected!\n", | ||
3397 | card->devname, dev->name, chan->dlci); | ||
3398 | |||
3399 | /* If the interface is up, bring it down, | ||
3400 | * since the channel is now disconnected */ | ||
3401 | trigger_fr_poll (dev); | ||
3402 | break; | ||
3403 | } | ||
3404 | |||
3405 | chan->common.state = state; | ||
3406 | } | ||
3407 | |||
3408 | chan->state_tick = jiffies; | ||
3409 | } | ||
3410 | |||
3411 | /*============================================================================ | ||
3412 | * Find network device by its channel number. | ||
3413 | * | ||
3414 | * We need this critical flag because we change | ||
3415 | * the dlci_to_dev_map outside the interrupt. | ||
3416 | * | ||
3417 | * NOTE: del_if() functions updates this array, it uses | ||
3418 | * the spin locks to avoid corruption. | ||
3419 | */ | ||
3420 | static struct net_device* find_channel(sdla_t* card, unsigned dlci) | ||
3421 | { | ||
3422 | if(dlci > HIGHEST_VALID_DLCI) | ||
3423 | return NULL; | ||
3424 | |||
3425 | return(card->u.f.dlci_to_dev_map[dlci]); | ||
3426 | } | ||
3427 | |||
3428 | /*============================================================================ | ||
3429 | * Check to see if a frame can be sent. If no transmit buffers available, | ||
3430 | * enable transmit interrupts. | ||
3431 | * | ||
3432 | * Return: 1 - Tx buffer(s) available | ||
3433 | * 0 - no buffers available | ||
3434 | */ | ||
3435 | static int is_tx_ready (sdla_t* card, fr_channel_t* chan) | ||
3436 | { | ||
3437 | unsigned char sb; | ||
3438 | |||
3439 | if(card->hw.type == SDLA_S514) | ||
3440 | return 1; | ||
3441 | |||
3442 | sb = inb(card->hw.port); | ||
3443 | if (sb & 0x02) | ||
3444 | return 1; | ||
3445 | |||
3446 | return 0; | ||
3447 | } | ||
3448 | |||
3449 | /*============================================================================ | ||
3450 | * Convert decimal string to unsigned integer. | ||
3451 | * If len != 0 then only 'len' characters of the string are converted. | ||
3452 | */ | ||
3453 | static unsigned int dec_to_uint (unsigned char* str, int len) | ||
3454 | { | ||
3455 | unsigned val; | ||
3456 | |||
3457 | if (!len) | ||
3458 | len = strlen(str); | ||
3459 | |||
3460 | for (val = 0; len && is_digit(*str); ++str, --len) | ||
3461 | val = (val * 10) + (*str - (unsigned)'0'); | ||
3462 | |||
3463 | return val; | ||
3464 | } | ||
3465 | |||
3466 | |||
3467 | |||
3468 | /*============================================================================= | ||
3469 | * Store a UDP management packet for later processing. | ||
3470 | */ | ||
3471 | |||
3472 | static int store_udp_mgmt_pkt(int udp_type, char udp_pkt_src, sdla_t* card, | ||
3473 | struct sk_buff *skb, int dlci) | ||
3474 | { | ||
3475 | int udp_pkt_stored = 0; | ||
3476 | |||
3477 | struct net_device *dev = find_channel(card, dlci); | ||
3478 | fr_channel_t *chan; | ||
3479 | |||
3480 | if (!dev || !(chan=dev->priv)) | ||
3481 | return 1; | ||
3482 | |||
3483 | if(!card->u.f.udp_pkt_lgth && (skb->len <= MAX_LGTH_UDP_MGNT_PKT)){ | ||
3484 | card->u.f.udp_pkt_lgth = skb->len + chan->fr_header_len; | ||
3485 | card->u.f.udp_type = udp_type; | ||
3486 | card->u.f.udp_pkt_src = udp_pkt_src; | ||
3487 | card->u.f.udp_dlci = dlci; | ||
3488 | memcpy(card->u.f.udp_pkt_data, skb->data, skb->len); | ||
3489 | card->u.f.timer_int_enabled |= TMR_INT_ENABLED_UDP; | ||
3490 | udp_pkt_stored = 1; | ||
3491 | |||
3492 | }else{ | ||
3493 | printk(KERN_INFO "ERROR: UDP packet not stored for DLCI %d\n", | ||
3494 | dlci); | ||
3495 | } | ||
3496 | |||
3497 | if(udp_pkt_src == UDP_PKT_FRM_STACK){ | ||
3498 | dev_kfree_skb_any(skb); | ||
3499 | }else{ | ||
3500 | dev_kfree_skb_any(skb); | ||
3501 | } | ||
3502 | |||
3503 | return(udp_pkt_stored); | ||
3504 | } | ||
3505 | |||
3506 | |||
3507 | /*============================================================================== | ||
3508 | * Process UDP call of type FPIPE8ND | ||
3509 | */ | ||
3510 | static int process_udp_mgmt_pkt(sdla_t* card) | ||
3511 | { | ||
3512 | |||
3513 | int c_retry = MAX_CMD_RETRY; | ||
3514 | unsigned char *buf; | ||
3515 | unsigned char frames; | ||
3516 | unsigned int len; | ||
3517 | unsigned short buffer_length; | ||
3518 | struct sk_buff *new_skb; | ||
3519 | fr_mbox_t* mbox = card->mbox; | ||
3520 | int err; | ||
3521 | struct timeval tv; | ||
3522 | int udp_mgmt_req_valid = 1; | ||
3523 | struct net_device* dev; | ||
3524 | fr_channel_t* chan; | ||
3525 | fr_udp_pkt_t *fr_udp_pkt; | ||
3526 | unsigned short num_trc_els; | ||
3527 | fr_trc_el_t* ptr_trc_el; | ||
3528 | fr_trc_el_t trc_el; | ||
3529 | fpipemon_trc_t* fpipemon_trc; | ||
3530 | |||
3531 | char udp_pkt_src = card->u.f.udp_pkt_src; | ||
3532 | int dlci = card->u.f.udp_dlci; | ||
3533 | |||
3534 | /* Find network interface for this packet */ | ||
3535 | dev = find_channel(card, dlci); | ||
3536 | if (!dev){ | ||
3537 | card->u.f.udp_pkt_lgth = 0; | ||
3538 | return 1; | ||
3539 | } | ||
3540 | if ((chan = dev->priv) == NULL){ | ||
3541 | card->u.f.udp_pkt_lgth = 0; | ||
3542 | return 1; | ||
3543 | } | ||
3544 | |||
3545 | /* If the UDP packet is from the network, we are going to have to | ||
3546 | transmit a response. Before doing so, we must check to see that | ||
3547 | we are not currently transmitting a frame (in 'if_send()') and | ||
3548 | that we are not already in a 'delayed transmit' state. | ||
3549 | */ | ||
3550 | if(udp_pkt_src == UDP_PKT_FRM_NETWORK) { | ||
3551 | if (check_tx_status(card,dev)){ | ||
3552 | card->u.f.udp_pkt_lgth = 0; | ||
3553 | return 1; | ||
3554 | } | ||
3555 | } | ||
3556 | |||
3557 | fr_udp_pkt = (fr_udp_pkt_t *)card->u.f.udp_pkt_data; | ||
3558 | |||
3559 | if(udp_pkt_src == UDP_PKT_FRM_NETWORK) { | ||
3560 | |||
3561 | switch(fr_udp_pkt->cblock.command) { | ||
3562 | |||
3563 | case FR_READ_MODEM_STATUS: | ||
3564 | case FR_READ_STATUS: | ||
3565 | case FPIPE_ROUTER_UP_TIME: | ||
3566 | case FR_READ_ERROR_STATS: | ||
3567 | case FPIPE_DRIVER_STAT_GEN: | ||
3568 | case FR_READ_STATISTICS: | ||
3569 | case FR_READ_ADD_DLC_STATS: | ||
3570 | case FR_READ_CONFIG: | ||
3571 | case FR_READ_CODE_VERSION: | ||
3572 | udp_mgmt_req_valid = 1; | ||
3573 | break; | ||
3574 | default: | ||
3575 | udp_mgmt_req_valid = 0; | ||
3576 | break; | ||
3577 | } | ||
3578 | } | ||
3579 | |||
3580 | if(!udp_mgmt_req_valid) { | ||
3581 | /* set length to 0 */ | ||
3582 | fr_udp_pkt->cblock.length = 0; | ||
3583 | /* set return code */ | ||
3584 | fr_udp_pkt->cblock.result = 0xCD; | ||
3585 | |||
3586 | chan->drvstats_gen.UDP_PIPE_mgmt_direction_err ++; | ||
3587 | |||
3588 | if (net_ratelimit()){ | ||
3589 | printk(KERN_INFO | ||
3590 | "%s: Warning, Illegal UDP command attempted from network: %x\n", | ||
3591 | card->devname,fr_udp_pkt->cblock.command); | ||
3592 | } | ||
3593 | |||
3594 | } else { | ||
3595 | |||
3596 | switch(fr_udp_pkt->cblock.command) { | ||
3597 | |||
3598 | case FPIPE_ENABLE_TRACING: | ||
3599 | if(!card->TracingEnabled) { | ||
3600 | do { | ||
3601 | mbox->cmd.command = FR_SET_TRACE_CONFIG; | ||
3602 | mbox->cmd.length = 1; | ||
3603 | mbox->cmd.dlci = 0x00; | ||
3604 | mbox->data[0] = fr_udp_pkt->data[0] | | ||
3605 | RESET_TRC; | ||
3606 | err = sdla_exec(mbox) ? | ||
3607 | mbox->cmd.result : CMD_TIMEOUT; | ||
3608 | } while (err && c_retry-- && fr_event(card, err, | ||
3609 | mbox)); | ||
3610 | |||
3611 | if(err) { | ||
3612 | card->TracingEnabled = 0; | ||
3613 | /* set the return code */ | ||
3614 | fr_udp_pkt->cblock.result = | ||
3615 | mbox->cmd.result; | ||
3616 | mbox->cmd.length = 0; | ||
3617 | break; | ||
3618 | } | ||
3619 | |||
3620 | sdla_peek(&card->hw, NO_TRC_ELEMENTS_OFF, | ||
3621 | &num_trc_els, 2); | ||
3622 | sdla_peek(&card->hw, BASE_TRC_ELEMENTS_OFF, | ||
3623 | &card->u.f.trc_el_base, 4); | ||
3624 | card->u.f.curr_trc_el = card->u.f.trc_el_base; | ||
3625 | card->u.f.trc_el_last = card->u.f.curr_trc_el + | ||
3626 | ((num_trc_els - 1) * | ||
3627 | sizeof(fr_trc_el_t)); | ||
3628 | |||
3629 | /* Calculate the maximum trace data area in */ | ||
3630 | /* the UDP packet */ | ||
3631 | card->u.f.trc_bfr_space=(MAX_LGTH_UDP_MGNT_PKT - | ||
3632 | //sizeof(fr_encap_hdr_t) - | ||
3633 | sizeof(ip_pkt_t) - | ||
3634 | sizeof(udp_pkt_t) - | ||
3635 | sizeof(wp_mgmt_t) - | ||
3636 | sizeof(cblock_t)); | ||
3637 | |||
3638 | /* set return code */ | ||
3639 | fr_udp_pkt->cblock.result = 0; | ||
3640 | |||
3641 | } else { | ||
3642 | /* set return code to line trace already | ||
3643 | enabled */ | ||
3644 | fr_udp_pkt->cblock.result = 1; | ||
3645 | } | ||
3646 | |||
3647 | mbox->cmd.length = 0; | ||
3648 | card->TracingEnabled = 1; | ||
3649 | break; | ||
3650 | |||
3651 | |||
3652 | case FPIPE_DISABLE_TRACING: | ||
3653 | if(card->TracingEnabled) { | ||
3654 | |||
3655 | do { | ||
3656 | mbox->cmd.command = FR_SET_TRACE_CONFIG; | ||
3657 | mbox->cmd.length = 1; | ||
3658 | mbox->cmd.dlci = 0x00; | ||
3659 | mbox->data[0] = ~ACTIVATE_TRC; | ||
3660 | err = sdla_exec(mbox) ? | ||
3661 | mbox->cmd.result : CMD_TIMEOUT; | ||
3662 | } while (err && c_retry-- && fr_event(card, err, mbox)); | ||
3663 | } | ||
3664 | |||
3665 | /* set return code */ | ||
3666 | fr_udp_pkt->cblock.result = 0; | ||
3667 | mbox->cmd.length = 0; | ||
3668 | card->TracingEnabled = 0; | ||
3669 | break; | ||
3670 | |||
3671 | case FPIPE_GET_TRACE_INFO: | ||
3672 | |||
3673 | /* Line trace cannot be performed on the 502 */ | ||
3674 | if(!card->TracingEnabled) { | ||
3675 | /* set return code */ | ||
3676 | fr_udp_pkt->cblock.result = 1; | ||
3677 | mbox->cmd.length = 0; | ||
3678 | break; | ||
3679 | } | ||
3680 | |||
3681 | ptr_trc_el = (void *)card->u.f.curr_trc_el; | ||
3682 | |||
3683 | buffer_length = 0; | ||
3684 | fr_udp_pkt->data[0x00] = 0x00; | ||
3685 | |||
3686 | for(frames = 0; frames < MAX_FRMS_TRACED; frames ++) { | ||
3687 | |||
3688 | sdla_peek(&card->hw, (unsigned long)ptr_trc_el, | ||
3689 | (void *)&trc_el.flag, | ||
3690 | sizeof(fr_trc_el_t)); | ||
3691 | if(trc_el.flag == 0x00) { | ||
3692 | break; | ||
3693 | } | ||
3694 | if((card->u.f.trc_bfr_space - buffer_length) | ||
3695 | < sizeof(fpipemon_trc_hdr_t)) { | ||
3696 | fr_udp_pkt->data[0x00] |= MORE_TRC_DATA; | ||
3697 | break; | ||
3698 | } | ||
3699 | |||
3700 | fpipemon_trc = | ||
3701 | (fpipemon_trc_t *)&fr_udp_pkt->data[buffer_length]; | ||
3702 | fpipemon_trc->fpipemon_trc_hdr.status = | ||
3703 | trc_el.attr; | ||
3704 | fpipemon_trc->fpipemon_trc_hdr.tmstamp = | ||
3705 | trc_el.tmstamp; | ||
3706 | fpipemon_trc->fpipemon_trc_hdr.length = | ||
3707 | trc_el.length; | ||
3708 | |||
3709 | if(!trc_el.offset || !trc_el.length) { | ||
3710 | |||
3711 | fpipemon_trc->fpipemon_trc_hdr.data_passed = 0x00; | ||
3712 | |||
3713 | }else if((trc_el.length + sizeof(fpipemon_trc_hdr_t) + 1) > | ||
3714 | (card->u.f.trc_bfr_space - buffer_length)){ | ||
3715 | |||
3716 | fpipemon_trc->fpipemon_trc_hdr.data_passed = 0x00; | ||
3717 | fr_udp_pkt->data[0x00] |= MORE_TRC_DATA; | ||
3718 | |||
3719 | }else { | ||
3720 | fpipemon_trc->fpipemon_trc_hdr.data_passed = 0x01; | ||
3721 | sdla_peek(&card->hw, trc_el.offset, | ||
3722 | fpipemon_trc->data, | ||
3723 | trc_el.length); | ||
3724 | } | ||
3725 | |||
3726 | trc_el.flag = 0x00; | ||
3727 | sdla_poke(&card->hw, (unsigned long)ptr_trc_el, | ||
3728 | &trc_el.flag, 1); | ||
3729 | |||
3730 | ptr_trc_el ++; | ||
3731 | if((void *)ptr_trc_el > card->u.f.trc_el_last) | ||
3732 | ptr_trc_el = (void*)card->u.f.trc_el_base; | ||
3733 | |||
3734 | buffer_length += sizeof(fpipemon_trc_hdr_t); | ||
3735 | if(fpipemon_trc->fpipemon_trc_hdr.data_passed) { | ||
3736 | buffer_length += trc_el.length; | ||
3737 | } | ||
3738 | |||
3739 | if(fr_udp_pkt->data[0x00] & MORE_TRC_DATA) { | ||
3740 | break; | ||
3741 | } | ||
3742 | } | ||
3743 | |||
3744 | if(frames == MAX_FRMS_TRACED) { | ||
3745 | fr_udp_pkt->data[0x00] |= MORE_TRC_DATA; | ||
3746 | } | ||
3747 | |||
3748 | card->u.f.curr_trc_el = (void *)ptr_trc_el; | ||
3749 | |||
3750 | /* set the total number of frames passed */ | ||
3751 | fr_udp_pkt->data[0x00] |= | ||
3752 | ((frames << 1) & (MAX_FRMS_TRACED << 1)); | ||
3753 | |||
3754 | /* set the data length and return code */ | ||
3755 | fr_udp_pkt->cblock.length = mbox->cmd.length = buffer_length; | ||
3756 | fr_udp_pkt->cblock.result = 0; | ||
3757 | break; | ||
3758 | |||
3759 | case FPIPE_FT1_READ_STATUS: | ||
3760 | sdla_peek(&card->hw, 0xF020, | ||
3761 | &fr_udp_pkt->data[0x00] , 2); | ||
3762 | fr_udp_pkt->cblock.length = mbox->cmd.length = 2; | ||
3763 | fr_udp_pkt->cblock.result = 0; | ||
3764 | break; | ||
3765 | |||
3766 | case FPIPE_FLUSH_DRIVER_STATS: | ||
3767 | init_chan_statistics(chan); | ||
3768 | init_global_statistics(card); | ||
3769 | mbox->cmd.length = 0; | ||
3770 | break; | ||
3771 | |||
3772 | case FPIPE_ROUTER_UP_TIME: | ||
3773 | do_gettimeofday(&tv); | ||
3774 | chan->router_up_time = tv.tv_sec - | ||
3775 | chan->router_start_time; | ||
3776 | *(unsigned long *)&fr_udp_pkt->data = | ||
3777 | chan->router_up_time; | ||
3778 | mbox->cmd.length = fr_udp_pkt->cblock.length = 4; | ||
3779 | fr_udp_pkt->cblock.result = 0; | ||
3780 | break; | ||
3781 | |||
3782 | case FPIPE_DRIVER_STAT_IFSEND: | ||
3783 | memcpy(fr_udp_pkt->data, | ||
3784 | &chan->drvstats_if_send.if_send_entry, | ||
3785 | sizeof(if_send_stat_t)); | ||
3786 | mbox->cmd.length = fr_udp_pkt->cblock.length =sizeof(if_send_stat_t); | ||
3787 | fr_udp_pkt->cblock.result = 0; | ||
3788 | break; | ||
3789 | |||
3790 | case FPIPE_DRIVER_STAT_INTR: | ||
3791 | |||
3792 | memcpy(fr_udp_pkt->data, | ||
3793 | &card->statistics.isr_entry, | ||
3794 | sizeof(global_stats_t)); | ||
3795 | |||
3796 | memcpy(&fr_udp_pkt->data[sizeof(global_stats_t)], | ||
3797 | &chan->drvstats_rx_intr.rx_intr_no_socket, | ||
3798 | sizeof(rx_intr_stat_t)); | ||
3799 | |||
3800 | mbox->cmd.length = fr_udp_pkt->cblock.length = | ||
3801 | sizeof(global_stats_t) + | ||
3802 | sizeof(rx_intr_stat_t); | ||
3803 | fr_udp_pkt->cblock.result = 0; | ||
3804 | break; | ||
3805 | |||
3806 | case FPIPE_DRIVER_STAT_GEN: | ||
3807 | memcpy(fr_udp_pkt->data, | ||
3808 | &chan->drvstats_gen.UDP_PIPE_mgmt_kmalloc_err, | ||
3809 | sizeof(pipe_mgmt_stat_t)); | ||
3810 | |||
3811 | memcpy(&fr_udp_pkt->data[sizeof(pipe_mgmt_stat_t)], | ||
3812 | &card->statistics, sizeof(global_stats_t)); | ||
3813 | |||
3814 | mbox->cmd.length = fr_udp_pkt->cblock.length = sizeof(global_stats_t)+ | ||
3815 | sizeof(rx_intr_stat_t); | ||
3816 | fr_udp_pkt->cblock.result = 0; | ||
3817 | break; | ||
3818 | |||
3819 | |||
3820 | case FR_FT1_STATUS_CTRL: | ||
3821 | if(fr_udp_pkt->data[0] == 1) { | ||
3822 | if(rCount++ != 0 ){ | ||
3823 | fr_udp_pkt->cblock.result = 0; | ||
3824 | mbox->cmd.length = 1; | ||
3825 | break; | ||
3826 | } | ||
3827 | } | ||
3828 | |||
3829 | /* Disable FT1 MONITOR STATUS */ | ||
3830 | if(fr_udp_pkt->data[0] == 0) { | ||
3831 | if( --rCount != 0) { | ||
3832 | fr_udp_pkt->cblock.result = 0; | ||
3833 | mbox->cmd.length = 1; | ||
3834 | break; | ||
3835 | } | ||
3836 | } | ||
3837 | goto udp_mgmt_dflt; | ||
3838 | |||
3839 | |||
3840 | default: | ||
3841 | udp_mgmt_dflt: | ||
3842 | do { | ||
3843 | memcpy(&mbox->cmd, | ||
3844 | &fr_udp_pkt->cblock.command, | ||
3845 | sizeof(fr_cmd_t)); | ||
3846 | if(mbox->cmd.length) { | ||
3847 | memcpy(&mbox->data, | ||
3848 | (char *)fr_udp_pkt->data, | ||
3849 | mbox->cmd.length); | ||
3850 | } | ||
3851 | |||
3852 | err = sdla_exec(mbox) ? mbox->cmd.result : | ||
3853 | CMD_TIMEOUT; | ||
3854 | } while (err && c_retry-- && fr_event(card, err, mbox)); | ||
3855 | |||
3856 | if(!err) | ||
3857 | chan->drvstats_gen. | ||
3858 | UDP_PIPE_mgmt_adptr_cmnd_OK ++; | ||
3859 | else | ||
3860 | chan->drvstats_gen. | ||
3861 | UDP_PIPE_mgmt_adptr_cmnd_timeout ++; | ||
3862 | |||
3863 | /* copy the result back to our buffer */ | ||
3864 | memcpy(&fr_udp_pkt->cblock.command, | ||
3865 | &mbox->cmd, sizeof(fr_cmd_t)); | ||
3866 | |||
3867 | if(mbox->cmd.length) { | ||
3868 | memcpy(&fr_udp_pkt->data, | ||
3869 | &mbox->data, mbox->cmd.length); | ||
3870 | } | ||
3871 | } | ||
3872 | } | ||
3873 | |||
3874 | /* Fill UDP TTL */ | ||
3875 | fr_udp_pkt->ip_pkt.ttl = card->wandev.ttl; | ||
3876 | len = reply_udp(card->u.f.udp_pkt_data, mbox->cmd.length); | ||
3877 | |||
3878 | if(udp_pkt_src == UDP_PKT_FRM_NETWORK) { | ||
3879 | |||
3880 | chan->fr_header_len=2; | ||
3881 | chan->fr_header[0]=Q922_UI; | ||
3882 | chan->fr_header[1]=NLPID_IP; | ||
3883 | |||
3884 | err = fr_send_data_header(card, dlci, 0, len, | ||
3885 | card->u.f.udp_pkt_data,chan->fr_header_len); | ||
3886 | if (err){ | ||
3887 | chan->drvstats_gen.UDP_PIPE_mgmt_adptr_send_passed ++; | ||
3888 | }else{ | ||
3889 | chan->drvstats_gen.UDP_PIPE_mgmt_adptr_send_failed ++; | ||
3890 | } | ||
3891 | |||
3892 | } else { | ||
3893 | /* Allocate socket buffer */ | ||
3894 | if((new_skb = dev_alloc_skb(len)) != NULL) { | ||
3895 | |||
3896 | /* copy data into new_skb */ | ||
3897 | buf = skb_put(new_skb, len); | ||
3898 | memcpy(buf, card->u.f.udp_pkt_data, len); | ||
3899 | |||
3900 | chan->drvstats_gen. | ||
3901 | UDP_PIPE_mgmt_passed_to_stack ++; | ||
3902 | new_skb->dev = dev; | ||
3903 | new_skb->protocol = htons(ETH_P_IP); | ||
3904 | new_skb->mac.raw = new_skb->data; | ||
3905 | netif_rx(new_skb); | ||
3906 | |||
3907 | } else { | ||
3908 | chan->drvstats_gen.UDP_PIPE_mgmt_no_socket ++; | ||
3909 | printk(KERN_INFO | ||
3910 | "%s: UDP mgmt cmnd, no socket buffers available!\n", | ||
3911 | card->devname); | ||
3912 | } | ||
3913 | } | ||
3914 | |||
3915 | card->u.f.udp_pkt_lgth = 0; | ||
3916 | |||
3917 | return 1; | ||
3918 | } | ||
3919 | |||
3920 | /*============================================================================== | ||
3921 | * Send Inverse ARP Request | ||
3922 | */ | ||
3923 | |||
3924 | int send_inarp_request(sdla_t *card, struct net_device *dev) | ||
3925 | { | ||
3926 | int err=0; | ||
3927 | |||
3928 | arphdr_1490_t *ArpPacket; | ||
3929 | arphdr_fr_t *arphdr; | ||
3930 | fr_channel_t *chan = dev->priv; | ||
3931 | struct in_device *in_dev; | ||
3932 | |||
3933 | in_dev = dev->ip_ptr; | ||
3934 | |||
3935 | if(in_dev != NULL ) { | ||
3936 | |||
3937 | ArpPacket = kmalloc(sizeof(arphdr_1490_t) + sizeof(arphdr_fr_t), GFP_ATOMIC); | ||
3938 | /* SNAP Header indicating ARP */ | ||
3939 | ArpPacket->control = 0x03; | ||
3940 | ArpPacket->pad = 0x00; | ||
3941 | ArpPacket->NLPID = 0x80; | ||
3942 | ArpPacket->OUI[0] = 0; | ||
3943 | ArpPacket->OUI[1] = 0; | ||
3944 | ArpPacket->OUI[2] = 0; | ||
3945 | ArpPacket->PID = 0x0608; | ||
3946 | |||
3947 | arphdr = (arphdr_fr_t *)(ArpPacket + 1); // Go to ARP Packet | ||
3948 | |||
3949 | /* InARP request */ | ||
3950 | arphdr->ar_hrd = 0x0F00; /* Frame Relay HW type */ | ||
3951 | arphdr->ar_pro = 0x0008; /* IP Protocol */ | ||
3952 | arphdr->ar_hln = 2; /* HW addr length */ | ||
3953 | arphdr->ar_pln = 4; /* IP addr length */ | ||
3954 | arphdr->ar_op = htons(0x08); /* InARP Request */ | ||
3955 | arphdr->ar_sha = 0; /* src HW DLCI - Doesn't matter */ | ||
3956 | if(in_dev->ifa_list != NULL) | ||
3957 | arphdr->ar_sip = in_dev->ifa_list->ifa_local; /* Local Address */else | ||
3958 | arphdr->ar_sip = 0; | ||
3959 | arphdr->ar_tha = 0; /* dst HW DLCI - Doesn't matter */ | ||
3960 | arphdr->ar_tip = 0; /* Remote Address -- what we want */ | ||
3961 | |||
3962 | err = fr_send(card, chan->dlci, 0, sizeof(arphdr_1490_t) + sizeof(arphdr_fr_t), | ||
3963 | (void *)ArpPacket); | ||
3964 | |||
3965 | if (!err){ | ||
3966 | printk(KERN_INFO "\n%s: Sending InARP request on DLCI %d.\n", | ||
3967 | card->devname, chan->dlci); | ||
3968 | clear_bit(ARP_CRIT,&card->wandev.critical); | ||
3969 | } | ||
3970 | |||
3971 | kfree(ArpPacket); | ||
3972 | }else{ | ||
3973 | printk(KERN_INFO "%s: INARP ERROR: %s doesn't have a local IP address!\n", | ||
3974 | card->devname,dev->name); | ||
3975 | return 1; | ||
3976 | } | ||
3977 | |||
3978 | return 0; | ||
3979 | } | ||
3980 | |||
3981 | |||
3982 | /*============================================================================== | ||
3983 | * Check packet for ARP Type | ||
3984 | */ | ||
3985 | |||
3986 | int is_arp(void *buf) | ||
3987 | { | ||
3988 | arphdr_1490_t *arphdr = (arphdr_1490_t *)buf; | ||
3989 | |||
3990 | if (arphdr->pad == 0x00 && | ||
3991 | arphdr->NLPID == 0x80 && | ||
3992 | arphdr->PID == 0x0608) | ||
3993 | return 1; | ||
3994 | else return 0; | ||
3995 | } | ||
3996 | |||
3997 | /*============================================================================== | ||
3998 | * Process ARP Packet Type | ||
3999 | */ | ||
4000 | |||
4001 | int process_ARP(arphdr_1490_t *ArpPacket, sdla_t *card, struct net_device* dev) | ||
4002 | { | ||
4003 | |||
4004 | |||
4005 | arphdr_fr_t *arphdr = (arphdr_fr_t *)(ArpPacket + 1); /* Skip header */ | ||
4006 | fr_rx_buf_ctl_t* frbuf = card->rxmb; | ||
4007 | struct in_device *in_dev; | ||
4008 | fr_channel_t *chan = dev->priv; | ||
4009 | |||
4010 | /* Before we transmit ARP packet, we must check | ||
4011 | * to see that we are not currently transmitting a | ||
4012 | * frame (in 'if_send()') and that we are not | ||
4013 | * already in a 'delayed transmit' state. */ | ||
4014 | if (check_tx_status(card,dev)){ | ||
4015 | if (net_ratelimit()){ | ||
4016 | printk(KERN_INFO "%s: Disabling comminication to process ARP\n", | ||
4017 | card->devname); | ||
4018 | } | ||
4019 | set_bit(ARP_CRIT,&card->wandev.critical); | ||
4020 | return 0; | ||
4021 | } | ||
4022 | |||
4023 | in_dev = dev->ip_ptr; | ||
4024 | |||
4025 | /* Check that IP addresses exist for our network address */ | ||
4026 | if (in_dev == NULL || in_dev->ifa_list == NULL) | ||
4027 | return -1; | ||
4028 | |||
4029 | switch (ntohs(arphdr->ar_op)) { | ||
4030 | |||
4031 | case 0x08: // Inverse ARP request -- Send Reply, add route. | ||
4032 | |||
4033 | /* Check for valid Address */ | ||
4034 | printk(KERN_INFO "%s: Recvd PtP addr -InArp Req: %u.%u.%u.%u\n", | ||
4035 | card->devname, NIPQUAD(arphdr->ar_sip)); | ||
4036 | |||
4037 | |||
4038 | /* Check that the network address is the same as ours, only | ||
4039 | * if the netowrk mask is not 255.255.255.255. Otherwise | ||
4040 | * this check would not make sense */ | ||
4041 | |||
4042 | if (in_dev->ifa_list->ifa_mask != 0xFFFFFFFF && | ||
4043 | (in_dev->ifa_list->ifa_mask & arphdr->ar_sip) != | ||
4044 | (in_dev->ifa_list->ifa_mask & in_dev->ifa_list->ifa_local)){ | ||
4045 | printk(KERN_INFO | ||
4046 | "%s: Invalid PtP address. %u.%u.%u.%u InARP ignored.\n", | ||
4047 | card->devname,NIPQUAD(arphdr->ar_sip)); | ||
4048 | |||
4049 | printk(KERN_INFO "%s: mask %u.%u.%u.%u\n", | ||
4050 | card->devname, NIPQUAD(in_dev->ifa_list->ifa_mask)); | ||
4051 | printk(KERN_INFO "%s: local %u.%u.%u.%u\n", | ||
4052 | card->devname,NIPQUAD(in_dev->ifa_list->ifa_local)); | ||
4053 | return -1; | ||
4054 | } | ||
4055 | |||
4056 | if (in_dev->ifa_list->ifa_local == arphdr->ar_sip){ | ||
4057 | printk(KERN_INFO | ||
4058 | "%s: Local addr = PtP addr. InARP ignored.\n", | ||
4059 | card->devname); | ||
4060 | return -1; | ||
4061 | } | ||
4062 | |||
4063 | arphdr->ar_op = htons(0x09); /* InARP Reply */ | ||
4064 | |||
4065 | /* Set addresses */ | ||
4066 | arphdr->ar_tip = arphdr->ar_sip; | ||
4067 | arphdr->ar_sip = in_dev->ifa_list->ifa_local; | ||
4068 | |||
4069 | chan->ip_local = in_dev->ifa_list->ifa_local; | ||
4070 | chan->ip_remote = arphdr->ar_sip; | ||
4071 | |||
4072 | fr_send(card, frbuf->dlci, 0, frbuf->length, (void *)ArpPacket); | ||
4073 | |||
4074 | if (test_bit(ARP_CRIT,&card->wandev.critical)){ | ||
4075 | if (net_ratelimit()){ | ||
4076 | printk(KERN_INFO "%s: ARP Processed Enabling Communication!\n", | ||
4077 | card->devname); | ||
4078 | } | ||
4079 | } | ||
4080 | clear_bit(ARP_CRIT,&card->wandev.critical); | ||
4081 | |||
4082 | chan->ip_local = in_dev->ifa_list->ifa_local; | ||
4083 | chan->ip_remote = arphdr->ar_sip; | ||
4084 | |||
4085 | /* Add Route Flag */ | ||
4086 | /* The route will be added in the polling routine so | ||
4087 | that it is not interrupt context. */ | ||
4088 | |||
4089 | chan->route_flag = ADD_ROUTE; | ||
4090 | trigger_fr_poll (dev); | ||
4091 | |||
4092 | break; | ||
4093 | |||
4094 | case 0x09: // Inverse ARP reply | ||
4095 | |||
4096 | /* Check for valid Address */ | ||
4097 | printk(KERN_INFO "%s: Recvd PtP addr %u.%u.%u.%u -InArp Reply\n", | ||
4098 | card->devname, NIPQUAD(arphdr->ar_sip)); | ||
4099 | |||
4100 | |||
4101 | /* Compare network addresses, only if network mask | ||
4102 | * is not 255.255.255.255 It would not make sense | ||
4103 | * to perform this test if the mask was all 1's */ | ||
4104 | |||
4105 | if (in_dev->ifa_list->ifa_mask != 0xffffffff && | ||
4106 | (in_dev->ifa_list->ifa_mask & arphdr->ar_sip) != | ||
4107 | (in_dev->ifa_list->ifa_mask & in_dev->ifa_list->ifa_local)) { | ||
4108 | |||
4109 | printk(KERN_INFO "%s: Invalid PtP address. InARP ignored.\n", | ||
4110 | card->devname); | ||
4111 | return -1; | ||
4112 | } | ||
4113 | |||
4114 | /* Make sure that the received IP address is not | ||
4115 | * the same as our own local address */ | ||
4116 | if (in_dev->ifa_list->ifa_local == arphdr->ar_sip) { | ||
4117 | printk(KERN_INFO "%s: Local addr = PtP addr. InARP ignored.\n", | ||
4118 | card->devname); | ||
4119 | return -1; | ||
4120 | } | ||
4121 | |||
4122 | chan->ip_local = in_dev->ifa_list->ifa_local; | ||
4123 | chan->ip_remote = arphdr->ar_sip; | ||
4124 | |||
4125 | /* Add Route Flag */ | ||
4126 | /* The route will be added in the polling routine so | ||
4127 | that it is not interrupt context. */ | ||
4128 | |||
4129 | chan->route_flag = ADD_ROUTE; | ||
4130 | chan->inarp = INARP_CONFIGURED; | ||
4131 | trigger_fr_poll(dev); | ||
4132 | |||
4133 | break; | ||
4134 | default: | ||
4135 | break; // ARP's and RARP's -- Shouldn't happen. | ||
4136 | } | ||
4137 | |||
4138 | return 0; | ||
4139 | } | ||
4140 | |||
4141 | |||
4142 | /*============================================================ | ||
4143 | * trigger_fr_arp | ||
4144 | * | ||
4145 | * Description: | ||
4146 | * Add an fr_arp() task into a arp | ||
4147 | * timer handler for a specific dlci/interface. | ||
4148 | * This will kick the fr_arp() routine | ||
4149 | * within the specified time interval. | ||
4150 | * | ||
4151 | * Usage: | ||
4152 | * This timer is used to send ARP requests at | ||
4153 | * certain time intervals. | ||
4154 | * Called by an interrupt to request an action | ||
4155 | * at a later date. | ||
4156 | */ | ||
4157 | |||
4158 | static void trigger_fr_arp(struct net_device *dev) | ||
4159 | { | ||
4160 | fr_channel_t* chan = dev->priv; | ||
4161 | |||
4162 | mod_timer(&chan->fr_arp_timer, jiffies + chan->inarp_interval * HZ); | ||
4163 | return; | ||
4164 | } | ||
4165 | |||
4166 | |||
4167 | |||
4168 | /*============================================================================== | ||
4169 | * ARP Request Action | ||
4170 | * | ||
4171 | * This funciton is called by timer interrupt to send an arp request | ||
4172 | * to the remote end. | ||
4173 | */ | ||
4174 | |||
4175 | static void fr_arp (unsigned long data) | ||
4176 | { | ||
4177 | struct net_device *dev = (struct net_device *)data; | ||
4178 | fr_channel_t *chan = dev->priv; | ||
4179 | volatile sdla_t *card = chan->card; | ||
4180 | fr508_flags_t* flags = card->flags; | ||
4181 | |||
4182 | /* Send ARP packets for all devs' until | ||
4183 | * ARP state changes to CONFIGURED */ | ||
4184 | |||
4185 | if (chan->inarp == INARP_REQUEST && | ||
4186 | chan->common.state == WAN_CONNECTED && | ||
4187 | card->wandev.state == WAN_CONNECTED){ | ||
4188 | set_bit(0,&chan->inarp_ready); | ||
4189 | card->u.f.timer_int_enabled |= TMR_INT_ENABLED_ARP; | ||
4190 | flags->imask |= FR_INTR_TIMER; | ||
4191 | } | ||
4192 | |||
4193 | return; | ||
4194 | } | ||
4195 | |||
4196 | |||
4197 | /*============================================================================== | ||
4198 | * Perform the Interrupt Test by running the READ_CODE_VERSION command MAX_INTR_ | ||
4199 | * TEST_COUNTER times. | ||
4200 | */ | ||
4201 | static int intr_test( sdla_t* card ) | ||
4202 | { | ||
4203 | fr_mbox_t* mb = card->mbox; | ||
4204 | int err,i; | ||
4205 | |||
4206 | err = fr_set_intr_mode(card, FR_INTR_READY, card->wandev.mtu, 0 ); | ||
4207 | |||
4208 | if (err == CMD_OK) { | ||
4209 | |||
4210 | for ( i = 0; i < MAX_INTR_TEST_COUNTER; i++ ) { | ||
4211 | /* Run command READ_CODE_VERSION */ | ||
4212 | mb->cmd.length = 0; | ||
4213 | mb->cmd.command = FR_READ_CODE_VERSION; | ||
4214 | err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; | ||
4215 | if (err != CMD_OK) | ||
4216 | fr_event(card, err, mb); | ||
4217 | } | ||
4218 | |||
4219 | } else { | ||
4220 | return err; | ||
4221 | } | ||
4222 | |||
4223 | err = fr_set_intr_mode( card, 0, card->wandev.mtu, 0 ); | ||
4224 | |||
4225 | if( err != CMD_OK ) | ||
4226 | return err; | ||
4227 | |||
4228 | return 0; | ||
4229 | } | ||
4230 | |||
4231 | /*============================================================================== | ||
4232 | * Determine what type of UDP call it is. FPIPE8ND ? | ||
4233 | */ | ||
4234 | static int udp_pkt_type( struct sk_buff *skb, sdla_t* card ) | ||
4235 | { | ||
4236 | fr_udp_pkt_t *fr_udp_pkt = (fr_udp_pkt_t *)skb->data; | ||
4237 | |||
4238 | /* Quick HACK */ | ||
4239 | |||
4240 | |||
4241 | if((fr_udp_pkt->ip_pkt.protocol == UDPMGMT_UDP_PROTOCOL) && | ||
4242 | (fr_udp_pkt->ip_pkt.ver_inet_hdr_length == 0x45) && | ||
4243 | (fr_udp_pkt->udp_pkt.udp_dst_port == | ||
4244 | ntohs(card->wandev.udp_port)) && | ||
4245 | (fr_udp_pkt->wp_mgmt.request_reply == | ||
4246 | UDPMGMT_REQUEST)) { | ||
4247 | if(!strncmp(fr_udp_pkt->wp_mgmt.signature, | ||
4248 | UDPMGMT_FPIPE_SIGNATURE, 8)){ | ||
4249 | return UDP_FPIPE_TYPE; | ||
4250 | } | ||
4251 | } | ||
4252 | return UDP_INVALID_TYPE; | ||
4253 | } | ||
4254 | |||
4255 | |||
4256 | /*============================================================================== | ||
4257 | * Initializes the Statistics values in the fr_channel structure. | ||
4258 | */ | ||
4259 | void init_chan_statistics( fr_channel_t* chan) | ||
4260 | { | ||
4261 | memset(&chan->drvstats_if_send.if_send_entry, 0, | ||
4262 | sizeof(if_send_stat_t)); | ||
4263 | memset(&chan->drvstats_rx_intr.rx_intr_no_socket, 0, | ||
4264 | sizeof(rx_intr_stat_t)); | ||
4265 | memset(&chan->drvstats_gen.UDP_PIPE_mgmt_kmalloc_err, 0, | ||
4266 | sizeof(pipe_mgmt_stat_t)); | ||
4267 | } | ||
4268 | |||
4269 | /*============================================================================== | ||
4270 | * Initializes the Statistics values in the Sdla_t structure. | ||
4271 | */ | ||
4272 | void init_global_statistics( sdla_t* card ) | ||
4273 | { | ||
4274 | /* Intialize global statistics for a card */ | ||
4275 | memset(&card->statistics.isr_entry, 0, sizeof(global_stats_t)); | ||
4276 | } | ||
4277 | |||
4278 | static void read_DLCI_IB_mapping( sdla_t* card, fr_channel_t* chan ) | ||
4279 | { | ||
4280 | fr_mbox_t* mbox = card->mbox; | ||
4281 | int retry = MAX_CMD_RETRY; | ||
4282 | dlci_IB_mapping_t* result; | ||
4283 | int err, counter, found; | ||
4284 | |||
4285 | do { | ||
4286 | mbox->cmd.command = FR_READ_DLCI_IB_MAPPING; | ||
4287 | mbox->cmd.length = 0; | ||
4288 | err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; | ||
4289 | } while (err && retry-- && fr_event(card, err, mbox)); | ||
4290 | |||
4291 | if( mbox->cmd.result != 0){ | ||
4292 | printk(KERN_INFO "%s: Read DLCI IB Mapping failed\n", | ||
4293 | chan->name); | ||
4294 | } | ||
4295 | |||
4296 | counter = mbox->cmd.length / sizeof(dlci_IB_mapping_t); | ||
4297 | result = (void *)mbox->data; | ||
4298 | |||
4299 | found = 0; | ||
4300 | for (; counter; --counter, ++result) { | ||
4301 | if ( result->dlci == chan->dlci ) { | ||
4302 | chan->IB_addr = result->addr_value; | ||
4303 | if(card->hw.type == SDLA_S514){ | ||
4304 | chan->dlci_int_interface = | ||
4305 | (void*)(card->hw.dpmbase + | ||
4306 | chan->IB_addr); | ||
4307 | }else{ | ||
4308 | chan->dlci_int_interface = | ||
4309 | (void*)(card->hw.dpmbase + | ||
4310 | (chan->IB_addr & 0x00001FFF)); | ||
4311 | |||
4312 | } | ||
4313 | found = 1; | ||
4314 | break; | ||
4315 | } | ||
4316 | } | ||
4317 | if (!found) | ||
4318 | printk( KERN_INFO "%s: DLCI %d not found by IB MAPPING cmd\n", | ||
4319 | card->devname, chan->dlci); | ||
4320 | } | ||
4321 | |||
4322 | |||
4323 | |||
4324 | void s508_s514_lock(sdla_t *card, unsigned long *smp_flags) | ||
4325 | { | ||
4326 | if (card->hw.type != SDLA_S514){ | ||
4327 | |||
4328 | spin_lock_irqsave(&card->wandev.lock, *smp_flags); | ||
4329 | }else{ | ||
4330 | spin_lock(&card->u.f.if_send_lock); | ||
4331 | } | ||
4332 | return; | ||
4333 | } | ||
4334 | |||
4335 | |||
4336 | void s508_s514_unlock(sdla_t *card, unsigned long *smp_flags) | ||
4337 | { | ||
4338 | if (card->hw.type != SDLA_S514){ | ||
4339 | |||
4340 | spin_unlock_irqrestore (&card->wandev.lock, *smp_flags); | ||
4341 | }else{ | ||
4342 | spin_unlock(&card->u.f.if_send_lock); | ||
4343 | } | ||
4344 | return; | ||
4345 | } | ||
4346 | |||
4347 | |||
4348 | |||
4349 | /*---------------------------------------------------------------------- | ||
4350 | RECEIVE INTERRUPT: BOTTOM HALF HANDLERS | ||
4351 | ----------------------------------------------------------------------*/ | ||
4352 | |||
4353 | |||
4354 | /*======================================================== | ||
4355 | * bh_enqueue | ||
4356 | * | ||
4357 | * Description: | ||
4358 | * Insert a received packet into a circular | ||
4359 | * rx queue. This packet will be picked up | ||
4360 | * by fr_bh() and sent up the stack to the | ||
4361 | * user. | ||
4362 | * | ||
4363 | * Usage: | ||
4364 | * This function is called by rx interrupt, | ||
4365 | * in API mode. | ||
4366 | * | ||
4367 | */ | ||
4368 | |||
4369 | static int bh_enqueue(struct net_device *dev, struct sk_buff *skb) | ||
4370 | { | ||
4371 | /* Check for full */ | ||
4372 | fr_channel_t* chan = dev->priv; | ||
4373 | sdla_t *card = chan->card; | ||
4374 | |||
4375 | |||
4376 | if (atomic_read(&chan->bh_buff_used) == MAX_BH_BUFF){ | ||
4377 | ++card->wandev.stats.rx_dropped; | ||
4378 | dev_kfree_skb_any(skb); | ||
4379 | return 1; | ||
4380 | } | ||
4381 | |||
4382 | ((bh_data_t *)&chan->bh_head[chan->bh_write])->skb = skb; | ||
4383 | |||
4384 | if (chan->bh_write == (MAX_BH_BUFF-1)){ | ||
4385 | chan->bh_write=0; | ||
4386 | }else{ | ||
4387 | ++chan->bh_write; | ||
4388 | } | ||
4389 | |||
4390 | atomic_inc(&chan->bh_buff_used); | ||
4391 | |||
4392 | return 0; | ||
4393 | } | ||
4394 | |||
4395 | |||
4396 | /*======================================================== | ||
4397 | * trigger_fr_bh | ||
4398 | * | ||
4399 | * Description: | ||
4400 | * Kick the fr_bh() handler | ||
4401 | * | ||
4402 | * Usage: | ||
4403 | * rx interrupt calls this function during | ||
4404 | * the API mode. | ||
4405 | */ | ||
4406 | |||
4407 | static void trigger_fr_bh (fr_channel_t *chan) | ||
4408 | { | ||
4409 | if (!test_and_set_bit(0,&chan->tq_working)){ | ||
4410 | wanpipe_queue_work(&chan->common.wanpipe_work); | ||
4411 | } | ||
4412 | } | ||
4413 | |||
4414 | |||
4415 | /*======================================================== | ||
4416 | * fr_bh | ||
4417 | * | ||
4418 | * Description: | ||
4419 | * Frame relay receive BH handler. | ||
4420 | * Dequeue data from the BH circular | ||
4421 | * buffer and pass it up the API sock. | ||
4422 | * | ||
4423 | * Rationale: | ||
4424 | * This fuction is used to offload the | ||
4425 | * rx_interrupt during API operation mode. | ||
4426 | * The fr_bh() function executes for each | ||
4427 | * dlci/interface. | ||
4428 | * | ||
4429 | * Once receive interrupt copies data from the | ||
4430 | * card into an skb buffer, the skb buffer | ||
4431 | * is appended to a circular BH buffer. | ||
4432 | * Then the interrupt kicks fr_bh() to finish the | ||
4433 | * job at a later time (not within the interrupt). | ||
4434 | * | ||
4435 | * Usage: | ||
4436 | * Interrupts use this to defer a task to | ||
4437 | * a polling routine. | ||
4438 | * | ||
4439 | */ | ||
4440 | |||
4441 | static void fr_bh(struct net_device * dev) | ||
4442 | { | ||
4443 | fr_channel_t* chan = dev->priv; | ||
4444 | sdla_t *card = chan->card; | ||
4445 | struct sk_buff *skb; | ||
4446 | |||
4447 | if (atomic_read(&chan->bh_buff_used) == 0){ | ||
4448 | clear_bit(0, &chan->tq_working); | ||
4449 | return; | ||
4450 | } | ||
4451 | |||
4452 | while (atomic_read(&chan->bh_buff_used)){ | ||
4453 | |||
4454 | if (chan->common.sk == NULL || chan->common.func == NULL){ | ||
4455 | clear_bit(0, &chan->tq_working); | ||
4456 | return; | ||
4457 | } | ||
4458 | |||
4459 | skb = ((bh_data_t *)&chan->bh_head[chan->bh_read])->skb; | ||
4460 | |||
4461 | if (skb != NULL){ | ||
4462 | |||
4463 | if (chan->common.sk == NULL || chan->common.func == NULL){ | ||
4464 | ++card->wandev.stats.rx_dropped; | ||
4465 | ++chan->ifstats.rx_dropped; | ||
4466 | dev_kfree_skb_any(skb); | ||
4467 | fr_bh_cleanup(dev); | ||
4468 | continue; | ||
4469 | } | ||
4470 | |||
4471 | if (chan->common.func(skb,dev,chan->common.sk) != 0){ | ||
4472 | /* Sock full cannot send, queue us for | ||
4473 | * another try */ | ||
4474 | atomic_set(&chan->common.receive_block,1); | ||
4475 | return; | ||
4476 | }else{ | ||
4477 | fr_bh_cleanup(dev); | ||
4478 | } | ||
4479 | }else{ | ||
4480 | fr_bh_cleanup(dev); | ||
4481 | } | ||
4482 | } | ||
4483 | clear_bit(0, &chan->tq_working); | ||
4484 | |||
4485 | return; | ||
4486 | } | ||
4487 | |||
4488 | static int fr_bh_cleanup(struct net_device *dev) | ||
4489 | { | ||
4490 | fr_channel_t* chan = dev->priv; | ||
4491 | |||
4492 | ((bh_data_t *)&chan->bh_head[chan->bh_read])->skb = NULL; | ||
4493 | |||
4494 | if (chan->bh_read == (MAX_BH_BUFF-1)){ | ||
4495 | chan->bh_read=0; | ||
4496 | }else{ | ||
4497 | ++chan->bh_read; | ||
4498 | } | ||
4499 | |||
4500 | atomic_dec(&chan->bh_buff_used); | ||
4501 | return 0; | ||
4502 | } | ||
4503 | |||
4504 | |||
4505 | /*---------------------------------------------------------------------- | ||
4506 | POLL BH HANDLERS AND KICK ROUTINES | ||
4507 | ----------------------------------------------------------------------*/ | ||
4508 | |||
4509 | /*============================================================ | ||
4510 | * trigger_fr_poll | ||
4511 | * | ||
4512 | * Description: | ||
4513 | * Add a fr_poll() task into a tq_scheduler bh handler | ||
4514 | * for a specific dlci/interface. This will kick | ||
4515 | * the fr_poll() routine at a later time. | ||
4516 | * | ||
4517 | * Usage: | ||
4518 | * Interrupts use this to defer a taks to | ||
4519 | * a polling routine. | ||
4520 | * | ||
4521 | */ | ||
4522 | static void trigger_fr_poll(struct net_device *dev) | ||
4523 | { | ||
4524 | fr_channel_t* chan = dev->priv; | ||
4525 | schedule_work(&chan->fr_poll_work); | ||
4526 | return; | ||
4527 | } | ||
4528 | |||
4529 | |||
4530 | /*============================================================ | ||
4531 | * fr_poll | ||
4532 | * | ||
4533 | * Rationale: | ||
4534 | * We cannot manipulate the routing tables, or | ||
4535 | * ip addresses withing the interrupt. Therefore | ||
4536 | * we must perform such actons outside an interrupt | ||
4537 | * at a later time. | ||
4538 | * | ||
4539 | * Description: | ||
4540 | * Frame relay polling routine, responsible for | ||
4541 | * shutting down interfaces upon disconnect | ||
4542 | * and adding/removing routes. | ||
4543 | * | ||
4544 | * Usage: | ||
4545 | * This function is executed for each frame relay | ||
4546 | * dlci/interface through a tq_schedule bottom half. | ||
4547 | * | ||
4548 | * trigger_fr_poll() function is used to kick | ||
4549 | * the fr_poll routine. | ||
4550 | */ | ||
4551 | |||
4552 | static void fr_poll(struct net_device *dev) | ||
4553 | { | ||
4554 | |||
4555 | fr_channel_t* chan; | ||
4556 | sdla_t *card; | ||
4557 | u8 check_gateway=0; | ||
4558 | |||
4559 | if (!dev || (chan = dev->priv) == NULL) | ||
4560 | return; | ||
4561 | |||
4562 | card = chan->card; | ||
4563 | |||
4564 | /* (Re)Configuraiton is in progress, stop what you are | ||
4565 | * doing and get out */ | ||
4566 | if (test_bit(PERI_CRIT,&card->wandev.critical)){ | ||
4567 | return; | ||
4568 | } | ||
4569 | |||
4570 | switch (chan->common.state){ | ||
4571 | |||
4572 | case WAN_DISCONNECTED: | ||
4573 | |||
4574 | if (test_bit(DYN_OPT_ON,&chan->interface_down) && | ||
4575 | !test_bit(DEV_DOWN, &chan->interface_down) && | ||
4576 | dev->flags&IFF_UP){ | ||
4577 | |||
4578 | printk(KERN_INFO "%s: Interface %s is Down.\n", | ||
4579 | card->devname,dev->name); | ||
4580 | change_dev_flags(dev,dev->flags&~IFF_UP); | ||
4581 | set_bit(DEV_DOWN, &chan->interface_down); | ||
4582 | chan->route_flag = NO_ROUTE; | ||
4583 | |||
4584 | }else{ | ||
4585 | if (chan->inarp != INARP_NONE) | ||
4586 | process_route(dev); | ||
4587 | } | ||
4588 | break; | ||
4589 | |||
4590 | case WAN_CONNECTED: | ||
4591 | |||
4592 | if (test_bit(DYN_OPT_ON,&chan->interface_down) && | ||
4593 | test_bit(DEV_DOWN, &chan->interface_down) && | ||
4594 | !(dev->flags&IFF_UP)){ | ||
4595 | |||
4596 | printk(KERN_INFO "%s: Interface %s is Up.\n", | ||
4597 | card->devname,dev->name); | ||
4598 | |||
4599 | change_dev_flags(dev,dev->flags|IFF_UP); | ||
4600 | clear_bit(DEV_DOWN, &chan->interface_down); | ||
4601 | check_gateway=1; | ||
4602 | } | ||
4603 | |||
4604 | if (chan->inarp != INARP_NONE){ | ||
4605 | process_route(dev); | ||
4606 | check_gateway=1; | ||
4607 | } | ||
4608 | |||
4609 | if (chan->gateway && check_gateway) | ||
4610 | add_gateway(card,dev); | ||
4611 | |||
4612 | break; | ||
4613 | |||
4614 | } | ||
4615 | |||
4616 | return; | ||
4617 | } | ||
4618 | |||
4619 | /*============================================================== | ||
4620 | * check_tx_status | ||
4621 | * | ||
4622 | * Rationale: | ||
4623 | * We cannot transmit from an interrupt while | ||
4624 | * the if_send is transmitting data. Therefore, | ||
4625 | * we must check whether the tx buffers are | ||
4626 | * begin used, before we transmit from an | ||
4627 | * interrupt. | ||
4628 | * | ||
4629 | * Description: | ||
4630 | * Checks whether it's safe to use the transmit | ||
4631 | * buffers. | ||
4632 | * | ||
4633 | * Usage: | ||
4634 | * ARP and UDP handling routines use this function | ||
4635 | * because, they need to transmit data during | ||
4636 | * an interrupt. | ||
4637 | */ | ||
4638 | |||
4639 | static int check_tx_status(sdla_t *card, struct net_device *dev) | ||
4640 | { | ||
4641 | |||
4642 | if (card->hw.type == SDLA_S514){ | ||
4643 | if (test_bit(SEND_CRIT, (void*)&card->wandev.critical) || | ||
4644 | test_bit(SEND_TXIRQ_CRIT, (void*)&card->wandev.critical)) { | ||
4645 | return 1; | ||
4646 | } | ||
4647 | } | ||
4648 | |||
4649 | if (netif_queue_stopped(dev) || (card->u.f.tx_interrupts_pending)) | ||
4650 | return 1; | ||
4651 | |||
4652 | return 0; | ||
4653 | } | ||
4654 | |||
4655 | /*=============================================================== | ||
4656 | * move_dev_to_next | ||
4657 | * | ||
4658 | * Description: | ||
4659 | * Move the dev pointer to the next location in the | ||
4660 | * link list. Check if we are at the end of the | ||
4661 | * list, if so start from the begining. | ||
4662 | * | ||
4663 | * Usage: | ||
4664 | * Timer interrupt uses this function to efficiently | ||
4665 | * step through the devices that need to send ARP data. | ||
4666 | * | ||
4667 | */ | ||
4668 | |||
4669 | struct net_device *move_dev_to_next(sdla_t *card, struct net_device *dev) | ||
4670 | { | ||
4671 | if (card->wandev.new_if_cnt != 1){ | ||
4672 | if (!*((struct net_device **)dev->priv)) | ||
4673 | return card->wandev.dev; | ||
4674 | else | ||
4675 | return *((struct net_device **)dev->priv); | ||
4676 | } | ||
4677 | return dev; | ||
4678 | } | ||
4679 | |||
4680 | /*============================================================== | ||
4681 | * trigger_config_fr | ||
4682 | * | ||
4683 | * Rationale: | ||
4684 | * All commands must be performed inside of a | ||
4685 | * interrupt. | ||
4686 | * | ||
4687 | * Description: | ||
4688 | * Kick the config_fr() routine throught the | ||
4689 | * timer interrupt. | ||
4690 | */ | ||
4691 | |||
4692 | |||
4693 | static void trigger_config_fr (sdla_t *card) | ||
4694 | { | ||
4695 | fr508_flags_t* flags = card->flags; | ||
4696 | |||
4697 | card->u.f.timer_int_enabled |= TMR_INT_ENABLED_CONFIG; | ||
4698 | flags->imask |= FR_INTR_TIMER; | ||
4699 | } | ||
4700 | |||
4701 | |||
4702 | /*============================================================== | ||
4703 | * config_fr | ||
4704 | * | ||
4705 | * Rationale: | ||
4706 | * All commands must be performed inside of a | ||
4707 | * interrupt. | ||
4708 | & | ||
4709 | * Description: | ||
4710 | * Configure a DLCI. This function is executed | ||
4711 | * by a timer_interrupt. The if_open() function | ||
4712 | * triggers it. | ||
4713 | * | ||
4714 | * Usage: | ||
4715 | * new_if() collects all data necessary to | ||
4716 | * configure the DLCI. It sets the chan->dlci_ready | ||
4717 | * bit. When the if_open() function is executed | ||
4718 | * it checks this bit, and if its set it triggers | ||
4719 | * the timer interrupt to execute the config_fr() | ||
4720 | * function. | ||
4721 | */ | ||
4722 | |||
4723 | static void config_fr (sdla_t *card) | ||
4724 | { | ||
4725 | struct net_device *dev; | ||
4726 | fr_channel_t *chan; | ||
4727 | |||
4728 | for (dev = card->wandev.dev; dev; | ||
4729 | dev = *((struct net_device **)dev->priv)) { | ||
4730 | |||
4731 | if ((chan=dev->priv) == NULL) | ||
4732 | continue; | ||
4733 | |||
4734 | if (!test_bit(0,&chan->config_dlci)) | ||
4735 | continue; | ||
4736 | |||
4737 | clear_bit(0,&chan->config_dlci); | ||
4738 | |||
4739 | /* If signalling is set to NO, then setup | ||
4740 | * DLCI addresses right away. Don't have to wait for | ||
4741 | * link to connect. | ||
4742 | */ | ||
4743 | if (card->wandev.signalling == WANOPT_NO){ | ||
4744 | printk(KERN_INFO "%s: Signalling set to NO: Mapping DLCI's\n", | ||
4745 | card->wandev.name); | ||
4746 | if (fr_init_dlci(card,chan)){ | ||
4747 | printk(KERN_INFO "%s: ERROR: Failed to configure DLCI %i !\n", | ||
4748 | card->devname, chan->dlci); | ||
4749 | return; | ||
4750 | } | ||
4751 | } | ||
4752 | |||
4753 | if (card->wandev.station == WANOPT_CPE) { | ||
4754 | |||
4755 | update_chan_state(dev); | ||
4756 | |||
4757 | /* CPE: issue full status enquiry */ | ||
4758 | fr_issue_isf(card, FR_ISF_FSE); | ||
4759 | |||
4760 | } else { | ||
4761 | /* FR switch: activate DLCI(s) */ | ||
4762 | |||
4763 | /* For Switch emulation we have to ADD and ACTIVATE | ||
4764 | * the DLCI(s) that were configured with the SET_DLCI_ | ||
4765 | * CONFIGURATION command. Add and Activate will fail if | ||
4766 | * DLCI specified is not included in the list. | ||
4767 | * | ||
4768 | * Also If_open is called once for each interface. But | ||
4769 | * it does not get in here for all the interface. So | ||
4770 | * we have to pass the entire list of DLCI(s) to add | ||
4771 | * activate routines. | ||
4772 | */ | ||
4773 | |||
4774 | if (!check_dlci_config (card, chan)){ | ||
4775 | fr_add_dlci(card, chan->dlci); | ||
4776 | fr_activate_dlci(card, chan->dlci); | ||
4777 | } | ||
4778 | } | ||
4779 | |||
4780 | card->u.f.dlci_to_dev_map[chan->dlci] = dev; | ||
4781 | } | ||
4782 | return; | ||
4783 | } | ||
4784 | |||
4785 | |||
4786 | /*============================================================== | ||
4787 | * config_fr | ||
4788 | * | ||
4789 | * Rationale: | ||
4790 | * All commands must be executed during an interrupt. | ||
4791 | * | ||
4792 | * Description: | ||
4793 | * Trigger uncofig_fr() function through | ||
4794 | * the timer interrupt. | ||
4795 | * | ||
4796 | */ | ||
4797 | |||
4798 | static void trigger_unconfig_fr(struct net_device *dev) | ||
4799 | { | ||
4800 | fr_channel_t *chan = dev->priv; | ||
4801 | volatile sdla_t *card = chan->card; | ||
4802 | u32 timeout; | ||
4803 | fr508_flags_t* flags = card->flags; | ||
4804 | int reset_critical=0; | ||
4805 | |||
4806 | if (test_bit(PERI_CRIT,(void*)&card->wandev.critical)){ | ||
4807 | clear_bit(PERI_CRIT,(void*)&card->wandev.critical); | ||
4808 | reset_critical=1; | ||
4809 | } | ||
4810 | |||
4811 | /* run unconfig_dlci() function | ||
4812 | * throught the timer interrupt */ | ||
4813 | set_bit(0,(void*)&chan->unconfig_dlci); | ||
4814 | card->u.f.timer_int_enabled |= TMR_INT_ENABLED_UNCONFIG; | ||
4815 | flags->imask |= FR_INTR_TIMER; | ||
4816 | |||
4817 | /* Wait for the command to complete */ | ||
4818 | timeout = jiffies; | ||
4819 | for(;;) { | ||
4820 | |||
4821 | if(!(card->u.f.timer_int_enabled & TMR_INT_ENABLED_UNCONFIG)) | ||
4822 | break; | ||
4823 | |||
4824 | if ((jiffies - timeout) > (1 * HZ)){ | ||
4825 | card->u.f.timer_int_enabled &= ~TMR_INT_ENABLED_UNCONFIG; | ||
4826 | printk(KERN_INFO "%s: Failed to delete DLCI %i\n", | ||
4827 | card->devname,chan->dlci); | ||
4828 | break; | ||
4829 | } | ||
4830 | } | ||
4831 | |||
4832 | if (reset_critical){ | ||
4833 | set_bit(PERI_CRIT,(void*)&card->wandev.critical); | ||
4834 | } | ||
4835 | } | ||
4836 | |||
4837 | /*============================================================== | ||
4838 | * unconfig_fr | ||
4839 | * | ||
4840 | * Rationale: | ||
4841 | * All commands must be executed during an interrupt. | ||
4842 | * | ||
4843 | * Description: | ||
4844 | * Remove the dlci from firmware. | ||
4845 | * This funciton is used in NODE shutdown. | ||
4846 | */ | ||
4847 | |||
4848 | static void unconfig_fr (sdla_t *card) | ||
4849 | { | ||
4850 | struct net_device *dev; | ||
4851 | fr_channel_t *chan; | ||
4852 | |||
4853 | for (dev = card->wandev.dev; dev; | ||
4854 | dev = *((struct net_device **)dev->priv)){ | ||
4855 | |||
4856 | if ((chan=dev->priv) == NULL) | ||
4857 | continue; | ||
4858 | |||
4859 | if (!test_bit(0,&chan->unconfig_dlci)) | ||
4860 | continue; | ||
4861 | |||
4862 | clear_bit(0,&chan->unconfig_dlci); | ||
4863 | |||
4864 | if (card->wandev.station == WANOPT_NODE){ | ||
4865 | printk(KERN_INFO "%s: Unconfiguring DLCI %i\n", | ||
4866 | card->devname,chan->dlci); | ||
4867 | fr_delete_dlci(card,chan->dlci); | ||
4868 | } | ||
4869 | card->u.f.dlci_to_dev_map[chan->dlci] = NULL; | ||
4870 | } | ||
4871 | } | ||
4872 | |||
4873 | static int setup_fr_header(struct sk_buff **skb_orig, struct net_device* dev, | ||
4874 | char op_mode) | ||
4875 | { | ||
4876 | struct sk_buff *skb = *skb_orig; | ||
4877 | fr_channel_t *chan=dev->priv; | ||
4878 | |||
4879 | if (op_mode == WANPIPE){ | ||
4880 | |||
4881 | chan->fr_header[0]=Q922_UI; | ||
4882 | |||
4883 | switch (htons(skb->protocol)){ | ||
4884 | |||
4885 | case ETH_P_IP: | ||
4886 | chan->fr_header[1]=NLPID_IP; | ||
4887 | break; | ||
4888 | default: | ||
4889 | return -EINVAL; | ||
4890 | } | ||
4891 | |||
4892 | return 2; | ||
4893 | } | ||
4894 | |||
4895 | /* If we are in bridging mode, we must apply | ||
4896 | * an Ethernet header */ | ||
4897 | if (op_mode == BRIDGE || op_mode == BRIDGE_NODE){ | ||
4898 | |||
4899 | |||
4900 | /* Encapsulate the packet as a bridged Ethernet frame. */ | ||
4901 | #ifdef DEBUG | ||
4902 | printk(KERN_INFO "%s: encapsulating skb for frame relay\n", | ||
4903 | dev->name); | ||
4904 | #endif | ||
4905 | |||
4906 | chan->fr_header[0] = 0x03; | ||
4907 | chan->fr_header[1] = 0x00; | ||
4908 | chan->fr_header[2] = 0x80; | ||
4909 | chan->fr_header[3] = 0x00; | ||
4910 | chan->fr_header[4] = 0x80; | ||
4911 | chan->fr_header[5] = 0xC2; | ||
4912 | chan->fr_header[6] = 0x00; | ||
4913 | chan->fr_header[7] = 0x07; | ||
4914 | |||
4915 | /* Yuck. */ | ||
4916 | skb->protocol = ETH_P_802_3; | ||
4917 | return 8; | ||
4918 | |||
4919 | } | ||
4920 | |||
4921 | return 0; | ||
4922 | } | ||
4923 | |||
4924 | |||
4925 | static int check_dlci_config (sdla_t *card, fr_channel_t *chan) | ||
4926 | { | ||
4927 | fr_mbox_t* mbox = card->mbox; | ||
4928 | int err=0; | ||
4929 | fr_conf_t *conf=NULL; | ||
4930 | unsigned short dlci_num = chan->dlci; | ||
4931 | int dlci_offset=0; | ||
4932 | struct net_device *dev = NULL; | ||
4933 | |||
4934 | mbox->cmd.command = FR_READ_CONFIG; | ||
4935 | mbox->cmd.length = 0; | ||
4936 | mbox->cmd.dlci = dlci_num; | ||
4937 | |||
4938 | err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; | ||
4939 | |||
4940 | if (err == CMD_OK){ | ||
4941 | return 0; | ||
4942 | } | ||
4943 | |||
4944 | for (dev = card->wandev.dev; dev; | ||
4945 | dev=*((struct net_device **)dev->priv)) | ||
4946 | set_chan_state(dev,WAN_DISCONNECTED); | ||
4947 | |||
4948 | printk(KERN_INFO "DLCI %i Not configured, configuring\n",dlci_num); | ||
4949 | |||
4950 | mbox->cmd.command = FR_COMM_DISABLE; | ||
4951 | mbox->cmd.length = 0; | ||
4952 | err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; | ||
4953 | if (err != CMD_OK){ | ||
4954 | fr_event(card, err, mbox); | ||
4955 | return 2; | ||
4956 | } | ||
4957 | |||
4958 | printk(KERN_INFO "Disabled Communications \n"); | ||
4959 | |||
4960 | mbox->cmd.command = FR_READ_CONFIG; | ||
4961 | mbox->cmd.length = 0; | ||
4962 | mbox->cmd.dlci = 0; | ||
4963 | |||
4964 | err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; | ||
4965 | |||
4966 | if (err != CMD_OK){ | ||
4967 | fr_event(card, err, mbox); | ||
4968 | return 2; | ||
4969 | } | ||
4970 | |||
4971 | conf = (fr_conf_t *)mbox->data; | ||
4972 | |||
4973 | dlci_offset=0; | ||
4974 | for (dev = card->wandev.dev; dev; | ||
4975 | dev = *((struct net_device **)dev->priv)) { | ||
4976 | fr_channel_t *chan_tmp = dev->priv; | ||
4977 | conf->dlci[dlci_offset] = chan_tmp->dlci; | ||
4978 | dlci_offset++; | ||
4979 | } | ||
4980 | |||
4981 | printk(KERN_INFO "Got Fr configuration Buffer Length is %x Dlci %i Dlci Off %i\n", | ||
4982 | mbox->cmd.length, | ||
4983 | mbox->cmd.length > 0x20 ? conf->dlci[0] : -1, | ||
4984 | dlci_offset ); | ||
4985 | |||
4986 | mbox->cmd.length = 0x20 + dlci_offset*2; | ||
4987 | |||
4988 | mbox->cmd.command = FR_SET_CONFIG; | ||
4989 | mbox->cmd.dlci = 0; | ||
4990 | |||
4991 | err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; | ||
4992 | |||
4993 | if (err != CMD_OK){ | ||
4994 | fr_event(card, err, mbox); | ||
4995 | return 2; | ||
4996 | } | ||
4997 | |||
4998 | initialize_rx_tx_buffers (card); | ||
4999 | |||
5000 | |||
5001 | printk(KERN_INFO "Configuraiton Succeded for new DLCI %i\n",dlci_num); | ||
5002 | |||
5003 | if (fr_comm_enable (card)){ | ||
5004 | return 2; | ||
5005 | } | ||
5006 | |||
5007 | printk(KERN_INFO "Enabling Communications \n"); | ||
5008 | |||
5009 | for (dev = card->wandev.dev; dev; | ||
5010 | dev = *((struct net_device **)dev->priv)) { | ||
5011 | fr_channel_t *chan_tmp = dev->priv; | ||
5012 | fr_init_dlci(card,chan_tmp); | ||
5013 | fr_add_dlci(card, chan_tmp->dlci); | ||
5014 | fr_activate_dlci(card, chan_tmp->dlci); | ||
5015 | } | ||
5016 | |||
5017 | printk(KERN_INFO "END OF CONFIGURAITON %i\n",dlci_num); | ||
5018 | |||
5019 | return 1; | ||
5020 | } | ||
5021 | |||
5022 | static void initialize_rx_tx_buffers (sdla_t *card) | ||
5023 | { | ||
5024 | fr_buf_info_t* buf_info; | ||
5025 | |||
5026 | if (card->hw.type == SDLA_S514) { | ||
5027 | |||
5028 | buf_info = (void*)(card->hw.dpmbase + FR_MB_VECTOR + | ||
5029 | FR508_RXBC_OFFS); | ||
5030 | |||
5031 | card->rxmb = (void*)(buf_info->rse_next + card->hw.dpmbase); | ||
5032 | |||
5033 | card->u.f.rxmb_base = | ||
5034 | (void*)(buf_info->rse_base + card->hw.dpmbase); | ||
5035 | |||
5036 | card->u.f.rxmb_last = | ||
5037 | (void*)(buf_info->rse_base + | ||
5038 | (buf_info->rse_num - 1) * sizeof(fr_rx_buf_ctl_t) + | ||
5039 | card->hw.dpmbase); | ||
5040 | }else{ | ||
5041 | buf_info = (void*)(card->hw.dpmbase + FR508_RXBC_OFFS); | ||
5042 | |||
5043 | card->rxmb = (void*)(buf_info->rse_next - | ||
5044 | FR_MB_VECTOR + card->hw.dpmbase); | ||
5045 | |||
5046 | card->u.f.rxmb_base = | ||
5047 | (void*)(buf_info->rse_base - | ||
5048 | FR_MB_VECTOR + card->hw.dpmbase); | ||
5049 | |||
5050 | card->u.f.rxmb_last = | ||
5051 | (void*)(buf_info->rse_base + | ||
5052 | (buf_info->rse_num - 1) * sizeof(fr_rx_buf_ctl_t) - | ||
5053 | FR_MB_VECTOR + card->hw.dpmbase); | ||
5054 | } | ||
5055 | |||
5056 | card->u.f.rx_base = buf_info->buf_base; | ||
5057 | card->u.f.rx_top = buf_info->buf_top; | ||
5058 | |||
5059 | card->u.f.tx_interrupts_pending = 0; | ||
5060 | |||
5061 | return; | ||
5062 | } | ||
5063 | |||
5064 | |||
5065 | |||
5066 | MODULE_LICENSE("GPL"); | ||
5067 | |||
5068 | /****** End *****************************************************************/ | ||