/***************************************************************************** * sdla_mp_fr.c Multi-Port Frame Relay driver module. * * Authors: Nenad Corbic * * Copyright: (c) 1995-2002 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 09,2002 Nenad Corbic Initial version * Based on raw-hdlc fimrware * Some of the frame realy protocol was * taken from linux/drivers/net/wan/hdlc.c * and from Sangoma's own frame relay firmware. *****************************************************************************/ #include #include #include /* WAN router definitions */ #include /* WANPIPE common user API definitions */ #include #include #include /* Socket Driver common area */ #include #include #include #ifdef CONFIG_PRODUCT_WANPIPE_ANNEXG #include #endif /****** Defines & Macros ****************************************************/ #ifdef _DEBUG_ #define STATIC #else #define STATIC static #endif #define MAX_TRACE_BUFFER (MAX_LGTH_UDP_MGNT_PKT- \ sizeof(struct iphdr)- \ sizeof(struct udphdr) - \ sizeof(wan_mgmt_t)- \ sizeof(wan_cmd_t)) /* 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_TE 0x03 #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 #define MAX_TRACE_LEN 25 #define MAX_TRACE_ASCII_LEN MAX_TRACE_LEN*3+5 #define MAX_FR_RX_BUF 80 #define FR_RX_BUF_LIMIT 1001 #define FR_PROT_AREA(a) ((fr_prot_t*)a->u.c.prot) #define MODE_FR_CCITT 0 #define MAX_FR_HEADER_SZ 16 #ifndef IS_TE1_CARD #define IS_TE1_CARD(card) IS_TE1(card->wandev.te_cfg) #endif #ifndef IS_56K_CARD #define IS_56K_CARD(card) IS_56K(card->wandev.te_cfg) #endif /* Enable TE1_56K Card support */ #define TE1_56_CARD_SUPPORT 1 #undef _DBG_ANNEXG_ /* Private critical flags */ enum { SEND_TXIRQ_CRIT = PRIV_CRIT, ARP_CRIT }; /******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 fr_private_area { wanpipe_common_t common; sdla_t *card; char if_name[WAN_IFNAME_SZ+1]; unsigned char route_status; unsigned char route_removed; unsigned long tick_counter; /* For 5s timeout counter */ 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; unsigned char trace_state; unsigned char trace_buf [MAX_TRACE_ASCII_LEN]; /* Entry in proc fs per each interface */ struct proc_dir_entry* dent; unsigned long router_last_change; unsigned int dlci_type; unsigned long rx_DE_set; unsigned long tx_DE_set; unsigned long rx_FECN; unsigned long rx_BECN; unsigned err_type; char err_data[SNMP_FR_ERRDATA_LEN]; unsigned long err_time; unsigned long err_faults; unsigned trap_state; unsigned long trap_max_rate; unsigned cir; /* committed information rate */ unsigned bc; /* committed burst size */ unsigned be; /* excess burst size */ unsigned char ignore_modem; unsigned short dlci; unsigned char dlci_state; unsigned char inarp; unsigned char route_flag; unsigned short newstate; struct net_device_stats stats; unsigned char hdr_len; unsigned char header[MAX_FR_HEADER_SZ]; unsigned char udp_pkt_data[sizeof(wan_udp_pkt_t)+10]; atomic_t udp_pkt_len; #ifdef CONFIG_PRODUCT_WANPIPE_ANNEXG netdevice_t *annexg_dev; unsigned char label[WAN_IF_LABEL_SZ+1]; #endif if_send_stat_t drvstats_if_send; rx_intr_stat_t drvstats_rx_intr; pipe_mgmt_stat_t drvstats_gen; unsigned long tracing_enabled; struct sk_buff_head trace_queue; unsigned long trace_timeout; unsigned int max_trace_queue; } fr_channel_t, fr_private_area_t; #if 0 int fr_to_hdlc_cmd_map[] { } #endif /* Route Flag options */ #define NO_ROUTE 0x00 #define ADD_ROUTE 0x01 #define ROUTE_ADDED 0x02 #define REMOVE_ROUTE 0x03 #define ARP_REQ 0x04 /* inarp options */ #define INARP_NONE 0x00 #define INARP_REQUEST 0x01 #define INARP_CONFIGURED 0x02 #undef TX_PKT_DEBUG #undef RX_PKT_DEBUG /* 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); extern unsigned short wan_calc_checksum (char *, int); //extern void debug_print_udp_pkt(unsigned char *data,int len,char trc_enabled, char direction); /****** 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 int fr_snmp_data(sdla_t* card, netdevice_t *dev, void* data); static void disable_comm (sdla_t *card); static unsigned int dec_to_uint (unsigned char* str, int len); static netdevice_t* find_channel (sdla_t* card, unsigned dlci); static void fr_timer(unsigned long arg); static void fr_lmi_send(sdla_t *card, int fullrep); static int fr_hard_header(sdla_t *card, netdevice_t *dev, u16 type); /* 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_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd); static int if_send (struct sk_buff* skb, netdevice_t* dev); static struct net_device_stats* if_stats (netdevice_t* dev); static void if_tx_timeout (netdevice_t *dev); /* CHDLC Firmware interface functions */ static int hdlc_configure (sdla_t* card, void* data); static int hdlc_comm_enable (sdla_t* card); static int hdlc_comm_disable (sdla_t* card); static int hdlc_read_version (sdla_t* card, char* str); static int hdlc_set_intr_mode (sdla_t* card, unsigned mode); static int hdlc_send (sdla_t* card, void* data, unsigned len); static int hdlc_send_hdr_data (sdla_t* card, netdevice_t *dev, void* data, unsigned len); static int hdlc_read_comm_err_stats (sdla_t* card); static int hdlc_read_op_stats (sdla_t* card); static int config_hdlc (sdla_t *card); #ifdef TE1_56_CARD_SUPPORT static int set_adapter_config (sdla_t* card); #endif /* Miscellaneous CHDLC Functions */ static int set_hdlc_config (sdla_t* card); static void init_hdlc_tx_rx_buff( sdla_t* card); static int hdlc_error (sdla_t *card, int err, wan_mbox_t *mb); static int process_hdlc_exception(sdla_t *card); static int process_global_exception(sdla_t *card); static int update_comms_stats(sdla_t* card); static void chan_set_state (netdevice_t *dev, int); /* Interrupt handlers */ static void wp_hdlc_fr_isr (sdla_t* card); static void rx_intr (sdla_t* card); static void tx_intr (sdla_t *card); static void timer_intr(sdla_t *); static void fr_bh (unsigned long card_data); /* 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, int direction); //static int store_udp_mgmt_pkt(char udp_pkt_src, sdla_t* card, // struct sk_buff *skb, netdevice_t* dev, // fr_private_area_t* chan); static int process_udp_mgmt_pkt(sdla_t* card, void* local_dev); static void s508_s514_lock (sdla_t *card, unsigned long *smp_flags); static void s508_s514_unlock (sdla_t *card, unsigned long *smp_flags); static int fr_get_config_info(void* priv, struct seq_file* m, int*); static int fr_get_status_info(void* priv, struct seq_file* m, int*); static int fr_set_dev_config(struct file*, const char*, unsigned long, void *); static int fr_set_if_info(struct file*, const char*, unsigned long, void *); static int capture_trace_packet (sdla_t *card,fr_private_area_t*chan,struct sk_buff *skb,char dir); /* TE1 */ #ifdef TE1_56_CARD_SUPPORT static WRITE_FRONT_END_REG_T write_front_end_reg; static READ_FRONT_END_REG_T read_front_end_reg; static void hdlc_enable_timer (void* card_id); static void fr_handle_front_end_state (void* card_id); #endif #ifdef CONFIG_PRODUCT_WANPIPE_ANNEXG static int bind_annexg(netdevice_t *dev, netdevice_t *annexg_dev); static netdevice_t * un_bind_annexg(wan_device_t *wandev, netdevice_t* annexg_dev_name); static int get_map(wan_device_t *wandev, netdevice_t *dev, struct seq_file* m, int *); static void get_active_inactive(wan_device_t *wandev, netdevice_t *dev, void *wp_stats); #endif /****** 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 wp_hdlc_fr_init (sdla_t* card, wandev_conf_t* conf) { unsigned char port_num; int err; unsigned long max_permitted_baud = 0; fr_prot_t *fr_prot; int i; struct timeval tv; union{ char str[80]; }u; volatile wan_mbox_t* mb; wan_mbox_t* mb1; unsigned long timeout, smp_lock; /* Verify configuration ID */ if (conf->config_id != WANCONFIG_MFR) { printk(KERN_INFO "%s: invalid configuration ID %u MFR=%u!\n", card->devname, conf->config_id, WANCONFIG_MFR); return -EINVAL; } /* Find out which Port to use. HDLC protocol can use both primary * and secondayr pory */ 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_INFO "%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_INFO "%s: ERROR - Invalid Port Selected!\n", card->wandev.name); return -EINVAL; } /* Allocate and initialize Frame relay protocol area */ if (!card->u.c.prot){ card->u.c.prot=kmalloc(sizeof(fr_prot_t), GFP_KERNEL); if (!card->u.c.prot){ return -ENOMEM; } memset(card->u.c.prot,0,sizeof(fr_prot_t)); } fr_prot = FR_PROT_AREA(card); fr_prot->station = conf->u.fr.station; memcpy(&fr_prot->cfg, &conf->u.fr, sizeof(wan_fr_conf_t)); /* Setup a shared memory pointers to protocol mailbox * (set a pointer to the actual mailbox in the allocated * virtual memory area) */ /* ALEX Apr 8 2004 Sangoma ISA card */ if (card->u.c.comm_port == WANOPT_PRI){ card->mbox_off = PRI_BASE_ADDR_MB_STRUCT; }else{ card->mbox_off = SEC_BASE_ADDR_MB_STRUCT; } mb = &card->wan_mbox; mb1 = &card->wan_mbox; /* Check that firmware is up and running by checking for I in * mail box */ if (!card->configured){ unsigned char return_code = 0x00; /* 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; do { return_code = 0x00; card->hw_iface.peek(card->hw, card->mbox_off+offsetof(wan_mbox_t, wan_return_code), &return_code, sizeof(unsigned char)); if ((jiffies - timeout) > 1*HZ) break; }while(return_code != 'I'); if (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; } } card->wandev.ignore_front_end_status=WANOPT_NO; //err=check_conf_hw_mismatch(card,conf->te_cfg.media); err = (card->hw_iface.check_mismatch) ? card->hw_iface.check_mismatch(card->hw,conf->fe_cfg.media) : -EINVAL; if (err){ return err; } /* TE1 Make special hardware initialization for T1/E1 board */ if (IS_TE1_MEDIA(conf->fe_cfg.media)) { #ifdef TE1_56_CARD_SUPPORT memcpy(&card->fe.fe_cfg, &conf->fe_cfg, sizeof(sdla_fe_cfg_t)); card->fe.name = card->devname; card->fe.card = card; card->fe.write_fe_reg = write_front_end_reg; card->fe.read_fe_reg = read_front_end_reg; card->wandev.te_enable_timer = hdlc_enable_timer; card->wandev.te_link_state = fr_handle_front_end_state; conf->interface = (IS_T1_CARD(card)) ? WANOPT_V35 : WANOPT_RS232; if (card->u.c.comm_port == WANOPT_PRI){ conf->clocking = WANOPT_EXTERNAL; } #else return -EINVAL; #endif }else if (IS_56K_MEDIA(conf->fe_cfg.media)) { #ifdef TE1_56_CARD_SUPPORT memcpy(&card->fe.fe_cfg, &conf->fe_cfg, sizeof(sdla_fe_cfg_t)); card->fe.name = card->devname; card->fe.card = card; card->fe.write_fe_reg = write_front_end_reg; card->fe.read_fe_reg = read_front_end_reg; if (card->u.c.comm_port == WANOPT_PRI){ conf->clocking = WANOPT_EXTERNAL; } #else return -EINVAL; #endif }else{ card->fe.fe_status = FE_CONNECTED; } if (card->wandev.ignore_front_end_status == WANOPT_NO){ printk(KERN_INFO "%s: Enabling front end state monitor\n", card->devname); }else{ printk(KERN_INFO "%s: Disabling front end state monitor\n", card->devname); } /* 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 (hdlc_read_version(card, u.str)) return -EIO; #ifdef CONFIG_PRODUCT_WANPIPE_ANNEXG printk(KERN_INFO "%s: Running Frame Relay AnnexG over Raw-HDLC firmware v%s\n", card->devname,u.str); #else printk(KERN_INFO "%s: Running Frame Relay over Raw-HDLC firmware v%s\n", card->devname,u.str); #endif #ifdef TE1_56_CARD_SUPPORT if (set_adapter_config(card)) { return -EIO; } #endif /* Initialize standard function pointer that are used * to control, configure and interigate currently * running protocol */ card->isr = &wp_hdlc_fr_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->disable_comm = &disable_comm; card->wandev.new_if_cnt = 0; #ifdef CONFIG_PRODUCT_WANPIPE_ANNEXG card->wandev.bind_annexg = &bind_annexg; card->wandev.un_bind_annexg = &un_bind_annexg; card->wandev.get_map = &get_map; card->wandev.get_active_inactive= &get_active_inactive; #endif /* Initialize Proc fs functions */ card->wandev.get_config_info = &fr_get_config_info; card->wandev.get_status_info = &fr_get_status_info; card->wandev.set_dev_config = &fr_set_dev_config; card->wandev.set_if_info = &fr_set_if_info; /* SNMP data */ card->get_snmp_data = &fr_snmp_data; /* 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; /* The secondary port on S508 card can only have RS232 interface */ if ((card->u.c.comm_port == WANOPT_SEC && conf->interface == WANOPT_V35)&& card->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 Baud Rate Bps */ if(card->wandev.clocking) { if((port_num == WANOPT_PRI) || card->u.c.receive_only) { /* For Primary Port 0 */ max_permitted_baud = (card->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->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) ? wp_min(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) ? wp_min(conf->mtu, SEC_MAX_NO_DATA_BYTES_IN_FRAME) : CHDLC_DFLT_DATA_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->wan_data_len = 0; mb1->wan_command = READ_CHDLC_CONFIGURATION; err = card->hw_iface.cmd(card->hw, card->mbox_off, mb1); if(err != COMMAND_OK) { clear_bit(1, (void*)&card->wandev.critical); if(card->type != SDLA_S514) enable_irq(card->wandev.irq/*ALEX_TODAY card->hw.irq*/); hdlc_error(card, err, mb1); return -EIO; } /* ALEX Apr 8 2004 Sangoma ISA card */ card->flags_off = ((CHDLC_CONFIGURATION_STRUCT *)mb1->wan_data)-> ptr_shared_mem_info_struct; card->intr_type_off = card->flags_off + offsetof(SHARED_MEMORY_INFO_STRUCT, interrupt_info_struct) + offsetof(INTERRUPT_INFORMATION_STRUCT, interrupt_type); card->intr_perm_off = card->flags_off + offsetof(SHARED_MEMORY_INFO_STRUCT, interrupt_info_struct) + offsetof(INTERRUPT_INFORMATION_STRUCT, interrupt_permission); card->fe_status_off = card->flags_off + offsetof(SHARED_MEMORY_INFO_STRUCT, FT1_info_struct) + offsetof(FT1_INFORMATION_STRUCT, parallel_port_A_input); skb_queue_head_init(&fr_prot->rx_free); skb_queue_head_init(&fr_prot->rx_used); skb_queue_head_init(&fr_prot->lmi_queue); skb_queue_head_init(&fr_prot->trace_queue); fr_prot->max_rx_queue = MAX_FR_RX_BUF; if (conf->max_rx_queue && conf->max_rx_queuemax_rx_queue = conf->max_rx_queue; } printk(KERN_INFO "%s: Setting Frame Relay global rx queue len to %i\n", card->devname,fr_prot->max_rx_queue); for (i=0;imax_rx_queue;i++){ struct sk_buff *skb; skb=dev_alloc_skb(card->wandev.mtu+10); if (!skb){ printk(KERN_INFO "%s: Failed to allocate rx queues! No Memory!\n",card->devname); skb_queue_purge(&fr_prot->rx_free); return -ENOMEM; } skb_queue_tail(&fr_prot->rx_free,skb); } /* This is for the ports link state */ card->wandev.state = WAN_DUALPORT; card->u.c.state = WAN_DISCONNECTED; tasklet_init(&fr_prot->wanpipe_task,fr_bh,(unsigned long)card); fr_prot->max_trace_queue = MAX_TRACE_QUEUE; if (conf->max_trace_queue && conf->max_trace_queuemax_trace_queue=conf->max_trace_queue; } printk(KERN_INFO "%s: Setting Max LMI trace queue to %i packets\n", card->devname,fr_prot->max_trace_queue); if (!card->wandev.piggyback){ err = intr_test(card); if(err || (card->timer_int_enabled < MAX_INTR_TEST_COUNTER)) { printk(KERN_INFO "%s: Interrupt test failed (%i)\n", card->devname, card->timer_int_enabled); printk(KERN_INFO "%s: Please choose another interrupt\n", card->devname); return -EIO; } printk(KERN_INFO "%s: Interrupt test passed (%i)\n", card->devname, card->timer_int_enabled); } wan_spin_lock_irq(&card->wandev.lock,&smp_lock); if (config_hdlc(card) < 0){ wan_spin_unlock_irq(&card->wandev.lock,&smp_lock); return -EINVAL; } wan_spin_unlock_irq(&card->wandev.lock,&smp_lock); spin_lock_init(&card->u.c.if_send_lock); printk(KERN_INFO "%s: Frame Station=%s, Signalling=%s\n", card->devname, fr_prot->station == WANOPT_NODE ? "NODE" : "CPE", fr_prot->cfg.signalling == WANOPT_FR_ANSI ? "ANSI":"LMI"); do_gettimeofday(&tv); card->u.c.router_start_time = tv.tv_sec; fr_prot->state = LINK_STATE_CHANGED; fr_prot->txseq = fr_prot->rxseq = 0; fr_prot->last_errors = 0xFFFFFFFF; fr_prot->n391cnt = 0; init_timer(&fr_prot->timer); fr_prot->timer.function = fr_timer; fr_prot->timer.data = (unsigned long)card; fr_prot->timer.expires = (jiffies+HZ); add_timer(&fr_prot->timer); if (fr_prot->station == WANOPT_CPE){ printk(KERN_INFO "%s: Waiting for DLCI report from frame relay switch...\n\n", card->devname); } fr_prot->state |= LINK_STATE_RELIABLE; wanpipe_set_state(card,WAN_CONNECTED); 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 (wan_device_t* wandev) { sdla_t* card = wandev->private; unsigned long smp_flags; #if 0 SHARED_MEMORY_INFO_STRUCT *flags; unsigned long timeout; #endif /* sanity checks */ if((wandev == NULL) || (wandev->private == NULL)) return -EFAULT; if(wandev->state == WAN_UNCONFIGURED) return -ENODEV; /* more sanity checks */ #if 0 if(!card->u.c.flags) return -ENODEV; flags = card->u.c.flags; #endif if(test_and_set_bit(0,&card->update_comms_stats)){ return -EAGAIN; } /* we will need 2 timer interrupts to complete the */ /* reading of the statistics */ #if 0 #ifdef TE1_56_CARD_SUPPORT card->update_comms_stats = (IS_TE1_CARD(card) || IS_56K_CARD(card)) ? 3 : 2; #else card->update_comms_stats = 2; #endif flags->interrupt_info_struct.interrupt_permission |= APP_INT_ON_TIMER; card->u.c.timer_int_enabled = TMR_INT_ENABLED_UPDATE; /* wait a maximum of 1 second for the statistics to be updated */ timeout = jiffies; for(;;) { if(card->update_comms_stats == 0) break; if ((jiffies - timeout) > (1 * HZ)){ card->update_comms_stats = 0; card->u.c.timer_int_enabled &= ~TMR_INT_ENABLED_UPDATE; return -EAGAIN; } schedule(); } #else spin_lock_irqsave(&card->wandev.lock, smp_flags); update_comms_stats(card); card->update_comms_stats=0; spin_unlock_irqrestore(&card->wandev.lock, smp_flags); #endif return 0; } /*============================================================================ * Create new logical channel. * This routine is called by the router when ROUTER_IFNEW IOCTL is being * handled. * o parse media- and hardware-specific configuration * o make sure that a new channel can be created * o allocate resources, if necessary * o prepare network device structure for registaration. * * Return: 0 o.k. * < 0 failure (channel will not be created) */ static int new_if (wan_device_t* wandev, netdevice_t* dev, wanif_conf_t* conf) { sdla_t* card = wandev->private; fr_private_area_t* chan; int err = 0; unsigned short dlci=0; fr_prot_t *fr_prot; unsigned long smp_lock; if ((conf->name[0] == '\0') || (strlen(conf->name) > WAN_IFNAME_SZ)) { printk(KERN_INFO "%s: Error invalid interface name!\n", card->devname); return -EINVAL; } /* allocate and initialize private data */ chan = kmalloc(sizeof(fr_private_area_t), GFP_KERNEL); if(chan == NULL) return -ENOMEM; memset(chan, 0, sizeof(fr_private_area_t)); strncpy(chan->if_name,conf->name,WAN_IFNAME_SZ); chan->card = card; fr_prot = FR_PROT_AREA(card); /* verify media address */ if (is_digit(conf->addr[0])) { dlci = dec_to_uint(conf->addr, 0); if (dlci && (dlci <= HIGHEST_VALID_DLCI)) { chan->dlci = dlci; chan->common.lcn=dlci; } else { printk(KERN_INFO "%s: Invalid DLCI %u on interface %s Max=%i!\n", wandev->name, dlci, chan->if_name,HIGHEST_VALID_DLCI); err = -EINVAL; } } else { printk(KERN_INFO "%s: Invalid media address on interface %s, i.e. no DLCI specified!\n", wandev->name, chan->if_name); err = -EINVAL; } if (err != 0){ kfree(chan); return err; } printk(KERN_INFO "\n"); printk(KERN_INFO "%s: Configuring interface %s with DLCI=%i\n", card->devname,conf->name,chan->dlci); /* Disallow duplicate dlci configurations. */ if (fr_prot->dlci_to_dev_map[chan->dlci] != NULL){ kfree(chan); printk(KERN_INFO "%s: %s: DLCI %i already configured!\n", card->devname,chan->if_name,chan->dlci); return -EEXIST; } chan->route_status = NO_ROUTE; chan->route_removed = 0; /* Setup wanpipe as a router (WANPIPE) or as an API */ if( strcmp(conf->usedby, "WANPIPE") == 0) { printk(KERN_INFO "%s: %s: Interface running in WANPIPE mode!\n", wandev->name,chan->if_name); card->u.c.usedby = WANPIPE; #ifdef CONFIG_PRODUCT_WANPIPE_ANNEXG }else if (strcmp(conf->usedby, "ANNEXG") == 0){ chan->common.usedby = ANNEXG; printk(KERN_INFO "%s: %s: Interface Running in ANNEXG mode.\n", card->devname,chan->if_name); #endif }else{ printk(KERN_INFO "%s: %s: API mode is not supported by Wanpipe Frame Realy!\n", wandev->name,chan->if_name); kfree(chan); return -EINVAL; } /* Get Multicast Information */ chan->mc = conf->mc; #ifdef CONFIG_PRODUCT_WANPIPE_ANNEXG if (strlen(conf->label)){ strncpy(chan->label,conf->label,WAN_IF_LABEL_SZ); } #endif /* * Create interface file in proc fs. */ err = wanrouter_proc_add_interface(wandev, &chan->dent, conf->name, dev); if (err){ printk(KERN_INFO "%s: Failed to create /proc/net/router/fr/%s entry!\n", card->devname, conf->name); kfree(chan); dev->priv=NULL; return err; } dev->init = NULL; dev->priv = chan; chan->dlci_state=0; chan->newstate=0; chan->max_trace_queue = MAX_TRACE_QUEUE; if (conf->max_trace_queue){ chan->max_trace_queue = conf->max_trace_queue; } printk(KERN_INFO "%s: %s: Setting DLCI=%i trace queue to %i packets\n", card->devname,chan->if_name,chan->dlci,chan->max_trace_queue); skb_queue_head_init(&chan->trace_queue); card->wandev.new_if_cnt++; chan->common.state = WAN_DISCONNECTED; if_init(dev); wan_spin_lock_irq(&card->wandev.lock,&smp_lock); fr_prot->dlci_to_dev_map[chan->dlci] = dev; wan_spin_unlock_irq(&card->wandev.lock,&smp_lock); printk(KERN_INFO "\n"); return 0; } /*============================================================================ * Delete logical channel. */ static int del_if (wan_device_t* wandev, netdevice_t* dev) { fr_private_area_t *chan = dev->priv; sdla_t *card = wandev->private; fr_prot_t *fr_prot = FR_PROT_AREA(card); unsigned long smp_flags; if (!chan) return 0; wan_spin_lock_irq(&card->wandev.lock,&smp_flags); if (fr_prot->tx_dev==dev){ fr_prot->tx_dev=NULL; } if (chan->dlci && fr_prot->dlci_to_dev_map[chan->dlci]){ fr_prot->dlci_to_dev_map[chan->dlci] = NULL; } wan_spin_unlock_irq(&card->wandev.lock,&smp_flags); #ifdef CONFIG_PRODUCT_WANPIPE_ANNEXG if (chan->common.usedby == ANNEXG && chan->annexg_dev){ struct net_device *tmp_dev; int err; printk(KERN_INFO "%s: Unregistering Lapb Protocol\n",wandev->name); if (!IS_FUNC_CALL(lapb_protocol,lapb_unregister)){ wan_spin_lock_irq(&wandev->lock, &smp_flags); chan->annexg_dev = NULL; wan_spin_unlock_irq(&wandev->lock, &smp_flags); return 0; } wan_spin_lock_irq(&wandev->lock, &smp_flags); tmp_dev=chan->annexg_dev; chan->annexg_dev=NULL; wan_spin_unlock_irq(&wandev->lock, &smp_flags); if ((err=lapb_protocol.lapb_unregister(tmp_dev))){ wan_spin_lock_irq(&wandev->lock, &smp_flags); chan->annexg_dev=tmp_dev; wan_spin_unlock_irq(&wandev->lock, &smp_flags); return err; } } #endif /* Delete interface name from proc fs. */ wanrouter_proc_delete_interface(wandev, chan->if_name); skb_queue_purge(&chan->trace_queue); chan_set_state(dev, WAN_DISCONNECTED); card->wandev.new_if_cnt--; return 0; } static void disable_comm (sdla_t *card) { fr_prot_t* fr_prot = FR_PROT_AREA(card); unsigned long smp_lock; tasklet_kill(&fr_prot->wanpipe_task); wan_spin_lock_irq(&card->wandev.lock,&smp_lock); hdlc_set_intr_mode(card, 0); if (card->u.c.comm_enabled){ hdlc_comm_disable(card); } wan_spin_unlock_irq(&card->wandev.lock,&smp_lock); if (fr_prot){ del_timer(&fr_prot->timer); wan_spin_lock_irq(&card->wandev.lock,&smp_lock); skb_queue_purge(&fr_prot->rx_free); skb_queue_purge(&fr_prot->rx_used); skb_queue_purge(&fr_prot->lmi_queue); skb_queue_purge(&fr_prot->trace_queue); wan_spin_unlock_irq(&card->wandev.lock,&smp_lock); kfree(fr_prot); card->u.c.prot=NULL; } #ifdef TE1_56_CARD_SUPPORT /* TE1 - Unconfiging */ if (IS_TE1_CARD(card)) { sdla_te_unconfig(&card->fe); } #endif } /****** Network Device Interface ********************************************/ /*============================================================================ * Initialize Linux network interface. * * This routine is called only once for each interface, during Linux network * interface registration. Returning anything but zero will fail interface * registration. */ static int if_init (netdevice_t* dev) { fr_private_area_t* chan = dev->priv; sdla_t* card = chan->card; fr_prot_t *fr_prot=FR_PROT_AREA(card); wan_device_t* 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; #if defined(LINUX_2_4)||defined(LINUX_2_6) dev->tx_timeout = &if_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; #endif dev->do_ioctl = if_do_ioctl; dev->hard_header = NULL; dev->hard_header_len = 0; dev->addr_len = 2; *(u16*)dev->dev_addr = htons(chan->dlci); dlci_to_q922(dev->broadcast, fr_prot->lmi_dlci); dev->flags |= IFF_POINTOPOINT; dev->flags |= IFF_NOARP; /* Initialize hardware parameters */ dev->irq = wandev->irq; dev->dma = wandev->dma; dev->base_addr = wandev->ioport; card->hw_iface.getcfg(card->hw, SDLA_MEMBASE, &dev->mem_start); //ALEX_TODAY wandev->maddr; card->hw_iface.getcfg(card->hw, SDLA_MEMEND, &dev->mem_end); //ALEX_TODAY wandev->maddr + wandev->msize - 1; dev->type = ARPHRD_DLCI; dev->mtu = card->wandev.mtu; /* 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; /* Initialize socket buffers */ //dev_init_buffers(dev); return 0; } /*============================================================================ * Handle transmit timeout event from netif watchdog */ static void if_tx_timeout (netdevice_t *dev) { fr_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 (netdevice_t* dev) { fr_private_area_t* chan = dev->priv; sdla_t* card = chan->card; fr_prot_t *fr_prot = FR_PROT_AREA(card); /* Only one open per interface is allowed */ if (open_dev_check(dev)) return -EBUSY; netif_start_queue(dev); wanpipe_open(card); if (fr_prot->station == WANOPT_NODE){ chan->dlci_state = 0; fr_prot->state |= LINK_STATE_CHANGED; }else{ if (chan->dlci_state & PVC_STATE_ACTIVE){ chan_set_state(dev,WAN_CONNECTED); }else{ chan_set_state(dev,WAN_CONNECTING); chan->dlci_state=0; } } return 0; } /*============================================================================ * Close network interface. * o if this is the last close, then disable communications and interrupts. * o reset flags. */ static int if_close (netdevice_t* dev) { fr_private_area_t* chan = dev->priv; sdla_t* card = chan->card; fr_prot_t *fr_prot = FR_PROT_AREA(card); stop_net_queue(dev); #if defined(LINUX_2_1) dev->start=0; #endif if (fr_prot->station == WANOPT_NODE){ chan->dlci_state &= ~(PVC_STATE_ACTIVE|PVC_STATE_NEW); fr_prot->state |= LINK_STATE_CHANGED; } wanpipe_close(card); chan_set_state(dev,WAN_DISCONNECTED); return 0; } /** * if_do_ioctl - Ioctl handler for fr * @dev: Device subject to ioctl * @ifr: Interface request block from the user * @cmd: Command that is being issued * * This function handles the ioctls that may be issued by the user * to control the settings of a FR. It does both busy * and security checks. This function is intended to be wrapped by * callers who wish to add additional ioctl calls of their own. */ /* SNMP */ static int if_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { unsigned long smp_flags; fr_private_area_t* chan = dev->priv; sdla_t *card; wan_udp_pkt_t *wan_udp_pkt; if (!chan) return -ENODEV; card = chan->card; if(!capable(CAP_NET_ADMIN)) return -EPERM; switch(cmd) { case SIOC_WANPIPE_SNMP: case SIOC_WANPIPE_SNMP_IFSPEED: return wan_snmp_data(card, dev, cmd, ifr); case SIOC_WANPIPE_PIPEMON: if (atomic_read(&chan->udp_pkt_len) != 0){ return -EBUSY; } atomic_set(&chan->udp_pkt_len,MAX_LGTH_UDP_MGNT_PKT); wan_udp_pkt=(wan_udp_pkt_t*)&chan->udp_pkt_data; if (copy_from_user(&wan_udp_pkt->wan_udp_hdr,ifr->ifr_data,sizeof(wan_udp_hdr_t))){ atomic_set(&chan->udp_pkt_len,0); return -EFAULT; } spin_lock_irqsave(&card->wandev.lock, smp_flags); /* We have to check here again because we don't know * what happened during spin_lock */ if (test_bit(0,&card->in_isr)){ printk(KERN_INFO "%s:%s pipemon command busy: try again!\n", card->devname,dev->name); atomic_set(&chan->udp_pkt_len,0); spin_unlock_irqrestore(&card->wandev.lock, smp_flags); return -EBUSY; } if (process_udp_mgmt_pkt(card,dev) <= 0 ){ atomic_set(&chan->udp_pkt_len,0); spin_unlock_irqrestore(&card->wandev.lock, smp_flags); return -EINVAL; } spin_unlock_irqrestore(&card->wandev.lock, smp_flags); /* This area will still be critical to other * PIPEMON commands due to udp_pkt_len * thus we can release the irq */ if (atomic_read(&chan->udp_pkt_len) > sizeof(wan_udp_pkt_t)){ printk(KERN_INFO "%s: Error: Pipemon buf too bit on the way up! %i\n", card->devname,atomic_read(&chan->udp_pkt_len)); atomic_set(&chan->udp_pkt_len,0); return -EINVAL; } if (copy_to_user(ifr->ifr_data,&wan_udp_pkt->wan_udp_hdr,sizeof(wan_udp_hdr_t))){ atomic_set(&chan->udp_pkt_len,0); return -EFAULT; } atomic_set(&chan->udp_pkt_len,0); return 0; default: return -EOPNOTSUPP; } 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, netdevice_t* dev) { fr_private_area_t *chan = dev->priv; sdla_t *card = chan->card; //int udp_type = 0; unsigned long smp_flags; int err=0; #if defined(LINUX_2_4)||defined(LINUX_2_6) netif_stop_queue(dev); dev->trans_start = jiffies; #endif 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); wake_net_dev(dev); return 0; } #if defined(LINUX_2_1) if (dev->tbusy){ /* If our device stays busy for at least 5 seconds then we will * kick start the device by making dev->tbusy = 0. We expect * that our device never stays busy more than 5 seconds. So this * is only used as a last resort. */ if((jiffies - chan->tick_counter) < (5 * HZ)) { return 1; } if_tx_timeout(dev); } #endif if (test_bit(SEND_TXIRQ_CRIT,&card->wandev.critical)){ stop_net_queue(dev); chan->tick_counter = jiffies; card->hw_iface.set_bit(card->hw, card->intr_perm_off, APP_INT_ON_TX_FRAME); //printk(KERN_INFO "%s: (Debug): IF send busy: on TXIRQ CRIT \n",dev->name); return 1; } s508_s514_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; ++chan->stats.tx_carrier_errors; start_net_queue(dev); goto if_send_crit_exit; } if (card->wandev.state != WAN_CONNECTED){ ++card->wandev.stats.tx_dropped; ++chan->stats.tx_carrier_errors; start_net_queue(dev); goto if_send_crit_exit; } if (chan->common.state != WAN_CONNECTED){ ++card->wandev.stats.tx_dropped; ++chan->stats.tx_carrier_errors; start_net_queue(dev); goto if_send_crit_exit; } if (fr_hard_header(card, dev, htons(skb->protocol)) <= 0){ ++card->wandev.stats.tx_errors; start_net_queue(dev); goto if_send_crit_exit; } err=hdlc_send_hdr_data(card, dev, skb->data, skb->len); if (err){ err=-1; stop_net_queue(dev); //printk(KERN_INFO "%s: (Debug): IF send failed\n",dev->name); }else{ if (capture_trace_packet(card,chan,skb,TRC_OUTGOING_FRM) < 0){ chan->stats.tx_fifo_errors++; } ++card->wandev.stats.tx_packets; card->wandev.stats.tx_bytes += skb->len; ++chan->stats.tx_packets; chan->stats.tx_bytes += skb->len; #if defined(LINUX_2_4)||defined(LINUX_2_6) dev->trans_start = jiffies; #endif #ifdef _DBG_ANNEXG_ check_x25_pr_ps_cnt(card,skb); #endif start_net_queue(dev); } if_send_crit_exit: if (err==0){ dev_kfree_skb_any(skb); }else{ chan->tick_counter = jiffies; card->hw_iface.set_bit(card->hw, card->intr_perm_off, APP_INT_ON_TX_FRAME); } clear_bit(SEND_CRIT, (void*)&card->wandev.critical); s508_s514_unlock(card, &smp_flags); return err; } /*============================================================================ * Reply to UDP Management system. * Return nothing. */ static int reply_udp( unsigned char *data, unsigned int mbox_len ) { unsigned short len, udp_length, temp, ip_length; unsigned long ip_temp; int even_bound = 0; wan_udp_pkt_t *wan_udp_pkt = (wan_udp_pkt_t *)data; /* Set length of packet */ len = //sizeof(fr_encap_hdr_t)+ sizeof(struct iphdr)+ sizeof(struct udphdr)+ sizeof(wan_mgmt_t)+ sizeof(wan_cmd_t)+ mbox_len; /* fill in UDP reply */ wan_udp_pkt->wan_udp_request_reply = UDPMGMT_REPLY; /* fill in UDP length */ udp_length = sizeof(struct udphdr)+ sizeof(wan_mgmt_t)+ sizeof(wan_cmd_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); wan_udp_pkt->wan_udp_len = temp; /* swap UDP ports */ temp = wan_udp_pkt->wan_udp_sport; wan_udp_pkt->wan_udp_sport = wan_udp_pkt->wan_udp_dport; wan_udp_pkt->wan_udp_dport = temp; /* add UDP pseudo header */ temp = 0x1100; *((unsigned short *) (wan_udp_pkt->wan_udp_data+mbox_len+even_bound)) = temp; temp = (udp_length<<8)|(udp_length>>8); *((unsigned short *) (wan_udp_pkt->wan_udp_data+mbox_len+even_bound+2)) = temp; /* calculate UDP checksum */ wan_udp_pkt->wan_udp_sum = 0; wan_udp_pkt->wan_udp_sum = wan_calc_checksum(&data[UDP_OFFSET/*+sizeof(fr_encap_hdr_t)*/], udp_length+UDP_OFFSET); /* fill in IP length */ ip_length = udp_length + sizeof(struct iphdr); temp = (ip_length<<8)|(ip_length>>8); wan_udp_pkt->wan_ip_len = temp; /* swap IP addresses */ ip_temp = wan_udp_pkt->wan_ip_src; wan_udp_pkt->wan_ip_src = wan_udp_pkt->wan_ip_dst; wan_udp_pkt->wan_ip_dst = ip_temp; /* fill in IP checksum */ wan_udp_pkt->wan_ip_sum = 0; wan_udp_pkt->wan_ip_sum = wan_calc_checksum(&data[/*sizeof(fr_encap_hdr_t)*/0], sizeof(struct iphdr)); return len; } /* reply_udp */ /*============================================================================ * Get ethernet-style interface statistics. * Return a pointer to struct enet_statistics. */ static struct net_device_stats* if_stats (netdevice_t* dev) { fr_private_area_t* chan; if (!dev || !(dev->flags&IFF_UP)) return NULL; /* 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 ((chan=dev->priv) == NULL) return NULL; return &chan->stats; } /****** Cisco HDLC Firmware Interface Functions *******************************/ /*============================================================================ * Read firmware code version. * Put code version as ASCII string in str. */ static int hdlc_read_version (sdla_t* card, char* str) { wan_mbox_t* mb = &card->wan_mbox; int len; char err; mb->wan_data_len = 0; mb->wan_command = READ_CHDLC_CODE_VERSION; err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); if(err != COMMAND_OK) { hdlc_error(card,err,mb); } else if (str) { /* is not null */ len = mb->wan_data_len; memcpy(str, mb->wan_data, len); str[len] = '\0'; } return (err); } /*----------------------------------------------------------------------------- * Configure CHDLC firmware. */ static int hdlc_configure (sdla_t* card, void* data) { int err; wan_mbox_t *mbox = &card->wan_mbox; int data_length = sizeof(CHDLC_CONFIGURATION_STRUCT); mbox->wan_data_len = data_length; memcpy(mbox->wan_data, data, data_length); mbox->wan_command = SET_CHDLC_CONFIGURATION; err = card->hw_iface.cmd(card->hw, card->mbox_off, mbox); if (err != COMMAND_OK) hdlc_error (card, err, mbox); return err; } /*============================================================================ * Set interrupt mode -- HDLC Version. */ static int hdlc_set_intr_mode (sdla_t* card, unsigned mode) { wan_mbox_t* mb = &card->wan_mbox; CHDLC_INT_TRIGGERS_STRUCT* int_data = (CHDLC_INT_TRIGGERS_STRUCT *)mb->wan_data; int err; int_data->CHDLC_interrupt_triggers = mode; int_data->IRQ = card->wandev.irq; //ALEX_TODAY card->hw.irq; int_data->interrupt_timer = 1; mb->wan_data_len = sizeof(CHDLC_INT_TRIGGERS_STRUCT); mb->wan_command = SET_CHDLC_INTERRUPT_TRIGGERS; err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); if (err != COMMAND_OK) hdlc_error (card, err, mb); return err; } /*============================================================================ * Enable communications. */ static int hdlc_comm_enable (sdla_t* card) { int err; wan_mbox_t* mb = &card->wan_mbox; mb->wan_data_len = 0; mb->wan_command = ENABLE_CHDLC_COMMUNICATIONS; err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); if (err != COMMAND_OK) hdlc_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 hdlc_comm_disable (sdla_t* card) { int err; wan_mbox_t* mb = &card->wan_mbox; mb->wan_data_len = 0; mb->wan_command = DISABLE_CHDLC_COMMUNICATIONS; err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); if (err != COMMAND_OK) hdlc_error(card,err,mb); return err; } /*============================================================================ * Read communication error statistics. */ static int hdlc_read_comm_err_stats (sdla_t* card) { int err; wan_mbox_t* mb = &card->wan_mbox; mb->wan_data_len = 0; mb->wan_command = READ_COMMS_ERROR_STATS; err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); if (err != COMMAND_OK) hdlc_error(card,err,mb); return err; } /*============================================================================ * Read CHDLC operational statistics. */ static int hdlc_read_op_stats (sdla_t* card) { int err; wan_mbox_t* mb = &card->wan_mbox; mb->wan_data_len = 0; mb->wan_command = READ_CHDLC_OPERATIONAL_STATS; err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); if (err != COMMAND_OK) hdlc_error(card,err,mb); return err; } /*============================================================================ * Update communications error and general packet statistics. */ static int update_comms_stats(sdla_t* card) { wan_mbox_t* mb = &card->wan_mbox; COMMS_ERROR_STATS_STRUCT* err_stats; CHDLC_OPERATIONAL_STATS_STRUCT *op_stats; /* on the first timer interrupt, read the comms error statistics */ #ifdef TE1_56_CARD_SUPPORT /* 1. On the first timer interrupt, update T1/E1 alarms * and PMON counters (only for T1/E1 card) (TE1) */ /* TE1 Update T1/E1 alarms */ if (IS_TE1_CARD(card)) { card->wandev.fe_iface.read_alarm(&card->fe, 0); /* TE1 Update T1/E1 perfomance counters */ card->wandev.fe_iface.read_pmon(&card->fe); }else if (IS_56K_CARD(card)) { /* 56K Update CSU/DSU alarms */ card->wandev.fe_iface.read_alarm(&card->fe, 1); } #endif if(hdlc_read_comm_err_stats(card)) return 1; err_stats = (COMMS_ERROR_STATS_STRUCT *)mb->wan_data; card->wandev.stats.rx_over_errors = err_stats->Rx_overrun_err_count; card->wandev.stats.rx_crc_errors = err_stats->CRC_err_count; card->wandev.stats.rx_frame_errors = err_stats->Rx_abort_count; card->wandev.stats.rx_fifo_errors = err_stats->Rx_dis_pri_bfrs_full_count; card->wandev.stats.rx_missed_errors = card->wandev.stats.rx_fifo_errors; card->wandev.stats.tx_aborted_errors = err_stats->sec_Tx_abort_count; if(hdlc_read_op_stats(card)) return 1; op_stats = (CHDLC_OPERATIONAL_STATS_STRUCT *)mb->wan_data; card->wandev.stats.rx_length_errors = (op_stats->Rx_Data_discard_short_count + op_stats->Rx_Data_discard_long_count); return 0; } static int hdlc_send_hdr_data (sdla_t* card, netdevice_t *dev, void* data, unsigned len) { CHDLC_DATA_TX_STATUS_EL_STRUCT txbuf; fr_private_area_t *chan = dev->priv; card->hw_iface.peek(card->hw, card->u.c.txbuf_off, &txbuf, sizeof(txbuf)); if (txbuf.opp_flag) return 1; #if TX_PKT_DEBUG if (len <= 5 && !(((char *)data)[1]&0x01)){ int x; if (len == 5 && (((char*)data)[4]&0x01)) goto tx_skip_error; printk(KERN_INFO "ERROR !!! TX: Annexg Tx Frame error %i\n", len); printk(KERN_INFO "Bad Packet : "); for (x=0;xhdr_len); card->hw_iface.poke(card->hw,txbuf.ptr_data_bfr,chan->header,chan->hdr_len); card->hw_iface.poke(card->hw,(txbuf.ptr_data_bfr+chan->hdr_len),data,len); txbuf.opp_flag = 1; /* start transmission */ card->hw_iface.peek(card->hw, card->u.c.txbuf_off, &txbuf, sizeof(txbuf)); /* Update transmit buffer control fields */ card->u.c.txbuf_off += sizeof(txbuf); if (card->u.c.txbuf_off > card->u.c.txbuf_last_off) card->u.c.txbuf_off = card->u.c.txbuf_base_off; return 0; } /*============================================================================ * Send packet. * Return: 0 - o.k. * 1 - no transmit buffers available */ static int hdlc_send (sdla_t* card, void* data, unsigned len) { CHDLC_DATA_TX_STATUS_EL_STRUCT txbuf; card->hw_iface.peek(card->hw, card->u.c.txbuf_off, &txbuf, sizeof(txbuf)); if (txbuf.opp_flag) return 1; card->hw_iface.poke(card->hw, txbuf.ptr_data_bfr, data, len); txbuf.frame_length = len; txbuf.opp_flag = 1; /* start transmission */ card->hw_iface.poke(card->hw, card->u.c.txbuf_off, &txbuf, sizeof(txbuf)); /* Update transmit buffer control fields */ card->u.c.txbuf_off += sizeof(txbuf); if (card->u.c.txbuf_off > card->u.c.txbuf_last_off) card->u.c.txbuf_off = card->u.c.txbuf_base_off; return 0; } #ifdef TE1_56_CARD_SUPPORT static int set_adapter_config (sdla_t* card) { wan_mbox_t* mb = &card->wan_mbox; ADAPTER_CONFIGURATION_STRUCT* cfg = (ADAPTER_CONFIGURATION_STRUCT*)mb->wan_data; int err; card->hw_iface.getcfg(card->hw, SDLA_ADAPTERTYPE, &cfg->adapter_type); cfg->adapter_config = 0x00; cfg->operating_frequency = 00; mb->wan_data_len = sizeof(ADAPTER_CONFIGURATION_STRUCT); mb->wan_command = SET_ADAPTER_CONFIGURATION; err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); if(err != COMMAND_OK) { hdlc_error(card,err,mb); } return (err); } /*============================================================================ * Read TE1/56K Front end registers */ static unsigned char read_front_end_reg (void* card1, unsigned short reg) { sdla_t* card = (sdla_t*)card1; wan_mbox_t* mb = &card->wan_mbox; char* data = mb->wan_data; int err; ((FRONT_END_REG_STRUCT *)data)->register_number = (unsigned short)reg; mb->wan_data_len = sizeof(FRONT_END_REG_STRUCT); mb->wan_command = READ_FRONT_END_REGISTER; err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); if (err != COMMAND_OK) hdlc_error(card,err,mb); return(((FRONT_END_REG_STRUCT *)data)->register_value); } /*============================================================================ * Write to TE1/56K Front end registers */ static unsigned char write_front_end_reg (void* card1, unsigned short reg, unsigned char value) { sdla_t* card = (sdla_t*)card1; wan_mbox_t* mb = &card->wan_mbox; char* data = mb->wan_data; int err; ((FRONT_END_REG_STRUCT *)data)->register_number = (unsigned short)reg; ((FRONT_END_REG_STRUCT *)data)->register_value = value; mb->wan_data_len = sizeof(FRONT_END_REG_STRUCT); mb->wan_command = WRITE_FRONT_END_REGISTER; err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); if (err != COMMAND_OK) hdlc_error(card,err,mb); return err; } /*============================================================================ * Enable timer interrupt */ static void hdlc_enable_timer (void* card_id) { sdla_t* card = (sdla_t*)card_id; card->u.c.timer_int_enabled |= TMR_INT_ENABLED_TE; card->hw_iface.set_bit(card->hw, card->intr_perm_off, APP_INT_ON_TIMER); return; } #endif /****** Firmware Error Handler **********************************************/ /*============================================================================ * Firmware error handler. * This routine is called whenever firmware command returns non-zero * return code. * * Return zero if previous command has to be cancelled. */ static int hdlc_error (sdla_t *card, int err, wan_mbox_t *mb) { unsigned cmd = mb->wan_command; switch (err) { case CMD_TIMEOUT: printk(KERN_INFO "%s: command 0x%02X timed out!\n", card->devname, cmd); break; case S514_BOTH_PORTS_SAME_CLK_MODE: if(cmd == SET_CHDLC_CONFIGURATION) { printk(KERN_INFO "%s: Configure both ports for the same clock source\n", card->devname); break; } default: printk(KERN_INFO "%s: command 0x%02X returned 0x%02X!\n", card->devname, cmd, err); } return 0; } /****** Interrupt Handlers **************************************************/ /*============================================================================ * Cisco HDLC interrupt service routine. */ STATIC void wp_hdlc_fr_isr (sdla_t* card) { SHARED_MEMORY_INFO_STRUCT flags; int i; /* Check for which port the interrupt has been generated * Since Secondary Port is piggybacking on the Primary * the check must be done here. */ /* Start card isr critical area */ set_bit(0,&card->in_isr); card->hw_iface.peek(card->hw, card->flags_off, &flags, sizeof(flags)); /* if critical due to peripheral operations * ie. update() or getstats() then reset the interrupt and * wait for the board to retrigger. */ if(test_bit(PERI_CRIT, (void*)&card->wandev.critical)) { printk(KERN_INFO "%s: ISR: Critical due to PERI\n", card->devname); card->hw_iface.poke_byte(card->hw, card->intr_type_off, 0x00); goto isr_done; } /* On a 508 Card, if critical due to if_send * Major Error !!! */ if(card->type != SDLA_S514) { if(test_bit(0, (void*)&card->wandev.critical)) { printk(KERN_INFO "%s: ISR: Critical due to SEND %lx\n", card->devname, card->wandev.critical); goto isr_done; } } switch(flags.interrupt_info_struct.interrupt_type) { case RX_APP_INT_PEND: /* 0x01: receive interrupt */ rx_intr(card); break; case TX_APP_INT_PEND: /* 0x02: transmit interrupt */ tx_intr(card); break; case COMMAND_COMPLETE_APP_INT_PEND:/* 0x04: cmd cplt */ ++ card->timer_int_enabled; break; case CHDLC_EXCEP_COND_APP_INT_PEND: /* 0x20 */ process_hdlc_exception(card); break; case GLOBAL_EXCEP_COND_APP_INT_PEND: process_global_exception(card); #ifdef TE1_56_CARD_SUPPORT /* Reset the 56k or T1/E1 front end exception condition */ if(IS_56K_CARD(card) || IS_TE1_CARD(card)) { FRONT_END_STATUS_STRUCT FE_status; card->hw_iface.peek(card->hw, card->fe_status_off, &FE_status, sizeof(FE_status)); FE_status.opp_flag = 0x01; card->hw_iface.poke(card->hw, card->fe_status_off, &FE_status, sizeof(FE_status)); } #endif break; case TIMER_APP_INT_PEND: timer_intr(card); break; default: if (card->next){ set_bit(0,&card->spurious); break; } printk(KERN_INFO "%s: spurious interrupt 0x%02X!\n", card->devname, flags.interrupt_info_struct.interrupt_type); printk(KERN_INFO "Code name: "); for(i = 0; i < 4; i ++) printk("%c", flags.global_info_struct.codename[i]); printk("\n"); printk(KERN_INFO "Code version: "); for(i = 0; i < 4; i ++) printk("%c", flags.global_info_struct.codeversion[i]); printk("\n"); break; } isr_done: card->in_isr = 0; card->hw_iface.poke_byte(card->hw, card->intr_type_off, 0x00); } /*============================================================================ * Receive interrupt handler. */ static void rx_intr (sdla_t* card) { SHARED_MEMORY_INFO_STRUCT flags; CHDLC_DATA_RX_STATUS_EL_STRUCT rxbuf; struct sk_buff *skb; unsigned len; unsigned addr; void *buf; int i; fr_prot_t *fr_prot = FR_PROT_AREA(card); if (!fr_prot){ printk(KERN_INFO "%s: Fr prot area not allocated!\n", card->devname); goto rx_exit; } card->hw_iface.peek(card->hw, card->flags_off, &flags, sizeof(flags)); card->hw_iface.peek(card->hw, card->u.c.rxmb_off, &rxbuf, sizeof(rxbuf)); addr = rxbuf.ptr_data_bfr; if (rxbuf.opp_flag != 0x01) { printk(KERN_INFO "%s: corrupted Rx buffer @ 0x%lX, flag = 0x%02X!\n", card->devname, card->u.c.rxmb_off, rxbuf.opp_flag); printk(KERN_INFO "Code name: "); for(i = 0; i < 4; i ++) printk(KERN_INFO "%c", flags.global_info_struct.codename[i]); printk(KERN_INFO "\n"); printk(KERN_INFO "Code version: "); for(i = 0; i < 4; i ++) printk(KERN_INFO "%c", flags.global_info_struct.codeversion[i]); printk(KERN_INFO "\n"); /* Bug Fix: Mar 6 2000 * If we get a corrupted mailbox, it measn that driver * is out of sync with the firmware. There is no recovery. * If we don't turn off all interrupts for this card * the machine will crash. */ printk(KERN_INFO "%s: Critical router failure ...!!!\n", card->devname); printk(KERN_INFO "Please contact Sangoma Technologies !\n"); hdlc_set_intr_mode(card,0); return; } if (rxbuf.error_flag){ printk(KERN_INFO "%s: Rx bad frame: error_flag=%i : len=%i\n", card->devname,rxbuf.error_flag, rxbuf.frame_length); goto rx_exit_kick; } if ((rxbuf.frame_length < (4+CRC_LENGTH)) || (rxbuf.frame_length > (card->wandev.mtu+CRC_LENGTH))){ printk(KERN_INFO "%s: Rx bad frame: invalid length : len=%i\n", card->devname,rxbuf.frame_length); goto rx_exit_kick; } /* Take off two CRC bytes */ len = rxbuf.frame_length - CRC_LENGTH; /* Allocate socket buffer */ skb = skb_dequeue(&fr_prot->rx_free); if (skb == NULL) { if (net_ratelimit()){ printk(KERN_INFO "%s: FR skb rx queue, Qlen=%i, is empty: no rx buffers available!\n", card->devname,MAX_FR_RX_BUF); printk(KERN_INFO "%s: The rx queue should be increased via config file!\n", card->devname); printk(KERN_INFO "%s: TQ Critical 0x%lX\n", card->devname,fr_prot->tq_working); } ++card->wandev.stats.rx_dropped; goto rx_exit_kick; } /* Copy data to the socket buffer */ if((addr + len) > card->u.c.rx_top_off + 1) { unsigned tmp = card->u.c.rx_top_off - addr + 1; buf = skb_put(skb, tmp); card->hw_iface.peek(card->hw, addr, buf, tmp); addr = card->u.c.rx_base_off; len -= tmp; } buf = skb_put(skb, len); card->hw_iface.peek(card->hw, addr, buf, len); skb->mac.raw = skb->data; #ifdef RX_PKT_DEBUG if (skb->len <= 7 && !(skb->data[3]&0x01)){ int x; if (skb->len == 7 && (skb->data[6]&0x01)) goto rx_skip_error; DEBUG_EVNET("ERROR !!! RX ISR: Annexg Rx Frame received %i : orig %i\n", skb->len,(rxbuf.frame_length-CRC_LENGTH)); printk(KERN_INFO "Bad Packet : "); for (x=0;xlen;x++){ printk("%X ",skb->data[x]); } printk("\n"); printk(KERN_INFO "\n"); printk(KERN_INFO "Element=%x Curr Ptr %x Len=%i Top %x\n", card->u.c.rxmb_off, (u32)addr,rxbuf.frame_length, (u32)card->u.c.rx_top_off); printk(KERN_INFO "ERROR WE ARE DEAD !!!\n"); hdlc_set_intr_mode(card,0); goto rx_exit; rx_skip_error: } #endif skb_queue_tail(&fr_prot->rx_used,skb); rx_exit_kick: if (!test_and_set_bit(0,&fr_prot->tq_working)){ tasklet_schedule(&fr_prot->wanpipe_task); } rx_exit: /* Release buffer element and calculate a pointer to the next one */ rxbuf.opp_flag = 0x00; card->hw_iface.poke_byte(card->hw, card->u.c.rxmb_off+offsetof(CHDLC_DATA_RX_STATUS_EL_STRUCT, opp_flag), rxbuf.opp_flag); card->u.c.rxmb_off += sizeof(rxbuf); if (card->u.c.rxmb_off > card->u.c.rxbuf_last_off){ card->u.c.rxmb_off = card->u.c.rxbuf_base_off; } } static netdevice_t * move_dev_to_next (sdla_t *card, netdevice_t *dev) { struct wan_dev_le *devle; if (!dev){ return dev; } if (card->wandev.new_if_cnt == 1){ return dev; } WAN_LIST_FOREACH(devle, &card->wandev.dev_head, dev_link){ if (devle->dev == dev){ dev = WAN_DEVLE2DEV(WAN_LIST_NEXT(devle, dev_link)); if (!dev){ dev = WAN_DEVLE2DEV(WAN_LIST_FIRST(&card->wandev.dev_head)); } return dev; } } return dev; } static void tx_intr (sdla_t *card) { fr_prot_t *fr_prot=FR_PROT_AREA(card); struct sk_buff *skb; netdevice_t *dev; int i=0,no_dev_busy=0; if (test_bit(SEND_CRIT,&card->wandev.critical)){ return; } set_bit(SEND_TXIRQ_CRIT,&card->wandev.critical); while ((skb=skb_dequeue(&fr_prot->lmi_queue))!=NULL){ if (hdlc_send(card, skb->data, skb->len)){ skb_queue_head(&fr_prot->lmi_queue,skb); /* We do not clear the critical flag because * we want to stop the if_send() from * attempting to tx. Since we have to * tx the fr stuff first */ return; } //card->wandev.stats.tx_aborted_errors++; dev_kfree_skb_any(skb); } clear_bit(SEND_TXIRQ_CRIT,&card->wandev.critical); if (fr_prot->tx_dev == NULL){ fr_prot->tx_dev = WAN_DEVLE2DEV(WAN_LIST_FIRST(&card->wandev.dev_head)); } dev = fr_prot->tx_dev; if (!dev){ printk(KERN_INFO "%s: No dev in tx intr\n",card->devname); card->hw_iface.clear_bit(card->hw, card->intr_perm_off, APP_INT_ON_TX_FRAME); return; } for (;;){ if (!dev || !(dev->flags & IFF_UP)){ goto tx_skip; } if (is_queue_stopped(dev)){ wake_net_dev(dev); #ifdef CONFIG_PRODUCT_WANPIPE_ANNEXG { fr_private_area_t *chan=dev->priv; if (chan && chan->common.usedby == ANNEXG && chan->annexg_dev){ if (IS_FUNC_CALL(lapb_protocol,lapb_mark_bh)) lapb_protocol.lapb_mark_bh(chan->annexg_dev); } } #endif dev=move_dev_to_next(card,dev); break; } tx_skip: dev=move_dev_to_next(card,dev); if (++i >= card->wandev.new_if_cnt){ no_dev_busy=1; break; } } fr_prot->tx_dev = dev; if (no_dev_busy){ card->hw_iface.clear_bit(card->hw, card->intr_perm_off, APP_INT_ON_TX_FRAME); } } /*============================================================================ * Timer interrupt handler. * The timer interrupt is used for two purposes: * 1) Processing udp calls from 'cpipemon'. * 2) Reading board-level statistics for updating the proc file system. */ void timer_intr(sdla_t *card) { if (test_bit(SEND_CRIT,&card->wandev.critical)){ return; } #ifdef TE1_56_CARD_SUPPORT /* TE timer interrupt */ if (card->u.c.timer_int_enabled & TMR_INT_ENABLED_TE) { DEBUG_EVENT("%s: TE Polling\n",card->devname); card->wandev.fe_iface.polling(&card->fe); card->u.c.timer_int_enabled &= ~TMR_INT_ENABLED_TE; } #endif /* only disable the timer interrupt if there are no udp or statistic */ /* updates pending */ if(!card->u.c.timer_int_enabled) { card->hw_iface.clear_bit(card->hw, card->intr_perm_off, APP_INT_ON_TIMER); } } /*------------------------------------------------------------------------------ Miscellaneous Functions - set_hdlc_config() used to set configuration options on the board ------------------------------------------------------------------------------*/ static int set_hdlc_config(sdla_t* card) { CHDLC_CONFIGURATION_STRUCT cfg; memset(&cfg, 0, sizeof(CHDLC_CONFIGURATION_STRUCT)); if(card->wandev.clocking) cfg.baud_rate = card->wandev.bps; cfg.line_config_options = (card->wandev.interface == WANOPT_RS232) ? INTERFACE_LEVEL_RS232 : INTERFACE_LEVEL_V35; cfg.modem_config_options = 0; //API OPTIONS cfg.CHDLC_API_options = DISCARD_RX_ERROR_FRAMES; cfg.modem_status_timer = 100; cfg.CHDLC_protocol_options = HDLC_STREAMING_MODE; cfg.percent_data_buffer_for_Tx = 50; cfg.CHDLC_statistics_options = (CHDLC_TX_DATA_BYTE_COUNT_STAT | CHDLC_RX_DATA_BYTE_COUNT_STAT); cfg.max_CHDLC_data_field_length = card->wandev.mtu+CRC_LENGTH; cfg.transmit_keepalive_timer = 0; cfg.receive_keepalive_timer = 0; cfg.keepalive_error_tolerance = 0; cfg.SLARP_request_timer = 0; cfg.IP_address = 0; cfg.IP_netmask = 0; return hdlc_configure(card, &cfg); } /*============================================================================ * Process global exception condition */ static int process_global_exception(sdla_t *card) { wan_mbox_t* mbox = &card->wan_mbox; int err; mbox->wan_data_len = 0; mbox->wan_command = READ_GLOBAL_EXCEPTION_CONDITION; err = card->hw_iface.cmd(card->hw, card->mbox_off, mbox); if(err != CMD_TIMEOUT ){ switch(mbox->wan_return_code) { case EXCEP_MODEM_STATUS_CHANGE: #ifdef TE1_56_CARD_SUPPORT if (IS_56K_CARD(card)) { FRONT_END_STATUS_STRUCT FE_status; card->hw_iface.peek(card->hw, card->fe_status_off, &FE_status, sizeof(FE_status)); card->fe.fe_param.k56_param.RR8_reg_56k = FE_status.FE_U.stat_56k.RR8_56k; card->fe.fe_param.k56_param.RRA_reg_56k = FE_status.FE_U.stat_56k.RRA_56k; card->fe.fe_param.k56_param.RRC_reg_56k = FE_status.FE_U.stat_56k.RRC_56k; card->wandev.fe_iface.read_alarm(&card->fe, 0); fr_handle_front_end_state(card); break; } if (IS_TE1_CARD(card)) { /* TE1 T1/E1 interrupt */ card->wandev.fe_iface.isr(&card->fe); fr_handle_front_end_state(card); break; } #endif if (mbox->wan_data[0] & DCD_HIGH){ card->fe.fe_status = FE_CONNECTED; }else{ card->fe.fe_status = FE_DISCONNECTED; } printk(KERN_INFO "%s: Modem status change\n", card->devname); switch(mbox->wan_data[0] & (DCD_HIGH | CTS_HIGH)) { case (DCD_HIGH): printk(KERN_INFO "%s: DCD high, CTS low\n",card->devname); break; case (CTS_HIGH): printk(KERN_INFO "%s: DCD low, CTS high\n",card->devname); break; case ((DCD_HIGH | CTS_HIGH)): printk(KERN_INFO "%s: DCD high, CTS high\n",card->devname); break; default: printk(KERN_INFO "%s: DCD low, CTS low\n",card->devname); break; } fr_handle_front_end_state(card); break; case EXCEP_TRC_DISABLED: printk(KERN_INFO "%s: Line trace disabled\n", card->devname); break; case EXCEP_IRQ_TIMEOUT: printk(KERN_INFO "%s: IRQ timeout occurred\n", card->devname); break; case 0x16: break; default: printk(KERN_INFO "%s: Global exception %x\n", card->devname, mbox->wan_return_code); break; } } return 0; } /*============================================================================ * Process fr exception condition */ static int process_hdlc_exception(sdla_t *card) { wan_mbox_t* mb = &card->wan_mbox; int err; mb->wan_data_len = 0; mb->wan_command = READ_CHDLC_EXCEPTION_CONDITION; err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); if(err != CMD_TIMEOUT) { switch (err) { case EXCEP_LINK_ACTIVE: card->fe.fe_status = FE_CONNECTED; fr_handle_front_end_state (card); break; case EXCEP_LINK_INACTIVE_MODEM: card->fe.fe_status = FE_DISCONNECTED; fr_handle_front_end_state (card); break; case EXCEP_LOOPBACK_CONDITION: printk(KERN_INFO "%s: Loopback Condition Detected.\n", card->devname); break; case NO_CHDLC_EXCEP_COND_TO_REPORT: printk(KERN_INFO "%s: No exceptions reported.\n", card->devname); break; default: printk(KERN_INFO "%s: Exception Condition %x!\n", card->devname,err); break; } } return 0; } /*============================================================================= * Store a UDP management packet for later processing. */ #if 0 static int store_udp_mgmt_pkt(char udp_pkt_src, sdla_t* card, struct sk_buff *skb, netdevice_t* dev, fr_private_area_t* chan ) { int udp_pkt_stored = 0; if(!chan->udp_pkt_lgth && (skb->len <= MAX_LGTH_UDP_MGNT_PKT)) { chan->udp_pkt_lgth = skb->len; chan->udp_pkt_src = udp_pkt_src; memcpy(chan->udp_pkt_data, skb->data, skb->len); card->u.c.timer_int_enabled = TMR_INT_ENABLED_UDP; udp_pkt_stored = 1; } if(udp_pkt_src == UDP_PKT_FRM_STACK) dev_kfree_skb_any(skb); else dev_kfree_skb_any(skb); return(udp_pkt_stored); } #endif static void fr_handle_front_end_state (void* card_id) { struct wan_dev_le *devle; sdla_t *card = (sdla_t*)card_id; netdevice_t *dev; fr_private_area_t *chan; if (card->wandev.ignore_front_end_status == WANOPT_YES){ return; } WAN_LIST_FOREACH(devle, &card->wandev.dev_head, dev_link){ dev = WAN_DEVLE2DEV(devle); if (!dev || !wan_netif_priv(dev)) continue; chan = wan_netif_priv(dev); if (card->fe.fe_status == FE_CONNECTED){ if (chan->dlci_state & PVC_STATE_ACTIVE && card->wandev.state == WAN_CONNECTED && chan->common.state != WAN_CONNECTED){ chan_set_state(dev,WAN_CONNECTED); } }else{ if (chan->common.state != WAN_DISCONNECTED){ if (chan->route_flag == ROUTE_ADDED) { chan->route_flag = REMOVE_ROUTE; /* The state change will trigger * the fr polling routine */ } if (chan->inarp == INARP_CONFIGURED) { chan->inarp = INARP_REQUEST; } chan_set_state(dev,WAN_DISCONNECTED); } } } } /*============================================================================== * Initializes the Statistics values in the fr_channel structure. */ void init_chan_statistics( fr_channel_t* chan) { memset(&chan->drvstats_if_send.if_send_entry, 0, sizeof(if_send_stat_t)); memset(&chan->drvstats_rx_intr.rx_intr_no_socket, 0, sizeof(rx_intr_stat_t)); memset(&chan->drvstats_gen.UDP_PIPE_mgmt_kmalloc_err, 0, sizeof(pipe_mgmt_stat_t)); } /*============================================================================== * Initializes the Statistics values in the Sdla_t structure. */ void init_global_statistics( sdla_t* card ) { /* Intialize global statistics for a card */ memset(&card->statistics.isr_entry, 0, sizeof(global_stats_t)); } /*============================================================================== * Process UDP call of type FPIPE8ND */ static int process_udp_mgmt_pkt(sdla_t* card, void *local_dev) { unsigned char frames; unsigned int len; unsigned short buffer_length; wan_mbox_t *mbox = &card->wan_mbox; int err; struct timeval tv; int udp_mgmt_req_valid = 1; netdevice_t* dev; fr_channel_t* chan; wan_udp_pkt_t *wan_udp_pkt; fpipemon_trc_t* fpipemon_trc; fr_prot_t *fr_prot = FR_PROT_AREA(card); SHARED_MEMORY_INFO_STRUCT flags; int dlci = 0; int orig_cmd=0; if (local_dev == NULL){ return 0; #if 0 /* Find network interface for this packet */ dev = find_channel(card, dlci); if (!dev){ card->u.f.udp_pkt_lgth = 0; return -ENODEV; } if ((chan = dev->priv) == NULL){ card->u.f.udp_pkt_lgth = 0; return -ENODEV; } /* If the UDP packet is from the network, we are going to have to transmit a response. Before doing so, we must check to see that we are not currently transmitting a frame (in 'if_send()') and that we are not already in a 'delayed transmit' state. */ if(udp_pkt_src == UDP_PKT_FRM_NETWORK) { if (check_tx_status(card,dev)){ card->u.f.udp_pkt_lgth = 0; return -EBUSY; } } wan_udp_pkt = (wan_udp_pkt_t *)card->u.f.udp_pkt_data; if(udp_pkt_src == UDP_PKT_FRM_NETWORK) { switch(wan_udp_pkt->wan_udp_command) { case FR_READ_MODEM_STATUS: case FR_READ_STATUS: case FPIPE_ROUTER_UP_TIME: case FR_READ_ERROR_STATS: case FPIPE_DRIVER_STAT_GEN: case FR_READ_STATISTICS: case FR_READ_ADD_DLC_STATS: case FR_READ_CONFIG: case FR_READ_CODE_VERSION: case WAN_GET_MEDIA_TYPE: case WAN_FE_GET_STAT: udp_mgmt_req_valid = 1; break; default: udp_mgmt_req_valid = 0; break; } } #endif }else{ dev = (netdevice_t *) local_dev; if ((chan = dev->priv) == NULL){ return -ENODEV; } dlci=chan->dlci; if (atomic_read(&chan->udp_pkt_len) == 0){ return -ENODEV; } wan_udp_pkt = (wan_udp_pkt_t *)chan->udp_pkt_data; udp_mgmt_req_valid=1; } //debug_print_udp_pkt((u8*)wan_udp_pkt,sizeof(wan_udp_pkt_t),0,1); card->hw_iface.peek(card->hw, card->flags_off, &flags, sizeof(flags)); if(!udp_mgmt_req_valid) { /* set length to 0 */ wan_udp_pkt->wan_udp_data_len = 0; /* set return code */ wan_udp_pkt->wan_udp_return_code = 0xCD; chan->drvstats_gen.UDP_PIPE_mgmt_direction_err ++; if (net_ratelimit()){ printk(KERN_INFO "%s: Warning, Illegal UDP command attempted from network: %x\n", card->devname,wan_udp_pkt->wan_udp_command); } } else { struct sk_buff *skb; struct sk_buff_head *trace_queue; switch(wan_udp_pkt->wan_udp_command) { case FR_READ_CONFIG: case FR_READ_CODE_VERSION: wan_udp_pkt->wan_udp_return_code = 0; wan_udp_pkt->wan_udp_data_len=0; break; case FR_LIST_ACTIVE_DLCI: { unsigned short *data_buf = (unsigned short*)wan_udp_pkt->wan_udp_data; int ch,data_len=0; for (ch=0;chglobal_dlci_map[ch]) continue; if (fr_prot->global_dlci_map[ch] & PVC_STATE_ACTIVE){ *data_buf=ch; data_buf ++; data_len +=2; } } wan_udp_pkt->wan_udp_return_code = 0; wan_udp_pkt->wan_udp_data_len = data_len; } break; case FR_READ_STATUS: { unsigned char *data_buf = (unsigned char*)wan_udp_pkt->wan_udp_data; int ch, data_len=0; *data_buf = (card->wandev.state == WAN_CONNECTED) ? 1:0; data_buf++; data_len+=1; for (ch=0;chglobal_dlci_map[ch]) continue; *(unsigned short*)data_buf=ch; data_buf +=2; *data_buf = (fr_prot->global_dlci_map[ch] | 0x40); data_buf++; data_len += 3; } wan_udp_pkt->wan_udp_return_code = 0; wan_udp_pkt->wan_udp_data_len = data_len; } break; case FR_READ_STATISTICS: memcpy(wan_udp_pkt->wan_udp_data,&fr_prot->link_stats,sizeof(fr_link_stat_t)); wan_udp_pkt->wan_udp_data_len = sizeof(fr_link_stat_t); wan_udp_pkt->wan_udp_return_code = 0; break; case FPIPE_ENABLE_TRACING: wan_udp_pkt->wan_udp_return_code = 0; if (wan_udp_pkt->wan_udp_data[0] & TRC_ACTIVE){ if (!test_bit(0,&chan->tracing_enabled)){ chan->stats.tx_fifo_errors=0; chan->stats.rx_over_errors=0; chan->trace_timeout=jiffies; skb_queue_purge(&chan->trace_queue); set_bit (0,&chan->tracing_enabled); printk(KERN_INFO "%s: %s: Frame Relay DLCI=%i trace enabled!\n", card->devname,chan->if_name,chan->dlci); }else{ printk(KERN_INFO "%s: %s: Error: Frame Relay DLCI=%i trace running!\n", card->devname,chan->if_name,chan->dlci); wan_udp_pkt->wan_udp_return_code = 2; } }else if (wan_udp_pkt->wan_udp_data[0] & (TRC_SIGNALLING_FRMS|TRC_INFO_FRMS)){ if (test_bit(0,&chan->tracing_enabled)){ printk(KERN_INFO "\n"); printk(KERN_INFO "%s: %s: Error: FR DLCI=%i trace running!\n", card->devname,chan->if_name,chan->dlci); wan_udp_pkt->wan_udp_return_code = 2; }else if (test_bit(1,&chan->tracing_enabled)){ printk(KERN_INFO "\n"); printk(KERN_INFO "%s: Error: Frame Relay LMI trace running!\n", card->devname); wan_udp_pkt->wan_udp_return_code = 1; }else if(!test_bit(0,&fr_prot->tracing_enabled)){ skb_queue_purge(&fr_prot->trace_queue); fr_prot->trace_timeout=jiffies; set_bit (1,&chan->tracing_enabled); set_bit (0,&fr_prot->tracing_enabled); printk(KERN_INFO "%s: Frame Relay LMI trace enabled!\n", card->devname); }else{ printk(KERN_INFO "\n"); printk(KERN_INFO "%s: %s: Error: FR LMI trace running!\n", card->devname,chan->if_name); wan_udp_pkt->wan_udp_return_code = 2; } }else{ printk(KERN_INFO "%s: %s: Invalid trace command options!\n", card->devname,chan->if_name); wan_udp_pkt->wan_udp_return_code = 1; } if (wan_udp_pkt->wan_udp_return_code == 0){ chan->stats.rx_fifo_errors=0; chan->stats.tx_fifo_errors=0; } wan_udp_pkt->wan_udp_data_len=0; break; case FPIPE_DISABLE_TRACING: wan_udp_pkt->wan_udp_return_code = 0; if(test_bit(0,&chan->tracing_enabled)) { clear_bit(0,&chan->tracing_enabled); skb_queue_purge(&chan->trace_queue); printk(KERN_INFO "%s: %s: Disabling FR DLCI=%i trace\n", card->devname,chan->if_name, chan->dlci); }else if (test_bit(1,&chan->tracing_enabled)){ clear_bit(1,&chan->tracing_enabled); clear_bit(0,&fr_prot->tracing_enabled); skb_queue_purge(&fr_prot->trace_queue); printk(KERN_INFO "%s: %s: Disabling FR LMI trace\n", card->devname,chan->if_name); }else{ /* set return code to line trace already disabled */ //printk(KERN_INFO "%s: %s: Frame Relay trace already disabled!\n", // card->devname,chan->if_name); wan_udp_pkt->wan_udp_return_code = 1; } /* set return code */ wan_udp_pkt->wan_udp_data_len=0; break; case FPIPE_GET_TRACE_INFO: if(test_bit(0,&chan->tracing_enabled)){ trace_queue=&chan->trace_queue; chan->trace_timeout=jiffies; }else if (test_bit(1,&chan->tracing_enabled)){ trace_queue=&fr_prot->trace_queue; fr_prot->trace_timeout=jiffies; }else{ printk(KERN_INFO "%s: %s: Error FR trace not enabled\n", card->devname,chan->if_name); /* set return code */ wan_udp_pkt->wan_udp_return_code = 1; wan_udp_pkt->wan_udp_data_len=0; break; } frames=0; buffer_length = 0; wan_udp_pkt->wan_udp_data[0x00] = 0x00; while ((skb=skb_dequeue(trace_queue)) != NULL){ fr_trc_el_t *trc_el = (fr_trc_el_t*)skb->data; if (trc_el->length > skb->len){ /* The frame is invalid or corrupted, * drop it */ dev_kfree_skb_any(skb); continue; } if((trc_el->length + sizeof(fpipemon_trc_hdr_t) + 1) > (MAX_TRACE_BUFFER - buffer_length)){ wan_udp_pkt->wan_udp_data[0x00] |= MORE_TRC_DATA; skb_queue_head(trace_queue,skb); break; } fpipemon_trc = (fpipemon_trc_t *)&wan_udp_pkt->wan_udp_data[buffer_length]; fpipemon_trc->fpipemon_trc_hdr.status = trc_el->attr; fpipemon_trc->fpipemon_trc_hdr.tmstamp = trc_el->tmstamp; fpipemon_trc->fpipemon_trc_hdr.length = trc_el->length; if(!trc_el->length) { fpipemon_trc->fpipemon_trc_hdr.data_passed = 0x00; }else { fpipemon_trc->fpipemon_trc_hdr.data_passed = 0x01; memcpy(fpipemon_trc->data, (skb->data+sizeof(fr_trc_el_t)), trc_el->length); } buffer_length += sizeof(fpipemon_trc_hdr_t); if(fpipemon_trc->fpipemon_trc_hdr.data_passed) { buffer_length += trc_el->length; } dev_kfree_skb_any(skb); if (++frames >= MAX_FRMS_TRACED){ break; } if(wan_udp_pkt->wan_udp_data[0x00] & MORE_TRC_DATA) { break; } } if(frames == MAX_FRMS_TRACED) { wan_udp_pkt->wan_udp_data[0x00] |= MORE_TRC_DATA; } /* set the total number of frames passed */ wan_udp_pkt->wan_udp_data[0x00] |= ((frames << 1) & (MAX_FRMS_TRACED << 1)); /* set the data length and return code */ wan_udp_pkt->wan_udp_data_len = buffer_length; wan_udp_pkt->wan_udp_return_code = 0; break; case FPIPE_FT1_READ_STATUS: ((unsigned char *)wan_udp_pkt->wan_udp_data )[0] = flags.FT1_info_struct.parallel_port_A_input; ((unsigned char *)wan_udp_pkt->wan_udp_data )[1] = flags.FT1_info_struct.parallel_port_B_input; wan_udp_pkt->wan_udp_return_code = 0; wan_udp_pkt->wan_udp_data_len = 2; break; case FPIPE_FLUSH_DRIVER_STATS: init_chan_statistics(chan); init_global_statistics(card); wan_udp_pkt->wan_udp_data_len=0; break; case FPIPE_ROUTER_UP_TIME: do_gettimeofday( &tv ); card->u.c.router_up_time = tv.tv_sec - card->u.c.router_start_time; *(unsigned long *)&wan_udp_pkt->wan_udp_data = card->u.c.router_up_time; wan_udp_pkt->wan_udp_data_len = sizeof(unsigned long); wan_udp_pkt->wan_udp_return_code = COMMAND_OK; break; case FPIPE_DRIVER_STAT_IFSEND: memcpy(wan_udp_pkt->wan_udp_data, &chan->drvstats_if_send.if_send_entry, sizeof(if_send_stat_t)); wan_udp_pkt->wan_udp_data_len =sizeof(if_send_stat_t); wan_udp_pkt->wan_udp_return_code = 0; break; case FPIPE_DRIVER_STAT_INTR: memcpy(wan_udp_pkt->wan_udp_data, &card->statistics.isr_entry, sizeof(global_stats_t)); memcpy(&wan_udp_pkt->wan_udp_data[sizeof(global_stats_t)], &chan->drvstats_rx_intr.rx_intr_no_socket, sizeof(rx_intr_stat_t)); wan_udp_pkt->wan_udp_data_len = sizeof(global_stats_t) + sizeof(rx_intr_stat_t); wan_udp_pkt->wan_udp_return_code = 0; break; case FPIPE_DRIVER_STAT_GEN: memcpy(wan_udp_pkt->wan_udp_data, &chan->drvstats_gen.UDP_PIPE_mgmt_kmalloc_err, sizeof(pipe_mgmt_stat_t)); memcpy(&wan_udp_pkt->wan_udp_data[sizeof(pipe_mgmt_stat_t)], &card->statistics, sizeof(global_stats_t)); wan_udp_pkt->wan_udp_data_len = sizeof(global_stats_t)+ sizeof(rx_intr_stat_t); wan_udp_pkt->wan_udp_return_code = 0; break; case FR_FT1_STATUS_CTRL: /* Enable FT1 MONITOR STATUS */ mbox->wan_command = 0x1C; if ((wan_udp_pkt->wan_udp_data[0] & ENABLE_READ_FT1_STATUS) || (wan_udp_pkt->wan_udp_data[0] & ENABLE_READ_FT1_OP_STATS)) { if( rCount++ != 0 ) { wan_udp_pkt->wan_udp_return_code = COMMAND_OK; wan_udp_pkt->wan_udp_data_len=1; mbox->wan_data_len = 1; break; } } /* Disable FT1 MONITOR STATUS */ if( wan_udp_pkt->wan_udp_data[0] == 0) { if( --rCount != 0) { wan_udp_pkt->wan_udp_return_code = COMMAND_OK; wan_udp_pkt->wan_udp_data_len=1; mbox->wan_data_len = 1; break; } } goto dflt_1; case FR_SET_FT1_MODE: mbox->wan_command = 0x1E; goto dflt_1; #ifdef TE1_56_CARD_SUPPORT case WAN_GET_MEDIA_TYPE: case WAN_FE_GET_STAT: case WAN_FE_SET_LB_MODE: case WAN_FE_FLUSH_PMON: case WAN_FE_GET_CFG: if (IS_TE1_CARD(card)){ card->wandev.fe_iface.process_udp( &card->fe, &wan_udp_pkt->wan_udp_cmd, &wan_udp_pkt->wan_udp_data[0]); }else if (IS_56K_CARD(card)){ card->wandev.fe_iface.process_udp( &card->fe, &wan_udp_pkt->wan_udp_cmd, &wan_udp_pkt->wan_udp_data[0]); }else{ if (wan_udp_pkt->wan_udp_command == WAN_GET_MEDIA_TYPE){ wan_udp_pkt->wan_udp_data_len = sizeof(unsigned char); wan_udp_pkt->wan_udp_return_code = CMD_OK; }else{ wan_udp_pkt->wan_udp_return_code = WAN_UDP_INVALID_CMD; } } break; #if 0 case WAN_FE_SET_LB_MODE: /* Activate/Deactivate Line Loopback modes */ if (IS_TE1_CARD(card)){ err = card->wandev.fe_iface.set_fe_lbmode( &card->fe, wan_udp_pkt->wan_udp_data[0], wan_udp_pkt->wan_udp_data[1]); wan_udp_pkt->wan_udp_return_code = (!err) ? CMD_OK : WAN_UDP_FAILED_CMD; }else{ wan_udp_pkt->wan_udp_return_code = WAN_UDP_INVALID_CMD; } wan_udp_pkt->wan_udp_data_len = 0x00; break; case WAN_GET_MEDIA_TYPE: wan_udp_pkt->wan_udp_data[0] = (IS_T1_CARD(card) ? WAN_MEDIA_T1 : IS_E1_CARD(card) ? WAN_MEDIA_E1 : IS_56K_CARD(card) ? WAN_MEDIA_56K : WAN_MEDIA_NONE); wan_udp_pkt->wan_udp_data_len = sizeof(unsigned char); wan_udp_pkt->wan_udp_return_code = COMMAND_OK; break; case WAN_FE_GET_STAT: if (IS_TE1_CARD(card)) { /* TE1_56K Read T1/E1/56K alarms */ *(unsigned long *)&wan_udp_pkt->wan_udp_data = card->wandev.fe_iface.read_alarm( &card->fe, 0); /* TE1 Update T1/E1 perfomance counters */ sdla_te_pmon(card); memcpy(&wan_udp_pkt->wan_udp_data[sizeof(unsigned long)], &card->wandev.te_pmon, sizeof(sdla_te_pmon_t)); wan_udp_pkt->wan_udp_return_code = COMMAND_OK; wan_udp_pkt->wan_udp_data_len = sizeof(unsigned long) + sizeof(sdla_te_pmon_t); }else if (IS_56K_CARD(card)){ /* 56K Update CSU/DSU alarms */ card->wandev.k56_alarm = sdla_56k_alarm(card, 1); *(unsigned long *)&wan_udp_pkt->wan_udp_data = card->wandev.k56_alarm; wan_udp_pkt->wan_udp_return_code = COMMAND_OK; wan_udp_pkt->wan_udp_data_len = sizeof(unsigned long); } break; case WAN_FE_FLUSH_PMON: /* TE1 Flush T1/E1 pmon counters */ if (IS_TE1_CARD(card)){ card->wandev.fe_iface.flush_pmon(&card->fe); wan_udp_pkt->wan_udp_return_code = COMMAND_OK; } wan_udp_pkt->wan_udp_data_len=0; break; case WAN_FE_GET_CFG: /* Read T1/E1 configuration */ if (IS_TE1_CARD(card)){ memcpy(&wan_udp_pkt->wan_udp_data[0], &card->wandev.te_cfg, sizeof(sdla_te_cfg_t)); wan_udp_pkt->wan_udp_return_code = COMMAND_OK; wan_udp_pkt->wan_udp_data_len = sizeof(sdla_te_cfg_t); } break; #endif case WAN_GET_PROTOCOL: wan_udp_pkt->wan_udp_data[0] = card->wandev.config_id; wan_udp_pkt->wan_udp_return_code = CMD_OK; wan_udp_pkt->wan_udp_data_len = 1; break; case WAN_GET_PLATFORM: wan_udp_pkt->wan_udp_data[0] = WAN_LINUX_PLATFORM; wan_udp_pkt->wan_udp_return_code = CMD_OK; wan_udp_pkt->wan_udp_data_len = 1; break; #endif default: orig_cmd=wan_udp_pkt->wan_udp_command; switch(wan_udp_pkt->wan_udp_command){ case FR_READ_MODEM_STATUS: mbox->wan_command = READ_MODEM_STATUS; break; case FR_READ_ERROR_STATS: mbox->wan_command = READ_COMMS_ERROR_STATS; break; case FR_FLUSH_ERROR_STATS: mbox->wan_command = FLUSH_COMMS_ERROR_STATS; break; default: mbox->wan_return_code=1; goto udp_cmd_done; } dflt_1: /* it's a board command */ mbox->wan_data_len = wan_udp_pkt->wan_udp_data_len; if (mbox->wan_data_len) { memcpy(&mbox->wan_data, (unsigned char *) wan_udp_pkt-> wan_udp_data, mbox->wan_data_len); } /* run the command on the board */ err = card->hw_iface.cmd(card->hw, card->mbox_off, mbox); if (err != COMMAND_OK) { hdlc_error(card,err,mbox); break; } /* copy the result back to our buffer */ memcpy(&wan_udp_pkt->wan_udp_hdr.wan_cmd, mbox, sizeof(wan_cmd_t)); if (mbox->wan_data_len) { memcpy(&wan_udp_pkt->wan_udp_data, &mbox->wan_data, mbox->wan_data_len); } wan_udp_pkt->wan_udp_data_len=mbox->wan_data_len; wan_udp_pkt->wan_udp_return_code=err; if(!err) chan->drvstats_gen. UDP_PIPE_mgmt_adptr_cmnd_OK ++; else chan->drvstats_gen. UDP_PIPE_mgmt_adptr_cmnd_timeout ++; switch(orig_cmd){ case FR_READ_ERROR_STATS: { COMMS_ERROR_STATS_STRUCT *comm_stats = (COMMS_ERROR_STATS_STRUCT *)mbox->wan_data; wan_udp_pkt->wan_udp_data[8]=comm_stats->DCD_state_change_count; wan_udp_pkt->wan_udp_data[9]=comm_stats->CTS_state_change_count; wan_udp_pkt->wan_udp_data_len=mbox->wan_data_len=10; wan_udp_pkt->wan_udp_return_code=0; } break; } } } udp_cmd_done: /* Fill UDP TTL */ wan_udp_pkt->wan_ip_ttl = card->wandev.ttl; len=0; if (local_dev){ len = reply_udp(chan->udp_pkt_data, wan_udp_pkt->wan_udp_data_len); }else{ //len = reply_udp(card->u.f.udp_pkt_data, mbox->wan_data_len); } //debug_print_udp_pkt((u8*)wan_udp_pkt,sizeof(wan_udp_pkt_t),0,0); if (local_dev){ atomic_set(&chan->udp_pkt_len,len); return len; } #if 0 else if(udp_pkt_src == UDP_PKT_FRM_NETWORK) { chan->fr_header_len=2; chan->fr_header[0]=chan->fr_encap_0; chan->fr_header[1]=chan->fr_encap_1; err = fr_send_data_header(card, dlci, 0, len, card->u.f.udp_pkt_data,chan->fr_header_len); if (err){ chan->drvstats_gen.UDP_PIPE_mgmt_adptr_send_passed ++; }else{ chan->drvstats_gen.UDP_PIPE_mgmt_adptr_send_failed ++; } }else{ /* Allocate socket buffer */ if((new_skb = dev_alloc_skb(len)) != NULL) { /* copy data into new_skb */ buf = skb_put(new_skb, len); memcpy(buf, card->u.f.udp_pkt_data, len); chan->drvstats_gen. UDP_PIPE_mgmt_passed_to_stack ++; new_skb->dev = dev; new_skb->protocol = htons(ETH_P_IP); new_skb->mac.raw = new_skb->data; netif_rx(new_skb); } else { chan->drvstats_gen.UDP_PIPE_mgmt_no_socket ++; printk(KERN_INFO "%s: UDP mgmt cmnd, no socket buffers available!\n", card->devname); } } card->u.f.udp_pkt_lgth = 0; #endif return len; } /*============================================================================ * Initialize Receive and Transmit Buffers. */ static void init_hdlc_tx_rx_buff( sdla_t* card) { wan_mbox_t* mb = &card->wan_mbox; unsigned long tx_config_off; unsigned long rx_config_off; CHDLC_TX_STATUS_EL_CFG_STRUCT tx_config; CHDLC_RX_STATUS_EL_CFG_STRUCT rx_config; char err; mb->wan_data_len = 0; mb->wan_command = READ_CHDLC_CONFIGURATION; err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); if(err != COMMAND_OK) { hdlc_error(card,err,mb); return; } /* ALEX Apr 8 2004 Sangoma ISA card */ tx_config_off = ((CHDLC_CONFIGURATION_STRUCT *)mb->wan_data)-> ptr_CHDLC_Tx_stat_el_cfg_struct; rx_config_off = ((CHDLC_CONFIGURATION_STRUCT *)mb->wan_data)-> ptr_CHDLC_Rx_stat_el_cfg_struct; /* Setup Head and Tails for buffers */ card->hw_iface.peek(card->hw, tx_config_off, &tx_config, sizeof(tx_config)); card->u.c.txbuf_base_off = tx_config.base_addr_Tx_status_elements; card->u.c.txbuf_last_off = card->u.c.txbuf_base_off + (tx_config.number_Tx_status_elements - 1) * sizeof(CHDLC_DATA_TX_STATUS_EL_STRUCT); card->hw_iface.peek(card->hw, tx_config_off, &tx_config, sizeof(tx_config)); card->hw_iface.peek(card->hw, rx_config_off, &rx_config, sizeof(rx_config)); card->u.c.rxbuf_base_off = rx_config.base_addr_Rx_status_elements; card->u.c.rxbuf_last_off = card->u.c.rxbuf_base_off + (rx_config.number_Rx_status_elements - 1) * sizeof(CHDLC_DATA_RX_STATUS_EL_STRUCT); /* Set up next pointer to be used */ card->u.c.txbuf_off = tx_config.next_Tx_status_element_to_use; card->u.c.rxmb_off = rx_config.next_Rx_status_element_to_use; /* Setup Actual Buffer Start and end addresses */ card->u.c.rx_base_off = rx_config.base_addr_Rx_buffer; card->u.c.rx_top_off = rx_config.end_addr_Rx_buffer; } /*============================================================================= * Perform Interrupt Test by running READ_CHDLC_CODE_VERSION command MAX_INTR * _TEST_COUNTER times. */ static int intr_test( sdla_t* card) { wan_mbox_t* mb = &card->wan_mbox; int err,i; card->timer_int_enabled = 0; /* The critical flag is unset because during intialization (if_open) * we want the interrupts to be enabled so that when the wpc_isr is * called it does not exit due to critical flag set. */ err = hdlc_set_intr_mode(card, APP_INT_ON_COMMAND_COMPLETE); if (err == CMD_OK) { for (i = 0; i < MAX_INTR_TEST_COUNTER; i ++) { mb->wan_data_len = 0; mb->wan_command = READ_CHDLC_CODE_VERSION; err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); } }else{ return err; } err = hdlc_set_intr_mode(card, 0); if (err != CMD_OK) return err; return 0; } /*============================================================================== * Determine what type of UDP call it is. FPIPE8ND ? */ #if 0 static int udp_pkt_type( struct sk_buff *skb, sdla_t* card, int direction) { wan_udp_pkt_t *wan_udp_pkt = (wan_udp_pkt_t *)skb->data; if (skb->len < sizeof(wan_udp_pkt_t)){ return UDP_INVALID_TYPE; } /* Quick HACK */ if (direction == UDP_PKT_FRM_NETWORK){ wan_udp_pkt = (wan_udp_pkt_t *)&skb->data[2]; } if((wan_udp_pkt->ip_pkt.protocol == UDPMGMT_UDP_PROTOCOL) && (wan_udp_pkt->ip_pkt.ver_inet_hdr_length == 0x45) && (wan_udp_pkt->udp_pkt.udp_dst_port == ntohs(card->wandev.udp_port)) && (wan_udp_pkt->wp_mgmt.request_reply == UDPMGMT_REQUEST)) { if(!strncmp(wan_udp_pkt->wp_mgmt.signature, UDPMGMT_FPIPE_SIGNATURE, 8)){ return UDP_FPIPE_TYPE; } } return UDP_INVALID_TYPE; } #endif /*============================================================================ * Set PORT state. */ static void chan_set_state (netdevice_t *dev, int state) { fr_private_area_t *chan; sdla_t *card; if (!dev || !dev->priv){ return; } chan=dev->priv; card = chan->card; if (chan->common.state != state){ chan->common.state = state; switch (state){ case WAN_CONNECTED: printk (KERN_INFO "%s: %s: DLCI %i: link connected!\n", card->devname,chan->if_name,chan->dlci); #ifdef CONFIG_PRODUCT_WANPIPE_ANNEXG if (chan->common.usedby == ANNEXG && chan->annexg_dev){ if (IS_FUNC_CALL(lapb_protocol,lapb_link_up)) lapb_protocol.lapb_link_up(chan->annexg_dev); } #endif break; case WAN_CONNECTING: printk (KERN_INFO "%s: %s: DLCI %i: link connecting...\n", card->devname,chan->if_name,chan->dlci); break; case WAN_DISCONNECTED: printk (KERN_INFO "%s: %s: DLCI %i: link disconnected!\n", card->devname,chan->if_name,chan->dlci); #ifdef CONFIG_PRODUCT_WANPIPE_ANNEXG if (chan->common.usedby == ANNEXG && chan->annexg_dev){ if (IS_FUNC_CALL(lapb_protocol,lapb_link_down)) lapb_protocol.lapb_link_down(chan->annexg_dev); } #endif break; } } } /*=========================================================================== * config_hdlc * * Configure the fr protocol and enable communications. * * The if_open() function binds this function to the poll routine. * Therefore, this function will run every time the fr interface * is brought up. We cannot run this function from the if_open * because if_open does not have access to the remote IP address. * * If the communications are not enabled, proceed to configure * the card and enable communications. * * If the communications are enabled, it means that the interface * was shutdown by ether the user or driver. In this case, we * have to check that the IP addresses have not changed. If * the IP addresses have changed, we have to reconfigure the firmware * and update the changed IP addresses. Otherwise, just exit. * */ static int config_hdlc (sdla_t *card) { if (card->u.c.comm_enabled){ hdlc_comm_disable(card); wanpipe_set_state(card, WAN_DISCONNECTED); } if (set_hdlc_config(card)) { printk(KERN_INFO "%s: CHDLC Configuration Failed!\n", card->devname); return -EIO; } #ifdef TE1_56_CARD_SUPPORT card->hw_iface.poke_byte(card->hw, card->intr_type_off, 0x00); card->hw_iface.poke_byte(card->hw, card->intr_perm_off, 0x00); if (IS_TE1_CARD(card)) { printk(KERN_INFO "%s: Configuring onboard %s CSU/DSU\n", card->devname, (IS_T1_CARD(card))?"T1":"E1"); if (sdla_te_config(&card->fe, &card->wandev.fe_iface)){ printk(KERN_INFO "%s: Failed %s configuratoin!\n", card->devname, (IS_T1_CARD(card))?"T1":"E1"); return -EINVAL; } } if (IS_56K_CARD(card)) { printk(KERN_INFO "%s: Configuring 56K onboard CSU/DSU\n", card->devname); if(sdla_56k_config(&card->fe, &card->wandev.fe_iface)){ printk (KERN_INFO "%s: Failed 56K configuration!\n", card->devname); return -EINVAL; } } #endif /* Set interrupt mode and mask */ if (hdlc_set_intr_mode(card, APP_INT_ON_RX_FRAME | APP_INT_ON_GLOBAL_EXCEP_COND | APP_INT_ON_TX_FRAME | APP_INT_ON_CHDLC_EXCEP_COND | APP_INT_ON_TIMER)){ printk (KERN_INFO "%s: Failed to set interrupt triggers!\n", card->devname); return -EIO; } /* Mask All interrupts */ card->hw_iface.clear_bit(card->hw, card->intr_perm_off, (APP_INT_ON_RX_FRAME | APP_INT_ON_TX_FRAME | APP_INT_ON_TIMER | APP_INT_ON_GLOBAL_EXCEP_COND | APP_INT_ON_CHDLC_EXCEP_COND)); if (hdlc_comm_enable(card) != 0) { printk(KERN_INFO "%s: Failed to enable fr communications!\n", card->devname); card->hw_iface.poke_byte(card->hw, card->intr_perm_off, 0x00); card->u.c.comm_enabled=0; hdlc_set_intr_mode(card,0); return -EIO; } init_hdlc_tx_rx_buff(card); #ifdef TE1_56_CARD_SUPPORT /* Manually poll the 56K CSU/DSU to get the status */ if (IS_56K_CARD(card)) { /* 56K Update CSU/DSU alarms */ card->wandev.fe_iface.read_alarm(&card->fe, 1); } #endif /* Unmask all interrupts except the Transmit and Timer interrupts */ card->hw_iface.set_bit(card->hw, card->intr_perm_off, (APP_INT_ON_RX_FRAME | APP_INT_ON_GLOBAL_EXCEP_COND | APP_INT_ON_CHDLC_EXCEP_COND)); card->hw_iface.poke_byte(card->hw, card->intr_type_off, 0x00); printk(KERN_INFO "%s: Enabling data link layer!\n",card->devname); return 0; } /* * ****************************************************************** * Proc FS function */ #define PROC_CFG_FRM "%-15s| %-12s| %-5u|\n" #define PROC_STAT_FRM "%-15s| %-12s| %-14s|\n" static char fr_config_hdr[] = "Interface name | Device name | DLCI |\n"; static char fr_status_hdr[] = "Interface name | Device name | Status |\n"; static int fr_get_config_info(void* priv, struct seq_file* m, int* stop_cnt) { fr_private_area_t* chan = priv; sdla_t* card = NULL; if (chan == NULL){ return m->count; }else{ card = chan->card; if ((m->from == 0 && m->count == 0) || (m->from && m->from == *stop_cnt)){ PROC_ADD_LINE(m, "%s", fr_config_hdr); } PROC_ADD_LINE(m, PROC_CFG_FRM, chan->if_name, card->devname, chan->dlci); } return m->count; } static int fr_get_status_info(void* priv, struct seq_file* m, int* stop_cnt) { fr_channel_t* chan = (fr_channel_t*)priv; sdla_t* card = chan->card; if (chan == NULL) return m->count; if ((m->from == 0 && m->count == 0) || (m->from && m->from == *stop_cnt)){ PROC_ADD_LINE(m, "%s", fr_status_hdr); } PROC_ADD_LINE(m, PROC_STAT_FRM, chan->if_name, card->devname, STATE_DECODE(chan->common.state)); return m->count; } #define PROC_DEV_FR_S_FRM "%-20s| %-14s|\n" #define PROC_DEV_FR_D_FRM "%-20s| %-14d|\n" #define PROC_DEV_SEPARATE "=====================================\n" /* DevName, DLCI, DlciState, DlciNewS, GDlciState, DevState */ #define PROC_DEV_FR_SDDD_TITLE_FRM "%-12s| %-5s | %-6s | %-7s | %-8s | %-13s |\n" #define PROC_DEV_FR_SDDD_FRM "%-12s| %-5d | %-6d | %-7d | %-8d | %-13s |\n" #define PROC_DEV_SEPARATE1 "===================================================================\n" static int fr_set_dev_config(struct file *file, const char *buffer, unsigned long count, void *data) { int cnt = 0; wan_device_t* wandev = (void*)data; sdla_t* card = NULL; if (wandev == NULL) return cnt; card = (sdla_t*)wandev->private; printk(KERN_INFO "%s: New device config (%s)\n", wandev->name, buffer); /* Parse string */ return count; } #define PROC_IF_FR_S_FRM "%-30s\t%-14s\n" #define PROC_IF_FR_D_FRM "%-30s\t%-14d\n" #define PROC_IF_FR_L_FRM "%-30s\t%-14ld\n" #define PROC_IF_SEPARATE "====================================================\n" static int fr_set_if_info(struct file *file, const char *buffer, unsigned long count, void *data) { netdevice_t* dev = (void*)data; fr_private_area_t* chan = NULL; sdla_t* card = NULL; if (dev == NULL || dev->priv == NULL) return count; chan = (fr_private_area_t*)dev->priv; if (chan->card == NULL) return count; card = chan->card; printk(KERN_INFO "%s: New interface config (%s)\n", chan->if_name, buffer); /* Parse string */ return count; } static void s508_s514_lock(sdla_t *card, unsigned long *smp_flags) { if (card->type != SDLA_S514){ spin_lock_irqsave(&card->wandev.lock, *smp_flags); }else{ spin_lock(&card->u.c.if_send_lock); } return; } static void s508_s514_unlock(sdla_t *card, unsigned long *smp_flags) { if (card->type != SDLA_S514){ spin_unlock_irqrestore (&card->wandev.lock, *smp_flags); }else{ spin_unlock(&card->u.c.if_send_lock); } return; } /*============================================================================ * Convert decimal string to unsigned integer. * If len != 0 then only 'len' characters of the string are converted. */ static unsigned int dec_to_uint (unsigned char* str, int len) { unsigned val; if (!len) len = strlen(str); for (val = 0; len && is_digit(*str); ++str, --len) val = (val * 10) + (*str - (unsigned)'0'); return val; } /* =============== Frame Relay Protocol ============================ */ static int fr_hard_header(sdla_t *card, netdevice_t *dev, u16 type) { fr_private_area_t *chan = dev->priv; if (!chan) return -ENODEV; #ifdef CONFIG_PRODUCT_WANPIPE_ANNEXG if (chan->common.usedby == ANNEXG){ dlci_to_q922(chan->header, chan->dlci); chan->hdr_len = 2; return chan->hdr_len; } #endif switch(type) { case ETH_P_IP: chan->hdr_len = 4; chan->header[3]=NLPID_IP; break; case ETH_P_IPV6: chan->hdr_len = 4; chan->header[3]=NLPID_IPV6; break; default: chan->hdr_len = 10; chan->header[3] = FR_PAD; chan->header[4] = NLPID_SNAP; chan->header[5] = FR_PAD; chan->header[6] = FR_PAD; chan->header[7] = FR_PAD; chan->header[8] = type>>8; chan->header[9] = (u8)type; } dlci_to_q922(chan->header, chan->dlci); chan->header[2] = FR_UI; return chan->hdr_len; } static __inline__ void dlci_to_status(sdla_t *card, u16 dlci, u8 *status, u8 state) { status[0] = (dlci>>4) & 0x3F; status[1] = ((dlci<<3) & 0x78) | 0x80; status[2] = 0x80; if (state & PVC_STATE_NEW) status[2] |= 0x08; else if (state & PVC_STATE_ACTIVE) status[2] |= 0x02; } static inline void fr_log_dlci_active(fr_private_area_t *chan) { printk(KERN_INFO "%s: %s: DLCI %i: %sactive%s\n", ((sdla_t*)chan->card)->devname, chan->if_name, chan->dlci, chan->dlci_state & PVC_STATE_ACTIVE ? "" : "in", chan->dlci_state & PVC_STATE_NEW ? " new" : ""); } static void fr_timer(unsigned long arg) { sdla_t *card = (sdla_t*)arg; fr_prot_t *fr_prot = FR_PROT_AREA(card); int i, cnt = 0, reliable; netdevice_t *dev; fr_private_area_t *chan; u32 list; // printk(KERN_INFO "FR TIMER FR:State=0x%X LastErrors=0x%X\n", // fr_prot->state,fr_prot->last_errors); if (fr_prot->station == WANOPT_NODE){ reliable = ((jiffies - fr_prot->last_rx_poll) < (fr_prot->cfg.t392*HZ)); if (!reliable){ fr_prot->link_stats.T392_timeouts++; } }else{ fr_prot->last_errors <<= 1; /* Shift the list */ if (fr_prot->state & LINK_STATE_REQUEST) { printk(KERN_INFO "%s: Frame Relay: No LMI status reply received\n", card->devname); fr_prot->last_errors |= 1; fr_prot->link_stats.T391_timeouts++; } for (i = 0, list = fr_prot->last_errors; i < fr_prot->cfg.n393; i++, list >>= 1){ cnt += (list & 1); /* errors count */ } reliable = (cnt < fr_prot->cfg.n392); } if ((fr_prot->state & LINK_STATE_RELIABLE) != (reliable ? LINK_STATE_RELIABLE : 0)){ struct wan_dev_le *devle; WAN_LIST_FOREACH(devle, &card->wandev.dev_head, dev_link){ dev = WAN_DEVLE2DEV(devle); if (!dev || !wan_netif_priv(dev)) continue; if (!(dev->flags & IFF_UP)) continue; chan = wan_netif_priv(dev); chan->dlci_state &= ~(PVC_STATE_NEW | PVC_STATE_ACTIVE); chan_set_state(dev,WAN_DISCONNECTED); } fr_prot->state ^= LINK_STATE_RELIABLE; if (reliable){ wanpipe_set_state(card,WAN_CONNECTED); }else{ printk(KERN_INFO "%s: Link unreliable !\n", card->devname); wanpipe_set_state(card,WAN_DISCONNECTED); } //printk(KERN_INFO "%s: Link %sreliable\n", card->devname, // reliable ? "" : "un"); if (reliable) { fr_prot->n391cnt = 0; /* Request full status */ fr_prot->state |= LINK_STATE_CHANGED; } } if (fr_prot->station == WANOPT_NODE){ fr_prot->timer.expires = jiffies + fr_prot->cfg.t392*HZ; }else{ if (fr_prot->n391cnt) fr_prot->n391cnt--; fr_lmi_send(card, (fr_prot->n391cnt == 0)); fr_prot->state |= LINK_STATE_REQUEST; fr_prot->timer.expires = jiffies + (fr_prot->cfg.t391*HZ); } add_timer(&fr_prot->timer); } static void fr_lmi_send(sdla_t *card, int fullrep) { struct sk_buff *skb; fr_prot_t *fr_prot = FR_PROT_AREA(card); netdevice_t *dev; fr_private_area_t *chan; int len = (fr_prot->cfg.signalling == WANOPT_FR_ANSI) ? LMI_ANSI_LENGTH : LMI_LENGTH; int stat_len = 3; u8 *data; int i = 0,ch; int dlci_cnt=0; if (fr_prot->station == WANOPT_NODE && fullrep) { dlci_cnt=card->wandev.new_if_cnt; len += dlci_cnt * (2 + stat_len); if (len > card->wandev.mtu) { printk(KERN_INFO "\n"); printk(KERN_INFO "%s: Error: Full status report size %i exceeds MTU=%i\n", card->devname,len,card->wandev.mtu); printk(KERN_INFO "%s: Error: Too many DLCI's configured or increase MTU\n", card->devname); card->wandev.stats.tx_errors++; return; } } skb = dev_alloc_skb(len); if (!skb) { printk(KERN_INFO "%s: Memory squeeze on fr_lmi_send()\n", card->devname); card->wandev.stats.tx_errors++; return; } memset(skb->data, 0, len); skb_reserve(skb, 4); skb_push(skb, 4); skb->data[3] = LMI_PROTO; dlci_to_q922(skb->data, fr_prot->lmi_dlci); skb->data[2] = FR_UI; data = skb->tail; data[i++] = LMI_CALLREF; data[i++] = (fr_prot->station == WANOPT_NODE) ? LMI_STATUS : LMI_STATUS_ENQUIRY; if (fr_prot->cfg.signalling == WANOPT_FR_ANSI){ data[i++] = LMI_ANSI_LOCKSHIFT; } data[i++] = MODE_FR_CCITT ? LMI_CCITT_REPTYPE : LMI_REPTYPE; data[i++] = LMI_REPT_LEN; data[i++] = fullrep ? LMI_FULLREP : LMI_INTEGRITY; data[i++] = MODE_FR_CCITT ? LMI_CCITT_ALIVE : LMI_ALIVE; data[i++] = LMI_INTEG_LEN; data[i++] = fr_prot->txseq = fr_lmi_nextseq(fr_prot->txseq); data[i++] = fr_prot->rxseq; if (fr_prot->station == WANOPT_NODE && fullrep) { for (ch=0;chdlci_to_dev_map[ch]) == NULL) continue; if (--dlci_cnt < 0) break; chan=dev->priv; if (!chan) continue; //printk(KERN_INFO "Interigating %s DLCI=%i\n",chan->if_name,chan->dlci); data[i++] = MODE_FR_CCITT ? LMI_CCITT_PVCSTAT:LMI_PVCSTAT; data[i++] = stat_len; if ((fr_prot->state & LINK_STATE_RELIABLE) && (dev->flags & IFF_UP) && !(chan->dlci_state & (PVC_STATE_ACTIVE|PVC_STATE_NEW))) { chan->dlci_state |= PVC_STATE_NEW; fr_log_dlci_active(chan); if (!(chan->dlci_state & PVC_STATE_ACTIVE)){ chan_set_state(dev,WAN_DISCONNECTED); } } dlci_to_status(card, chan->dlci, data+i, chan->dlci_state); i += stat_len; } } if (fr_prot->station == WANOPT_NODE){ if (fullrep){ fr_prot->link_stats.node_tx_FSR++; }else{ fr_prot->link_stats.node_tx_LIV++; } }else{ if (fullrep){ fr_prot->link_stats.cpe_tx_FSE++; }else{ fr_prot->link_stats.cpe_tx_LIV++; } } skb_put(skb, i); skb->priority = TC_PRIO_CONTROL; capture_trace_packet(card,NULL,skb,TRC_OUTGOING_FRM); skb_queue_tail(&fr_prot->lmi_queue,skb); card->hw_iface.set_bit(card->hw, card->intr_perm_off, APP_INT_ON_TX_FRAME); } void init_global_dlci_state(sdla_t *card) { fr_prot_t *fr_prot = FR_PROT_AREA(card); memset(fr_prot->global_dlci_map,0,sizeof(fr_prot->global_dlci_map)); return; } void set_global_dlci_state(sdla_t *card, u16 dlci, u8 state) { fr_prot_t *fr_prot = FR_PROT_AREA(card); if (dlci > HIGHEST_VALID_DLCI){ return; } fr_prot->global_dlci_map[dlci] = state; } static int fr_lmi_recv(sdla_t* card, struct sk_buff *skb) { struct wan_dev_le *devle; int stat_len; int reptype = -1, error; u8 rxseq, txseq; fr_prot_t *fr_prot=FR_PROT_AREA(card); netdevice_t *dev; fr_private_area_t *chan; int i; // printk(KERN_INFO "\n"); // printk(KERN_INFO "FR LMI REC: Len=%i Min=%i\n",skb->len, LMI_ANSI_LENGTH); if (skb->len < ((fr_prot->cfg.signalling == WANOPT_FR_ANSI) ? LMI_ANSI_LENGTH : LMI_LENGTH)) { printk(KERN_INFO "%s: Short LMI frame\n", card->devname); fr_prot->link_stats.rx_dropped++; return 1; } if (skb->data[5] != ((fr_prot->station != WANOPT_NODE) ? LMI_STATUS : LMI_STATUS_ENQUIRY)) { printk(KERN_INFO "%s: LMI msgtype=%x, Not LMI status %s\n", card->devname, skb->data[2], (fr_prot->station != WANOPT_NODE) ? "enquiry" : "reply"); fr_prot->link_stats.rx_bad_format++; return 1; } i = (fr_prot->cfg.signalling == WANOPT_FR_ANSI) ? 7 : 6; if (skb->data[i] != (MODE_FR_CCITT ? LMI_CCITT_REPTYPE : LMI_REPTYPE)) { printk(KERN_INFO "%s: Not a report type=%x\n", card->devname, skb->data[i]); fr_prot->link_stats.rx_bad_format++; return 1; } i++; i++; /* Skip length field */ reptype = skb->data[i++]; //printk(KERN_INFO "(Debug) RepType = 0x%x, Inc=%i\n",reptype,i); if (skb->data[i] != ((MODE_FR_CCITT) ? LMI_CCITT_ALIVE : LMI_ALIVE)) { printk(KERN_INFO "%s: Unsupported status element=%x\n", card->devname, skb->data[i]); fr_prot->link_stats.rx_bad_format++; return 1; } i++; i++; /* Skip length field */ fr_prot->rxseq = skb->data[i++]; /* TX sequence from peer */ rxseq = skb->data[i++]; /* Should confirm our sequence */ txseq = fr_prot->txseq; //printk(KERN_INFO "TxSeqOrig=%i TxSeqFrame=%i RxSeqFrame=%i Inc=%i\n", // txseq, fr_prot->rxseq, rxseq,i); if (fr_prot->station == WANOPT_NODE) { switch (reptype){ case LMI_INTEGRITY: fr_prot->link_stats.node_rx_LIV++; //card->wandev.stats.rx_crc_errors++; break; case LMI_FULLREP: fr_prot->link_stats.node_rx_FSE++; //card->wandev.stats.rx_frame_errors++; break; default: printk(KERN_INFO "%s: Unsupported report type=%x\n", card->devname, reptype); fr_prot->link_stats.rx_bad_format++; return 1; } }else{ switch (reptype){ case LMI_INTEGRITY: fr_prot->link_stats.cpe_rx_LIV++; break; case LMI_FULLREP: fr_prot->link_stats.cpe_rx_FSR++; break; } } error = 0; if (!(fr_prot->state & LINK_STATE_RELIABLE)){ //printk(KERN_INFO "FR Link State ! Reliable\n"); error = 1; } if (rxseq == 0 || rxseq != txseq) { //printk(KERN_INFO "Rxseq =0 or != TxSeq ask for full status again\n"); fr_prot->n391cnt = 0; /* Ask for full report next time */ error = 1; } if (fr_prot->station == WANOPT_NODE) { if ((fr_prot->state & LINK_STATE_FULLREP_SENT) && !error) { /* Stop sending full report - the last one has been confirmed by DTE */ fr_prot->state &= ~LINK_STATE_FULLREP_SENT; WAN_LIST_FOREACH(devle, &card->wandev.dev_head, dev_link){ dev = WAN_DEVLE2DEV(devle); if (!dev || !wan_netif_priv(dev)) continue; chan = wan_netif_priv(dev); if (chan->dlci_state & PVC_STATE_NEW) { chan->dlci_state &= ~PVC_STATE_NEW; chan->dlci_state |= PVC_STATE_ACTIVE; fr_log_dlci_active(chan); if (card->fe.fe_status == FE_CONNECTED){ chan_set_state(dev,WAN_CONNECTED); } /* Tell DTE that new PVC is now active */ fr_prot->state |= LINK_STATE_CHANGED; } } } if (fr_prot->state & LINK_STATE_CHANGED) { reptype = LMI_FULLREP; fr_prot->state |= LINK_STATE_FULLREP_SENT; fr_prot->state &= ~LINK_STATE_CHANGED; } fr_lmi_send(card, (reptype == LMI_FULLREP ? 1 : 0)); return 0; } /* DTE */ if (reptype != LMI_FULLREP || error){ //printk(KERN_INFO "RepType=%i != LMI_FULLREP(0) Error=%i\n", // reptype,error); return 0; } stat_len = 3; //printk(KERN_INFO "JUST BEFORE DEV LIST Cnt=%i Cnt=%i\n",i,(i + 2 + stat_len)); WAN_LIST_FOREACH(devle, &card->wandev.dev_head, dev_link){ dev = WAN_DEVLE2DEV(devle); if (!dev || !wan_netif_priv(dev)) continue; chan = wan_netif_priv(dev); chan->newstate=0; } //printk(KERN_INFO "Starting to go through dlcis\n"); init_global_dlci_state(card); while (skb->len >= (i + 2 + stat_len)) { u16 dlci; u8 state = 0; if (skb->data[i] != ((MODE_FR_CCITT) ? LMI_CCITT_PVCSTAT : LMI_PVCSTAT)) { printk(KERN_INFO "%s: Invalid PVCSTAT ID: %x\n", card->devname, skb->data[i]); fr_prot->link_stats.rx_bad_format++; return 1; } i++; if (skb->data[i] != stat_len) { printk(KERN_INFO "%s: Invalid PVCSTAT length: %x\n", card->devname, skb->data[i]); fr_prot->link_stats.rx_bad_format++; return 1; } i++; //printk(KERN_INFO "DLCI TO STATUS starting at I=%i\n",i); dlci = status_to_dlci((skb->data+i), &state); //printk(KERN_INFO "DLCI IS %i State 0x%x\n",dlci,state); dev = find_channel(card,dlci); if (dev){ chan=dev->priv; if (!chan){ fr_prot->link_stats.rx_dropped++; return 1; } chan->newstate = state; }else if (state == PVC_STATE_NEW){ printk(KERN_INFO "%s: New PVC available, DLCI=%u\n", card->devname, dlci); } set_global_dlci_state(card,dlci,state); i += stat_len; } //printk(KERN_INFO "End of dlci report\n"); WAN_LIST_FOREACH(devle, &card->wandev.dev_head, dev_link){ dev = WAN_DEVLE2DEV(devle); if (!dev || !wan_netif_priv(dev)) continue; chan = wan_netif_priv(dev); if (chan->newstate == PVC_STATE_NEW) chan->newstate = PVC_STATE_ACTIVE; chan->newstate |= (chan->dlci_state & ~(PVC_STATE_NEW|PVC_STATE_ACTIVE)); if (chan->dlci_state != chan->newstate) { chan->dlci_state = chan->newstate; fr_log_dlci_active(chan); if ((chan->dlci_state & PVC_STATE_ACTIVE) && card->fe.fe_status == FE_CONNECTED){ chan_set_state(dev,WAN_CONNECTED); } if (!(chan->dlci_state & PVC_STATE_ACTIVE)){ chan_set_state(dev,WAN_DISCONNECTED); } }else{ if (!(chan->dlci_state & PVC_STATE_ACTIVE) && chan->common.state != WAN_DISCONNECTED){ chan_set_state(dev,WAN_DISCONNECTED); } } } /* Next full report after N391 polls */ fr_prot->n391cnt = fr_prot->cfg.n391; return 0; } static void fr_netif(sdla_t *card, struct sk_buff *skb) { fr_hdr *fh = (fr_hdr*)skb->data; u8 *data = skb->data; netdevice_t *dev; u16 dlci; fr_private_area_t *chan=NULL; fr_prot_t *fr_prot = FR_PROT_AREA(card); if (skb->len<4 || fh->ea1){ fr_prot->link_stats.rx_bad_format++; goto fr_rx_error; } dlci = q922_to_dlci(skb->data); if (dlci == LMI_ANSI_DLCI || dlci == LMI_LMI_DLCI) { capture_trace_packet(card,NULL,skb,TRC_INCOMING_FRM); if (data[2] != FR_UI){ goto fr_rx_error; } if (data[3] == LMI_PROTO) { if (fr_lmi_recv(card, skb)) goto fr_rx_error; else { /* No request pending */ fr_prot->state &= ~LINK_STATE_REQUEST; fr_prot->last_rx_poll = jiffies; return; } } printk(KERN_INFO "%s: Received non-LMI frame with LMI DLCI\n",card->devname); fr_prot->link_stats.rx_bad_format++; goto fr_rx_error; } dev = WAN_DEVLE2DEV(WAN_LIST_FIRST(&card->wandev.dev_head)); if (!dev){ printk(KERN_INFO "%s: FR Protocol no dev!\n",card->devname); return; } dev = find_channel(card, dlci); if (!dev) { fr_prot->link_stats.rx_bad_dlci++; goto fr_rx_error; } if ((dev->flags & IFF_UP) == 0) { printk(KERN_INFO "%s: Interface for receive DLCI %d is down\n", card->devname, dlci); fr_prot->link_stats.rx_bad_dlci++; goto fr_rx_error; } chan=(fr_private_area_t*)dev->priv; if (!chan){ printk(KERN_INFO "%s: PVC for received frame's DLCI %d is down\n", card->devname, dlci); fr_prot->link_stats.rx_bad_dlci++; goto fr_rx_error; } if ((chan->dlci_state & PVC_STATE_FECN) != (fh->fecn ? PVC_STATE_FECN : 0)) { chan->rx_FECN++; printk(KERN_INFO "%s: FECN O%s\n", dev->name, fh->fecn ? "N" : "FF"); chan->dlci_state ^= PVC_STATE_FECN; } if ((chan->dlci_state & PVC_STATE_BECN) != (fh->becn ? PVC_STATE_BECN : 0)) { chan->rx_BECN++; printk(KERN_INFO "%s: BECN O%s\n", dev->name, fh->becn ? "N" : "FF"); chan->dlci_state ^= PVC_STATE_BECN; } if (chan->dlci_state & PVC_STATE_BECN){ chan->stats.rx_compressed++; } if( capture_trace_packet(card,chan,skb,TRC_INCOMING_FRM) < 0){ chan->stats.rx_fifo_errors++; } #ifdef CONFIG_PRODUCT_WANPIPE_ANNEXG if (chan->common.usedby == ANNEXG){ if (chan->annexg_dev){ if (IS_FUNC_CALL(lapb_protocol,lapb_rx)){ struct sk_buff *new_skb; skb_pull(skb, 2); new_skb=dev_alloc_skb(skb->len); if (!new_skb){ chan->stats.rx_errors++; card->wandev.stats.rx_dropped++; fr_prot->link_stats.rx_dropped++; printk(KERN_INFO "%s: Annexg: Failed to allocate memory\n", card->devname); return; } new_skb->protocol = htons(ETH_P_X25); new_skb->dev = chan->annexg_dev; memcpy(skb_put(new_skb,skb->len),skb->data,skb->len); #if 0 if (new_skb->len <= 5 && !(new_skb->data[1]&0x01)){ int x; if (new_skb->len == 5 && (new_skb->data[4]&0x01)) goto skip_error; printk(KERN_INFO "%s: ERROR: Rx bad annexg frame len=%i\n", card->devname, new_skb->len); printk(KERN_INFO "Bad Packet : "); for (x=0;xlen;x++){ printk("%X ",new_skb->data[x]); } printk("\n"); printk(KERN_INFO "\n"); chan->stats.rx_dropped++; card->wandev.stats.rx_dropped++; dev_kfree_skb_any(new_skb); return; skip_error: } #endif chan->stats.rx_packets++; chan->stats.rx_bytes += new_skb->len; card->wandev.stats.rx_packets++; card->wandev.stats.rx_bytes += new_skb->len; lapb_protocol.lapb_rx(chan->annexg_dev,new_skb); }else{ chan->stats.rx_errors++; card->wandev.stats.rx_dropped++; fr_prot->link_stats.rx_dropped++; } }else{ chan->stats.rx_errors++; fr_prot->link_stats.rx_dropped++; card->wandev.stats.rx_dropped++; } return; } #endif if (data[2] != FR_UI){ fr_prot->link_stats.rx_bad_format++; chan->stats.rx_errors++; goto fr_rx_error; } if (data[3] == NLPID_IP) { struct sk_buff *new_skb; skb_pull(skb, 4); /* Remove 4-byte header (hdr, UI, NLPID) */ skb->protocol = htons(ETH_P_IP); skb->dev = dev; new_skb=skb_clone(skb,GFP_ATOMIC); if (!new_skb){ chan->stats.rx_errors++; fr_prot->link_stats.rx_dropped++; return; } ++card->wandev.stats.rx_packets; card->wandev.stats.rx_bytes += skb->len; chan->stats.rx_packets++; /* PVC traffic */ chan->stats.rx_bytes += skb->len; netif_rx(new_skb); return; } if (data[3] == NLPID_IPV6) { struct sk_buff *new_skb; skb_pull(skb, 4); /* Remove 4-byte header (hdr, UI, NLPID) */ skb->protocol = htons(ETH_P_IPV6); skb->dev = dev; new_skb=skb_clone(skb,GFP_ATOMIC); if (!new_skb){ chan->stats.rx_errors++; fr_prot->link_stats.rx_dropped++; return; } ++card->wandev.stats.rx_packets; card->wandev.stats.rx_bytes += skb->len; chan->stats.rx_packets++; /* PVC traffic */ chan->stats.rx_bytes += skb->len; netif_rx(new_skb); return; } if (data[3] == FR_PAD && data[4] == NLPID_SNAP && data[5] == FR_PAD && data[6] == FR_PAD && data[7] == FR_PAD && ((data[8]<<8) | data[9]) == ETH_P_ARP) { struct sk_buff *new_skb; skb_pull(skb, 10); skb->protocol = htons(ETH_P_ARP); skb->dev = dev; new_skb=skb_clone(skb,GFP_ATOMIC); if (!new_skb){ chan->stats.rx_errors++; fr_prot->link_stats.rx_dropped++; return; } ++card->wandev.stats.rx_packets; card->wandev.stats.rx_bytes += skb->len; chan->stats.rx_packets++; /* PVC traffic */ chan->stats.rx_bytes += skb->len; netif_rx(new_skb); return; } printk(KERN_INFO "%s: Unusupported protocol %x\n", card->devname, data[3]); fr_prot->link_stats.rx_bad_format++; card->wandev.stats.rx_dropped++; chan->stats.rx_dropped++; return; fr_rx_error: card->wandev.stats.rx_dropped++; return; } /*============================================================================ * Find network device by its channel number. * * We need this critical flag because we change * the dlci_to_dev_map outside the interrupt. * * NOTE: del_if() functions updates this array, it uses * the spin locks to avoid corruption. */ static netdevice_t* find_channel (sdla_t* card, unsigned dlci) { fr_prot_t *fr_prot=FR_PROT_AREA(card); if(dlci > HIGHEST_VALID_DLCI) return NULL; return(fr_prot->dlci_to_dev_map[dlci]); } static void fr_bh (unsigned long card_data) { #define card ((sdla_t*)card_data) fr_prot_t *fr_prot = FR_PROT_AREA(card); struct sk_buff *skb; unsigned long timeout=jiffies; if (!skb_queue_len(&fr_prot->rx_used)){ clear_bit(0, &fr_prot->tq_working); return; } while ((skb=skb_dequeue(&fr_prot->rx_used)) != NULL){ fr_netif(card,skb); skb->data = skb->head+16; skb_trim(skb,0); skb_queue_tail(&fr_prot->rx_free,skb); if ((jiffies-timeout) >= 4){ printk(KERN_INFO "%s: FR BH Kicking out, bh timeout 40ms\n", card->devname); break; } } clear_bit(0, &fr_prot->tq_working); return; #undef card } static int capture_trace_packet (sdla_t *card,fr_private_area_t*chan,struct sk_buff *skb,char direction) { fr_prot_t *fr_prot = FR_PROT_AREA(card); if (!chan){ goto trace_protocol; } if (test_bit(0,&chan->tracing_enabled)){ if ((jiffies-chan->trace_timeout) > MAX_TRACE_TIMEOUT){ printk(KERN_INFO "%s: %s: Disabling DLCI=%i trace, timeout!\n", card->devname,chan->if_name,chan->dlci); clear_bit(0,&chan->tracing_enabled); return 0; } if (skb_queue_len(&chan->trace_queue) < chan->max_trace_queue){ struct sk_buff *new_skb; new_skb=dev_alloc_skb(skb->len+sizeof(fr_trc_el_t)+chan->hdr_len); if (new_skb){ fr_trc_el_t *trc_el = (fr_trc_el_t*)skb_put(new_skb,sizeof(fr_trc_el_t)); trc_el->attr = direction; trc_el->tmstamp = (unsigned short)(jiffies%0xFFFF); trc_el->length = skb->len; if (direction == TRC_OUTGOING_FRM){ trc_el->length += chan->hdr_len; memcpy(skb_put(new_skb,chan->hdr_len),chan->header,chan->hdr_len); } memcpy(skb_put(new_skb,skb->len),skb->data,skb->len); skb_queue_tail(&chan->trace_queue,new_skb); }else{ //ALEX //printk(KERN_INFO "%s: %s: %i: Failed allocate memory for new packets in trace queue!\n", // card->devname, chan->if_name, chan->dlci); return -ENOMEM; } }else{ //ALEX //printk(KERN_INFO "%s: %s: %i: Too many packets in trace queue (%i)!\n", // card->devname, chan->if_name, chan->dlci, // skb_queue_len(&chan->trace_queue)); return -ENOBUFS; } } return 0; trace_protocol: if (test_bit(0,&fr_prot->tracing_enabled)){ if ((jiffies-fr_prot->trace_timeout) > MAX_TRACE_TIMEOUT){ printk(KERN_INFO "%s: Disabling LMI trace, timeout!\n", card->devname); clear_bit(0,&fr_prot->tracing_enabled); return 0; } if (skb_queue_len(&fr_prot->trace_queue) < fr_prot->max_trace_queue){ struct sk_buff *new_skb; new_skb=dev_alloc_skb(skb->len+sizeof(fr_trc_el_t)); if (new_skb){ fr_trc_el_t *trc_el = (fr_trc_el_t*)skb_put(new_skb,sizeof(fr_trc_el_t)); trc_el->attr = direction; trc_el->tmstamp = (unsigned short)(jiffies%0xFFFF); trc_el->length = skb->len; memcpy(skb_put(new_skb,skb->len),skb->data,skb->len); skb_queue_tail(&fr_prot->trace_queue,new_skb); }else{ //ALEX printk(KERN_INFO "%s: Failed to allocate memory for new packets in trace queue!\n", card->devname); return -ENOMEM; } }else{ //ALEX printk(KERN_INFO "%s: Too many packets in trace queue (%i)!\n", card->devname, skb_queue_len(&fr_prot->trace_queue)); return -ENOBUFS; } } return 0; } /* SNMP ****************************************************************************** * fr_snmp_data() * * Description: Save snmp request and parameters in private structure, enable * TIMER interrupt, put current process in sleep. * Arguments: * Returns: ****************************************************************************** */ #define FRDLCMIIFINDEX 3 #define FRDLCMISTATE 4 #define FRDLCMIADDRESS 5 #define FRDLCMIADDRESSLEN 6 #define FRDLCMIPOLLINGINTERVAL 7 #define FRDLCMIFULLENQUIRYINTERVAL 8 #define FRDLCMIERRORTHRESHOLD 9 #define FRDLCMIMONITOREDEVENTS 10 #define FRDLCMIMAXSUPPORTEDVCS 11 #define FRDLCMIMULTICAST 12 #define FRDLCMISTATUS 13 #define FRDLCMIROWSTATUS 14 #define FRCIRCUITIFINDEX 17 #define FRCIRCUITDLCI 18 #define FRCIRCUITSTATE 19 #define FRCIRCUITRECEIVEDFECNS 20 #define FRCIRCUITRECEIVEDBECNS 21 #define FRCIRCUITSENTFRAMES 22 #define FRCIRCUITSENTOCTETS 23 #define FRCIRCUITRECEIVEDFRAMES 24 #define FRCIRCUITRECEIVEDOCTETS 25 #define FRCIRCUITCREATIONTIME 26 #define FRCIRCUITLASTTIMECHANGE 27 #define FRCIRCUITCOMMITTEDBURST 28 #define FRCIRCUITEXCESSBURST 29 #define FRCIRCUITTHROUGHPUT 30 #define FRCIRCUITMULTICAST 31 #define FRCIRCUITTYPE 32 #define FRCIRCUITDISCARDS 33 #define FRCIRCUITRECEIVEDDES 34 #define FRCIRCUITSENTDES 35 #define FRCIRCUITLOGICALIFINDEX 36 #define FRCIRCUITROWSTATUS 37 #define FRERRIFINDEX 40 #define FRERRTYPE 41 #define FRERRDATA 42 #define FRERRTIME 43 #define FRERRFAULTS 44 #define FRERRFAULTTIME 45 #define FRTRAPSTATE 46 #define FRTRAPMAXRATE 47 static int fr_snmp_data(sdla_t* card, netdevice_t *dev, void* data) { fr_channel_t* chan = NULL; wanpipe_snmp_t* snmp = NULL; struct timeval tv; fr_prot_t *fr_prot; if (dev == NULL || dev->priv == NULL) return -EFAULT; chan = (fr_channel_t*)dev->priv; fr_prot=FR_PROT_AREA(card); /* Update device statistics */ if (card->wandev.update) { int rslt = 0; fr_prot->update_dlci = chan; rslt = card->wandev.update(&card->wandev); if(rslt) { return (rslt) ? (-EBUSY) : (-EINVAL); } } snmp = (wanpipe_snmp_t*)data; switch(snmp->snmp_magic){ /***** Data Link Connection Management Interface ****/ case FRDLCMIIFINDEX: break; case FRDLCMISTATE: snmp->snmp_val = (card->wandev.signalling == WANOPT_FR_ANSI) ? SNMP_FR_ANSIT1617D : (card->wandev.signalling == WANOPT_FR_Q933) ? SNMP_FR_ITUT933A : (card->wandev.signalling == WANOPT_FR_LMI) ? SNMP_FR_LMIREV: SNMP_FR_NOLMICONF; break; case FRDLCMIADDRESS: snmp->snmp_val = SNMP_FR_Q922; break; case FRDLCMIADDRESSLEN: snmp->snmp_val = SNMP_FR_4BYTE_ADDR; break; case FRDLCMIPOLLINGINTERVAL: snmp->snmp_val = fr_prot->cfg.t391; break; case FRDLCMIFULLENQUIRYINTERVAL: snmp->snmp_val = fr_prot->cfg.n391; break; case FRDLCMIERRORTHRESHOLD: snmp->snmp_val = fr_prot->cfg.n392; break; case FRDLCMIMONITOREDEVENTS: snmp->snmp_val = fr_prot->cfg.n393; break; case FRDLCMIMAXSUPPORTEDVCS: snmp->snmp_val = HIGHEST_VALID_DLCI; break; case FRDLCMIMULTICAST: snmp->snmp_val = SNMP_FR_NONBROADCAST; break; case FRDLCMISTATUS: /* FIXME */ snmp->snmp_val = SNMP_FR_RUNNING; break; case FRDLCMIROWSTATUS: /* FIXME */ snmp->snmp_val = 0; break; /****************** Circuit Table *******************/ case FRCIRCUITIFINDEX: break; case FRCIRCUITDLCI: snmp->snmp_val = chan->dlci; break; case FRCIRCUITSTATE: snmp->snmp_val = (chan->common.state == WAN_CONNECTED) ? SNMP_FR_ACTIVE : SNMP_FR_INACTIVE; break; case FRCIRCUITRECEIVEDFECNS: snmp->snmp_val = chan->rx_FECN; break; case FRCIRCUITRECEIVEDBECNS: snmp->snmp_val = chan->rx_BECN; break; case FRCIRCUITSENTFRAMES: snmp->snmp_val = chan->stats.tx_packets; break; case FRCIRCUITSENTOCTETS: snmp->snmp_val = chan->stats.tx_bytes; break; case FRCIRCUITRECEIVEDFRAMES: snmp->snmp_val = chan->stats.rx_packets; break; case FRCIRCUITRECEIVEDOCTETS: snmp->snmp_val = chan->stats.rx_bytes; break; case FRCIRCUITCREATIONTIME: do_gettimeofday( &tv ); snmp->snmp_val = tv.tv_sec - card->u.c.router_start_time; break; case FRCIRCUITLASTTIMECHANGE: do_gettimeofday( &tv ); snmp->snmp_val = tv.tv_sec - chan->router_last_change; break; case FRCIRCUITCOMMITTEDBURST: snmp->snmp_val = (unsigned long)chan->bc; break; case FRCIRCUITEXCESSBURST: snmp->snmp_val = (unsigned long)chan->be; break; case FRCIRCUITTHROUGHPUT: /* FIXME */ snmp->snmp_val = (unsigned long)0; break; case FRCIRCUITMULTICAST: snmp->snmp_val = (chan->mc) ? SNMP_FR_ONEWAY : SNMP_FR_UNICAST; break; case FRCIRCUITTYPE: snmp->snmp_val = chan->dlci_type; break; case FRCIRCUITDISCARDS: snmp->snmp_val = chan->stats.rx_errors; break; case FRCIRCUITRECEIVEDDES: snmp->snmp_val = chan->rx_DE_set; break; case FRCIRCUITSENTDES: snmp->snmp_val = chan->tx_DE_set; break; case FRCIRCUITLOGICALIFINDEX: /* FIXME */ snmp->snmp_val = 0; break; case FRCIRCUITROWSTATUS: /* FIXME */ snmp->snmp_val = 0; break; /****************** Errort Table *******************/ case FRERRIFINDEX: break; case FRERRTYPE: /* FIXME */ snmp->snmp_val = chan->err_type; break; case FRERRDATA: /* FIXME */ strcpy((void*)snmp->snmp_data, chan->err_data); break; case FRERRTIME: /* FIXME */ snmp->snmp_val = chan->err_time; break; case FRERRFAULTS: /* FIXME */ snmp->snmp_val = chan->err_faults; break; case FRERRFAULTTIME: /* FIXME */ snmp->snmp_val = (unsigned long)0; break; /************ Frame Relay Trap Control **************/ case FRTRAPSTATE: snmp->snmp_val = chan->trap_state; break; case FRTRAPMAXRATE: snmp->snmp_val = chan->trap_max_rate; break; default: return -EAFNOSUPPORT; } return 0; } #ifdef CONFIG_PRODUCT_WANPIPE_ANNEXG static int bind_annexg(netdevice_t *dev, netdevice_t *annexg_dev) { unsigned long smp_flags=0; fr_channel_t* chan = dev->priv; sdla_t *card = chan->card; if (!chan) return -EINVAL; if (chan->common.usedby != ANNEXG) return -EPROTONOSUPPORT; if (chan->annexg_dev) return -EBUSY; spin_lock_irqsave(&card->wandev.lock,smp_flags); chan->annexg_dev = annexg_dev; spin_unlock_irqrestore(&card->wandev.lock,smp_flags); return 0; } static netdevice_t * un_bind_annexg(wan_device_t *wandev, netdevice_t *annexg_dev) { struct wan_dev_le *devle; netdevice_t *dev; unsigned long smp_flags=0; sdla_t *card = wandev->private; WAN_LIST_FOREACH(devle, &card->wandev.dev_head, dev_link){ fr_channel_t *chan; dev = WAN_DEVLE2DEV(devle); if (!dev || !wan_netif_priv(dev)) continue; chan = wan_netif_priv(dev); if (!chan->annexg_dev || chan->common.usedby != ANNEXG) continue; if (chan->annexg_dev == annexg_dev){ spin_lock_irqsave(&card->wandev.lock,smp_flags); chan->annexg_dev = NULL; spin_unlock_irqrestore(&card->wandev.lock,smp_flags); return dev; } } return NULL; } static void get_active_inactive(wan_device_t *wandev, netdevice_t *dev, void *wp_stats_ptr) { fr_channel_t* chan = dev->priv; wp_stack_stats_t *wp_stats = (wp_stack_stats_t *)wp_stats_ptr; if (chan->common.usedby == ANNEXG && chan->annexg_dev){ if (IS_FUNC_CALL(lapb_protocol,lapb_get_active_inactive)){ lapb_protocol.lapb_get_active_inactive(chan->annexg_dev,wp_stats); } } if (chan->common.state == WAN_CONNECTED){ wp_stats->fr_active++; }else{ wp_stats->fr_inactive++; } } static int get_map(wan_device_t *wandev, netdevice_t *dev, struct seq_file* m, int *stop_cnt) { fr_channel_t* chan = dev->priv; if (!(dev->flags&IFF_UP)){ return m->count; } if (chan->common.usedby == ANNEXG && chan->annexg_dev){ if (IS_FUNC_CALL(lapb_protocol,lapb_get_map)){ return lapb_protocol.lapb_get_map(chan->annexg_dev, m); } } PROC_ADD_LINE(m, "%15s:%s:%c:%s:%c\n", chan->label, wandev->name,(wandev->state == WAN_CONNECTED) ? '*' : ' ', dev->name,(chan->common.state == WAN_CONNECTED) ? '*' : ' '); return m->count; } #endif #ifdef _DBG_ANNEXG_ #undef DBG_LAPB #define DBG_X25 static int g_ps_cnt=0; static unsigned int g_skb_ptr=0; void check_x25_pr_ps_cnt(sdla_t *card,struct sk_buff *skb) { int ps_cnt; int lcn; #ifdef DBG_LAPB if (skb->len >= 2 && !test_bit(0,&skb->data[1])){ ps_cnt = (skb->data[1]&0x0F)>>1; if (ps_cnt == g_ps_cnt){ printk(KERN_INFO "%s: Sending Len=%i Ps=%i Old=%i : New ptr=%u Prev=%u\n", card->devname,skb->len,ps_cnt,g_ps_cnt, (u32)skb,g_skb_ptr); } g_ps_cnt=ps_cnt; g_skb_ptr=(u32)skb; } #endif #ifdef DBG_X25 if (skb->len >= 5 && !test_bit(0,&skb->data[1])){ if (!test_bit(0,&skb->data[4])){ lcn=((skb->data[2]&0x0F)<<8) | skb->data[3]; if (lcn!=2) return; ps_cnt = (skb->data[4]&0x0F)>>1; if (ps_cnt == g_ps_cnt){ printk(KERN_INFO "%s: Sending Lcn=%i Len=%i Ps=%i Old=%i : New ptr=%u Prev=%u\n", card->devname,lcn,skb->len,ps_cnt,g_ps_cnt, (u32)skb,g_skb_ptr); } g_ps_cnt=ps_cnt; g_skb_ptr=(u32)skb; } } #endif return; } #endif /****** End ****************************************************************/