File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / libnet / src / libnet_build_ip.c
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Mon Jul 22 11:54:42 2013 UTC (10 years, 11 months ago) by misho
Branches: libnet, MAIN
CVS tags: v1_1_6p5, v1_1_6p4, v1_1_6p0, v1_1_6, HEAD
1.1.6

    1: /*
    2:  *  $Id: libnet_build_ip.c,v 1.1.1.2 2013/07/22 11:54:42 misho Exp $
    3:  *
    4:  *  libnet
    5:  *  libnet_build_ip.c - IP packet assembler
    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: 
   43: /* TODO len - should be calculated if -1 */
   44: libnet_ptag_t
   45: libnet_build_ipv4(uint16_t ip_len, uint8_t tos, uint16_t id, uint16_t frag,
   46: uint8_t ttl, uint8_t prot, uint16_t sum, uint32_t src, uint32_t dst,
   47: const uint8_t *payload, uint32_t payload_s, libnet_t *l, libnet_ptag_t ptag)
   48: {
   49:     uint32_t n = LIBNET_IPV4_H; /* size of memory block */
   50:     libnet_pblock_t *p, *p_data, *p_temp;
   51:     struct libnet_ipv4_hdr ip_hdr;
   52:     libnet_ptag_t ptag_data = 0; /* used if there is ipv4 payload */
   53:     libnet_ptag_t ptag_hold;
   54: 
   55:     if (l == NULL)
   56:     { 
   57:         return (-1);
   58:     } 
   59: 
   60:     /*
   61:      *  Find the existing protocol block if a ptag is specified, or create
   62:      *  a new one.
   63:      */
   64:     p = libnet_pblock_probe(l, ptag, n, LIBNET_PBLOCK_IPV4_H);
   65:     if (p == NULL)
   66:     {
   67:         return (-1);
   68:     }
   69: 
   70:     memset(&ip_hdr, 0, sizeof(ip_hdr));
   71:     ip_hdr.ip_v          = 4;      /* version 4 */
   72:     ip_hdr.ip_hl         = 5;      /* 20 byte header,  measured in 32-bit words */
   73: 
   74:     /* check to see if there are IP options to include */
   75:     if (p->prev)
   76:     {
   77:         if (p->prev->type == LIBNET_PBLOCK_IPO_H)
   78:         {
   79:             /* IPO block's length must be multiple of 4, or it's incorrectly
   80:              * padded, in which case there is no "correct" IP header length,
   81:              * it will too short or too long, we choose too short.
   82:              */
   83:             ip_hdr.ip_hl += p->prev->b_len / 4;
   84:         }
   85:     }
   86:     /* Note that p->h_len is not adjusted. This seems a bug, but it is because
   87:      * it is not used!  libnet_do_checksum() is passed the h_len (as `len'),
   88:      * but for IPPROTO_IP it is ignored in favor of the ip_hl.
   89:      */
   90: 
   91:     ip_hdr.ip_tos        = tos;                       /* IP tos */
   92:     ip_hdr.ip_len        = htons(ip_len);             /* total length */
   93:     ip_hdr.ip_id         = htons(id);                 /* IP ID */
   94:     ip_hdr.ip_off        = htons(frag);               /* fragmentation flags */
   95:     ip_hdr.ip_ttl        = ttl;                       /* time to live */
   96:     ip_hdr.ip_p          = prot;                      /* transport protocol */
   97:     ip_hdr.ip_sum        = (sum ? htons(sum) : 0);    /* checksum */
   98:     ip_hdr.ip_src.s_addr = src;                       /* source ip */
   99:     ip_hdr.ip_dst.s_addr = dst;                       /* destination ip */
  100:     
  101:     n = libnet_pblock_append(l, p, (uint8_t *)&ip_hdr, LIBNET_IPV4_H);
  102:     if (n == -1)
  103:     {
  104:         goto bad;
  105:     }
  106: 
  107:     /* save the original ptag value */
  108:     ptag_hold = ptag;
  109: 
  110:     if (ptag == LIBNET_PTAG_INITIALIZER)
  111:     {
  112:         ptag = libnet_pblock_update(l, p, LIBNET_IPV4_H, LIBNET_PBLOCK_IPV4_H);
  113:     }
  114: 
  115:     /* find and set the appropriate ptag, or else use the default of 0 */
  116:     /* When updating the ipv4 block, we need to find the data block, and
  117:      * adjust our ip_offset if the new payload size is different from what
  118:      * it used to be.
  119:      */
  120:     if (ptag_hold && p->prev)
  121:     {
  122:         p_temp = p->prev;
  123:         while (p_temp->prev &&
  124:               (p_temp->type != LIBNET_PBLOCK_IPDATA) &&
  125:               (p_temp->type != LIBNET_PBLOCK_IPV4_H))
  126:         {
  127:             p_temp = p_temp->prev;
  128:         }
  129: 
  130:         if (p_temp->type == LIBNET_PBLOCK_IPDATA)
  131:         {
  132:             ptag_data = p_temp->ptag;
  133:         }
  134:         else
  135:         {
  136:              snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
  137:                      "%s(): IPv4 data pblock not found\n", __func__);
  138:         }
  139:     }
  140: 
  141:     if (payload_s && !payload)
  142:     {
  143:          snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
  144:                  "%s(): payload inconsistency\n", __func__);
  145:         goto bad;
  146:     }
  147: 
  148:     if (payload_s)
  149:     {
  150:         /* update ptag_data with the new payload */
  151:         /* on create:
  152:          *    b_len = payload_s
  153:          *    l->total_size += b_len
  154:          *    h_len = 0
  155:          * on update:
  156:          *    b_len = payload_s
  157:          *    h_len += <diff in size between new b_len and old b_len>
  158:          *      increments if if b_len goes up, down if it goes down
  159:          * in either case:
  160:          *    copied = 0
  161: 	 */
  162:         p_data = libnet_pblock_probe(l, ptag_data, payload_s,
  163:                 LIBNET_PBLOCK_IPDATA);
  164:         if (p_data == NULL)
  165:         {
  166:             return (-1);
  167:         }
  168: 
  169:         if (libnet_pblock_append(l, p_data, payload, payload_s) == -1)
  170:         {
  171:             goto bad;
  172:         }
  173: 
  174:         if (ptag_data == LIBNET_PTAG_INITIALIZER)
  175:         {
  176:             /* IPDATA's h_len gets set to payload_s in both branches */
  177:             if (p_data->prev->type == LIBNET_PBLOCK_IPV4_H)
  178:             {
  179:                 libnet_pblock_update(l, p_data, payload_s,
  180:                         LIBNET_PBLOCK_IPDATA);
  181:                 /* swap pblocks to correct the protocol order */
  182:                 libnet_pblock_swap(l, p->ptag, p_data->ptag); 
  183:             }
  184:             else
  185:             {
  186:                 /* SR - I'm not sure how to reach this code. Maybe if the first
  187:                  * time we added an ipv4 block, there was no payload, but when
  188:                  * we modify the block the next time, we have payload?
  189: 		 */
  190: 
  191:                 /* update without setting this as the final pblock */
  192:                 p_data->type  =  LIBNET_PBLOCK_IPDATA;
  193:                 p_data->ptag  =  ++(l->ptag_state);
  194:                 p_data->h_len =  payload_s; /* TODO dead code, data blocks don't have headers */
  195: 
  196:                 /* data was added after the initial construction */
  197:                 for (p_temp = l->protocol_blocks;
  198:                         p_temp->type == LIBNET_PBLOCK_IPV4_H ||
  199:                         p_temp->type == LIBNET_PBLOCK_IPO_H;
  200:                         p_temp = p_temp->next)
  201:                 {
  202:                     libnet_pblock_insert_before(l, p_temp->ptag, p_data->ptag);
  203:                     break;
  204:                 }
  205: 
  206:                 /* the end block needs to have its next pointer cleared */
  207:                 l->pblock_end->next = NULL;
  208:             }
  209: 
  210:             if (p_data->prev && p_data->prev->type == LIBNET_PBLOCK_IPO_H)
  211:             {
  212:                 libnet_pblock_swap(l, p_data->prev->ptag, p_data->ptag); 
  213:             }
  214:         }
  215:     }
  216:     else
  217:     {
  218:         p_data = libnet_pblock_find(l, ptag_data);
  219:         if (p_data) 
  220:         {
  221:             libnet_pblock_delete(l, p_data);
  222:         }
  223:         else
  224:         {
  225:             /* 
  226:              * XXX - When this completes successfully, libnet errbuf contains 
  227:              * an error message so to come correct, we'll clear it.
  228:              */ 
  229:             memset(l->err_buf, 0, sizeof (l->err_buf));
  230:         }
  231:     }
  232:     if (sum == 0)
  233:     {
  234:         /*
  235:          *  If checksum is zero, by default libnet will compute a checksum
  236:          *  for the user.  The programmer can override this by calling
  237:          *  libnet_toggle_checksum(l, ptag, 1);
  238:          */
  239:         libnet_pblock_setflags(p, LIBNET_PBLOCK_DO_CHECKSUM);
  240:     }
  241: 
  242:     return (ptag);
  243: bad:
  244:     libnet_pblock_delete(l, p);
  245:     return (-1);
  246: }
  247: 
  248: libnet_ptag_t
  249: libnet_autobuild_ipv4(uint16_t len, uint8_t prot, uint32_t dst, libnet_t *l)
  250: {
  251:     uint32_t n, i, j, src;
  252:     uint16_t h;
  253:     libnet_pblock_t *p;
  254:     libnet_ptag_t ptag;
  255:     struct libnet_ipv4_hdr ip_hdr;
  256: 
  257:     if (l == NULL)
  258:     { 
  259:         return (-1);
  260:     } 
  261: 
  262:     n = LIBNET_IPV4_H;                                /* size of memory block */
  263:     h = len;                                          /* header length */
  264:     ptag = LIBNET_PTAG_INITIALIZER;
  265:     src = libnet_get_ipaddr4(l);
  266:     if (src == -1)
  267:     {
  268:         /* err msg set in libnet_get_ipaddr() */ 
  269:         return (-1);
  270:     }
  271: 
  272:     /*
  273:      *  Create a new pblock.
  274:      */
  275:     p = libnet_pblock_probe(l, ptag, n, LIBNET_PBLOCK_IPV4_H);
  276:     if (p == NULL)
  277:     {
  278:         return (-1);
  279:     }
  280: 	
  281:     memset(&ip_hdr, 0, sizeof(ip_hdr));
  282:     ip_hdr.ip_v          = 4;                         /* version 4 */
  283:     ip_hdr.ip_hl         = 5;                         /* 20 byte header */
  284: 
  285:     /* check to see if there are IP options to include */
  286:     if (p->prev)
  287:     {
  288:         if (p->prev->type == LIBNET_PBLOCK_IPO_H)
  289:         {
  290:             /*
  291:              *  Count up number of 32-bit words in options list, padding if
  292:              *  neccessary.
  293:              */
  294:             for (i = 0, j = 0; i < p->prev->b_len; i++)
  295:             {
  296:                 (i % 4) ? j : j++;
  297:             }
  298:             ip_hdr.ip_hl += j;
  299:         }
  300:     }
  301: 
  302:     ip_hdr.ip_tos        = 0;                         /* IP tos */
  303:     ip_hdr.ip_len        = htons(h);                  /* total length */
  304:     ip_hdr.ip_id         = htons((l->ptag_state) & 0x0000ffff); /* IP ID */
  305:     ip_hdr.ip_off        = 0;                         /* fragmentation flags */
  306:     ip_hdr.ip_ttl        = 64;                        /* time to live */
  307:     ip_hdr.ip_p          = prot;                      /* transport protocol */
  308:     ip_hdr.ip_sum        = 0;                         /* checksum */
  309:     ip_hdr.ip_src.s_addr = src;                       /* source ip */
  310:     ip_hdr.ip_dst.s_addr = dst;                       /* destination ip */
  311: 
  312:     n = libnet_pblock_append(l, p, (uint8_t *)&ip_hdr, LIBNET_IPV4_H);
  313:     if (n == -1)
  314:     {
  315:         goto bad;
  316:     }
  317: 
  318:     libnet_pblock_setflags(p, LIBNET_PBLOCK_DO_CHECKSUM);
  319:     ptag = libnet_pblock_update(l, p, LIBNET_IPV4_H, LIBNET_PBLOCK_IPV4_H);
  320: 
  321:     return (ptag);
  322: 
  323: bad:
  324:     libnet_pblock_delete(l, p);
  325:     return (-1);
  326: }
  327: 
  328: libnet_ptag_t
  329: libnet_build_ipv4_options(const uint8_t *options, uint32_t options_s, libnet_t *l, 
  330: libnet_ptag_t ptag)
  331: {
  332:     int options_size_increase = 0; /* increase will be negative if it's a decrease */
  333:     uint32_t n, adj_size;
  334:     libnet_pblock_t *p, *p_temp;
  335:     struct libnet_ipv4_hdr *ip_hdr;
  336: 
  337:     if (l == NULL)
  338:     { 
  339:         return (-1);
  340:     }
  341: 
  342:     /* check options list size */
  343:     if (options_s > LIBNET_MAXOPTION_SIZE)
  344:     {
  345:         snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
  346:             "%s(): options list is too large %d\n", __func__, options_s);
  347:         return (-1);
  348:     }
  349: 
  350:     adj_size = options_s;
  351:     if (adj_size % 4)
  352:     {
  353:         /* size of memory block with padding */
  354:         adj_size += 4 - (options_s % 4);
  355:     }
  356: 
  357:     /* if this pblock already exists, determine if there is a size diff */
  358:     if (ptag)
  359:     {
  360:         p_temp = libnet_pblock_find(l, ptag);
  361:         if (p_temp)
  362:         {
  363:             options_size_increase = adj_size - p_temp->b_len;
  364:         }
  365:     }
  366:     /* If we aren't modifying an options block, we are pushing a new one, and
  367:      * since it must be pushed before the IPv4 block is pushed, there is no
  368:      * need to remember that options size has "increased".
  369:      */
  370:     
  371:     /*
  372:      *  Find the existing protocol block if a ptag is specified, or create
  373:      *  a new one.
  374:      */
  375:     p = libnet_pblock_probe(l, ptag, adj_size, LIBNET_PBLOCK_IPO_H);
  376:     if (p == NULL)
  377:     {
  378:         return (-1);
  379:     }
  380: 
  381:     /* append options */
  382:     n = libnet_pblock_append(l, p, options, options_s);
  383:     if (n == -1)
  384:     {
  385:         goto bad;
  386:     }
  387: 
  388:     /* append padding */
  389:     n = libnet_pblock_append(l, p, (uint8_t*)"\0\0\0", adj_size - options_s);
  390:     if (n == -1)
  391:     {
  392:         goto bad;
  393:     }
  394: 
  395:     if (ptag && p->next)
  396:     {
  397:         p_temp = p->next;
  398: 
  399:         /* fix the IP header sizes */
  400:         if (p_temp->type == LIBNET_PBLOCK_IPV4_H)
  401:         {
  402:             ip_hdr = (struct libnet_ipv4_hdr *) p_temp->buf;
  403:             ip_hdr->ip_hl = 5 + adj_size / 4; /* 4 bits wide, so no byte order concerns */
  404:             ip_hdr->ip_len = htons(ntohs(ip_hdr->ip_len) + options_size_increase);
  405: 
  406:             p_temp->h_len = ip_hdr->ip_hl * 4; /* Dead code, h_len isn't used for IPv4 block */
  407:         }
  408:     }
  409: 
  410:     return (ptag ? ptag : libnet_pblock_update(l, p, adj_size,
  411:             LIBNET_PBLOCK_IPO_H));
  412: bad:
  413:     libnet_pblock_delete(l, p);
  414:     return (-1);
  415: }
  416: 
  417: libnet_ptag_t
  418: libnet_build_ipv6(uint8_t tc, uint32_t fl, uint16_t len, uint8_t nh,
  419: uint8_t hl, struct libnet_in6_addr src, struct libnet_in6_addr dst, 
  420: const uint8_t *payload, uint32_t payload_s, libnet_t *l, libnet_ptag_t ptag)
  421: {   
  422:     uint32_t n;
  423:     libnet_pblock_t *p;
  424:     struct libnet_ipv6_hdr ip_hdr;
  425: 
  426:     if (l == NULL)
  427:     {
  428:         return (-1);
  429:     }
  430: 
  431:     n = LIBNET_IPV6_H + payload_s;          /* size of memory block */
  432:        
  433:     if (LIBNET_IPV6_H + payload_s > IP_MAXPACKET)
  434:     {  
  435:          snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
  436:                  "%s(): IP packet too large\n", __func__);
  437:         return (-1);
  438:     }  
  439:        
  440:     /*
  441:      *  Find the existing protocol block if a ptag is specified, or create
  442:      *  a new one.
  443:      */
  444:     p = libnet_pblock_probe(l, ptag, n, LIBNET_PBLOCK_IPV6_H);
  445:     if (p == NULL)
  446:     {   
  447:         return (-1);
  448:     }  
  449:     
  450:     memset(&ip_hdr, 0, sizeof(ip_hdr));
  451:     ip_hdr.ip_flags[0] = (0x06 << 4) | ((tc & 0xF0) >> 4);
  452:     ip_hdr.ip_flags[1] = ((tc & 0x0F) << 4) | ((fl & 0xF0000) >> 16);
  453:     ip_hdr.ip_flags[2] = fl & 0x0FF00 >> 8;
  454:     ip_hdr.ip_flags[3] = fl & 0x000FF;
  455:     ip_hdr.ip_len      = htons(len);
  456:     ip_hdr.ip_nh       = nh;
  457:     ip_hdr.ip_hl       = hl;
  458:     ip_hdr.ip_src      = src;
  459:     ip_hdr.ip_dst      = dst;
  460:      
  461:     n = libnet_pblock_append(l, p, (uint8_t *)&ip_hdr, LIBNET_IPV6_H);
  462:     if (n == -1)
  463:     {
  464:         goto bad;
  465:     }
  466: 
  467:     /* boilerplate payload sanity check / append macro */
  468:     LIBNET_DO_PAYLOAD(l, p);
  469: 
  470:     /* no checksum for IPv6 */
  471:     ptag = ptag ? ptag : libnet_pblock_update(l, p, LIBNET_IPV6_H,
  472:             LIBNET_PBLOCK_IPV6_H);
  473: 
  474:     return ptag;
  475: 
  476: bad:
  477:     libnet_pblock_delete(l, p);
  478:     return (-1);
  479: }
  480: 
  481: libnet_ptag_t
  482: libnet_build_ipv6_frag(uint8_t nh, uint8_t reserved, uint16_t frag,
  483: uint32_t id, const uint8_t *payload, uint32_t payload_s, libnet_t *l,
  484: libnet_ptag_t ptag)
  485: {
  486:     uint32_t n;
  487:     uint16_t h;
  488:     libnet_pblock_t *p;
  489:     struct libnet_ipv6_frag_hdr ipv6_frag_hdr;
  490: 
  491:     if (l == NULL)
  492:     { 
  493:         return (-1);
  494:     }
  495: 
  496:     n = LIBNET_IPV6_FRAG_H + payload_s;
  497:     h = 0; 
  498: 
  499:     if (LIBNET_IPV6_FRAG_H + payload_s > IP_MAXPACKET)
  500:     {
  501:          snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
  502:                  "%s(): IP packet too large\n", __func__);
  503:         return (-1);
  504:     }
  505: 
  506:     /*
  507:      *  Find the existing protocol block if a ptag is specified, or create
  508:      *  a new one.
  509:      */
  510:     p = libnet_pblock_probe(l, ptag, n, LIBNET_PBLOCK_IPV6_FRAG_H);
  511:     if (p == NULL)
  512:     {
  513:         return (-1);
  514:     }
  515: 
  516:     memset(&ipv6_frag_hdr, 0 , sizeof(ipv6_frag_hdr));
  517:     ipv6_frag_hdr.ip_nh       = nh;
  518:     ipv6_frag_hdr.ip_reserved = reserved;
  519:     ipv6_frag_hdr.ip_frag     = frag;
  520:     ipv6_frag_hdr.ip_id       = id;
  521: 
  522:     /*
  523:      *  Appened the protocol unit to the list.
  524:      */
  525:     n = libnet_pblock_append(l, p, (uint8_t *)&ipv6_frag_hdr,
  526:         LIBNET_IPV6_FRAG_H);
  527:     if (n == -1)
  528:     {
  529:         goto bad;
  530:     }
  531: 
  532:     /* boilerplate payload sanity check / append macro */
  533:     LIBNET_DO_PAYLOAD(l, p);
  534: 
  535:     /*
  536:      *  Update the protocol block's meta information and return the protocol
  537:      *  tag id of this pblock.  This tag will be used to locate the pblock
  538:      *  in order to modify the protocol header in subsequent calls.
  539:      */
  540:     return (ptag ? ptag : libnet_pblock_update(l, p, h, 
  541:             LIBNET_PBLOCK_IPV6_FRAG_H));
  542: bad:
  543:     libnet_pblock_delete(l, p);
  544:     return (-1);
  545: }
  546: 
  547: libnet_ptag_t
  548: libnet_build_ipv6_routing(uint8_t nh, uint8_t len, uint8_t rtype, 
  549: uint8_t segments, const uint8_t *payload, uint32_t payload_s, libnet_t *l,
  550: libnet_ptag_t ptag)
  551: {
  552:     uint32_t n;
  553:     uint16_t h;
  554:     libnet_pblock_t *p;
  555:     struct libnet_ipv6_routing_hdr ipv6_routing_hdr;
  556: 
  557:     if (l == NULL)
  558:     { 
  559:         return (-1);
  560:     }
  561: 
  562:     /* Important: IPv6 routing header routes are specified using the payload
  563:      * interface!
  564:      */
  565:     n = LIBNET_IPV6_ROUTING_H + payload_s;
  566:     h = 0;
  567: 
  568:     if (LIBNET_IPV6_ROUTING_H + payload_s > IP_MAXPACKET)
  569:     {
  570:          snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
  571:                  "%s(): IP packet too large\n", __func__);
  572:         return (-1);
  573:     }
  574: 
  575:     /*
  576:      *  Find the existing protocol block if a ptag is specified, or create
  577:      *  a new one.
  578:      */
  579:     p = libnet_pblock_probe(l, ptag, n, LIBNET_PBLOCK_IPV6_ROUTING_H);
  580:     if (p == NULL)
  581:     {
  582:         return (-1);
  583:     }
  584: 
  585:     memset(&ipv6_routing_hdr, 0 , sizeof(ipv6_routing_hdr));
  586:     ipv6_routing_hdr.ip_nh       = nh;
  587:     ipv6_routing_hdr.ip_len      = len;
  588:     ipv6_routing_hdr.ip_rtype    = rtype;
  589:     ipv6_routing_hdr.ip_segments = segments;
  590: 
  591:     /*
  592:      *  Appened the protocol unit to the list.
  593:      */
  594:     n = libnet_pblock_append(l, p, (uint8_t *)&ipv6_routing_hdr,
  595:         LIBNET_IPV6_ROUTING_H);
  596:     if (n == -1)
  597:     {
  598:         goto bad;
  599:     }
  600: 
  601:     /* boilerplate payload sanity check / append macro */
  602:     LIBNET_DO_PAYLOAD(l, p);
  603: 
  604:     /*
  605:      *  Update the protocol block's meta information and return the protocol
  606:      *  tag id of this pblock.  This tag will be used to locate the pblock
  607:      *  in order to modify the protocol header in subsequent calls.
  608:      */
  609:     return (ptag ? ptag : libnet_pblock_update(l, p, h, 
  610:             LIBNET_PBLOCK_IPV6_ROUTING_H));
  611: bad:
  612:     libnet_pblock_delete(l, p);
  613:     return (-1);
  614: }
  615: 
  616: libnet_ptag_t
  617: libnet_build_ipv6_destopts(uint8_t nh, uint8_t len, const uint8_t *payload,
  618: uint32_t payload_s, libnet_t *l, libnet_ptag_t ptag)
  619: {
  620:     uint32_t n;
  621:     uint16_t h;
  622:     libnet_pblock_t *p;
  623:     struct libnet_ipv6_destopts_hdr ipv6_destopts_hdr;
  624: 
  625:     if (l == NULL)
  626:     { 
  627:         return (-1);
  628:     }
  629: 
  630:     /* Important: IPv6 dest opts information is specified using the payload
  631:      * interface!
  632:      */
  633:     n = LIBNET_IPV6_DESTOPTS_H + payload_s;
  634:     h = 0;
  635: 
  636:     if (LIBNET_IPV6_DESTOPTS_H + payload_s > IP_MAXPACKET)
  637:     {
  638:          snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
  639:                  "%s(): IP packet too large\n", __func__);
  640:         return (-1);
  641:     }
  642: 
  643:     /*
  644:      *  Find the existing protocol block if a ptag is specified, or create
  645:      *  a new one.
  646:      */
  647:     p = libnet_pblock_probe(l, ptag, n, LIBNET_PBLOCK_IPV6_DESTOPTS_H);
  648:     if (p == NULL)
  649:     {
  650:         return (-1);
  651:     }
  652: 
  653:     memset(&ipv6_destopts_hdr, 0 , sizeof(ipv6_destopts_hdr));
  654:     ipv6_destopts_hdr.ip_nh  = nh;
  655:     ipv6_destopts_hdr.ip_len = len;
  656: 
  657:     /*
  658:      *  Appened the protocol unit to the list.
  659:      */
  660:     n = libnet_pblock_append(l, p, (uint8_t *)&ipv6_destopts_hdr,
  661:         LIBNET_IPV6_DESTOPTS_H);
  662:     if (n == -1)
  663:     {
  664:         goto bad;
  665:     }
  666: 
  667:     /* boilerplate payload sanity check / append macro */
  668:     LIBNET_DO_PAYLOAD(l, p);
  669: 
  670:     /*
  671:      *  Update the protocol block's meta information and return the protocol
  672:      *  tag id of this pblock.  This tag will be used to locate the pblock
  673:      *  in order to modify the protocol header in subsequent calls.
  674:      */
  675:     return (ptag ? ptag : libnet_pblock_update(l, p, h, 
  676:             LIBNET_PBLOCK_IPV6_DESTOPTS_H));
  677: bad:
  678:     libnet_pblock_delete(l, p);
  679:     return (-1);
  680: }
  681: 
  682: libnet_ptag_t
  683: libnet_build_ipv6_hbhopts(uint8_t nh, uint8_t len, const uint8_t *payload,
  684: uint32_t payload_s, libnet_t *l, libnet_ptag_t ptag)
  685: {
  686:     uint32_t n;
  687:     uint16_t h;
  688:     libnet_pblock_t *p;
  689:     struct libnet_ipv6_hbhopts_hdr ipv6_hbhopts_hdr;
  690: 
  691:     if (l == NULL)
  692:     { 
  693:         return (-1);
  694:     }
  695: 
  696:     /* Important: IPv6 hop by hop opts information is specified using the
  697:      * payload interface!
  698:      */
  699:     n = LIBNET_IPV6_HBHOPTS_H + payload_s;
  700:     h = 0;
  701: 
  702:     if (LIBNET_IPV6_HBHOPTS_H + payload_s > IP_MAXPACKET)
  703:     {
  704:          snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
  705:                  "%s(): IP packet too large\n", __func__);
  706:         return (-1);
  707:     }
  708: 
  709:     /*
  710:      *  Find the existing protocol block if a ptag is specified, or create
  711:      *  a new one.
  712:      */
  713:     p = libnet_pblock_probe(l, ptag, n, LIBNET_PBLOCK_IPV6_HBHOPTS_H);
  714:     if (p == NULL)
  715:     {
  716:         return (-1);
  717:     }
  718: 
  719:     memset(&ipv6_hbhopts_hdr, 0 , sizeof(ipv6_hbhopts_hdr));
  720:     ipv6_hbhopts_hdr.ip_nh  = nh;
  721:     ipv6_hbhopts_hdr.ip_len = len;
  722: 
  723:     /*
  724:      *  Appened the protocol unit to the list.
  725:      */
  726:     n = libnet_pblock_append(l, p, (uint8_t *)&ipv6_hbhopts_hdr,
  727:         LIBNET_IPV6_HBHOPTS_H);
  728:     if (n == -1)
  729:     {
  730:         goto bad;
  731:     }
  732: 
  733:     /* boilerplate payload sanity check / append macro */
  734:     LIBNET_DO_PAYLOAD(l, p);
  735: 
  736:     /*
  737:      *  Update the protocol block's meta information and return the protocol
  738:      *  tag id of this pblock.  This tag will be used to locate the pblock
  739:      *  in order to modify the protocol header in subsequent calls.
  740:      */
  741:     return (ptag ? ptag : libnet_pblock_update(l, p, h, 
  742:             LIBNET_PBLOCK_IPV6_HBHOPTS_H));
  743: bad:
  744:     libnet_pblock_delete(l, p);
  745:     return (-1);
  746: }
  747: 
  748: libnet_ptag_t
  749: libnet_autobuild_ipv6(uint16_t len, uint8_t nh, struct libnet_in6_addr dst,
  750:             libnet_t *l, libnet_ptag_t ptag)
  751: {
  752:     struct libnet_in6_addr src;
  753: 
  754:     src = libnet_get_ipaddr6(l);
  755: 
  756:     if (libnet_in6_is_error(src))
  757:     {
  758:         return (-1);
  759:     }
  760: 
  761:     return libnet_build_ipv6(0, 0, len, nh, 64, src, dst, NULL, 0, l, ptag);
  762: }
  763: 

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