/[lwip]/lwip/src/core/ipv4/ip.c
ViewVC logotype

Diff of /lwip/src/core/ipv4/ip.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1.3 by likewise, Thu Nov 21 10:32:39 2002 UTC revision 1.4 by jani, Fri Nov 22 15:46:50 2002 UTC
# Line 44  Line 44 
44  #include "lwip/def.h"  #include "lwip/def.h"
45  #include "lwip/mem.h"  #include "lwip/mem.h"
46  #include "lwip/ip.h"  #include "lwip/ip.h"
47    #include "lwip/ip_frag.h"
48  #include "lwip/inet.h"  #include "lwip/inet.h"
49  #include "lwip/netif.h"  #include "lwip/netif.h"
50  #include "lwip/icmp.h"  #include "lwip/icmp.h"
# Line 220  ip_forward(struct pbuf *p, struct ip_hdr Line 221  ip_forward(struct pbuf *p, struct ip_hdr
221  }  }
222  #endif /* IP_FORWARD */  #endif /* IP_FORWARD */
223  /*-----------------------------------------------------------------------------------*/  /*-----------------------------------------------------------------------------------*/
 /* ip_reass:  
  *  
  * Tries to reassemble a fragmented IP packet.  
  */  
 /*-----------------------------------------------------------------------------------*/  
 #define IP_REASSEMBLY 1  
 #define IP_REASS_BUFSIZE 5760  
 #define IP_REASS_MAXAGE 10  
   
 #if IP_REASSEMBLY  
 static u8_t ip_reassbuf[IP_HLEN + IP_REASS_BUFSIZE];  
 static u8_t ip_reassbitmap[IP_REASS_BUFSIZE / (8 * 8)];  
 static const u8_t bitmap_bits[8] = {0xff, 0x7f, 0x3f, 0x1f,  
                                     0x0f, 0x07, 0x03, 0x01};  
 static u16_t ip_reasslen;  
 static u8_t ip_reassflags;  
 #define IP_REASS_FLAG_LASTFRAG 0x01  
 static u8_t ip_reasstmr;  
   
 static struct pbuf *  
 ip_reass(struct pbuf *p)  
 {  
   struct pbuf *q;  
   struct ip_hdr *fraghdr, *iphdr;  
   u16_t offset, len;  
   u16_t i;  
     
   iphdr = (struct ip_hdr *)ip_reassbuf;  
   fraghdr = (struct ip_hdr *)p->payload;  
   
   /* 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(ip_reasstmr == 0) {  
     DEBUGF(IP_REASS_DEBUG, ("ip_reass: new packet\n"));  
     bcopy(fraghdr, iphdr, IP_HLEN);  
     ip_reasstmr = IP_REASS_MAXAGE;  
     ip_reassflags = 0;  
     /* Clear the bitmap. */  
     bzero(ip_reassbitmap, sizeof(ip_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(ip_addr_cmp(&iphdr->src, &fraghdr->src) &&  
      ip_addr_cmp(&iphdr->dest, &fraghdr->dest) &&  
      IPH_ID(iphdr) == IPH_ID(fraghdr)) {  
     DEBUGF(IP_REASS_DEBUG, ("ip_reass: matching old packet\n"));  
     /* Find out the offset in the reassembly buffer where we should  
        copy the fragment. */  
     len = ntohs(IPH_LEN(fraghdr)) - IPH_HL(fraghdr) * 4;  
     offset = (ntohs(IPH_OFFSET(fraghdr)) & IP_OFFMASK) * 8;  
   
     /* If the offset or the offset + fragment length overflows the  
        reassembly buffer, we discard the entire packet. */  
     if(offset > IP_REASS_BUFSIZE ||  
        offset + len > IP_REASS_BUFSIZE) {  
       DEBUGF(IP_REASS_DEBUG, ("ip_reass: fragment outside of buffer (%d:%d/%d).\n",  
                               offset, offset + len, IP_REASS_BUFSIZE));  
       ip_reasstmr = 0;  
       goto nullreturn;  
     }  
   
     /* Copy the fragment into the reassembly buffer, at the right  
        offset. */  
     DEBUGF(IP_REASS_DEBUG, ("ip_reass: copying with offset %d into %d:%d\n",  
                             offset, IP_HLEN + offset, IP_HLEN + offset + len));  
     bcopy((u8_t *)fraghdr + IPH_HL(fraghdr) * 4,  
           &ip_reassbuf[IP_HLEN + offset], len);  
   
     /* Update the bitmap. */  
     if(offset / (8 * 8) == (offset + len) / (8 * 8)) {  
       DEBUGF(IP_REASS_DEBUG, ("ip_reass: updating single byte in bitmap.\n"));  
       /* If the two endpoints are in the same byte, we only update  
          that byte. */  
       ip_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. */  
       ip_reassbitmap[offset / (8 * 8)] |= bitmap_bits[(offset / 8 ) & 7];  
       DEBUGF(IP_REASS_DEBUG, ("ip_reass: updating many bytes in bitmap (%d:%d).\n",  
                               1 + offset / (8 * 8), (offset + len) / (8 * 8)));  
       for(i = 1 + offset / (8 * 8); i < (offset + len) / (8 * 8); ++i) {  
         ip_reassbitmap[i] = 0xff;  
       }        
       ip_reassbitmap[(offset + len) / (8 * 8)] |= ~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((ntohs(IPH_OFFSET(fraghdr)) & IP_MF) == 0) {  
       ip_reassflags |= IP_REASS_FLAG_LASTFRAG;  
       ip_reasslen = offset + len;  
       DEBUGF(IP_REASS_DEBUG, ("ip_reass: last fragment seen, total len %d\n", ip_reasslen));  
     }  
       
     /* 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(ip_reassflags & IP_REASS_FLAG_LASTFRAG) {  
       /* Check all bytes up to and including all but the last byte in  
          the bitmap. */  
       for(i = 0; i < ip_reasslen / (8 * 8) - 1; ++i) {  
         if(ip_reassbitmap[i] != 0xff) {  
           DEBUGF(IP_REASS_DEBUG, ("ip_reass: last fragment seen, bitmap %d/%d failed (%x)\n", i, ip_reasslen / (8 * 8) - 1, ip_reassbitmap[i]));  
           goto nullreturn;  
         }  
       }  
       /* Check the last byte in the bitmap. It should contain just the  
          right amount of bits. */  
       if(ip_reassbitmap[ip_reasslen / (8 * 8)] !=  
          (u8_t)~bitmap_bits[ip_reasslen / 8 & 7]) {  
         DEBUGF(IP_REASS_DEBUG, ("ip_reass: last fragment seen, bitmap %d didn't contain %x (%x)\n",  
                                 ip_reasslen / (8 * 8), ~bitmap_bits[ip_reasslen / 8 & 7],  
                                 ip_reassbitmap[ip_reasslen / (8 * 8)]));  
         goto nullreturn;  
       }  
   
       /* Pretend to be a "normal" (i.e., not fragmented) IP packet  
          from now on. */  
       IPH_OFFSET_SET(iphdr, 0);  
       IPH_CHKSUM_SET(iphdr, 0);  
       IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IP_HLEN));  
         
       /* 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. */  
       ip_reasstmr = 0;  
       pbuf_free(p);  
       p = pbuf_alloc(PBUF_LINK, ip_reasslen, PBUF_POOL);  
       if(p != NULL) {  
         i = 0;  
         for(q = p; q != NULL; q = q->next) {  
           /* Copy enough bytes to fill this pbuf in the chain. The  
              avaliable data in the pbuf is given by the q->len  
              variable. */  
           DEBUGF(IP_REASS_DEBUG, ("ip_reass: bcopy from %p (%d) to %p, %d bytes\n",  
                                   &ip_reassbuf[i], i, q->payload, q->len > ip_reasslen - i? ip_reasslen - i: q->len));  
           bcopy(&ip_reassbuf[i], q->payload,  
                 q->len > ip_reasslen - i? ip_reasslen - i: q->len);  
           i += q->len;  
         }  
       }  
       DEBUGF(IP_REASS_DEBUG, ("ip_reass: p %p\n", p));  
       return p;  
     }  
   }  
   
  nullreturn:  
   pbuf_free(p);  
   return NULL;  
 }  
 #endif /* IP_REASSEMBLY */  
 /*-----------------------------------------------------------------------------------*/  
224  /* ip_input:  /* ip_input:
225   *   *
226   * This function is called by the network interface device driver when   * This function is called by the network interface device driver when
# Line 668  ip_output_if(struct pbuf *p, struct ip_a Line 507  ip_output_if(struct pbuf *p, struct ip_a
507      dest = &(iphdr->dest);      dest = &(iphdr->dest);
508    }    }
509    
510    #if IP_FRAG    
511      if (p->tot_len > netif->mtu)
512        return ip_frag(p,netif,dest);
513    #endif
514      
515  #ifdef IP_STATS  #ifdef IP_STATS
516    stats.ip.xmit++;    stats.ip.xmit++;
517  #endif /* IP_STATS */  #endif /* IP_STATS */

Legend:
Removed from v.1.3  
changed lines
  Added in v.1.4

savannah-hackers-public@gnu.org
ViewVC Help
Powered by ViewVC 1.1.26