📄 sdla_chdlc.c
字号:
#endif /* Get Multicast Information */ chdlc_priv_area->mc = conf->mc; /* 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); sprintf(dev->name, "%s", card->u.c.if_name);#endif dev->init = &if_init; dev->priv = chdlc_priv_area; /* Initialize the polling task routine */#ifndef LINUX_2_4 chdlc_priv_area->poll_task.next = NULL;#endif chdlc_priv_area->poll_task.sync=0; chdlc_priv_area->poll_task.routine = (void*)(void*)chdlc_poll; chdlc_priv_area->poll_task.data = dev; /* Initialize the polling delay timer */ init_timer(&chdlc_priv_area->poll_delay_timer); chdlc_priv_area->poll_delay_timer.data = (unsigned long)dev; chdlc_priv_area->poll_delay_timer.function = chdlc_poll_delay; printk(KERN_INFO "\n"); 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 /* Initialize device driver entry points */ dev->open = &if_open; dev->stop = &if_close; dev->hard_header = &if_header; dev->rebuild_header = &if_rebuild_hdr; dev->hard_start_xmit = &if_send; dev->get_stats = &if_stats;#ifdef LINUX_2_4 dev->tx_timeout = &if_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT;#endif /* Initialize media-specific parameters */ dev->flags |= IFF_POINTOPOINT; dev->flags |= IFF_NOARP; /* Enable Mulitcasting if user selected */ if (chdlc_priv_area->mc == WANOPT_YES){ dev->flags |= IFF_MULTICAST; } #ifdef LINUX_2_0 dev->family = AF_INET;#endif if (chdlc_priv_area->true_if_encoding){#if defined(LINUX_2_1) || defined(LINUX_2_4) dev->type = ARPHRD_HDLC; /* This breaks the tcpdump */#else dev->type = ARPHRD_PPP;#endif }else{ dev->type = ARPHRD_PPP; } dev->mtu = card->wandev.mtu; /* for API usage, add the API header size to the requested MTU size */ if(card->u.c.usedby == API) { dev->mtu += sizeof(api_tx_hdr_t); } dev->hard_header_len = CHDLC_HDR_LEN; /* 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 too low packets will not be retransmitted * by stack. */ 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;}/*============================================================================ * 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; int err = 0; /* Only one open per interface is allowed */ if (is_dev_running(dev)) return -EBUSY;#if defined(LINUX_2_1) || defined(LINUX_2_4) /* Initialize the task queue */ chdlc_priv_area->tq_working=0;#ifndef LINUX_2_4 chdlc_priv_area->common.wanpipe_task.next = NULL;#endif chdlc_priv_area->common.wanpipe_task.sync = 0; chdlc_priv_area->common.wanpipe_task.routine = (void *)(void *)chdlc_bh; chdlc_priv_area->common.wanpipe_task.data = dev; /* Allocate and initialize BH circular buffer */ /* Add 1 to MAX_BH_BUFF so we don't have test with (MAX_BH_BUFF-1) */ chdlc_priv_area->bh_head = kmalloc((sizeof(bh_data_t)*(MAX_BH_BUFF+1)),GFP_ATOMIC); memset(chdlc_priv_area->bh_head,0,(sizeof(bh_data_t)*(MAX_BH_BUFF+1))); atomic_set(&chdlc_priv_area->bh_buff_used, 0);#endif 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); /* TTY is configured during wanpipe_set_termios * call, not here */ if (card->tty_opt) return err; set_bit(0,&chdlc_priv_area->config_chdlc); chdlc_priv_area->config_chdlc_timeout=jiffies; del_timer(&chdlc_priv_area->poll_delay_timer); /* Start the CHDLC configuration after 1sec delay. * This will give the interface initilization time * to finish its configuration */ chdlc_priv_area->poll_delay_timer.expires=jiffies+HZ; add_timer(&chdlc_priv_area->poll_delay_timer); return err;}/*============================================================================ * 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;#if defined(LINUX_2_1) || defined(LINUX_2_4) if (chdlc_priv_area->bh_head){ int i; struct sk_buff *skb; for (i=0; i<(MAX_BH_BUFF+1); i++){ skb = ((bh_data_t *)&chdlc_priv_area->bh_head[i])->skb; if (skb != NULL){ wan_dev_kfree_skb(skb, FREE_READ); } } kfree(chdlc_priv_area->bh_head); chdlc_priv_area->bh_head=NULL; }#endif stop_net_queue(dev);#ifndef LINUX_2_4 dev->start=0;#endif wanpipe_close(card); del_timer(&chdlc_priv_area->poll_delay_timer); return 0;}static void disable_comm (sdla_t *card){ SHARED_MEMORY_INFO_STRUCT *flags = card->u.c.flags; if (card->u.c.comm_enabled){ chdlc_disable_comm_shutdown (card); }else{ flags->interrupt_info_struct.interrupt_permission = 0; }#if defined(LINUX_2_4) || defined(LINUX_2_1) if (!tty_init_cnt) return; if (card->tty_opt){ struct serial_state * state; if (!(--tty_init_cnt)){ int e1,e2; *serial_driver.refcount=0; if ((e1 = tty_unregister_driver(&serial_driver))) printk("SERIAL: failed to unregister serial driver (%d)\n", e1); if ((e2 = tty_unregister_driver(&callout_driver))) printk("SERIAL: failed to unregister callout driver (%d)\n", e2); printk(KERN_INFO "%s: Unregistering TTY Driver, Major %i\n", card->devname,WAN_TTY_MAJOR); } card->tty=NULL; tty_card_map[card->tty_minor]=NULL; state = &rs_table[card->tty_minor]; memset(state,0,sizeof(state)); }#endif return;}/*============================================================================ * Build media header. * * The trick here is to put packet type (Ethertype) into 'protocol' field of * the socket buffer, so that we don't forget it. If packet type is not * supported, set skb->protocol to 0 and discard packet later. * * Return: media header length. */static int if_header (struct sk_buff* skb, netdevice_t* dev, unsigned short type, void* daddr, void* saddr, unsigned len){ skb->protocol = htons(type); return CHDLC_HDR_LEN;}#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/*============================================================================ * Re-build media header. * * Return: 1 physical address resolved. * 0 physical address not resolved */#if defined(LINUX_2_1) || defined(LINUX_2_4)static int if_rebuild_hdr (struct sk_buff *skb){ return 1;}#elsestatic int if_rebuild_hdr (void* hdr, netdevice_t* dev, unsigned long raddr, struct sk_buff* skb){ return 1;}#endif/*============================================================================ * Send a packet on a network interface. * o set tbusy flag (marks start of the transmission) to block a timer-based * transmit from overlapping. * o 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: 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 timeout !\n", card->devname); /* unbusy the interface */ clear_bit(0,&dev->tbusy); }#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; } /* check to see if the source IP address is a broadcast or */ /* multicast IP address */ if(chk_bcast_mcast_addr(card, dev, skb)){ ++card->wandev.stats.tx_dropped; wan_dev_kfree_skb(skb,FREE_WRITE); 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", card->wandev.name,card->wandev.critical); ++card->wandev.stats.tx_dropped; start_net_queue(dev); goto if_send_exit_crit; } if(card->u.c.state != WAN_CONNECTED){ ++card->wandev.stats.tx_dropped; start_net_queue(dev); }else if(!skb->protocol){ ++card->wandev.stats.tx_errors; start_net_queue(dev); }else { void* data = skb->data; unsigned len = skb->len; unsigned char attr; /* If it's an API packet pull off the API * header. Also check that the packet size * is larger than the API header */ if (card->u.c.usedby == API){ api_tx_hdr_t* api_tx_hdr; /* discard the frame if we are configured for */ /* 'receive only' mode or if there is no data */ if (card->u.c.receive_only || (len <= sizeof(api_tx_hdr_t))) { ++card->wandev.stats.tx_dropped; start_net_queue(dev); goto if_send_exit_crit; } api_tx_hdr = (api_tx_hdr_t *)data; attr = api_tx_hdr->attr; data += sizeof(api_tx_hdr_t); len -= sizeof(api_tx_hdr_t);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -