Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1772479
  • 博文数量: 272
  • 博客积分: 1272
  • 博客等级: 少尉
  • 技术积分: 1866
  • 用 户 组: 普通用户
  • 注册时间: 2011-03-09 15:51
文章分类

全部博文(272)

文章存档

2016年(16)

2015年(28)

2014年(97)

2013年(59)

2012年(25)

2011年(47)

分类: LINUX

2014-12-15 15:16:30

static struct sk_buff *ip_frag_reasm(struct ipq *qp, struct net_device *dev)

{

       struct iphdr *iph;

       struct sk_buff *fp, *head = qp->fragments;

       int len;

       int ihlen;

 

       ipq_kill(qp);

 

       BUG_TRAP(head != NULL);

       BUG_TRAP(FRAG_CB(head)->offset == 0);

      

       //取得ipq中fragments头节点的ip头长度

       ihlen = ip_hdrlen(head);

 

       //如果把头节点的IP首部长度加上ipq结构中的碎片总长度相加,就得到了重组之

       //后报文的长度

       len = ihlen + qp->len;

 

       if (len > 65535)

              goto out_oversize;

 

       //头节点必须没有被克隆过

       if (skb_cloned(head) && pskb_expand_head(head, 0, 0, GFP_ATOMIC))

              goto out_nomem;

 

       //碎片中第一个节点如果是分片的,需要特殊处理,这里的”分片”并不是指IP包的

       //碎片,而是指skb存储结构离散分布,并不在一个连续的内存空间内

 

       if (skb_shinfo(head)->frag_list) {

              struct sk_buff *clone;

              int i, plen = 0;

              //如果头节点是分片的,那么需要重新申请一个skb,并且把这个新的skb放到

              //第一个skb end指针之后skb_shared_info结构的frag_list链表上

              if ((clone = alloc_skb(0, GFP_ATOMIC)) == NULL)

                     goto out_nomem;

              clone->next = head->next;

              head->next = clone;

 

              //把head原来的分片放在新申请的skb的frag_list里面

              skb_shinfo(clone)->frag_list = skb_shinfo(head)->frag_list;

              skb_shinfo(head)->frag_list = NULL;

 

              //计算head中总的分片长度

              for (i=0; inr_frags; i++)

                     plen += skb_shinfo(head)->frags[i].size;

             

              //实际上最后生成了一个自身数据为0.不包含任何数据,但是

              //这个新的的frag_list中却包含了所有的分片

              clone->len = clone->data_len = head->data_len - plen;

              head->data_len -= clone->len;

              head->len -= clone->len;

              clone->csum = 0;

              clone->ip_summed = head->ip_summed;

              atomic_add(clone->truesize, &ip_frag_mem);

       }

    

       //把head以后所有的碎片都当作是head frag_list里面的分片来处理

       skb_shinfo(head)->frag_list = head->next;

 

 

       skb_push(head, head->data - skb_network_header(head));

       atomic_sub(head->truesize, &ip_frag_mem);

 

       //协议栈的处理会通过skb_linearize()函数将head报文的frag_list链表里面的数据包

       //都合并成一个报文,所以将链表里面所有skb的len和data_len,以及true_size都

       //和head中相应的值相加,最后得到了合并后数据包的长度

       for (fp=head->next; fp; fp = fp->next) {

              head->data_len += fp->len;

              head->len += fp->len;

              if (head->ip_summed != fp->ip_summed)

                     head->ip_summed = CHECKSUM_NONE;

              else if (head->ip_summed == CHECKSUM_COMPLETE)

                     head->csum = csum_add(head->csum, fp->csum);

              head->truesize += fp->truesize;

              atomic_sub(fp->truesize, &ip_frag_mem);

       }

 

       head->next = NULL;

       head->dev = dev;

       head->tstamp = qp->stamp;

 

       iph = ip_hdr(head);

       iph->frag_off = 0;

       iph->tot_len = htons(len);

       IP_INC_STATS_BH(IPSTATS_MIB_REASMOKS);

       qp->fragments = NULL;

       return head;

 

      //省去部分代码

}

阅读(4269) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~