Diff for /embedaddon/libnet/src/libnet_pblock.c between versions 1.1.1.1 and 1.1.1.2

version 1.1.1.1, 2012/02/21 22:14:23 version 1.1.1.2, 2013/07/22 11:54:42
Line 38 Line 38
 #else  #else
 #include "../include/win32/libnet.h"  #include "../include/win32/libnet.h"
 #endif  #endif
   #include <assert.h>
   
 libnet_pblock_t *  libnet_pblock_t *
libnet_pblock_probe(libnet_t *l, libnet_ptag_t ptag, u_int32_t n, u_int8_t type)libnet_pblock_probe(libnet_t *l, libnet_ptag_t ptag, uint32_t b_len, uint8_t type)
 {  {
     int offset;      int offset;
     libnet_pblock_t *p;      libnet_pblock_t *p;
   
     if (ptag == LIBNET_PTAG_INITIALIZER)      if (ptag == LIBNET_PTAG_INITIALIZER)
     {      {
        /*        return libnet_pblock_new(l, b_len);
         *  Create a new pblock and enough buffer space for the packet.    }
         */
        p = libnet_pblock_new(l, n);    /*
        if (p == NULL)     *  Update this pblock, don't create a new one.  Note that if the
      *  new packet size is larger than the old one we will do a malloc.
      */
     p = libnet_pblock_find(l, ptag);
 
     if (p == NULL)
     {
         /* err msg set in libnet_pblock_find() */
         return (NULL);
     }
     if (p->type != type)
     {
         snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
                 "%s(): ptag refers to different type than expected (0x%x != 0x%x)",
                 __func__, p->type, type);
         return (NULL); 
     }
     /*
      *  If size is greater than the original block of memory, we need 
      *  to malloc more memory.  Should we use realloc?
      */
     if (b_len > p->b_len)
     {
         offset = b_len - p->b_len;  /* how many bytes larger new pblock is */
         free(p->buf);
         p->buf = malloc(b_len);
         if (p->buf == NULL)
         {          {
            /* err msg set in libnet_pblock_new() */            snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
                     "%s(): can't resize pblock buffer: %s\n", __func__,
                     strerror(errno));
             return (NULL);              return (NULL);
         }          }
           memset(p->buf, 0, b_len);
           p->h_len += offset; /* new length for checksums */
           p->b_len = b_len;       /* new buf len */
           l->total_size += offset;
     }      }
     else      else
     {      {
        /*        offset = p->b_len - b_len;
         *  Update this pblock, don't create a new one.  Note that if the        p->h_len -= offset; /* new length for checksums */
         *  new packet size is larger than the old one we will do a malloc.        p->b_len = b_len;       /* new buf len */
         */        l->total_size -= offset;
        p = libnet_pblock_find(l, ptag); 
 
        if (p == NULL) 
        { 
            /* err msg set in libnet_pblock_find() */ 
            return (NULL); 
        } 
        if (p->type != type) 
        { 
            snprintf(l->err_buf, LIBNET_ERRBUF_SIZE, 
               "%s(): ptag refers to different type than expected (%d != %d)", 
               __func__, p->type, type); 
            return (NULL);  
        } 
        /* 
         *  If size is greater than the original block of memory, we need  
         *  to malloc more memory.  Should we use realloc? 
         */ 
        if (n > p->b_len) 
        { 
            offset = n - p->b_len;  /* how many bytes larger new pblock is */ 
            free(p->buf); 
            p->buf = malloc(n); 
            if (p->buf == NULL) 
            { 
                snprintf(l->err_buf, LIBNET_ERRBUF_SIZE, 
                        "%s(): can't resize pblock buffer: %s\n", __func__, 
                        strerror(errno)); 
                return (NULL); 
            } 
            memset(p->buf, 0, n); 
            p->h_len += offset; /* new length for checksums */ 
            p->b_len = n;       /* new buf len */ 
            l->total_size += offset; 
        } 
        else 
        { 
            offset = p->b_len - n; 
            p->h_len -= offset; /* new length for checksums */ 
            p->b_len = n;       /* new buf len */ 
            l->total_size -= offset; 
        } 
        p->copied = 0;      /* reset copied counter */ 
     }      }
       p->copied = 0;      /* reset copied counter */
   
     return (p);      return (p);
 }  }
   
   static void* zmalloc(libnet_t* l, uint32_t size, const char* func)
   {
       void* v = malloc(size);
       if(v)
           memset(v, 0, size);
       else
           snprintf(l->err_buf, LIBNET_ERRBUF_SIZE, "%s(): malloc(): %s\n", func, 
                   strerror(errno));
       return v;
   }
   
 libnet_pblock_t *  libnet_pblock_t *
libnet_pblock_new(libnet_t *l, u_int32_t size)libnet_pblock_new(libnet_t *l, uint32_t b_len)
 {  {
    libnet_pblock_t *p;    libnet_pblock_t *p = zmalloc(l, sizeof(libnet_pblock_t), __func__);
    /*    if(!p)
     *  Should we do error checking the size of the pblock here, or        return NULL;
     *  should we rely on the underlying operating system to complain when 
     *  the user tries to write some ridiculously huge packet? 
     */ 
   
       p->buf = zmalloc(l, b_len, __func__);
   
       if(!p->buf)
       {
           free(p);
           return NULL;
       }
   
       p->b_len = b_len;
   
       l->total_size += b_len;
       l->n_pblocks++;
   
     /* make the head node if it doesn't exist */      /* make the head node if it doesn't exist */
     if (l->protocol_blocks == NULL)      if (l->protocol_blocks == NULL)
     {      {
        p = l->protocol_blocks = malloc(sizeof (libnet_pblock_t));        l->protocol_blocks = p;
        if (p == NULL)        l->pblock_end = p;
        { 
            goto bad; 
        } 
        memset(p, 0, sizeof (libnet_pblock_t)); 
     }      }
     else      else
     {      {
        p = l->pblock_end;        l->pblock_end->next = p;
        p->next = malloc(sizeof (libnet_pblock_t));        p->prev = l->pblock_end;
        l->pblock_end = p;
        if (p->next == NULL) 
        { 
            goto bad; 
        } 
        memset(p->next, 0, sizeof (libnet_pblock_t)); 
        p->next->prev = p; 
        p = p->next; 
     }      }
   
    p->buf = malloc(size);    return p;
    if (p->buf == NULL) 
    { 
        free(p); 
        p = NULL; 
        goto bad; 
    } 
    memset(p->buf, 0, size); 
    p->b_len      = size; 
    l->total_size += size; 
    l->n_pblocks++; 
    return (p); 
 
    bad: 
    snprintf(l->err_buf, LIBNET_ERRBUF_SIZE, "%s(): malloc(): %s\n", __func__,  
            strerror(errno)); 
    return (NULL); 
 }  }
   
 int  int
Line 203  libnet_pblock_swap(libnet_t *l, libnet_ptag_t ptag1, l Line 189  libnet_pblock_swap(libnet_t *l, libnet_ptag_t ptag1, l
     return (1);      return (1);
 }  }
   
   static void libnet_pblock_remove_from_list(libnet_t *l, libnet_pblock_t *p)
   {
       if (p->prev) 
       {
           p->prev->next = p->next;
       }
       else
       {
           l->protocol_blocks = p->next;
       }
   
       if (p->next)
       {
           p->next->prev = p->prev;
       }
       else
       {
           l->pblock_end = p->prev;
       }
   }
   
 int  int
 libnet_pblock_insert_before(libnet_t *l, libnet_ptag_t ptag1,  libnet_pblock_insert_before(libnet_t *l, libnet_ptag_t ptag1,
         libnet_ptag_t ptag2)          libnet_ptag_t ptag2)
