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

📄 sdla_fr.c

📁 上传linux-jx2410的源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
 * o if this is the first open, then 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_channel_t* chan = dev->priv;	sdla_t* card = chan->card;	int err = 0;	struct timeval tv;	if (is_dev_running(dev))		return -EBUSY;	#if defined(LINUX_2_1) || defined(LINUX_2_4)	/* Initialize the task queue */	chan->tq_working=0;#ifndef LINUX_2_4	chan->common.wanpipe_task.next = NULL;#endif	chan->common.wanpipe_task.sync = 0;	chan->common.wanpipe_task.routine = (void *)(void *)fr_bh;	chan->common.wanpipe_task.data = dev;	/* Allocate and initialize BH circular buffer */	chan->bh_head = kmalloc((sizeof(bh_data_t)*MAX_BH_BUFF),GFP_ATOMIC);	memset(chan->bh_head,0,(sizeof(bh_data_t)*MAX_BH_BUFF));	atomic_set(&chan->bh_buff_used, 0);#endif#ifdef LINUX_2_4	netif_start_queue(dev);#else		dev->interrupt = 0;	dev->tbusy = 0;	dev->start = 1;#endif	wanpipe_open(card);	do_gettimeofday( &tv );	chan->router_start_time = tv.tv_sec;		if (test_bit(0,&chan->config_dlci)){		trigger_config_fr (card);	}else if (chan->inarp == INARP_REQUEST){		trigger_fr_arp(dev);	}		return err;}/*============================================================================ * Close network interface. * o if this is the last open, then disable communications and interrupts. * o reset flags. */static int if_close (netdevice_t* dev){	fr_channel_t* chan = dev->priv;	sdla_t* card = chan->card;	if (chan->inarp == INARP_CONFIGURED) {		chan->inarp = INARP_REQUEST;	}	stop_net_queue(dev);#ifndef LINUX_2_4	dev->start=0;#endif	wanpipe_close(card);	return 0;}/*============================================================================ * 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){#elsestatic int if_rebuild_hdr (void* hdr, netdevice_t* dev, unsigned long raddr,                           struct sk_buff* skb){#endif#if defined(LINUX_2_1) || defined(LINUX_2_4) 	netdevice_t *dev = skb->dev;#endif	fr_channel_t* chan = dev->priv;	sdla_t* card = chan->card;	printk(KERN_INFO "%s: rebuild_header() called for interface %s!\n",		card->devname, dev->name);	return 1;}#ifdef LINUX_2_4/*============================================================================ * Handle transmit timeout event from netif watchdog */static void if_tx_timeout (netdevice_t *dev){    	fr_channel_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.	 */	chan->drvstats_if_send.if_send_tbusy++;	++chan->ifstats.collisions;	printk (KERN_INFO "%s: Transmit timed out on %s\n", 			card->devname, dev->name);	chan->drvstats_if_send.if_send_tbusy_timeout++;	netif_wake_queue (dev);}#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 set critical flag when accessing board. * o check link state. If link is not up, then drop the packet. * o check channel status. If it's down then initiate a call. * o pass a packet to corresponding WAN device. * 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. Using the start_net_queue() and stop_net_queue() MACROS *    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_channel_t* chan = dev->priv;    	sdla_t* card = chan->card;        int err;    	unsigned char *sendpacket;    	fr508_flags_t* adptr_flags = card->flags;	int udp_type, delay_tx_queued=0;	unsigned long smp_flags=0;	unsigned char attr = 0;	chan->drvstats_if_send.if_send_entry++;#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);		chan->drvstats_if_send.if_send_skb_null ++;		wake_net_dev(dev);		return 0;	}	/* If a peripheral task is running just drop packets */	if (test_bit(PERI_CRIT, &card->wandev.critical)){				printk(KERN_INFO "%s: Critical in if_send(): Peripheral running!\n",				card->devname);				wan_dev_kfree_skb(skb,FREE_WRITE);		start_net_queue(dev);		return 0;	}	/* We must set the 'tbusy' flag if we already have a packet queued for	   transmission in the transmit interrupt handler. However, we must	   ensure that the transmit interrupt does not reset the 'tbusy' flag	   just before we set it, as this will result in a "transmit timeout".	*/	set_bit(SEND_TXIRQ_CRIT, (void*)&card->wandev.critical);        if(chan->transmit_length) {		stop_net_queue(dev);		chan->tick_counter = jiffies; 		clear_bit(SEND_TXIRQ_CRIT, (void*)&card->wandev.critical);		return 1;	}       	clear_bit(SEND_TXIRQ_CRIT, (void*)&card->wandev.critical); #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.                 */				chan->drvstats_if_send.if_send_tbusy++;		++chan->ifstats.collisions;		if ((jiffies - chan->tick_counter) < (5 * HZ)) {			return 1;		}		printk(KERN_INFO "%s: Transmit timed out on %s\n", 				card->devname, chan->name);		chan->drvstats_if_send.if_send_tbusy_timeout ++;		dev->tbusy = 0;    	}#endif		/* Move the if_header() code to here. By inserting frame	 * relay header in if_header() we would break the	 * tcpdump and other packet sniffers */	chan->fr_header_len = setup_fr_header(&skb,dev,chan->common.usedby);	if (chan->fr_header_len < 0 ){		++chan->ifstats.tx_dropped;		++card->wandev.stats.tx_dropped;				wan_dev_kfree_skb(skb,FREE_WRITE);		start_net_queue(dev);			return 0;	}	sendpacket = skb->data;	udp_type = udp_pkt_type(skb, card);        if(udp_type != UDP_INVALID_TYPE) {		if(store_udp_mgmt_pkt(udp_type, UDP_PKT_FRM_STACK, card, skb,                        chan->dlci)) {                        adptr_flags->imask |= FR_INTR_TIMER;                        if (udp_type == UDP_FPIPE_TYPE){                                chan->drvstats_if_send.					if_send_PIPE_request ++;			}                }		start_net_queue(dev);		return 0;	}	//FIXME: can we do better than sendpacket[2]?  	if ((chan->common.usedby == WANPIPE) && (sendpacket[2] == 0x45)) {		               	/* check to see if the source IP address is a broadcast or */                /* multicast IP address */                if(chk_bcast_mcast_addr(card, dev, skb)){            		++chan->ifstats.tx_dropped;			++card->wandev.stats.tx_dropped;                	wan_dev_kfree_skb(skb, FREE_WRITE);			start_net_queue(dev);			return 0;		}	}		/* Lock the S514/S508 card: SMP Supported */    	s508_s514_lock(card,&smp_flags);	if (test_and_set_bit(SEND_CRIT, (void*)&card->wandev.critical)) {				chan->drvstats_if_send.if_send_critical_non_ISR ++;		chan->ifstats.tx_dropped ++;		printk(KERN_INFO "%s Critical in IF_SEND: if_send() already running!\n", 				card->devname);		goto if_send_start_and_exit;	}		/* API packet check: minimum packet size must be greater than 	 * 16 byte API header */	if((chan->common.usedby == API) && (skb->len <= sizeof(api_tx_hdr_t))) {		++chan->ifstats.tx_dropped;		++card->wandev.stats.tx_dropped;	    				goto if_send_start_and_exit; 	}else{		/* During API transmission, get rid of the API header */		if (chan->common.usedby == API) {			api_tx_hdr_t* api_tx_hdr;			api_tx_hdr = (api_tx_hdr_t*)&skb->data[0x00];			attr = api_tx_hdr->attr;			skb_pull(skb,sizeof(api_tx_hdr_t));		}	}	if (card->wandev.state != WAN_CONNECTED) {		chan->drvstats_if_send.if_send_wan_disconnected ++;		++chan->ifstats.tx_dropped;        	++card->wandev.stats.tx_dropped;		} else if (chan->common.state != WAN_CONNECTED) {		chan->drvstats_if_send.if_send_dlci_disconnected ++;		/* Update the DLCI state in timer interrupt */		card->u.f.timer_int_enabled |= TMR_INT_ENABLED_UPDATE_STATE;			adptr_flags->imask |= FR_INTR_TIMER;        	++chan->ifstats.tx_dropped;        	++card->wandev.stats.tx_dropped;			} else if (!is_tx_ready(card, chan)) {		/* No tx buffers available, store for delayed transmit */		if (!setup_for_delayed_transmit(dev, skb)){			set_bit(1,&delay_tx_queued);		}		chan->drvstats_if_send.if_send_no_bfrs++;			} else if (!skb->protocol) {		/* No protocols drop packet */		chan->drvstats_if_send.if_send_protocol_error ++;		++card->wandev.stats.tx_errors;		} else if (test_bit(ARP_CRIT,&card->wandev.critical)){		/* We are trying to send an ARP Packet, block IP data until		 * ARP is sent */		++chan->ifstats.tx_dropped;        	++card->wandev.stats.tx_dropped;			} else {		//FIXME: IPX is not implemented in this version of Frame Relay ?		if((chan->common.usedby == WANPIPE) &&		 	sendpacket[1] == 0x00 &&		    	sendpacket[2] == 0x80 &&		    	sendpacket[6] == 0x81 &&		    	sendpacket[7] == 0x37) {						if( chan->enable_IPX ) {				switch_net_numbers(sendpacket, 						chan->network_number, 0);			} else {				//FIXME: Take this out when IPX is fixed 				printk(KERN_INFO 				"%s: WARNING: Unsupported IPX data in send, packet dropped\n",					card->devname);			}					}else{        		err = fr_send_data_header(card, chan->dlci, attr, skb->len, skb->data, chan->fr_header_len);			if (err) {				switch(err) {				case FRRES_CIR_OVERFLOW:				case FRRES_BUFFER_OVERFLOW:                			if (!setup_for_delayed_transmit(dev, skb)){						set_bit(1,&delay_tx_queued);					}           				chan->drvstats_if_send.						if_send_adptr_bfrs_full ++;					break;									case FRRES_TOO_LONG:					if (net_ratelimit()){						printk(KERN_INFO 						"%s: Error: Frame too long, transmission failed %i\n",						 card->devname, (unsigned int)skb->len);					}					/* Drop down to default */				default:					chan->drvstats_if_send.						if_send_dlci_disconnected ++;        				++chan->ifstats.tx_dropped;        				++card->wandev.stats.tx_dropped;					break;				}			} else {				chan->drvstats_if_send.					if_send_bfr_passed_to_adptr++;				++chan->ifstats.tx_packets;				++card->wandev.stats.tx_packets;				#if defined(LINUX_2_1) || defined(LINUX_2_4)                                chan->ifstats.tx_bytes += skb->len;                                card->wandev.stats.tx_bytes += skb->len;#endif#ifdef LINUX_2_4				dev->trans_start = jiffies;#endif			}		}	}if_send_start_and_exit:	start_net_queue(dev);		/* If we queued the packet for transmission, we must not	 * deallocate it. The packet is unlinked from the IP stack	 * not copied. Therefore, we must keep the original packet */	if (!test_bit(1,&delay_tx_queued)) {                wan_dev_kfree_skb(skb, FREE_WRITE);	}else{		adptr_flags->imask |= FR_INTR_TXRDY;		card->u.f.tx_interrupts_pending ++;	}        clear_bit(SEND_CRIT, (void*)&card->wandev.critical);	s508_s514_unlock(card,&smp_flags);	return 0;}/*============================================================================ * Setup so that a frame can be transmitted on the occurence of a transmit * interrupt. */static int setup_for_delayed_transmit (netdevice_t* dev, struct sk_buff *skb){        fr_channel_t* chan = dev->priv;        sdla_t* card = chan->card;        fr_dlci_interface_t* dlci_interface;	int len = skb->len;	/* Check that the dlci is properly configured,         * before using tx interrupt */	if (!chan->dlci_int_interface){		if (net_ratelimit()){ 			printk(KERN_INFO 

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -