patch-2.4.4 linux/drivers/net/wan/sdla_fr.c
Next file: linux/drivers/net/wan/sdla_ft1.c
Previous file: linux/drivers/net/wan/sdla_chdlc.c
Back to the patch index
Back to the overall index
- Lines: 4865
- Date:
Fri Apr 20 11:54:22 2001
- Orig file:
v2.4.3/linux/drivers/net/wan/sdla_fr.c
- Orig date:
Tue Mar 6 19:44:36 2001
diff -u --recursive --new-file v2.4.3/linux/drivers/net/wan/sdla_fr.c linux/drivers/net/wan/sdla_fr.c
@@ -4,14 +4,43 @@
* Author(s): Nenad Corbic <ncorbic@sangoma.com>
* Gideon Hack
*
-* Copyright: (c) 1995-1999 Sangoma Technologies Inc.
+* Copyright: (c) 1995-2001 Sangoma Technologies Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
* ============================================================================
-* Feb 28, 2000 Jeff Garzik o softnet updates
+* Nov 23, 2000 Nenad Corbic o Added support for 2.4.X kernels
+* Nov 15, 2000 David Rokavarg
+* Nenad Corbic o Added frame relay bridging support.
+* Original code from Mark Wells and Kristian Hoffmann has
+* been integrated into the frame relay driver.
+* Nov 13, 2000 Nenad Corbic o Added true interface type encoding option.
+* Tcpdump doesn't support Frame Relay inteface
+* types, to fix this true type option will set
+* the interface type to RAW IP mode.
+* Nov 07, 2000 Nenad Corbic o Added security features for UDP debugging:
+* Deny all and specify allowed requests.
+* Nov 06, 2000 Nenad Corbic o Wanpipe interfaces conform to raw packet interfaces.
+* Moved the if_header into the if_send() routine.
+* The if_header() was breaking the libpcap
+* support. i.e. support for tcpdump, ethereal ...
+* Oct 12. 2000 Nenad Corbic o Added error message in fr_configure
+* Jul 31, 2000 Nenad Corbic o Fixed the Router UP Time.
+* Apr 28, 2000 Nenad Corbic o Added the option to shutdown an interface
+* when the channel gets disconnected.
+* Apr 28, 2000 Nenad Corbic o Added M.Grants patch: disallow duplicate
+* interface setups.
+* Apr 25, 2000 Nenad Corbic o Added M.Grants patch: dynamically add/remove
+* new dlcis/interfaces.
+* Mar 23, 2000 Nenad Corbic o Improved task queue, bh handling.
+* Mar 16, 2000 Nenad Corbic o Added Inverse ARP support
+* Mar 13, 2000 Nenad Corbic o Added new socket API support.
+* Mar 06, 2000 Nenad Corbic o Bug Fix: corrupted mbox recovery.
+* Feb 24, 2000 Nenad Corbic o Fixed up FT1 UDP debugging problem.
+* Dev 15, 1999 Nenad Corbic o Fixed up header files for 2.0.X kernels
+*
* Nov 08, 1999 Nenad Corbic o Combined all debug UDP calls into one function
* o Removed the ARP support. This has to be done
* in the next version.
@@ -109,12 +138,12 @@
* Jan 02, 1997 Gene Kozin Initial version.
*****************************************************************************/
-#include <linux/config.h>
+#include <linux/version.h>
#include <linux/kernel.h> /* printk(), and other useful stuff */
#include <linux/stddef.h> /* offsetof(), etc. */
#include <linux/errno.h> /* return codes */
#include <linux/string.h> /* inline memset(), etc. */
-#include <linux/slab.h> /* kmalloc(), kfree() */
+#include <linux/malloc.h> /* kmalloc(), kfree() */
#include <linux/wanrouter.h> /* WAN router definitions */
#include <linux/wanpipe.h> /* WANPIPE common user API definitions */
#include <linux/if_arp.h> /* ARPHRD_* defines */
@@ -123,14 +152,29 @@
#include <linux/time.h> /* for do_gettimeofday */
#include <linux/in.h> /* sockaddr_in */
#include <linux/inet.h> /* in_ntoa(), etc... */
-#include <asm/uaccess.h>
-#include <linux/inetdevice.h>
+#include <asm/errno.h>
+
#include <linux/ip.h>
-#include <net/route.h> /* Dynamic Route Creation */
#include <linux/if.h>
-#include <linux/sdla_fr.h> /* frame relay firmware API definitions */
-
+#include <linux/if_wanpipe_common.h> /* Wanpipe Socket */
+#include <linux/if_wanpipe.h>
+
+#include <linux/sdla_fr.h> /* frame relay firmware API definitions */
+
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
+ #include <asm/uaccess.h>
+ #include <linux/inetdevice.h>
+ #include <linux/netdevice.h>
+
+#else
+ #include <asm/segment.h>
+#endif
+
+#include <net/route.h> /* Dynamic Route Creation */
+#include <linux/etherdevice.h> /* eth_type_trans() used for bridging */
+#include <linux/random.h>
+
/****** Defines & Macros ****************************************************/
#define MAX_CMD_RETRY 10 /* max number of firmware retries */
@@ -151,25 +195,20 @@
#define CIR_ENABLED 0x00
#define CIR_DISABLED 0x01
-#define WANPIPE 0x00
-#define API 0x01
#define FRAME_RELAY_API 1
-
-#define TX_TIMEOUT (5*HZ)
+#define MAX_BH_BUFF 10
/* For handle_IPXWAN() */
#define CVHexToAscii(b) (((unsigned char)(b) > (unsigned char)9) ? ((unsigned char)'A' + ((unsigned char)(b) - (unsigned char)10)) : ((unsigned char)'0' + (unsigned char)(b)))
/****** Data Structures *****************************************************/
-/* This is an extention of the 'struct net_device' we create for each network
+/* This is an extention of the 'struct device' we create for each network
* interface to keep the rest of channel-specific data.
*/
typedef struct fr_channel
{
- /* This member must be first. */
- struct net_device *slave; /* WAN slave */
-
+ wanpipe_common_t common;
char name[WAN_IFNAME_SZ+1]; /* interface name, ASCIIZ */
unsigned dlci_configured ; /* check whether configured or not */
unsigned cir_status; /* check whether CIR enabled or not */
@@ -183,7 +222,6 @@
unsigned long router_start_time;/* Router start time in seconds */
unsigned long tick_counter; /* counter for transmit time out */
char dev_pending_devtint; /* interface pending dev_tint() */
- char state; /* channel state */
void *dlci_int_interface; /* pointer to the DLCI Interface */
unsigned long IB_addr; /* physical address of Interface Byte */
unsigned long state_tick; /* time of the last state change */
@@ -192,19 +230,52 @@
sdla_t *card; /* -> owner */
unsigned route_flag; /* Add/Rem dest addr in route tables */
unsigned inarp; /* Inverse Arp Request status */
+ unsigned char inarp_ready; /* Ready to send requests */
int inarp_interval; /* Time between InArp Requests */
unsigned long inarp_tick; /* InArp jiffies tick counter */
+ unsigned char interface_down; /* Bring interface down on disconnect */
+ #if defined(LINUX_2_1) || defined(LINUX_2_4)
struct net_device_stats ifstats; /* interface statistics */
+ #else
+ struct enet_statistics ifstats;
+ #endif
if_send_stat_t drvstats_if_send;
rx_intr_stat_t drvstats_rx_intr;
pipe_mgmt_stat_t drvstats_gen;
-
- unsigned char usedby; /* Used by WANPIPE or API */
-
unsigned long router_up_time;
unsigned short transmit_length;
- char transmit_buffer[FR_MAX_NO_DATA_BYTES_IN_FRAME];
+ struct sk_buff *delay_skb;
+
+
+ #if defined(LINUX_2_1) || defined(LINUX_2_4)
+ bh_data_t *bh_head; /* Circular buffer for chdlc_bh */
+ unsigned long tq_working;
+ volatile int bh_write;
+ volatile int bh_read;
+ atomic_t bh_buff_used;
+ #endif
+
+ /* Polling task queue. Each interface
+ * has its own task queue, which is used
+ * to defer events from the interrupt */
+ struct tq_struct fr_poll_task;
+ struct timer_list fr_arp_timer;
+
+ u32 ip_local;
+ u32 ip_remote;
+ u8 config_dlci;
+ u32 unconfig_dlci;
+
+ /* Whether this interface should be setup as a gateway.
+ * Used by dynamic route setup code */
+ u8 gateway;
+
+ /* True interface type */
+ u8 true_if_encoding;
+ u8 fr_header[FR_HEADER_LEN];
+ char fr_header_len;
+
} fr_channel_t;
/* Route Flag options */
@@ -212,6 +283,7 @@
#define ADD_ROUTE 0x01
#define ROUTE_ADDED 0x02
#define REMOVE_ROUTE 0x03
+#define ARP_REQ 0x04
/* inarp options */
#define INARP_NONE 0x00
@@ -221,6 +293,10 @@
/* reasons for enabling the timer interrupt on the adapter */
#define TMR_INT_ENABLED_UDP 0x01
#define TMR_INT_ENABLED_UPDATE 0x02
+#define TMR_INT_ENABLED_ARP 0x04
+#define TMR_INT_ENABLED_UPDATE_STATE 0x08
+#define TMR_INT_ENABLED_CONFIG 0x10
+#define TMR_INT_ENABLED_UNCONFIG 0x20
typedef struct dlci_status
@@ -248,7 +324,6 @@
/* variable for keeping track of enabling/disabling FT1 monitor status */
static int rCount = 0;
-extern int ip_rt_ioctl(unsigned int, void *);
extern void disable_irq(unsigned int);
extern void enable_irq(unsigned int);
@@ -256,27 +331,43 @@
* interrupt test routine
*/
static int Intr_test_counter;
+
/****** Function Prototypes *************************************************/
/* WAN link driver entry points. These are called by the WAN router module. */
static int update(wan_device_t *wandev);
-static int new_if(wan_device_t *wandev, struct net_device *dev, wanif_conf_t *conf);
-static int del_if(wan_device_t *wandev, struct net_device *dev);
+static int new_if(wan_device_t *wandev, netdevice_t *dev, wanif_conf_t *conf);
+static int del_if(wan_device_t *wandev, netdevice_t *dev);
+static void disable_comm (sdla_t *card);
/* WANPIPE-specific entry points */
static int wpf_exec(struct sdla *card, void *u_cmd, void *u_data);
/* Network device interface */
-static int if_init(struct net_device *dev);
-static int if_open(struct net_device *dev);
-static int if_close(struct net_device *dev);
-static int if_header(struct sk_buff *skb, struct net_device *dev, unsigned short type, void *daddr, void *saddr, unsigned len);
-static int if_rebuild_hdr(struct sk_buff *skb);
-static int if_send(struct sk_buff *skb, struct net_device *dev);
-static void if_tx_timeout (struct net_device *dev);
-static int chk_bcast_mcast_addr(sdla_t *card, struct net_device* dev,
+static int if_init(netdevice_t *dev);
+static int if_open(netdevice_t *dev);
+static int if_close(netdevice_t *dev);
+
+
+#ifdef LINUX_2_4
+static void if_tx_timeout (netdevice_t *dev);
+#endif
+
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
+static int if_rebuild_hdr (struct sk_buff *skb);
+#else
+static int if_rebuild_hdr (void* hdr, netdevice_t* dev, unsigned long raddr,
+ struct sk_buff* skb);
+#endif
+
+static int if_send(struct sk_buff *skb, netdevice_t *dev);
+static int chk_bcast_mcast_addr(sdla_t *card, netdevice_t* dev,
struct sk_buff *skb);
-static struct net_device_stats *if_stats(struct net_device *dev);
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
+static struct net_device_stats *if_stats(netdevice_t *dev);
+#else
+static struct enet_statistics* if_stats (netdevice_t* dev);
+#endif
/* Interrupt handlers */
static void fr_isr(sdla_t *card);
@@ -292,7 +383,7 @@
static int fr_init_dlci (sdla_t *card, fr_channel_t *chan);
static int fr_set_intr_mode (sdla_t *card, unsigned mode, unsigned mtu, unsigned short timeout);
static int fr_comm_enable(sdla_t *card);
-static int fr_comm_disable(sdla_t *card);
+static void fr_comm_disable(sdla_t *card);
static int fr_get_err_stats(sdla_t *card);
static int fr_get_stats(sdla_t *card);
static int fr_add_dlci(sdla_t *card, int dlci);
@@ -301,6 +392,13 @@
static int fr_issue_isf(sdla_t *card, int isf);
static int fr_send(sdla_t *card, int dlci, unsigned char attr, int len,
void *buf);
+static int fr_send_data_header(sdla_t *card, int dlci, unsigned char attr, int len,
+ void *buf,unsigned char hdr_len);
+static unsigned int fr_send_hdr(sdla_t *card, int dlci, unsigned int offset);
+
+static int check_dlci_config (sdla_t *card, fr_channel_t *chan);
+static void initialize_rx_tx_buffers (sdla_t *card);
+
/* Firmware asynchronous event handlers */
static int fr_event(sdla_t *card, int event, fr_mbox_t *mbox);
@@ -308,9 +406,9 @@
static int fr_dlci_change(sdla_t *card, fr_mbox_t *mbox);
/* Miscellaneous functions */
-static int update_chan_state(struct net_device *dev);
-static void set_chan_state(struct net_device *dev, int state);
-static struct net_device *find_channel(sdla_t *card, unsigned dlci);
+static int update_chan_state(netdevice_t *dev);
+static void set_chan_state(netdevice_t *dev, int state);
+static netdevice_t *find_channel(sdla_t *card, unsigned dlci);
static int is_tx_ready(sdla_t *card, fr_channel_t *chan);
static unsigned int dec_to_uint(unsigned char *str, int len);
static int reply_udp( unsigned char *data, unsigned int mbox_len );
@@ -319,14 +417,38 @@
static void init_chan_statistics( fr_channel_t* chan );
static void init_global_statistics( sdla_t* card );
static void read_DLCI_IB_mapping( sdla_t* card, fr_channel_t* chan );
-static void setup_for_delayed_transmit(struct net_device* dev, void* buf,
- unsigned len);
+static int setup_for_delayed_transmit(netdevice_t* dev, struct sk_buff *skb);
+
+netdevice_t * move_dev_to_next (sdla_t *, netdevice_t *);
+static int check_tx_status(sdla_t *, netdevice_t *);
+
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
+/* Frame Relay Socket API */
+static void trigger_fr_bh (fr_channel_t *);
+static void fr_bh (netdevice_t *);
+static int fr_bh_cleanup (netdevice_t *);
+static int bh_enqueue (netdevice_t *, struct sk_buff *);
+#endif
+
+static void trigger_fr_poll (netdevice_t *);
+static void fr_poll (netdevice_t *);
+//static void add_gateway (netdevice_t *);
+
+static void trigger_unconfig_fr (netdevice_t *dev);
+static void unconfig_fr (sdla_t *);
+
+static void trigger_config_fr (sdla_t *);
+static void config_fr (sdla_t *);
/* Inverse ARP and Dynamic routing functions */
-int process_ARP(arphdr_1490_t *ArpPacket, sdla_t *card, struct net_device *dev);
+int process_ARP(arphdr_1490_t *ArpPacket, sdla_t *card, netdevice_t *dev);
int is_arp(void *buf);
-int send_inarp_request(sdla_t *card, struct net_device *dev);
+int send_inarp_request(sdla_t *card, netdevice_t *dev);
+
+static void trigger_fr_arp (netdevice_t *);
+static void fr_arp (unsigned long data);
+
/* Udp management functions */
static int process_udp_mgmt_pkt(sdla_t *card);
@@ -346,6 +468,7 @@
void s508_s514_lock(sdla_t *card, unsigned long *smp_flags);
unsigned short calc_checksum (char *, int);
+static int setup_fr_header(struct sk_buff** skb, netdevice_t* dev, char op_mode);
/****** Public Functions ****************************************************/
@@ -366,15 +489,20 @@
{
int err;
+ fr508_flags_t* flags;
union
{
char str[80];
fr_conf_t cfg;
} u;
+
fr_buf_info_t* buf_info;
int i;
+
+ printk(KERN_INFO "\n");
+
/* Verify configuration ID */
if (conf->config_id != WANCONFIG_FR) {
@@ -403,6 +531,8 @@
return -EINVAL;
}
+ flags = card->flags;
+
/* Read firmware version. Note that when adapter initializes, it
* clears the mailbox, so it may appear that the first command was
* executed successfully when in fact it was merely erased. To work
@@ -429,7 +559,7 @@
memset(card->u.f.dlci_to_dev_map, 0, sizeof(card->u.f.dlci_to_dev_map));
/* Configure adapter firmware */
-
+
u.cfg.mtu = conf->mtu;
u.cfg.kbps = conf->bps / 1000;
@@ -546,9 +676,7 @@
(void*)(buf_info->rse_base +
(buf_info->rse_num - 1) * sizeof(fr_rx_buf_ctl_t) +
card->hw.dpmbase);
- }
-
- else {
+ }else{
buf_info = (void*)(card->hw.dpmbase + FR508_RXBC_OFFS);
card->rxmb = (void*)(buf_info->rse_next -
@@ -582,6 +710,8 @@
card->wandev.state = WAN_DISCONNECTED;
card->wandev.ttl = conf->ttl;
card->wandev.udp_port = conf->udp_port;
+ card->disable_comm = &disable_comm;
+ card->u.f.arp_dev = NULL;
/* Intialize global statistics for a card */
init_global_statistics( card );
@@ -593,11 +723,13 @@
card->intr_mode = INTR_TEST_MODE;
err = intr_test( card );
+ printk(KERN_INFO "%s: End of Interrupt Test rc=0x%x count=%i\n",
+ card->devname,err,Intr_test_counter);
+
if (err || (Intr_test_counter < MAX_INTR_TEST_COUNTER)) {
- printk(
- "%s: Interrupt Test Failed, Counter: %i\n",
+ printk(KERN_ERR "%s: Interrupt Test Failed, Counter: %i\n",
card->devname, Intr_test_counter);
- printk( "Please choose another interrupt\n");
+ printk(KERN_ERR "Please choose another interrupt\n");
err = -EIO;
return err;
}
@@ -606,6 +738,32 @@
card->devname, Intr_test_counter);
+ /* Apr 28 2000. Nenad Corbic
+ * Enable commnunications here, not in if_open or new_if, since
+ * interfaces come down when the link is disconnected.
+ */
+
+ /* If you enable comms and then set ints, you get a Tx int as you
+ * perform the SET_INT_TRIGGERS command. So, we only set int
+ * triggers and then adjust the interrupt mask (to disable Tx ints)
+ * before enabling comms.
+ */
+ if (fr_set_intr_mode(card, (FR_INTR_RXRDY | FR_INTR_TXRDY |
+ FR_INTR_DLC | FR_INTR_TIMER | FR_INTR_TX_MULT_DLCIs) ,
+ card->wandev.mtu, 0)) {
+ return -EIO;
+ }
+
+ flags->imask &= ~(FR_INTR_TXRDY | FR_INTR_TIMER);
+
+ if (fr_comm_enable(card)) {
+ return -EIO;
+ }
+ wanpipe_set_state(card, WAN_CONNECTED);
+ spin_lock_init(&card->u.f.if_send_lock);
+
+ printk(KERN_INFO "\n");
+
return 0;
}
@@ -627,9 +785,6 @@
if (wandev->state == WAN_UNCONFIGURED)
return -ENODEV;
- if (test_bit(1, (void*)&wandev->critical))
- return -EAGAIN;
-
card = wandev->private;
flags = card->flags;
@@ -646,6 +801,7 @@
return -EAGAIN;
}
}
+
return 0;
}
@@ -661,16 +817,17 @@
* Return: 0 o.k.
* < 0 failure (channel will not be created)
*/
-static int new_if (wan_device_t* wandev, struct net_device* dev, wanif_conf_t* conf)
+static int new_if (wan_device_t* wandev, netdevice_t* dev, wanif_conf_t* conf)
{
sdla_t* card = wandev->private;
fr_channel_t* chan;
int dlci = 0;
int err = 0;
+
if ((conf->name[0] == '\0') || (strlen(conf->name) > WAN_IFNAME_SZ)) {
- printk(KERN_INFO "%s: invalid interface name!\n",
+ printk(KERN_INFO "%s: Invalid interface name!\n",
card->devname);
return -EINVAL;
}
@@ -684,7 +841,7 @@
memset(chan, 0, sizeof(fr_channel_t));
strcpy(chan->name, conf->name);
chan->card = card;
-
+
/* verify media address */
if (is_digit(conf->addr[0])) {
@@ -697,36 +854,89 @@
} else {
printk(KERN_ERR
- "%s: invalid DLCI %u on interface %s!\n",
+ "%s: Invalid DLCI %u on interface %s!\n",
wandev->name, dlci, chan->name);
err = -EINVAL;
}
} else {
printk(KERN_ERR
- "%s: invalid media address on interface %s!\n",
+ "%s: Invalid media address on interface %s!\n",
wandev->name, chan->name);
err = -EINVAL;
}
- /* Setup wanpipe as a router (WANPIPE) or as an API */
- if(strcmp(conf->usedby, "WANPIPE") == 0){
- printk(KERN_INFO "%s: Running in WANPIPE mode %s\n",
- wandev->name, chan->name);
- chan->usedby = WANPIPE;
+ if ((chan->true_if_encoding = conf->true_if_encoding) == WANOPT_YES){
+ printk(KERN_INFO
+ "%s: Enabling, true interface type encoding.\n",
+ card->devname);
+ }
+
- } else if(strcmp(conf->usedby, "API") == 0){
-#ifdef FRAME_RELAY_API
- chan->usedby = API;
- printk(KERN_INFO "%s: Running in API mode %s\n",
- wandev->name, chan->name);
+ /* Setup wanpipe as a router (WANPIPE) even if it is
+ * a bridged DLCI, or as an API
+ */
+ if (strcmp(conf->usedby, "WANPIPE") == 0 ||
+ strcmp(conf->usedby, "BRIDGE") == 0 ||
+ strcmp(conf->usedby, "BRIDGE_N") == 0){
+
+ if(strcmp(conf->usedby, "WANPIPE") == 0){
+ chan->common.usedby = WANPIPE;
+
+ printk(KERN_INFO "%s: Running in WANPIPE mode.\n",
+ card->devname);
+
+ }else if(strcmp(conf->usedby, "BRIDGE") == 0){
+
+ chan->common.usedby = BRIDGE;
+
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
+ printk(KERN_INFO "%s: Running in WANPIPE (BRIDGE) mode.\n",
+ card->devname);
+#else
+ printk(KERN_INFO "%s: WANPIPE Bridging mode not supported in 2.0.X kernels.\n",
+ card->devname);
+ err = -EPROTONOSUPPORT;
+#endif
+ }else if( strcmp(conf->usedby, "BRIDGE_N") == 0 ){
+
+ chan->common.usedby = BRIDGE_NODE;
+
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
+ printk(KERN_INFO "%s: Running in WANPIPE (BRIDGE_NODE) mode.\n",
+ card->devname);
#else
- printk(KERN_INFO "%s: API Mode is not supported !\n",
+ printk(KERN_INFO "%s: WANPIPE Bridging mode not supported in 2.0.X kernels.\n",
+ card->devname);
+ err = -EPROTONOSUPPORT;
+#endif
+ }
+
+ if (!err){
+ /* Dynamic interface configuration option.
+ * On disconnect, if the options is selected,
+ * the interface will be brought down */
+ if (conf->if_down == WANOPT_YES){
+ set_bit(DYN_OPT_ON,&chan->interface_down);
+ printk(KERN_INFO
+ "%s: Dynamic interface configuration enabled.\n",
+ card->devname);
+ }
+ }
+
+ } else if(strcmp(conf->usedby, "API") == 0){
+
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
+ chan->common.usedby = API;
+ printk(KERN_INFO "%s: Running in API mode.\n",
wandev->name);
- printk(KERN_INFO
- "%s: API patch can be obtained from Sangoma Tech.\n",
- wandev->name);
+#else
+ printk(KERN_INFO "%s: The API Mode is not supported for"
+ "kernels lower than 2.2.X !\n",
+ wandev->name);
+ printk(KERN_INFO "%s: Please upgrade to a 2.2.X kernel for the API support\n",
+ wandev->name);
err = -EINVAL;
#endif
}
@@ -737,8 +947,6 @@
return err;
}
- card->u.f.dlci_to_dev_map[dlci] = dev;
-
/* place cir,be,bc and other channel specific information into the
* chan structure
*/
@@ -774,20 +982,24 @@
chan->mc = conf->mc;
- /* FIXME: ARP is not supported by this frame relay verson */
if (conf->inarp == WANOPT_YES){
- printk(KERN_INFO "%s: ERROR - This version of WANPIPE doesn't support ARPs\n",
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
+ printk(KERN_INFO "%s: Inverse ARP Support Enabled\n",card->devname);
+ chan->inarp = conf->inarp ? INARP_REQUEST : INARP_NONE;
+ chan->inarp_interval = conf->inarp_interval ? conf->inarp_interval : 10;
+#else
+ printk(KERN_INFO "%s: Warning, Inverse ARP Support not available for 2.0.X kernels!\n",
card->devname);
-
- //chan->inarp = conf->inarp ? INARP_REQUEST : INARP_NONE;
- //chan->inarp_interval = conf->inarp_interval ? conf->inarp_interval : 10;
- kfree(chan);
- return -EINVAL;
+ chan->inarp = INARP_NONE;
+ chan->inarp_interval = 10;
+#endif
}else{
+ printk(KERN_INFO "%s: Inverse ARP Support Disabled\n",card->devname);
chan->inarp = INARP_NONE;
chan->inarp_interval = 10;
}
+
chan->dlci_configured = DLCI_NOT_CONFIGURED;
@@ -814,64 +1026,107 @@
chan->transmit_length = 0;
/* prepare network device data space for registration */
- strcpy(dev->name, chan->name);
+#ifdef LINUX_2_4
+ strcpy(dev->name,chan->name);
+#else
+ dev->name = (char *)kmalloc(strlen(chan->name) + 2, GFP_KERNEL);
+ if(dev->name == NULL)
+ {
+ kfree(chan);
+ return -ENOMEM;
+ }
+ sprintf(dev->name, "%s", chan->name);
+#endif
+
dev->init = &if_init;
dev->priv = chan;
-
- /* Enable Interrupts and Communications */
- if (!wandev->new_if_cnt){
- fr508_flags_t* flags = card->flags;
-
- wandev->new_if_cnt++;
-
- /*
- If you enable comms and then set ints, you get a Tx int as you
- perform the SET_INT_TRIGGERS command. So, we only set int
- triggers and then adjust the interrupt mask (to disable Tx ints)
- before enabling comms.
- */
- if (fr_set_intr_mode(card, (FR_INTR_RXRDY | FR_INTR_TXRDY |
- FR_INTR_DLC | FR_INTR_TIMER | FR_INTR_TX_MULT_DLCIs) ,
- card->wandev.mtu, 0)) {
- kfree(chan);
- return -EIO;
- }
-
- flags->imask &= ~(FR_INTR_TXRDY | FR_INTR_TIMER);
-
- if (fr_comm_enable(card)) {
- kfree(chan);
- return -EIO;
- }
- wanpipe_set_state(card, WAN_CONNECTED);
+ /* Initialize FR Polling Task Queue
+ * We need a poll routine for each network
+ * interface.
+ */
+#ifndef LINUX_2_4
+ chan->fr_poll_task.next = NULL;
+#endif
+ chan->fr_poll_task.sync = 0;
+ chan->fr_poll_task.routine = (void *)(void *)fr_poll;
+ chan->fr_poll_task.data = dev;
+
+ init_timer(&chan->fr_arp_timer);
+ chan->fr_arp_timer.data=(unsigned long)dev;
+ chan->fr_arp_timer.function = fr_arp;
+
+ wandev->new_if_cnt++;
+
+ /* Tells us that if this interface is a
+ * gateway or not */
+ if ((chan->gateway = conf->gateway) == WANOPT_YES){
+ printk(KERN_INFO "%s: Interface %s is set as a gateway.\n",
+ card->devname,dev->name);
+ }
+
+ /* M. Grant Patch Apr 28 2000
+ * Disallow duplicate dlci configurations. */
+ if (card->u.f.dlci_to_dev_map[chan->dlci] != NULL) {
+ kfree(chan);
+ return -EBUSY;
}
+ /* Configure this dlci at a later date, when
+ * the interface comes up. i.e. when if_open()
+ * executes */
+ set_bit(0,&chan->config_dlci);
+
+ printk(KERN_INFO "\n");
+
return 0;
}
/*============================================================================
* Delete logical channel.
*/
-static int del_if (wan_device_t* wandev, struct net_device* dev)
+static int del_if (wan_device_t* wandev, netdevice_t* dev)
{
- sdla_t *card = wandev->private;
+ fr_channel_t* chan = dev->priv;
+ unsigned long smp_flags=0;
- /* Execute shutdown very first time we enter del_if */
+ /* This interface is dead, make sure the
+ * ARP timer is stopped */
+ del_timer(&chan->fr_arp_timer);
+
+ /* If we are a NODE, we must unconfigure this DLCI
+ * Trigger an unconfigure command that will
+ * be executed in timer interrupt. We must wait
+ * for the command to complete. */
+ trigger_unconfig_fr(dev);
+
+ lock_adapter_irq(&wandev->lock, &smp_flags);
+ wandev->new_if_cnt--;
+ unlock_adapter_irq(&wandev->lock, &smp_flags);
- if (!wandev->del_if_cnt) {
- wandev->del_if_cnt++;
- wanpipe_set_state(card, WAN_DISCONNECTED);
- fr_set_intr_mode(card, 0, 0, 0);
- fr_comm_disable(card);
- }
+ return 0;
+}
- if (dev->priv) {
- kfree(dev->priv);
- dev->priv = NULL;
- }
- return 0;
+/*=====================================================================
+ * disable_comm
+ *
+ * Description:
+ * Disable communications.
+ * This code runs in shutdown (sdlamain.c)
+ * under critical flag. Therefore it is not
+ * necessary to set a critical flag here
+ *
+ * Usage:
+ * Commnunications are disabled only on a card
+ * shutdown.
+ */
+
+static void disable_comm (sdla_t *card)
+{
+ printk(KERN_INFO "%s: Disabling Communications!\n",
+ card->devname);
+ fr_comm_disable(card);
}
/****** WANPIPE-specific entry points ***************************************/
@@ -886,6 +1141,8 @@
int err, len;
fr_cmd_t cmd;
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
+
if(copy_from_user((void*)&cmd, u_cmd, sizeof(cmd)))
return -EFAULT;
@@ -916,6 +1173,43 @@
return -EFAULT;
return 0;
+#else
+ if (!u_cmd || verify_area(VERIFY_WRITE, u_cmd, sizeof(fr_cmd_t)))
+ return -EFAULT;
+
+ memcpy_fromfs((void*)&cmd, u_cmd, sizeof(cmd));
+
+ if (cmd.length) {
+
+ if (!u_data || verify_area(VERIFY_READ, u_data, cmd.length))
+ return -EFAULT;
+ }
+
+ /* execute command */
+ do
+ {
+ memcpy(&mbox->cmd, &cmd, sizeof(cmd));
+
+ if (cmd.length)
+ memcpy_fromfs((void*)&mbox->data, u_data, cmd.length);
+
+ if (sdla_exec(mbox))
+ err = mbox->cmd.result;
+
+ else return -EIO;
+ } while (err && retry-- && fr_event(card, err, mbox));
+
+ /* return result */
+ memcpy_tofs(u_cmd, (void*)&mbox->cmd, sizeof(fr_cmd_t));
+ len = mbox->cmd.length;
+
+ if (len && u_data && !verify_area(VERIFY_WRITE, u_data, len))
+ memcpy_tofs(u_data, (void*)&mbox->data, len);
+
+ return 0;
+
+#endif
+
}
/****** Network Device Interface ********************************************/
@@ -927,44 +1221,79 @@
* interface registration. Returning anything but zero will fail interface
* registration.
*/
-static int if_init (struct net_device* dev)
+static int if_init (netdevice_t* dev)
{
fr_channel_t* chan = dev->priv;
sdla_t* card = chan->card;
wan_device_t* wandev = &card->wandev;
+#ifdef LINUX_2_0
+ int i;
+#endif
/* Initialize device driver entry points */
dev->open = &if_open;
dev->stop = &if_close;
- dev->hard_header = &if_header;
+ dev->hard_header = NULL;
dev->rebuild_header = &if_rebuild_hdr;
dev->hard_start_xmit = &if_send;
dev->get_stats = &if_stats;
+#ifdef LINUX_2_4
dev->tx_timeout = &if_tx_timeout;
dev->watchdog_timeo = TX_TIMEOUT;
+#endif
+
+ if (chan->common.usedby == WANPIPE || chan->common.usedby == API){
+#ifdef LINUX_2_0
+ dev->family = AF_INET;
+#endif
+ /* Initialize media-specific parameters */
+ if (chan->true_if_encoding){
+ dev->type = ARPHRD_DLCI; /* This breaks tcpdump */
+ }else{
+ dev->type = ARPHRD_PPP; /* ARP h/w type */
+ }
+
+ dev->flags |= IFF_POINTOPOINT;
+ dev->flags |= IFF_NOARP;
- /* Initialize media-specific parameters */
- dev->type = ARPHRD_DLCI; /* ARP h/w type */
- dev->flags |= IFF_POINTOPOINT;
-
- /* Enable Multicast addressing */
- if (chan->mc == WANOPT_YES){
- dev->flags |= IFF_MULTICAST;
- }
+ /* Enable Multicast addressing */
+ if (chan->mc == WANOPT_YES){
+ dev->flags |= IFF_MULTICAST;
+ }
- dev->mtu = wandev->mtu - FR_HEADER_LEN;
- /* For an API, the maximum number of bytes that the stack will pass
- to the driver is (dev->mtu + dev->hard_header_len). So, adjust the
- mtu so that a frame of maximum size can be transmitted by the API.
- */
- if(chan->usedby == API) {
- dev->mtu += (sizeof(api_tx_hdr_t) - FR_HEADER_LEN);
- }
-
- dev->hard_header_len = FR_HEADER_LEN;/* media header length */
- dev->addr_len = 2; /* hardware address length */
- *(unsigned short*)dev->dev_addr = htons(chan->dlci);
+ dev->mtu = wandev->mtu - FR_HEADER_LEN;
+ /* For an API, the maximum number of bytes that the stack will pass
+ to the driver is (dev->mtu + dev->hard_header_len). So, adjust the
+ mtu so that a frame of maximum size can be transmitted by the API.
+ */
+ if(chan->common.usedby == API) {
+ dev->mtu += (sizeof(api_tx_hdr_t) - FR_HEADER_LEN);
+ }
+
+ dev->hard_header_len = FR_HEADER_LEN;/* media header length */
+ dev->addr_len = 2; /* hardware address length */
+ *(unsigned short*)dev->dev_addr = htons(chan->dlci);
+
+ /* Set transmit buffer queue length */
+ dev->tx_queue_len = 100;
+
+ /* Initialize socket buffers */
+#if !defined(LINUX_2_1) && !defined(LINUX_2_4)
+ for (i = 0; i < DEV_NUMBUFFS; ++i)
+ skb_queue_head_init(&dev->buffs[i]);
+#endif
+ }else{
+ /* Setup the interface for Bridging */
+ int hw_addr=0;
+ ether_setup(dev);
+
+ /* Use a random number to generate the MAC address */
+ memcpy(dev->dev_addr, "\xFE\xFC\x00\x00\x00\x00", 6);
+ get_random_bytes(&hw_addr, sizeof(hw_addr));
+ *(int *)(dev->dev_addr + 2) += hw_addr;
+ }
+
/* Initialize hardware parameters (just for reference) */
dev->irq = wandev->irq;
dev->dma = wandev->dma;
@@ -972,13 +1301,6 @@
dev->mem_start = wandev->maddr;
dev->mem_end = wandev->maddr + wandev->msize - 1;
- /* Set transmit buffer queue length */
- dev->tx_queue_len = 100;
-
- /* Initialize socket buffers */
- dev_init_buffers(dev);
-
- set_chan_state(dev, WAN_DISCONNECTED);
return 0;
}
@@ -989,60 +1311,51 @@
*
* Return 0 if O.k. or errno.
*/
-static int if_open (struct net_device* dev)
+static int if_open (netdevice_t* dev)
{
fr_channel_t* chan = dev->priv;
sdla_t* card = chan->card;
int err = 0;
struct timeval tv;
- if (netif_running(dev))
- return -EBUSY; /* only one open is allowed */
-
- if (test_and_set_bit(1, (void*)&card->wandev.critical))
- return -EAGAIN;
+ if (is_dev_running(dev))
+ return -EBUSY;
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
+ /* Initialize the task queue */
+ chan->tq_working=0;
- /* If signalling is set to NO, then setup
- * DLCI addresses right away. Don't have to wait for
- * link to connect.
- */
- if (card->wandev.signalling == WANOPT_NO){
- printk(KERN_INFO "%s: Signalling set to NO: Mapping DLCI's\n",
- card->wandev.name);
- if (fr_init_dlci(card,chan)){
- return -EAGAIN;
- }
- }
-
- if (card->wandev.station == WANOPT_CPE) {
-
- /* CPE: issue full status enquiry */
- fr_issue_isf(card, FR_ISF_FSE);
-
- } else { /* FR switch: activate DLCI(s) */
-
- /* For Switch emulation we have to ADD and ACTIVATE
- * the DLCI(s) that were configured with the SET_DLCI_
- * CONFIGURATION command. Add and Activate will fail if
- * DLCI specified is not included in the list.
- *
- * Also If_open is called once for each interface. But
- * it does not get in here for all the interface. So
- * we have to pass the entire list of DLCI(s) to add
- * activate routines.
- */
-
- fr_add_dlci(card, chan->dlci);
- fr_activate_dlci(card, chan->dlci);
- }
+#ifndef LINUX_2_4
+ chan->common.wanpipe_task.next = NULL;
+#endif
+ chan->common.wanpipe_task.sync = 0;
+ chan->common.wanpipe_task.routine = (void *)(void *)fr_bh;
+ chan->common.wanpipe_task.data = dev;
+
+ /* Allocate and initialize BH circular buffer */
+ chan->bh_head = kmalloc((sizeof(bh_data_t)*MAX_BH_BUFF),GFP_ATOMIC);
+ memset(chan->bh_head,0,(sizeof(bh_data_t)*MAX_BH_BUFF));
+ atomic_set(&chan->bh_buff_used, 0);
+#endif
+#ifdef LINUX_2_4
netif_start_queue(dev);
+#else
+ dev->interrupt = 0;
+ dev->tbusy = 0;
+ dev->start = 1;
+#endif
+
wanpipe_open(card);
- update_chan_state(dev);
do_gettimeofday( &tv );
chan->router_start_time = tv.tv_sec;
- clear_bit(1, (void*)&card->wandev.critical);
+
+ if (test_bit(0,&chan->config_dlci)){
+ trigger_config_fr (card);
+ }else if (chan->inarp == INARP_REQUEST){
+ trigger_fr_arp(dev);
+ }
+
return err;
}
@@ -1051,61 +1364,42 @@
* o if this is the last open, then disable communications and interrupts.
* o reset flags.
*/
-static int if_close (struct net_device* dev)
+static int if_close (netdevice_t* dev)
{
fr_channel_t* chan = dev->priv;
sdla_t* card = chan->card;
- if (test_and_set_bit(1, (void*)&card->wandev.critical))
- return -EAGAIN;
+ if (chan->inarp == INARP_CONFIGURED) {
+ chan->inarp = INARP_REQUEST;
+ }
- netif_stop_queue(dev);
+ stop_net_queue(dev);
+#ifndef LINUX_2_4
+ dev->start=0;
+#endif
wanpipe_close(card);
- if (card->wandev.station == WANOPT_NODE) {
- fr_delete_dlci (card,chan->dlci);
- }
- clear_bit(1, (void*)&card->wandev.critical);
return 0;
}
/*============================================================================
- * Build media header.
- * o encapsulate packet according to encapsulation type.
- *
- * The trick here is to put packet type (Ethertype) into 'protocol' field of
- * the socket buffer, so that we don't forget it. If encapsulation fails,
- * set skb->protocol to 0 and discard packet later.
- *
- * Return: media header length.
- */
-static int if_header (struct sk_buff* skb, struct net_device* dev,
- unsigned short type, void* daddr, void* saddr, unsigned len)
-{
- int hdr_len = 0;
-
- skb->protocol = type;
- hdr_len = wanrouter_encapsulate(skb, dev);
-
- if (hdr_len < 0) {
- hdr_len = 0;
- skb->protocol = 0;
- }
- skb_push(skb, 1);
- skb->data[0] = Q922_UI;
- ++hdr_len;
- return hdr_len;
-}
-
-/*============================================================================
* Re-build media header.
*
* Return: 1 physical address resolved.
* 0 physical address not resolved
*/
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
static int if_rebuild_hdr (struct sk_buff* skb)
{
- struct net_device *dev = skb->dev;
+#else
+static int if_rebuild_hdr (void* hdr, netdevice_t* dev, unsigned long raddr,
+ struct sk_buff* skb)
+{
+#endif
+
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
+ netdevice_t *dev = skb->dev;
+#endif
fr_channel_t* chan = dev->priv;
sdla_t* card = chan->card;
@@ -1114,13 +1408,14 @@
return 1;
}
-
+#ifdef LINUX_2_4
/*============================================================================
* Handle transmit timeout event from netif watchdog
*/
-static void if_tx_timeout (struct net_device *dev)
+static void if_tx_timeout (netdevice_t *dev)
{
fr_channel_t* chan = dev->priv;
+ sdla_t *card = chan->card;
/* If our device stays busy for at least 5 seconds then we will
* kick start the device by making dev->tbusy = 0. We expect
@@ -1131,12 +1426,13 @@
chan->drvstats_if_send.if_send_tbusy++;
++chan->ifstats.collisions;
- printk (KERN_INFO "%s: Transmit timed out\n", chan->name);
+ printk (KERN_INFO "%s: Transmit timed out on %s\n",
+ card->devname, dev->name);
chan->drvstats_if_send.if_send_tbusy_timeout++;
netif_wake_queue (dev);
}
-
+#endif
/*============================================================================
* Send a packet on a network interface.
@@ -1154,23 +1450,28 @@
* Notes:
* 1. This routine is called either by the protocol stack or by the "net
* bottom half" (with interrupts enabled).
- * 2. Setting tbusy flag will inhibit further transmit requests from the
- * protocol stack and can be used for flow control with protocol layer.
+ *
+ * 2. Using the start_net_queue() and stop_net_queue() MACROS
+ * will inhibit further transmit requests from the protocol stack
+ * and can be used for flow control with protocol layer.
*/
-static int if_send (struct sk_buff* skb, struct net_device* dev)
+static int if_send (struct sk_buff* skb, netdevice_t* dev)
{
fr_channel_t* chan = dev->priv;
sdla_t* card = chan->card;
int err;
unsigned char *sendpacket;
fr508_flags_t* adptr_flags = card->flags;
- int udp_type, send_data;
+ int udp_type, delay_tx_queued=0;
unsigned long smp_flags=0;
- void* data;
- unsigned len;
+ unsigned char attr = 0;
chan->drvstats_if_send.if_send_entry++;
+#ifdef LINUX_2_4
+ netif_stop_queue(dev);
+#endif
+
if (skb == NULL) {
/* if we get here, some higher layer thinks we've missed an
* tx-done interrupt.
@@ -1178,7 +1479,19 @@
printk(KERN_INFO "%s: interface %s got kicked!\n",
card->devname, dev->name);
chan->drvstats_if_send.if_send_skb_null ++;
- netif_wake_queue(dev);
+
+ wake_net_dev(dev);
+ return 0;
+ }
+
+ /* If a peripheral task is running just drop packets */
+ if (test_bit(PERI_CRIT, &card->wandev.critical)){
+
+ printk(KERN_INFO "%s: Critical in if_send(): Peripheral running!\n",
+ card->devname);
+
+ wan_dev_kfree_skb(skb,FREE_WRITE);
+ start_net_queue(dev);
return 0;
}
@@ -1187,23 +1500,58 @@
ensure that the transmit interrupt does not reset the 'tbusy' flag
just before we set it, as this will result in a "transmit timeout".
*/
- set_bit(2, (void*)&card->wandev.critical);
+ set_bit(SEND_TXIRQ_CRIT, (void*)&card->wandev.critical);
if(chan->transmit_length) {
- netif_stop_queue(dev);
- chan->tick_counter = jiffies;
- clear_bit(2, (void*)&card->wandev.critical);
+ stop_net_queue(dev);
+ chan->tick_counter = jiffies;
+ clear_bit(SEND_TXIRQ_CRIT, (void*)&card->wandev.critical);
return 1;
}
- clear_bit(2, (void*)&card->wandev.critical);
-
- data = skb->data;
+ clear_bit(SEND_TXIRQ_CRIT, (void*)&card->wandev.critical);
+
+#ifndef LINUX_2_4
+ if (dev->tbusy) {
+
+ /* If our device stays busy for at least 5 seconds then we will
+ * kick start the device by making dev->tbusy = 0. We expect
+ * that our device never stays busy more than 5 seconds. So this
+ * is only used as a last resort.
+ */
+
+ chan->drvstats_if_send.if_send_tbusy++;
+ ++chan->ifstats.collisions;
+
+ if ((jiffies - chan->tick_counter) < (5 * HZ)) {
+ return 1;
+ }
+
+ printk(KERN_INFO "%s: Transmit timed out on %s\n",
+ card->devname, chan->name);
+ chan->drvstats_if_send.if_send_tbusy_timeout ++;
+ dev->tbusy = 0;
+ }
+#endif
+
+
+ /* Move the if_header() code to here. By inserting frame
+ * relay header in if_header() we would break the
+ * tcpdump and other packet sniffers */
+ chan->fr_header_len = setup_fr_header(&skb,dev,chan->common.usedby);
+ if (chan->fr_header_len < 0 ){
+ ++chan->ifstats.tx_dropped;
+ ++card->wandev.stats.tx_dropped;
+
+ wan_dev_kfree_skb(skb,FREE_WRITE);
+ start_net_queue(dev);
+ return 0;
+ }
+
sendpacket = skb->data;
- len = skb->len;
udp_type = udp_pkt_type(skb, card);
if(udp_type != UDP_INVALID_TYPE) {
- if(store_udp_mgmt_pkt(udp_type, UDP_PKT_FRM_STACK, card, skb,
+ if(store_udp_mgmt_pkt(udp_type, UDP_PKT_FRM_STACK, card, skb,
chan->dlci)) {
adptr_flags->imask |= FR_INTR_TIMER;
if (udp_type == UDP_FPIPE_TYPE){
@@ -1211,61 +1559,92 @@
if_send_PIPE_request ++;
}
}
+ start_net_queue(dev);
return 0;
}
- if((chan->usedby == API) && (len <= sizeof(api_tx_hdr_t))) {
- //FIXME: increment some error statistic
- dev_kfree_skb(skb);
- return 0;
- }
-
//FIXME: can we do better than sendpacket[2]?
- if ((chan->usedby == WANPIPE) && (sendpacket[2] == 0x45)) {
+ if ((chan->common.usedby == WANPIPE) && (sendpacket[2] == 0x45)) {
+
/* check to see if the source IP address is a broadcast or */
/* multicast IP address */
- if(chk_bcast_mcast_addr(card, dev, skb))
- return 0;
+ if(chk_bcast_mcast_addr(card, dev, skb)){
+ ++chan->ifstats.tx_dropped;
+ ++card->wandev.stats.tx_dropped;
+ wan_dev_kfree_skb(skb, FREE_WRITE);
+ start_net_queue(dev);
+ return 0;
+ }
}
- /* Lock the 508 card: SMP Supported */
+
+ /* Lock the S514/S508 card: SMP Supported */
s508_s514_lock(card,&smp_flags);
- if (test_and_set_bit(0, (void*)&card->wandev.critical)) {
+ if (test_and_set_bit(SEND_CRIT, (void*)&card->wandev.critical)) {
+
chan->drvstats_if_send.if_send_critical_non_ISR ++;
chan->ifstats.tx_dropped ++;
- printk(KERN_INFO "%s Critical in IF_SEND %02X\n",
- card->devname, card->wandev.critical);
- dev_kfree_skb(skb);
- /* Unlock the 508 card */
- s508_s514_unlock(card,&smp_flags);
- return 0;
+ printk(KERN_INFO "%s Critical in IF_SEND: if_send() already running!\n",
+ card->devname);
+ goto if_send_start_and_exit;
}
-
- if (card->wandev.state != WAN_CONNECTED) {
- chan->drvstats_if_send.if_send_wan_disconnected ++;
- ++chan->ifstats.tx_dropped;
- ++card->wandev.stats.tx_dropped;
- } else if (chan->state != WAN_CONNECTED) {
- chan->drvstats_if_send.if_send_dlci_disconnected ++;
- /* Critical area on 514, since disabl_irq is not used
- * thus, interrupt would execute a command at
- * the same time as if_send.
- */
- set_bit(1, (void*)&card->wandev.critical);
- update_chan_state(dev);
- clear_bit(1, (void*)&card->wandev.critical);
- ++chan->ifstats.tx_dropped;
+ /* API packet check: minimum packet size must be greater than
+ * 16 byte API header */
+ if((chan->common.usedby == API) && (skb->len <= sizeof(api_tx_hdr_t))) {
+ ++chan->ifstats.tx_dropped;
+ ++card->wandev.stats.tx_dropped;
+
+
+ goto if_send_start_and_exit;
+
+ }else{
+ /* During API transmission, get rid of the API header */
+ if (chan->common.usedby == API) {
+ api_tx_hdr_t* api_tx_hdr;
+ api_tx_hdr = (api_tx_hdr_t*)&skb->data[0x00];
+ attr = api_tx_hdr->attr;
+ skb_pull(skb,sizeof(api_tx_hdr_t));
+ }
+ }
+
+ if (card->wandev.state != WAN_CONNECTED) {
+ chan->drvstats_if_send.if_send_wan_disconnected ++;
+ ++chan->ifstats.tx_dropped;
++card->wandev.stats.tx_dropped;
+
+ } else if (chan->common.state != WAN_CONNECTED) {
+ chan->drvstats_if_send.if_send_dlci_disconnected ++;
+ /* Update the DLCI state in timer interrupt */
+ card->u.f.timer_int_enabled |= TMR_INT_ENABLED_UPDATE_STATE;
+ adptr_flags->imask |= FR_INTR_TIMER;
+
+ ++chan->ifstats.tx_dropped;
+ ++card->wandev.stats.tx_dropped;
+
} else if (!is_tx_ready(card, chan)) {
- setup_for_delayed_transmit(dev, data, len);
+ /* No tx buffers available, store for delayed transmit */
+ if (!setup_for_delayed_transmit(dev, skb)){
+ set_bit(1,&delay_tx_queued);
+ }
chan->drvstats_if_send.if_send_no_bfrs++;
- } else {
- send_data = 1;
+
+ } else if (!skb->protocol) {
+ /* No protocols drop packet */
+ chan->drvstats_if_send.if_send_protocol_error ++;
+ ++card->wandev.stats.tx_errors;
+
+ } else if (test_bit(ARP_CRIT,&card->wandev.critical)){
+ /* We are trying to send an ARP Packet, block IP data until
+ * ARP is sent */
+ ++chan->ifstats.tx_dropped;
+ ++card->wandev.stats.tx_dropped;
+
+ } else {
//FIXME: IPX is not implemented in this version of Frame Relay ?
- if((chan->usedby == WANPIPE) &&
+ if((chan->common.usedby == WANPIPE) &&
sendpacket[1] == 0x00 &&
sendpacket[2] == 0x80 &&
sendpacket[6] == 0x81 &&
@@ -1279,32 +1658,28 @@
printk(KERN_INFO
"%s: WARNING: Unsupported IPX data in send, packet dropped\n",
card->devname);
- send_data = 0;
- }
- }
-
- if (send_data) {
- unsigned char attr = 0;
-
- /* For an API transmission, get rid of the API header */
- if (chan->usedby == API) {
- api_tx_hdr_t* api_tx_hdr;
- api_tx_hdr = (api_tx_hdr_t*)&skb->data[0x00];
- attr = api_tx_hdr->attr;
- data += sizeof(api_tx_hdr_t);
- len -= sizeof(api_tx_hdr_t);
}
-
- err = fr_send(card, chan->dlci, attr, len, data);
+
+ }else{
+ err = fr_send_data_header(card, chan->dlci, attr, skb->len, skb->data, chan->fr_header_len);
if (err) {
switch(err) {
case FRRES_CIR_OVERFLOW:
case FRRES_BUFFER_OVERFLOW:
- setup_for_delayed_transmit(dev, data,
- len);
+ if (!setup_for_delayed_transmit(dev, skb)){
+ set_bit(1,&delay_tx_queued);
+ }
chan->drvstats_if_send.
if_send_adptr_bfrs_full ++;
- break;
+ break;
+
+ case FRRES_TOO_LONG:
+ if (net_ratelimit()){
+ printk(KERN_INFO
+ "%s: Error: Frame too long, transmission failed %i\n",
+ card->devname, (unsigned int)skb->len);
+ }
+ /* Drop down to default */
default:
chan->drvstats_if_send.
if_send_dlci_disconnected ++;
@@ -1317,20 +1692,37 @@
if_send_bfr_passed_to_adptr++;
++chan->ifstats.tx_packets;
++card->wandev.stats.tx_packets;
- chan->ifstats.tx_bytes += len;
- card->wandev.stats.tx_bytes += len;
+
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
+ chan->ifstats.tx_bytes += skb->len;
+ card->wandev.stats.tx_bytes += skb->len;
+#endif
+#ifdef LINUX_2_4
+ dev->trans_start = jiffies;
+#endif
}
}
}
- if (!netif_queue_stopped(dev))
- dev_kfree_skb(skb);
+if_send_start_and_exit:
+
+ start_net_queue(dev);
+
+ /* If we queued the packet for transmission, we must not
+ * deallocate it. The packet is unlinked from the IP stack
+ * not copied. Therefore, we must keep the original packet */
+ if (!test_bit(1,&delay_tx_queued)) {
+ wan_dev_kfree_skb(skb, FREE_WRITE);
+ }else{
+ adptr_flags->imask |= FR_INTR_TXRDY;
+ card->u.f.tx_interrupts_pending ++;
+ }
- clear_bit(0, (void*)&card->wandev.critical);
+ clear_bit(SEND_CRIT, (void*)&card->wandev.critical);
s508_s514_unlock(card,&smp_flags);
- return (netif_queue_stopped(dev));
+ return 0;
}
@@ -1339,33 +1731,49 @@
* Setup so that a frame can be transmitted on the occurence of a transmit
* interrupt.
*/
-static void setup_for_delayed_transmit (struct net_device* dev, void* buf,
- unsigned len)
+static int setup_for_delayed_transmit (netdevice_t* dev, struct sk_buff *skb)
{
fr_channel_t* chan = dev->priv;
sdla_t* card = chan->card;
- fr508_flags_t* adptr_flags = card->flags;
- fr_dlci_interface_t* dlci_interface = chan->dlci_int_interface;
+ fr_dlci_interface_t* dlci_interface;
+ int len = skb->len;
+
+ /* Check that the dlci is properly configured,
+ * before using tx interrupt */
+ if (!chan->dlci_int_interface){
+ if (net_ratelimit()){
+ printk(KERN_INFO
+ "%s: ERROR on DLCI %i: Not configured properly !\n",
+ card->devname, chan->dlci);
+ printk(KERN_INFO "%s: Please contact Sangoma Technologies\n",
+ card->devname);
+ }
+ return 1;
+ }
+
+ dlci_interface = chan->dlci_int_interface;
if(chan->transmit_length) {
printk(KERN_INFO "%s: Big mess in setup_for_del...\n",
card->devname);
- return;
+ return 1;
}
if(len > FR_MAX_NO_DATA_BYTES_IN_FRAME) {
//FIXME: increment some statistic */
- return;
+ return 1;
}
+ skb_unlink(skb);
+
chan->transmit_length = len;
- memcpy(chan->transmit_buffer, buf, len);
-
+ chan->delay_skb = skb;
+
dlci_interface->gen_interrupt |= FR_INTR_TXRDY;
dlci_interface->packet_length = len;
- adptr_flags->imask |= FR_INTR_TXRDY;
- card->u.f.tx_interrupts_pending ++;
+ /* Turn on TX interrupt at the end of if_send */
+ return 0;
}
@@ -1375,18 +1783,21 @@
* Return 0 if not broadcast/multicast address, otherwise return 1.
*/
-static int chk_bcast_mcast_addr(sdla_t *card, struct net_device* dev,
+static int chk_bcast_mcast_addr(sdla_t *card, netdevice_t* dev,
struct sk_buff *skb)
{
u32 src_ip_addr;
u32 broadcast_ip_addr = 0;
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
struct in_device *in_dev;
+#endif
fr_channel_t* chan = dev->priv;
/* read the IP source address from the outgoing packet */
src_ip_addr = *(u32 *)(skb->data + 14);
/* read the IP broadcast address for the device */
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
in_dev = dev->ip_ptr;
if(in_dev != NULL) {
struct in_ifaddr *ifa= in_dev->ifa_list;
@@ -1395,13 +1806,15 @@
else
return 0;
}
+#else
+ broadcast_ip_addr = dev->pa_brdaddr;
+#endif
/* check if the IP Source Address is a Broadcast address */
- if((dev->flags & IFF_BROADCAST) && (src_ip_addr == broadcast_ip_addr)) { printk(KERN_INFO
+ if((dev->flags & IFF_BROADCAST) && (src_ip_addr == broadcast_ip_addr)) {
+ printk(KERN_INFO
"%s: Broadcast Source Address silently discarded\n",
card->devname);
- dev_kfree_skb(skb);
- ++ chan->ifstats.tx_dropped;
return 1;
}
@@ -1411,8 +1824,6 @@
printk(KERN_INFO
"%s: Multicast Source Address silently discarded\n",
card->devname);
- dev_kfree_skb(skb);
- ++ chan->ifstats.tx_dropped;
return 1;
}
@@ -1433,7 +1844,7 @@
fr_udp_pkt_t *fr_udp_pkt = (fr_udp_pkt_t *)data;
/* Set length of packet */
- len = sizeof(fr_encap_hdr_t)+
+ len = //sizeof(fr_encap_hdr_t)+
sizeof(ip_pkt_t)+
sizeof(udp_pkt_t)+
sizeof(wp_mgmt_t)+
@@ -1481,7 +1892,7 @@
fr_udp_pkt->udp_pkt.udp_checksum = 0;
fr_udp_pkt->udp_pkt.udp_checksum =
- calc_checksum(&data[UDP_OFFSET+sizeof(fr_encap_hdr_t)],
+ calc_checksum(&data[UDP_OFFSET/*+sizeof(fr_encap_hdr_t)*/],
udp_length+UDP_OFFSET);
/* fill in IP length */
@@ -1499,7 +1910,7 @@
/* fill in IP checksum */
fr_udp_pkt->ip_pkt.hdr_checksum = 0;
fr_udp_pkt->ip_pkt.hdr_checksum =
- calc_checksum(&data[sizeof(fr_encap_hdr_t)],
+ calc_checksum(&data[/*sizeof(fr_encap_hdr_t)*/0],
sizeof(ip_pkt_t));
return len;
@@ -1588,9 +1999,13 @@
/*============================================================================
* Get ethernet-style interface statistics.
- * Return a pointer to struct net_device_stats.
+ * Return a pointer to struct enet_statistics.
*/
-static struct net_device_stats* if_stats (struct net_device* dev)
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
+static struct net_device_stats *if_stats(netdevice_t *dev)
+#else
+static struct enet_statistics* if_stats (netdevice_t* dev)
+#endif
{
fr_channel_t* chan = dev->priv;
@@ -1603,7 +2018,12 @@
/****** Interrupt Handlers **************************************************/
/*============================================================================
- * S508 frame relay interrupt service routine.
+ * fr_isr: S508 frame relay interrupt service routine.
+ *
+ * Description:
+ * Frame relay main interrupt service route. This
+ * function check the interrupt type and takes
+ * the appropriate action.
*/
static void fr_isr (sdla_t* card)
{
@@ -1613,26 +2033,25 @@
fr_mbox_t* mbox = card->mbox;
/* This flag prevents nesting of interrupts. See sdla_isr() routine
- * in sdlamain.c.
- */
+ * in sdlamain.c. */
card->in_isr = 1;
++card->statistics.isr_entry;
- if(test_bit(1, (void*)&card->wandev.critical)) {
- card->wandev.critical = 0;
- flags->iflag = 0;
- card->in_isr = 0;
- return;
- }
+ /* All peripheral (configuraiton, re-configuration) events
+ * take presidence over the ISR. Thus, retrigger */
+ if (test_bit(PERI_CRIT, (void*)&card->wandev.critical)) {
+ ++card->statistics.isr_already_critical;
+ goto fr_isr_exit;
+ }
+
if(card->hw.type != SDLA_S514) {
- if (test_and_set_bit(0, (void*)&card->wandev.critical)) {
- printk(KERN_INFO "%s: Critical while in ISR (0x%02X)\n",
- card->devname, card->wandev.critical);
+ if (test_bit(SEND_CRIT, (void*)&card->wandev.critical)) {
+ printk(KERN_INFO "%s: Critical while in ISR: If Send Running!\n",
+ card->devname);
++card->statistics.isr_already_critical;
- card->in_isr = 0;
- return;
+ goto fr_isr_exit;
}
}
@@ -1649,12 +2068,12 @@
tx_intr(card);
break;
- case FR_INTR_READY:
+ case FR_INTR_READY:
Intr_test_counter++;
++card->statistics.isr_intr_test;
break;
- case FR_INTR_DLC: /* Event interrupt occurred */
+ case FR_INTR_DLC: /* Event interrupt occured */
mbox->cmd.command = FR_READ_STATUS;
mbox->cmd.length = 0;
err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
@@ -1680,27 +2099,31 @@
break;
}
+fr_isr_exit:
+
card->in_isr = 0;
flags->iflag = 0;
- if(card->hw.type != SDLA_S514)
- clear_bit(0, (void*)&card->wandev.critical);
+ return;
}
-/*============================================================================
- * Receive interrupt handler.
- * When a receive interrupt occurs do the following:
- * 1- Find the structure for the dlci that the interrupt occurred on
- * 2- If it doesn't exist then print appropriate msg and goto step 8.
- * 3- If it exist then copy data to a skb.
- * 4- If skb contains Sangoma UDP data then process them
- * 5- If skb contains IPXWAN data then send IPXWAN reply packets
- * 6- If skb contains Inverse Arp data then send Inv Arp replies
- * 7- If skb contains any other data then decapsulate the packet and
- * send it to the stack.
- * 8- Release the receive element and update receive pointers on the board
+/*===========================================================
+ * rx_intr Receive interrupt handler.
+ *
+ * Description
+ * Upon receiveing an interrupt:
+ * 1. Check that the firmware is in sync with
+ * the driver.
+ * 2. Find an appropriate network interface
+ * based on the received dlci number.
+ * 3. Check that the netowrk interface exists
+ * and that it's setup properly.
+ * 4. Copy the data into an skb buffer.
+ * 5. Check the packet type and take
+ * appropriate acton: UPD, API, ARP or Data.
*/
+
static void rx_intr (sdla_t* card)
{
fr_rx_buf_ctl_t* frbuf = card->rxmb;
@@ -1708,11 +2131,13 @@
fr_channel_t* chan;
char *ptr = &flags->iflag;
struct sk_buff* skb;
- struct net_device* dev;
+ netdevice_t* dev;
void* buf;
unsigned dlci, len, offs, len_incl_hdr;
int i, udp_type;
+
+ /* Check that firmware buffers are in sync */
if (frbuf->flag != 0x01) {
printk(KERN_INFO
@@ -1725,6 +2150,16 @@
printk(KERN_INFO "\n");
++card->statistics.rx_intr_corrupt_rx_bfr;
+
+ /* Bug Fix: Mar 6 2000
+ * If we get a corrupted mailbox, it means that driver
+ * is out of sync with the firmware. There is no recovery.
+ * If we don't turn off all interrupts for this card
+ * the machine will crash.
+ */
+ printk(KERN_INFO "%s: Critical router failure ...!!!\n", card->devname);
+ printk(KERN_INFO "Please contact Sangoma Technologies !\n");
+ fr_set_intr_mode(card, 0, 0, 0);
return;
}
@@ -1732,134 +2167,206 @@
dlci = frbuf->dlci;
offs = frbuf->offset;
- /* Find network interface for this packet */
+ /* Find the network interface for this packet */
dev = find_channel(card, dlci);
-
- if (dev == NULL) {
+
- /* unconfigured DLCI, so discard packet */
- printk(KERN_INFO "%s: received data on unconfigured DLCI %d!\n",
+ /* Check that the network interface is active and
+ * properly setup */
+ if (dev == NULL) {
+ if( net_ratelimit()) {
+ printk(KERN_INFO "%s: received data on unconfigured DLCI %d!\n",
card->devname, dlci);
+ }
++card->statistics.rx_intr_on_orphaned_DLCI;
+ ++card->wandev.stats.rx_dropped;
+ goto rx_done;
+ }
- } else {
- chan = dev->priv;
+ if ((chan = dev->priv) == NULL){
+ if( net_ratelimit()) {
+ printk(KERN_INFO "%s: received data on unconfigured DLCI %d!\n",
+ card->devname, dlci);
+ }
+ ++card->statistics.rx_intr_on_orphaned_DLCI;
+ ++card->wandev.stats.rx_dropped;
+ goto rx_done;
+ }
- skb = dev_alloc_skb(len);
+ skb = dev_alloc_skb(len);
- if (!netif_running(dev) || (skb == NULL)) {
- ++chan->ifstats.rx_dropped;
-
- if(netif_running(dev)) {
+ if (!is_dev_running(dev) || (skb == NULL)){
+ ++chan->ifstats.rx_dropped;
+
+ if(skb == NULL) {
+ if (net_ratelimit()) {
printk(KERN_INFO
- "%s: no socket buffers available!\n",
- card->devname);
- chan->drvstats_rx_intr.rx_intr_no_socket ++;
-
- } else
- chan->drvstats_rx_intr.
- rx_intr_dev_not_started ++;
- } else {
- /* Copy data to the socket buffer */
- if ((offs + len) > card->u.f.rx_top + 1) {
- unsigned tmp = card->u.f.rx_top - offs + 1;
-
- buf = skb_put(skb, tmp);
- sdla_peek(&card->hw, offs, buf, tmp);
- offs = card->u.f.rx_base;
- len -= tmp;
- }
-
- buf = skb_put(skb, len);
- sdla_peek(&card->hw, offs, buf, len);
-
- udp_type = udp_pkt_type( skb, card );
-
- if(udp_type != UDP_INVALID_TYPE) {
- if(store_udp_mgmt_pkt(udp_type,
- UDP_PKT_FRM_NETWORK, card, skb, dlci)) {
- flags->imask |= FR_INTR_TIMER;
- if (udp_type == UDP_FPIPE_TYPE){
- chan->drvstats_rx_intr.
- rx_intr_PIPE_request ++;
- }
- }
+ "%s: no socket buffers available!\n",
+ card->devname);
}
+ chan->drvstats_rx_intr.rx_intr_no_socket ++;
+ }
- else if (chan->usedby == API) {
- api_rx_hdr_t* api_rx_hdr;
- chan->drvstats_rx_intr.
- rx_intr_bfr_passed_to_stack ++;
- chan->ifstats.rx_packets ++;
- card->wandev.stats.rx_packets ++;
- chan->ifstats.rx_bytes += skb->len;
- card->wandev.stats.rx_bytes += skb->len;
-
- skb_push(skb, sizeof(api_rx_hdr_t));
- api_rx_hdr = (api_rx_hdr_t*)&skb->data[0x00];
- api_rx_hdr->attr = frbuf->attr;
- api_rx_hdr->time_stamp = frbuf->tmstamp;
- skb->protocol = htons(0x16);
- skb->pkt_type = PACKET_HOST;
- /* Pass it up the protocol stack */
- skb->dev = dev;
- skb->mac.raw = skb->data;
- netif_rx(skb);
-
- } else if (handle_IPXWAN(skb->data,chan->name,
- chan->enable_IPX, chan->network_number)) {
- if (chan->enable_IPX) {
- fr_send(card, dlci, 0, skb->len,
- skb->data);
- }
- dev_kfree_skb(skb);
+ if (!is_dev_running(dev)){
+ chan->drvstats_rx_intr.
+ rx_intr_dev_not_started ++;
+ if (skb){
+ wan_dev_kfree_skb(skb, FREE_READ);
+ }
+ }
+ goto rx_done;
+ }
-/*FIXME: Fix the ARPS in next release
+ /* Copy data from the board into the socket buffer */
+ if ((offs + len) > card->u.f.rx_top + 1) {
+ unsigned tmp = card->u.f.rx_top - offs + 1;
- } else if (is_arp(skb->data)) {
- if (process_ARP((arphdr_1490_t *)skb->data, card, dev)) {
- printk (KERN_INFO "%s: Error processing ARP Packet.\n", card->devname);
- }
- dev_kfree_skb(skb);
-*/
+ buf = skb_put(skb, tmp);
+ sdla_peek(&card->hw, offs, buf, tmp);
+ offs = card->u.f.rx_base;
+ len -= tmp;
+ }
- } else if ( skb->data[0] != 0x03) {
- printk(KERN_INFO "%s: Non IETF packet discarded.\n", card->devname);
- dev_kfree_skb(skb);
+ buf = skb_put(skb, len);
+ sdla_peek(&card->hw, offs, buf, len);
- } else {
- len_incl_hdr = skb->len;
- /* Decapsulate packet and pass it up the
- protocol stack */
- skb->dev = dev;
+ /* We got the packet from the bard.
+ * Check the packet type and take appropriate action */
- /* remove hardware header */
- buf = skb_pull(skb, 1);
+ udp_type = udp_pkt_type( skb, card );
- if (!wanrouter_type_trans(skb, dev)) {
-
- /* can't decapsulate packet */
- dev_kfree_skb(skb);
- chan->drvstats_rx_intr.
- rx_intr_bfr_not_passed_to_stack ++;
- ++ chan->ifstats.rx_errors;
- ++ card->wandev.stats.rx_errors;
-
- } else {
- netif_rx(skb);
- chan->drvstats_rx_intr.
- rx_intr_bfr_passed_to_stack ++;
- ++ chan->ifstats.rx_packets;
- ++ card->wandev.stats.rx_packets;
- chan->ifstats.rx_bytes += len_incl_hdr;
- card->wandev.stats.rx_bytes +=
- len_incl_hdr;
+ if(udp_type != UDP_INVALID_TYPE) {
+
+ /* UDP Debug packet received, store the
+ * packet and handle it in timer interrupt */
+
+ skb_pull(skb, 1);
+ if (wanrouter_type_trans(skb, dev)){
+ if(store_udp_mgmt_pkt(udp_type,UDP_PKT_FRM_NETWORK,card,skb,dlci)){
+
+ flags->imask |= FR_INTR_TIMER;
+
+ if (udp_type == UDP_FPIPE_TYPE){
+ ++chan->drvstats_rx_intr.rx_intr_PIPE_request;
}
- }
- }
- }
+ }
+ }
+
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
+ }else if (chan->common.usedby == API) {
+
+ /* We are in API mode.
+ * Add an API header to the RAW packet
+ * and queue it into a circular buffer.
+ * Then kick the fr_bh() bottom half handler */
+
+ api_rx_hdr_t* api_rx_hdr;
+ chan->drvstats_rx_intr.rx_intr_bfr_passed_to_stack ++;
+ chan->ifstats.rx_packets ++;
+ card->wandev.stats.rx_packets ++;
+
+ chan->ifstats.rx_bytes += skb->len;
+ card->wandev.stats.rx_bytes += skb->len;
+
+ skb_push(skb, sizeof(api_rx_hdr_t));
+ api_rx_hdr = (api_rx_hdr_t*)&skb->data[0x00];
+ api_rx_hdr->attr = frbuf->attr;
+ api_rx_hdr->time_stamp = frbuf->tmstamp;
+
+ skb->protocol = htons(ETH_P_IP);
+ skb->mac.raw = skb->data;
+ skb->dev = dev;
+ skb->pkt_type = WAN_PACKET_DATA;
+
+ bh_enqueue(dev, skb);
+
+ trigger_fr_bh(chan);
+ #endif
+
+ }else if (handle_IPXWAN(skb->data,chan->name,chan->enable_IPX, chan->network_number)){
+
+ //FIXME: Frame Relay IPX is not supported, Yet !
+ //if (chan->enable_IPX) {
+ // fr_send(card, dlci, 0, skb->len,skb->data);
+ //}
+ wan_dev_kfree_skb(skb, FREE_READ);
+
+ } else if (is_arp(skb->data)) {
+
+ /* ARP support enabled Mar 16 2000
+ * Process incoming ARP reply/request, setup
+ * dynamic routes. */
+
+ if (process_ARP((arphdr_1490_t *)skb->data, card, dev)) {
+ if (net_ratelimit()){
+ printk (KERN_INFO
+ "%s: Error processing ARP Packet.\n",
+ card->devname);
+ }
+ }
+ wan_dev_kfree_skb(skb, FREE_READ);
+
+ } else if (skb->data[0] != 0x03) {
+
+ if (net_ratelimit()) {
+ printk(KERN_INFO "%s: Non IETF packet discarded.\n",
+ card->devname);
+ }
+ wan_dev_kfree_skb(skb, FREE_READ);
+
+ } else {
+
+ len_incl_hdr = skb->len;
+ /* Decapsulate packet and pass it up the
+ protocol stack */
+ skb->dev = dev;
+
+ if (chan->common.usedby == BRIDGE || chan->common.usedby == BRIDGE_NODE){
+
+ /* Make sure it's an Ethernet frame, otherwise drop it */
+ if (!memcmp(skb->data, "\x03\x00\x80\x00\x80\xC2\x00\x07", 8)) {
+ skb_pull(skb, 8);
+ skb->protocol=eth_type_trans(skb,dev);
+ }else{
+ ++chan->drvstats_rx_intr.rx_intr_bfr_not_passed_to_stack;
+ ++chan->ifstats.rx_errors;
+ ++card->wandev.stats.rx_errors;
+ goto rx_done;
+ }
+ }else{
+
+ /* remove hardware header */
+ buf = skb_pull(skb, 1);
+
+ if (!wanrouter_type_trans(skb, dev)) {
+
+ /* can't decapsulate packet */
+ wan_dev_kfree_skb(skb, FREE_READ);
+
+ ++chan->drvstats_rx_intr.rx_intr_bfr_not_passed_to_stack;
+ ++chan->ifstats.rx_errors;
+ ++card->wandev.stats.rx_errors;
+ goto rx_done;
+ }
+ skb->mac.raw = skb->data;
+ }
+
+
+ /* Send a packed up the IP stack */
+ netif_rx(skb);
+ ++chan->drvstats_rx_intr.rx_intr_bfr_passed_to_stack;
+ ++chan->ifstats.rx_packets;
+ ++card->wandev.stats.rx_packets;
+
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
+ chan->ifstats.rx_bytes += len_incl_hdr;
+ card->wandev.stats.rx_bytes += len_incl_hdr;
+#endif
+ }
+
+rx_done:
/* Release buffer element and calculate a pointer to the next one */
frbuf->flag = 0;
@@ -1869,14 +2376,36 @@
}
-/*============================================================================
- * Transmit interrupt handler.
+/*==================================================================
+ * tx_intr: Transmit interrupt handler.
+ *
+ * Rationale:
+ * If the board is busy transmitting, if_send() will
+ * buffers a single packet and turn on
+ * the tx interrupt. Tx interrupt will be called
+ * by the board, once the firmware can send more
+ * data. Thus, no polling is required.
+ *
+ * Description:
+ * Tx interrupt is called for each
+ * configured dlci channel. Thus:
+ * 1. Obtain the netowrk interface based on the
+ * dlci number.
+ * 2. Check that network interface is up and
+ * properly setup.
+ * 3. Check for a buffered packed.
+ * 4. Transmit the packed.
+ * 5. If we are in WANPIPE mode, mark the
+ * NET_BH handler.
+ * 6. If we are in API mode, kick
+ * the AF_WANPIPE socket for more data.
+ *
*/
static void tx_intr(sdla_t *card)
{
fr508_flags_t* flags = card->flags;
fr_tx_buf_ctl_t* bctl;
- struct net_device* dev = card->wandev.dev;
+ netdevice_t* dev;
fr_channel_t* chan;
if(card->hw.type == SDLA_S514){
@@ -1888,61 +2417,112 @@
/* Find the structure and make it unbusy */
dev = find_channel(card, flags->dlci);
- chan = dev->priv;
+ if (dev == NULL){
+ printk(KERN_INFO "NO DEV IN TX Interrupt\n");
+ goto end_of_tx_intr;
+ }
+
+ if ((chan = dev->priv) == NULL){
+ printk(KERN_INFO "NO CHAN IN TX Interrupt\n");
+ goto end_of_tx_intr;
+ }
- if(!chan->transmit_length) {
+ if(!chan->transmit_length || !chan->delay_skb) {
printk(KERN_INFO "%s: tx int error - transmit length zero\n",
card->wandev.name);
- return;
+ goto end_of_tx_intr;
}
/* If the 'if_send()' procedure is currently checking the 'tbusy'
status, then we cannot transmit. Instead, we configure the microcode
so as to re-issue this transmit interrupt at a later stage.
*/
- if (test_bit(2, (void*)&card->wandev.critical)) {
+ if (test_bit(SEND_TXIRQ_CRIT, (void*)&card->wandev.critical)) {
+
fr_dlci_interface_t* dlci_interface = chan->dlci_int_interface;
bctl->flag = 0xA0;
dlci_interface->gen_interrupt |= FR_INTR_TXRDY;
- printk(KERN_INFO "%s: TX Interrupt Detected busy if_send\n",card->devname);
+ return;
- } else {
+ }else{
bctl->dlci = flags->dlci;
- bctl->length = chan->transmit_length;
- sdla_poke(&card->hw, bctl->offset, chan->transmit_buffer,
- chan->transmit_length);
+ bctl->length = chan->transmit_length+chan->fr_header_len;
+ sdla_poke(&card->hw,
+ fr_send_hdr(card,bctl->dlci,bctl->offset),
+ chan->delay_skb->data,
+ chan->delay_skb->len);
bctl->flag = 0xC0;
++chan->ifstats.tx_packets;
++card->wandev.stats.tx_packets;
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
chan->ifstats.tx_bytes += chan->transmit_length;
card->wandev.stats.tx_bytes += chan->transmit_length;
+#endif
+
+ /* We must free an sk buffer, which we used
+ * for delayed transmission; Otherwise, the sock
+ * will run out of memory */
+ wan_dev_kfree_skb(chan->delay_skb, FREE_WRITE);
+
+ chan->delay_skb = NULL;
chan->transmit_length = 0;
- /* if any other interfaces have transmit interrupts pending, */
- /* do not disable the global transmit interrupt */
- if(!(-- card->u.f.tx_interrupts_pending))
- flags->imask &= ~FR_INTR_TXRDY;
+#ifdef LINUX_2_4
+ dev->trans_start = jiffies;
+#endif
- netif_wake_queue (dev);
+#ifdef LINUX_2_0
+ wake_net_dev(dev);
+#else
+ if (is_queue_stopped(dev)){
+ /* If using API, than wakeup socket BH handler */
+ if (chan->common.usedby == API){
+ start_net_queue(dev);
+ wakeup_sk_bh(dev);
+ }else{
+ wake_net_dev(dev);
+ }
+ }
+#endif
}
+
+end_of_tx_intr:
+
+ /* if any other interfaces have transmit interrupts pending,
+ * do not disable the global transmit interrupt */
+ if(!(-- card->u.f.tx_interrupts_pending))
+ flags->imask &= ~FR_INTR_TXRDY;
+
+
}
/*============================================================================
- * Timer interrupt handler.
- FIXME: update comments as we modify the code
- * The timer interrupt is used for three purposes:
- * 1) Processing udp calls from 'fpipemon'.
- * 2) Processing update calls from /proc file system
- * 2) Reading board-level statistics for updating the proc file system.
- * 3) Sending inverse ARP request packets.
+ * timer_intr: Timer interrupt handler.
+ *
+ * Rationale:
+ * All commans must be executed within the timer
+ * interrupt since no two commands should execute
+ * at the same time.
+ *
+ * Description:
+ * The timer interrupt is used to:
+ * 1. Processing udp calls from 'fpipemon'.
+ * 2. Processing update calls from /proc file system
+ * 3. Reading board-level statistics for
+ * updating the proc file system.
+ * 4. Sending inverse ARP request packets.
+ * 5. Configure a dlci/channel.
+ * 6. Unconfigure a dlci/channel. (Node only)
*/
+
static void timer_intr(sdla_t *card)
{
fr508_flags_t* flags = card->flags;
- if(card->u.f.timer_int_enabled & TMR_INT_ENABLED_UDP) {
+ /* UDP Debuging: fpipemon call */
+ if (card->u.f.timer_int_enabled & TMR_INT_ENABLED_UDP) {
if(card->u.f.udp_type == UDP_FPIPE_TYPE) {
if(process_udp_mgmt_pkt(card)) {
card->u.f.timer_int_enabled &=
@@ -1951,81 +2531,132 @@
}
}
- if(card->u.f.timer_int_enabled & TMR_INT_ENABLED_UPDATE) {
+ /* /proc update call : triggered from update() */
+ if (card->u.f.timer_int_enabled & TMR_INT_ENABLED_UPDATE) {
fr_get_err_stats(card);
fr_get_stats(card);
card->u.f.update_comms_stats = 0;
card->u.f.timer_int_enabled &= ~TMR_INT_ENABLED_UPDATE;
}
+ /* Update the channel state call. This is call is
+ * triggered by if_send() function */
+ if (card->u.f.timer_int_enabled & TMR_INT_ENABLED_UPDATE_STATE){
+ netdevice_t *dev;
+ if (card->wandev.state == WAN_CONNECTED){
+ for (dev=card->wandev.dev; dev; dev = *((netdevice_t **)dev->priv)){
+ fr_channel_t *chan = dev->priv;
+ if (chan->common.state != WAN_CONNECTED){
+ update_chan_state(dev);
+ }
+ }
+ }
+ card->u.f.timer_int_enabled &= ~TMR_INT_ENABLED_UPDATE_STATE;
+ }
+
+ /* configure a dlci/channel */
+ if (card->u.f.timer_int_enabled & TMR_INT_ENABLED_CONFIG){
+ config_fr(card);
+ card->u.f.timer_int_enabled &= ~TMR_INT_ENABLED_CONFIG;
+ }
-//FIXME: Fix the dynamic IP addressing
-/*
-goto L4;
+ /* unconfigure a dlci/channel */
+ if (card->u.f.timer_int_enabled & TMR_INT_ENABLED_UNCONFIG){
+ unconfig_fr(card);
+ card->u.f.timer_int_enabled &= ~TMR_INT_ENABLED_UNCONFIG;
+ }
- // Used to send inarp request at given interval
- if (card->wandev.state == WAN_CONNECTED) {
- int num_remaining = 0;
-
- dev = card->wandev.dev;
- while (dev) {
- fr_channel_t *chan = dev->priv;
-
- if (chan->inarp == INARP_REQUEST &&
- chan->state == WAN_CONNECTED) {
- num_remaining++;
-
- if ((jiffies - chan->inarp_tick) > (chan->inarp_interval * HZ)) {
- send_inarp_request(card,dev);
- chan->inarp_tick = jiffies;
- }
+
+ /* Transmit ARP packets */
+ if (card->u.f.timer_int_enabled & TMR_INT_ENABLED_ARP){
+ int i=0;
+ netdevice_t *dev;
+
+ if (card->u.f.arp_dev == NULL)
+ card->u.f.arp_dev = card->wandev.dev;
+
+ dev = card->u.f.arp_dev;
+
+ for (;;){
+
+ fr_channel_t *chan = dev->priv;
+
+ /* If the interface is brought down cancel sending In-ARPs */
+ if (!(dev->flags&IFF_UP)){
+ clear_bit(0,&chan->inarp_ready);
+ }
+
+ if (test_bit(0,&chan->inarp_ready)){
+
+ if (check_tx_status(card,dev)){
+ set_bit(ARP_CRIT,&card->wandev.critical);
+ break;
+ }
+
+ if (!send_inarp_request(card,dev)){
+ trigger_fr_arp(dev);
+ chan->inarp_tick = jiffies;
+ }
+
+ clear_bit(0,&chan->inarp_ready);
+ dev = move_dev_to_next(card,dev);
+ break;
+ }
+ dev = move_dev_to_next(card,dev);
+
+ if (++i == card->wandev.new_if_cnt){
+ card->u.f.timer_int_enabled &= ~TMR_INT_ENABLED_ARP;
+ break;
}
- dev = chan->slave;
- }
- if (!num_remaining) { // no more to process
- flags->imask &= ~FR_INTR_TIMER;
}
+ card->u.f.arp_dev = dev;
}
-L4:
- ;
-*/
+
if(!card->u.f.timer_int_enabled)
flags->imask &= ~FR_INTR_TIMER;
}
/*============================================================================
- * Spurious interrupt handler.
- * o print a warning
- * o
+ * spur_intr: Spurious interrupt handler.
+ *
+ * Description:
+ * We don't know this interrupt.
+ * Print a warning.
*/
+
static void spur_intr (sdla_t* card)
{
- printk(KERN_INFO "%s: spurious interrupt!\n", card->devname);
+ if (net_ratelimit()){
+ printk(KERN_INFO "%s: spurious interrupt!\n", card->devname);
+ }
}
+
//FIXME: Fix the IPX in next version
/*===========================================================================
* Return 0 for non-IPXWAN packet
* 1 for IPXWAN packet or IPX is not enabled!
* FIXME: Use a IPX structure here not offsets
*/
-static int handle_IPXWAN(unsigned char *sendpacket, char *devname, unsigned char enable_IPX, unsigned long network_number)
+static int handle_IPXWAN(unsigned char *sendpacket,
+ char *devname, unsigned char enable_IPX,
+ unsigned long network_number)
{
int i;
- if( sendpacket[1] == 0x00 &&
- sendpacket[2] == 0x80 &&
- sendpacket[6] == 0x81 &&
- sendpacket[7] == 0x37) {
+ if( sendpacket[1] == 0x00 && sendpacket[2] == 0x80 &&
+ sendpacket[6] == 0x81 && sendpacket[7] == 0x37) {
/* It's an IPX packet */
- if(!enable_IPX) {
+ if (!enable_IPX){
/* Return 1 so we don't pass it up the stack. */
//FIXME: Take this out when IPX is fixed
- printk (KERN_INFO
+ if (net_ratelimit()){
+ printk (KERN_INFO
"%s: WARNING: Unsupported IPX packet received and dropped\n",
devname);
+ }
return 1;
}
} else {
@@ -2033,39 +2664,33 @@
return 0;
}
- if( sendpacket[24] == 0x90 &&
- sendpacket[25] == 0x04)
- {
+ if( sendpacket[24] == 0x90 && sendpacket[25] == 0x04){
/* It's IPXWAN */
- if( sendpacket[10] == 0x02 &&
- sendpacket[42] == 0x00)
- {
+ if( sendpacket[10] == 0x02 && sendpacket[42] == 0x00){
+
/* It's a timer request packet */
- printk(KERN_INFO "%s: Received IPXWAN Timer Request packet\n",devname);
+ printk(KERN_INFO "%s: Received IPXWAN Timer Request packet\n",
+ devname);
/* Go through the routing options and answer no to every
* option except Unnumbered RIP/SAP
*/
- for(i = 49; sendpacket[i] == 0x00; i += 5)
- {
+ for(i = 49; sendpacket[i] == 0x00; i += 5){
/* 0x02 is the option for Unnumbered RIP/SAP */
- if( sendpacket[i + 4] != 0x02)
- {
+ if( sendpacket[i + 4] != 0x02){
sendpacket[i + 1] = 0;
}
}
/* Skip over the extended Node ID option */
- if( sendpacket[i] == 0x04 )
- {
+ if( sendpacket[i] == 0x04 ){
i += 8;
}
/* We also want to turn off all header compression opt.
*/
- for(; sendpacket[i] == 0x80 ;)
- {
+ for(; sendpacket[i] == 0x80 ;){
sendpacket[i + 1] = 0;
i += (sendpacket[i + 2] << 8) + (sendpacket[i + 3]) + 4;
}
@@ -2073,12 +2698,15 @@
/* Set the packet type to timer response */
sendpacket[42] = 0x01;
- printk(KERN_INFO "%s: Sending IPXWAN Timer Response\n",devname);
- }
- else if( sendpacket[42] == 0x02 )
- {
+ printk(KERN_INFO "%s: Sending IPXWAN Timer Response\n",
+ devname);
+
+ } else if( sendpacket[42] == 0x02 ){
+
/* This is an information request packet */
- printk(KERN_INFO "%s: Received IPXWAN Information Request packet\n",devname);
+ printk(KERN_INFO
+ "%s: Received IPXWAN Information Request packet\n",
+ devname);
/* Set the packet type to information response */
sendpacket[42] = 0x03;
@@ -2103,10 +2731,10 @@
sendpacket[i] = 0;
}
- printk(KERN_INFO "%s: Sending IPXWAN Information Response packet\n",devname);
- }
- else
- {
+ printk(KERN_INFO "%s: Sending IPXWAN Information Response packet\n",
+ devname);
+ } else {
+
printk(KERN_INFO "%s: Unknown IPXWAN packet!\n",devname);
return 0;
}
@@ -2128,103 +2756,183 @@
return 0;
}
/*============================================================================
- * Process Route.
- * This routine is called as a polling routine to dynamically add/delete routes
- * negotiated by inverse ARP. It is in this "task" because we don't want routes
- * to be added while in interrupt context.
-*/
+ * process_route
+ *
+ * Rationale:
+ * If the interface goes down, or we receive an ARP request,
+ * we have to change the network interface ip addresses.
+ * This cannot be done within the interrupt.
+ *
+ * Description:
+ *
+ * This routine is called as a polling routine to dynamically
+ * add/delete routes negotiated by inverse ARP. It is in this
+ * "task" because we don't want routes to be added while in
+ * interrupt context.
+ *
+ * Usage:
+ * This function is called by fr_poll() polling funtion.
+ */
-static void process_route (sdla_t* card)
+static void process_route (netdevice_t *dev)
{
- struct net_device* dev;
- struct in_device *in_dev;
- struct rtentry route;
- int err = 0;
- mm_segment_t fs;
+ fr_channel_t *chan = dev->priv;
+ sdla_t *card = chan->card;
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
- /* Dynamic Route adding/removing */
- dev = card->wandev.dev;
- while (dev) {
- fr_channel_t *chan = dev->priv;
-
- if (chan->route_flag == ADD_ROUTE ||
- chan->route_flag == REMOVE_ROUTE ) {
- fs = get_fs();
-
- in_dev = dev->ip_ptr;
-
- if( in_dev != NULL && in_dev->ifa_list != NULL) {
- memset(&route, 0, sizeof(route));
- route.rt_dev = dev->name;
- route.rt_flags = 0;
-
- ((struct sockaddr_in *) &(route.rt_dst)) ->
- sin_addr.s_addr=in_dev->ifa_list->ifa_address;
- ((struct sockaddr_in *) &(route.rt_dst)) ->
- sin_family = AF_INET;
- ((struct sockaddr_in *) &(route.rt_genmask)) ->
- sin_addr.s_addr = 0xFFFFFFFF;
- ((struct sockaddr_in *) &(route.rt_genmask)) ->
- sin_family = AF_INET;
-
- switch(chan->route_flag) {
-
- case ADD_ROUTE:
- set_fs(get_ds()); /* get user space block */
- err = ip_rt_ioctl( SIOCADDRT, &route);
- set_fs(fs); /* restore old block */
-
- if (err) {
- printk(KERN_INFO "%s: Adding of route failed. Error: %d\n", card->devname,err);
- printk(KERN_INFO "%s: Address: %s\n",
- chan->name,
- in_ntoa(in_dev->ifa_list->ifa_address) );
- } else {
- chan->route_flag = ROUTE_ADDED;
- }
- break;
+ struct ifreq if_info;
+ struct sockaddr_in *if_data;
+ mm_segment_t fs = get_fs();
+ u32 ip_tmp;
+ int err;
- case REMOVE_ROUTE:
- set_fs(get_ds()); /* get user space block */
- err = ip_rt_ioctl( SIOCDELRT, &route);
- set_fs(fs); /* restore old block */
-
- if (err) {
- printk(KERN_INFO "%s: Deleting of route failed. Error: %d\n", card->devname,err);
- printk(KERN_INFO "%s: Address: %s\n",
- dev->name,in_ntoa(in_dev->ifa_list->ifa_address) );
- } else {
- printk(KERN_INFO "%s: Removed route.\n",
- chan->name);
- chan->route_flag = NO_ROUTE;
- }
- break;
- } /* Case Statement */
- }
- } /* If ADD/DELETE ROUTE */
- dev = chan->slave;
- } /* Device 'While' Loop */
+ switch(chan->route_flag){
- card->poll = NULL;
-}
+ case ADD_ROUTE:
+
+ /* Set remote addresses */
+ memset(&if_info, 0, sizeof(if_info));
+ strcpy(if_info.ifr_name, dev->name);
+ set_fs(get_ds()); /* get user space block */
+
+ if_data = (struct sockaddr_in *)&if_info.ifr_dstaddr;
+ if_data->sin_addr.s_addr = chan->ip_remote;
+ if_data->sin_family = AF_INET;
+ err = devinet_ioctl( SIOCSIFDSTADDR, &if_info );
+ set_fs(fs); /* restore old block */
-/****** Frame Relay Firmware-Specific Functions *****************************/
+ if (err) {
-/*============================================================================
- * Read firmware code version.
- * o fill string str with firmware version info.
- */
-static int fr_read_version (sdla_t* card, char* str)
-{
- fr_mbox_t* mbox = card->mbox;
- int retry = MAX_CMD_RETRY;
- int err;
+ printk(KERN_INFO
+ "%s: Route Add failed. Error: %d\n",
+ card->devname,err);
+ printk(KERN_INFO "%s: Address: %s\n",
+ chan->name, in_ntoa(chan->ip_remote));
+
+ }else {
+ printk(KERN_INFO "%s: Route Added Successfully: %s\n",
+ card->devname,in_ntoa(chan->ip_remote));
+ chan->route_flag = ROUTE_ADDED;
+ }
+ break;
- do
+ case REMOVE_ROUTE:
+
+ /* Set remote addresses */
+ memset(&if_info, 0, sizeof(if_info));
+ strcpy(if_info.ifr_name, dev->name);
+
+ ip_tmp = get_ip_address(dev,WAN_POINTOPOINT_IP);
+
+ set_fs(get_ds()); /* get user space block */
+
+ if_data = (struct sockaddr_in *)&if_info.ifr_dstaddr;
+ if_data->sin_addr.s_addr = 0;
+ if_data->sin_family = AF_INET;
+ err = devinet_ioctl( SIOCSIFDSTADDR, &if_info );
+
+ set_fs(fs);
+
+ if (err) {
+
+ printk(KERN_INFO
+ "%s: Deleting of route failed. Error: %d\n",
+ card->devname,err);
+ printk(KERN_INFO "%s: Address: %s\n",
+ dev->name,in_ntoa(chan->ip_remote) );
+
+ } else {
+
+ printk(KERN_INFO "%s: Route Removed Sucessfuly: %s\n",
+ card->devname,in_ntoa(ip_tmp));
+ chan->route_flag = NO_ROUTE;
+ }
+ break;
+
+ } /* Case Statement */
+
+#else
+ /* Dynamic Route adding/removing */
+ struct rtentry route;
+ int err = 0;
+ unsigned long fs = get_fs();
+
+ memset(&route, 0, sizeof(route));
+ route.rt_dev = dev->name;
+ route.rt_flags = 0;
+
+ ((struct sockaddr_in *) &(route.rt_dst)) ->
+ sin_addr.s_addr=dev->pa_dstaddr;
+ ((struct sockaddr_in *) &(route.rt_dst)) ->
+ sin_family = AF_INET;
+ ((struct sockaddr_in *) &(route.rt_genmask)) ->
+ sin_addr.s_addr = 0xFFFFFFFF;
+ ((struct sockaddr_in *) &(route.rt_genmask)) ->
+ sin_family = AF_INET;
+ switch(chan->route_flag) {
+
+ case ADD_ROUTE:
+
+ set_fs(get_ds()); /* get user space block */
+ err = ip_rt_new(&route);
+ set_fs(fs); /* restore old block */
+
+ if (err) {
+ printk(KERN_INFO "%s: Adding of route failed. Error: %d\n",
+ card->devname,err);
+ printk(KERN_INFO "%s: Address: %s\n",
+ chan->name, in_ntoa(dev->pa_dstaddr) );
+ }
+ else {
+ chan->route_flag = ROUTE_ADDED;
+ }
+ break;
+
+ case REMOVE_ROUTE:
+
+ set_fs(get_ds()); /* get user space block */
+ err = ip_rt_kill(&route);
+ set_fs(fs); /* restore old block */
+
+ if (err) {
+
+ printk(KERN_INFO "%s: Deleting of route failed. Error: %d\n",
+ card->devname,err);
+ printk(KERN_INFO "%s: Address: %s\n",
+ dev->name,in_ntoa(dev->pa_dstaddr) );
+ } else {
+
+ printk(KERN_INFO "%s: Removed route.\n",
+ ((fr_channel_t*)dev->priv)->name);
+ chan->route_flag = NO_ROUTE;
+
+ }
+ break;
+ }
+
+#endif
+
+}
+
+
+
+/****** Frame Relay Firmware-Specific Functions *****************************/
+
+/*============================================================================
+ * Read firmware code version.
+ * o fill string str with firmware version info.
+ */
+static int fr_read_version (sdla_t* card, char* str)
+{
+ fr_mbox_t* mbox = card->mbox;
+ int retry = MAX_CMD_RETRY;
+ int err;
+
+ do
{
mbox->cmd.command = FR_READ_CODE_VERSION;
mbox->cmd.length = 0;
@@ -2264,6 +2972,12 @@
err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
} while (err && retry-- && fr_event(card, err, mbox));
+
+ /*NC Oct 12 2000 */
+ if (err != CMD_OK){
+ printk(KERN_ERR "%s: Frame Relay Configuration Failed: rc=0x%x\n",
+ card->devname,err);
+ }
return err;
}
@@ -2338,33 +3052,39 @@
}
/*============================================================================
- * Disable communications.
+ * fr_comm_disable
+ *
+ * Warning: This functin is called by the shutdown() procedure. It is void
+ * since dev->priv are has already been deallocated and no
+ * error checking is possible using fr_event() function.
*/
-static int fr_comm_disable (sdla_t* card)
+static void fr_comm_disable (sdla_t* card)
{
fr_mbox_t* mbox = card->mbox;
int retry = MAX_CMD_RETRY;
int err;
- do
- {
- mbox->cmd.command = FR_COMM_DISABLE;
- mbox->cmd.length = 0;
- err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
- } while (err && retry-- && fr_event(card, err, mbox));
-
- retry = MAX_CMD_RETRY;
-
do {
mbox->cmd.command = FR_SET_MODEM_STATUS;
mbox->cmd.length = 1;
mbox->data[0] = 0;
err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
- } while (err && retry-- && fr_event(card, err, mbox));
+ } while (err && retry--);
- return err;
+ retry = MAX_CMD_RETRY;
+
+ do
+ {
+ mbox->cmd.command = FR_COMM_DISABLE;
+ mbox->cmd.length = 0;
+ err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
+ } while (err && retry--);
+
+ return;
}
+
+
/*============================================================================
* Get communications error statistics.
*/
@@ -2518,9 +3238,58 @@
return err;
}
+
+static unsigned int fr_send_hdr (sdla_t*card, int dlci, unsigned int offset)
+{
+ netdevice_t *dev = find_channel(card,dlci);
+ fr_channel_t *chan;
+
+ if (!dev || !(chan=dev->priv))
+ return offset;
+
+ if (chan->fr_header_len){
+ sdla_poke(&card->hw, offset, chan->fr_header, chan->fr_header_len);
+ }
+
+ return offset+chan->fr_header_len;
+}
+
/*============================================================================
* Send a frame on a selected DLCI.
*/
+static int fr_send_data_header (sdla_t* card, int dlci, unsigned char attr, int len,
+ void *buf, unsigned char hdr_len)
+{
+ fr_mbox_t* mbox = card->mbox + 0x800;
+ int retry = MAX_CMD_RETRY;
+ int err;
+
+ do
+ {
+ mbox->cmd.dlci = dlci;
+ mbox->cmd.attr = attr;
+ mbox->cmd.length = len+hdr_len;
+ mbox->cmd.command = FR_WRITE;
+ err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
+ } while (err && retry-- && fr_event(card, err, mbox));
+
+ if (!err) {
+ fr_tx_buf_ctl_t* frbuf;
+
+ if(card->hw.type == SDLA_S514)
+ frbuf = (void*)(*(unsigned long*)mbox->data +
+ card->hw.dpmbase);
+ else
+ frbuf = (void*)(*(unsigned long*)mbox->data -
+ FR_MB_VECTOR + card->hw.dpmbase);
+
+ sdla_poke(&card->hw, fr_send_hdr(card,dlci,frbuf->offset), buf, len);
+ frbuf->flag = 0x01;
+ }
+
+ return err;
+}
+
static int fr_send (sdla_t* card, int dlci, unsigned char attr, int len,
void *buf)
{
@@ -2538,7 +3307,6 @@
} while (err && retry-- && fr_event(card, err, mbox));
if (!err) {
-
fr_tx_buf_ctl_t* frbuf;
if(card->hw.type == SDLA_S514)
@@ -2555,6 +3323,7 @@
return err;
}
+
/****** Firmware Asynchronous Event Handlers ********************************/
/*============================================================================
@@ -2577,46 +3346,41 @@
case FRRES_CHANNEL_DOWN:
{
- struct net_device *dev;
+ netdevice_t *dev;
/* Remove all routes from associated DLCI's */
- dev = card->wandev.dev;
- while (dev) {
+ for (dev = card->wandev.dev; dev; dev = *((netdevice_t **)dev->priv)) {
fr_channel_t *chan = dev->priv;
if (chan->route_flag == ROUTE_ADDED) {
chan->route_flag = REMOVE_ROUTE;
- card->poll = &process_route;
}
if (chan->inarp == INARP_CONFIGURED) {
chan->inarp = INARP_REQUEST;
}
- dev = chan->slave;
+ /* If the link becomes disconnected then,
+ * all channels will be disconnected
+ * as well.
+ */
+ set_chan_state(dev,WAN_DISCONNECTED);
}
-
+
wanpipe_set_state(card, WAN_DISCONNECTED);
return 1;
}
case FRRES_CHANNEL_UP:
{
- struct net_device *dev;
- int num_requests = 0;
+ netdevice_t *dev;
- /* Remove all routes from associated DLCI's */
- dev = card->wandev.dev;
- while (dev) {
- fr_channel_t *chan = dev->priv;
- if( chan->inarp == INARP_REQUEST ){
- num_requests++;
- chan->inarp_tick = jiffies;
- }
- dev = chan->slave;
+ /* FIXME: Only startup devices that are on the list */
+
+ for (dev = card->wandev.dev; dev; dev = *((netdevice_t **)dev->priv)) {
+
+ set_chan_state(dev,WAN_CONNECTED);
}
- /* Allow timer interrupts */
- if (num_requests) flags->imask |= 0x20;
wanpipe_set_state(card, WAN_CONNECTED);
return 1;
}
@@ -2644,8 +3408,10 @@
case FRRES_CIR_OVERFLOW:
break;
+
case FRRES_BUFFER_OVERFLOW:
break;
+
default:
printk(KERN_INFO "%s: command 0x%02X returned 0x%02X!\n"
, card->devname, mbox->cmd.command, event);
@@ -2684,13 +3450,13 @@
dlci_status_t* status = (void*)mbox->data;
int cnt = mbox->cmd.length / sizeof(dlci_status_t);
fr_channel_t *chan;
- struct net_device* dev2;
+ netdevice_t* dev2;
for (; cnt; --cnt, ++status) {
unsigned short dlci= status->dlci;
- struct net_device* dev = find_channel(card, dlci);
+ netdevice_t* dev = find_channel(card, dlci);
if (dev == NULL){
printk(KERN_INFO
@@ -2707,7 +3473,7 @@
"%s: DLCI %u is inactive!\n",
card->devname, dlci);
- if (dev && netif_running(dev))
+ if (dev && is_dev_running(dev))
set_chan_state(dev, WAN_DISCONNECTED);
}
@@ -2717,12 +3483,14 @@
"%s: DLCI %u has been deleted!\n",
card->devname, dlci);
- if (dev && netif_running(dev)) {
+ if (dev && is_dev_running(dev)){
+
fr_channel_t *chan = dev->priv;
if (chan->route_flag == ROUTE_ADDED) {
chan->route_flag = REMOVE_ROUTE;
- card->poll = &process_route;
+ /* The state change will trigger
+ * the fr polling routine */
}
if (chan->inarp == INARP_CONFIGURED) {
@@ -2740,16 +3508,15 @@
DLCI(s) when they become active.
*/
chan->dlci_configured = DLCI_CONFIG_PENDING;
-
- if (dev && netif_running(dev))
- set_chan_state(dev, WAN_CONNECTED);
+
+ set_chan_state(dev, WAN_CONNECTED);
}
}
}
- dev2 = card->wandev.dev;
- while (dev2) {
+ for (dev2 =card->wandev.dev; dev2; dev2 = *((netdevice_t **)dev2->priv)){
+
chan = dev2->priv;
if (chan->dlci_configured == DLCI_CONFIG_PENDING) {
@@ -2758,7 +3525,6 @@
}
}
- dev2 = chan->slave;
}
return 1;
}
@@ -2767,8 +3533,7 @@
static int fr_init_dlci (sdla_t *card, fr_channel_t *chan)
{
fr_dlc_conf_t cfg;
- fr508_flags_t* flags = card->flags;
-
+
memset(&cfg, 0, sizeof(cfg));
if ( chan->cir_status == CIR_DISABLED) {
@@ -2786,22 +3551,16 @@
}
if (fr_dlci_configure( card, &cfg , chan->dlci)){
- printk(KERN_INFO
- "%s: DLCI Configure failed for %d\n",
- card->devname, chan->dlci);
+ printk(KERN_INFO
+ "%s: DLCI Configure failed for %d\n",
+ card->devname, chan->dlci);
return 1;
}
chan->dlci_configured = DLCI_CONFIGURED;
- /* Allow timer interrupts */
- if( chan->inarp == INARP_REQUEST && card->wandev.state == WAN_CONNECTED) {
- chan->inarp_tick = jiffies;
- flags->imask |= 0x20;
- }
-
/* Read the interface byte mapping into the channel
- structure.
+ * structure.
*/
read_DLCI_IB_mapping( card, chan );
@@ -2812,7 +3571,7 @@
/*============================================================================
* Update channel state.
*/
-static int update_chan_state (struct net_device* dev)
+static int update_chan_state (netdevice_t* dev)
{
fr_channel_t* chan = dev->priv;
sdla_t* card = chan->card;
@@ -2828,14 +3587,25 @@
} while (err && retry-- && fr_event(card, err, mbox));
if (!err) {
-
+
unsigned short* list = (void*)mbox->data;
int cnt = mbox->cmd.length / sizeof(short);
-
+
+ err=1;
+
for (; cnt; --cnt, ++list) {
if (*list == chan->dlci) {
set_chan_state(dev, WAN_CONNECTED);
+
+
+ /* May 23 2000. NC
+ * When a dlci is added or restarted,
+ * the dlci_int_interface pointer must
+ * be reinitialized. */
+ if (!chan->dlci_int_interface){
+ err=fr_init_dlci (card,chan);
+ }
break;
}
}
@@ -2847,16 +3617,12 @@
/*============================================================================
* Set channel state.
*/
-static void set_chan_state (struct net_device* dev, int state)
+static void set_chan_state (netdevice_t* dev, int state)
{
fr_channel_t* chan = dev->priv;
sdla_t* card = chan->card;
- unsigned long flags;
-
- save_flags(flags);
- cli();
- if (chan->state != state) {
+ if (chan->common.state != state) {
switch (state) {
@@ -2864,6 +3630,12 @@
printk(KERN_INFO
"%s: Interface %s: DLCI %d connected\n",
card->devname, dev->name, chan->dlci);
+
+ /* If the interface was previoulsy down,
+ * bring it up, since the channel is active */
+
+ trigger_fr_poll (dev);
+ trigger_fr_arp (dev);
break;
case WAN_CONNECTING:
@@ -2876,20 +3648,29 @@
printk (KERN_INFO
"%s: Interface %s: DLCI %d disconnected!\n",
card->devname, dev->name, chan->dlci);
+
+ /* If the interface is up, bring it down,
+ * since the channel is now disconnected */
+ trigger_fr_poll (dev);
break;
}
- chan->state = state;
+ chan->common.state = state;
}
chan->state_tick = jiffies;
- restore_flags(flags);
}
/*============================================================================
* Find network device by its channel number.
+ *
+ * We need this critical flag because we change
+ * the dlci_to_dev_map outside the interrupt.
+ *
+ * NOTE: del_if() functions updates this array, it uses
+ * the spin locks to avoid corruption.
*/
-static struct net_device* find_channel (sdla_t* card, unsigned dlci)
+static netdevice_t* find_channel (sdla_t* card, unsigned dlci)
{
if(dlci > HIGHEST_VALID_DLCI)
return NULL;
@@ -2945,9 +3726,15 @@
struct sk_buff *skb, int dlci)
{
int udp_pkt_stored = 0;
-
- if(!card->u.f.udp_pkt_lgth &&(skb->len <= MAX_LGTH_UDP_MGNT_PKT)){
- card->u.f.udp_pkt_lgth = skb->len;
+
+ netdevice_t *dev=find_channel(card,dlci);
+ fr_channel_t *chan;
+
+ if (!dev || !(chan=dev->priv))
+ return 1;
+
+ if(!card->u.f.udp_pkt_lgth && (skb->len <= MAX_LGTH_UDP_MGNT_PKT)){
+ card->u.f.udp_pkt_lgth = skb->len + chan->fr_header_len;
card->u.f.udp_type = udp_type;
card->u.f.udp_pkt_src = udp_pkt_src;
card->u.f.udp_dlci = dlci;
@@ -2960,8 +3747,12 @@
dlci);
}
- dev_kfree_skb(skb);
-
+ if(udp_pkt_src == UDP_PKT_FRM_STACK){
+ wan_dev_kfree_skb(skb, FREE_WRITE);
+ }else{
+ wan_dev_kfree_skb(skb, FREE_READ);
+ }
+
return(udp_pkt_stored);
}
@@ -2982,7 +3773,7 @@
int err;
struct timeval tv;
int udp_mgmt_req_valid = 1;
- struct net_device* dev;
+ netdevice_t* dev;
fr_channel_t* chan;
fr_udp_pkt_t *fr_udp_pkt;
unsigned short num_trc_els;
@@ -2995,7 +3786,14 @@
/* Find network interface for this packet */
dev = find_channel(card, dlci);
- chan = dev->priv;
+ if (!dev){
+ card->u.f.udp_pkt_lgth = 0;
+ return 1;
+ }
+ if ((chan = dev->priv) == NULL){
+ card->u.f.udp_pkt_lgth = 0;
+ return 1;
+ }
/* If the UDP packet is from the network, we are going to have to
transmit a response. Before doing so, we must check to see that
@@ -3003,39 +3801,49 @@
that we are not already in a 'delayed transmit' state.
*/
if(udp_pkt_src == UDP_PKT_FRM_NETWORK) {
- if (test_bit(0, (void*)&card->wandev.critical) ||
- test_bit(2, (void*)&card->wandev.critical)) {
- return 0;
- }
- if((netif_queue_stopped(dev)) || (card->u.f.tx_interrupts_pending)) {
- return 0;
+ if (check_tx_status(card,dev)){
+ card->u.f.udp_pkt_lgth = 0;
+ return 1;
}
}
fr_udp_pkt = (fr_udp_pkt_t *)card->u.f.udp_pkt_data;
- switch(fr_udp_pkt->cblock.command) {
+ if(udp_pkt_src == UDP_PKT_FRM_NETWORK) {
+
+ switch(fr_udp_pkt->cblock.command) {
- case FPIPE_ENABLE_TRACING:
- case FPIPE_DISABLE_TRACING:
- case FPIPE_GET_TRACE_INFO:
- case FR_SET_FT1_MODE:
- if(udp_pkt_src == UDP_PKT_FRM_NETWORK) {
- chan->drvstats_gen.
- UDP_PIPE_mgmt_direction_err ++;
+ case FR_READ_MODEM_STATUS:
+ case FR_READ_STATUS:
+ case FPIPE_ROUTER_UP_TIME:
+ case FR_READ_ERROR_STATS:
+ case FPIPE_DRIVER_STAT_GEN:
+ case FR_READ_STATISTICS:
+ case FR_READ_ADD_DLC_STATS:
+ case FR_READ_CONFIG:
+ case FR_READ_CODE_VERSION:
+ udp_mgmt_req_valid = 1;
+ break;
+ default:
udp_mgmt_req_valid = 0;
break;
- }
-
- default:
- break;
- }
+ }
+ }
if(!udp_mgmt_req_valid) {
/* set length to 0 */
fr_udp_pkt->cblock.length = 0;
/* set return code */
fr_udp_pkt->cblock.result = 0xCD;
+
+ chan->drvstats_gen.UDP_PIPE_mgmt_direction_err ++;
+
+ if (net_ratelimit()){
+ printk(KERN_INFO
+ "%s: Warning, Illegal UDP command attempted from network: %x\n",
+ card->devname,fr_udp_pkt->cblock.command);
+ }
+
} else {
switch(fr_udp_pkt->cblock.command) {
@@ -3074,7 +3882,7 @@
/* Calculate the maximum trace data area in */
/* the UDP packet */
card->u.f.trc_bfr_space=(MAX_LGTH_UDP_MGNT_PKT -
- sizeof(fr_encap_hdr_t) -
+ //sizeof(fr_encap_hdr_t) -
sizeof(ip_pkt_t) -
sizeof(udp_pkt_t) -
sizeof(wp_mgmt_t) -
@@ -3204,7 +4012,7 @@
case FPIPE_FT1_READ_STATUS:
sdla_peek(&card->hw, 0xF020,
&fr_udp_pkt->data[0x00] , 2);
- fr_udp_pkt->cblock.length = 2;
+ fr_udp_pkt->cblock.length = mbox->cmd.length = 2;
fr_udp_pkt->cblock.result = 0;
break;
@@ -3220,44 +4028,32 @@
chan->router_start_time;
*(unsigned long *)&fr_udp_pkt->data =
chan->router_up_time;
- mbox->cmd.length = 4;
+ mbox->cmd.length = fr_udp_pkt->cblock.length = 4;
+ fr_udp_pkt->cblock.result = 0;
break;
-
- case FR_FT1_STATUS_CTRL:
- if(fr_udp_pkt->data[0] == 1) {
- if(rCount++ != 0 ){
- fr_udp_pkt->cblock.result = 0;
- mbox->cmd.length = 1;
- break;
- }
- }
-
- /* Disable FT1 MONITOR STATUS */
- if(fr_udp_pkt->data[0] == 0) {
- if( --rCount != 0) {
- fr_udp_pkt->cblock.result = 0;
- mbox->cmd.length = 1;
- break;
- }
- }
-
case FPIPE_DRIVER_STAT_IFSEND:
memcpy(fr_udp_pkt->data,
&chan->drvstats_if_send.if_send_entry,
sizeof(if_send_stat_t));
- mbox->cmd.length = sizeof(if_send_stat_t);
+ mbox->cmd.length = fr_udp_pkt->cblock.length =sizeof(if_send_stat_t);
+ fr_udp_pkt->cblock.result = 0;
break;
case FPIPE_DRIVER_STAT_INTR:
+
memcpy(fr_udp_pkt->data,
&card->statistics.isr_entry,
sizeof(global_stats_t));
+
memcpy(&fr_udp_pkt->data[sizeof(global_stats_t)],
&chan->drvstats_rx_intr.rx_intr_no_socket,
sizeof(rx_intr_stat_t));
- mbox->cmd.length = sizeof(global_stats_t) +
+
+ mbox->cmd.length = fr_udp_pkt->cblock.length =
+ sizeof(global_stats_t) +
sizeof(rx_intr_stat_t);
+ fr_udp_pkt->cblock.result = 0;
break;
case FPIPE_DRIVER_STAT_GEN:
@@ -3268,13 +4064,34 @@
memcpy(&fr_udp_pkt->data[sizeof(pipe_mgmt_stat_t)],
&card->statistics, sizeof(global_stats_t));
- fr_udp_pkt->cblock.result = 0;
- fr_udp_pkt->cblock.length = sizeof(global_stats_t)+
+ mbox->cmd.length = fr_udp_pkt->cblock.length = sizeof(global_stats_t)+
sizeof(rx_intr_stat_t);
- mbox->cmd.length = fr_udp_pkt->cblock.length;
+ fr_udp_pkt->cblock.result = 0;
break;
-
+
+
+ case FR_FT1_STATUS_CTRL:
+ if(fr_udp_pkt->data[0] == 1) {
+ if(rCount++ != 0 ){
+ fr_udp_pkt->cblock.result = 0;
+ mbox->cmd.length = 1;
+ break;
+ }
+ }
+
+ /* Disable FT1 MONITOR STATUS */
+ if(fr_udp_pkt->data[0] == 0) {
+ if( --rCount != 0) {
+ fr_udp_pkt->cblock.result = 0;
+ mbox->cmd.length = 1;
+ break;
+ }
+ }
+ goto udp_mgmt_dflt;
+
+
default:
+udp_mgmt_dflt:
do {
memcpy(&mbox->cmd,
&fr_udp_pkt->cblock.command,
@@ -3312,12 +4129,19 @@
len = reply_udp(card->u.f.udp_pkt_data, mbox->cmd.length);
if(udp_pkt_src == UDP_PKT_FRM_NETWORK) {
-
- err = fr_send(card, dlci, 0, len, card->u.f.udp_pkt_data);
- if (err)
+
+ chan->fr_header_len=2;
+ chan->fr_header[0]=Q922_UI;
+ chan->fr_header[1]=NLPID_IP;
+
+ err = fr_send_data_header(card, dlci, 0, len,
+ card->u.f.udp_pkt_data,chan->fr_header_len);
+ if (err){
chan->drvstats_gen.UDP_PIPE_mgmt_adptr_send_passed ++;
- else
+ }else{
chan->drvstats_gen.UDP_PIPE_mgmt_adptr_send_failed ++;
+ }
+
} else {
/* Allocate socket buffer */
if((new_skb = dev_alloc_skb(len)) != NULL) {
@@ -3326,22 +4150,12 @@
buf = skb_put(new_skb, len);
memcpy(buf, card->u.f.udp_pkt_data, len);
- /* Decapsulate packet and pass it up the protocol
- stack */
+ chan->drvstats_gen.
+ UDP_PIPE_mgmt_passed_to_stack ++;
new_skb->dev = dev;
- buf = skb_pull(new_skb, 1); /* remove hardware header*/
-
- if(!wanrouter_type_trans(new_skb, dev)) {
-
- chan->drvstats_gen.
- UDP_PIPE_mgmt_not_passed_to_stack ++;
- /* can't decapsulate packet */
- dev_kfree_skb(new_skb);
- } else {
- chan->drvstats_gen.
- UDP_PIPE_mgmt_passed_to_stack ++;
- netif_rx(new_skb);
- }
+ new_skb->protocol = htons(ETH_P_IP);
+ new_skb->mac.raw = new_skb->data;
+ netif_rx(new_skb);
} else {
chan->drvstats_gen.UDP_PIPE_mgmt_no_socket ++;
@@ -3360,15 +4174,19 @@
* Send Inverse ARP Request
*/
-int send_inarp_request(sdla_t *card, struct net_device *dev)
+int send_inarp_request(sdla_t *card, netdevice_t *dev)
{
+ int err=0;
+
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
+
arphdr_1490_t *ArpPacket;
arphdr_fr_t *arphdr;
fr_channel_t *chan = dev->priv;
struct in_device *in_dev;
in_dev = dev->ip_ptr;
-
+
if(in_dev != NULL ) {
ArpPacket = kmalloc(sizeof(arphdr_1490_t) + sizeof(arphdr_fr_t), GFP_ATOMIC);
@@ -3396,16 +4214,66 @@
arphdr->ar_tha = 0; /* dst HW DLCI - Doesn't matter */
arphdr->ar_tip = 0; /* Remote Address -- what we want */
- printk(KERN_INFO "%s: Sending InARP request on DLCI %d.\n", card->devname, chan->dlci);
- fr_send(card, chan->dlci, 0,
- sizeof(arphdr_1490_t) + sizeof(arphdr_fr_t),
- (void *)ArpPacket);
+ err = fr_send(card, chan->dlci, 0, sizeof(arphdr_1490_t) + sizeof(arphdr_fr_t),
+ (void *)ArpPacket);
+
+ if (!err){
+ printk(KERN_INFO "\n%s: Sending InARP request on DLCI %d.\n",
+ card->devname, chan->dlci);
+ clear_bit(ARP_CRIT,&card->wandev.critical);
+ }
+
kfree(ArpPacket);
+ }else{
+ printk(KERN_INFO "%s: INARP ERROR: %s doesn't have a local IP address!\n",
+ card->devname,dev->name);
+ return 1;
}
- return 1;
-}
-
+#else
+ arphdr_1490_t *ArpPacket;
+ arphdr_fr_t *arphdr;
+ fr_channel_t *chan = dev->priv;
+
+ ArpPacket = kmalloc(sizeof(arphdr_1490_t) + sizeof(arphdr_fr_t), GFP_ATOMIC);
+ /* SNAP Header indicating ARP */
+ ArpPacket->control = 0x03;
+ ArpPacket->pad = 0x00;
+ ArpPacket->NLPID = 0x80;
+ ArpPacket->OUI[0] = 0;
+ ArpPacket->OUI[1] = 0;
+ ArpPacket->OUI[2] = 0;
+ ArpPacket->PID = 0x0608;
+
+ arphdr = (arphdr_fr_t *)(ArpPacket + 1); // Go to ARP Packet
+ /* InARP request */
+ arphdr->ar_hrd = 0x0F00; /* Frame Relay HW type */
+ arphdr->ar_pro = 0x0008; /* IP Protocol */
+ arphdr->ar_hln = 2; /* HW addr length */
+ arphdr->ar_pln = 4; /* IP addr length */
+ arphdr->ar_op = htons(0x08); /* InARP Request */
+ arphdr->ar_sha = 0; /* src HW DLCI - Doesn't matter */
+ arphdr->ar_sip = dev->pa_addr; /* Local Address */
+ arphdr->ar_tha = 0; /* dst HW DLCI - Doesn't matter */
+ arphdr->ar_tip = 0; /* Remote Address -- what we want */
+
+ printk(KERN_INFO "%s: Sending InARP request on DLCI %d.\n", card->devname, chan->dlci);
+ err = fr_send(card, chan->dlci, 0,
+ sizeof(arphdr_1490_t) + sizeof(arphdr_fr_t),
+ (void *)ArpPacket);
+
+ if (!err){
+ printk(KERN_INFO "\n%s: Sending InARP request on DLCI %d.\n",
+ card->devname, chan->dlci);
+ clear_bit(ARP_CRIT,&card->wandev.critical);
+ }
+
+ kfree(ArpPacket);
+#endif
+
+ return 0;
+}
+
/*==============================================================================
* Check packet for ARP Type
@@ -3426,123 +4294,289 @@
* Process ARP Packet Type
*/
-int process_ARP(arphdr_1490_t *ArpPacket, sdla_t *card, struct net_device* dev)
+int process_ARP(arphdr_1490_t *ArpPacket, sdla_t *card, netdevice_t* dev)
{
+
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
arphdr_fr_t *arphdr = (arphdr_fr_t *)(ArpPacket + 1); /* Skip header */
fr_rx_buf_ctl_t* frbuf = card->rxmb;
struct in_device *in_dev;
+ fr_channel_t *chan = dev->priv;
+#else
+ arphdr_fr_t *arphdr = (arphdr_fr_t *)(ArpPacket + 1); /* Skip header */
+ fr_rx_buf_ctl_t* frbuf = card->rxmb;
+#endif
+
+ /* Before we transmit ARP packet, we must check
+ * to see that we are not currently transmitting a
+ * frame (in 'if_send()') and that we are not
+ * already in a 'delayed transmit' state. */
+ if (check_tx_status(card,dev)){
+ if (net_ratelimit()){
+ printk(KERN_INFO "%s: Disabling comminication to process ARP\n",
+ card->devname);
+ }
+ set_bit(ARP_CRIT,&card->wandev.critical);
+ return 0;
+ }
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
in_dev = dev->ip_ptr;
- if( in_dev != NULL && in_dev->ifa_list != NULL) {
- switch (ntohs(arphdr->ar_op)) {
- case 0x08: // Inverse ARP request -- Send Reply, add route.
+ /* Check that IP addresses exist for our network address */
+ if (in_dev == NULL || in_dev->ifa_list == NULL)
+ return -1;
+
+ switch (ntohs(arphdr->ar_op)) {
+
+ case 0x08: // Inverse ARP request -- Send Reply, add route.
- /* Check for valid Address */
- printk(KERN_INFO "%s: Recvd PtP addr %s -InArp Req\n", ((fr_channel_t *)dev->priv)->name, in_ntoa(arphdr->ar_sip));
+ /* Check for valid Address */
+ printk(KERN_INFO "%s: Recvd PtP addr -InArp Req: %s\n",
+ card->devname, in_ntoa(arphdr->ar_sip));
- if ((in_dev->ifa_list->ifa_mask & arphdr->ar_sip) != (in_dev->ifa_list->ifa_mask & in_dev->ifa_list->ifa_local)) {
- printk(KERN_INFO "%s: Invalid PtP address. InARP ignored.\n", card->devname);
- printk(KERN_INFO "mask %X\n", in_dev->ifa_list->ifa_mask);
- printk(KERN_INFO "local %X\n", in_dev->ifa_list->ifa_local);
- return -1;
- }
-
- if (in_dev->ifa_list->ifa_local == arphdr->ar_sip) {
- printk(KERN_INFO "%s: Local addr = PtP addr. InARP ignored.\n", card->devname);
- return -1;
- }
+
+ /* Check that the network address is the same as ours, only
+ * if the netowrk mask is not 255.255.255.255. Otherwise
+ * this check would not make sense */
+
+ if (in_dev->ifa_list->ifa_mask != 0xFFFFFFFF &&
+ (in_dev->ifa_list->ifa_mask & arphdr->ar_sip) !=
+ (in_dev->ifa_list->ifa_mask & in_dev->ifa_list->ifa_local)){
+
+ printk(KERN_INFO
+ "%s: Invalid PtP address. %s InARP ignored.\n",
+ card->devname,in_ntoa(arphdr->ar_sip));
+
+ printk(KERN_INFO "%s: mask %s\n",
+ card->devname, in_ntoa(in_dev->ifa_list->ifa_mask));
+ printk(KERN_INFO "%s: local %s\n",
+ card->devname,in_ntoa(in_dev->ifa_list->ifa_local));
+ return -1;
+ }
+
+ if (in_dev->ifa_list->ifa_local == arphdr->ar_sip){
+ printk(KERN_INFO
+ "%s: Local addr = PtP addr. InARP ignored.\n",
+ card->devname);
+ return -1;
+ }
- arphdr->ar_op = htons(0x09); /* InARP Reply */
+ arphdr->ar_op = htons(0x09); /* InARP Reply */
- /* Set addresses */
- arphdr->ar_tip = arphdr->ar_sip;
- arphdr->ar_sip = in_dev->ifa_list->ifa_local;
+ /* Set addresses */
+ arphdr->ar_tip = arphdr->ar_sip;
+ arphdr->ar_sip = in_dev->ifa_list->ifa_local;
- fr_send(card, frbuf->dlci, 0, frbuf->length, (void *)ArpPacket);
+ chan->ip_local = in_dev->ifa_list->ifa_local;
+ chan->ip_remote = arphdr->ar_sip;
- /* Modify Point-to-Point Address */
- {
- struct ifreq if_info;
- struct sockaddr_in *if_data;
- mm_segment_t fs = get_fs();
- int err;
-
- /* Set remote addresses */
- memset(&if_info, 0, sizeof(if_info));
- strcpy(if_info.ifr_name, dev->name);
-
- set_fs(get_ds()); /* get user space block */
-
- if_data = (struct sockaddr_in *)&if_info.ifr_dstaddr;
- if_data->sin_addr.s_addr = arphdr->ar_tip;
- if_data->sin_family = AF_INET;
- err = devinet_ioctl( SIOCSIFDSTADDR, &if_info );
+ fr_send(card, frbuf->dlci, 0, frbuf->length, (void *)ArpPacket);
- set_fs(fs); /* restore old block */
+ if (test_bit(ARP_CRIT,&card->wandev.critical)){
+ if (net_ratelimit()){
+ printk(KERN_INFO "%s: ARP Processed Enabling Communication!\n",
+ card->devname);
}
-
- /* Add Route Flag */
- /* The route will be added in the polling routine so
- that it is not interrupt context. */
+ }
+ clear_bit(ARP_CRIT,&card->wandev.critical);
+
+ chan->ip_local = in_dev->ifa_list->ifa_local;
+ chan->ip_remote = arphdr->ar_sip;
- ((fr_channel_t *) dev->priv)->route_flag = ADD_ROUTE;
- card->poll = &process_route;
+ /* Add Route Flag */
+ /* The route will be added in the polling routine so
+ that it is not interrupt context. */
- break;
+ chan->route_flag = ADD_ROUTE;
+ trigger_fr_poll (dev);
- case 0x09: // Inverse ARP reply
+ break;
- /* Check for valid Address */
- printk(KERN_INFO "%s: Recvd PtP addr %s -InArp Reply\n", ((fr_channel_t *)dev->priv)->name, in_ntoa(arphdr->ar_sip));
+ case 0x09: // Inverse ARP reply
- if ((in_dev->ifa_list->ifa_mask & arphdr->ar_sip) != (in_dev->ifa_list->ifa_mask & in_dev->ifa_list->ifa_local)) {
- printk(KERN_INFO "%s: Invalid PtP address. InARP ignored.\n", card->devname);
- return -1;
- }
+ /* Check for valid Address */
+ printk(KERN_INFO "%s: Recvd PtP addr %s -InArp Reply\n",
+ card->devname, in_ntoa(arphdr->ar_sip));
- if (in_dev->ifa_list->ifa_local == arphdr->ar_sip) {
- printk(KERN_INFO "%s: Local addr = PtP addr. InARP ignored.\n", card->devname);
- return -1;
- }
- /* Modify Point-to-Point Address */
- {
- struct ifreq if_info;
- struct sockaddr_in *if_data;
- mm_segment_t fs = get_fs();
- int err;
+ /* Compare network addresses, only if network mask
+ * is not 255.255.255.255 It would not make sense
+ * to perform this test if the mask was all 1's */
- /* Set remote addresses */
- memset(&if_info, 0, sizeof(if_info));
- strcpy(if_info.ifr_name, dev->name);
+ if (in_dev->ifa_list->ifa_mask != 0xffffffff &&
+ (in_dev->ifa_list->ifa_mask & arphdr->ar_sip) !=
+ (in_dev->ifa_list->ifa_mask & in_dev->ifa_list->ifa_local)) {
- set_fs(get_ds()); /* get user space block */
-
- if_data = (struct sockaddr_in *)&if_info.ifr_dstaddr;
- if_data->sin_addr.s_addr = arphdr->ar_sip;
- if_data->sin_family = AF_INET;
- err = devinet_ioctl( SIOCSIFDSTADDR, &if_info );
+ printk(KERN_INFO "%s: Invalid PtP address. InARP ignored.\n",
+ card->devname);
+ return -1;
+ }
- set_fs(fs); /* restore old block */
- }
+ /* Make sure that the received IP address is not
+ * the same as our own local address */
+ if (in_dev->ifa_list->ifa_local == arphdr->ar_sip) {
+ printk(KERN_INFO "%s: Local addr = PtP addr. InARP ignored.\n",
+ card->devname);
+ return -1;
+ }
- /* Add Route Flag */
- /* The route will be added in the polling routine so
- that it is not interrupt context. */
+ chan->ip_local = in_dev->ifa_list->ifa_local;
+ chan->ip_remote = arphdr->ar_sip;
- ((fr_channel_t *) dev->priv)->route_flag = ADD_ROUTE;
- ((fr_channel_t *) dev->priv)->inarp = INARP_CONFIGURED;
- card->poll = &process_route;
-
- break;
- default: // ARP's and RARP's -- Shouldn't happen.
- }
+ /* Add Route Flag */
+ /* The route will be added in the polling routine so
+ that it is not interrupt context. */
+
+ chan->route_flag = ADD_ROUTE;
+ chan->inarp = INARP_CONFIGURED;
+ trigger_fr_poll(dev);
+
+ break;
+ default: // ARP's and RARP's -- Shouldn't happen.
}
return 0;
+#else
+
+ switch (ntohs(arphdr->ar_op)) {
+
+ case 0x08: // Inverse ARP request -- Send Reply, add route.
+
+ /* Check for valid Address */
+ printk(KERN_INFO "%s: Recvd PtP addr %s -InArp Req\n",
+ ((fr_channel_t *)dev->priv)->name, in_ntoa(arphdr->ar_sip));
+
+
+ if (dev->pa_mask != 0xFFFFFFFF){
+
+ if ((dev->pa_mask & arphdr->ar_sip) != (dev->pa_mask & dev->pa_addr)) {
+ printk(KERN_INFO "%s: Invalid PtP address. InARP ignored.\n",
+ card->devname);
+ return -1;
+ }
+ }
+
+ if (dev->pa_addr == arphdr->ar_sip) {
+ printk(KERN_INFO "%s: Local addr = PtP addr. InARP ignored.\n",
+ card->devname);
+ return -1;
+ }
+
+ arphdr->ar_op = htons(0x09); /* InARP Reply */
+
+ /* Set addresses */
+ arphdr->ar_tip = arphdr->ar_sip;
+ arphdr->ar_sip = dev->pa_addr;
+
+ fr_send(card, frbuf->dlci, 0, frbuf->length, (void *)ArpPacket);
+
+ clear_bit(ARP_CRIT,&card->wandev.critical);
+
+ /* Modify Point-to-Point Address */
+ dev->pa_dstaddr = arphdr->ar_tip;
+
+ /* Add Route Flag */
+ /* The route will be added in the polling routine so
+ that it is not interrupt context. */
+ ((fr_channel_t *) dev->priv)->route_flag = ADD_ROUTE;
+ trigger_fr_poll(dev);
+
+ break;
+ case 0x09: // Inverse ARP reply
+
+ /* Check for valid Address */
+ printk(KERN_INFO "%s: Recvd PtP addr %s -InArp Reply\n",
+ ((fr_channel_t *)dev->priv)->name, in_ntoa(arphdr->ar_sip));
+
+ if ((dev->pa_mask & arphdr->ar_sip) != (dev->pa_mask & dev->pa_addr)) {
+ printk(KERN_INFO "%s: Invalid PtP address. InARP ignored.\n",
+ card->devname);
+ return -1;
+ }
+
+ if (dev->pa_addr == arphdr->ar_sip) {
+ printk(KERN_INFO "%s: Local addr = PtP addr. InARP ignored.\n",
+ card->devname);
+ return -1;
+ }
+
+ /* Modify Point-to-Point Address */
+ dev->pa_dstaddr = arphdr->ar_sip;
+ /* Add Route Flag */
+ /* The route will be added in the polling routine so
+ that it is not interrupt context. */
+
+ ((fr_channel_t *) dev->priv)->route_flag = ADD_ROUTE;
+ ((fr_channel_t *) dev->priv)->inarp = INARP_CONFIGURED;
+ trigger_fr_poll(dev);
+
+ break;
+ default: // ARP's and RARP's -- Shouldn't happen.
+ }
+
+ return 0;
+
+#endif
+}
+
+
+/*============================================================
+ * trigger_fr_arp
+ *
+ * Description:
+ * Add an fr_arp() task into a arp
+ * timer handler for a specific dlci/interface.
+ * This will kick the fr_arp() routine
+ * within the specified time interval.
+ *
+ * Usage:
+ * This timer is used to send ARP requests at
+ * certain time intervals.
+ * Called by an interrupt to request an action
+ * at a later date.
+ */
+
+static void trigger_fr_arp (netdevice_t *dev)
+{
+ fr_channel_t* chan = dev->priv;
+
+ del_timer(&chan->fr_arp_timer);
+ chan->fr_arp_timer.expires = jiffies + (chan->inarp_interval * HZ);
+ add_timer(&chan->fr_arp_timer);
+ return;
+}
+
+
+
+/*==============================================================================
+ * ARP Request Action
+ *
+ * This funciton is called by timer interrupt to send an arp request
+ * to the remote end.
+ */
+
+static void fr_arp (unsigned long data)
+{
+ netdevice_t *dev = (netdevice_t *)data;
+ fr_channel_t *chan = dev->priv;
+ volatile sdla_t *card = chan->card;
+ fr508_flags_t* flags = card->flags;
+
+ /* Send ARP packets for all devs' until
+ * ARP state changes to CONFIGURED */
+
+ if (chan->inarp == INARP_REQUEST &&
+ chan->common.state == WAN_CONNECTED &&
+ card->wandev.state == WAN_CONNECTED){
+ set_bit(0,&chan->inarp_ready);
+ card->u.f.timer_int_enabled |= TMR_INT_ENABLED_ARP;
+ flags->imask |= FR_INTR_TIMER;
+ }
+
+ return;
}
@@ -3555,11 +4589,6 @@
fr_mbox_t* mb = card->mbox;
int err,i;
- /* The critical flag is unset here because we want to get into the
- ISR without the flag already set. The If_open sets the flag.
- */
- clear_bit(1, (void*)&card->wandev.critical);
-
err = fr_set_intr_mode(card, FR_INTR_READY, card->wandev.mtu, 0 );
if (err == CMD_OK) {
@@ -3582,7 +4611,6 @@
if( err != CMD_OK )
return err;
- set_bit(1, (void*)&card->wandev.critical);
return 0;
}
@@ -3593,6 +4621,9 @@
{
fr_udp_pkt_t *fr_udp_pkt = (fr_udp_pkt_t *)skb->data;
+ /* Quick HACK */
+
+
if((fr_udp_pkt->ip_pkt.protocol == UDPMGMT_UDP_PROTOCOL) &&
(fr_udp_pkt->ip_pkt.ver_inet_hdr_length == 0x45) &&
(fr_udp_pkt->udp_pkt.udp_dst_port ==
@@ -3600,10 +4631,10 @@
(fr_udp_pkt->wp_mgmt.request_reply ==
UDPMGMT_REQUEST)) {
if(!strncmp(fr_udp_pkt->wp_mgmt.signature,
- UDPMGMT_FPIPE_SIGNATURE, 8))
+ UDPMGMT_FPIPE_SIGNATURE, 8)){
return UDP_FPIPE_TYPE;
+ }
}
-
return UDP_INVALID_TYPE;
}
@@ -3674,38 +4705,772 @@
card->devname, chan->dlci);
}
+
+
void s508_s514_lock(sdla_t *card, unsigned long *smp_flags)
{
-
if (card->hw.type != SDLA_S514){
-#ifdef CONFIG_SMP
- spin_lock_irqsave(&card->lock, *smp_flags);
+
+#if defined(__SMP__) || defined(LINUX_2_4)
+ spin_lock_irqsave(&card->wandev.lock, *smp_flags);
#else
- disable_irq(card->hw.irq);
+ disable_irq(card->hw.irq);
#endif
- }
-#ifdef CONFIG_SMP
- else{
- spin_lock(&card->lock);
- }
+ }else{
+#if defined(__SMP__) || defined(LINUX_2_4)
+ spin_lock(&card->u.f.if_send_lock);
#endif
+ }
+ return;
}
+
void s508_s514_unlock(sdla_t *card, unsigned long *smp_flags)
{
if (card->hw.type != SDLA_S514){
-#ifdef CONFIG_SMP
- spin_unlock_irqrestore(&card->lock, *smp_flags);
+
+#if defined(__SMP__) || defined(LINUX_2_4)
+ spin_unlock_irqrestore (&card->wandev.lock, *smp_flags);
#else
- enable_irq(card->hw.irq);
+ enable_irq(card->hw.irq);
+#endif
+ }else{
+#if defined(__SMP__) || defined(LINUX_2_4)
+ spin_unlock(&card->u.f.if_send_lock);
#endif
}
-#ifdef CONFIG_SMP
- else{
- spin_unlock(&card->lock);
+ return;
+}
+
+
+
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
+
+/*----------------------------------------------------------------------
+ RECEIVE INTERRUPT: BOTTOM HALF HANDLERS
+ ----------------------------------------------------------------------*/
+
+
+/*========================================================
+ * bh_enqueue
+ *
+ * Description:
+ * Insert a received packed into a circular
+ * rx queue. This packed will be picked up
+ * by fr_bh() and sent up the stack to the
+ * user.
+ *
+ * Usage:
+ * This function is called by rx interrupt,
+ * in API mode.
+ *
+ */
+
+static int bh_enqueue (netdevice_t *dev, struct sk_buff *skb)
+{
+ /* Check for full */
+ fr_channel_t* chan = dev->priv;
+ sdla_t *card = chan->card;
+
+
+ if (atomic_read(&chan->bh_buff_used) == MAX_BH_BUFF){
+ ++card->wandev.stats.rx_dropped;
+ wan_dev_kfree_skb(skb, FREE_READ);
+ return 1;
+ }
+
+ ((bh_data_t *)&chan->bh_head[chan->bh_write])->skb = skb;
+
+ if (chan->bh_write == (MAX_BH_BUFF-1)){
+ chan->bh_write=0;
+ }else{
+ ++chan->bh_write;
+ }
+
+ atomic_inc(&chan->bh_buff_used);
+
+ return 0;
+}
+
+
+/*========================================================
+ * trigger_fr_bh
+ *
+ * Description:
+ * Kick the fr_bh() handler
+ *
+ * Usage:
+ * rx interrupt calls this function during
+ * the API mode.
+ */
+
+static void trigger_fr_bh (fr_channel_t *chan)
+{
+ if (!test_and_set_bit(0,&chan->tq_working)){
+ wanpipe_queue_tq(&chan->common.wanpipe_task);
+ wanpipe_mark_bh();
+ }
+}
+
+
+/*========================================================
+ * fr_bh
+ *
+ * Description:
+ * Frame relay receive BH handler.
+ * Dequeue data from the BH circular
+ * buffer and pass it up the API sock.
+ *
+ * Rationale:
+ * This fuction is used to offload the
+ * rx_interrupt during API operation mode.
+ * The fr_bh() function executes for each
+ * dlci/interface.
+ *
+ * Once receive interrupt copies data from the
+ * card into an skb buffer, the skb buffer
+ * is appended to a circular BH buffer.
+ * Then the interrupt kicks fr_bh() to finish the
+ * job at a later time (no within the interrupt).
+ *
+ * Usage:
+ * Interrupts use this to defer a taks to
+ * a polling routine.
+ *
+ */
+
+static void fr_bh (netdevice_t * dev)
+{
+ fr_channel_t* chan = dev->priv;
+ sdla_t *card = chan->card;
+ struct sk_buff *skb;
+
+ if (atomic_read(&chan->bh_buff_used) == 0){
+ clear_bit(0, &chan->tq_working);
+ return;
+ }
+
+ while (atomic_read(&chan->bh_buff_used)){
+
+ if (chan->common.sk == NULL || chan->common.func == NULL){
+ clear_bit(0, &chan->tq_working);
+ return;
+ }
+
+ skb = ((bh_data_t *)&chan->bh_head[chan->bh_read])->skb;
+
+ if (skb != NULL){
+
+ if (chan->common.sk == NULL || chan->common.func == NULL){
+ ++card->wandev.stats.rx_dropped;
+ ++chan->ifstats.rx_dropped;
+ wan_dev_kfree_skb(skb, FREE_READ);
+ fr_bh_cleanup(dev);
+ continue;
+ }
+
+ if (chan->common.func(skb,dev,chan->common.sk) != 0){
+ /* Sock full cannot send, queue us for
+ * another try */
+ atomic_set(&chan->common.receive_block,1);
+ return;
+ }else{
+ fr_bh_cleanup(dev);
+ }
+ }else{
+ fr_bh_cleanup(dev);
+ }
}
+ clear_bit(0, &chan->tq_working);
+
+ return;
+}
+
+static int fr_bh_cleanup (netdevice_t *dev)
+{
+ fr_channel_t* chan = dev->priv;
+
+ ((bh_data_t *)&chan->bh_head[chan->bh_read])->skb = NULL;
+
+ if (chan->bh_read == (MAX_BH_BUFF-1)){
+ chan->bh_read=0;
+ }else{
+ ++chan->bh_read;
+ }
+
+ atomic_dec(&chan->bh_buff_used);
+ return 0;
+}
+#endif
+
+
+/*----------------------------------------------------------------------
+ POLL BH HANDLERS AND KICK ROUTINES
+ ----------------------------------------------------------------------*/
+
+/*============================================================
+ * trigger_fr_poll
+ *
+ * Description:
+ * Add a fr_poll() task into a tq_scheduler bh handler
+ * for a specific dlci/interface. This will kick
+ * the fr_poll() routine at a later time.
+ *
+ * Usage:
+ * Interrupts use this to defer a taks to
+ * a polling routine.
+ *
+ */
+static void trigger_fr_poll (netdevice_t *dev)
+{
+ fr_channel_t* chan = dev->priv;
+#ifdef LINUX_2_4
+ schedule_task(&chan->fr_poll_task);
+#else
+ queue_task(&chan->fr_poll_task, &tq_scheduler);
+#endif
+ return;
+}
+
+
+/*============================================================
+ * fr_poll
+ *
+ * Rationale:
+ * We cannot manipulate the routing tables, or
+ * ip addresses withing the interrupt. Therefore
+ * we must perform such actons outside an interrupt
+ * at a later time.
+ *
+ * Description:
+ * Frame relay polling routine, responsible for
+ * shutting down interfaces upon disconnect
+ * and adding/removing routes.
+ *
+ * Usage:
+ * This function is executed for each frame relay
+ * dlci/interface through a tq_schedule bottom half.
+ *
+ * trigger_fr_poll() function is used to kick
+ * the fr_poll routine.
+ */
+
+static void fr_poll (netdevice_t *dev)
+{
+
+ fr_channel_t* chan;
+ sdla_t *card;
+ u8 check_gateway=0;
+
+ if (!dev || (chan = dev->priv) == NULL)
+ return;
+
+ card = chan->card;
+
+ /* (Re)Configuraiton is in progress, stop what you are
+ * doing and get out */
+ if (test_bit(PERI_CRIT,&card->wandev.critical)){
+ return;
+ }
+
+ switch (chan->common.state){
+
+ case WAN_DISCONNECTED:
+
+ if (test_bit(DYN_OPT_ON,&chan->interface_down) &&
+ !test_bit(DEV_DOWN, &chan->interface_down) &&
+ dev->flags&IFF_UP){
+
+ printk(KERN_INFO "%s: Interface %s is Down.\n",
+ card->devname,dev->name);
+ change_dev_flags(dev,dev->flags&~IFF_UP);
+ set_bit(DEV_DOWN, &chan->interface_down);
+ chan->route_flag = NO_ROUTE;
+
+ }else{
+ if (chan->inarp != INARP_NONE)
+ process_route(dev);
+ }
+ break;
+
+ case WAN_CONNECTED:
+
+ if (test_bit(DYN_OPT_ON,&chan->interface_down) &&
+ test_bit(DEV_DOWN, &chan->interface_down) &&
+ !(dev->flags&IFF_UP)){
+
+ printk(KERN_INFO "%s: Interface %s is Up.\n",
+ card->devname,dev->name);
+
+ change_dev_flags(dev,dev->flags|IFF_UP);
+ clear_bit(DEV_DOWN, &chan->interface_down);
+ check_gateway=1;
+ }
+
+ if (chan->inarp != INARP_NONE){
+ process_route(dev);
+ check_gateway=1;
+ }
+
+ if (chan->gateway && check_gateway)
+ add_gateway(card,dev);
+
+ break;
+
+ }
+
+ return;
+}
+
+/*==============================================================
+ * check_tx_status
+ *
+ * Rationale:
+ * We cannot transmit from an interrupt while
+ * the if_send is transmitting data. Therefore,
+ * we must check whether the tx buffers are
+ * begin used, before we transmit from an
+ * interrupt.
+ *
+ * Description:
+ * Checks whether it's safe to use the transmit
+ * buffers.
+ *
+ * Usage:
+ * ARP and UDP handling routines use this function
+ * because, they need to transmit data during
+ * an interrupt.
+ */
+
+static int check_tx_status(sdla_t *card, netdevice_t *dev)
+{
+
+ if (card->hw.type == SDLA_S514){
+ if (test_bit(SEND_CRIT, (void*)&card->wandev.critical) ||
+ test_bit(SEND_TXIRQ_CRIT, (void*)&card->wandev.critical)) {
+ return 1;
+ }
+ }
+
+ if (is_queue_stopped(dev) || (card->u.f.tx_interrupts_pending))
+ return 1;
+
+ return 0;
+}
+
+/*===============================================================
+ * move_dev_to_next
+ *
+ * Description:
+ * Move the dev pointer to the next location in the
+ * link list. Check if we are at the end of the
+ * list, if so start from the begining.
+ *
+ * Usage:
+ * Timer interrupt uses this function to efficiently
+ * step through the devices that need to send ARP data.
+ *
+ */
+
+netdevice_t * move_dev_to_next (sdla_t *card, netdevice_t *dev)
+{
+ if (card->wandev.new_if_cnt != 1){
+ if (*((netdevice_t **)dev->priv) == NULL){
+ return card->wandev.dev;
+ }else{
+ return *((netdevice_t **)dev->priv);
+ }
+ }
+ return dev;
+}
+
+/*==============================================================
+ * trigger_config_fr
+ *
+ * Rationale:
+ * All commands must be performed inside of a
+ * interrupt.
+ *
+ * Description:
+ * Kick the config_fr() routine throught the
+ * timer interrupt.
+ */
+
+
+static void trigger_config_fr (sdla_t *card)
+{
+ fr508_flags_t* flags = card->flags;
+
+ card->u.f.timer_int_enabled |= TMR_INT_ENABLED_CONFIG;
+ flags->imask |= FR_INTR_TIMER;
+}
+
+
+/*==============================================================
+ * config_fr
+ *
+ * Rationale:
+ * All commands must be performed inside of a
+ * interrupt.
+ &
+ * Description:
+ * Configure a DLCI. This function is executed
+ * by a timer_interrupt. The if_open() function
+ * triggers it.
+ *
+ * Usage:
+ * new_if() collects all data necessary to
+ * configure the DLCI. It sets the chan->dlci_ready
+ * bit. When the if_open() function is executed
+ * it checks this bit, and if its set it triggers
+ * the timer interrupt to execute the config_fr()
+ * function.
+ */
+
+static void config_fr (sdla_t *card)
+{
+ netdevice_t *dev;
+ fr_channel_t *chan;
+
+ for (dev=card->wandev.dev; dev; dev=*((netdevice_t **)dev->priv)){
+
+ if ((chan=dev->priv) == NULL)
+ continue;
+
+ if (!test_bit(0,&chan->config_dlci))
+ continue;
+
+ clear_bit(0,&chan->config_dlci);
+
+ /* If signalling is set to NO, then setup
+ * DLCI addresses right away. Don't have to wait for
+ * link to connect.
+ */
+ if (card->wandev.signalling == WANOPT_NO){
+ printk(KERN_INFO "%s: Signalling set to NO: Mapping DLCI's\n",
+ card->wandev.name);
+ if (fr_init_dlci(card,chan)){
+ printk(KERN_INFO "%s: ERROR: Failed to configure DLCI %i !\n",
+ card->devname, chan->dlci);
+ return;
+ }
+ }
+
+ if (card->wandev.station == WANOPT_CPE) {
+
+ update_chan_state(dev);
+
+ /* CPE: issue full status enquiry */
+ fr_issue_isf(card, FR_ISF_FSE);
+
+ } else {
+ /* FR switch: activate DLCI(s) */
+
+ /* For Switch emulation we have to ADD and ACTIVATE
+ * the DLCI(s) that were configured with the SET_DLCI_
+ * CONFIGURATION command. Add and Activate will fail if
+ * DLCI specified is not included in the list.
+ *
+ * Also If_open is called once for each interface. But
+ * it does not get in here for all the interface. So
+ * we have to pass the entire list of DLCI(s) to add
+ * activate routines.
+ */
+
+ if (!check_dlci_config (card, chan)){
+ fr_add_dlci(card, chan->dlci);
+ fr_activate_dlci(card, chan->dlci);
+ }
+ }
+
+ card->u.f.dlci_to_dev_map[chan->dlci] = dev;
+ }
+ return;
+}
+
+
+/*==============================================================
+ * config_fr
+ *
+ * Rationale:
+ * All commands must be executed during an interrupt.
+ *
+ * Description:
+ * Trigger uncofig_fr() function through
+ * the timer interrupt.
+ *
+ */
+
+static void trigger_unconfig_fr (netdevice_t *dev)
+{
+ fr_channel_t *chan = dev->priv;
+ volatile sdla_t *card = chan->card;
+ u32 timeout;
+ fr508_flags_t* flags = card->flags;
+ int reset_critical=0;
+
+ if (test_bit(PERI_CRIT,(void*)&card->wandev.critical)){
+ clear_bit(PERI_CRIT,(void*)&card->wandev.critical);
+ reset_critical=1;
+ }
+
+ /* run unconfig_dlci() function
+ * throught the timer interrupt */
+ set_bit(0,(void*)&chan->unconfig_dlci);
+ card->u.f.timer_int_enabled |= TMR_INT_ENABLED_UNCONFIG;
+ flags->imask |= FR_INTR_TIMER;
+
+ /* Wait for the command to complete */
+ timeout = jiffies;
+ for(;;) {
+
+ if(!(card->u.f.timer_int_enabled & TMR_INT_ENABLED_UNCONFIG))
+ break;
+
+ if ((jiffies - timeout) > (1 * HZ)){
+ card->u.f.timer_int_enabled &= ~TMR_INT_ENABLED_UNCONFIG;
+ printk(KERN_INFO "%s: Failed to delete DLCI %i\n",
+ card->devname,chan->dlci);
+ break;
+ }
+ }
+
+ if (reset_critical){
+ set_bit(PERI_CRIT,(void*)&card->wandev.critical);
+ }
+}
+
+/*==============================================================
+ * unconfig_fr
+ *
+ * Rationale:
+ * All commands must be executed during an interrupt.
+ *
+ * Description:
+ * Remove the dlci from firmware.
+ * This funciton is used in NODE shutdown.
+ */
+
+static void unconfig_fr (sdla_t *card)
+{
+ netdevice_t *dev;
+ fr_channel_t *chan;
+
+ for (dev=card->wandev.dev; dev; dev=*((netdevice_t **)dev->priv)){
+
+ if ((chan=dev->priv) == NULL)
+ continue;
+
+ if (!test_bit(0,&chan->unconfig_dlci))
+ continue;
+
+ clear_bit(0,&chan->unconfig_dlci);
+
+ if (card->wandev.station == WANOPT_NODE){
+ printk(KERN_INFO "%s: Unconfiguring DLCI %i\n",
+ card->devname,chan->dlci);
+ fr_delete_dlci(card,chan->dlci);
+ }
+ card->u.f.dlci_to_dev_map[chan->dlci] = NULL;
+ }
+}
+
+static int setup_fr_header(struct sk_buff ** skb_orig, netdevice_t* dev, char op_mode)
+{
+ struct sk_buff *skb = *skb_orig;
+ fr_channel_t *chan=dev->priv;
+
+ if (op_mode == WANPIPE){
+
+ chan->fr_header[0]=Q922_UI;
+
+ switch (htons(skb->protocol)){
+
+ case ETH_P_IP:
+ chan->fr_header[1]=NLPID_IP;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 2;
+ }
+
+ /* If we are in bridging mode, we must apply
+ * an Ethernet header */
+ if (op_mode == BRIDGE || op_mode == BRIDGE_NODE){
+
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
+
+ /* Encapsulate the packet as a bridged Ethernet frame. */
+#ifdef DEBUG
+ printk(KERN_INFO "%s: encapsulating skb for frame relay\n",
+ dev->name);
+#endif
+
+ chan->fr_header[0] = 0x03;
+ chan->fr_header[1] = 0x00;
+ chan->fr_header[2] = 0x80;
+ chan->fr_header[3] = 0x00;
+ chan->fr_header[4] = 0x80;
+ chan->fr_header[5] = 0xC2;
+ chan->fr_header[6] = 0x00;
+ chan->fr_header[7] = 0x07;
+
+ /* Yuck. */
+ skb->protocol = ETH_P_802_3;
+ return 8;
+
+#else
+
+ /* BRIDGING is not supported in 2.0.X */
+ return -EINVAL;
+
#endif
+ }
+
+ return 0;
+}
+
+
+static int check_dlci_config (sdla_t *card, fr_channel_t *chan)
+{
+ fr_mbox_t* mbox = card->mbox;
+ int err=0;
+ fr_conf_t *conf=NULL;
+ unsigned short dlci_num = chan->dlci;
+ int dlci_offset=0;
+ netdevice_t *dev=NULL;
+
+ mbox->cmd.command = FR_READ_CONFIG;
+ mbox->cmd.length = 0;
+ mbox->cmd.dlci = dlci_num;
+
+ err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
+
+ if (err == CMD_OK){
+ return 0;
+ }
+
+ for (dev=card->wandev.dev; dev; dev=*((netdevice_t**)dev->priv)){
+ set_chan_state(dev,WAN_DISCONNECTED);
+ }
+
+ printk(KERN_INFO "DLCI %i Not configured, configuring\n",dlci_num);
+
+ mbox->cmd.command = FR_COMM_DISABLE;
+ mbox->cmd.length = 0;
+ err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
+ if (err != CMD_OK){
+ fr_event(card, err, mbox);
+ return 2;
+ }
+
+ printk(KERN_INFO "Disabled Communications \n");
+
+ mbox->cmd.command = FR_READ_CONFIG;
+ mbox->cmd.length = 0;
+ mbox->cmd.dlci = 0;
+
+ err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
+
+ if (err != CMD_OK){
+ fr_event(card, err, mbox);
+ return 2;
+ }
+
+ conf = (fr_conf_t *)mbox->data;
+
+ dlci_offset=0;
+ for (dev=card->wandev.dev; dev; dev=*((netdevice_t**)dev->priv)){
+ fr_channel_t *chan_tmp = dev->priv;
+ conf->dlci[dlci_offset] = chan_tmp->dlci;
+ dlci_offset++;
+ }
+
+ printk(KERN_INFO "Got Fr configuration Buffer Length is %x Dlci %i Dlci Off %i\n",
+ mbox->cmd.length,
+ mbox->cmd.length > 0x20 ? conf->dlci[0] : -1,
+ dlci_offset );
+
+ mbox->cmd.length = 0x20 + dlci_offset*2;
+
+ mbox->cmd.command = FR_SET_CONFIG;
+ mbox->cmd.dlci = 0;
+
+ err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
+
+ if (err != CMD_OK){
+ fr_event(card, err, mbox);
+ return 2;
+ }
+
+ initialize_rx_tx_buffers (card);
+
+
+ printk(KERN_INFO "Configuraiton Succeded for new DLCI %i\n",dlci_num);
+
+ if (fr_comm_enable (card)){
+ return 2;
+ }
+
+ printk(KERN_INFO "Enabling Communications \n");
+
+ for (dev=card->wandev.dev; dev; dev=*((netdevice_t**)dev->priv)){
+ fr_channel_t *chan_tmp = dev->priv;
+ fr_init_dlci(card,chan_tmp);
+ fr_add_dlci(card, chan_tmp->dlci);
+ fr_activate_dlci(card, chan_tmp->dlci);
+ }
+ printk(KERN_INFO "END OF CONFIGURAITON %i\n",dlci_num);
+
+ return 1;
}
+
+static void initialize_rx_tx_buffers (sdla_t *card)
+{
+ fr_buf_info_t* buf_info;
+
+ if (card->hw.type == SDLA_S514) {
+
+ buf_info = (void*)(card->hw.dpmbase + FR_MB_VECTOR +
+ FR508_RXBC_OFFS);
+
+ card->rxmb = (void*)(buf_info->rse_next + card->hw.dpmbase);
+
+ card->u.f.rxmb_base =
+ (void*)(buf_info->rse_base + card->hw.dpmbase);
+
+ card->u.f.rxmb_last =
+ (void*)(buf_info->rse_base +
+ (buf_info->rse_num - 1) * sizeof(fr_rx_buf_ctl_t) +
+ card->hw.dpmbase);
+ }else{
+ buf_info = (void*)(card->hw.dpmbase + FR508_RXBC_OFFS);
+
+ card->rxmb = (void*)(buf_info->rse_next -
+ FR_MB_VECTOR + card->hw.dpmbase);
+
+ card->u.f.rxmb_base =
+ (void*)(buf_info->rse_base -
+ FR_MB_VECTOR + card->hw.dpmbase);
+
+ card->u.f.rxmb_last =
+ (void*)(buf_info->rse_base +
+ (buf_info->rse_num - 1) * sizeof(fr_rx_buf_ctl_t) -
+ FR_MB_VECTOR + card->hw.dpmbase);
+ }
+
+ card->u.f.rx_base = buf_info->buf_base;
+ card->u.f.rx_top = buf_info->buf_top;
+
+ card->u.f.tx_interrupts_pending = 0;
+
+ return;
+}
+
+
+
/****** End *****************************************************************/
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)