File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / libnet / src / libnet_pblock.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Feb 21 22:14:23 2012 UTC (12 years, 5 months ago) by misho
Branches: libnet, MAIN
CVS tags: v1_1_2_1, HEAD
libnet

    1: /*
    2:  *  $Id: libnet_pblock.c,v 1.1.1.1 2012/02/21 22:14:23 misho Exp $
    3:  *
    4:  *  libnet
    5:  *  libnet_pblock.c - Memory protocol block routines.
    6:  *
    7:  *  Copyright (c) 1998 - 2004 Mike D. Schiffman <mike@infonexus.com>
    8:  *  All rights reserved.
    9:  *
   10:  * Redistribution and use in source and binary forms, with or without
   11:  * modification, are permitted provided that the following conditions
   12:  * are met:
   13:  * 1. Redistributions of source code must retain the above copyright
   14:  *    notice, this list of conditions and the following disclaimer.
   15:  * 2. Redistributions in binary form must reproduce the above copyright
   16:  *    notice, this list of conditions and the following disclaimer in the
   17:  *    documentation and/or other materials provided with the distribution.
   18:  *
   19:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   20:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   21:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   22:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   23:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   24:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   25:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   26:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   27:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   28:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   29:  * SUCH DAMAGE.
   30:  *
   31:  */
   32: 
   33: #if (HAVE_CONFIG_H)
   34: #include "../include/config.h"
   35: #endif
   36: #if (!(_WIN32) || (__CYGWIN__)) 
   37: #include "../include/libnet.h"
   38: #else
   39: #include "../include/win32/libnet.h"
   40: #endif
   41: 
   42: libnet_pblock_t *
   43: libnet_pblock_probe(libnet_t *l, libnet_ptag_t ptag, u_int32_t n, u_int8_t type)
   44: {
   45:     int offset;
   46:     libnet_pblock_t *p;
   47: 
   48:     if (ptag == LIBNET_PTAG_INITIALIZER)
   49:     {
   50:         /*
   51:          *  Create a new pblock and enough buffer space for the packet.
   52:          */
   53:         p = libnet_pblock_new(l, n);
   54:         if (p == NULL)
   55:         {
   56:             /* err msg set in libnet_pblock_new() */
   57:             return (NULL);
   58:         }
   59:     }
   60:     else
   61:     {
   62:         /*
   63:          *  Update this pblock, don't create a new one.  Note that if the
   64:          *  new packet size is larger than the old one we will do a malloc.
   65:          */
   66:         p = libnet_pblock_find(l, ptag);
   67: 
   68:         if (p == NULL)
   69:         {
   70:             /* err msg set in libnet_pblock_find() */
   71:             return (NULL);
   72:         }
   73:         if (p->type != type)
   74:         {
   75:             snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
   76:                "%s(): ptag refers to different type than expected (%d != %d)",
   77:                __func__, p->type, type);
   78:             return (NULL); 
   79:         }
   80:         /*
   81:          *  If size is greater than the original block of memory, we need 
   82:          *  to malloc more memory.  Should we use realloc?
   83:          */
   84:         if (n > p->b_len)
   85:         {
   86:             offset = n - p->b_len;  /* how many bytes larger new pblock is */
   87:             free(p->buf);
   88:             p->buf = malloc(n);
   89:             if (p->buf == NULL)
   90:             {
   91:                 snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
   92:                         "%s(): can't resize pblock buffer: %s\n", __func__,
   93:                         strerror(errno));
   94:                 return (NULL);
   95:             }
   96:             memset(p->buf, 0, n);
   97:             p->h_len += offset; /* new length for checksums */
   98:             p->b_len = n;       /* new buf len */
   99:             l->total_size += offset;
  100:         }
  101:         else
  102:         {
  103:             offset = p->b_len - n;
  104:             p->h_len -= offset; /* new length for checksums */
  105:             p->b_len = n;       /* new buf len */
  106:             l->total_size -= offset;
  107:         }
  108:         p->copied = 0;      /* reset copied counter */
  109:     }
  110:     return (p);
  111: }
  112: 
  113: libnet_pblock_t *
  114: libnet_pblock_new(libnet_t *l, u_int32_t size)
  115: {
  116:     libnet_pblock_t *p;
  117:     /*
  118:      *  Should we do error checking the size of the pblock here, or
  119:      *  should we rely on the underlying operating system to complain when
  120:      *  the user tries to write some ridiculously huge packet?
  121:      */
  122: 
  123:     /* make the head node if it doesn't exist */
  124:     if (l->protocol_blocks == NULL)
  125:     {
  126:         p = l->protocol_blocks = malloc(sizeof (libnet_pblock_t));
  127:         if (p == NULL)
  128:         {
  129:             goto bad;
  130:         }
  131:         memset(p, 0, sizeof (libnet_pblock_t));
  132:     }
  133:     else
  134:     {
  135:         p = l->pblock_end;
  136:         p->next = malloc(sizeof (libnet_pblock_t));
  137: 
  138:         if (p->next == NULL)
  139:         {
  140:             goto bad;
  141:         }
  142:         memset(p->next, 0, sizeof (libnet_pblock_t));
  143:         p->next->prev = p;
  144:         p = p->next;
  145:     }
  146: 
  147:     p->buf = malloc(size);
  148:     if (p->buf == NULL)
  149:     {
  150:         free(p);
  151:         p = NULL;
  152:         goto bad;
  153:     }
  154:     memset(p->buf, 0, size);
  155:     p->b_len      = size;
  156:     l->total_size += size;
  157:     l->n_pblocks++;
  158:     return (p);
  159: 
  160:     bad:
  161:     snprintf(l->err_buf, LIBNET_ERRBUF_SIZE, "%s(): malloc(): %s\n", __func__, 
  162:             strerror(errno));
  163:     return (NULL);
  164: }
  165: 
  166: int
  167: libnet_pblock_swap(libnet_t *l, libnet_ptag_t ptag1, libnet_ptag_t ptag2)
  168: {
  169:     libnet_pblock_t *p1, *p2;
  170: 
  171:     p1 = libnet_pblock_find(l, ptag1);
  172:     p2 = libnet_pblock_find(l, ptag2);
  173:     if (p1 == NULL || p2 == NULL)
  174:     {
  175:         /* error set elsewhere */
  176:         return (-1);
  177:     }
  178: 
  179:     p2->prev = p1->prev;
  180:     p1->next = p2->next;
  181:     p2->next = p1;
  182:     p1->prev = p2;
  183: 
  184:     if (p1->next)
  185:     {
  186:         p1->next->prev = p1;
  187:     }
  188: 
  189:     if (p2->prev)
  190:     {
  191:         p2->prev->next = p2;
  192:     }
  193:     else
  194:     {
  195:         /* first node on the list */
  196:         l->protocol_blocks = p2;
  197:     }
  198: 
  199:     if (l->pblock_end == p2)
  200:     {
  201:         l->pblock_end = p1;
  202:     }
  203:     return (1);
  204: }
  205: 
  206: int
  207: libnet_pblock_insert_before(libnet_t *l, libnet_ptag_t ptag1,
  208:         libnet_ptag_t ptag2)
  209: {
  210:     libnet_pblock_t *p1, *p2;
  211: 
  212:     p1 = libnet_pblock_find(l, ptag1);
  213:     p2 = libnet_pblock_find(l, ptag2);
  214:     if (p1 == NULL || p2 == NULL)
  215:     {
  216:         /* error set elsewhere */
  217:         return (-1);
  218:     }
  219: 
  220:     p2->prev = p1->prev;
  221:     p2->next = p1;
  222:     p1->prev = p2;
  223: 
  224:     if (p2->prev)  
  225:     {
  226:         p2->prev->next = p2;
  227:     }
  228:     else
  229:     {
  230:         /* first node on the list */
  231:         l->protocol_blocks = p2;
  232:     }
  233:     
  234:     return (1);
  235: }
  236: 
  237: libnet_pblock_t *
  238: libnet_pblock_find(libnet_t *l, libnet_ptag_t ptag)
  239: {
  240:     libnet_pblock_t *p;
  241: 
  242:     for (p = l->protocol_blocks; p; p = p->next)
  243:     {
  244:         if (p->ptag == ptag)
  245:         {
  246:             return (p); 
  247:         }
  248:     }
  249:     snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
  250:             "%s(): couldn't find protocol block\n", __func__);
  251:     return (NULL);
  252: }
  253: 
  254: int
  255: libnet_pblock_append(libnet_t *l, libnet_pblock_t *p, u_int8_t *buf,
  256:             u_int32_t len)
  257: {
  258:     if (p->copied + len > p->b_len)
  259:     {
  260:         snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
  261:                 "%s(): memcpy would overflow buffer\n", __func__);
  262:         return (-1);
  263:     }
  264:     memcpy(p->buf + p->copied, buf, len);
  265:     p->copied += len;
  266:     return (1);
  267: }
  268: 
  269: void
  270: libnet_pblock_setflags(libnet_pblock_t *p, u_int8_t flags)
  271: {
  272:     p->flags = flags;
  273: }
  274: 
  275: libnet_ptag_t
  276: libnet_pblock_update(libnet_t *l, libnet_pblock_t *p, u_int32_t h,
  277: u_int8_t type)
  278: {
  279:     p->type  =  type;
  280:     p->ptag  =  ++(l->ptag_state);
  281:     p->h_len = h;
  282:     l->pblock_end = p;              /* point end of pblock list here */
  283: 
  284:     return (p->ptag);
  285: }
  286: 
  287: int
  288: libnet_pblock_coalesce(libnet_t *l, u_int8_t **packet, u_int32_t *size)
  289: {
  290:     libnet_pblock_t *p, *q;
  291:     u_int32_t c, n;
  292: 
  293:     /*
  294:      *  Determine the offset required to keep memory aligned (strict
  295:      *  architectures like solaris enforce this, but's a good practice
  296:      *  either way).  This is only required on the link layer with the
  297:      *  14 byte ethernet offset (others are similarly unkind).
  298:      */
  299:     if (l->injection_type == LIBNET_LINK || 
  300:         l->injection_type == LIBNET_LINK_ADV)
  301:     {
  302:         /* 8 byte alignment should work */
  303:         l->aligner = 8 - (l->link_offset % 8);
  304:     }
  305:     else
  306:     {
  307:         l->aligner = 0;
  308:     }
  309: 
  310:     *packet = malloc(l->aligner + l->total_size);
  311:     if (*packet == NULL)
  312:     {
  313:         snprintf(l->err_buf, LIBNET_ERRBUF_SIZE, "%s(): malloc(): %s\n",
  314:                 __func__, strerror(errno));
  315:         return (-1);
  316:     }
  317: 
  318:     memset(*packet, 0, l->aligner + l->total_size);
  319: 
  320:     if (l->injection_type == LIBNET_RAW4 && 
  321:         l->pblock_end->type == LIBNET_PBLOCK_IPV4_H)
  322:     {
  323:         libnet_pblock_setflags(l->pblock_end, LIBNET_PBLOCK_DO_CHECKSUM); 
  324:     }
  325:     
  326:     /* additional sanity checks to perform if we're not in advanced mode */
  327:     if (!(l->injection_type & LIBNET_ADV_MASK))
  328:     {
  329:     	switch (l->injection_type)
  330:     	{
  331:             case LIBNET_LINK:
  332:                 if ((l->pblock_end->type != LIBNET_PBLOCK_TOKEN_RING_H) &&
  333:                     (l->pblock_end->type != LIBNET_PBLOCK_FDDI_H)       &&
  334:                     (l->pblock_end->type != LIBNET_PBLOCK_ETH_H)        &&
  335:                     (l->pblock_end->type != LIBNET_PBLOCK_802_1Q_H)     &&
  336:                     (l->pblock_end->type != LIBNET_PBLOCK_ISL_H)        &&
  337:                     (l->pblock_end->type != LIBNET_PBLOCK_802_3_H))
  338:                 {
  339:                     snprintf(l->err_buf, LIBNET_ERRBUF_SIZE, 
  340:                     "%s(): packet assembly cannot find a layer 2 header\n",
  341:                     __func__);
  342:                     return (-1);
  343:                 }
  344:                 break;
  345:             case LIBNET_RAW4:
  346:                 if ((l->pblock_end->type != LIBNET_PBLOCK_IPV4_H))
  347:                 {
  348:                     snprintf(l->err_buf, LIBNET_ERRBUF_SIZE, 
  349:                     "%s(): packet assembly cannot find an IPv4 header\n",
  350:                      __func__);
  351:                     return (-1);
  352:                 }
  353:                 break;
  354:             case LIBNET_RAW6:
  355:                 if ((l->pblock_end->type != LIBNET_PBLOCK_IPV6_H))
  356:                 {
  357:                     snprintf(l->err_buf, LIBNET_ERRBUF_SIZE, 
  358:                     "%s(): packet assembly cannot find an IPv6 header\n",
  359:                      __func__);
  360:                     return (-1);
  361:                 }
  362:                 break;
  363:             default:
  364:                 /* we should not end up here ever */
  365:                 snprintf(l->err_buf, LIBNET_ERRBUF_SIZE, 
  366:                 "%s(): suddenly the dungeon collapses -- you die\n",
  367:                  __func__);
  368:                 return (-1);
  369:             break;
  370:         }
  371:     }
  372: 
  373:     q = NULL; 
  374:     for (n = l->aligner + l->total_size, p = l->protocol_blocks; p || q; )
  375:     {
  376:         if (q)
  377:         {
  378:             p = p->next;
  379:         }
  380:         if (p)
  381:         {
  382:             n -= p->b_len;
  383:             /* copy over the packet chunk */
  384:             memcpy(*packet + n, p->buf, p->b_len);
  385:         }
  386:         if (q)
  387:         {
  388:             if (p == NULL || ((p->flags) & LIBNET_PBLOCK_DO_CHECKSUM))
  389:             {
  390:                 if ((q->flags) & LIBNET_PBLOCK_DO_CHECKSUM)
  391:                 {
  392:                     int offset = (l->total_size + l->aligner) - q->ip_offset;
  393:                     c = libnet_do_checksum(l, *packet + offset,
  394:                             libnet_pblock_p2p(q->type), q->h_len);
  395:                     if (c == -1)
  396:                     {
  397:                         /* err msg set in libnet_do_checksum() */
  398:                         return (-1);
  399:                     }
  400:                 }
  401:                 q = p;
  402:             }
  403:         }
  404:         else
  405:         {
  406:             q = p;
  407:         }
  408:     }
  409:     *size = l->aligner + l->total_size;
  410: 
  411:     /*
  412:      *  Set the packet pointer to the true beginning of the packet and set
  413:      *  the size for transmission.
  414:      */
  415:     if ((l->injection_type == LIBNET_LINK ||
  416:         l->injection_type == LIBNET_LINK_ADV) && l->aligner)
  417:     {
  418:         *packet += l->aligner;
  419:         *size -= l->aligner;
  420:     }
  421:     return (1);
  422: }
  423: 
  424: void
  425: libnet_pblock_delete(libnet_t *l, libnet_pblock_t *p)
  426: {
  427:     if (p)
  428:     {
  429:         l->total_size -= p->b_len;
  430:         l->n_pblocks--;
  431:         if (p->prev) 
  432:         {
  433:             p->prev->next = p->next;
  434:         }
  435:         else
  436:         {
  437:             l->protocol_blocks = p->next;
  438:         }
  439: 
  440:         if (p->next)
  441:         {
  442:             p->next->prev = p->prev;
  443:         }
  444:         else
  445:         {
  446:             l->pblock_end = p->prev;
  447:         }
  448: 
  449:         if (p->buf)
  450:         {
  451:           free(p->buf);
  452:         }
  453: 
  454:         free(p);
  455:         p = NULL;
  456:     }
  457: }
  458: 
  459: int
  460: libnet_pblock_p2p(u_int8_t type)
  461: {
  462:     /* for checksum; return the protocol number given a pblock type*/
  463:     switch (type)
  464:     {
  465:         case LIBNET_PBLOCK_CDP_H:
  466:             return (LIBNET_PROTO_CDP);
  467:         case LIBNET_PBLOCK_ICMPV4_H:
  468:         case LIBNET_PBLOCK_ICMPV4_ECHO_H:
  469:         case LIBNET_PBLOCK_ICMPV4_MASK_H:
  470:         case LIBNET_PBLOCK_ICMPV4_UNREACH_H:
  471:         case LIBNET_PBLOCK_ICMPV4_TIMXCEED_H:
  472:         case LIBNET_PBLOCK_ICMPV4_REDIRECT_H:
  473:         case LIBNET_PBLOCK_ICMPV4_TS_H:
  474:             return (IPPROTO_ICMP);
  475:         case LIBNET_PBLOCK_IGMP_H:
  476:             return (IPPROTO_IGMP);
  477:         case LIBNET_PBLOCK_IPV4_H:
  478:             return (IPPROTO_IP);
  479:         case LIBNET_ISL_H:
  480:             return (LIBNET_PROTO_ISL);
  481:         case LIBNET_PBLOCK_OSPF_H:
  482:             return (IPPROTO_OSPF);
  483:         case LIBNET_PBLOCK_LS_RTR_H:
  484:             return (IPPROTO_OSPF_LSA);
  485:         case LIBNET_PBLOCK_TCP_H:
  486:             return (IPPROTO_TCP);
  487:         case LIBNET_PBLOCK_UDP_H:
  488:             return (IPPROTO_UDP);
  489:         case LIBNET_PBLOCK_VRRP_H:
  490:             return (IPPROTO_VRRP);
  491:         case LIBNET_PBLOCK_GRE_H:
  492:             return (IPPROTO_GRE);
  493:         default:
  494:             return (-1);
  495:     }
  496: }
  497: 
  498: void
  499: libnet_pblock_record_ip_offset(libnet_t *l, u_int32_t offset)
  500: {
  501:     libnet_pblock_t *p = l->pblock_end;
  502: 
  503:     do
  504:     {
  505:         p->ip_offset = offset;
  506:         p = p->prev;
  507:     } while (p && p->type != LIBNET_PBLOCK_IPV4_H);
  508: }
  509: 
  510: 
  511: /* EOF */

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