sdla_fr.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:148k
- /*****************************************************************************
- * sdla_fr.c WANPIPE(tm) Multiprotocol WAN Link Driver. Frame relay module.
- *
- * Author(s): Nenad Corbic <ncorbic@sangoma.com>
- * Gideon Hack
- *
- * 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.
- * ============================================================================
- * 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.
- * o Only a Node can implement NO signalling.
- * Initialize DLCI during if_open() if NO
- * signalling.
- * o Took out IPX support, implement in next
- * version
- * Sep 29, 1999 Nenad Corbic o Added SMP support and changed the update
- * function to use timer interrupt.
- * o Fixed the CIR bug: Set the value of BC
- * to CIR when the CIR is enabled.
- * o Updated comments, statistics and tracing.
- * Jun 02, 1999 Gideon Hack o Updated for S514 support.
- * Sep 18, 1998 Jaspreet Singh o Updated for 2.2.X kernels.
- * Jul 31, 1998 Jaspreet Singh o Removed wpf_poll routine. The channel/DLCI
- * status is received through an event interrupt.
- * Jul 08, 1998 David Fong o Added inverse ARP support.
- * Mar 26, 1997 Jaspreet Singh o Returning return codes for failed UDP cmds.
- * Jan 28, 1997 Jaspreet Singh o Improved handling of inactive DLCIs.
- * Dec 30, 1997 Jaspreet Singh o Replaced dev_tint() with mark_bh(NET_BH)
- * Dec 16, 1997 Jaspreet Singh o Implemented Multiple IPX support.
- * Nov 26, 1997 Jaspreet Singh o Improved load sharing with multiple boards
- * o Added Cli() to protect enabling of interrupts
- * while polling is called.
- * Nov 24, 1997 Jaspreet Singh o Added counters to avoid enabling of interrupts
- * when they have been disabled by another
- * interface or routine (eg. wpf_poll).
- * Nov 06, 1997 Jaspreet Singh o Added INTR_TEST_MODE to avoid polling
- * routine disable interrupts during interrupt
- * testing.
- * Oct 20, 1997 Jaspreet Singh o Added hooks in for Router UP time.
- * Oct 16, 1997 Jaspreet Singh o The critical flag is used to maintain flow
- * control by avoiding RACE conditions. The
- * cli() and restore_flags() are taken out.
- * The fr_channel structure is appended for
- * Driver Statistics.
- * Oct 15, 1997 Farhan Thawar o updated if_send() and receive for IPX
- * Aug 29, 1997 Farhan Thawar o Removed most of the cli() and sti()
- * o Abstracted the UDP management stuff
- * o Now use tbusy and critical more intelligently
- * Jul 21, 1997 Jaspreet Singh o Can configure T391, T392, N391, N392 & N393
- * through router.conf.
- * o Protected calls to sdla_peek() by adDing
- * save_flags(), cli() and restore_flags().
- * o Added error message for Inactive DLCIs in
- * fr_event() and update_chan_state().
- * o Fixed freeing up of buffers using kfree()
- * when packets are received.
- * Jul 07, 1997 Jaspreet Singh o Added configurable TTL for UDP packets
- * o Added ability to discard multicast and
- * broadcast source addressed packets
- * Jun 27, 1997 Jaspreet Singh o Added FT1 monitor capabilities
- * New case (0x44) statement in if_send routine
- * Added a global variable rCount to keep track
- * of FT1 status enabled on the board.
- * May 29, 1997 Jaspreet Singh o Fixed major Flow Control Problem
- * With multiple boards a problem was seen where
- * the second board always stopped transmitting
- * packet after running for a while. The code
- * got into a stage where the interrupts were
- * disabled and dev->tbusy was set to 1.
- * This caused the If_send() routine to get into
- * the if clause for it(0,dev->tbusy)
- * forever.
- * The code got into this stage due to an
- * interrupt occuring within the if clause for
- * set_bit(0,dev->tbusy). Since an interrupt
- * disables furhter transmit interrupt and
- * makes dev->tbusy = 0, this effect was undone
- * by making dev->tbusy = 1 in the if clause.
- * The Fix checks to see if Transmit interrupts
- * are disabled then do not make dev->tbusy = 1
- * Introduced a global variable: int_occur and
- * added tx_int_enabled in the wan_device
- * structure.
- * May 21, 1997 Jaspreet Singh o Fixed UDP Management for multiple
- * boards.
- *
- * Apr 25, 1997 Farhan Thawar o added UDP Management stuff
- * o fixed bug in if_send() and tx_intr() to
- * sleep and wakeup all devices
- * Mar 11, 1997 Farhan Thawar Version 3.1.1
- * o fixed (+1) bug in fr508_rx_intr()
- * o changed if_send() to return 0 if
- * wandev.critical() is true
- * o free socket buffer in if_send() if
- * returning 0
- * o added tx_intr() routine
- * Jan 30, 1997 Gene Kozin Version 3.1.0
- * o implemented exec() entry point
- * o fixed a bug causing driver configured as
- * a FR switch to be stuck in WAN_
- * mode
- * Jan 02, 1997 Gene Kozin Initial version.
- *****************************************************************************/
- #include <linux/module.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/wanrouter.h> /* WAN router definitions */
- #include <linux/wanpipe.h> /* WANPIPE common user API definitions */
- #include <linux/if_arp.h> /* ARPHRD_* defines */
- #include <asm/byteorder.h> /* htons(), etc. */
- #include <asm/io.h> /* for inb(), outb(), etc. */
- #include <linux/time.h> /* for do_gettimeofday */
- #include <linux/in.h> /* sockaddr_in */
- #include <linux/inet.h> /* in_ntoa(), etc... */
- #include <asm/errno.h>
- #include <linux/ip.h>
- #include <linux/if.h>
- #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 */
- #define FR_HEADER_LEN 8 /* max encapsulation header size */
- #define FR_CHANNEL_MTU 1500 /* unfragmented logical channel MTU */
- /* Q.922 frame types */
- #define Q922_UI 0x03 /* Unnumbered Info frame */
- #define Q922_XID 0xAF
- /* DLCI configured or not */
- #define DLCI_NOT_CONFIGURED 0x00
- #define DLCI_CONFIG_PENDING 0x01
- #define DLCI_CONFIGURED 0x02
- /* CIR enabled or not */
- #define CIR_ENABLED 0x00
- #define CIR_DISABLED 0x01
- #define FRAME_RELAY_API 1
- #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 device' we create for each network
- * interface to keep the rest of channel-specific data.
- */
- typedef struct fr_channel
- {
- 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 */
- unsigned dlci; /* logical channel number */
- unsigned cir; /* committed information rate */
- unsigned bc; /* committed burst size */
- unsigned be; /* excess burst size */
- unsigned mc; /* multicast support on or off */
- unsigned tx_int_status; /* Transmit Interrupt Status */
- unsigned short pkt_length; /* Packet Length */
- 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() */
- 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 */
- unsigned char enable_IPX; /* Enable/Disable the use of IPX */
- unsigned long network_number; /* Internal Network Number for IPX*/
- 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 long router_up_time;
- unsigned short transmit_length;
- 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 */
- #define NO_ROUTE 0x00
- #define ADD_ROUTE 0x01
- #define ROUTE_ADDED 0x02
- #define REMOVE_ROUTE 0x03
- #define ARP_REQ 0x04
- /* inarp options */
- #define INARP_NONE 0x00
- #define INARP_REQUEST 0x01
- #define INARP_CONFIGURED 0x02
- /* 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
- {
- unsigned short dlci PACKED;
- unsigned char state PACKED;
- } dlci_status_t;
- typedef struct dlci_IB_mapping
- {
- unsigned short dlci PACKED;
- unsigned long addr_value PACKED;
- } dlci_IB_mapping_t;
- /* This structure is used for DLCI list Tx interrupt mode. It is used to
- enable interrupt bit and set the packet length for transmission
- */
- typedef struct fr_dlci_interface
- {
- unsigned char gen_interrupt PACKED;
- unsigned short packet_length PACKED;
- unsigned char reserved PACKED;
- } fr_dlci_interface_t;
- /* variable for keeping track of enabling/disabling FT1 monitor status */
- static int rCount = 0;
- extern void disable_irq(unsigned int);
- extern void enable_irq(unsigned int);
- /* variable for keeping track of number of interrupts generated during
- * 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, 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(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);
- #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);
- static void rx_intr(sdla_t *card);
- static void tx_intr(sdla_t *card);
- static void timer_intr(sdla_t *card);
- static void spur_intr(sdla_t *card);
- /* Frame relay firmware interface functions */
- static int fr_read_version(sdla_t *card, char *str);
- static int fr_configure(sdla_t *card, fr_conf_t *conf);
- static int fr_dlci_configure(sdla_t *card, fr_dlc_conf_t *conf, unsigned dlci);
- 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 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);
- static int fr_activate_dlci(sdla_t *card, int dlci);
- static int fr_delete_dlci (sdla_t* card, int dlci);
- 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);
- static int fr_modem_failure(sdla_t *card, fr_mbox_t *mbox);
- static int fr_dlci_change(sdla_t *card, fr_mbox_t *mbox);
- /* Miscellaneous functions */
- 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 );
- static int intr_test( sdla_t* card );
- 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 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, netdevice_t *dev);
- int is_arp(void *buf);
- 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);
- static int udp_pkt_type( struct sk_buff *skb, sdla_t *card );
- static int store_udp_mgmt_pkt(int udp_type, char udp_pkt_src, sdla_t* card,
- struct sk_buff *skb, int dlci);
- /* IPX functions */
- static void switch_net_numbers(unsigned char *sendpacket,
- unsigned long network_number, unsigned char incoming);
- static int handle_IPXWAN(unsigned char *sendpacket, char *devname,
- unsigned char enable_IPX, unsigned long network_number);
- /* Lock Functions: SMP supported */
- void s508_s514_unlock(sdla_t *card, unsigned long *smp_flags);
- 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 ****************************************************/
- /*============================================================================
- * Frame relay protocol initialization routine.
- *
- * This routine is called by the main WANPIPE module during setup. At this
- * point adapter is completely initialized and firmware is running.
- * o read firmware version (to make sure it's alive)
- * o configure adapter
- * o initialize protocol-specific fields of the adapter data space.
- *
- * Return: 0 o.k.
- * < 0 failure.
- */
- int wpf_init(sdla_t *card, wandev_conf_t *conf)
- {
- 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) {
-
- printk(KERN_INFO "%s: invalid configuration ID %u!n",
- card->devname, conf->config_id);
- return -EINVAL;
-
- }
- /* Initialize protocol-specific fields of adapter data space */
- switch (card->hw.fwid) {
-
- case SFID_FR508:
- card->mbox = (void*)(card->hw.dpmbase +
- FR508_MBOX_OFFS);
- card->flags = (void*)(card->hw.dpmbase +
- FR508_FLAG_OFFS);
- if(card->hw.type == SDLA_S514) {
- card->mbox += FR_MB_VECTOR;
- card->flags += FR_MB_VECTOR;
- }
- card->isr = &fr_isr;
- break;
- default:
- 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
- * around this, we execute the first command twice.
- */
- if (fr_read_version(card, NULL) || fr_read_version(card, u.str))
- return -EIO;
- printk(KERN_INFO "%s: running frame relay firmware v%sn",
- card->devname, u.str);
- /* Adjust configuration */
- conf->mtu += FR_HEADER_LEN;
- conf->mtu = (conf->mtu >= MIN_LGTH_FR_DATA_CFG) ?
- min_t(unsigned int, conf->mtu, FR_MAX_NO_DATA_BYTES_IN_FRAME) :
- FR_CHANNEL_MTU + FR_HEADER_LEN;
-
- conf->bps = min_t(unsigned int, conf->bps, 2048000);
- /* Initialze the configuration structure sent to the board to zero */
- memset(&u.cfg, 0, sizeof(u.cfg));
- 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;
- u.cfg.cir_fwd = u.cfg.cir_bwd = 16;
- u.cfg.bc_fwd = u.cfg.bc_bwd = 16;
-
- u.cfg.options = 0x0000;
- printk(KERN_INFO "%s: Global CIR enabled by Defaultn", card->devname);
-
- switch (conf->u.fr.signalling) {
- case WANOPT_FR_ANSI:
- u.cfg.options = 0x0000;
- break;
-
- case WANOPT_FR_Q933:
- u.cfg.options |= 0x0200;
- break;
-
- case WANOPT_FR_LMI:
- u.cfg.options |= 0x0400;
- break;
- case WANOPT_NO:
- u.cfg.options |= 0x0800;
- break;
- default:
- printk(KERN_INFO "%s: Illegal Signalling optionn",
- card->wandev.name);
- return -EINVAL;
- }
- card->wandev.signalling = conf->u.fr.signalling;
- if (conf->station == WANOPT_CPE) {
- if (conf->u.fr.signalling == WANOPT_NO){
- printk(KERN_INFO
- "%s: ERROR - For NO signalling, station must be set to Node!",
- card->devname);
- return -EINVAL;
- }
- u.cfg.station = 0;
- u.cfg.options |= 0x8000; /* auto config DLCI */
- card->u.f.dlci_num = 0;
-
- } else {
- u.cfg.station = 1; /* switch emulation mode */
- /* For switch emulation we have to create a list of dlci(s)
- * that will be sent to be global SET_DLCI_CONFIGURATION
- * command in fr_configure() routine.
- */
- card->u.f.dlci_num = min_t(unsigned int, max_t(unsigned int, conf->u.fr.dlci_num, 1), 100);
-
- for ( i = 0; i < card->u.f.dlci_num; i++) {
- card->u.f.node_dlci[i] = (unsigned short)
- conf->u.fr.dlci[i] ? conf->u.fr.dlci[i] : 16;
-
- }
- }
- if (conf->clocking == WANOPT_INTERNAL)
- u.cfg.port |= 0x0001;
- if (conf->interface == WANOPT_RS232)
- u.cfg.port |= 0x0002;
- if (conf->u.fr.t391)
- u.cfg.t391 = min_t(unsigned int, conf->u.fr.t391, 30);
- else
- u.cfg.t391 = 5;
- if (conf->u.fr.t392)
- u.cfg.t392 = min_t(unsigned int, conf->u.fr.t392, 30);
- else
- u.cfg.t392 = 15;
- if (conf->u.fr.n391)
- u.cfg.n391 = min_t(unsigned int, conf->u.fr.n391, 255);
- else
- u.cfg.n391 = 2;
- if (conf->u.fr.n392)
- u.cfg.n392 = min_t(unsigned int, conf->u.fr.n392, 10);
- else
- u.cfg.n392 = 3;
- if (conf->u.fr.n393)
- u.cfg.n393 = min_t(unsigned int, conf->u.fr.n393, 10);
- else
- u.cfg.n393 = 4;
- if (fr_configure(card, &u.cfg))
- return -EIO;
- 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;
- card->wandev.mtu = conf->mtu;
- card->wandev.bps = conf->bps;
- card->wandev.interface = conf->interface;
- card->wandev.clocking = conf->clocking;
- card->wandev.station = conf->station;
- card->poll = NULL;
- card->exec = &wpf_exec;
- card->wandev.update = &update;
- card->wandev.new_if = &new_if;
- card->wandev.del_if = &del_if;
- 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 );
- card->TracingEnabled = 0;
- /* Interrupt Test */
- Intr_test_counter = 0;
- card->intr_mode = INTR_TEST_MODE;
- err = intr_test( card );
- printk(KERN_INFO "%s: End of Interrupt Test rc=0x%x count=%in",
- card->devname,err,Intr_test_counter);
-
- if (err || (Intr_test_counter < MAX_INTR_TEST_COUNTER)) {
- printk(KERN_ERR "%s: Interrupt Test Failed, Counter: %in",
- card->devname, Intr_test_counter);
- printk(KERN_ERR "Please choose another interruptn");
- err = -EIO;
- return err;
- }
- printk(KERN_INFO "%s: Interrupt Test Passed, Counter: %in",
- 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;
- }
- /******* WAN Device Driver Entry Points *************************************/
- /*============================================================================
- * Update device status & statistics.
- */
- static int update (wan_device_t* wandev)
- {
- volatile sdla_t* card;
- unsigned long timeout;
- fr508_flags_t* flags;
- /* sanity checks */
- if ((wandev == NULL) || (wandev->private == NULL))
- return -EFAULT;
- if (wandev->state == WAN_UNCONFIGURED)
- return -ENODEV;
- card = wandev->private;
- flags = card->flags;
- card->u.f.update_comms_stats = 1;
- card->u.f.timer_int_enabled |= TMR_INT_ENABLED_UPDATE;
- flags->imask |= FR_INTR_TIMER;
- timeout = jiffies;
- for(;;) {
- if(card->u.f.update_comms_stats == 0)
- break;
- if ((jiffies - timeout) > (1 * HZ)){
- card->u.f.update_comms_stats = 0;
- return -EAGAIN;
- }
- }
- return 0;
- }
- /*============================================================================
- * Create new logical channel.
- * This routine is called by the router when ROUTER_IFNEW IOCTL is being
- * handled.
- * o parse media- and hardware-specific configuration
- * o make sure that a new channel can be created
- * o allocate resources, if necessary
- * o prepare network device structure for registaration.
- *
- * Return: 0 o.k.
- * < 0 failure (channel will not be created)
- */
- 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] == ' ') || (strlen(conf->name) > WAN_IFNAME_SZ)) {
-
- printk(KERN_INFO "%s: Invalid interface name!n",
- card->devname);
- return -EINVAL;
- }
- /* allocate and initialize private data */
- chan = kmalloc(sizeof(fr_channel_t), GFP_KERNEL);
- if (chan == NULL)
- return -ENOMEM;
- memset(chan, 0, sizeof(fr_channel_t));
- strcpy(chan->name, conf->name);
- chan->card = card;
- /* verify media address */
- if (is_digit(conf->addr[0])) {
- dlci = dec_to_uint(conf->addr, 0);
- if (dlci && (dlci <= HIGHEST_VALID_DLCI)) {
-
- chan->dlci = dlci;
-
- } else {
-
- printk(KERN_ERR
- "%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",
- wandev->name, chan->name);
- err = -EINVAL;
- }
- if ((chan->true_if_encoding = conf->true_if_encoding) == WANOPT_YES){
- printk(KERN_INFO
- "%s: Enabling, true interface type encoding.n",
- card->devname);
- }
-
- /* 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: 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);
- #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 supportn",
- wandev->name);
- err = -EINVAL;
- #endif
- }
- if (err) {
-
- kfree(chan);
- return err;
- }
- /* place cir,be,bc and other channel specific information into the
- * chan structure
- */
- if (conf->cir) {
- chan->cir = max_t(unsigned int, 1,
- min_t(unsigned int, conf->cir, 512));
- chan->cir_status = CIR_ENABLED;
-
- /* If CIR is enabled, force BC to equal CIR
- * this solves number of potential problems if CIR is
- * set and BC is not
- */
- chan->bc = chan->cir;
- if (conf->be){
- chan->be = max_t(unsigned int,
- 0, min_t(unsigned int, conf->be, 511));
- }else{
- conf->be = 0;
- }
- printk (KERN_INFO "%s: CIR enabled for DLCI %i n",
- wandev->name,chan->dlci);
- printk (KERN_INFO "%s: CIR = %i ; BC = %i ; BE = %in",
- wandev->name,chan->cir,chan->bc,chan->be);
- }else{
- chan->cir_status = CIR_DISABLED;
- printk (KERN_INFO "%s: CIR disabled for DLCI %in",
- wandev->name,chan->dlci);
- }
- chan->mc = conf->mc;
- if (conf->inarp == WANOPT_YES){
- #if defined(LINUX_2_1) || defined(LINUX_2_4)
- printk(KERN_INFO "%s: Inverse ARP Support Enabledn",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 = INARP_NONE;
- chan->inarp_interval = 10;
- #endif
- }else{
- printk(KERN_INFO "%s: Inverse ARP Support Disabledn",card->devname);
- chan->inarp = INARP_NONE;
- chan->inarp_interval = 10;
- }
- chan->dlci_configured = DLCI_NOT_CONFIGURED;
- /*FIXME: IPX disabled in this WANPIPE version */
- if (conf->enable_IPX == WANOPT_YES){
- printk(KERN_INFO "%s: ERROR - This version of WANPIPE doesn't support IPXn",
- card->devname);
- kfree(chan);
- return -EINVAL;
- }else{
- chan->enable_IPX = WANOPT_NO;
- }
- if (conf->network_number){
- chan->network_number = conf->network_number;
- }else{
- chan->network_number = 0xDEADBEEF;
- }
- chan->route_flag = NO_ROUTE;
-
- init_chan_statistics(chan);
- chan->transmit_length = 0;
- /* prepare network device data space for registration */
- #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;
- /* 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, netdevice_t* dev)
- {
- fr_channel_t* chan = dev->priv;
- unsigned long smp_flags=0;
- /* 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);
- 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 ***************************************/
- /*============================================================================
- * Execute adapter interface command.
- */
- static int wpf_exec (struct sdla* card, void* u_cmd, void* u_data)
- {
- fr_mbox_t* mbox = card->mbox;
- int retry = MAX_CMD_RETRY;
- 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;
-
- /* execute command */
- do
- {
- memcpy(&mbox->cmd, &cmd, sizeof(cmd));
-
- if (cmd.length){
- if( copy_from_user((void*)&mbox->data, u_data, cmd.length))
- return -EFAULT;
- }
-
- if (sdla_exec(mbox))
- err = mbox->cmd.result;
- else return -EIO;
-
- } while (err && retry-- && fr_event(card, err, mbox));
- /* return result */
- if (copy_to_user(u_cmd, (void*)&mbox->cmd, sizeof(fr_cmd_t)))
- return -EFAULT;
- len = mbox->cmd.length;
- if (len && u_data && !copy_to_user(u_data, (void*)&mbox->data, len))
- 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 ********************************************/
- /*============================================================================
- * Initialize Linux network interface.
- *
- * This routine is called only once for each interface, during Linux network
- * interface registration. Returning anything but zero will fail interface
- * registration.
- */
- 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 = 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;
- /* 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->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, "xFExFCx00x00x00x00", 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;
- dev->base_addr = wandev->ioport;
- dev->mem_start = wandev->maddr;
- dev->mem_end = wandev->maddr + wandev->msize - 1;
- return 0;
- }
- /*============================================================================
- * Open network interface.
- * o if this is the first open, then enable communications and interrupts.
- * o prevent module from unloading by incrementing use count
- *
- * Return 0 if O.k. or errno.
- */
- 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 (is_dev_running(dev))
- return -EBUSY;
-
- #if defined(LINUX_2_1) || defined(LINUX_2_4)
- /* Initialize the task queue */
- chan->tq_working=0;
- #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);
- do_gettimeofday( &tv );
- chan->router_start_time = tv.tv_sec;
-
- if (test_bit(0,&chan->config_dlci)){
- trigger_config_fr (card);
- }else if (chan->inarp == INARP_REQUEST){
- trigger_fr_arp(dev);
- }
-
- return err;
- }
- /*============================================================================
- * Close network interface.
- * o if this is the last open, then disable communications and interrupts.
- * o reset flags.
- */
- static int if_close (netdevice_t* dev)
- {
- fr_channel_t* chan = dev->priv;
- sdla_t* card = chan->card;
- if (chan->inarp == INARP_CONFIGURED) {
- chan->inarp = INARP_REQUEST;
- }
- stop_net_queue(dev);
- #ifndef LINUX_2_4
- dev->start=0;
- #endif
- wanpipe_close(card);
- return 0;
- }
- /*============================================================================
- * 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)
- {
- #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;
- printk(KERN_INFO "%s: rebuild_header() called for interface %s!n",
- card->devname, dev->name);
- return 1;
- }
- #ifdef LINUX_2_4
- /*============================================================================
- * Handle transmit timeout event from netif watchdog
- */
- 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
- * 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;
- printk (KERN_INFO "%s: Transmit timed out on %sn",
- card->devname, dev->name);
- chan->drvstats_if_send.if_send_tbusy_timeout++;
- netif_wake_queue (dev);
- }
- #endif
- /*============================================================================
- * Send a packet on a network interface.
- * o set tbusy flag (marks start of the transmission) to block a timer-based
- * transmit from overlapping.
- * o set critical flag when accessing board.
- * o check link state. If link is not up, then drop the packet.
- * o check channel status. If it's down then initiate a call.
- * o pass a packet to corresponding WAN device.
- * o free socket buffer
- *
- * Return: 0 complete (socket buffer must be freed)
- * non-0 packet may be re-transmitted (tbusy must be set)
- *
- * Notes:
- * 1. This routine is called either by the protocol stack or by the "net
- * bottom half" (with interrupts enabled).
- *
- * 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, 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, delay_tx_queued=0;
- unsigned long smp_flags=0;
- 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.
- */
- printk(KERN_INFO "%s: interface %s got kicked!n",
- card->devname, dev->name);
- chan->drvstats_if_send.if_send_skb_null ++;
- 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;
- }
- /* We must set the 'tbusy' flag if we already have a packet queued for
- transmission in the transmit interrupt handler. However, we must
- 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(SEND_TXIRQ_CRIT, (void*)&card->wandev.critical);
- if(chan->transmit_length) {
- stop_net_queue(dev);
- chan->tick_counter = jiffies;
- clear_bit(SEND_TXIRQ_CRIT, (void*)&card->wandev.critical);
- return 1;
- }
- 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 %sn",
- 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;
- 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,
- chan->dlci)) {
- adptr_flags->imask |= FR_INTR_TIMER;
- if (udp_type == UDP_FPIPE_TYPE){
- chan->drvstats_if_send.
- if_send_PIPE_request ++;
- }
- }
- start_net_queue(dev);
- return 0;
- }
- //FIXME: can we do better than sendpacket[2]?
- 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)){
- ++chan->ifstats.tx_dropped;
- ++card->wandev.stats.tx_dropped;
- wan_dev_kfree_skb(skb, FREE_WRITE);
- start_net_queue(dev);
- return 0;
- }
- }
-
- /* Lock the S514/S508 card: SMP Supported */
- s508_s514_lock(card,&smp_flags);
- 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: if_send() already running!n",
- card->devname);
- goto if_send_start_and_exit;
- }
-
- /* 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)) {
- /* 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 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->common.usedby == WANPIPE) &&
- sendpacket[1] == 0x00 &&
- sendpacket[2] == 0x80 &&
- sendpacket[6] == 0x81 &&
- sendpacket[7] == 0x37) {
-
- if( chan->enable_IPX ) {
- switch_net_numbers(sendpacket,
- chan->network_number, 0);
- } else {
- //FIXME: Take this out when IPX is fixed
- printk(KERN_INFO
- "%s: WARNING: Unsupported IPX data in send, packet droppedn",
- card->devname);
- }
-
- }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:
- if (!setup_for_delayed_transmit(dev, skb)){
- set_bit(1,&delay_tx_queued);
- }
- chan->drvstats_if_send.
- if_send_adptr_bfrs_full ++;
- break;
-
- case FRRES_TOO_LONG:
- if (net_ratelimit()){
- printk(KERN_INFO
- "%s: Error: Frame too long, transmission failed %in",
- card->devname, (unsigned int)skb->len);
- }
- /* Drop down to default */
- default:
- chan->drvstats_if_send.
- if_send_dlci_disconnected ++;
- ++chan->ifstats.tx_dropped;
- ++card->wandev.stats.tx_dropped;
- break;
- }
- } else {
- chan->drvstats_if_send.
- if_send_bfr_passed_to_adptr++;
- ++chan->ifstats.tx_packets;
- ++card->wandev.stats.tx_packets;
-
- #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_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(SEND_CRIT, (void*)&card->wandev.critical);
- s508_s514_unlock(card,&smp_flags);
- return 0;
- }
- /*============================================================================
- * Setup so that a frame can be transmitted on the occurence of a transmit
- * interrupt.
- */
- static int setup_for_delayed_transmit (netdevice_t* dev, struct sk_buff *skb)
- {
- fr_channel_t* chan = dev->priv;
- sdla_t* card = chan->card;
- 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 Technologiesn",
- 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 1;
- }
- if(len > FR_MAX_NO_DATA_BYTES_IN_FRAME) {
- //FIXME: increment some statistic */
- return 1;
- }
- skb_unlink(skb);
-
- chan->transmit_length = len;
- chan->delay_skb = skb;
-
- dlci_interface->gen_interrupt |= FR_INTR_TXRDY;
- dlci_interface->packet_length = len;
- /* Turn on TX interrupt at the end of if_send */
- return 0;
- }
- /*============================================================================
- * Check to see if the packet to be transmitted contains a broadcast or
- * multicast source IP address.
- * Return 0 if not broadcast/multicast address, otherwise return 1.
- */
- 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;
- if(ifa != NULL)
- broadcast_ip_addr = ifa->ifa_broadcast;
- 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
- "%s: Broadcast Source Address silently discardedn",
- card->devname);
- return 1;
- }
- /* check if the IP Source Address is a Multicast address */
- if((chan->mc == WANOPT_NO) && (ntohl(src_ip_addr) >= 0xE0000001) &&
- (ntohl(src_ip_addr) <= 0xFFFFFFFE)) {
- printk(KERN_INFO
- "%s: Multicast Source Address silently discardedn",
- card->devname);
- return 1;
- }
- return 0;
- }
- /*============================================================================
- * Reply to UDP Management system.
- * Return nothing.
- */
- static int reply_udp( unsigned char *data, unsigned int mbox_len )
- {
- unsigned short len, udp_length, temp, ip_length;
- unsigned long ip_temp;
- int even_bound = 0;
-
- fr_udp_pkt_t *fr_udp_pkt = (fr_udp_pkt_t *)data;
- /* Set length of packet */
- len = //sizeof(fr_encap_hdr_t)+
- sizeof(ip_pkt_t)+
- sizeof(udp_pkt_t)+
- sizeof(wp_mgmt_t)+
- sizeof(cblock_t)+
- mbox_len;
-
- /* fill in UDP reply */
- fr_udp_pkt->wp_mgmt.request_reply = UDPMGMT_REPLY;
-
- /* fill in UDP length */
- udp_length = sizeof(udp_pkt_t)+
- sizeof(wp_mgmt_t)+
- sizeof(cblock_t)+
- mbox_len;
- /* put it on an even boundary */
- if ( udp_length & 0x0001 ) {
- udp_length += 1;
- len += 1;
- even_bound = 1;
- }
- temp = (udp_length<<8)|(udp_length>>8);
- fr_udp_pkt->udp_pkt.udp_length = temp;
-
- /* swap UDP ports */
- temp = fr_udp_pkt->udp_pkt.udp_src_port;
- fr_udp_pkt->udp_pkt.udp_src_port =
- fr_udp_pkt->udp_pkt.udp_dst_port;
- fr_udp_pkt->udp_pkt.udp_dst_port = temp;
- /* add UDP pseudo header */
- temp = 0x1100;
- *((unsigned short *)
- (fr_udp_pkt->data+mbox_len+even_bound)) = temp;
- temp = (udp_length<<8)|(udp_length>>8);
- *((unsigned short *)
- (fr_udp_pkt->data+mbox_len+even_bound+2)) = temp;
-
- /* calculate UDP checksum */
- 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)*/],
- udp_length+UDP_OFFSET);
- /* fill in IP length */
- ip_length = udp_length + sizeof(ip_pkt_t);
- temp = (ip_length<<8)|(ip_length>>8);
- fr_udp_pkt->ip_pkt.total_length = temp;
-
- /* swap IP addresses */
- ip_temp = fr_udp_pkt->ip_pkt.ip_src_address;
- fr_udp_pkt->ip_pkt.ip_src_address =
- fr_udp_pkt->ip_pkt.ip_dst_address;
- fr_udp_pkt->ip_pkt.ip_dst_address = ip_temp;
-
- /* 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)*/0],
- sizeof(ip_pkt_t));
- return len;
- } /* reply_udp */
- unsigned short calc_checksum (char *data, int len)
- {
- unsigned short temp;
- unsigned long sum=0;
- int i;
- for( i = 0; i <len; i+=2 ) {
- memcpy(&temp,&data[i],2);
- sum += (unsigned long)temp;
- }
- while (sum >> 16 ) {
- sum = (sum & 0xffffUL) + (sum >> 16);
- }
- temp = (unsigned short)sum;
- temp = ~temp;
- if( temp == 0 )
- temp = 0xffff;
- return temp;
- }
- /*
- If incoming is 0 (outgoing)- if the net numbers is ours make it 0
- if incoming is 1 - if the net number is 0 make it ours
- */
- static void switch_net_numbers(unsigned char *sendpacket, unsigned long network_number, unsigned char incoming)
- {
- unsigned long pnetwork_number;
- pnetwork_number = (unsigned long)((sendpacket[14] << 24) +
- (sendpacket[15] << 16) + (sendpacket[16] << 8) +
- sendpacket[17]);
- if (!incoming) {
- /* If the destination network number is ours, make it 0 */
- if( pnetwork_number == network_number) {
- sendpacket[14] = sendpacket[15] = sendpacket[16] =
- sendpacket[17] = 0x00;
- }
- } else {
- /* If the incoming network is 0, make it ours */
- if( pnetwork_number == 0) {
- sendpacket[14] = (unsigned char)(network_number >> 24);
- sendpacket[15] = (unsigned char)((network_number &
- 0x00FF0000) >> 16);
- sendpacket[16] = (unsigned char)((network_number &
- 0x0000FF00) >> 8);
- sendpacket[17] = (unsigned char)(network_number &
- 0x000000FF);
- }
- }
- pnetwork_number = (unsigned long)((sendpacket[26] << 24) +
- (sendpacket[27] << 16) + (sendpacket[28] << 8) +
- sendpacket[29]);
- if( !incoming ) {
- /* If the source network is ours, make it 0 */
- if( pnetwork_number == network_number) {
- sendpacket[26] = sendpacket[27] = sendpacket[28] =
- sendpacket[29] = 0x00;
- }
- } else {
- /* If the source network is 0, make it ours */
- if( pnetwork_number == 0 ) {
- sendpacket[26] = (unsigned char)(network_number >> 24);
- sendpacket[27] = (unsigned char)((network_number &
- 0x00FF0000) >> 16);
- sendpacket[28] = (unsigned char)((network_number &
- 0x0000FF00) >> 8);
- sendpacket[29] = (unsigned char)(network_number &
- 0x000000FF);
- }
- }
- } /* switch_net_numbers */
- /*============================================================================
- * Get ethernet-style interface statistics.
- * Return a pointer to struct enet_statistics.
- */
- #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;
-
- if(chan == NULL)
- return NULL;
- return &chan->ifstats;
- }
- /****** Interrupt Handlers **************************************************/
- /*============================================================================
- * 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)
- {
- fr508_flags_t* flags = card->flags;
- char *ptr = &flags->iflag;
- int i,err;
- fr_mbox_t* mbox = card->mbox;
- /* This flag prevents nesting of interrupts. See sdla_isr() routine
- * in sdlamain.c. */
- card->in_isr = 1;
-
- ++card->statistics.isr_entry;
- /* 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_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;
- goto fr_isr_exit;
- }
- }
- switch (flags->iflag) {
- case FR_INTR_RXRDY: /* receive interrupt */
- ++card->statistics.isr_rx;
- rx_intr(card);
- break;
- case FR_INTR_TXRDY: /* transmit interrupt */
- ++ card->statistics.isr_tx;
- tx_intr(card);
- break;
- case FR_INTR_READY:
- Intr_test_counter++;
- ++card->statistics.isr_intr_test;
- break;
- 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;
- if (err)
- fr_event(card, err, mbox);
- break;
- case FR_INTR_TIMER: /* Timer interrupt */
- timer_intr(card);
- break;
-
- default:
- ++card->statistics.isr_spurious;
- spur_intr(card);
- printk(KERN_INFO "%s: Interrupt Type 0x%02X!n",
- card->devname, flags->iflag);
-
- printk(KERN_INFO "%s: ID Bytes = ",card->devname);
- for(i = 0; i < 8; i ++)
- printk(KERN_INFO "0x%02X ", *(ptr + 0x28 + i));
- printk(KERN_INFO "n");
-
- break;
- }
- fr_isr_exit:
-
- card->in_isr = 0;
- flags->iflag = 0;
- return;
- }
- /*===========================================================
- * 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;
- fr508_flags_t* flags = card->flags;
- fr_channel_t* chan;
- char *ptr = &flags->iflag;
- struct sk_buff* skb;
- 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
- "%s: corrupted Rx buffer @ 0x%X, flag = 0x%02X!n",
- card->devname, (unsigned)frbuf, frbuf->flag);
-
- printk(KERN_INFO "%s: ID Bytes = ",card->devname);
- for(i = 0; i < 8; i ++)
- printk(KERN_INFO "0x%02X ", *(ptr + 0x28 + i));
- 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;
- }
- len = frbuf->length;
- dlci = frbuf->dlci;
- offs = frbuf->offset;
- /* Find the network interface for this packet */
- dev = find_channel(card, dlci);
-
- /* 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;
- }
- 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);
- 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 ++;
- }
- 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;
- }
- /* 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;
- 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);
- /* We got the packet from the bard.
- * Check the packet type and take appropriate action */
- udp_type = udp_pkt_type( skb, card );
- 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, "x03x00x80x00x80xC2x00x07", 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;
- card->rxmb = ++frbuf;
- if ((void*)frbuf > card->u.f.rxmb_last)
- card->rxmb = card->u.f.rxmb_base;
- }
- /*==================================================================
- * 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;
- netdevice_t* dev;
- fr_channel_t* chan;
- if(card->hw.type == SDLA_S514){
- bctl = (void*)(flags->tse_offs + card->hw.dpmbase);
- }else{
- bctl = (void*)(flags->tse_offs - FR_MB_VECTOR +
- card->hw.dpmbase);
- }
- /* Find the structure and make it unbusy */
- dev = find_channel(card, flags->dlci);
- if (dev == NULL){
- printk(KERN_INFO "NO DEV IN TX Interruptn");
- goto end_of_tx_intr;
- }
- if ((chan = dev->priv) == NULL){
- printk(KERN_INFO "NO CHAN IN TX Interruptn");
- goto end_of_tx_intr;
- }
- if(!chan->transmit_length || !chan->delay_skb) {
- printk(KERN_INFO "%s: tx int error - transmit length zeron",
- card->wandev.name);
- 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(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;
- return;
- }else{
- bctl->dlci = flags->dlci;
- 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;
- #ifdef LINUX_2_4
- dev->trans_start = jiffies;
- #endif
- #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_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;
- /* 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 &=
- ~TMR_INT_ENABLED_UDP;
- }
- }
- }
- /* /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;
- }
- /* 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;
- }
-
- /* 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;
- }
- }
- card->u.f.arp_dev = dev;
- }
- if(!card->u.f.timer_int_enabled)
- flags->imask &= ~FR_INTR_TIMER;
- }
- /*============================================================================
- * spur_intr: Spurious interrupt handler.
- *
- * Description:
- * We don't know this interrupt.
- * Print a warning.
- */
- static void spur_intr (sdla_t* card)
- {
- 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)
- {
- int i;
- if( sendpacket[1] == 0x00 && sendpacket[2] == 0x80 &&
- sendpacket[6] == 0x81 && sendpacket[7] == 0x37) {
- /* It's an IPX packet */
- if (!enable_IPX){
- /* Return 1 so we don't pass it up the stack. */
- //FIXME: Take this out when IPX is fixed
- if (net_ratelimit()){
- printk (KERN_INFO
- "%s: WARNING: Unsupported IPX packet received and droppedn",
- devname);
- }
- return 1;
- }
- } else {
- /* It's not IPX so return and pass it up the stack. */
- return 0;
- }
- if( sendpacket[24] == 0x90 && sendpacket[25] == 0x04){
- /* It's IPXWAN */
- if( sendpacket[10] == 0x02 && sendpacket[42] == 0x00){
- /* It's a timer request packet */
- printk(KERN_INFO "%s: Received IPXWAN Timer Request packetn",
- devname);
- /* Go through the routing options and answer no to every
- * option except Unnumbered RIP/SAP
- */
- for(i = 49; sendpacket[i] == 0x00; i += 5){
- /* 0x02 is the option for Unnumbered RIP/SAP */
- if( sendpacket[i + 4] != 0x02){
- sendpacket[i + 1] = 0;
- }
- }
- /* Skip over the extended Node ID option */
- if( sendpacket[i] == 0x04 ){
- i += 8;
- }
- /* We also want to turn off all header compression opt.
- */
- for(; sendpacket[i] == 0x80 ;){
- sendpacket[i + 1] = 0;
- i += (sendpacket[i + 2] << 8) + (sendpacket[i + 3]) + 4;
- }
- /* Set the packet type to timer response */
- sendpacket[42] = 0x01;
- printk(KERN_INFO "%s: Sending IPXWAN Timer Responsen",
- devname);
- } else if( sendpacket[42] == 0x02 ){
- /* This is an information request packet */
- printk(KERN_INFO
- "%s: Received IPXWAN Information Request packetn",
- devname);
- /* Set the packet type to information response */
- sendpacket[42] = 0x03;
- /* Set the router name */
- sendpacket[59] = 'F';
- sendpacket[60] = 'P';
- sendpacket[61] = 'I';
- sendpacket[62] = 'P';
- sendpacket[63] = 'E';
- sendpacket[64] = '-';
- sendpacket[65] = CVHexToAscii(network_number >> 28);
- sendpacket[66] = CVHexToAscii((network_number & 0x0F000000)>> 24);
- sendpacket[67] = CVHexToAscii((network_number & 0x00F00000)>> 20);
- sendpacket[68] = CVHexToAscii((network_number & 0x000F0000)>> 16);
- sendpacket[69] = CVHexToAscii((network_number & 0x0000F000)>> 12);
- sendpacket[70] = CVHexToAscii((network_number & 0x00000F00)>> 8);
- sendpacket[71] = CVHexToAscii((network_number & 0x000000F0)>> 4);
- sendpacket[72] = CVHexToAscii(network_number & 0x0000000F);
- for(i = 73; i < 107; i+= 1)
- {
- sendpacket[i] = 0;
- }
- printk(KERN_INFO "%s: Sending IPXWAN Information Response packetn",
- devname);
- } else {
- printk(KERN_INFO "%s: Unknown IPXWAN packet!n",devname);