Chinaunix首页 | 论坛 | 博客
  • 博客访问: 819620
  • 博文数量: 264
  • 博客积分: 592
  • 博客等级: 中士
  • 技术积分: 1574
  • 用 户 组: 普通用户
  • 注册时间: 2011-10-24 22:02
文章分类

全部博文(264)

文章存档

2019年(2)

2018年(1)

2017年(1)

2016年(4)

2015年(14)

2014年(57)

2013年(88)

2012年(97)

分类: LINUX

2014-02-12 15:52:57

转:http://blog.csdn.net/nerdx/article/details/12717817
  1. //调用路径ip_defrag->ip_frag_reasm  
  2. //  所有ip分片都被接收到时,重组ip数据包  
  3. //  判断ip所有分片都接收到的条件:  
  4. //      1.FIRST_IN, LAST_IN  
  5. //      2.meat = len,即 根据offset推断出的最大封包长度等于已接收到的封包长度  
  6.   
  7. //  重组过程:  
  8. //      1.将sk_buff链表从ipq->fragments取下  
  9. //      2.将第一个分片以后的分片挂在第一个分片的frag_list域  
  10. //      3.从分片子系统使用内存中减去该ip数据包的内存  
  11. //      4.返回第一个分片  
  12. 1.1 static struct sk_buff *ip_frag_reasm(struct ipq *qp, struct net_device *dev)  
  13. {  
  14.     struct iphdr *iph;  
  15.     struct sk_buff *fp, *head = qp->fragments;  
  16.     int len;  
  17.     int ihlen;  
  18.     //  
  19.     ipq_kill(qp);  
  20.   
  21.   
  22.     //ip报头+ip选项大小  
  23.     ihlen = head->nh.iph->ihl*4;  
  24.     //ipq->len只包括ip有效载荷的长度  
  25.     len = ihlen + qp->len;//ip分包总长度  
  26.     //ip报文最大长度为64k  
  27.     if(len > 65535)  
  28.         goto out_oversize;  
  29.     //由于第一个skb是通过skb_cloned构造,则需要重新拷贝一份skb缓存区  
  30.     //skb_cloned与skb_shared区别:  
  31.     //  1.skb_cloned 表示该sk_buff与另一个sk_buff共享同一个缓存区  
  32.     //  2.skb_shared 表示该sk_buff引用计数大于1  
  33.     if (skb_cloned(head) && pskb_expand_head(head, 0, 0, GFP_ATOMIC))  
  34.         goto out_nomem;  
  35.   
  36.     //保证第一个ip分片没有frag_list  
  37.     //  解决办法:  
  38.     //      1.创建一个新的sk_buff  
  39.     //      2.将该分片的frag_list添加到新sk_buff的frag_list上  
  40.     //      3.更新该skb,新skb的长度  
  41.     if (skb_shinfo(head)->frag_list) {  
  42.         struct sk_buff *clone;  
  43.         int i, plen = 0;  
  44.   
  45.         if ((clone = alloc_skb(0, GFP_ATOMIC)) == NULL)  
  46.             goto out_nomem;  
  47.         clone->next = head->next;  
  48.         head->next = clone;  
  49.         skb_shinfo(clone)->frag_list = skb_shinfo(head)->frag_list;  
  50.         skb_shinfo(head)->frag_list = NULL;  
  51.         for (i=0; inr_frags; i++)  
  52.             plen += skb_shinfo(head)->frags[i].size;  
  53.         clone->len = clone->data_len = head->data_len - plen;  
  54.         head->data_len -= clone->len;  
  55.         head->len -= clone->len;  
  56.         clone->csum = 0;  
  57.         clone->ip_summed = head->ip_summed;  
  58.         atomic_add(clone->truesize, &ip_frag_mem);  
  59.     }  
  60.   
  61.     //将ipq中,属于同一ip数据包的所有sk_buff,链接到第一个ip分片的frag_list上  
  62.     //  即: first->frag_list = first->next  
  63.     skb_shinfo(head)->frag_list = head->next;  
  64.     skb_push(head, head->data - head->nh.raw);  
  65.     atomic_sub(head->truesize, &ip_frag_mem);//减去ip分片子系统使用的内存  
  66.   
  67.     //通过第一个skb,统计该ip数据包的总长度  
  68.     for (fp=head->next; fp; fp = fp->next) {  
  69.         head->data_len += fp->len;  
  70.         head->len += fp->len;  
  71.         if (head->ip_summed != fp->ip_summed)//只要有其中一个分片的校验和失效,则标记第一个分片的校验和失效  
  72.             head->ip_summed = CHECKSUM_NONE;  
  73.         else if (head->ip_summed == CHECKSUM_HW)//已经由硬件计算了校验和  
  74.             head->csum = csum_add(head->csum, fp->csum);//l4校验和保存在sk_buff->csum  
  75.         head->truesize += fp->truesize;  
  76.         atomic_sub(fp->truesize, &ip_frag_mem);  
  77.     }  
  78.   
  79.     head->next = NULL;  
  80.     head->dev = dev;  
  81.     head->stamp = qp->stamp;//skb的时间戳为最后一个分片到达的时间戳  
  82.   
  83.     iph = head->nh.iph;  
  84.     iph->frag_off = 0;  
  85.     iph->tot_len = htons(len);  
  86.     IP_INC_STATS_BH(IPSTATS_MIB_REASMOKS);  
  87.     qp->fragments = NULL;  
  88.     return head;  
  89.   
  90. out_nomem:  
  91.     NETDEBUG(if (net_ratelimit())  
  92.              printk(KERN_ERR   
  93.             "IP: queue_glue: no memory for gluing queue %p\n",  
  94.             qp));  
  95.     goto out_fail;  
  96. out_oversize:  
  97.     if (net_ratelimit())  
  98.         printk(KERN_INFO  
  99.             "Oversized IP packet from %d.%d.%d.%d.\n",  
  100.             NIPQUAD(qp->saddr));  
  101. out_fail:  
  102.     IP_INC_STATS_BH(IPSTATS_MIB_REASMFAILS);  
  103.     return NULL;  
  104. }  
阅读(747) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~