File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / libnet / src / libnet_build_ip.c
Revision 1.1.1.3 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Sep 27 11:11:38 2023 UTC (9 months, 1 week ago) by misho
Branches: libnet, MAIN
CVS tags: v1_2p1, HEAD
Version 1.2p1

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

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