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

📄 hamachi.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
#define csum_add(it, val) \do { \    it += (u16) (val); \    if (it & 0xffff0000) { \	it &= 0xffff; \	++it; \    } \} while (0)    /* printk("add %04x --> %04x\n", val, it); \ *//* uh->len already network format, do not swap */#define pseudo_csum_udp(sum,ih,uh) do { \    sum = 0; \    csum_add(sum, (ih)->saddr >> 16); \    csum_add(sum, (ih)->saddr & 0xffff); \    csum_add(sum, (ih)->daddr >> 16); \    csum_add(sum, (ih)->daddr & 0xffff); \    csum_add(sum, __constant_htons(IPPROTO_UDP)); \    csum_add(sum, (uh)->len); \} while (0)/* swap len */#define pseudo_csum_tcp(sum,ih,len) do { \    sum = 0; \    csum_add(sum, (ih)->saddr >> 16); \    csum_add(sum, (ih)->saddr & 0xffff); \    csum_add(sum, (ih)->daddr >> 16); \    csum_add(sum, (ih)->daddr & 0xffff); \    csum_add(sum, __constant_htons(IPPROTO_TCP)); \    csum_add(sum, htons(len)); \} while (0)#endifstatic int hamachi_start_xmit(struct sk_buff *skb, struct net_device *dev){	struct hamachi_private *hmp = (struct hamachi_private *)dev->priv;	unsigned entry;	u16 status;	/* Ok, now make sure that the queue has space before trying to 		add another skbuff.  if we return non-zero the scheduler		should interpret this as a queue full and requeue the buffer		for later.	 */	if (hmp->tx_full) {		/* We should NEVER reach this point -KDU */		printk(KERN_WARNING "%s: Hamachi transmit queue full at slot %d.\n",dev->name, hmp->cur_tx);		/* Wake the potentially-idle transmit channel. */		/* If we don't need to read status, DON'T -KDU */		status=readw(dev->base_addr + TxStatus);		if( !(status & 0x0001) || (status & 0x0002))			writew(0x0001, dev->base_addr + TxCmd);		return 1;	} 	/* Caution: the write order is important here, set the field	   with the "ownership" bits last. */	/* Calculate the next Tx descriptor entry. */	entry = hmp->cur_tx % TX_RING_SIZE;	hmp->tx_skbuff[entry] = skb;#ifdef TX_CHECKSUM	{	    /* tack on checksum tag */	    u32 tagval = 0;	    struct ethhdr *eh = (struct ethhdr *)skb->data;	    if (eh->h_proto == __constant_htons(ETH_P_IP)) {		struct iphdr *ih = (struct iphdr *)((char *)eh + ETH_HLEN);		if (ih->protocol == IPPROTO_UDP) {		    struct udphdr *uh		      = (struct udphdr *)((char *)ih + ih->ihl*4);		    u32 offset = ((unsigned char *)uh + 6) - skb->data;		    u32 pseudo;		    pseudo_csum_udp(pseudo, ih, uh);		    pseudo = htons(pseudo);		    printk("udp cksum was %04x, sending pseudo %04x\n",		      uh->check, pseudo);		    uh->check = 0;  /* zero out uh->check before card calc */		    /*		     * start at 14 (skip ethhdr), store at offset (uh->check),		     * use pseudo value given.		     */		    tagval = (14 << 24) | (offset << 16) | pseudo;		} else if (ih->protocol == IPPROTO_TCP) {		    printk("tcp, no auto cksum\n");		}	    }	    *(u32 *)skb_push(skb, 8) = tagval;	}#endif	hmp->tx_ring[entry].addr = virt_to_desc(skb->data);    	/* Hmmmm, could probably put a DescIntr on these, but the way		the driver is currently coded makes Tx interrupts unnecessary		since the clearing of the Tx ring is handled by the start_xmit		routine.  This organization helps mitigate the interrupts a		bit and probably renders the max_tx_latency param useless.				Update: Putting a DescIntr bit on all of the descriptors and		mitigating interrupt frequency with the tx_min_pkt parameter. -KDU	*/	if (entry >= TX_RING_SIZE-1)		 /* Wrap ring */		hmp->tx_ring[entry].status_n_length = 			cpu_to_le32(DescOwn|DescEndPacket|DescEndRing|DescIntr | skb->len);	else		hmp->tx_ring[entry].status_n_length = 			cpu_to_le32(DescOwn|DescEndPacket|DescIntr | skb->len);	hmp->cur_tx++;	/* Non-x86 Todo: explicitly flush cache lines here. */	/* Wake the potentially-idle transmit channel. */	/* If we don't need to read status, DON'T -KDU */	status=readw(dev->base_addr + TxStatus);	if( !(status & 0x0001) || (status & 0x0002))		writew(0x0001, dev->base_addr + TxCmd);	/* Immediately before returning, let's clear as many entries as we can. */	hamachi_tx(dev);	/* We should kick the bottom half here, since we are not accepting	 * interrupts with every packet.  i.e. realize that Gigabit ethernet	 * can transmit faster than ordinary machines can load packets;	 * hence, any packet that got put off because we were in the transmit	 * routine should IMMEDIATELY get a chance to be re-queued. -KDU	 */	if ((hmp->cur_tx - hmp->dirty_tx) < (TX_RING_SIZE - 4)) 		netif_wake_queue(dev);  /* Typical path */	else {		hmp->tx_full = 1;		netif_stop_queue(dev);	}	dev->trans_start = jiffies;	if (hamachi_debug > 4) {		printk(KERN_DEBUG "%s: Hamachi transmit frame #%d queued in slot %d.\n",			   dev->name, hmp->cur_tx, entry);	}	return 0;}/* The interrupt handler does all of the Rx thread work and cleans up   after the Tx thread. */static void hamachi_interrupt(int irq, void *dev_instance, struct pt_regs *rgs){	struct net_device *dev = (struct net_device *)dev_instance;	struct hamachi_private *hmp;	long ioaddr, boguscnt = max_interrupt_work;#ifndef final_version			/* Can never occur. */	if (dev == NULL) {		printk (KERN_ERR "hamachi_interrupt(): irq %d for unknown device.\n", irq);		return;	}#endif	ioaddr = dev->base_addr;	hmp = (struct hamachi_private *)dev->priv;	spin_lock(&hmp->lock);	do {		u32 intr_status = readl(ioaddr + InterruptClear);		if (hamachi_debug > 4)			printk(KERN_DEBUG "%s: Hamachi interrupt, status %4.4x.\n",				   dev->name, intr_status);		if (intr_status == 0)			break;		if (intr_status & IntrRxDone)			hamachi_rx(dev);		if (intr_status & IntrTxDone){			/* This code should RARELY need to execute. After all, this is			 * a gigabit link, it should consume packets as fast as we put			 * them in AND we clear the Tx ring in hamachi_start_xmit().			 */ 			if (hmp->tx_full){				for (; hmp->cur_tx - hmp->dirty_tx > 0; hmp->dirty_tx++){					int entry = hmp->dirty_tx % TX_RING_SIZE;					if (hmp->tx_ring[entry].status_n_length & cpu_to_le32(DescOwn)) 						break;					/* Free the original skb. */					if (hmp->tx_skbuff[entry]){						dev_kfree_skb_irq(hmp->tx_skbuff[entry]);						hmp->tx_skbuff[entry] = 0;					}					hmp->tx_ring[entry].status_n_length = 0;					if (entry >= TX_RING_SIZE-1)  						hmp->tx_ring[TX_RING_SIZE-1].status_n_length |= 							cpu_to_le32(DescEndRing);					hmp->stats.tx_packets++;				}				if (hmp->cur_tx - hmp->dirty_tx < TX_RING_SIZE - 4){					/* The ring is no longer full */					hmp->tx_full = 0;					netif_wake_queue(dev);				}			} else {				netif_wake_queue(dev);			}		}		/* Abnormal error summary/uncommon events handlers. */		if (intr_status &			(IntrTxPCIFault | IntrTxPCIErr | IntrRxPCIFault | IntrRxPCIErr |			 LinkChange | NegotiationChange | StatsMax))			hamachi_error(dev, intr_status);		if (--boguscnt < 0) {			printk(KERN_WARNING "%s: Too much work at interrupt, status=0x%4.4x.\n",				   dev->name, intr_status);			break;		}	} while (1);	if (hamachi_debug > 3)		printk(KERN_DEBUG "%s: exiting interrupt, status=%#4.4x.\n",			   dev->name, readl(ioaddr + IntrStatus));#ifndef final_version	/* Code that should never be run!  Perhaps remove after testing.. */	{		static int stopit = 10;		if (dev->start == 0  &&  --stopit < 0) {			printk(KERN_ERR "%s: Emergency stop, looping startup interrupt.\n",				   dev->name);			free_irq(irq, dev);		}	}#endif	spin_unlock(&hmp->lock);}#ifdef TX_CHECKSUM/* * Copied from eth_type_trans(), with reduced header, since we don't * get it on RX, only on TX. */static unsigned short hamachi_eth_type_trans(struct sk_buff *skb,  struct net_device *dev){	struct ethhdr *eth;	unsigned char *rawp;		skb->mac.raw=skb->data;	skb_pull(skb,dev->hard_header_len-8);  /* artificially enlarged on tx */	eth= skb->mac.ethernet;		if(*eth->h_dest&1)	{		if(memcmp(eth->h_dest,dev->broadcast, ETH_ALEN)==0)			skb->pkt_type=PACKET_BROADCAST;		else			skb->pkt_type=PACKET_MULTICAST;	}		/*	 *	This ALLMULTI check should be redundant by 1.4	 *	so don't forget to remove it.	 *	 *	Seems, you forgot to remove it. All silly devices	 *	seems to set IFF_PROMISC.	 */	 	else if(dev->flags&(IFF_PROMISC/*|IFF_ALLMULTI*/))	{		if(memcmp(eth->h_dest,dev->dev_addr, ETH_ALEN))			skb->pkt_type=PACKET_OTHERHOST;	}		if (ntohs(eth->h_proto) >= 1536)		return eth->h_proto;			rawp = skb->data;		/*	 *	This is a magic hack to spot IPX packets. Older Novell breaks	 *	the protocol design and runs IPX over 802.3 without an 802.2 LLC	 *	layer. We look for FFFF which isn't a used 802.2 SSAP/DSAP. This	 *	won't work for fault tolerant netware but does for the rest.	 */	if (*(unsigned short *)rawp == 0xFFFF)		return htons(ETH_P_802_3);			/*	 *	Real 802.2 LLC	 */	return htons(ETH_P_802_2);}#endif  /* TX_CHECKSUM *//* This routine is logically part of the interrupt handler, but seperated   for clarity and better register allocation. */static int hamachi_rx(struct net_device *dev){	struct hamachi_private *hmp = (struct hamachi_private *)dev->priv;	int entry = hmp->cur_rx % RX_RING_SIZE;	int boguscnt = (hmp->dirty_rx + RX_RING_SIZE) - hmp->cur_rx;	if (hamachi_debug > 4) {		printk(KERN_DEBUG " In hamachi_rx(), entry %d status %4.4x.\n",			   entry, hmp->rx_ring[entry].status_n_length);	}	/* If EOP is set on the next entry, it's a new packet. Send it up. */	while ( ! (hmp->rx_head_desc->status_n_length & cpu_to_le32(DescOwn))) {		struct hamachi_desc *desc = hmp->rx_head_desc;		u32 desc_status = le32_to_cpu(desc->status_n_length);		u16 data_size = desc_status;			/* Implicit truncate */		u8 *buf_addr = le32desc_to_virt(desc->addr);		s32 frame_status = 			le32_to_cpu(get_unaligned((s32*)&(buf_addr[data_size - 12])));				if (hamachi_debug > 4)			printk(KERN_DEBUG "  hamachi_rx() status was %8.8x.\n",				frame_status);		if (--boguscnt < 0)			break;		if ( ! (desc_status & DescEndPacket)) {			printk(KERN_WARNING "%s: Oversized Ethernet frame spanned "				   "multiple buffers, entry %#x length %d status %4.4x!\n",				   dev->name, hmp->cur_rx, data_size, desc_status);			printk(KERN_WARNING "%s: Oversized Ethernet frame %p vs %p.\n",				   dev->name, desc, &hmp->rx_ring[hmp->cur_rx % RX_RING_SIZE]);			printk(KERN_WARNING "%s: Oversized Ethernet frame -- next status %x/%x last status %x.\n",				   dev->name,				   hmp->rx_ring[(hmp->cur_rx+1) % RX_RING_SIZE].status_n_length & 0xffff0000,				   hmp->rx_ring[(hmp->cur_rx+1) % RX_RING_SIZE].status_n_length & 0x0000ffff,				   hmp->rx_ring[(hmp->cur_rx-1) % RX_RING_SIZE].status_n_length);			hmp->stats.rx_length_errors++;		} /* else  Omit for prototype errata??? */		if (frame_status & 0x00380000) {			/* There was an error. */			if (hamachi_debug > 2)				printk(KERN_DEBUG "  hamachi_rx() Rx error was %8.8x.\n",					   frame_status);			hmp->stats.rx_errors++;			if (frame_status & 0x00600000) hmp->stats.rx_length_errors++;			if (frame_status & 0x00080000) hmp->stats.rx_frame_errors++;			if (frame_status & 0x00100000) hmp->stats.rx_crc_errors++;			if (frame_status < 0) hmp->stats.rx_dropped++;		} else {			struct sk_buff *skb;			/* Omit CRC */			u16 pkt_len = (frame_status & 0x07ff) - 4;	#ifdef RX_CHECKSUM			u32 pfck = *(u32 *) &buf_addr[data_size - 8];#endif#ifndef final_version			if (hamachi_debug > 4)				printk(KERN_DEBUG "  hamachi_rx() normal Rx pkt length %d"					   " of %d, bogus_cnt %d.\n",					   pkt_len, data_size, boguscnt);			if (hamachi_debug > 5)				printk(KERN_DEBUG"%s:  rx status %8.8x %8.8x %8.8x %8.8x %8.8x.\n",					   dev->name,					   *(s32*)&(buf_addr[data_size - 20]),					   *(s32*)&(buf_addr[data_size - 16]),					   *(s32*)&(buf_addr[data_size - 12]),					   *(s32*)&(buf_addr[data_size - 8]),					   *(s32*)&(buf_addr[data_size - 4]));#endif			/* Check if the packet is long enough to accept without copying			   to a minimally-sized skbuff. */			if (pkt_len < rx_copybreak				&& (skb = dev_alloc_skb(pkt_len + 2)) != NULL) {#ifdef RX_CHECKSUM				printk(KERN_ERR "%s: rx_copybreak non-zero "				  "not good with RX_CHECKSUM\n", dev->name);#endif				skb->dev = dev;

⌨️ 快捷键说明

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