Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1659853
  • 博文数量: 1493
  • 博客积分: 38
  • 博客等级: 民兵
  • 技术积分: 5834
  • 用 户 组: 普通用户
  • 注册时间: 2009-08-19 17:28
文章分类

全部博文(1493)

文章存档

2016年(11)

2015年(38)

2014年(137)

2013年(253)

2012年(1054)

2011年(1)

分类: 嵌入式

2013-04-25 08:52:31

原文地址:uip IP包分片重组函数解析 作者:hnylcxq


            uip 里面其实支持收到IP分片的报文,但是只能同时处理一个连接上的分片,因为只有一个buffer,但是该函数前面注明了,该函数没有经过很好的测试,所以我们还是不能轻易使用。
    所以在uIP配置文件里面还是不要开启此功能。下面将这个函数分析下,完全处于兴趣
 
此方法是将TCP流中的每8个字节对应于位图中的一个位,当最后一片到来后再每次都检查是否来齐了。 由于TCP偏移量是8字节对齐的。


#if UIP_REASSEMBLY && !UIP_CONF_IPV6
#define UIP_REASS_BUFSIZE (UIP_BUFSIZE - UIP_LLH_LEN)
static u8_t uip_reassbuf[UIP_REASS_BUFSIZE];                        //重组buffer 4200-14
static u8_t uip_reassbitmap[UIP_REASS_BUFSIZE / (8 * 8)];     //每一位表示一个字节
static const u8_t bitmap_bits[8] = {0xff, 0x7f, 0x3f, 0x1f,        
   0x0f, 0x07, 0x03, 0x01};
static u16_t uip_reasslen;
static u8_t uip_reassflags;
#define UIP_REASS_FLAG_LASTFRAG 0x01
static u8_t uip_reasstmr;                    


#define IP_MF   0x20


