diff options
Diffstat (limited to 'drivers/net/wan/wanpipe_multppp.c')
-rw-r--r-- | drivers/net/wan/wanpipe_multppp.c | 2358 |
1 files changed, 0 insertions, 2358 deletions
diff --git a/drivers/net/wan/wanpipe_multppp.c b/drivers/net/wan/wanpipe_multppp.c deleted file mode 100644 index 812a1183c50..00000000000 --- a/drivers/net/wan/wanpipe_multppp.c +++ /dev/null @@ -1,2358 +0,0 @@ -/***************************************************************************** -* wanpipe_multppp.c Multi-Port PPP driver module. -* -* Authors: Nenad Corbic <ncorbic@sangoma.com> -* -* 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. -* ============================================================================ -* Dec 15 2000 Updated for 2.4.X kernel -* Nov 15 2000 Fixed the SyncPPP support for kernels 2.2.16 and higher. -* The pppstruct has changed. -* Jul 13 2000 Using the kernel Syncppp module on top of RAW Wanpipe CHDLC -* module. -*****************************************************************************/ - -#include <linux/module.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 <linux/jiffies.h> /* time_after() macro */ - -#include <linux/in.h> /* sockaddr_in */ -#include <linux/inet.h> -#include <linux/if.h> -#include <asm/byteorder.h> /* htons(), etc. */ -#include <linux/sdlapci.h> -#include <asm/io.h> - -#include <linux/sdla_chdlc.h> /* CHDLC firmware API definitions */ -#include <linux/sdla_asy.h> /* CHDLC (async) API definitions */ - -#include <linux/if_wanpipe_common.h> /* Socket Driver common area */ -#include <linux/if_wanpipe.h> - - -#include <linux/inetdevice.h> -#include <asm/uaccess.h> - -#include <net/syncppp.h> - - -/****** Defines & Macros ****************************************************/ - -#ifdef _DEBUG_ -#define STATIC -#else -#define STATIC static -#endif - -/* 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_CONFIG 0x04 - -#define CHDLC_DFLT_DATA_LEN 1500 /* default MTU */ -#define CHDLC_HDR_LEN 1 - -#define IFF_POINTTOPOINT 0x10 - -#define CHDLC_API 0x01 - -#define PORT(x) (x == 0 ? "PRIMARY" : "SECONDARY" ) -#define MAX_BH_BUFF 10 - -#define CRC_LENGTH 2 -#define PPP_HEADER_LEN 4 - -/******Data Structures*****************************************************/ - -/* This structure is placed in the private data area of the device structure. - * The card structure used to occupy the private area but now the following - * structure will incorporate the card structure along with CHDLC specific data - */ - -typedef struct chdlc_private_area -{ - void *if_ptr; /* General Pointer used by SPPP */ - wanpipe_common_t common; - sdla_t *card; - int TracingEnabled; /* For enabling Tracing */ - unsigned long curr_trace_addr; /* Used for Tracing */ - unsigned long start_trace_addr; - unsigned long end_trace_addr; - unsigned long base_addr_trace_buffer; - unsigned long end_addr_trace_buffer; - unsigned short number_trace_elements; - unsigned available_buffer_space; - unsigned long router_start_time; - unsigned char route_status; - unsigned char route_removed; - unsigned long tick_counter; /* For 5s timeout counter */ - unsigned long router_up_time; - u32 IP_address; /* IP addressing */ - u32 IP_netmask; - unsigned char mc; /* Mulitcast support on/off */ - unsigned short udp_pkt_lgth; /* udp packet processing */ - char udp_pkt_src; - char udp_pkt_data[MAX_LGTH_UDP_MGNT_PKT]; - unsigned short timer_int_enabled; - char update_comms_stats; /* updating comms stats */ - - //FIXME: add driver stats as per frame relay! - -} chdlc_private_area_t; - -/* Route Status options */ -#define NO_ROUTE 0x00 -#define ADD_ROUTE 0x01 -#define ROUTE_ADDED 0x02 -#define REMOVE_ROUTE 0x03 - - -/* variable for keeping track of enabling/disabling FT1 monitor status */ -static int rCount = 0; - -/* variable for tracking how many interfaces to open for WANPIPE on the - two ports */ - -extern void disable_irq(unsigned int); -extern void enable_irq(unsigned int); - -/****** Function Prototypes *************************************************/ -/* WAN link driver entry points. These are called by the WAN router module. */ -static int update(struct wan_device* wandev); -static int new_if(struct wan_device* wandev, struct net_device* dev, - wanif_conf_t* conf); -static int del_if(struct wan_device* wandev, struct net_device* dev); - -/* 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_send(struct sk_buff* skb, struct net_device* dev); -static struct net_device_stats* if_stats(struct net_device* dev); - -static void if_tx_timeout(struct net_device *dev); - -/* CHDLC Firmware interface functions */ -static int chdlc_configure (sdla_t* card, void* data); -static int chdlc_comm_enable (sdla_t* card); -static int chdlc_comm_disable (sdla_t* card); -static int chdlc_read_version (sdla_t* card, char* str); -static int chdlc_set_intr_mode (sdla_t* card, unsigned mode); -static int chdlc_send (sdla_t* card, void* data, unsigned len); -static int chdlc_read_comm_err_stats (sdla_t* card); -static int chdlc_read_op_stats (sdla_t* card); -static int config_chdlc (sdla_t *card); - - -/* Miscellaneous CHDLC Functions */ -static int set_chdlc_config (sdla_t* card); -static void init_chdlc_tx_rx_buff(sdla_t* card, struct net_device *dev); -static int chdlc_error (sdla_t *card, int err, CHDLC_MAILBOX_STRUCT *mb); -static int process_chdlc_exception(sdla_t *card); -static int process_global_exception(sdla_t *card); -static int update_comms_stats(sdla_t* card, - chdlc_private_area_t* chdlc_priv_area); -static void port_set_state (sdla_t *card, int); - -/* Interrupt handlers */ -static void wsppp_isr (sdla_t* card); -static void rx_intr (sdla_t* card); -static void timer_intr(sdla_t *); - -/* Miscellaneous functions */ -static int reply_udp( unsigned char *data, unsigned int mbox_len ); -static int intr_test( sdla_t* card); -static int udp_pkt_type( struct sk_buff *skb , sdla_t* card); -static int store_udp_mgmt_pkt(char udp_pkt_src, sdla_t* card, - struct sk_buff *skb, struct net_device* dev, - chdlc_private_area_t* chdlc_priv_area); -static int process_udp_mgmt_pkt(sdla_t* card, struct net_device* dev, - chdlc_private_area_t* chdlc_priv_area); -static unsigned short calc_checksum (char *, int); -static void s508_lock (sdla_t *card, unsigned long *smp_flags); -static void s508_unlock (sdla_t *card, unsigned long *smp_flags); -static void send_ppp_term_request(struct net_device *dev); - - -static int Intr_test_counter; -/****** Public Functions ****************************************************/ - -/*============================================================================ - * Cisco HDLC 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 wsppp_init (sdla_t* card, wandev_conf_t* conf) -{ - unsigned char port_num; - int err; - unsigned long max_permitted_baud = 0; - SHARED_MEMORY_INFO_STRUCT *flags; - - union - { - char str[80]; - } u; - volatile CHDLC_MAILBOX_STRUCT* mb; - CHDLC_MAILBOX_STRUCT* mb1; - unsigned long timeout; - - /* Verify configuration ID */ - if (conf->config_id != WANCONFIG_MPPP) { - printk(KERN_INFO "%s: invalid configuration ID %u!\n", - card->devname, conf->config_id); - return -EINVAL; - } - - /* Find out which Port to use */ - if ((conf->comm_port == WANOPT_PRI) || (conf->comm_port == WANOPT_SEC)){ - if (card->next){ - - if (conf->comm_port != card->next->u.c.comm_port){ - card->u.c.comm_port = conf->comm_port; - }else{ - printk(KERN_ERR "%s: ERROR - %s port used!\n", - card->wandev.name, PORT(conf->comm_port)); - return -EINVAL; - } - }else{ - card->u.c.comm_port = conf->comm_port; - } - }else{ - printk(KERN_ERR "%s: ERROR - Invalid Port Selected!\n", - card->wandev.name); - return -EINVAL; - } - - - /* Initialize protocol-specific fields */ - if(card->hw.type != SDLA_S514){ - - if (card->u.c.comm_port == WANOPT_PRI){ - card->mbox = (void *) card->hw.dpmbase; - }else{ - card->mbox = (void *) card->hw.dpmbase + - SEC_BASE_ADDR_MB_STRUCT - PRI_BASE_ADDR_MB_STRUCT; - } - }else{ - /* for a S514 adapter, set a pointer to the actual mailbox in the */ - /* allocated virtual memory area */ - if (card->u.c.comm_port == WANOPT_PRI){ - card->mbox = (void *) card->hw.dpmbase + PRI_BASE_ADDR_MB_STRUCT; - }else{ - card->mbox = (void *) card->hw.dpmbase + SEC_BASE_ADDR_MB_STRUCT; - } - } - - mb = mb1 = card->mbox; - - if (!card->configured){ - - /* The board will place an 'I' in the return code to indicate that it is - ready to accept commands. We expect this to be completed in less - than 1 second. */ - - timeout = jiffies + 1 * HZ; - while (mb->return_code != 'I') /* Wait 1s for board to initialize */ - if (time_after(jiffies, timeout)) break; - - if (mb->return_code != 'I') { - printk(KERN_INFO - "%s: Initialization not completed by adapter\n", - card->devname); - printk(KERN_INFO "Please contact Sangoma representative.\n"); - return -EIO; - } - } - - /* 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 (chdlc_read_version(card, u.str)) - return -EIO; - - printk(KERN_INFO "%s: Running Raw CHDLC firmware v%s\n" - "%s: for Multi-Port PPP protocol.\n", - card->devname,u.str,card->devname); - - card->isr = &wsppp_isr; - card->poll = NULL; - card->exec = NULL; - card->wandev.update = &update; - card->wandev.new_if = &new_if; - card->wandev.del_if = &del_if; - card->wandev.udp_port = conf->udp_port; - - card->wandev.new_if_cnt = 0; - - /* reset the number of times the 'update()' proc has been called */ - card->u.c.update_call_count = 0; - - card->wandev.ttl = conf->ttl; - card->wandev.interface = conf->interface; - - if ((card->u.c.comm_port == WANOPT_SEC && conf->interface == WANOPT_V35)&& - card->hw.type != SDLA_S514){ - printk(KERN_INFO "%s: ERROR - V35 Interface not supported on S508 %s port \n", - card->devname, PORT(card->u.c.comm_port)); - return -EIO; - } - - - card->wandev.clocking = conf->clocking; - - port_num = card->u.c.comm_port; - - /* Setup Port Bps */ - - if(card->wandev.clocking) { - if((port_num == WANOPT_PRI) || card->u.c.receive_only) { - /* For Primary Port 0 */ - max_permitted_baud = - (card->hw.type == SDLA_S514) ? - PRI_MAX_BAUD_RATE_S514 : - PRI_MAX_BAUD_RATE_S508; - } - else if(port_num == WANOPT_SEC) { - /* For Secondary Port 1 */ - max_permitted_baud = - (card->hw.type == SDLA_S514) ? - SEC_MAX_BAUD_RATE_S514 : - SEC_MAX_BAUD_RATE_S508; - } - - if(conf->bps > max_permitted_baud) { - conf->bps = max_permitted_baud; - printk(KERN_INFO "%s: Baud too high!\n", - card->wandev.name); - printk(KERN_INFO "%s: Baud rate set to %lu bps\n", - card->wandev.name, max_permitted_baud); - } - - card->wandev.bps = conf->bps; - }else{ - card->wandev.bps = 0; - } - - /* Setup the Port MTU */ - if((port_num == WANOPT_PRI) || card->u.c.receive_only) { - - /* For Primary Port 0 */ - card->wandev.mtu = - (conf->mtu >= MIN_LGTH_CHDLC_DATA_CFG) ? - min_t(unsigned int, conf->mtu, PRI_MAX_NO_DATA_BYTES_IN_FRAME) : - CHDLC_DFLT_DATA_LEN; - } else if(port_num == WANOPT_SEC) { - /* For Secondary Port 1 */ - card->wandev.mtu = - (conf->mtu >= MIN_LGTH_CHDLC_DATA_CFG) ? - min_t(unsigned int, conf->mtu, SEC_MAX_NO_DATA_BYTES_IN_FRAME) : - CHDLC_DFLT_DATA_LEN; - } - - /* Add on a PPP Header */ - card->wandev.mtu += PPP_HEADER_LEN; - - /* Set up the interrupt status area */ - /* Read the CHDLC Configuration and obtain: - * Ptr to shared memory infor struct - * Use this pointer to calculate the value of card->u.c.flags ! - */ - mb1->buffer_length = 0; - mb1->command = READ_CHDLC_CONFIGURATION; - err = sdla_exec(mb1) ? mb1->return_code : CMD_TIMEOUT; - if(err != COMMAND_OK) { - clear_bit(1, (void*)&card->wandev.critical); - - if(card->hw.type != SDLA_S514) - enable_irq(card->hw.irq); - - chdlc_error(card, err, mb1); - return -EIO; - } - - if(card->hw.type == SDLA_S514){ - card->u.c.flags = (void *)(card->hw.dpmbase + - (((CHDLC_CONFIGURATION_STRUCT *)mb1->data)-> - ptr_shared_mem_info_struct)); - }else{ - card->u.c.flags = (void *)(card->hw.dpmbase + - (((CHDLC_CONFIGURATION_STRUCT *)mb1->data)-> - ptr_shared_mem_info_struct % SDLA_WINDOWSIZE)); - } - - flags = card->u.c.flags; - - /* This is for the ports link state */ - card->wandev.state = WAN_DUALPORT; - card->u.c.state = WAN_DISCONNECTED; - - - if (!card->wandev.piggyback){ - err = intr_test(card); - - if(err || (Intr_test_counter < MAX_INTR_TEST_COUNTER)) { - printk(KERN_ERR "%s: Interrupt test failed (%i)\n", - card->devname, Intr_test_counter); - printk(KERN_ERR "%s: Please choose another interrupt\n", - card->devname); - return -EIO; - } - - printk(KERN_INFO "%s: Interrupt test passed (%i)\n", - card->devname, Intr_test_counter); - } - - - if (chdlc_set_intr_mode(card, APP_INT_ON_TIMER)){ - printk (KERN_INFO "%s: Failed to set interrupt triggers!\n", - card->devname); - return -EIO; - } - - /* Mask the Timer interrupt */ - flags->interrupt_info_struct.interrupt_permission &= - ~APP_INT_ON_TIMER; - - printk(KERN_INFO "\n"); - - return 0; -} - -/******* WAN Device Driver Entry Points *************************************/ - -/*============================================================================ - * Update device status & statistics - * This procedure is called when updating the PROC file system and returns - * various communications statistics. These statistics are accumulated from 3 - * different locations: - * 1) The 'if_stats' recorded for the device. - * 2) Communication error statistics on the adapter. - * 3) CHDLC operational statistics on the adapter. - * The board level statistics are read during a timer interrupt. Note that we - * read the error and operational statistics during consecitive timer ticks so - * as to minimize the time that we are inside the interrupt handler. - * - */ -static int update(struct wan_device* wandev) -{ - sdla_t* card = wandev->private; - struct net_device* dev; - volatile chdlc_private_area_t* chdlc_priv_area; - SHARED_MEMORY_INFO_STRUCT *flags; - unsigned long timeout; - - /* sanity checks */ - if((wandev == NULL) || (wandev->private == NULL)) - return -EFAULT; - - if(wandev->state == WAN_UNCONFIGURED) - return -ENODEV; - - /* more sanity checks */ - if(!card->u.c.flags) - return -ENODEV; - - if((dev=card->wandev.dev) == NULL) - return -ENODEV; - - if((chdlc_priv_area=dev->priv) == NULL) - return -ENODEV; - - flags = card->u.c.flags; - - if(chdlc_priv_area->update_comms_stats){ - return -EAGAIN; - } - - /* we will need 2 timer interrupts to complete the */ - /* reading of the statistics */ - chdlc_priv_area->update_comms_stats = 2; - flags->interrupt_info_struct.interrupt_permission |= APP_INT_ON_TIMER; - chdlc_priv_area->timer_int_enabled = TMR_INT_ENABLED_UPDATE; - - /* wait a maximum of 1 second for the statistics to be updated */ - timeout = jiffies + 1 * HZ; - for(;;) { - if(chdlc_priv_area->update_comms_stats == 0) - break; - if (time_after(jiffies, timeout)){ - chdlc_priv_area->update_comms_stats = 0; - chdlc_priv_area->timer_int_enabled &= - ~TMR_INT_ENABLED_UPDATE; - 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(struct wan_device* wandev, struct net_device* pdev, - wanif_conf_t* conf) -{ - - struct ppp_device *pppdev = (struct ppp_device *)pdev; - struct net_device *dev = NULL; - struct sppp *sp; - sdla_t* card = wandev->private; - chdlc_private_area_t* chdlc_priv_area; - - if ((conf->name[0] == '\0') || (strlen(conf->name) > WAN_IFNAME_SZ)) { - printk(KERN_INFO "%s: invalid interface name!\n", - card->devname); - return -EINVAL; - } - - /* allocate and initialize private data */ - chdlc_priv_area = kmalloc(sizeof(chdlc_private_area_t), GFP_KERNEL); - - if(chdlc_priv_area == NULL) - return -ENOMEM; - - memset(chdlc_priv_area, 0, sizeof(chdlc_private_area_t)); - - chdlc_priv_area->card = card; - - /* initialize data */ - strcpy(card->u.c.if_name, conf->name); - - if(card->wandev.new_if_cnt > 0) { - kfree(chdlc_priv_area); - return -EEXIST; - } - - card->wandev.new_if_cnt++; - - chdlc_priv_area->TracingEnabled = 0; - - //We don't need this any more - chdlc_priv_area->route_status = NO_ROUTE; - chdlc_priv_area->route_removed = 0; - - printk(KERN_INFO "%s: Firmware running in HDLC STREAMING Mode\n", - wandev->name); - - /* Setup wanpipe as a router (WANPIPE) or as an API */ - if( strcmp(conf->usedby, "WANPIPE") == 0) { - printk(KERN_INFO "%s: Driver running in WANPIPE mode!\n", - wandev->name); - card->u.c.usedby = WANPIPE; - } else { - printk(KERN_INFO - "%s: API Mode is not supported for SyncPPP!\n", - wandev->name); - kfree(chdlc_priv_area); - return -EINVAL; - } - - /* Get Multicast Information */ - chdlc_priv_area->mc = conf->mc; - - - chdlc_priv_area->if_ptr = pppdev; - - /* prepare network device data space for registration */ - - strcpy(dev->name,card->u.c.if_name); - - /* Attach PPP protocol layer to pppdev - * The sppp_attach() will initilize the dev structure - * and setup ppp layer protocols. - * All we have to do is to bind in: - * if_open(), if_close(), if_send() and get_stats() functions. - */ - sppp_attach(pppdev); - dev = pppdev->dev; - sp = &pppdev->sppp; - - /* Enable PPP Debugging */ - // FIXME Fix this up somehow - //sp->pp_flags |= PP_DEBUG; - sp->pp_flags &= ~PP_CISCO; - - dev->init = &if_init; - dev->priv = chdlc_priv_area; - - return 0; -} - - - - -/*============================================================================ - * Delete logical channel. - */ -static int del_if(struct wan_device* wandev, struct net_device* dev) -{ - chdlc_private_area_t *chdlc_priv_area = dev->priv; - sdla_t *card = chdlc_priv_area->card; - unsigned long smp_lock; - - /* Detach the PPP layer */ - printk(KERN_INFO "%s: Detaching SyncPPP Module from %s\n", - wandev->name,dev->name); - - lock_adapter_irq(&wandev->lock,&smp_lock); - - sppp_detach(dev); - chdlc_priv_area->if_ptr=NULL; - - chdlc_set_intr_mode(card, 0); - if (card->u.c.comm_enabled) - chdlc_comm_disable(card); - unlock_adapter_irq(&wandev->lock,&smp_lock); - - port_set_state(card, WAN_DISCONNECTED); - - return 0; -} - - -/****** 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(struct net_device* dev) -{ - chdlc_private_area_t* chdlc_priv_area = dev->priv; - sdla_t* card = chdlc_priv_area->card; - struct wan_device* wandev = &card->wandev; - - /* NOTE: Most of the dev initialization was - * done in sppp_attach(), called by new_if() - * function. All we have to do here is - * to link four major routines below. - */ - - /* Initialize device driver entry points */ - dev->open = &if_open; - dev->stop = &if_close; - dev->hard_start_xmit = &if_send; - dev->get_stats = &if_stats; - dev->tx_timeout = &if_tx_timeout; - dev->watchdog_timeo = TX_TIMEOUT; - - - /* Initialize hardware parameters */ - 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; - - /* Set transmit buffer queue length - * If we over fill this queue the packets will - * be droped by the kernel. - * sppp_attach() sets this to 10, but - * 100 will give us more room at low speeds. - */ - dev->tx_queue_len = 100; - - return 0; -} - - -/*============================================================================ - * Handle transmit timeout event from netif watchdog - */ -static void if_tx_timeout(struct net_device *dev) -{ - chdlc_private_area_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. - */ - - ++card->wandev.stats.collisions; - - printk (KERN_INFO "%s: Transmit timed out on %s\n", card->devname,dev->name); - netif_wake_queue (dev); -} - - -/*============================================================================ - * Open network interface. - * o enable communications and interrupts. - * o prevent module from unloading by incrementing use count - * - * Return 0 if O.k. or errno. - */ -static int if_open(struct net_device* dev) -{ - chdlc_private_area_t* chdlc_priv_area = dev->priv; - sdla_t* card = chdlc_priv_area->card; - struct timeval tv; - SHARED_MEMORY_INFO_STRUCT *flags = card->u.c.flags; - - /* Only one open per interface is allowed */ - if (netif_running(dev)) - return -EBUSY; - - /* Start PPP Layer */ - if (sppp_open(dev)){ - return -EIO; - } - - do_gettimeofday(&tv); - chdlc_priv_area->router_start_time = tv.tv_sec; - - netif_start_queue(dev); - - wanpipe_open(card); - - chdlc_priv_area->timer_int_enabled |= TMR_INT_ENABLED_CONFIG; - flags->interrupt_info_struct.interrupt_permission |= APP_INT_ON_TIMER; - return 0; -} - -/*============================================================================ - * Close network interface. - * o if this is the last close, then disable communications and interrupts. - * o reset flags. - */ -static int if_close(struct net_device* dev) -{ - chdlc_private_area_t* chdlc_priv_area = dev->priv; - sdla_t* card = chdlc_priv_area->card; - - /* Stop the PPP Layer */ - sppp_close(dev); - netif_stop_queue(dev); - - wanpipe_close(card); - - return 0; -} - -/*============================================================================ - * 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 check link state. If link is not up, then drop the packet. - * o execute adapter send command. - * 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. Setting tbusy flag 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) -{ - chdlc_private_area_t *chdlc_priv_area = dev->priv; - sdla_t *card = chdlc_priv_area->card; - SHARED_MEMORY_INFO_STRUCT *flags = card->u.c.flags; - INTERRUPT_INFORMATION_STRUCT *chdlc_int = &flags->interrupt_info_struct; - int udp_type = 0; - unsigned long smp_flags; - int err=0; - - netif_stop_queue(dev); - - - if (skb == NULL){ - /* If we get here, some higher layer thinks we've missed an - * tx-done interrupt. - */ - printk(KERN_INFO "%s: Received NULL skb buffer! interface %s got kicked!\n", - card->devname, dev->name); - - netif_wake_queue(dev); - return 0; - } - - if (ntohs(skb->protocol) != htons(PVC_PROT)){ - /* check the udp packet type */ - - udp_type = udp_pkt_type(skb, card); - if (udp_type == UDP_CPIPE_TYPE){ - if(store_udp_mgmt_pkt(UDP_PKT_FRM_STACK, card, skb, dev, - chdlc_priv_area)){ - chdlc_int->interrupt_permission |= - APP_INT_ON_TIMER; - } - netif_start_queue(dev); - return 0; - } - } - - /* Lock the 508 Card: SMP is supported */ - if(card->hw.type != SDLA_S514){ - s508_lock(card,&smp_flags); - } - - if (test_and_set_bit(SEND_CRIT, (void*)&card->wandev.critical)){ - - printk(KERN_INFO "%s: Critical in if_send: %lx\n", - card->wandev.name,card->wandev.critical); - ++card->wandev.stats.tx_dropped; - netif_start_queue(dev); - goto if_send_crit_exit; - } - - if (card->wandev.state != WAN_CONNECTED){ - ++card->wandev.stats.tx_dropped; - netif_start_queue(dev); - goto if_send_crit_exit; - } - - if (chdlc_send(card, skb->data, skb->len)){ - netif_stop_queue(dev); - - }else{ - ++card->wandev.stats.tx_packets; - card->wandev.stats.tx_bytes += skb->len; - dev->trans_start = jiffies; - netif_start_queue(dev); - } - -if_send_crit_exit: - if (!(err=netif_queue_stopped(dev))){ - dev_kfree_skb_any(skb); - }else{ - chdlc_priv_area->tick_counter = jiffies; - chdlc_int->interrupt_permission |= APP_INT_ON_TX_FRAME; - } - - clear_bit(SEND_CRIT, (void*)&card->wandev.critical); - if(card->hw.type != SDLA_S514){ - s508_unlock(card,&smp_flags); - } - - return err; -} - - -/*============================================================================ - * Reply to UDP Management system. - * Return length of reply. - */ -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; - chdlc_udp_pkt_t *c_udp_pkt = (chdlc_udp_pkt_t *)data; - - /* Set length of packet */ - len = sizeof(ip_pkt_t)+ - sizeof(udp_pkt_t)+ - sizeof(wp_mgmt_t)+ - sizeof(cblock_t)+ - sizeof(trace_info_t)+ - mbox_len; - - /* fill in UDP reply */ - c_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)+ - sizeof(trace_info_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); - c_udp_pkt->udp_pkt.udp_length = temp; - - /* swap UDP ports */ - temp = c_udp_pkt->udp_pkt.udp_src_port; - c_udp_pkt->udp_pkt.udp_src_port = - c_udp_pkt->udp_pkt.udp_dst_port; - c_udp_pkt->udp_pkt.udp_dst_port = temp; - - /* add UDP pseudo header */ - temp = 0x1100; - *((unsigned short *)(c_udp_pkt->data+mbox_len+even_bound)) = temp; - temp = (udp_length<<8)|(udp_length>>8); - *((unsigned short *)(c_udp_pkt->data+mbox_len+even_bound+2)) = temp; - - - /* calculate UDP checksum */ - c_udp_pkt->udp_pkt.udp_checksum = 0; - c_udp_pkt->udp_pkt.udp_checksum = calc_checksum(&data[UDP_OFFSET],udp_length+UDP_OFFSET); - - /* fill in IP length */ - ip_length = len; - temp = (ip_length<<8)|(ip_length>>8); - c_udp_pkt->ip_pkt.total_length = temp; - - /* swap IP addresses */ - ip_temp = c_udp_pkt->ip_pkt.ip_src_address; - c_udp_pkt->ip_pkt.ip_src_address = c_udp_pkt->ip_pkt.ip_dst_address; - c_udp_pkt->ip_pkt.ip_dst_address = ip_temp; - - /* fill in IP checksum */ - c_udp_pkt->ip_pkt.hdr_checksum = 0; - c_udp_pkt->ip_pkt.hdr_checksum = calc_checksum(data,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; -} - - -/*============================================================================ - * Get ethernet-style interface statistics. - * Return a pointer to struct enet_statistics. - */ -static struct net_device_stats* if_stats(struct net_device* dev) -{ - sdla_t *my_card; - chdlc_private_area_t* chdlc_priv_area; - - /* Shutdown bug fix. In del_if() we kill - * dev->priv pointer. This function, gets - * called after del_if(), thus check - * if pointer has been deleted */ - if ((chdlc_priv_area=dev->priv) == NULL) - return NULL; - - my_card = chdlc_priv_area->card; - return &my_card->wandev.stats; -} - - -/****** Cisco HDLC Firmware Interface Functions *******************************/ - -/*============================================================================ - * Read firmware code version. - * Put code version as ASCII string in str. - */ -static int chdlc_read_version (sdla_t* card, char* str) -{ - CHDLC_MAILBOX_STRUCT* mb = card->mbox; - int len; - char err; - mb->buffer_length = 0; - mb->command = READ_CHDLC_CODE_VERSION; - err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; - - if(err != COMMAND_OK) { - chdlc_error(card,err,mb); - } - else if (str) { /* is not null */ - len = mb->buffer_length; - memcpy(str, mb->data, len); - str[len] = '\0'; - } - return (err); -} - -/*----------------------------------------------------------------------------- - * Configure CHDLC firmware. - */ -static int chdlc_configure (sdla_t* card, void* data) -{ - int err; - CHDLC_MAILBOX_STRUCT *mailbox = card->mbox; - int data_length = sizeof(CHDLC_CONFIGURATION_STRUCT); - - mailbox->buffer_length = data_length; - memcpy(mailbox->data, data, data_length); - mailbox->command = SET_CHDLC_CONFIGURATION; - err = sdla_exec(mailbox) ? mailbox->return_code : CMD_TIMEOUT; - - if (err != COMMAND_OK) chdlc_error (card, err, mailbox); - - return err; -} - - -/*============================================================================ - * Set interrupt mode -- HDLC Version. - */ - -static int chdlc_set_intr_mode (sdla_t* card, unsigned mode) -{ - CHDLC_MAILBOX_STRUCT* mb = card->mbox; - CHDLC_INT_TRIGGERS_STRUCT* int_data = - (CHDLC_INT_TRIGGERS_STRUCT *)mb->data; - int err; - - int_data->CHDLC_interrupt_triggers = mode; - int_data->IRQ = card->hw.irq; - int_data->interrupt_timer = 1; - - mb->buffer_length = sizeof(CHDLC_INT_TRIGGERS_STRUCT); - mb->command = SET_CHDLC_INTERRUPT_TRIGGERS; - err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; - if (err != COMMAND_OK) - chdlc_error (card, err, mb); - return err; -} - - -/*============================================================================ - * Enable communications. - */ - -static int chdlc_comm_enable (sdla_t* card) -{ - int err; - CHDLC_MAILBOX_STRUCT* mb = card->mbox; - - mb->buffer_length = 0; - mb->command = ENABLE_CHDLC_COMMUNICATIONS; - err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; - if (err != COMMAND_OK) - chdlc_error(card, err, mb); - else - card->u.c.comm_enabled=1; - - return err; -} - -/*============================================================================ - * Disable communications and Drop the Modem lines (DCD and RTS). - */ -static int chdlc_comm_disable (sdla_t* card) -{ - int err; - CHDLC_MAILBOX_STRUCT* mb = card->mbox; - - mb->buffer_length = 0; - mb->command = DISABLE_CHDLC_COMMUNICATIONS; - err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; - if (err != COMMAND_OK) - chdlc_error(card,err,mb); - - return err; -} - -/*============================================================================ - * Read communication error statistics. - */ -static int chdlc_read_comm_err_stats (sdla_t* card) -{ - int err; - CHDLC_MAILBOX_STRUCT* mb = card->mbox; - - mb->buffer_length = 0; - mb->command = READ_COMMS_ERROR_STATS; - err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; - if (err != COMMAND_OK) - chdlc_error(card,err,mb); - return err; -} - - -/*============================================================================ - * Read CHDLC operational statistics. - */ -static int chdlc_read_op_stats (sdla_t* card) -{ - int err; - CHDLC_MAILBOX_STRUCT* mb = card->mbox; - - mb->buffer_length = 0; - mb->command = READ_CHD |