Line 217  libnet_pblock_insert_before(libnet_t *l, libnet_ptag_t Line 224  libnet_pblock_insert_before(libnet_t *l, libnet_ptag_t
         return (-1);          return (-1);
     }      }
   
       /* check for already present before */
       if(p2->next == p1)
           return 1;
   
       libnet_pblock_remove_from_list(l, p2);
   
       /* insert p2 into list */
     p2->prev = p1->prev;      p2->prev = p1->prev;
     p2->next = p1;      p2->next = p1;
     p1->prev = p2;      p1->prev = p2;
Line 252  libnet_pblock_find(libnet_t *l, libnet_ptag_t ptag) Line 266  libnet_pblock_find(libnet_t *l, libnet_ptag_t ptag)
 }  }
   
 int  int
libnet_pblock_append(libnet_t *l, libnet_pblock_t *p, u_int8_t *buf,libnet_pblock_append(libnet_t *l, libnet_pblock_t *p, const void *buf, uint32_t len)
            u_int32_t len) 
 {  {
       if (len && !buf)
       {
           snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
                               "%s(): payload inconsistency\n", __func__);
           return -1;
       }
   
     if (p->copied + len > p->b_len)      if (p->copied + len > p->b_len)
     {      {
         snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,          snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
Line 267  libnet_pblock_append(libnet_t *l, libnet_pblock_t *p,  Line 287  libnet_pblock_append(libnet_t *l, libnet_pblock_t *p, 
 }  }
   
 void  void
libnet_pblock_setflags(libnet_pblock_t *p, u_int8_t flags)libnet_pblock_setflags(libnet_pblock_t *p, uint8_t flags)
 {  {
     p->flags = flags;      p->flags = flags;
 }  }
   
   /* FIXME both ptag setting and end setting should be done in pblock new and/or pblock probe. */
 libnet_ptag_t  libnet_ptag_t
libnet_pblock_update(libnet_t *l, libnet_pblock_t *p, u_int32_t h,libnet_pblock_update(libnet_t *l, libnet_pblock_t *p, uint32_t h_len, uint8_t type)
u_int8_t type) 
 {  {
     p->type  =  type;      p->type  =  type;
     p->ptag  =  ++(l->ptag_state);      p->ptag  =  ++(l->ptag_state);
    p->h_len = h;    p->h_len = h_len;
     l->pblock_end = p;              /* point end of pblock list here */      l->pblock_end = p;              /* point end of pblock list here */
   
     return (p->ptag);      return (p->ptag);
 }  }
   
intstatic int pblock_is_ip(libnet_pblock_t* p)
libnet_pblock_coalesce(libnet_t *l, u_int8_t **packet, u_int32_t *size) 
 {  {
    libnet_pblock_t *p, *q;    return p->type == LIBNET_PBLOCK_IPV4_H || p->type == LIBNET_PBLOCK_IPV6_H;
    u_int32_t c, n;}
   
   /* q is either an ip hdr, or is followed  by an ip hdr. return the offset
    * from end of packet. if there is no offset, we'll return the total size,
    * and things will break later
    */
   static int calculate_ip_offset(libnet_t* l, libnet_pblock_t* q)
   {
       int ip_offset = 0;
       libnet_pblock_t* p = l->protocol_blocks;
       for(; p && p != q; p = p->next) {
           ip_offset += p->b_len;
       }
       assert(p == q); /* if not true, then q is not a pblock! */
   
       for(; p; p = p->next) {
           ip_offset += p->b_len;
           if(pblock_is_ip(p))
               break;
       }
   
       return ip_offset;
   }
   
   int
   libnet_pblock_coalesce(libnet_t *l, uint8_t **packet, uint32_t *size)
   {
     /*      /*
      *  Determine the offset required to keep memory aligned (strict       *  Determine the offset required to keep memory aligned (strict
      *  architectures like solaris enforce this, but's a good practice       *  architectures like solaris enforce this, but's a good practice
Line 307  libnet_pblock_coalesce(libnet_t *l, u_int8_t **packet, Line 351  libnet_pblock_coalesce(libnet_t *l, u_int8_t **packet,
         l->aligner = 0;          l->aligner = 0;
     }      }
   
    *packet = malloc(l->aligner + l->total_size);    if(!l->total_size && !l->aligner) {
         /* Avoid allocating zero bytes of memory, it perturbs electric fence. */
         *packet = malloc(1);
         **packet =1;
     } else {
         *packet = malloc(l->aligner + l->total_size);
     }
     if (*packet == NULL)      if (*packet == NULL)
     {      {
         snprintf(l->err_buf, LIBNET_ERRBUF_SIZE, "%s(): malloc(): %s\n",          snprintf(l->err_buf, LIBNET_ERRBUF_SIZE, "%s(): malloc(): %s\n",
Line 339  libnet_pblock_coalesce(libnet_t *l, u_int8_t **packet, Line 389  libnet_pblock_coalesce(libnet_t *l, u_int8_t **packet,
                     snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,                       snprintf(l->err_buf, LIBNET_ERRBUF_SIZE, 
                     "%s(): packet assembly cannot find a layer 2 header\n",                      "%s(): packet assembly cannot find a layer 2 header\n",
                     __func__);                      __func__);
                    return (-1);                    goto err;
                 }                  }
                 break;                  break;
             case LIBNET_RAW4:              case LIBNET_RAW4:
Line 348  libnet_pblock_coalesce(libnet_t *l, u_int8_t **packet, Line 398  libnet_pblock_coalesce(libnet_t *l, u_int8_t **packet,
                     snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,                       snprintf(l->err_buf, LIBNET_ERRBUF_SIZE, 
                     "%s(): packet assembly cannot find an IPv4 header\n",                      "%s(): packet assembly cannot find an IPv4 header\n",
                      __func__);                       __func__);
                    return (-1);                    goto err;
                 }                  }
                 break;                  break;
             case LIBNET_RAW6:              case LIBNET_RAW6:
Line 357  libnet_pblock_coalesce(libnet_t *l, u_int8_t **packet, Line 407  libnet_pblock_coalesce(libnet_t *l, u_int8_t **packet,
                     snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,                       snprintf(l->err_buf, LIBNET_ERRBUF_SIZE, 
                     "%s(): packet assembly cannot find an IPv6 header\n",                      "%s(): packet assembly cannot find an IPv6 header\n",
                      __func__);                       __func__);
                    return (-1);                    goto err;
                 }                  }
                 break;                  break;
             default:              default:
Line 365  libnet_pblock_coalesce(libnet_t *l, u_int8_t **packet, Line 415  libnet_pblock_coalesce(libnet_t *l, u_int8_t **packet,
                 snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,                   snprintf(l->err_buf, LIBNET_ERRBUF_SIZE, 
                 "%s(): suddenly the dungeon collapses -- you die\n",                  "%s(): suddenly the dungeon collapses -- you die\n",
                  __func__);                   __func__);
                return (-1);                goto err;
             break;              break;
         }          }
     }      }
   
    q = NULL;     /* Build packet from end to start. */
    for (n = l->aligner + l->total_size, p = l->protocol_blocks; p || q; ) 
     {      {
        if (q)        /*
            From top to bottom, go through pblocks pairwise:
 
            p   is the currently being copied pblock, and steps through every block
            q   is the prev pblock to p that needs checksumming, it will
                not step through every block as p does, it will skip any that do not
                need checksumming.
            n   offset from start of packet to beginning of block we are writing
 
            q is NULL on first iteration
            p is NULL on last iteration
 
            Checksums are done on q, to give p a chance to be copied over, since
            checksumming q can require a lower-level header to be encoded, in the
            case of IP protocols (which are the only kinds handled by libnet's
            checksum implementation).
 
            This is very obscure, or would be much more clear if it was done in
            two loops.
            */
         libnet_pblock_t *q = NULL;
         libnet_pblock_t *p = NULL;
         uint32_t n;
 
         for (n = l->aligner + l->total_size, p = l->protocol_blocks; p || q; )
         {          {
            p = p->next;            if (q)
        } 
        if (p) 
        { 
            n -= p->b_len; 
            /* copy over the packet chunk */ 
            memcpy(*packet + n, p->buf, p->b_len); 
        } 
        if (q) 
        { 
            if (p == NULL || ((p->flags) & LIBNET_PBLOCK_DO_CHECKSUM)) 
             {              {
                if ((q->flags) & LIBNET_PBLOCK_DO_CHECKSUM)                p = p->next;
             }
             if (p)
             {
                 n -= p->b_len;
                 /* copy over the packet chunk */
                 memcpy(*packet + n, p->buf, p->b_len);
             }
 #if 0
             printf("-- n %d/%d cksum? %d\n", n, l->aligner + l->total_size,
                     q &&
                     (p == NULL || (p->flags & LIBNET_PBLOCK_DO_CHECKSUM)) &&
                     (q->flags & LIBNET_PBLOCK_DO_CHECKSUM));
             if(q)
             {
                 printf(" iph %d/%d offset -%d\n",
                         (l->total_size + l->aligner) - q->ip_offset,
                         l->total_size + l->aligner,
                         q->ip_offset
                       );
             }
             if (p)
             {
                 printf("p %p ptag %d b_len %d h_len %d cksum? %d type %s\n",
                         p, p->ptag,
                         p->b_len, p->h_len,
                         p->flags & LIBNET_PBLOCK_DO_CHECKSUM,
                         libnet_diag_dump_pblock_type(p->type)
                       );
             }
             if (q)
             {
                 printf("q %p ptag %d b_len %d h_len %d cksum? %d type %s\n",
                         q, q->ptag,
                         q->b_len, q->h_len,
                         q->flags & LIBNET_PBLOCK_DO_CHECKSUM,
                         libnet_diag_dump_pblock_type(q->type)
                       );
             }
 #endif
             if (q)
             {
                 if (p == NULL || (p->flags & LIBNET_PBLOCK_DO_CHECKSUM))
                 {                  {
                    int offset = (l->total_size + l->aligner) - q->ip_offset;                    if (q->flags & LIBNET_PBLOCK_DO_CHECKSUM)
                    c = libnet_do_checksum(l, *packet + offset, 
                            libnet_pblock_p2p(q->type), q->h_len); 
                    if (c == -1) 
                     {                      {
                        /* err msg set in libnet_do_checksum() */                        uint32_t c;
                        return (-1);                        uint8_t* end = *packet + l->aligner + l->total_size;
                         uint8_t* beg = *packet + n;
                         int ip_offset = calculate_ip_offset(l, q);
                         uint8_t* iph = end - ip_offset;
 #if 0
                         printf("p %d/%s q %d/%s offset calculated %d\n",
                                 p ? p->ptag : -1, p ? libnet_diag_dump_pblock_type(p->type) : "nil",
                                 q->ptag, libnet_diag_dump_pblock_type(q->type),
                                 ip_offset);
 #endif
                         c = libnet_inet_checksum(l, iph,
                                 libnet_pblock_p2p(q->type), q->h_len,
                                 beg, end);
                         if (c == -1)
                         {
                             /* err msg set in libnet_do_checksum() */
                             goto err;
                         }
                     }                      }
                       q = p;
                 }                  }
               }
               else
               {
                 q = p;                  q = p;
             }              }
         }          }
         else  
         {  
             q = p;  
         }  
     }      }
     *size = l->aligner + l->total_size;      *size = l->aligner + l->total_size;
   
Line 419  libnet_pblock_coalesce(libnet_t *l, u_int8_t **packet, Line 538  libnet_pblock_coalesce(libnet_t *l, u_int8_t **packet,
         *size -= l->aligner;          *size -= l->aligner;
     }      }
     return (1);      return (1);
   
   err:
       free(*packet);
       *packet = NULL;
       return (-1);
 }  }
   
 void  void
Line 428  libnet_pblock_delete(libnet_t *l, libnet_pblock_t *p) Line 552  libnet_pblock_delete(libnet_t *l, libnet_pblock_t *p)
     {      {
         l->total_size -= p->b_len;          l->total_size -= p->b_len;
         l->n_pblocks--;          l->n_pblocks--;
         if (p->prev)   
         {  
             p->prev->next = p->next;  
         }  
         else  
         {  
             l->protocol_blocks = p->next;  
         }  
   
        if (p->next)        libnet_pblock_remove_from_list(l, p);
        { 
            p->next->prev = p->prev; 
        } 
        else 
        { 
            l->pblock_end = p->prev; 
        } 
   
         if (p->buf)          if (p->buf)
         {          {
          free(p->buf);            free(p->buf);
             p->buf = NULL;
         }          }
   
         free(p);          free(p);
         p = NULL;  
     }      }
 }  }
   
 int  int
libnet_pblock_p2p(u_int8_t type)libnet_pblock_p2p(uint8_t type)
 {  {
     /* for checksum; return the protocol number given a pblock type*/      /* for checksum; return the protocol number given a pblock type*/
     switch (type)      switch (type)
Line 472  libnet_pblock_p2p(u_int8_t type) Line 581  libnet_pblock_p2p(u_int8_t type)
         case LIBNET_PBLOCK_ICMPV4_REDIRECT_H:          case LIBNET_PBLOCK_ICMPV4_REDIRECT_H:
         case LIBNET_PBLOCK_ICMPV4_TS_H:          case LIBNET_PBLOCK_ICMPV4_TS_H:
             return (IPPROTO_ICMP);              return (IPPROTO_ICMP);
           case LIBNET_PBLOCK_ICMPV6_H:
           case LIBNET_PBLOCK_ICMPV6_ECHO_H:
           case LIBNET_PBLOCK_ICMPV6_UNREACH_H:
           case LIBNET_PBLOCK_ICMPV6_NDP_NSOL_H:
           case LIBNET_PBLOCK_ICMPV6_NDP_NADV_H:
               return (IPPROTO_ICMPV6);
         case LIBNET_PBLOCK_IGMP_H:          case LIBNET_PBLOCK_IGMP_H:
             return (IPPROTO_IGMP);              return (IPPROTO_IGMP);
         case LIBNET_PBLOCK_IPV4_H:          case LIBNET_PBLOCK_IPV4_H:
             return (IPPROTO_IP);              return (IPPROTO_IP);
           case LIBNET_PBLOCK_IPV6_H:
               return (IPPROTO_IPV6);
         case LIBNET_ISL_H:          case LIBNET_ISL_H:
             return (LIBNET_PROTO_ISL);              return (LIBNET_PROTO_ISL);
         case LIBNET_PBLOCK_OSPF_H:          case LIBNET_PBLOCK_OSPF_H:
Line 496  libnet_pblock_p2p(u_int8_t type) Line 613  libnet_pblock_p2p(u_int8_t type)
 }  }
   
 void  void
libnet_pblock_record_ip_offset(libnet_t *l, u_int32_t offset)libnet_pblock_record_ip_offset(libnet_t *l, libnet_pblock_t *p)
 {  {
    libnet_pblock_t *p = l->pblock_end;    (void) l;
    (void) p;
    do    /* For backwards compatibility, libnet_pblock_t no longer includes
    {       an ip_offset, so calling this is unnecessary.
        p->ip_offset = offset;       */
        p = p->prev; 
    } while (p && p->type != LIBNET_PBLOCK_IPV4_H); 
 }  }
   
   
 /* EOF */  

Removed from v.1.1.1.1  
changed lines
  Added in v.1.1.1.2


FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>