static u8_t
uip_reass(void)
{
  u16_t offset, len;
  u16_t i;


  /* If ip_reasstmr is zero, no packet is present in the buffer, so we
     write the IP header of the fragment into the reassembly
     buffer. The timer is updated with the maximum age. */
  if(uip_reasstmr == 0) {
    memcpy(uip_reassbuf, &BUF->vhl, UIP_IPH_LEN);
    uip_reasstmr = UIP_REASS_MAXAGE;
    uip_reassflags = 0;
    /* Clear the bitmap. */
    memset(uip_reassbitmap, 0, sizeof(uip_reassbitmap));                    
  }


  /* Check if the incoming fragment matches the one currently present
     in the reasembly buffer. If so, we proceed with copying the
     fragment into the buffer. */
  if(BUF->srcipaddr[0] == FBUF->srcipaddr[0] &&
     BUF->srcipaddr[1] == FBUF->srcipaddr[1] &&
     BUF->destipaddr[0] == FBUF->destipaddr[0] &&
     BUF->destipaddr[1] == FBUF->destipaddr[1] &&
     BUF->ipid[0] == FBUF->ipid[0] &&
     BUF->ipid[1] == FBUF->ipid[1]) {


    len = (BUF->len[0] << 8) + BUF->len[1] - (BUF->vhl & 0x0f) * 4;                //得到IP数据包的数据部分长度
    offset = (((BUF->ipoffset[0] & 0x1f) << 8) + BUF->ipoffset[1]) * 8;            //得到该分片的偏移量(字节偏移量)


    /* If the offset or the offset + fragment length overflows the                    //判断是否超过缓冲区大小
       reassembly buffer, we discard the entire packet. */
    if(offset > UIP_REASS_BUFSIZE ||
       offset + len > UIP_REASS_BUFSIZE) {
      uip_reasstmr = 0;
      goto nullreturn;
    }


    /* Copy the fragment into the reassembly buffer, at the right
       offset. */
    memcpy(&uip_reassbuf[UIP_IPH_LEN + offset],                                    //将数据拷贝到缓冲的正确位置,前面放置的IP头必须保留
  (char *)BUF + (int)((BUF->vhl & 0x0f) * 4),                                            //省去分片包的IP头,拷贝len长度
  len);
      
    /* Update the bitmap. */
    if(offset / (8 * 8) == (offset + len) / (8 * 8)) {                                    //设置位图,这里应该不太会发生,数据包的长度为0?
      /* If the two endpoints are in the same byte, we only update
that byte. */
    
      uip_reassbitmap[offset / (8 * 8)] |=
    bitmap_bits[(offset / 8 ) & 7] &
    ~bitmap_bits[((offset + len) / 8 ) & 7];
    } else {
      /* If the two endpoints are in different bytes, we update the
bytes in the endpoints and fill the stuff inbetween with
0xff. */                                                            //offset/8 得到的是八字节偏移量,然后再除以8,得到的是在位图中的按个字节,这个是下取整的,
      uip_reassbitmap[offset / (8 * 8)] |=              //八字节对齐的时候,第一个八字节和最后一个八字节 不一定是 刚好在位图中字节对齐。但中间的可以直接赋值为0xff,    
                                                                     //  比如此包加入到位图中的情况可能是  0x3 ff ff ff ...  f4  前后一个字节都不是对齐的,需要另外处理
bitmap_bits[(offset / 8 ) & 7];                            //这里找到offset/8得到的余数,该余数就是在位图中的起始位,上面有一个位图,如果余数为0,说明下面的一个字节都要填充为0xff,
                                                                        //如果余数为4则,该字节的前4位已经是1了,这里把后面4位或上uip_reassbitmap[i]=0x0f,就行了,这个位图就是设计好的
      for(i = 1 + offset / (8 * 8); i < (offset + len) / (8 * 8); ++i) {  //后面的连续字节都是全部是设置为0xff。这里i 是小于最后一个字节的前面一个字节停止的。
uip_reassbitmap[i] = 0xff;
      }
      uip_reassbitmap[(offset + len) / (8 * 8)] |=            //最后一个字节需要特殊处理,刚好根据余数把对于bitmap_bits 的前余数为设置1,也就是取该数组的非就行了,后面为0.真是妙
~bitmap_bits[((offset + len) / 8 ) & 7];
    }
    
    /* If this fragment has the More Fragments flag set to zero, we
       know that this is the last fragment, so we can calculate the
       size of the entire packet. We also set the
       IP_REASS_FLAG_LASTFRAG flag to indicate that we have received
       the final fragment. */


    if((BUF->ipoffset[0] & IP_MF) == 0) {
      uip_reassflags |= UIP_REASS_FLAG_LASTFRAG;                
      uip_reasslen = offset + len;            //得到最后一个分片,可以计算出整个包的大小,但不能确定整个包已经全部到来,来的顺序可能不一样
    }
    
    /* Finally, we check if we have a full packet in the buffer. We do
       this by checking if we have the last fragment and if all bits
       in the bitmap are set. */
    if(uip_reassflags & UIP_REASS_FLAG_LASTFRAG) {            //如果收到最后一片,就可以经行检测了,是必要不充分条件
      /* Check all bytes up to and including all but the last byte in
the bitmap. */
      for(i = 0; i < uip_reasslen / (8 * 8) - 1; ++i) {            //前面的应该是满字节不应该有空闲
if(uip_reassbitmap[i] != 0xff) {
 goto nullreturn;
}
      }
      /* Check the last byte in the bitmap. It should contain just the
right amount of bits. */
      if(uip_reassbitmap[uip_reasslen / (8 * 8)] !=        //最后一个字节位可能不能占用整个一个整数倍的位图,比如 0xff ff  fe  所以必须衡量最后一个字节
(u8_t)~bitmap_bits[uip_reasslen / 8 & 7]) {
goto nullreturn;
      }


      /* If we have come this far, we have a full packet in the
buffer, so we allocate a pbuf and copy the packet into it. We
also reset the timer. */
      uip_reasstmr = 0;
      memcpy(BUF, FBUF, uip_reasslen);


      /* Pretend to be a "normal" (i.e., not fragmented) IP packet
from now on. */
      BUF->ipoffset[0] = BUF->ipoffset[1] = 0;
      BUF->len[0] = uip_reasslen >> 8;
      BUF->len[1] = uip_reasslen & 0xff;
      BUF->ipchksum = 0;
      BUF->ipchksum = ~(uip_ipchksum());


      return uip_reasslen;
    }
  }


 nullreturn:
  return 0;
}
阅读(945) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~