📄 sdla_chdlc.c
字号:
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, struct net_device* dev, wanif_conf_t* conf){ 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; chdlc_priv_area->route_status = NO_ROUTE; chdlc_priv_area->route_removed = 0; /* Setup protocol options */ card->u.c.protocol_options = 0; if (conf->ignore_dcd == WANOPT_YES){ card->u.c.protocol_options |= IGNORE_DCD_FOR_LINK_STAT; } if (conf->ignore_cts == WANOPT_YES){ card->u.c.protocol_options |= IGNORE_CTS_FOR_LINK_STAT; } if (conf->ignore_keepalive == WANOPT_YES) { card->u.c.protocol_options |= IGNORE_KPALV_FOR_LINK_STAT; card->u.c.kpalv_tx = MIN_Tx_KPALV_TIMER; card->u.c.kpalv_rx = MIN_Rx_KPALV_TIMER; card->u.c.kpalv_err = MIN_KPALV_ERR_TOL; } else { /* Do not ignore keepalives */ card->u.c.kpalv_tx = (conf->keepalive_tx_tmr - MIN_Tx_KPALV_TIMER) >= 0 ? min (conf->keepalive_tx_tmr, MAX_Tx_KPALV_TIMER) : DEFAULT_Tx_KPALV_TIMER; card->u.c.kpalv_rx = (conf->keepalive_rx_tmr - MIN_Rx_KPALV_TIMER) >= 0 ? min (conf->keepalive_rx_tmr, MAX_Rx_KPALV_TIMER) : DEFAULT_Rx_KPALV_TIMER; card->u.c.kpalv_err = (conf->keepalive_err_margin - MIN_KPALV_ERR_TOL) >= 0 ? min (conf->keepalive_err_margin, MAX_KPALV_ERR_TOL) : DEFAULT_KPALV_ERR_TOL; } /* Setup slarp timer to control delay between slarps */ card->u.c.slarp_timer = (conf->slarp_timer - MIN_SLARP_REQ_TIMER) >=0 ? min (conf->slarp_timer, MAX_SLARP_REQ_TIMER) : DEFAULT_SLARP_REQ_TIMER; /* If HDLC_STRAMING is enabled then IGNORE DCD, CTS and KEEPALIVES * are automatically ignored */ if (conf->hdlc_streaming == WANOPT_YES) { printk(KERN_INFO "%s: Enabling HDLC STREAMING Mode\n", wandev->name); card->u.c.protocol_options = HDLC_STREAMING_MODE; } /* Setup wanpipe as a router (WANPIPE) or as an API */ if( strcmp(conf->usedby, "WANPIPE") == 0) { printk(KERN_INFO "%s: Running in WANPIPE mode !\n",wandev->name); card->u.c.usedby = WANPIPE; } else if( strcmp(conf->usedby, "API") == 0){#ifdef CHDLC_API card->u.c.usedby = API; printk(KERN_INFO "%s: Running in API mode !\n",wandev->name);#else printk(KERN_INFO "%s: API Mode is not supported!\n", wandev->name); printk(KERN_INFO "%s: Chdlc API patch can be obtained from Sangoma Tech.\n", wandev->name); kfree(chdlc_priv_area); return -EINVAL;#endif } /* Get Multicast Information */ chdlc_priv_area->mc = conf->mc; /* prepare network device data space for registration */ strcpy(dev->name, card->u.c.if_name); dev->init = &if_init; dev->priv = chdlc_priv_area; return 0;}/*============================================================================ * Delete logical channel. */static int del_if (wan_device_t* wandev, struct net_device* dev){/* FIXME: This code generates kernel panic during router stop!. Investigate futher. (Error is dereferencing a NULL pointer) if(dev->priv){ kfree(dev->priv); dev->priv = NULL; }*/ return 0;}/****** Network Device Interface ********************************************//*============================================================================ * Initialize Linux network interface. * * This routine is called only once for each interface, during Linux network * interface registration. Returning anything but zero will fail interface * registration. */static int if_init (struct net_device* dev) { chdlc_private_area_t* chdlc_priv_area = dev->priv; sdla_t* card = chdlc_priv_area->card; wan_device_t* wandev = &card->wandev;#ifndef LINUX_2_1 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; dev->tx_timeout = &if_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; /* Initialize media-specific parameters */ dev->flags |= IFF_POINTTOPOINT; /* Enable Mulitcasting if user selected */ if (chdlc_priv_area->mc == WANOPT_YES){ dev->flags |= IFF_MULTICAST; }#ifndef LINUX_2_1 dev->family = AF_INET;#endif dev->type = ARPHRD_PPP; /* ARP hw type -- dummy value */ dev->mtu = card->wandev.mtu; 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 */#ifdef LINUX_2_1 dev_init_buffers(dev);#else 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 (struct net_device* dev){ chdlc_private_area_t* chdlc_priv_area = dev->priv; sdla_t* card = chdlc_priv_area->card; SHARED_MEMORY_INFO_STRUCT* flags = card->u.c.flags; struct timeval tv; int err = 0; /* Only one open per interface is allowed */ if(netif_running(dev)) return -EBUSY; if(test_and_set_bit(1, (void*)&card->wandev.critical)) { return -EAGAIN; } /* Setup the Board for CHDLC */ if (set_chdlc_config(card)) { clear_bit(1, (void*)&card->wandev.critical); return -EIO; } if (!card->configured && !card->wandev.piggyback){ /* Perform interrupt testing */ err = intr_test(card, dev); if(err || (Intr_test_counter < MAX_INTR_TEST_COUNTER)) { printk(KERN_ERR "%s: Interrupt test failed (%i)\n", card->devname, Intr_test_counter); printk(KERN_ERR "%s: Please choose another interrupt\n", card->devname); clear_bit(1, (void*)&card->wandev.critical); return -EIO; } printk(KERN_INFO "%s: Interrupt test passed (%i)\n", card->devname, Intr_test_counter); card->configured = 1; }else{ printk(KERN_INFO "%s: Card configured, skip interrupt test\n", card->devname); } /* Initialize Rx/Tx buffer control fields */ init_chdlc_tx_rx_buff(card, dev); /* Set interrupt mode and mask */ if (chdlc_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)){ clear_bit(1, (void*)&card->wandev.critical); return -EIO; } /* Mask the Transmit and Timer interrupt */ flags->interrupt_info_struct.interrupt_permission &= ~(APP_INT_ON_TX_FRAME | APP_INT_ON_TIMER); /* Enable communications */ if (chdlc_comm_enable(card)) { clear_bit(1, (void*)&card->wandev.critical); return -EIO; } clear_bit(1, (void*)&card->wandev.critical); port_set_state(card, WAN_CONNECTING); do_gettimeofday(&tv); chdlc_priv_area->router_start_time = tv.tv_sec; netif_start_queue(dev); dev->flags |= IFF_POINTTOPOINT; wanpipe_open(card); return err;}/*============================================================================ * Close network interface. * o if this is the last close, then disable communications and interrupts. * o reset flags. */static int if_close (struct net_device* dev){ chdlc_private_area_t* chdlc_priv_area = dev->priv; sdla_t* card = chdlc_priv_area->card; if(test_and_set_bit(1, (void*)&card->wandev.critical)) return -EAGAIN; netif_stop_queue(dev); wanpipe_close(card); port_set_state(card, WAN_DISCONNECTED); chdlc_set_intr_mode(card, 0); chdlc_comm_disable(card); clear_bit(1, (void*)&card->wandev.critical); return 0;}/*============================================================================ * 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, struct net_device* dev, unsigned short type, void* daddr, void* saddr, unsigned len){ skb->protocol = htons(type); return CHDLC_HDR_LEN;}/*============================================================================ * Re-build media header. * * Return: 1 physical address resolved. * 0 physical address not resolved */#ifdef LINUX_2_1static int if_rebuild_hdr (struct sk_buff *skb){ return 1;}#elsestatic int if_rebuild_hdr (void* hdr, struct net_device* dev, unsigned long raddr, struct sk_buff* skb){ return 1;}#endif/*============================================================================ * Handle transmit timeout event from netif watchdog */static void if_tx_timeout (struct net_device *dev){ chdlc_private_area_t *chdlc_priv_area = dev->priv; sdla_t *card = chdlc_priv_area->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 timeout !\n", card->devname); /* unbusy the interface */ netif_start_queue (dev);}/*============================================================================ * Send a packet on a network interface. * o set tbusy flag (marks start of the transmission) to block a timer-based * transmit from overlapping. * o check link state. If link is not up, then drop the packet. * o execute adapter send command. * o free socket buffer * * Return: 0 complete (socket buffer must be freed) * non-0 packet may be re-transmitted (tbusy must be set) * * Notes: * 1. This routine is called either by the protocol stack or by the "net * bottom half" (with interrupts enabled). * 2. Setting tbusy flag will inhibit further transmit requests from the * protocol stack and can be used for flow control with protocol layer. */static int if_send (struct sk_buff* skb, struct net_device* dev){ chdlc_private_area_t *chdlc_priv_area = dev->priv; sdla_t *card = chdlc_priv_area->card; SHARED_MEMORY_INFO_STRUCT *flags = card->u.c.flags; INTERRUPT_INFORMATION_STRUCT *chdlc_int = &flags->interrupt_info_struct; int udp_type = 0; unsigned long smp_flags;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -