sdla_x25.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:151k
- /*****************************************************************************
- * sdla_x25.c WANPIPE(tm) Multiprotocol WAN Link Driver. X.25 module.
- *
- * Author: 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.
- * ============================================================================
- * Apr 03, 2001 Nenad Corbic o Fixed the rx_skb=NULL bug in x25 in rx_intr().
- * Dec 26, 2000 Nenad Corbic o Added a new polling routine, that uses
- * a kernel timer (more efficient).
- * Dec 25, 2000 Nenad Corbic o Updated for 2.4.X kernel
- * Jul 26, 2000 Nenad Corbic o Increased the local packet buffering
- * for API to 4096+header_size.
- * Jul 17, 2000 Nenad Corbic o Fixed the x25 startup bug. Enable
- * communications only after all interfaces
- * come up. HIGH SVC/PVC is used to calculate
- * the number of channels.
- * Enable protocol only after all interfaces
- * are enabled.
- * Jul 10, 2000 Nenad Corbic o Fixed the M_BIT bug.
- * Apr 25, 2000 Nenad Corbic o Pass Modem messages to the API.
- * Disable idle timeout in X25 API.
- * Apr 14, 2000 Nenad Corbic o Fixed: Large LCN number support.
- * Maximum LCN number is 4095.
- * Maximum number of X25 channels is 255.
- * Apr 06, 2000 Nenad Corbic o Added SMP Support.
- * Mar 29, 2000 Nenad Corbic o Added support for S514 PCI Card
- * Mar 23, 2000 Nenad Corbic o Improved task queue, BH handling.
- * Mar 14, 2000 Nenad Corbic o Updated Protocol Violation handling
- * routines. Bug Fix.
- * Mar 10, 2000 Nenad Corbic o Bug Fix: corrupted mbox recovery.
- * Mar 09, 2000 Nenad Corbic o Fixed the auto HDLC bug.
- * Mar 08, 2000 Nenad Corbic o Fixed LAPB HDLC startup problems.
- * Application must bring the link up
- * before tx/rx, and bring the
- * link down on close().
- * Mar 06, 2000 Nenad Corbic o Added an option for logging call setup
- * information.
- * Feb 29, 2000 Nenad Corbic o Added support for LAPB HDLC API
- * Feb 25, 2000 Nenad Corbic o Fixed the modem failure handling.
- * No Modem OOB message will be passed
- * to the user.
- * Feb 21, 2000 Nenad Corbic o Added Xpipemon Debug Support
- * Dec 30, 1999 Nenad Corbic o Socket based X25API
- * Sep 17, 1998 Jaspreet Singh o Updates for 2.2.X kernel
- * Mar 15, 1998 Alan Cox o 2.1.x porting
- * Dec 19, 1997 Jaspreet Singh o Added multi-channel IPX support
- * Nov 27, 1997 Jaspreet Singh o Added protection against enabling of irqs
- * when they are disabled.
- * Nov 17, 1997 Farhan Thawar o Added IPX support
- * o Changed if_send() to now buffer packets when
- * the board is busy
- * o Removed queueing of packets via the polling
- * routing
- * o Changed if_send() critical flags to properly
- * handle race conditions
- * Nov 06, 1997 Farhan Thawar o Added support for SVC timeouts
- * o Changed PVC encapsulation to ETH_P_IP
- * Jul 21, 1997 Jaspreet Singh o Fixed freeing up of buffers using kfree()
- * when packets are received.
- * Mar 11, 1997 Farhan Thawar Version 3.1.1
- * o added support for V35
- * o changed if_send() to return 0 if
- * wandev.critical() is true
- * o free socket buffer in if_send() if
- * returning 0
- * o added support for single '@' address to
- * accept all incoming calls
- * o fixed bug in set_chan_state() to disconnect
- * Jan 15, 1997 Gene Kozin Version 3.1.0
- * o implemented exec() entry point
- * Jan 07, 1997 Gene Kozin Initial version.
- *****************************************************************************/
- /*======================================================
- * Includes
- *=====================================================*/
- #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/ctype.h>
- #include <linux/slab.h> /* kmalloc(), kfree() */
- #include <linux/wanrouter.h> /* WAN router definitions */
- #include <linux/wanpipe.h> /* WANPIPE common user API definitions */
- #include <asm/byteorder.h> /* htons(), etc. */
- #include <asm/atomic.h>
- #include <linux/delay.h> /* Experimental delay */
- #if defined(LINUX_2_1) || defined(LINUX_2_4)
- #include <asm/uaccess.h>
- #else
- #include <asm/segment.h>
- #include <net/route.h>
- #endif
- #include <linux/if.h>
- #include <linux/if_arp.h>
- #include <linux/sdla_x25.h> /* X.25 firmware API definitions */
- #include <linux/if_wanpipe_common.h>
- #include <linux/if_wanpipe.h>
- /*======================================================
- * Defines & Macros
- *=====================================================*/
- #define CMD_OK 0 /* normal firmware return code */
- #define CMD_TIMEOUT 0xFF /* firmware command timed out */
- #define MAX_CMD_RETRY 10 /* max number of firmware retries */
- #define X25_CHAN_MTU 4096 /* unfragmented logical channel MTU */
- #define X25_HRDHDR_SZ 7 /* max encapsulation header size */
- #define X25_CONCT_TMOUT (90*HZ) /* link connection timeout */
- #define X25_RECON_TMOUT (10*HZ) /* link connection timeout */
- #define CONNECT_TIMEOUT (90*HZ) /* link connection timeout */
- #define HOLD_DOWN_TIME (30*HZ) /* link hold down time */
- #define MAX_BH_BUFF 10
- #define M_BIT 0x01
- //#define PRINT_DEBUG 1
- #ifdef PRINT_DEBUG
- #define DBG_PRINTK(format, a...) printk(format, ## a)
- #else
- #define DBG_PRINTK(format, a...)
- #endif
- #define TMR_INT_ENABLED_POLL_ACTIVE 0x01
- #define TMR_INT_ENABLED_POLL_CONNECT_ON 0x02
- #define TMR_INT_ENABLED_POLL_CONNECT_OFF 0x04
- #define TMR_INT_ENABLED_POLL_DISCONNECT 0x08
- #define TMR_INT_ENABLED_CMD_EXEC 0x10
- #define TMR_INT_ENABLED_UPDATE 0x20
- #define TMR_INT_ENABLED_UDP_PKT 0x40
- #define MAX_X25_ADDR_SIZE 16
- #define MAX_X25_DATA_SIZE 129
- #define MAX_X25_FACL_SIZE 110
- #define TRY_CMD_AGAIN 2
- #define DELAY_RESULT 1
- #define RETURN_RESULT 0
- #define DCD(x) (x & 0x03 ? "HIGH" : "LOW")
- #define CTS(x) (x & 0x05 ? "HIGH" : "LOW")
- /* Driver will not write log messages about
- * modem status if defined.*/
- #define MODEM_NOT_LOG 1
- /*====================================================
- * For 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)))
- /*====================================================
- * MEMORY DEBUGGING FUNCTION
- *====================================================
- #define KMEM_SAFETYZONE 8
- static void * dbg_kmalloc(unsigned int size, int prio, int line) {
- int i = 0;
- void * v = kmalloc(size+sizeof(unsigned int)+2*KMEM_SAFETYZONE*8,prio);
- char * c1 = v;
- c1 += sizeof(unsigned int);
- *((unsigned int *)v) = size;
- for (i = 0; i < KMEM_SAFETYZONE; i++) {
- c1[0] = 'D'; c1[1] = 'E'; c1[2] = 'A'; c1[3] = 'D';
- c1[4] = 'B'; c1[5] = 'E'; c1[6] = 'E'; c1[7] = 'F';
- c1 += 8;
- }
- c1 += size;
- for (i = 0; i < KMEM_SAFETYZONE; i++) {
- c1[0] = 'M'; c1[1] = 'U'; c1[2] = 'N'; c1[3] = 'G';
- c1[4] = 'W'; c1[5] = 'A'; c1[6] = 'L'; c1[7] = 'L';
- c1 += 8;
- }
- v = ((char *)v) + sizeof(unsigned int) + KMEM_SAFETYZONE*8;
- printk(KERN_INFO "line %d kmalloc(%d,%d) = %pn",line,size,prio,v);
- return v;
- }
- static void dbg_kfree(void * v, int line) {
- unsigned int * sp = (unsigned int *)(((char *)v) - (sizeof(unsigned int) + KMEM_SAFETYZONE*8));
- unsigned int size = *sp;
- char * c1 = ((char *)v) - KMEM_SAFETYZONE*8;
- int i = 0;
- for (i = 0; i < KMEM_SAFETYZONE; i++) {
- if ( c1[0] != 'D' || c1[1] != 'E' || c1[2] != 'A' || c1[3] != 'D'
- || c1[4] != 'B' || c1[5] != 'E' || c1[6] != 'E' || c1[7] != 'F') {
- printk(KERN_INFO "kmalloced block at %p has been corrupted (underrun)!n",v);
- printk(KERN_INFO " %4x: %2x %2x %2x %2x %2x %2x %2x %2xn", i*8,
- c1[0],c1[1],c1[2],c1[3],c1[4],c1[5],c1[6],c1[7] );
- }
- c1 += 8;
- }
- c1 += size;
- for (i = 0; i < KMEM_SAFETYZONE; i++) {
- if ( c1[0] != 'M' || c1[1] != 'U' || c1[2] != 'N' || c1[3] != 'G'
- || c1[4] != 'W' || c1[5] != 'A' || c1[6] != 'L' || c1[7] != 'L'
- ) {
- printk(KERN_INFO "kmalloced block at %p has been corrupted (overrun):n",v);
- printk(KERN_INFO " %4x: %2x %2x %2x %2x %2x %2x %2x %2xn", i*8,
- c1[0],c1[1],c1[2],c1[3],c1[4],c1[5],c1[6],c1[7] );
- }
- c1 += 8;
- }
- printk(KERN_INFO "line %d kfree(%p)n",line,v);
- v = ((char *)v) - (sizeof(unsigned int) + KMEM_SAFETYZONE*8);
- kfree(v);
- }
- #define kmalloc(x,y) dbg_kmalloc(x,y,__LINE__)
- #define kfree(x) dbg_kfree(x,__LINE__)
- ==============================================================*/
- /*===============================================
- * Data Structures
- *===============================================*/
- /*========================================================
- * Name: x25_channel
- *
- * Purpose: To hold private informaton for each
- * logical channel.
- *
- * Rationale: Per-channel debugging is possible if each
- * channel has its own private area.
- *
- * Assumptions:
- *
- * Description: This is an extention of the 'netdevice_t'
- * we create for each network interface to keep
- * the rest of X.25 channel-specific data.
- *
- * Construct: Typedef
- */
- typedef struct x25_channel
- {
- wanpipe_common_t common; /* common area for x25api and socket */
- char name[WAN_IFNAME_SZ+1]; /* interface name, ASCIIZ */
- char addr[WAN_ADDRESS_SZ+1]; /* media address, ASCIIZ */
- unsigned tx_pkt_size;
- unsigned short protocol; /* ethertype, 0 - multiplexed */
- char drop_sequence; /* mark sequence for dropping */
- unsigned long state_tick; /* time of the last state change */
- unsigned idle_timeout; /* sec, before disconnecting */
- unsigned long i_timeout_sofar; /* # of sec's we've been idle */
- unsigned hold_timeout; /* sec, before re-connecting */
- unsigned long tick_counter; /* counter for transmit time out */
- char devtint; /* Weather we should dev_tint() */
- struct sk_buff* rx_skb; /* receive socket buffer */
- struct sk_buff* tx_skb; /* transmit socket buffer */
- bh_data_t *bh_head; /* Circular buffer for x25api_bh */
- unsigned long tq_working;
- volatile int bh_write;
- volatile int bh_read;
- atomic_t bh_buff_used;
- sdla_t* card; /* -> owner */
- netdevice_t *dev; /* -> bound devce */
- int ch_idx;
- unsigned char enable_IPX;
- unsigned long network_number;
- #if defined(LINUX_2_1) || defined(LINUX_2_4)
- struct net_device_stats ifstats; /* interface statistics */
- #else
- struct enet_statistics ifstats;
- #endif
- unsigned short transmit_length;
- unsigned short tx_offset;
- char transmit_buffer[X25_CHAN_MTU+sizeof(x25api_hdr_t)];
- if_send_stat_t if_send_stat;
- rx_intr_stat_t rx_intr_stat;
- pipe_mgmt_stat_t pipe_mgmt_stat;
- unsigned long router_start_time; /* Router start time in seconds */
- unsigned long router_up_time;
-
- } x25_channel_t;
- /* FIXME Take this out */
- #ifdef NEX_OLD_CALL_INFO
- typedef struct x25_call_info
- {
- char dest[17]; PACKED;/* ASCIIZ destination address */
- char src[17]; PACKED;/* ASCIIZ source address */
- char nuser; PACKED;/* number of user data bytes */
- unsigned char user[127]; PACKED;/* user data */
- char nfacil; PACKED;/* number of facilities */
- struct
- {
- unsigned char code; PACKED;
- unsigned char parm; PACKED;
- } facil[64]; /* facilities */
- } x25_call_info_t;
- #else
- typedef struct x25_call_info
- {
- char dest[MAX_X25_ADDR_SIZE] PACKED;/* ASCIIZ destination address */
- char src[MAX_X25_ADDR_SIZE] PACKED;/* ASCIIZ source address */
- unsigned char nuser PACKED;
- unsigned char user[MAX_X25_DATA_SIZE] PACKED;/* user data */
- unsigned char nfacil PACKED;
- unsigned char facil[MAX_X25_FACL_SIZE] PACKED;
- unsigned short lcn PACKED;
- } x25_call_info_t;
- #endif
-
- /*===============================================
- * Private 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);
- static void disable_comm_shutdown(sdla_t *card);
- /*=================================================
- * WANPIPE-specific entry points
- */
- static int wpx_exec (struct sdla* card, void* u_cmd, void* u_data);
- static void x25api_bh (netdevice_t *);
- static int x25api_bh_cleanup (netdevice_t *);
- static int bh_enqueue (netdevice_t *, struct sk_buff *);
- /*=================================================
- * Network device interface
- */
- static int if_init (netdevice_t* dev);
- static int if_open (netdevice_t* dev);
- static int if_close (netdevice_t* dev);
- static int if_header (struct sk_buff* skb, netdevice_t* dev,
- unsigned short type, void* daddr, void* saddr, unsigned len);
- static int if_rebuild_hdr (struct sk_buff* skb);
- static int if_send (struct sk_buff* skb, netdevice_t* dev);
- static struct net_device_stats *if_stats (netdevice_t* dev);
- #ifdef LINUX_2_4
- static void if_tx_timeout (netdevice_t *dev);
- #endif
- /*=================================================
- * Interrupt handlers
- */
- static void wpx_isr (sdla_t *);
- static void rx_intr (sdla_t *);
- static void tx_intr (sdla_t *);
- static void status_intr (sdla_t *);
- static void event_intr (sdla_t *);
- static void spur_intr (sdla_t *);
- static void timer_intr (sdla_t *);
- static int tx_intr_send(sdla_t *, netdevice_t *);
- static netdevice_t * move_dev_to_next (sdla_t *, netdevice_t *);
- /*=================================================
- * Background polling routines
- */
- static void wpx_poll (sdla_t* card);
- static void poll_disconnected (sdla_t* card);
- static void poll_connecting (sdla_t* card);
- static void poll_active (sdla_t* card);
- static void trigger_x25_poll(sdla_t *card);
- static void x25_timer_routine(unsigned long data);
- /*=================================================
- * X.25 firmware interface functions
- */
- static int x25_get_version (sdla_t* card, char* str);
- static int x25_configure (sdla_t* card, TX25Config* conf);
- static int hdlc_configure (sdla_t* card, TX25Config* conf);
- static int set_hdlc_level (sdla_t* card);
- static int x25_get_err_stats (sdla_t* card);
- static int x25_get_stats (sdla_t* card);
- static int x25_set_intr_mode (sdla_t* card, int mode);
- static int x25_close_hdlc (sdla_t* card);
- static int x25_open_hdlc (sdla_t* card);
- static int x25_setup_hdlc (sdla_t* card);
- static int x25_set_dtr (sdla_t* card, int dtr);
- static int x25_get_chan_conf (sdla_t* card, x25_channel_t* chan);
- static int x25_place_call (sdla_t* card, x25_channel_t* chan);
- static int x25_accept_call (sdla_t* card, int lcn, int qdm);
- static int x25_clear_call (sdla_t* card, int lcn, int cause, int diagn);
- static int x25_send (sdla_t* card, int lcn, int qdm, int len, void* buf);
- static int x25_fetch_events (sdla_t* card);
- static int x25_error (sdla_t* card, int err, int cmd, int lcn);
- /*=================================================
- * X.25 asynchronous event handlers
- */
- static int incoming_call (sdla_t* card, int cmd, int lcn, TX25Mbox* mb);
- static int call_accepted (sdla_t* card, int cmd, int lcn, TX25Mbox* mb);
- static int call_cleared (sdla_t* card, int cmd, int lcn, TX25Mbox* mb);
- static int timeout_event (sdla_t* card, int cmd, int lcn, TX25Mbox* mb);
- static int restart_event (sdla_t* card, int cmd, int lcn, TX25Mbox* mb);
- /*=================================================
- * Miscellaneous functions
- */
- static int connect (sdla_t* card);
- static int disconnect (sdla_t* card);
- static netdevice_t* get_dev_by_lcn(wan_device_t* wandev, unsigned lcn);
- static int chan_connect (netdevice_t* dev);
- static int chan_disc (netdevice_t* dev);
- static void set_chan_state (netdevice_t* dev, int state);
- static int chan_send (netdevice_t* , void* , unsigned, unsigned char);
- static unsigned char bps_to_speed_code (unsigned long bps);
- static unsigned int dec_to_uint (unsigned char* str, int len);
- static unsigned int hex_to_uint (unsigned char*, int);
- static void parse_call_info (unsigned char*, x25_call_info_t*);
- static netdevice_t * find_channel(sdla_t *, unsigned);
- static void bind_lcn_to_dev (sdla_t *, netdevice_t *,unsigned);
- static void setup_for_delayed_transmit (netdevice_t*, void*, unsigned);
- /*=================================================
- * X25 API Functions
- */
- static int wanpipe_pull_data_in_skb (sdla_t *, netdevice_t *, struct sk_buff **);
- static void timer_intr_exec(sdla_t *, unsigned char);
- static int execute_delayed_cmd (sdla_t*, netdevice_t *, mbox_cmd_t *,char);
- static int api_incoming_call (sdla_t*, TX25Mbox *, int);
- static int alloc_and_init_skb_buf (sdla_t *,struct sk_buff **, int);
- static void send_delayed_cmd_result(sdla_t *, netdevice_t *dev, TX25Mbox*);
- static int clear_confirm_event (sdla_t *, TX25Mbox*);
- static void send_oob_msg (sdla_t *, netdevice_t *, TX25Mbox *);
- static int timer_intr_cmd_exec(sdla_t *card);
- static void api_oob_event (sdla_t *card,TX25Mbox *mbox);
- static int check_bad_command (sdla_t *, netdevice_t *);
- static int channel_disconnect (sdla_t*, netdevice_t *);
- static void hdlc_link_down (sdla_t*);
- /*=================================================
- * XPIPEMON Functions
- */
- static int process_udp_mgmt_pkt(sdla_t *);
- static int udp_pkt_type( struct sk_buff *, sdla_t*);
- static int reply_udp( unsigned char *, unsigned int);
- static void init_x25_channel_struct( x25_channel_t *);
- static void init_global_statistics( sdla_t *);
- static int store_udp_mgmt_pkt(int, char, sdla_t*, netdevice_t *, struct sk_buff *, int);
- static unsigned short calc_checksum (char *, int);
- /*=================================================
- * IPX functions
- */
- static void switch_net_numbers(unsigned char *, unsigned long, unsigned char);
- static int handle_IPXWAN(unsigned char *, char *, unsigned char ,
- unsigned long , unsigned short );
- extern void disable_irq(unsigned int);
- extern void enable_irq(unsigned int);
- static void S508_S514_lock(sdla_t *, unsigned long *);
- static void S508_S514_unlock(sdla_t *, unsigned long *);
- /*=================================================
- * Global Variables
- *=================================================*/
- /*=================================================
- * Public Functions
- *=================================================*/
- /*===================================================================
- * wpx_init: X.25 Protocol Initialization routine.
- *
- * Purpose: To initialize the protocol/firmware.
- *
- * Rationale: This function is called by setup() function, in
- * sdlamain.c, to dynamically setup the x25 protocol.
- * This is the first protocol specific function, which
- * executes once on startup.
- *
- * Description: This procedure initializes the x25 firmware and
- * sets up the mailbox, transmit and receive buffer
- * pointers. It also initializes all debugging structures
- * and sets up the X25 environment.
- *
- * Sets up hardware options defined by user in [wanpipe#]
- * section of wanpipe#.conf configuration file.
- *
- * At this point adapter is completely initialized
- * and X.25 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.
- *
- * Called by: setup() function in sdlamain.c
- *
- * Assumptions: None
- *
- * Warnings: None
- *
- * Return: 0 o.k.
- * < 0 failure.
- */
- int wpx_init (sdla_t* card, wandev_conf_t* conf)
- {
- union{
- char str[80];
- TX25Config cfg;
- } u;
- /* Verify configuration ID */
- if (conf->config_id != WANCONFIG_X25){
- printk(KERN_INFO "%s: invalid configuration ID %u!n",
- card->devname, conf->config_id)
- ;
- return -EINVAL;
- }
- /* Initialize protocol-specific fields */
- card->mbox = (void*)(card->hw.dpmbase + X25_MBOX_OFFS);
- card->rxmb = (void*)(card->hw.dpmbase + X25_RXMBOX_OFFS);
- card->flags = (void*)(card->hw.dpmbase + X25_STATUS_OFFS);
- /* Initialize for S514 Card */
- if(card->hw.type == SDLA_S514) {
- card->mbox += X25_MB_VECTOR;
- card->flags += X25_MB_VECTOR;
- card->rxmb += X25_MB_VECTOR;
- }
- /* 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 (x25_get_version(card, NULL) || x25_get_version(card, u.str))
- return -EIO;
- /* X25 firmware can run ether in X25 or LAPB HDLC mode.
- * Check the user defined option and configure accordingly */
- if (conf->u.x25.LAPB_hdlc_only == WANOPT_YES){
- if (set_hdlc_level(card) != CMD_OK){
- return -EIO;
- }else{
- printk(KERN_INFO "%s: running LAP_B HDLC firmware v%sn",
- card->devname, u.str);
- }
- card->u.x.LAPB_hdlc = 1;
- }else{
- printk(KERN_INFO "%s: running X.25 firmware v%sn",
- card->devname, u.str);
- card->u.x.LAPB_hdlc = 0;
- }
- /* Configure adapter. Here we set resonable defaults, then parse
- * device configuration structure and set configuration options.
- * Most configuration options are verified and corrected (if
- * necessary) since we can't rely on the adapter to do so.
- */
- memset(&u.cfg, 0, sizeof(u.cfg));
- u.cfg.t1 = 3;
- u.cfg.n2 = 10;
- u.cfg.autoHdlc = 1; /* automatic HDLC connection */
- u.cfg.hdlcWindow = 7;
- u.cfg.pktWindow = 2;
- u.cfg.station = 1; /* DTE */
- u.cfg.options = 0x0090; /* disable D-bit pragmatics */
- u.cfg.ccittCompat = 1988;
- u.cfg.t10t20 = 30;
- u.cfg.t11t21 = 30;
- u.cfg.t12t22 = 30;
- u.cfg.t13t23 = 30;
- u.cfg.t16t26 = 30;
- u.cfg.t28 = 30;
- u.cfg.r10r20 = 5;
- u.cfg.r12r22 = 5;
- u.cfg.r13r23 = 5;
- u.cfg.responseOpt = 1; /* RR's after every packet */
- if (card->u.x.LAPB_hdlc){
- u.cfg.hdlcMTU = 1027;
- }
- if (conf->u.x25.x25_conf_opt){
- u.cfg.options = conf->u.x25.x25_conf_opt;
- }
- if (conf->clocking != WANOPT_EXTERNAL)
- u.cfg.baudRate = bps_to_speed_code(conf->bps);
- if (conf->station != WANOPT_DTE){
- u.cfg.station = 0; /* DCE mode */
- }
- if (conf->interface != WANOPT_RS232 ){
- u.cfg.hdlcOptions |= 0x80; /* V35 mode */
- }
- /* adjust MTU */
- if (!conf->mtu || (conf->mtu >= 1024))
- card->wandev.mtu = 1024;
- else if (conf->mtu >= 512)
- card->wandev.mtu = 512;
- else if (conf->mtu >= 256)
- card->wandev.mtu = 256;
- else if (conf->mtu >= 128)
- card->wandev.mtu = 128;
- else
- card->wandev.mtu = 64;
- u.cfg.defPktSize = u.cfg.pktMTU = card->wandev.mtu;
- if (conf->u.x25.hi_pvc){
- card->u.x.hi_pvc = min_t(unsigned int, conf->u.x25.hi_pvc, MAX_LCN_NUM);
- card->u.x.lo_pvc = min_t(unsigned int, conf->u.x25.lo_pvc, card->u.x.hi_pvc);
- }
- if (conf->u.x25.hi_svc){
- card->u.x.hi_svc = min_t(unsigned int, conf->u.x25.hi_svc, MAX_LCN_NUM);
- card->u.x.lo_svc = min_t(unsigned int, conf->u.x25.lo_svc, card->u.x.hi_svc);
- }
- /* Figure out the total number of channels to configure */
- card->u.x.num_of_ch = 0;
- if (card->u.x.hi_svc != 0){
- card->u.x.num_of_ch = (card->u.x.hi_svc - card->u.x.lo_svc) + 1;
- }
- if (card->u.x.hi_pvc != 0){
- card->u.x.num_of_ch += (card->u.x.hi_pvc - card->u.x.lo_pvc) + 1;
- }
- if (card->u.x.num_of_ch == 0){
- printk(KERN_INFO "%s: ERROR, Minimum number of PVC/SVC channels is 1 !n"
- "%s: Please set the Lowest/Highest PVC/SVC values !n",
- card->devname,card->devname);
- return -ECHRNG;
- }
-
- u.cfg.loPVC = card->u.x.lo_pvc;
- u.cfg.hiPVC = card->u.x.hi_pvc;
- u.cfg.loTwoWaySVC = card->u.x.lo_svc;
- u.cfg.hiTwoWaySVC = card->u.x.hi_svc;
- if (conf->u.x25.hdlc_window)
- u.cfg.hdlcWindow = min_t(unsigned int, conf->u.x25.hdlc_window, 7);
- if (conf->u.x25.pkt_window)
- u.cfg.pktWindow = min_t(unsigned int, conf->u.x25.pkt_window, 7);
- if (conf->u.x25.t1)
- u.cfg.t1 = min_t(unsigned int, conf->u.x25.t1, 30);
- if (conf->u.x25.t2)
- u.cfg.t2 = min_t(unsigned int, conf->u.x25.t2, 29);
- if (conf->u.x25.t4)
- u.cfg.t4 = min_t(unsigned int, conf->u.x25.t4, 240);
- if (conf->u.x25.n2)
- u.cfg.n2 = min_t(unsigned int, conf->u.x25.n2, 30);
- if (conf->u.x25.t10_t20)
- u.cfg.t10t20 = min_t(unsigned int, conf->u.x25.t10_t20,255);
- if (conf->u.x25.t11_t21)
- u.cfg.t11t21 = min_t(unsigned int, conf->u.x25.t11_t21,255);
- if (conf->u.x25.t12_t22)
- u.cfg.t12t22 = min_t(unsigned int, conf->u.x25.t12_t22,255);
- if (conf->u.x25.t13_t23)
- u.cfg.t13t23 = min_t(unsigned int, conf->u.x25.t13_t23,255);
- if (conf->u.x25.t16_t26)
- u.cfg.t16t26 = min_t(unsigned int, conf->u.x25.t16_t26, 255);
- if (conf->u.x25.t28)
- u.cfg.t28 = min_t(unsigned int, conf->u.x25.t28, 255);
- if (conf->u.x25.r10_r20)
- u.cfg.r10r20 = min_t(unsigned int, conf->u.x25.r10_r20,250);
- if (conf->u.x25.r12_r22)
- u.cfg.r12r22 = min_t(unsigned int, conf->u.x25.r12_r22,250);
- if (conf->u.x25.r13_r23)
- u.cfg.r13r23 = min_t(unsigned int, conf->u.x25.r13_r23,250);
- if (conf->u.x25.ccitt_compat)
- u.cfg.ccittCompat = conf->u.x25.ccitt_compat;
- /* initialize adapter */
- if (card->u.x.LAPB_hdlc){
- if (hdlc_configure(card, &u.cfg) != CMD_OK)
- return -EIO;
- }else{
- if (x25_configure(card, &u.cfg) != CMD_OK)
- return -EIO;
- }
- if ((x25_close_hdlc(card) != CMD_OK) || /* close HDLC link */
- (x25_set_dtr(card, 0) != CMD_OK)) /* drop DTR */
- return -EIO;
- /* Initialize protocol-specific fields of adapter data space */
- card->wandev.bps = conf->bps;
- card->wandev.interface = conf->interface;
- card->wandev.clocking = conf->clocking;
- card->wandev.station = conf->station;
- card->isr = &wpx_isr;
- card->poll = NULL; //&wpx_poll;
- card->disable_comm = &disable_comm;
- card->exec = &wpx_exec;
- card->wandev.update = &update;
- card->wandev.new_if = &new_if;
- card->wandev.del_if = &del_if;
- /* WARNING: This function cannot exit with an error
- * after the change of state */
- card->wandev.state = WAN_DISCONNECTED;
-
- card->wandev.enable_tx_int = 0;
- card->irq_dis_if_send_count = 0;
- card->irq_dis_poll_count = 0;
- card->u.x.tx_dev = NULL;
- card->u.x.no_dev = 0;
- /* Configure for S514 PCI Card */
- if (card->hw.type == SDLA_S514) {
- card->u.x.hdlc_buf_status =
- (volatile unsigned char *)
- (card->hw.dpmbase + X25_MB_VECTOR+ X25_MISC_HDLC_BITS);
- }else{
- card->u.x.hdlc_buf_status =
- (volatile unsigned char *)(card->hw.dpmbase + X25_MISC_HDLC_BITS);
- }
- card->u.x.poll_device=NULL;
- card->wandev.udp_port = conf->udp_port;
- /* Enable or disable call setup logging */
- if (conf->u.x25.logging == WANOPT_YES){
- printk(KERN_INFO "%s: Enabling Call Logging.n",
- card->devname);
- card->u.x.logging = 1;
- }else{
- card->u.x.logging = 0;
- }
- /* Enable or disable modem status reporting */
- if (conf->u.x25.oob_on_modem == WANOPT_YES){
- printk(KERN_INFO "%s: Enabling OOB on Modem change.n",
- card->devname);
- card->u.x.oob_on_modem = 1;
- }else{
- card->u.x.oob_on_modem = 0;
- }
-
- init_global_statistics(card);
- #ifndef LINUX_2_4
- card->u.x.x25_poll_task.next = NULL;
- #endif
- card->u.x.x25_poll_task.sync=0;
- card->u.x.x25_poll_task.routine = (void*)(void*)wpx_poll;
- card->u.x.x25_poll_task.data = card;
- init_timer(&card->u.x.x25_timer);
- card->u.x.x25_timer.data = (unsigned long)card;
- card->u.x.x25_timer.function = x25_timer_routine;
-
- return 0;
- }
- /*=========================================================
- * WAN Device Driver Entry Points
- *========================================================*/
- /*============================================================
- * Name: update(), Update device status & statistics.
- *
- * Purpose: To provide debugging and statitical
- * information to the /proc file system.
- * /proc/net/wanrouter/wanpipe#
- *
- * Rationale: The /proc file system is used to collect
- * information about the kernel and drivers.
- * Using the /proc file system the user
- * can see exactly what the sangoma drivers are
- * doing. And in what state they are in.
- *
- * Description: Collect all driver statistical information
- * and pass it to the top laywer.
- *
- * Since we have to execute a debugging command,
- * to obtain firmware statitics, we trigger a
- * UPDATE function within the timer interrtup.
- * We wait until the timer update is complete.
- * Once complete return the appropriate return
- * code to indicate that the update was successful.
- *
- * Called by: device_stat() in wanmain.c
- *
- * Assumptions:
- *
- * Warnings: This function will degrade the performance
- * of the router, since it uses the mailbox.
- *
- * Return: 0 OK
- * <0 Failed (or busy).
- */
- static int update (wan_device_t* wandev)
- {
- volatile sdla_t* card;
- TX25Status* status;
- unsigned long timeout;
- /* sanity checks */
- if ((wandev == NULL) || (wandev->private == NULL))
- return -EFAULT;
- if (wandev->state == WAN_UNCONFIGURED)
- return -ENODEV;
- if (test_bit(SEND_CRIT, (void*)&wandev->critical))
- return -EAGAIN;
- if (!wandev->dev)
- return -ENODEV;
-
- card = wandev->private;
- status = card->flags;
- card->u.x.timer_int_enabled |= TMR_INT_ENABLED_UPDATE;
- status->imask |= INTR_ON_TIMER;
- timeout = jiffies;
- for (;;){
- if (!(card->u.x.timer_int_enabled & TMR_INT_ENABLED_UPDATE)){
- break;
- }
- if ((jiffies-timeout) > 1*HZ){
- card->u.x.timer_int_enabled &= ~TMR_INT_ENABLED_UPDATE;
- return -EAGAIN;
- }
- }
- return 0;
- }
- /*===================================================================
- * Name: new_if
- *
- * Purpose: To allocate and initialize resources for a
- * new logical channel.
- *
- * Rationale: A new channel can be added dynamically via
- * ioctl call.
- *
- * Description: Allocate a private channel structure, x25_channel_t.
- * Parse the user interface options from wanpipe#.conf
- * configuration file.
- * Bind the private are into the network device private
- * area pointer (dev->priv).
- * Prepare the network device structure for registration.
- *
- * Called by: ROUTER_IFNEW Ioctl call, from wanrouter_ioctl()
- * (wanmain.c)
- *
- * Assumptions: None
- *
- * Warnings: None
- *
- * Return: 0 Ok
- * <0 Failed (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;
- x25_channel_t* chan;
- 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;
- }
- if(card->wandev.new_if_cnt++ > 0 && card->u.x.LAPB_hdlc) {
- printk(KERN_INFO "%s: Error: Running LAPB HDLC Mode !n",
- card->devname);
- printk(KERN_INFO
- "%s: Maximum number of network interfaces must be one !n",
- card->devname);
- return -EEXIST;
- }
- /* allocate and initialize private data */
- chan = kmalloc(sizeof(x25_channel_t), GFP_ATOMIC);
- if (chan == NULL){
- return -ENOMEM;
- }
-
- memset(chan, 0, sizeof(x25_channel_t));
- /* Bug Fix: Seg Err on PVC startup
- * It must be here since bind_lcn_to_dev expects
- * it bellow */
- dev->priv = chan;
-
- strcpy(chan->name, conf->name);
- chan->card = card;
- chan->dev = dev;
- chan->common.sk = NULL;
- chan->common.func = NULL;
- chan->common.rw_bind = 0;
- chan->tx_skb = chan->rx_skb = NULL;
- /* verify media address */
- if (conf->addr[0] == '@'){ /* SVC */
- chan->common.svc = 1;
- strncpy(chan->addr, &conf->addr[1], WAN_ADDRESS_SZ);
- /* Set channel timeouts (default if not specified) */
- chan->idle_timeout = (conf->idle_timeout) ?
- conf->idle_timeout : 90;
- chan->hold_timeout = (conf->hold_timeout) ?
- conf->hold_timeout : 10;
- }else if (is_digit(conf->addr[0])){ /* PVC */
- int lcn = dec_to_uint(conf->addr, 0);
- if ((lcn >= card->u.x.lo_pvc) && (lcn <= card->u.x.hi_pvc)){
- bind_lcn_to_dev (card, dev, lcn);
- }else{
- printk(KERN_ERR
- "%s: PVC %u is out of range on interface %s!n",
- wandev->name, lcn, chan->name);
- err = -EINVAL;
- }
- }else{
- printk(KERN_ERR
- "%s: invalid media address on interface %s!n",
- wandev->name, chan->name);
- err = -EINVAL;
- }
- if(strcmp(conf->usedby, "WANPIPE") == 0){
- printk(KERN_INFO "%s: Running in WANPIPE mode %sn",
- wandev->name, chan->name);
- chan->common.usedby = WANPIPE;
- chan->protocol = htons(ETH_P_IP);
- }else if(strcmp(conf->usedby, "API") == 0){
- chan->common.usedby = API;
- printk(KERN_INFO "%s: Running in API mode %sn",
- wandev->name, chan->name);
- chan->protocol = htons(X25_PROT);
- }
- if (err){
- kfree(chan);
- dev->priv = NULL;
- return err;
- }
-
- chan->enable_IPX = conf->enable_IPX;
-
- if (chan->enable_IPX)
- chan->protocol = htons(ETH_P_IPX);
-
- if (conf->network_number)
- chan->network_number = conf->network_number;
- else
- chan->network_number = 0xDEADBEEF;
- /* 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);
- dev->priv = NULL;
- return -ENOMEM;
- }
- sprintf(dev->name, "%s", chan->name);
- #endif
- dev->init = &if_init;
- init_x25_channel_struct(chan);
- return 0;
- }
- /*===================================================================
- * Name: del_if(), Remove a logical channel.
- *
- * Purpose: To dynamically remove a logical channel.
- *
- * Rationale: Each logical channel should be dynamically
- * removable. This functin is called by an
- * IOCTL_IFDEL ioctl call or shutdown().
- *
- * Description: Do nothing.
- *
- * Called by: IOCTL_IFDEL : wanrouter_ioctl() from wanmain.c
- * shutdown() from sdlamain.c
- *
- * Assumptions:
- *
- * Warnings:
- *
- * Return: 0 Ok. Void function.
- */
- //FIXME Del IF Should be taken out now.
- static int del_if (wan_device_t* wandev, netdevice_t* dev)
- {
- return 0;
- }
- /*============================================================
- * Name: wpx_exec
- *
- * Description: Execute adapter interface command.
- * This option is currently dissabled.
- *===========================================================*/
- static int wpx_exec (struct sdla* card, void* u_cmd, void* u_data)
- {
- return 0;
- }
- /*============================================================
- * Name: disable_comm
- *
- * Description: Disable communications during shutdown.
- * Dont check return code because there is
- * nothing we can do about it.
- *
- * Warning: Dev and private areas are gone at this point.
- *===========================================================*/
- static void disable_comm(sdla_t* card)
- {
- disable_comm_shutdown(card);
- del_timer(&card->u.x.x25_timer);
- return;
- }
- /*============================================================
- * Network Device Interface
- *===========================================================*/
- /*===================================================================
- * Name: if_init(), Netowrk Interface Initialization
- *
- * Purpose: To initialize a network interface device structure.
- *
- * Rationale: During network interface startup, the if_init
- * is called by the kernel to initialize the
- * netowrk device structure. Thus a driver
- * can customze a network device.
- *
- * Description: Initialize the netowrk device call back
- * routines. This is where we tell the kernel
- * which function to use when it wants to send
- * via our interface.
- * Furthermore, we initialize the device flags,
- * MTU and physical address of the board.
- *
- * Called by: Kernel (/usr/src/linux/net/core/dev.c)
- * (dev->init())
- *
- * Assumptions: None
- *
- * Warnings: None
- *
- * Return: 0 Ok : Void function.
- */
- static int if_init (netdevice_t* dev)
- {
- x25_channel_t* chan = dev->priv;
- sdla_t* card = chan->card;
- wan_device_t* wandev = &card->wandev;
- #ifdef LINUX_2_0
- int i;
- #endif
- /* Initialize device driver entry points */
- dev->open = &if_open;
- dev->stop = &if_close;
- dev->hard_header = &if_header;
- dev->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
- /* Initialize media-specific parameters */
- #if defined(LINUX_2_1) || defined(LINUX_2_4)
- dev->type = ARPHRD_PPP; /* ARP h/w type */
- #else
- dev->family = AF_INET; /* address family */
- dev->type = ARPHRD_PPP; /* no x25 type */
- #endif
- dev->flags |= IFF_POINTOPOINT;
- dev->flags |= IFF_NOARP;
- if (chan->common.usedby == API){
- dev->mtu = X25_CHAN_MTU+sizeof(x25api_hdr_t);
- }else{
- dev->mtu = card->wandev.mtu;
- }
-
- dev->hard_header_len = X25_HRDHDR_SZ; /* media header length */
- dev->addr_len = 2; /* hardware address length */
-
- if (!chan->common.svc){
- *(unsigned short*)dev->dev_addr = htons(chan->common.lcn);
- }
-
- /* Initialize hardware parameters (just for reference) */
- dev->irq = wandev->irq;
- dev->dma = wandev->dma;
- dev->base_addr = wandev->ioport;
- dev->mem_start = (unsigned long)wandev->maddr;
- dev->mem_end = wandev->maddr + wandev->msize - 1;
- /* 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
- /* FIXME Why are we doing this */
- set_chan_state(dev, WAN_DISCONNECTED);
- return 0;
- }
- /*===================================================================
- * Name: if_open(), Open/Bring up the Netowrk Interface
- *
- * Purpose: To bring up a network interface.
- *
- * Rationale:
- *
- * Description: Open network interface.
- * o prevent module from unloading by incrementing use count
- * o if link is disconnected then initiate connection
- *
- * Called by: Kernel (/usr/src/linux/net/core/dev.c)
- * (dev->open())
- *
- * Assumptions: None
- *
- * Warnings: None
- *
- * Return: 0 Ok
- * <0 Failur: Interface will not come up.
- */
- static int if_open (netdevice_t* dev)
- {
- x25_channel_t* chan = dev->priv;
- sdla_t* card = chan->card;
- struct timeval tv;
- unsigned long smp_flags;
-
- if (is_dev_running(dev))
- return -EBUSY;
- chan->tq_working = 0;
- /* Initialize the task queue */
- #ifndef LINUX_2_4
- chan->common.wanpipe_task.next = NULL;
- #endif
- chan->common.wanpipe_task.sync = 0;
- chan->common.wanpipe_task.routine = (void *)(void *)x25api_bh;
- chan->common.wanpipe_task.data = dev;
- /* Allocate and initialize BH circular buffer */
- /* Add 1 to MAX_BH_BUFF so we don't have test with (MAX_BH_BUFF-1) */
- chan->bh_head = kmalloc((sizeof(bh_data_t)*(MAX_BH_BUFF+1)),GFP_ATOMIC);
- if (chan->bh_head == NULL){
- printk(KERN_INFO "%s: ERROR, failed to allocate memory ! BH_BUFFERS !n",
- card->devname);
- return -ENOBUFS;
- }
- memset(chan->bh_head,0,(sizeof(bh_data_t)*(MAX_BH_BUFF+1)));
- atomic_set(&chan->bh_buff_used, 0);
- /* Increment the number of interfaces */
- ++card->u.x.no_dev;
-
- wanpipe_open(card);
- /* LAPB protocol only uses one interface, thus
- * start the protocol after it comes up. */
- if (card->u.x.LAPB_hdlc){
- if (card->open_cnt == 1){
- TX25Status* status = card->flags;
- S508_S514_lock(card, &smp_flags);
- x25_set_intr_mode(card, INTR_ON_TIMER);
- status->imask &= ~INTR_ON_TIMER;
- S508_S514_unlock(card, &smp_flags);
- }
- }else{
- /* X25 can have multiple interfaces thus, start the
- * protocol once all interfaces are up */
- //FIXME: There is a bug here. If interface is
- //brought down and up, it will try to enable comm.
- if (card->open_cnt == card->u.x.num_of_ch){
- S508_S514_lock(card, &smp_flags);
- connect(card);
- S508_S514_unlock(card, &smp_flags);
- del_timer(&card->u.x.x25_timer);
- card->u.x.x25_timer.expires=jiffies+HZ;
- add_timer(&card->u.x.x25_timer);
- }
- }
- /* Device is not up untill the we are in connected state */
- do_gettimeofday( &tv );
- chan->router_start_time = tv.tv_sec;
- #ifdef LINUX_2_4
- netif_start_queue(dev);
- #else
- dev->interrupt = 0;
- dev->tbusy = 0;
- dev->start = 1;
- #endif
- return 0;
- }
- /*===================================================================
- * Name: if_close(), Close/Bring down the Netowrk Interface
- *
- * Purpose: To bring down a network interface.
- *
- * Rationale:
- *
- * Description: Close network interface.
- * o decrement use module use count
- *
- * Called by: Kernel (/usr/src/linux/net/core/dev.c)
- * (dev->close())
- * ifconfig <name> down: will trigger the kernel
- * which will call this function.
- *
- * Assumptions: None
- *
- * Warnings: None
- *
- * Return: 0 Ok
- * <0 Failure: Interface will not exit properly.
- */
- static int if_close (netdevice_t* dev)
- {
- x25_channel_t* chan = dev->priv;
- sdla_t* card = chan->card;
- unsigned long smp_flags;
-
- stop_net_queue(dev);
- #ifndef LINUX_2_4
- dev->start=0;
- #endif
- if ((chan->common.state == WAN_CONNECTED) ||
- (chan->common.state == WAN_CONNECTING)){
- S508_S514_lock(card, &smp_flags);
- chan_disc(dev);
- S508_S514_unlock(card, &smp_flags);
- }
- wanpipe_close(card);
- S508_S514_lock(card, &smp_flags);
- if (chan->bh_head){
- int i;
- struct sk_buff *skb;
-
- for (i=0; i<(MAX_BH_BUFF+1); i++){
- skb = ((bh_data_t *)&chan->bh_head[i])->skb;
- if (skb != NULL){
- wan_dev_kfree_skb(skb, FREE_READ);
- }
- }
- kfree(chan->bh_head);
- chan->bh_head=NULL;
- }
- S508_S514_unlock(card, &smp_flags);
- /* If this is the last close, disconnect physical link */
- if (!card->open_cnt){
- S508_S514_lock(card, &smp_flags);
- disconnect(card);
- x25_set_intr_mode(card, 0);
- S508_S514_unlock(card, &smp_flags);
- }
-
- /* Decrement the number of interfaces */
- --card->u.x.no_dev;
- return 0;
- }
- /*======================================================================
- * Build media header.
- * o encapsulate packet according to encapsulation type.
- *
- * The trick here is to put packet type (Ethertype) into 'protocol'
- * field of the socket buffer, so that we don't forget it.
- * If encapsulation fails, set skb->protocol to 0 and discard
- * packet later.
- *
- * Return: media header length.
- *======================================================================*/
- static int if_header (struct sk_buff* skb, netdevice_t* dev,
- unsigned short type, void* daddr, void* saddr, unsigned len)
- {
- x25_channel_t* chan = dev->priv;
- int hdr_len = dev->hard_header_len;
-
- skb->protocol = htons(type);
- if (!chan->protocol){
- hdr_len = wanrouter_encapsulate(skb, dev, type);
- if (hdr_len < 0){
- hdr_len = 0;
- skb->protocol = htons(0);
- }
- }
- return hdr_len;
- }
- /*===============================================================
- * Re-build media header.
- *
- * Return: 1 physical address resolved.
- * 0 physical address not resolved
- *==============================================================*/
- static int if_rebuild_hdr (struct sk_buff* skb)
- {
- netdevice_t *dev = skb->dev;
- x25_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)
- {
- x25_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->if_send_stat.if_send_tbusy_timeout;
- printk (KERN_INFO "%s: Transmit timed out on %sn",
- card->devname, dev->name);
- netif_wake_queue (dev);
- }
- #endif
- /*=========================================================================
- * Send a packet on a network interface.
- * o set tbusy flag (marks start of the transmission).
- * 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. 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, netdevice_t* dev)
- {
- x25_channel_t* chan = dev->priv;
- sdla_t* card = chan->card;
- TX25Status* status = card->flags;
- int udp_type;
- unsigned long smp_flags=0;
- ++chan->if_send_stat.if_send_entry;
- #ifdef LINUX_2_4
- netif_stop_queue(dev);
- #endif
- /* No need to check frame length, since socket code
- * will perform the check for us */
- #ifndef LINUX_2_4
- if (dev->tbusy){
- netdevice_t *dev2;
-
- ++chan->if_send_stat.if_send_tbusy;
- if ((jiffies - chan->tick_counter) < (5*HZ)){
- return 1;
- }
- printk(KERN_INFO "%s: Transmit time out %s!n",
- card->devname, dev->name);
-
- for( dev2 = card->wandev.dev; dev2;
- dev2 = *((netdevice_t**)dev2->priv)){
- dev2->tbusy = 0;
- }
- ++chan->if_send_stat.if_send_tbusy_timeout;
- }
- #endif
- chan->tick_counter = jiffies;
-
- /* Critical region starts here */
- S508_S514_lock(card, &smp_flags);
-
- if (test_and_set_bit(SEND_CRIT, (void*)&card->wandev.critical)){
- printk(KERN_INFO "Hit critical in if_send()! %lxn",card->wandev.critical);
- goto if_send_crit_exit;
- }
-
- 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, dev, skb,
- chan->common.lcn)) {
- status->imask |= INTR_ON_TIMER;
- if (udp_type == UDP_XPIPE_TYPE){
- chan->if_send_stat.if_send_PIPE_request++;
- }
- }
- start_net_queue(dev);
- clear_bit(SEND_CRIT,(void*)&card->wandev.critical);
- S508_S514_unlock(card, &smp_flags);
- return 0;
- }
- if (chan->transmit_length){
- //FIXME: This check doesn't make sense any more
- if (chan->common.state != WAN_CONNECTED){
- chan->transmit_length=0;
- atomic_set(&chan->common.driver_busy,0);
- }else{
- stop_net_queue(dev);
- ++card->u.x.tx_interrupts_pending;
- status->imask |= INTR_ON_TX_FRAME;
- clear_bit(SEND_CRIT,(void*)&card->wandev.critical);
- S508_S514_unlock(card, &smp_flags);
- return 1;
- }
- }
- if (card->wandev.state != WAN_CONNECTED){
- ++chan->ifstats.tx_dropped;
- ++card->wandev.stats.tx_dropped;
- ++chan->if_send_stat.if_send_wan_disconnected;
-
- }else if ( chan->protocol && (chan->protocol != skb->protocol)){
- printk(KERN_INFO
- "%s: unsupported Ethertype 0x%04X on interface %s!n",
- chan->name, htons(skb->protocol), dev->name);
-
- printk(KERN_INFO "PROTO %Xn", htons(chan->protocol));
- ++chan->ifstats.tx_errors;
- ++chan->ifstats.tx_dropped;
- ++card->wandev.stats.tx_dropped;
- ++chan->if_send_stat.if_send_protocol_error;
-
- }else switch (chan->common.state){
- case WAN_DISCONNECTED:
- /* Try to establish connection. If succeded, then start
- * transmission, else drop a packet.
- */
- if (chan->common.usedby == API){
- ++chan->ifstats.tx_dropped;
- ++card->wandev.stats.tx_dropped;
- break;
- }else{
- if (chan_connect(dev) != 0){
- ++chan->ifstats.tx_dropped;
- ++card->wandev.stats.tx_dropped;
- break;
- }
- }
- /* fall through */
- case WAN_CONNECTED:
- if( skb->protocol == htons(ETH_P_IPX)) {
- if(chan->enable_IPX) {
- switch_net_numbers( skb->data,
- chan->network_number, 0);
- } else {
- ++card->wandev.stats.tx_dropped;
- ++chan->ifstats.tx_dropped;
- ++chan->if_send_stat.if_send_protocol_error;
- goto if_send_crit_exit;
- }
- }
- /* We never drop here, if cannot send than, copy
- * a packet into a transmit buffer
- */
- chan_send(dev, skb->data, skb->len, 0);
- break;
- default:
- ++chan->ifstats.tx_dropped;
- ++card->wandev.stats.tx_dropped;
- break;
- }
- if_send_crit_exit:
-
- wan_dev_kfree_skb(skb, FREE_WRITE);
- start_net_queue(dev);
- 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 void setup_for_delayed_transmit (netdevice_t* dev, void* buf,
- unsigned len)
- {
- x25_channel_t* chan = dev->priv;
- sdla_t* card = chan->card;
- TX25Status* status = card->flags;
- ++chan->if_send_stat.if_send_adptr_bfrs_full;
- if(chan->transmit_length) {
- printk(KERN_INFO "%s: Error, transmit length set in delayed transmit!n",
- card->devname);
- return;
- }
- if (chan->common.usedby == API){
- if (len > X25_CHAN_MTU+sizeof(x25api_hdr_t)) {
- ++chan->ifstats.tx_dropped;
- ++card->wandev.stats.tx_dropped;
- printk(KERN_INFO "%s: Length is too big for delayed transmitn",
- card->devname);
- return;
- }
- }else{
- if (len > X25_MAX_DATA) {
- ++chan->ifstats.tx_dropped;
- ++card->wandev.stats.tx_dropped;
- printk(KERN_INFO "%s: Length is too big for delayed transmitn",
- card->devname);
- return;
- }
- }
- chan->transmit_length = len;
- atomic_set(&chan->common.driver_busy,1);
- memcpy(chan->transmit_buffer, buf, len);
- ++chan->if_send_stat.if_send_tx_int_enabled;
- /* Enable Transmit Interrupt */
- ++card->u.x.tx_interrupts_pending;
- status->imask |= INTR_ON_TX_FRAME;
- }
- /*===============================================================
- * net_device_stats
- *
- * Get ethernet-style interface statistics.
- * Return a pointer to struct enet_statistics.
- *
- *==============================================================*/
- static struct net_device_stats *if_stats (netdevice_t* dev)
- {
- x25_channel_t *chan = dev->priv;
- if(chan == NULL)
- return NULL;
- return &chan->ifstats;
- }
- /*
- * Interrupt Handlers
- */
- /*
- * X.25 Interrupt Service Routine.
- */
- static void wpx_isr (sdla_t* card)
- {
- TX25Status* status = card->flags;
- card->in_isr = 1;
- ++card->statistics.isr_entry;
- if (test_bit(PERI_CRIT,(void*)&card->wandev.critical)){
- card->in_isr=0;
- status->iflags = 0;
- return;
- }
-
- if (test_bit(SEND_CRIT, (void*)&card->wandev.critical)){
- printk(KERN_INFO "%s: wpx_isr: wandev.critical set to 0x%02lx, int type = 0x%02xn",
- card->devname, card->wandev.critical, status->iflags);
- card->in_isr = 0;
- status->iflags = 0;
- return;
- }
- /* For all interrupts set the critical flag to CRITICAL_RX_INTR.
- * If the if_send routine is called with this flag set it will set
- * the enable transmit flag to 1. (for a delayed interrupt)
- */
- switch (status->iflags){
- case RX_INTR_PENDING: /* receive interrupt */
- rx_intr(card);
- break;
- case TX_INTR_PENDING: /* transmit interrupt */
- tx_intr(card);
- break;
- case MODEM_INTR_PENDING: /* modem status interrupt */
- status_intr(card);
- break;
- case X25_ASY_TRANS_INTR_PENDING: /* network event interrupt */
- event_intr(card);
- break;
- case TIMER_INTR_PENDING:
- timer_intr(card);
- break;
- default: /* unwanted interrupt */
- spur_intr(card);
- }
- card->in_isr = 0;
- status->iflags = 0; /* clear interrupt condition */
- }
- /*
- * Receive interrupt handler.
- * This routine handles fragmented IP packets using M-bit according to the
- * RFC1356.
- * o map ligical channel number to network interface.
- * o allocate socket buffer or append received packet to the existing one.
- * o if M-bit is reset (i.e. it's the last packet in a sequence) then
- * decapsulate packet and pass socket buffer to the protocol stack.
- *
- * Notes:
- * 1. When allocating a socket buffer, if M-bit is set then more data is
- * coming and we have to allocate buffer for the maximum IP packet size
- * expected on this channel.
- * 2. If something goes wrong and X.25 packet has to be dropped (e.g. no
- * socket buffers available) the whole packet sequence must be discarded.
- */
- static void rx_intr (sdla_t* card)
- {
- TX25Mbox* rxmb = card->rxmb;
- unsigned lcn = rxmb->cmd.lcn;
- netdevice_t* dev = find_channel(card,lcn);
- x25_channel_t* chan;
- struct sk_buff* skb=NULL;
- if (dev == NULL){
- /* Invalid channel, discard packet */
- printk(KERN_INFO "%s: receiving on orphaned LCN %d!n",
- card->devname, lcn);
- return;
- }
- chan = dev->priv;
- chan->i_timeout_sofar = jiffies;
- /* Copy the data from the board, into an
- * skb buffer
- */
- if (wanpipe_pull_data_in_skb(card,dev,&skb)){
- ++chan->ifstats.rx_dropped;
- ++card->wandev.stats.rx_dropped;
- ++chan->rx_intr_stat.rx_intr_no_socket;
- ++chan->rx_intr_stat.rx_intr_bfr_not_passed_to_stack;
- return;
- }
- dev->last_rx = jiffies; /* timestamp */
- /* ------------ API ----------------*/
- if (chan->common.usedby == API){
- if (bh_enqueue(dev, skb)){
- ++chan->ifstats.rx_dropped;
- ++card->wandev.stats.rx_dropped;
- ++chan->rx_intr_stat.rx_intr_bfr_not_passed_to_stack;
- wan_dev_kfree_skb(skb, FREE_READ);
- return;
- }
- ++chan->ifstats.rx_packets;
- #if defined(LINUX_2_1) || defined(LINUX_2_4)
- chan->ifstats.rx_bytes += skb->len;
- #endif
-
- chan->rx_skb = NULL;
- if (!test_and_set_bit(0, &chan->tq_working)){
- wanpipe_queue_tq(&chan->common.wanpipe_task);
- wanpipe_mark_bh();
- }
- return;
- }
- /* ------------- WANPIPE -------------------*/
-
- /* set rx_skb to NULL so we won't access it later when kernel already owns it */
- chan->rx_skb=NULL;
-
- /* Decapsulate packet, if necessary */
- if (!skb->protocol && !wanrouter_type_trans(skb, dev)){
- /* can't decapsulate packet */
- wan_dev_kfree_skb(skb, FREE_READ);
- ++chan->ifstats.rx_errors;
- ++chan->ifstats.rx_dropped;
- ++card->wandev.stats.rx_dropped;
- ++chan->rx_intr_stat.rx_intr_bfr_not_passed_to_stack;
- }else{
- if( handle_IPXWAN(skb->data, chan->name,
- chan->enable_IPX, chan->network_number,
- skb->protocol)){
- if( chan->enable_IPX ){
- if(chan_send(dev, skb->data, skb->len,0)){
- chan->tx_skb = skb;
- }else{
- wan_dev_kfree_skb(skb, FREE_WRITE);
- ++chan->rx_intr_stat.rx_intr_bfr_not_passed_to_stack;
- }
- }else{
- /* increment IPX packet dropped statistic */
- ++chan->ifstats.rx_dropped;
- ++chan->rx_intr_stat.rx_intr_bfr_not_passed_to_stack;
- }
- }else{
- skb->mac.raw = skb->data;
- #if defined(LINUX_2_1) || defined(LINUX_2_4)
- chan->ifstats.rx_bytes += skb->len;
- #endif
- ++chan->ifstats.rx_packets;
- ++chan->rx_intr_stat.rx_intr_bfr_passed_to_stack;
- netif_rx(skb);
- }
- }
-
- return;
- }
- static int wanpipe_pull_data_in_skb (sdla_t *card, netdevice_t *dev, struct sk_buff **skb)
- {
- void *bufptr;
- TX25Mbox* rxmb = card->rxmb;
- unsigned len = rxmb->cmd.length; /* packet length */
- unsigned qdm = rxmb->cmd.qdm; /* Q,D and M bits */
- x25_channel_t *chan = dev->priv;
- struct sk_buff *new_skb = *skb;
- if (chan->common.usedby == WANPIPE){
- if (chan->drop_sequence){
- if (!(qdm & 0x01)){
- chan->drop_sequence = 0;
- }
- return 1;
- }
- new_skb = chan->rx_skb;
- }else{
- /* Add on the API header to the received
- * data
- */
- len += sizeof(x25api_hdr_t);
- }
- if (new_skb == NULL){
- int bufsize;
- if (chan->common.usedby == WANPIPE){
- bufsize = (qdm & 0x01) ? dev->mtu : len;
- }else{
- bufsize = len;
- }
- /* Allocate new socket buffer */
- new_skb = dev_alloc_skb(bufsize + dev->hard_header_len);
- if (new_skb == NULL){
- printk(KERN_INFO "%s: no socket buffers available!n",
- card->devname);
- chan->drop_sequence = 1; /* set flag */
- ++chan->ifstats.rx_dropped;
- return 1;
- }
- }
- if (skb_tailroom(new_skb) < len){
- /* No room for the packet. Call off the whole thing! */
- wan_dev_kfree_skb(new_skb, FREE_READ);
- if (chan->common.usedby == WANPIPE){
- chan->rx_skb = NULL;
- if (qdm & 0x01){
- chan->drop_sequence = 1;
- }
- }
- printk(KERN_INFO "%s: unexpectedly long packet sequence "
- "on interface %s!n", card->devname, dev->name);
- ++chan->ifstats.rx_length_errors;
- return 1;
- }
- bufptr = skb_put(new_skb,len);
- if (chan->common.usedby == API){
- /* Fill in the x25api header
- */
- x25api_t * api_data = (x25api_t*)bufptr;
- api_data->hdr.qdm = rxmb->cmd.qdm;
- api_data->hdr.cause = rxmb->cmd.cause;
- api_data->hdr.diagn = rxmb->cmd.diagn;
- api_data->hdr.length = rxmb->cmd.length;
- memcpy(api_data->data, rxmb->data, rxmb->cmd.length);
- }else{
- memcpy(bufptr, rxmb->data, len);
- }
- new_skb->dev = dev;
- if (chan->common.usedby == API){
- new_skb->mac.raw = new_skb->data;
- new_skb->protocol = htons(X25_PROT);
- new_skb->pkt_type = WAN_PACKET_DATA;
- }else{
- new_skb->protocol = chan->protocol;
- chan->rx_skb = new_skb;
- }
- /* If qdm bit is set, more data is coming
- * thus, exit and wait for more data before
- * sending the packet up. (Used by router only)
- */
- if ((qdm & 0x01) && (chan->common.usedby == WANPIPE))
- return 1;
- *skb = new_skb;
- return 0;
- }
- /*===============================================================
- * tx_intr
- *
- * Transmit interrupt handler.
- * For each dev, check that there is something to send.
- * If data available, transmit.
- *
- *===============================================================*/
- static void tx_intr (sdla_t* card)
- {
- netdevice_t *dev;
- TX25Status* status = card->flags;
- unsigned char more_to_tx=0;
- x25_channel_t *chan=NULL;
- int i=0;
- if (card->u.x.tx_dev == NULL){
- card->u.x.tx_dev = card->wandev.dev;
- }
- dev = card->u.x.tx_dev;
- for (;;){
- chan = dev->priv;
- if (chan->transmit_length){
- /* Device was set to transmit, check if the TX
- * buffers are available
- */
- if (chan->common.state != WAN_CONNECTED){
- chan->transmit_length = 0;
- atomic_set(&chan->common.driver_busy,0);
- chan->tx_offset=0;
- if (is_queue_stopped(dev)){
- if (chan->common.usedby == API){
- start_net_queue(dev);
- wakeup_sk_bh(dev);
- }else{
- wake_net_dev(dev);
- }
- }
- dev = move_dev_to_next(card,dev);
- break;
- }
- if ((status->cflags[chan->ch_idx] & 0x40 || card->u.x.LAPB_hdlc) &&
- (*card->u.x.hdlc_buf_status & 0x40) ){
- /* Tx buffer available, we can send */
-
- if (tx_intr_send(card, dev)){
- more_to_tx=1;
- }
- /* If more than one interface present, move the
- * device pointer to the next interface, so on the
- * next TX interrupt we will try sending from it.
- */
- dev = move_dev_to_next(card,dev);
- break;
- }else{
- /* Tx buffers not available, but device set
- * the TX interrupt. Set more_to_tx and try
- * to transmit for other devices.
- */
- more_to_tx=1;
- dev = move_dev_to_next(card,dev);
- }
- }else{
- /* This device was not set to transmit,
- * go to next
- */
- dev = move_dev_to_next(card,dev);
- }
- if (++i == card->u.x.no_dev){
- if (!more_to_tx){
- DBG_PRINTK(KERN_INFO "%s: Nothing to Send in TX INTRn",
- card->devname);
- }
- break;
- }
- } //End of FOR
- card->u.x.tx_dev = dev;
-
- if (!more_to_tx){
- /* if any other interfaces have transmit interrupts pending, */
- /* do not disable the global transmit interrupt */
- if (!(--card->u.x.tx_interrupts_pending)){
- status->imask &= ~INTR_ON_TX_FRAME;
- }
- }
- return;
- }
- /*===============================================================
- * move_dev_to_next
- *
- *
- *===============================================================*/
- netdevice_t * move_dev_to_next (sdla_t *card, netdevice_t *dev)
- {
- if (card->u.x.no_dev != 1){
- if (*((netdevice_t**)dev->priv) == NULL){
- return card->wandev.dev;
- }else{
- return *((netdevice_t**)dev->priv);
- }
- }
- return dev;
- }
- /*===============================================================
- * tx_intr_send
- *
- *
- *===============================================================*/
- static int tx_intr_send(sdla_t *card, netdevice_t *dev)
- {
- x25_channel_t* chan = dev->priv;
- if (chan_send (dev,chan->transmit_buffer,chan->transmit_length,1)){
-
- /* Packet was split up due to its size, do not disable
- * tx_intr
- */
- return 1;
- }
- chan->transmit_length=0;
- atomic_set(&chan->common.driver_busy,0);
- chan->tx_offset=0;
- /* If we are in API mode, wakeup the
- * sock BH handler, not the NET_BH */
- if (is_queue_stopped(dev)){
- if (chan->common.usedby == API){
- start_net_queue(dev);
- wakeup_sk_bh(dev);
- }else{
- wake_net_dev(dev);
- }
- }
- return 0;
- }
- /*===============================================================
- * timer_intr
- *
- * Timer interrupt handler.
- * Check who called the timer interrupt and perform
- * action accordingly.
- *
- *===============================================================*/
- static void timer_intr (sdla_t *card)
- {
- TX25Status* status = card->flags;
- if (card->u.x.timer_int_enabled & TMR_INT_ENABLED_CMD_EXEC){
- if (timer_intr_cmd_exec(card) == 0){
- card->u.x.timer_int_enabled &=
- ~TMR_INT_ENABLED_CMD_EXEC;
- }
- }else if(card->u.x.timer_int_enabled & TMR_INT_ENABLED_UDP_PKT) {
- if ((*card->u.x.hdlc_buf_status & 0x40) &&
- card->u.x.udp_type == UDP_XPIPE_TYPE){
- if(process_udp_mgmt_pkt(card)) {
- card->u.x.timer_int_enabled &=
- ~TMR_INT_ENABLED_UDP_PKT;
- }
- }
- }else if (card->u.x.timer_int_enabled & TMR_INT_ENABLED_POLL_ACTIVE) {
- netdevice_t *dev = card->u.x.poll_device;
- x25_channel_t *chan = NULL;
- if (!dev){
- card->u.x.timer_int_enabled &= ~TMR_INT_ENABLED_POLL_ACTIVE;
- return;
- }
- chan = dev->priv;
- printk(KERN_INFO
- "%s: Closing down Idle link %s on LCN %dn",
- card->devname,chan->name,chan->common.lcn);
- chan->i_timeout_sofar = jiffies;
- chan_disc(dev);
- card->u.x.timer_int_enabled &= ~TMR_INT_ENABLED_POLL_ACTIVE;
- card->u.x.poll_device=NULL;
- }else if (card->u.x.timer_int_enabled & TMR_INT_ENABLED_POLL_CONNECT_ON) {
- wanpipe_set_state(card, WAN_CONNECTED);
- if (card->u.x.LAPB_hdlc){
- netdevice_t *dev = card->wandev.dev;
- set_chan_state(dev,WAN_CONNECTED);
- send_delayed_cmd_result(card,dev,card->mbox);
- }
- /* 0x8F enable all interrupts */
- x25_set_intr_mode(card, INTR_ON_RX_FRAME|
- INTR_ON_TX_FRAME|
- INTR_ON_MODEM_STATUS_CHANGE|
- //INTR_ON_COMMAND_COMPLETE|
- X25_ASY_TRANS_INTR_PENDING |
- INTR_ON_TIMER |
- DIRECT_RX_INTR_USAGE
- );
- status->imask &= ~INTR_ON_TX_FRAME; /* mask Tx interrupts */
- card->u.x.timer_int_enabled &= ~TMR_INT_ENABLED_POLL_CONNECT_ON;
- }else if (card->u.x.timer_int_enabled & TMR_INT_ENABLED_POLL_CONNECT_OFF) {
- //printk(KERN_INFO "Poll connect, Turning OFFn");
- disconnect(card);
- card->u.x.timer_int_enabled &= ~TMR_INT_ENABLED_POLL_CONNECT_OFF;
- }else if (card->u.x.timer_int_enabled & TMR_INT_ENABLED_POLL_DISCONNECT) {
- //printk(KERN_INFO "POll disconnect, trying to connectn");
- connect(card);
- card->u.x.timer_int_enabled &= ~TMR_INT_ENABLED_POLL_DISCONNECT;
- }else if (card->u.x.timer_int_enabled & TMR_INT_ENABLED_UPDATE){
- if (*card->u.x.hdlc_buf_status & 0x40){
- x25_get_err_stats(card);
- x25_get_stats(card);
- card->u.x.timer_int_enabled &= ~TMR_INT_ENABLED_UPDATE;
- }
- }
- if(!card->u.x.timer_int_enabled){
- //printk(KERN_INFO "Turning Timer Off n");
- status->imask &= ~INTR_ON_TIMER;
- }
- }
- /*====================================================================
- * Modem status interrupt handler.
- *===================================================================*/
- static void status_intr (sdla_t* card)
- {
- /* Added to avoid Modem status message flooding */
- static TX25ModemStatus last_stat;
- TX25Mbox* mbox = card->mbox;
- TX25ModemStatus *modem_status;
- netdevice_t *dev;
- x25_channel_t *chan;
- int err;
- memset(&mbox->cmd, 0, sizeof(TX25Cmd));
- mbox->cmd.command = X25_READ_MODEM_STATUS;
- err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
- if (err){
- x25_error(card, err, X25_READ_MODEM_STATUS, 0);
- }else{
-
- modem_status = (TX25ModemStatus*)mbox->data;
-
- /* Check if the last status was the same
- * if it was, do NOT print message again */
-
- if (last_stat.status != modem_status->status){
- printk(KERN_INFO "%s: Modem Status Change: DCD=%s, CTS=%sn",
- card->devname,DCD(modem_status->status),CTS(modem_status->status));
- last_stat.status = modem_status->status;
-
- if (card->u.x.oob_on_modem){
- mbox->cmd.pktType = mbox->cmd.command;
- mbox->cmd.result = 0x08;
- /* Send a OOB to all connected sockets */
- for (dev = card->wandev.dev; dev; dev = *((netdevice_t**)dev->priv)){
- chan=dev->priv;
- if (chan->common.usedby == API){
- send_oob_msg(card,dev,mbox);
- }
- }
- /* The modem OOB message will probably kill the
- * the link. If we don't clear the flag here,
- * a deadlock could occur */
- if (atomic_read(&card->u.x.command_busy)){
- atomic_set(&card->u.x.command_busy,0);
- }
- }
- }
- }
- memset(&mbox->cmd, 0, sizeof(TX25Cmd));
- mbox->cmd.command = X25_HDLC_LINK_STATUS;
- err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
- if (err){
- x25_error(card, err, X25_HDLC_LINK_STATUS, 0);
- }
- }
- /*====================================================================
- * Network event interrupt handler.
- *===================================================================*/
- static void event_intr (sdla_t* card)
- {
- x25_fetch_events(card);
- }
- /*====================================================================
- * Spurious interrupt handler.
- * o print a warning
- * o
- *====================================================================*/
- static void spur_intr (sdla_t* card)
- {
- printk(KERN_INFO "%s: spurious interrupt!n", card->devname);
- }
- /*
- * Background Polling Routines
- */
- /*====================================================================
- * Main polling routine.
- * This routine is repeatedly called by the WANPIPE 'thead' to allow for
- * time-dependent housekeeping work.
- *
- * Notes:
- * 1. This routine may be called on interrupt context with all interrupts
- * enabled. Beware!
- *====================================================================*/
- static void wpx_poll (sdla_t *card)
- {
- if (!card->wandev.dev){
- goto wpx_poll_exit;
- }
- if (card->open_cnt != card->u.x.num_of_ch){
- goto wpx_poll_exit;
- }
-
- if (test_bit(PERI_CRIT,&card->wandev.critical)){
- goto wpx_poll_exit;
- }
- if (test_bit(SEND_CRIT,&card->wandev.critical)){
- goto wpx_poll_exit;
- }
- switch(card->wandev.state){
- case WAN_CONNECTED:
- poll_active(card);
- break;
- case WAN_CONNECTING:
- poll_connecting(card);
- break;
- case WAN_DISCONNECTED:
- poll_disconnected(card);
- break;
- }
- wpx_poll_exit:
- clear_bit(POLL_CRIT,&card->wandev.critical);
- return;
- }
- static void trigger_x25_poll(sdla_t *card)
- {
- #ifdef LINUX_2_4
- schedule_task(&card->u.x.x25_poll_task);
- #else
- queue_task(&card->u.x.x25_poll_task, &tq_scheduler);
- #endif
- }
- /*====================================================================
- * Handle physical link establishment phase.
- * o if connection timed out, disconnect the link.
- *===================================================================*/
- static void poll_connecting (sdla_t* card)
- {
- volatile TX25Status* status = card->flags;
- if (status->gflags & X25_HDLC_ABM){
- timer_intr_exec (card, TMR_INT_ENABLED_POLL_CONNECT_ON);
- }else if ((jiffies - card->state_tick) > CONNECT_TIMEOUT){
- timer_intr_exec (card, TMR_INT_ENABLED_POLL_CONNECT_OFF);
- }
- }
- /*====================================================================
- * Handle physical link disconnected phase.
- * o if hold-down timeout has expired and there are open interfaces,
- * connect link.
- *===================================================================*/
- static void poll_disconnected (sdla_t* card)
- {
- netdevice_t *dev;
- x25_channel_t *chan;
- TX25Status* status = card->flags;
- if (!card->u.x.LAPB_hdlc && card->open_cnt &&
- ((jiffies - card->state_tick) > HOLD_DOWN_TIME)){
- timer_intr_exec(card, TMR_INT_ENABLED_POLL_DISCONNECT);
- }
- if ((dev=card->wandev.dev) == NULL)
- return;
- if ((chan=dev->priv) == NULL)
- return;
- if (chan->common.usedby == API &&
- atomic_read(&chan->common.command) &&
- card->u.x.LAPB_hdlc){
- if (!(card->u.x.timer_int_enabled & TMR_INT_ENABLED_CMD_EXEC))
- card->u.x.timer_int_enabled |= TMR_INT_ENABLED_CMD_EXEC;
- if (!(status->imask & INTR_ON_TIMER))
- status->imask |= INTR_ON_TIMER;
- }
- }
- /*====================================================================
- * Handle active link phase.
- * o fetch X.25 asynchronous events.
- * o kick off transmission on all interfaces.
- *===================================================================*/
- static void poll_active (sdla_t* card)
- {
- netdevice_t* dev;
- TX25Status* status = card->flags;
- for (dev = card->wandev.dev; dev; dev = *((netdevice_t**)dev->priv)){
- x25_channel_t* chan = dev->priv;
- /* If SVC has been idle long enough, close virtual circuit */
- if ( chan->common.svc &&
- chan->common.state == WAN_CONNECTED &&
- chan->common.usedby == WANPIPE ){
-
- if( (jiffies - chan->i_timeout_sofar) / HZ > chan->idle_timeout ){
- /* Close svc */
- card->u.x.poll_device=dev;
- timer_intr_exec (card, TMR_INT_ENABLED_POLL_ACTIVE);
- }
- }
- #ifdef PRINT_DEBUG
- chan->ifstats.tx_compressed = atomic_read(&chan->common.command);
- chan->ifstats.tx_errors = chan->common.state;
- chan->ifstats.rx_fifo_errors = atomic_read(&card->u.x.command_busy);
- ++chan->ifstats.tx_bytes;
- chan->ifstats.rx_fifo_errors=atomic_read(&chan->common.disconnect);
- chan->ifstats.multicast=atomic_read(&chan->bh_buff_used);
- chan->ifstats.rx_length_errors=*card->u.x.hdlc_buf_status;
- #endif
- if (chan->common.usedby == API &&
- atomic_read(&chan->common.command) &&
- !card->u.x.LAPB_hdlc){
- if (!(card->u.x.timer_int_enabled & TMR_INT_ENABLED_CMD_EXEC))
- card->u.x.timer_int_enabled |= TMR_INT_ENABLED_CMD_EXEC;
- if (!(status->imask & INTR_ON_TIMER))
- status->imask |= INTR_ON_TIMER;
- }
- if ((chan->common.usedby == API) &&
- atomic_read(&chan->common.disconnect)){
- if (chan->common.state == WAN_DISCONNECTED){
- atomic_set(&chan->common.disconnect,0);
- return;
- }
- atomic_set(&chan->common.command,X25_CLEAR_CALL);
- if (!(card->u.x.timer_int_enabled & TMR_INT_ENABLED_CMD_EXEC))
- card->u.x.timer_int_enabled |= TMR_INT_ENABLED_CMD_EXEC;
- if (!(status->imask & INTR_ON_TIMER))
- status->imask |= INTR_ON_TIMER;
- }
- }
- }
- static void timer_intr_exec(sdla_t *card, unsigned char TYPE)
- {
- TX25Status* status = card->flags;
- card->u.x.timer_int_enabled |= TYPE;
- if (!(status->imask & INTR_ON_TIMER))
- status->imask |= INTR_ON_TIMER;
- }
- /*====================================================================
- * SDLA Firmware-Specific Functions
- *
- * Almost all X.25 commands can unexpetedly fail due to so called 'X.25
- * asynchronous events' such as restart, interrupt, incoming call request,
- * call clear request, etc. They can't be ignored and have to be delt with
- * immediately. To tackle with this problem we execute each interface
- * command in a loop until good return code is received or maximum number
- * of retries is reached. Each interface command returns non-zero return
- * code, an asynchronous event/error handler x25_error() is called.
- *====================================================================*/
- /*====================================================================
- * Read X.25 firmware version.
- * Put code version as ASCII string in str.
- *===================================================================*/
- static int x25_get_version (sdla_t* card, char* str)
- {
- TX25Mbox* mbox = card->mbox;
- int retry = MAX_CMD_RETRY;
- int err;
- do
- {
- memset(&mbox->cmd, 0, sizeof(TX25Cmd));
- mbox->cmd.command = X25_READ_CODE_VERSION;
- err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
- } while (err && retry-- &&
- x25_error(card, err, X25_READ_CODE_VERSION, 0));
- if (!err && str)
- {
- int len = mbox->cmd.length;
- memcpy(str, mbox->data, len);
- str[len] = ' ';
- }
- return err;
- }
- /*====================================================================
- * Configure adapter.
- *===================================================================*/
- static int x25_configure (sdla_t* card, TX25Config* conf)
- {
- TX25Mbox* mbox = card->mbox;
- int retry = MAX_CMD_RETRY;
- int err;
- do{
- memset(&mbox->cmd, 0, sizeof(TX25Cmd));
- memcpy(mbox->data, (void*)conf, sizeof(TX25Config));
- mbox->cmd.length = sizeof(TX25Config);
- mbox->cmd.command = X25_SET_CONFIGURATION;
- err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
- } while (err && retry-- && x25_error(card, err, X25_SET_CONFIGURATION, 0));
- return err;
- }
- /*====================================================================
- * Configure adapter for HDLC only.
- *===================================================================*/
- static int hdlc_configure (sdla_t* card, TX25Config* conf)
- {
- TX25Mbox* mbox = card->mbox;
- int retry = MAX_CMD_RETRY;
- int err;
- do{
- memset(&mbox->cmd, 0, sizeof(TX25Cmd));
- memcpy(mbox->data, (void*)conf, sizeof(TX25Config));
- mbox->cmd.length = sizeof(TX25Config);
- mbox->cmd.command = X25_HDLC_SET_CONFIG;
- err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
- } while (err && retry-- && x25_error(card, err, X25_SET_CONFIGURATION, 0));
- return err;
- }
- static int set_hdlc_level (sdla_t* card)
- {
- TX25Mbox* mbox = card->mbox;
- int retry = MAX_CMD_RETRY;
- int err;
- do{
- memset(&mbox->cmd, 0, sizeof(TX25Cmd));
- mbox->cmd.command = SET_PROTOCOL_LEVEL;
- mbox->cmd.length = 1;
- mbox->data[0] = HDLC_LEVEL; //| DO_HDLC_LEVEL_ERROR_CHECKING;
- err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
- } while (err && retry-- && x25_error(card, err, SET_PROTOCOL_LEVEL, 0));
- return err;
- }
- /*====================================================================
- * Get communications error statistics.
- *====================================================================*/
- static int x25_get_err_stats (sdla_t* card)
- {
- TX25Mbox* mbox = card->mbox;
- int retry = MAX_CMD_RETRY;
- int err;
- do
- {
- memset(&mbox->cmd, 0, sizeof(TX25Cmd));
- mbox->cmd.command = X25_HDLC_READ_COMM_ERR;
- err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
- } while (err && retry-- && x25_error(card, err, X25_HDLC_READ_COMM_ERR, 0));
-
- if (!err)
- {
- THdlcCommErr* stats = (void*)mbox->data;
- card->wandev.stats.rx_over_errors = stats->rxOverrun;
- card->wandev.stats.rx_crc_errors = stats->rxBadCrc;
- card->wandev.stats.rx_missed_errors = stats->rxAborted;
- card->wandev.stats.tx_aborted_errors = stats->txAborted;
- }
- return err;
- }
- /*====================================================================
- * Get protocol statistics.
- *===================================================================*/
- static int x25_get_stats (sdla_t* card)
- {
- TX25Mbox* mbox = card->mbox;
- int retry = MAX_CMD_RETRY;
- int err;
- do
- {
- memset(&mbox->cmd, 0, sizeof(TX25Cmd));
- mbox->cmd.command = X25_READ_STATISTICS;
- err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
- } while (err && retry-- && x25_error(card, err, X25_READ_STATISTICS, 0)) ;
-
- if (!err)
- {
- TX25Stats* stats = (void*)mbox->data;
- card->wandev.stats.rx_packets = stats->rxData;
- card->wandev.stats.tx_packets = stats->txData;
- }
- return err;
- }
- /*====================================================================
- * Close HDLC link.
- *===================================================================*/
- static int x25_close_hdlc (sdla_t* card)
- {
- TX25Mbox* mbox = card->mbox;
- int retry = MAX_CMD_RETRY;
- int err;
- do
- {
- memset(&mbox->cmd, 0, sizeof(TX25Cmd));
- mbox->cmd.command = X25_HDLC_LINK_CLOSE;
- err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
- } while (err && retry-- && x25_error(card, err, X25_HDLC_LINK_CLOSE, 0));
-
- return err;
- }
- /*====================================================================
- * Open HDLC link.
- *===================================================================*/
- static int x25_open_hdlc (sdla_t* card)
- {
- TX25Mbox* mbox = card->mbox;
- int retry = MAX_CMD_RETRY;
- int err;
- do
- {
- memset(&mbox->cmd, 0, sizeof(TX25Cmd));
- mbox->cmd.command = X25_HDLC_LINK_OPEN;
- err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
- } while (err && retry-- && x25_error(card, err, X25_HDLC_LINK_OPEN, 0));
- return err;
- }
- /*=====================================================================
- * Setup HDLC link.
- *====================================================================*/
- static int x25_setup_hdlc (sdla_t* card)
- {
- TX25Mbox* mbox = card->mbox;
- int retry = MAX_CMD_RETRY;
- int err;
- do
- {
- memset(&mbox->cmd, 0, sizeof(TX25Cmd));
- mbox->cmd.command = X25_HDLC_LINK_SETUP;
- err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
- } while (err && retry-- && x25_error(card, err, X25_HDLC_LINK_SETUP, 0));
-
- return err;
- }
- /*====================================================================
- * Set (raise/drop) DTR.
- *===================================================================*/
- static int x25_set_dtr (sdla_t* card, int dtr)
- {
- TX25Mbox* mbox = card->mbox;
- int retry = MAX_CMD_RETRY;
- int err;
- do
- {
- memset(&mbox->cmd, 0, sizeof(TX25Cmd));
- mbox->data[0] = 0;
- mbox->data[2] = 0;
- mbox->data[1] = dtr ? 0x02 : 0x01;
- mbox->cmd.length = 3;
- mbox->cmd.command = X25_SET_GLOBAL_VARS;
- err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
- } while (err && retry-- && x25_error(card, err, X25_SET_GLOBAL_VARS, 0));
-
- return err;
- }
- /*====================================================================
- * Set interrupt mode.
- *===================================================================*/
- static int x25_set_intr_mode (sdla_t* card, int mode)
- {
- TX25Mbox* mbox = card->mbox;
- int retry = MAX_CMD_RETRY;
- int err;
- do
- {
- memset(&mbox->cmd, 0, sizeof(TX25Cmd));
- mbox->data[0] = mode;
- if (card->hw.fwid == SFID_X25_508){
- mbox->data[1] = card->hw.irq;
- mbox->data[2] = 2;
- mbox->cmd.length = 3;
- }else {
- mbox->cmd.length = 1;
- }
- mbox->cmd.command = X25_SET_INTERRUPT_MODE;
- err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
- } while (err && retry-- && x25_error(card, err, X25_SET_INTERRUPT_MODE, 0));
-
- return err;
- }
- /*====================================================================
- * Read X.25 channel configuration.
- *===================================================================*/
- static int x25_get_chan_conf (sdla_t* card, x25_channel_t* chan)
- {
- TX25Mbox* mbox = card->mbox;
- int retry = MAX_CMD_RETRY;
- int lcn = chan->common.lcn;
- int err;
- do{
- memset(&mbox->cmd, 0, sizeof(TX25Cmd));
- mbox->cmd.lcn = lcn;
- mbox->cmd.command = X25_READ_CHANNEL_CONFIG;
- err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
- } while (err && retry-- && x25_error(card, err, X25_READ_CHANNEL_CONFIG, lcn));
- if (!err)
- {
- TX25Status* status = card->flags;
- /* calculate an offset into the array of status bytes */
- if (card->u.x.hi_svc <= X25_MAX_CHAN){
- chan->ch_idx = lcn - 1;
- }else{
- int offset;
- /* FIX: Apr 14 2000 : Nenad Corbic
- * The data field was being compared to 0x1F using
- * '&&' instead of '&'.
- * This caused X25API to fail for LCNs greater than 255.
- */