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

📄 sdla_fr.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 5 页
字号:
 *		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 netif_start_queue() and netif_stop_queue() *    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){    	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;	long delay_tx_queued = 0;	unsigned long smp_flags=0;	unsigned char attr = 0;	chan->drvstats_if_send.if_send_entry++;	netif_stop_queue(dev);	        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 ++;		netif_wake_queue(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);				dev_kfree_skb_any(skb);		netif_start_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) {		netif_stop_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); 	/* 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;				dev_kfree_skb_any(skb);		netif_start_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 ++;			}                }		netif_start_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;                	dev_kfree_skb_any(skb);			netif_start_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;				                                chan->ifstats.tx_bytes += skb->len;                                card->wandev.stats.tx_bytes += skb->len;				dev->trans_start = jiffies;			}		}	}if_send_start_and_exit:	netif_start_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)) {                dev_kfree_skb_any(skb);	}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 occurrence of a transmit * interrupt. */static int setup_for_delayed_transmit(struct net_device* 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 				"%s: ERROR on DLCI %i: Not configured properly !\n",					card->devname, chan->dlci);			printk(KERN_INFO "%s: Please contact Sangoma Technologies\n",					card->devname);		}		return 1;	}			dlci_interface = chan->dlci_int_interface;        if(chan->transmit_length) {                printk(KERN_INFO "%s: Big mess in setup_for_del...\n",				card->devname);                return 1;        }	if(len > FR_MAX_NO_DATA_BYTES_IN_FRAME) {		//FIXME: increment some statistic */		return 1;	}        chan->transmit_length = len;	chan->delay_skb = skb;                dlci_interface->gen_interrupt |= FR_INTR_TXRDY;        dlci_interface->packet_length = len;	/* Turn on TX interrupt at the end of if_send */	return 0;}/*============================================================================ * Check to see if the packet to be transmitted contains a broadcast or * multicast source IP address. * Return 0 if not broadcast/multicast address, otherwise return 1. */static int chk_bcast_mcast_addr(sdla_t *card, struct net_device* dev,                                struct sk_buff *skb){        u32 src_ip_addr;        u32 broadcast_ip_addr = 0;        struct in_device *in_dev;        fr_channel_t* chan = dev->priv;         /* read the IP source address from the outgoing packet */        src_ip_addr = *(u32 *)(skb->data + 14);        /* read the IP broadcast address for the device */        in_dev = dev->ip_ptr;        if(in_dev != NULL) {                struct in_ifaddr *ifa= in_dev->ifa_list;                if(ifa != NULL)                        broadcast_ip_addr = ifa->ifa_broadcast;                else                        return 0;        }        /* check if the IP Source Address is a Broadcast address */        if((dev->flags & IFF_BROADCAST) && (src_ip_addr == broadcast_ip_addr)) {                printk(KERN_INFO                        "%s: Broadcast Source Address silently discarded\n",                        card->devname);                return 1;        }        /* check if the IP Source Address is a Multicast address */        if((chan->mc == WANOPT_NO) && (ntohl(src_ip_addr) >= 0xE0000001) &&                (ntohl(src_ip_addr) <= 0xFFFFFFFE)) {                printk(KERN_INFO                        "%s: Multicast Source Address silently discarded\n",                        card->devname);                return 1;        }        return 0;}/*============================================================================ * Reply to UDP Management system. * Return nothing. */static int reply_udp( unsigned char *data, unsigned int mbox_len ) {	unsigned short len, udp_length, temp, ip_length;	unsigned long ip_temp;	int even_bound = 0;  	fr_udp_pkt_t *fr_udp_pkt = (fr_udp_pkt_t *)data; 	/* Set length of packet */	len = //sizeof(fr_encap_hdr_t)+	      sizeof(ip_pkt_t)+ 	      sizeof(udp_pkt_t)+	      sizeof(wp_mgmt_t)+	      sizeof(cblock_t)+	      mbox_len; 	/* fill in UDP reply */	fr_udp_pkt->wp_mgmt.request_reply = UDPMGMT_REPLY;  	/* fill in UDP length */	udp_length = sizeof(udp_pkt_t)+ 		     sizeof(wp_mgmt_t)+		     sizeof(cblock_t)+		     mbox_len; 	/* put it on an even boundary */	if ( udp_length & 0x0001 ) {		udp_length += 1;		len += 1;		even_bound = 1;	}	temp = (udp_length<<8)|(udp_length>>8);	fr_udp_pkt->udp_pkt.udp_length = temp;	 	/* swap UDP ports */	temp = fr_udp_pkt->udp_pkt.udp_src_port;	fr_udp_pkt->udp_pkt.udp_src_port = 			fr_udp_pkt->udp_pkt.udp_dst_port; 	fr_udp_pkt->udp_pkt.udp_dst_port = temp;	/* add UDP pseudo header */	temp = 0x1100;	*((unsigned short *)		(fr_udp_pkt->data+mbox_len+even_bound)) = temp;		temp = (udp_length<<8)|(udp_length>>8);	*((unsigned short *)		(fr_udp_pkt->data+mbox_len+even_bound+2)) = temp;		 	/* calculate UDP checksum */	fr_udp_pkt->udp_pkt.udp_checksum = 0;	fr_udp_pkt->udp_pkt.udp_checksum = 		calc_checksum(&data[UDP_OFFSET/*+sizeof(fr_encap_hdr_t)*/],			      udp_length+UDP_OFFSET);	/* fill in IP length */	ip_length = udp_length + sizeof(ip_pkt_t);	temp = (ip_length<<8)|(ip_length>>8);	fr_udp_pkt->ip_pkt.total_length = temp;  	/* swap IP addresses */	ip_temp = fr_udp_pkt->ip_pkt.ip_src_address;	fr_udp_pkt->ip_pkt.ip_src_address = 				fr_udp_pkt->ip_pkt.ip_dst_address;	fr_udp_pkt->ip_pkt.ip_dst_address = ip_temp;		 	/* fill in IP checksum */	fr_udp_pkt->ip_pkt.hdr_checksum = 0;	fr_udp_pkt->ip_pkt.hdr_checksum = 		calc_checksum(&data[/*sizeof(fr_encap_hdr_t)*/0],		      	      sizeof(ip_pkt_t));	return len;} /* reply_udp */unsigned short calc_checksum (char *data, int len)

⌨️ 快捷键说明

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