📄 wanpipe_multppp.c
字号:
/*============================================================================ * 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; netdevice_t* dev; volatile chdlc_private_area_t* chdlc_priv_area; SHARED_MEMORY_INFO_STRUCT *flags; unsigned long timeout; /* sanity checks */ if((wandev == NULL) || (wandev->private == NULL)) return -EFAULT; if(wandev->state == WAN_UNCONFIGURED) return -ENODEV; /* more sanity checks */ if(!card->u.c.flags) return -ENODEV; if((dev=card->wandev.dev) == NULL) return -ENODEV; if((chdlc_priv_area=dev->priv) == NULL) return -ENODEV; flags = card->u.c.flags; if(chdlc_priv_area->update_comms_stats){ return -EAGAIN; } /* we will need 2 timer interrupts to complete the */ /* reading of the statistics */ chdlc_priv_area->update_comms_stats = 2; flags->interrupt_info_struct.interrupt_permission |= APP_INT_ON_TIMER; chdlc_priv_area->timer_int_enabled = TMR_INT_ENABLED_UPDATE; /* wait a maximum of 1 second for the statistics to be updated */ timeout = jiffies; for(;;) { if(chdlc_priv_area->update_comms_stats == 0) break; if ((jiffies - timeout) > (1 * HZ)){ chdlc_priv_area->update_comms_stats = 0; chdlc_priv_area->timer_int_enabled &= ~TMR_INT_ENABLED_UPDATE; return -EAGAIN; } } return 0;}/*============================================================================ * Create new logical channel. * This routine is called by the router when ROUTER_IFNEW IOCTL is being * handled. * o parse media- and hardware-specific configuration * o make sure that a new channel can be created * o allocate resources, if necessary * o prepare network device structure for registaration. * * Return: 0 o.k. * < 0 failure (channel will not be created) */static int new_if (wan_device_t* wandev, netdevice_t* pdev, wanif_conf_t* conf){ struct ppp_device *pppdev = (struct ppp_device *)pdev; netdevice_t *dev=NULL; struct sppp *sp; sdla_t* card = wandev->private; chdlc_private_area_t* chdlc_priv_area; if ((conf->name[0] == '\0') || (strlen(conf->name) > WAN_IFNAME_SZ)) { printk(KERN_INFO "%s: invalid interface name!\n", card->devname); return -EINVAL; } /* allocate and initialize private data */ chdlc_priv_area = kmalloc(sizeof(chdlc_private_area_t), GFP_KERNEL); if(chdlc_priv_area == NULL) return -ENOMEM; memset(chdlc_priv_area, 0, sizeof(chdlc_private_area_t)); chdlc_priv_area->card = card; /* initialize data */ strcpy(card->u.c.if_name, conf->name); if(card->wandev.new_if_cnt > 0) { kfree(chdlc_priv_area); return -EEXIST; } card->wandev.new_if_cnt++; chdlc_priv_area->TracingEnabled = 0; //We don't need this any more chdlc_priv_area->route_status = NO_ROUTE; chdlc_priv_area->route_removed = 0; printk(KERN_INFO "%s: Firmware running in HDLC STREAMING Mode\n", wandev->name); /* Setup wanpipe as a router (WANPIPE) or as an API */ if( strcmp(conf->usedby, "WANPIPE") == 0) { printk(KERN_INFO "%s: Driver running in WANPIPE mode!\n", wandev->name); card->u.c.usedby = WANPIPE; } else { printk(KERN_INFO "%s: API Mode is not supported for SyncPPP!\n", wandev->name); kfree(chdlc_priv_area); return -EINVAL; } /* Get Multicast Information */ chdlc_priv_area->mc = conf->mc; chdlc_priv_area->if_ptr = pppdev; /* prepare network device data space for registration */#ifdef LINUX_2_4 strcpy(dev->name,card->u.c.if_name);#else dev->name = (char *)kmalloc(strlen(card->u.c.if_name) + 2, GFP_KERNEL); if(dev->name == NULL) { kfree(chdlc_priv_area); return -ENOMEM; } sprintf(dev->name, "%s", card->u.c.if_name);#endif /* Attach PPP protocol layer to pppdev * The sppp_attach() will initilize the dev structure * and setup ppp layer protocols. * All we have to do is to bind in: * if_open(), if_close(), if_send() and get_stats() functions. */ sppp_attach(pppdev);#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,16) dev = pppdev->dev;#else dev = &pppdev->dev;#endif sp = &pppdev->sppp; /* Enable PPP Debugging */ // FIXME Fix this up somehow //sp->pp_flags |= PP_DEBUG; sp->pp_flags &= ~PP_CISCO; dev->init = &if_init; dev->priv = chdlc_priv_area; return 0;}/*============================================================================ * Delete logical channel. */static int del_if (wan_device_t* wandev, netdevice_t* dev){ chdlc_private_area_t *chdlc_priv_area = dev->priv; sdla_t *card = chdlc_priv_area->card; unsigned long smp_lock; /* Detach the PPP layer */ printk(KERN_INFO "%s: Detaching SyncPPP Module from %s\n", wandev->name,dev->name); lock_adapter_irq(&wandev->lock,&smp_lock); sppp_detach(dev); chdlc_priv_area->if_ptr=NULL; chdlc_set_intr_mode(card, 0); if (card->u.c.comm_enabled) chdlc_comm_disable(card); unlock_adapter_irq(&wandev->lock,&smp_lock); port_set_state(card, WAN_DISCONNECTED); return 0;}/****** Network Device Interface ********************************************//*============================================================================ * Initialize Linux network interface. * * This routine is called only once for each interface, during Linux network * interface registration. Returning anything but zero will fail interface * registration. */static int if_init (netdevice_t* dev) { chdlc_private_area_t* chdlc_priv_area = dev->priv; sdla_t* card = chdlc_priv_area->card; wan_device_t* wandev = &card->wandev;#ifdef LINUX_2_0 int i;#endif /* 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;#ifdef LINUX_2_4 dev->tx_timeout = &if_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT;#endif#ifdef LINUX_2_0 dev->family = AF_INET;#endif /* Initialize hardware parameters */ dev->irq = wandev->irq; dev->dma = wandev->dma; dev->base_addr = wandev->ioport; dev->mem_start = wandev->maddr; dev->mem_end = wandev->maddr + wandev->msize - 1; /* Set transmit buffer queue length * If we over fill this queue the packets will * be droped by the kernel. * sppp_attach() sets this to 10, but * 100 will give us more room at low speeds. */ dev->tx_queue_len = 100; /* Initialize socket buffers */#if !defined(LINUX_2_1) && !defined(LINUX_2_4) for (i = 0; i < DEV_NUMBUFFS; ++i) skb_queue_head_init(&dev->buffs[i]);#endif return 0;}#ifdef LINUX_2_4/*============================================================================ * Handle transmit timeout event from netif watchdog */static void if_tx_timeout (netdevice_t *dev){ chdlc_private_area_t* chan = dev->priv; sdla_t *card = chan->card; /* If our device stays busy for at least 5 seconds then we will * kick start the device by making dev->tbusy = 0. We expect * that our device never stays busy more than 5 seconds. So this * is only used as a last resort. */ ++card->wandev.stats.collisions; printk (KERN_INFO "%s: Transmit timed out on %s\n", card->devname,dev->name); netif_wake_queue (dev);}#endif/*============================================================================ * 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){ chdlc_private_area_t* chdlc_priv_area = dev->priv; sdla_t* card = chdlc_priv_area->card; struct timeval tv; SHARED_MEMORY_INFO_STRUCT *flags = card->u.c.flags; /* Only one open per interface is allowed */#ifdef LINUX_2_4 if (netif_running(dev)) return -EBUSY;#else if (dev->start) return -EBUSY; /* only one open is allowed */#endif /* Start PPP Layer */ if (sppp_open(dev)){ return -EIO; } do_gettimeofday(&tv); chdlc_priv_area->router_start_time = tv.tv_sec; #ifdef LINUX_2_4 netif_start_queue(dev);#else dev->interrupt = 0; dev->tbusy = 0; dev->start = 1;#endif wanpipe_open(card); chdlc_priv_area->timer_int_enabled |= TMR_INT_ENABLED_CONFIG; flags->interrupt_info_struct.interrupt_permission |= APP_INT_ON_TIMER; return 0;}/*============================================================================ * Close network interface. * o if this is the last close, then disable communications and interrupts. * o reset flags. */static int if_close (netdevice_t* dev){ chdlc_private_area_t* chdlc_priv_area = dev->priv; sdla_t* card = chdlc_priv_area->card; /* Stop the PPP Layer */ sppp_close(dev); stop_net_queue(dev);#ifndef LINUX_2_4 dev->start=0;#endif wanpipe_close(card); return 0;}/*============================================================================ * Send a packet on a network interface. * o set tbusy flag (marks start of the transmission) to block a timer-based * transmit from overlapping. * o check link state. If link is not up, then drop the packet. * o execute adapter send command. * o free socket buffer * * Return: 0 complete (socket buffer must be freed) * non-0 packet may be re-transmitted (tbusy must be set) * * Notes: * 1. This routine is called either by the protocol stack or by the "net * bottom half" (with interrupts enabled). * 2. Setting tbusy flag will inhibit further transmit requests from the * protocol stack and can be used for flow control with protocol layer. */static int if_send (struct sk_buff* skb, netdevice_t* dev){ chdlc_private_area_t *chdlc_priv_area = dev->priv; sdla_t *card = chdlc_priv_area->card; SHARED_MEMORY_INFO_STRUCT *flags = card->u.c.flags; INTERRUPT_INFORMATION_STRUCT *chdlc_int = &flags->interrupt_info_struct; int udp_type = 0; unsigned long smp_flags; int err=0;#ifdef LINUX_2_4 netif_stop_queue(dev);#endif if (skb == NULL){ /* If we get here, some higher layer thinks we've missed an * tx-done interrupt. */ printk(KERN_INFO "%s: Received NULL skb buffer! interface %s got kicked!\n", card->devname, dev->name); wake_net_dev(dev); return 0; }#ifndef LINUX_2_4 if (dev->tbusy){ /* If our device stays busy for at least 5 seconds then we will * kick start the device by making dev->tbusy = 0. We expect * that our device never stays busy more than 5 seconds. So this * is only used as a last resort. */ ++card->wandev.stats.collisions; if((jiffies - chdlc_priv_area->tick_counter) < (5 * HZ)) { return 1; } printk (KERN_INFO "%s: Transmit (tbusy) timeout !\n", card->devname); /* unbusy the interface */ dev->tbusy = 0; }#endif if (ntohs(skb->protocol) != htons(PVC_PROT)){ /* check the udp packet type */ udp_type = udp_pkt_type(skb, card); if (udp_type == UDP_CPIPE_TYPE){ if(store_udp_mgmt_pkt(UDP_PKT_FRM_STACK, card, skb, dev, chdlc_priv_area)){ chdlc_int->interrupt_permission |= APP_INT_ON_TIMER; } start_net_queue(dev); return 0; } } /* Lock the 508 Card: SMP is supported */ if(card->hw.type != SDLA_S514){ s508_lock(card,&smp_flags); } if (test_and_set_bit(SEND_CRIT, (void*)&card->wandev.critical)){ printk(KERN_INFO "%s: Critical in if_send: %lx\n",
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -