Linux内核源代码解析——IP切碎了又粘好

本文原创为freas_1990,转载请标明出处:http://blog.csdn.net/freas_1990/article/details/23795587


IP分片定义如下:

/* Describe an IP fragment. */
struct ipfrag {
  int		offset;		/* offset of fragment in IP datagram	*/
  int		end;		/* last byte of data in datagram	*/
  int		len;		/* length of this fragment		*/
  struct sk_buff *skb;			/* complete received fragment		*/
  unsigned char		*ptr;		/* pointer into real fragment data	*/
  struct ipfrag		*next;		/* linked list pointers			*/
  struct ipfrag		*prev;
};

IP datagram定义如下:

/* Describe an entry in the "incomplete datagrams" queue. */
struct ipq	 {
  unsigned char		*mac;		/* pointer to MAC header		*/
  struct iphdr	*iph;		/* pointer to IP header			*/
  int		len;		/* total length of original datagram	*/
  short			ihlen;		/* length of the IP header		*/
  short 	maclen;		/* length of the MAC header		*/
  struct timer_list timer;	/* when will this queue expire?		*/
  struct ipfrag		*fragments;	/* linked list of received fragments	*/
  struct ipq	*next;		/* linked list pointers			*/
  struct ipq	*prev;
  struct device *dev;		/* Device - for icmp replies */
};

IP分片构建如下:

 /* Create a new fragment entry. */
static struct ipfrag *ip_frag_create(int offset, int end, struct sk_buff *skb, unsigned char *ptr)
{
   	struct ipfrag *fp;
 
   	fp = (struct ipfrag *) kmalloc(sizeof(struct ipfrag), GFP_ATOMIC);
   	if (fp == NULL) 
   	{
	 	printk("IP: frag_create: no memory left !\n");
	 	return(NULL);
   	}
  	memset(fp, 0, sizeof(struct ipfrag));

        /* Fill in the structure. */
	fp->offset = offset;
	fp->end = end;
	fp->len = end - offset;
	fp->skb = skb;
	fp->ptr = ptr;
 
	return(fp);
}

IP分片完整性检查如下:

 /* See if a fragment queue is complete. */
static int ip_done(struct ipq *qp)
{
	struct ipfrag *fp;
	int offset;
 
   	/* Only possible if we received the final fragment. */
   	if (qp->len == 0) 
   		return(0);
 
   	/* Check all fragment offsets to see if they connect. */
  	fp = qp->fragments;
   	offset = 0;
   	while (fp != NULL) 
   	{
 		if (fp->offset > offset) 
 			return(0);	/* fragment(s) missing */
 		offset = fp->end;
 		fp = fp->next;
   	}
 
   	/* All fragments are present. */
   	return(1);
 }

从所有的fragments构建出一个IP datagram的代码如下:

/* Build a new IP datagram from all its fragments. */
static struct sk_buff *ip_glue(struct ipq *qp)
{
	struct sk_buff *skb;
   	struct iphdr *iph;
   	struct ipfrag *fp;
   	unsigned char *ptr;
   	int count, len;
 
   	/* Allocate a new buffer for the datagram. */
   	len = sizeof(struct sk_buff)+qp->maclen + qp->ihlen + qp->len;
   	if ((skb = alloc_skb(len,GFP_ATOMIC)) == NULL) 
   	{
 		printk("IP: queue_glue: no memory for glueing queue 0x%X\n", (int) qp);
 		ip_free(qp);
 		return(NULL);
   	}
 
   	/* Fill in the basic details. */
   	skb->len = (len - qp->maclen);
   	skb->h.raw = skb->data;
   	skb->free = 1;
 
   	/* Copy the original MAC and IP headers into the new buffer. */
   	ptr = (unsigned char *) skb->h.raw;
   	memcpy(ptr, ((unsigned char *) qp->mac), qp->maclen);
/*   	printk("Copied %d bytes of mac header.\n",qp->maclen);*/
   	ptr += qp->maclen;
   	memcpy(ptr, ((unsigned char *) qp->iph), qp->ihlen);
/*   	printk("Copied %d byte of ip header.\n",qp->ihlen);*/
   	ptr += qp->ihlen;
   	skb->h.raw += qp->maclen;
   	
/*   	printk("Protocol = %d\n",skb->h.iph->protocol);*/
   	count = 0;
 
   	/* Copy the data portions of all fragments into the new buffer. */
   	fp = qp->fragments;
   	while(fp != NULL) 
   	{
   		if(count+fp->len>skb->len)
   		{
   			printk("Invalid fragment list: Fragment over size.\n");
   			ip_free(qp);
   			kfree_skb(skb,FREE_WRITE);
   			return NULL;
   		}
/*   		printk("Fragment %d size %d\n",fp->offset,fp->len);*/
 		memcpy((ptr + fp->offset), fp->ptr, fp->len);
 		count += fp->len;
 		fp = fp->next;
   	}
 
   	/* We glued together all fragments, so remove the queue entry. */
   	ip_free(qp);
 
   	/* Done with all fragments. Fixup the new IP header. */
   	iph = skb->h.iph;
   	iph->frag_off = 0;
   	iph->tot_len = htons((iph->ihl * sizeof(unsigned long)) + count);
   	skb->ip_hdr = iph;
   	return(skb);
}

24岁生日之后写的第一篇技术文章。

年龄越大,人越懒,除了源代码什么都不想说了。

原谅我一生不羁放纵爱自由。。。

Linux内核源代码解析——IP切碎了又粘好,古老的榕树,5-wow.com

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。