您的位置:首页 > 运维架构 > Linux

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

2015-11-08 01:45 531 查看
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岁生日之后写的第一篇技术文章。

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

原谅我一生不羁放纵爱自由。。。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: