⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sdla_chdlc.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
      	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 + -