PERFORCE change 100526 for review

Clément Lecigne clem1 at FreeBSD.org
Mon Jul 3 21:11:02 UTC 2006


http://perforce.freebsd.org/chv.cgi?CH=100526

Change 100526 by clem1 at clem1_ipv6vulns on 2006/07/03 21:10:22

	ICMPv6 option support in libnet.	

Affected files ...

.. //depot/projects/soc2006/clem1_ipv6vulns/libnet/include/libnet/libnet-functions.h#6 edit
.. //depot/projects/soc2006/clem1_ipv6vulns/libnet/include/libnet/libnet-headers.h#5 edit
.. //depot/projects/soc2006/clem1_ipv6vulns/libnet/include/libnet/libnet-structures.h#4 edit
.. //depot/projects/soc2006/clem1_ipv6vulns/libnet/src/libnet_build_icmpv6.c#3 edit

Differences ...

==== //depot/projects/soc2006/clem1_ipv6vulns/libnet/include/libnet/libnet-functions.h#6 (text+ko) ====

@@ -999,6 +999,100 @@
 u_int32_t unused, struct libnet_in6_addr, struct libnet_in6_addr, 
 u_int8_t *payload, u_int32_t payload_s, libnet_t *l, libnet_ptag_t ptag);
 
+/**
+ * Builds an IP version 6 RFC 2461 Internet Control Message Protocol (ICMP)
+ * target link layer option header
+ * @param type of ICMP option packet (should be ICMP6_OPT_TLLA)
+ * @param code of ICMP option packet (should be 0)
+ * @param target mac address
+ * @param payload optional payload or NULL
+ * @param payload_s payload length or 0
+ * @param l pointer to a libnet context
+ * @param ptag protocol tag to modify an existing header, 0 to build a new one
+ * @return protocol tag value on success, -1 on error
+ */
+libnet_ptag_t
+libnet_build_icmpv6_opt_tlla(u_int8_t type, u_int8_t length,
+        u_int8_t *target, u_int8_t *payload, u_int32_t payload_s, 
+        libnet_t *l, libnet_ptag_t ptag);
+
+/**
+ * Builds an IP version 6 RFC 2461 Internet Control Message Protocol (ICMP)
+ * source link layer option header
+ * @param type of ICMP option packet (should be ICMP6_OPT_SLLA)
+ * @param len of ICMP option packet 
+ * @param source mac address
+ * @param payload optional payload or NULL
+ * @param payload_s payload length or 0
+ * @param l pointer to a libnet context
+ * @param ptag protocol tag to modify an existing header, 0 to build a new one
+ * @return protocol tag value on success, -1 on error
+ */
+libnet_ptag_t
+libnet_build_icmpv6_opt_slla(u_int8_t type, u_int8_t length,
+        u_int8_t *source, u_int8_t *payload, u_int32_t payload_s, 
+        libnet_t *l, libnet_ptag_t ptag);
+
+/**
+ * Builds an IP version 6 RFC 2461 Internet Control Message Protocol (ICMP)
+ * prefix information option header
+ * @param type of ICMP option packet (should be ICMP6_OPT_PI)
+ * @param len of ICMP option packet
+ * @param prefix len
+ * @param on link flag
+ * @param autonomous addr configuration flag
+ * @param valid lifetime
+ * @param preferred lifetime
+ * @param reserved
+ * @param ip6 prefix
+ * @param payload optional payload or NULL
+ * @param payload_s payload length or 0
+ * @param l pointer to a libnet context
+ * @param ptag protocol tag to modify an existing header, 0 to build a new one
+ * @return protocol tag value on success, -1 on error
+ */
+libnet_ptag_t
+libnet_build_icmpv6_opt_pi(u_int8_t type, u_int8_t length, u_int8_t prefixlen,
+        u_int8_t ol, u_int8_t a, u_int32_t validlt, u_int32_t preferredlt,
+        u_int32_t reserved, struct libnet_in6_addr prefix,
+        u_int32_t payload_s, u_int8_t *payload, libnet_t *l, 
+        libnet_ptag_t ptag);
+
+/**
+ * Builds an IP version 6 RFC 2461 Internet Control Message Protocol (ICMP)
+ * redirected option header
+ * @param type of ICMP option packet (should be ICMP6_OPT_RH)
+ * @param len of ICMP option packet
+ * @param reserved
+ * @param reserved
+ * @param payload optional payload or NULL
+ * @param payload_s payload length or 0
+ * @param l pointer to a libnet context
+ * @param ptag protocol tag to modify an existing header, 0 to build a new one
+ * @return protocol tag value on success, -1 on error
+ */
+libnet_ptag_t
+libnet_build_icmpv6_opt_rh(u_int8_t type, u_int8_t length, u_int16_t r1,
+        u_int32_t r2, u_int32_t payload_s, u_int8_t *payload, libnet_t *l, 
+        libnet_ptag_t ptag);
+
+/**
+ * Builds an IP version 6 RFC 2461 Internet Control Message Protocol (ICMP)
+ * MTU option header
+ * @param type of ICMP option packet (should be ICMP6_OPT_RH)
+ * @param len of ICMP option packet
+ * @param reserved
+ * @param MTU
+ * @param payload optional payload or NULL
+ * @param payload_s payload length or 0
+ * @param l pointer to a libnet context
+ * @param ptag protocol tag to modify an existing header, 0 to build a new one
+ * @return protocol tag value on success, -1 on error
+ */
+libnet_ptag_t
+libnet_build_icmpv6_opt_mtu(u_int8_t type, u_int8_t length, u_int16_t r,
+        u_int32_t mtu, u_int32_t payload_s, u_int8_t *payload, libnet_t *l, 
+        libnet_ptag_t ptag);
 
 /**
  * Builds an RFC 1112 Internet Group Memebership Protocol (IGMP) header.

==== //depot/projects/soc2006/clem1_ipv6vulns/libnet/include/libnet/libnet-headers.h#5 (text+ko) ====

@@ -75,6 +75,11 @@
 #define LIBNET_ICMPV6_RA_H      0x10    /**< ICMPV6_RA header:    16 bytes */
 #define LIBNET_ICMPV6_NS_H      0x18    /**< ICMPV6_NS header:    24 bytes */
 #define LIBNET_ICMPV6_NA_H      0x18    /**< ICMPV6_NA header:    24 bytes */
+#define LIBNET_ICMPV6_OPT_SLLA_H  0x08    /**< ICMPV6_LLLA header:   8 bytes */
+#define LIBNET_ICMPV6_OPT_TLLA_H  0x08    /**< ICMPV6_TLLA header:   8 bytes */
+#define LIBNET_ICMPV6_OPT_PI_H    0x20    /**< ICMPV6_PI header:    32 bytes */
+#define LIBNET_ICMPV6_OPT_MTU_H   0x08    /**< ICMPV6_MTU header:    8 bytes */
+#define LIBNET_ICMPV6_OPT_RH_H    0x08    /**< ICMPV6_RH header:     8 bytes */
 #define LIBNET_IGMP_H           0x08    /**< IGMP header:          8 bytes */
 #define LIBNET_IPV4_H           0x14    /**< IPv4 header:         20 bytes */
 #define LIBNET_IPV6_H           0x28    /**< IPv6 header:         40 bytes */
@@ -967,7 +972,7 @@
 #undef icmp_maxdelay
 #undef icmp_reserved2
 #define icmp_maxdelay hun.mld.maxdelay
-#define icmp_reserved hun.mld.reserved2
+#define icmp_reserved2 hun.mld.reserved2
         u_int32_t pointer;          /* ICMP pointer */
 #undef icmp_pointer
 #define icmp_pointer hun.pointer
@@ -1015,8 +1020,74 @@
     }qun;
 };
 
+/*
+ *  ICMPV6 link-layer address option header
+ *  Base header size: 8 bytes
+ */
+struct libnet_icmpv6_opt_lla_hdr
+{
+    u_int8_t type;     /* ICMP opt type */
+#ifndef ICMP6_OPT_SLLA
+#define ICMP6_OPT_SLLA 1
+#endif
+#ifndef ICMP6_OPT_TLLA
+#define ICMP6_OPT_TLLA 2
+#endif
+    u_int8_t len;      /* ICMP opt header len */
+    int8_t addr[6];
+};
 
 /*
+ *  ICMPV6 prefix information option header
+ *  Header size: 32 bytes
+ */
+struct libnet_icmpv6_opt_pi_hdr
+{
+    u_int8_t type;      /* ICMP opt type */
+#ifndef ICMP6_OPT_PI
+#define ICMP6_OPT_PI 3
+#endif
+    u_int8_t len; 
+    u_int8_t prefixlen;
+    u_int8_t la;
+    u_int32_t validlt;
+    u_int32_t preferredlt;
+    u_int32_t reserved;
+    struct libnet_in6_addr prefix;
+};
+
+/*
+ *  ICMPV6 redirect option header
+ *  Header size: 8 bytes
+ */
+struct libnet_icmpv6_opt_rh_hdr
+{
+    u_int8_t type;
+#ifndef ICMP6_OPT_RH
+#define ICMP6_OPT_RH 4
+#endif
+    u_int8_t len;
+    u_int16_t reserved1;
+    u_int32_t reserved2;
+};
+
+/*
+ *  ICMPV6 MTU option header
+ *  Header size: 8 bytes
+ */
+struct libnet_icmpv6_opt_mtu_hdr
+{
+    u_int8_t type;
+#ifndef ICMP6_OPT_MTU
+#define ICMP6_OPT_MTU 5
+#endif
+    u_int8_t len;
+    u_int16_t reserved;
+    u_int32_t mtu;
+};
+    
+    
+/*
  *  ICMP header
  *  Internet Control Message Protocol
  *  Base header size: 4 bytes

==== //depot/projects/soc2006/clem1_ipv6vulns/libnet/include/libnet/libnet-structures.h#4 (text+ko) ====

@@ -159,6 +159,11 @@
 #define LIBNET_PBLOCK_ICMPV6_MULTICAST_H 0x4a   /* ICMP6 multicast group management header */
 #define LIBNET_PBLOCK_ICMPV6_NI_H        0x4b    /* ICMP6 node information header */
 #define LIBNET_PBLOCK_ICMPV6_UNREACH_H  0x4c    /* ICMP6 destination unreach packet */
+#define LIBNET_PBLOCK_ICMPV6_OPT_TLLA_H 0x4d    /* ICMP6 option target link layer header */
+#define LIBNET_PBLOCK_ICMPV6_OPT_SLLA_H 0x4e    /* ICMP6 option source link layer header */
+#define LIBNET_PBLOCK_ICMPV6_OPT_PI_H   0x4f    /* ICMP6 option prefix information header */
+#define LIBNET_PBLOCK_ICMPV6_OPT_RH_H   0x50    /* ICMP6 option redirect header */
+#define LIBNET_PBLOCK_ICMPV6_OPT_MTU_H  0x51    /* ICMP6 option MTU header */
     u_int8_t flags;                             /* control flags */
 #define LIBNET_PBLOCK_DO_CHECKSUM       0x01    /* needs a checksum */
     libnet_ptag_t ptag;                 /* protocol block tag */

==== //depot/projects/soc2006/clem1_ipv6vulns/libnet/src/libnet_build_icmpv6.c#3 (text+ko) ====

@@ -461,6 +461,31 @@
         }
     }
 
+    /*
+     * Some shits around icmpv6 option and related to checksumming
+     */
+    if (p->prev && sum == 0)
+    {
+        switch(p->prev->type)
+        {
+            case LIBNET_PBLOCK_ICMPV6_OPT_SLLA_H:
+            case LIBNET_PBLOCK_ICMPV6_OPT_TLLA_H:
+                h += LIBNET_ICMPV6_OPT_TLLA_H;
+                break;
+            case LIBNET_PBLOCK_ICMPV6_OPT_PI_H:
+                h += LIBNET_ICMPV6_OPT_PI_H;
+                break;
+            case LIBNET_PBLOCK_ICMPV6_OPT_RH_H:
+                h += LIBNET_ICMPV6_OPT_RH_H;
+                break;
+             case LIBNET_PBLOCK_ICMPV6_OPT_MTU_H:
+                h += LIBNET_ICMPV6_OPT_MTU_H;
+                break;
+             default:
+                break;
+        }
+    }
+    
     if (sum == 0)
     {
         /*
@@ -613,6 +638,31 @@
         }
     }
 
+    /*
+     * Some shits around icmpv6 option and related to checksumming
+     */
+    if (p->prev && sum == 0)
+    {
+        switch(p->prev->type)
+        {
+            case LIBNET_PBLOCK_ICMPV6_OPT_SLLA_H:
+            case LIBNET_PBLOCK_ICMPV6_OPT_TLLA_H:
+                h += LIBNET_ICMPV6_OPT_TLLA_H;
+                break;
+            case LIBNET_PBLOCK_ICMPV6_OPT_PI_H:
+                h += LIBNET_ICMPV6_OPT_PI_H;
+                break;
+            case LIBNET_PBLOCK_ICMPV6_OPT_RH_H:
+                h += LIBNET_ICMPV6_OPT_RH_H;
+                break;
+             case LIBNET_PBLOCK_ICMPV6_OPT_MTU_H:
+                h += LIBNET_ICMPV6_OPT_MTU_H;
+                break;
+             default:
+                break;
+        }
+    } 
+    
     if (sum == 0)
     {
         /*
@@ -685,6 +735,31 @@
         }
     }
 
+    /*
+     * Some shits around icmpv6 option and related to checksumming
+     */
+    if (p->prev && sum == 0)
+    {
+        switch(p->prev->type)
+        {
+            case LIBNET_PBLOCK_ICMPV6_OPT_SLLA_H:
+            case LIBNET_PBLOCK_ICMPV6_OPT_TLLA_H:
+                h += LIBNET_ICMPV6_OPT_TLLA_H;
+                break;
+            case LIBNET_PBLOCK_ICMPV6_OPT_PI_H:
+                h += LIBNET_ICMPV6_OPT_PI_H;
+                break;
+            case LIBNET_PBLOCK_ICMPV6_OPT_RH_H:
+                h += LIBNET_ICMPV6_OPT_RH_H;
+                break;
+             case LIBNET_PBLOCK_ICMPV6_OPT_MTU_H:
+                h += LIBNET_ICMPV6_OPT_MTU_H;
+                break;
+             default:
+                break;
+        }
+    }
+    
     if (sum == 0)
     {
         /*
@@ -764,6 +839,31 @@
         }
     }
 
+    /*
+     * Some shits around icmpv6 option and related to checksumming
+     */
+    if (p->prev && sum == 0)
+    {
+        switch(p->prev->type)
+        {
+            case LIBNET_PBLOCK_ICMPV6_OPT_SLLA_H:
+            case LIBNET_PBLOCK_ICMPV6_OPT_TLLA_H:
+                h += LIBNET_ICMPV6_OPT_TLLA_H;
+                break;
+            case LIBNET_PBLOCK_ICMPV6_OPT_PI_H:
+                h += LIBNET_ICMPV6_OPT_PI_H;
+                break;
+            case LIBNET_PBLOCK_ICMPV6_OPT_RH_H:
+                h += LIBNET_ICMPV6_OPT_RH_H;
+                break;
+             case LIBNET_PBLOCK_ICMPV6_OPT_MTU_H:
+                h += LIBNET_ICMPV6_OPT_MTU_H;
+                break;
+             default:
+                break;
+        }
+    }
+    
     if (sum == 0)
     {
         /*
@@ -844,6 +944,31 @@
         }
     }
 
+    /*
+     * Some shits around icmpv6 option and related to checksumming
+     */
+    if (p->prev && sum == 0)
+    {
+        switch(p->prev->type)
+        {
+            case LIBNET_PBLOCK_ICMPV6_OPT_SLLA_H:
+            case LIBNET_PBLOCK_ICMPV6_OPT_TLLA_H:
+                h += LIBNET_ICMPV6_OPT_TLLA_H;
+                break;
+            case LIBNET_PBLOCK_ICMPV6_OPT_PI_H:
+                h += LIBNET_ICMPV6_OPT_PI_H;
+                break;
+            case LIBNET_PBLOCK_ICMPV6_OPT_RH_H:
+                h += LIBNET_ICMPV6_OPT_RH_H;
+                break;
+             case LIBNET_PBLOCK_ICMPV6_OPT_MTU_H:
+                h += LIBNET_ICMPV6_OPT_MTU_H;
+                break;
+             default:
+                break;
+        }
+    }          
+
     if (sum == 0)
     {
         /*
@@ -860,3 +985,322 @@
     return (-1);
 }
 
+libnet_ptag_t
+libnet_build_icmpv6_opt_tlla(u_int8_t type, u_int8_t length,
+        u_int8_t *target, u_int8_t *payload, u_int32_t payload_s, 
+        libnet_t *l, libnet_ptag_t ptag)
+{
+    u_int32_t n, h, i;
+    libnet_pblock_t *p;
+    struct libnet_icmpv6_opt_lla_hdr opt;
+
+    if(l == NULL)
+    {
+        return (-1);
+    }
+
+    n = LIBNET_ICMPV6_OPT_TLLA_H + payload_s; /* size of memory block */
+    h = LIBNET_ICMPV6_OPT_TLLA_H + payload_s; /* hl for checksum */
+
+    /*
+     * Find the existing protocol block if a ptag is specified, or create
+     * a new one.
+     */
+    p = libnet_pblock_probe(l, ptag, n, LIBNET_PBLOCK_ICMPV6_OPT_TLLA_H);
+    if(p == NULL)
+    {
+        return (-1);
+    }
+
+    memset(&opt, 0, sizeof(opt));
+    opt.type = type;  /* option type */
+    opt.len = length;     /* header len */
+    for (i = 0; i < 8; i++)
+    {
+        opt.addr[i] = target[i];  /* target */
+    }
+    
+    n = libnet_pblock_append(l, p, (u_int8_t *)&opt, LIBNET_ICMPV6_OPT_TLLA_H);
+    if (n == -1)
+    {
+        goto bad;
+    }
+
+    if ((payload && !payload_s) || (!payload && payload_s))
+    {
+        snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
+                "%s(): payload inconsistency\n", __func__);
+        goto bad;
+    }
+
+    if (payload && payload_s)
+    {
+        n = libnet_pblock_append(l, p, payload, payload_s);
+        if (n == -1)
+        {
+            goto bad;
+        }
+    }
+
+    return (ptag ? ptag : libnet_pblock_update(l, p, h, 
+            LIBNET_PBLOCK_ICMPV6_OPT_TLLA_H));
+bad:
+    libnet_pblock_delete(l, p);   
+    return (-1);
+}
+
+libnet_ptag_t
+libnet_build_icmpv6_opt_slla(u_int8_t type, u_int8_t length,
+        u_int8_t *source, u_int8_t *payload, u_int32_t payload_s, 
+        libnet_t *l, libnet_ptag_t ptag)
+{
+    u_int32_t n, h, i;
+    libnet_pblock_t *p;
+    struct libnet_icmpv6_opt_lla_hdr opt;
+
+    if(l == NULL)
+    {
+        return (-1);
+    }
+
+    n = LIBNET_ICMPV6_OPT_SLLA_H + payload_s; /* size of memory block */
+    h = LIBNET_ICMPV6_OPT_SLLA_H + payload_s; /* hl for checksum */
+
+    /*
+     * Find the existing protocol block if a ptag is specified, or create
+     * a new one.
+     */
+    p = libnet_pblock_probe(l, ptag, n, LIBNET_PBLOCK_ICMPV6_OPT_SLLA_H);
+    if(p == NULL)
+    {
+        return (-1);
+    }
+
+    memset(&opt, 0, sizeof(opt));
+    opt.type = type;  /* option type */
+    opt.len = length;  /* packet code */
+    for (i = 0; i < 8; i++)
+    {
+        opt.addr[i] = source[i];  /* target */
+    }
+    
+    n = libnet_pblock_append(l, p, (u_int8_t *)&opt, LIBNET_ICMPV6_OPT_SLLA_H);
+    if (n == -1)
+    {
+        goto bad;
+    }
+
+    if ((payload && !payload_s) || (!payload && payload_s))
+    {
+        snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
+                "%s(): payload inconsistency\n", __func__);
+        goto bad;
+    }
+
+    if (payload && payload_s)
+    {
+        n = libnet_pblock_append(l, p, payload, payload_s);
+        if (n == -1)
+        {
+            goto bad;
+        }
+    }
+
+    return (ptag ? ptag : libnet_pblock_update(l, p, h, 
+            LIBNET_PBLOCK_ICMPV6_OPT_SLLA_H));
+bad:
+    libnet_pblock_delete(l, p);   
+    return (-1);
+}
+
+libnet_ptag_t
+libnet_build_icmpv6_opt_pi(u_int8_t type, u_int8_t length, u_int8_t prefixlen,
+        u_int8_t ol, u_int8_t a, u_int32_t validlt, u_int32_t preferredlt,
+        u_int32_t reserved, struct libnet_in6_addr prefix,
+        u_int32_t payload_s, u_int8_t *payload, libnet_t *l, 
+        libnet_ptag_t ptag)
+{
+    u_int32_t n, h;
+    libnet_pblock_t *p;
+    struct libnet_icmpv6_opt_pi_hdr opt;
+
+    if(l == NULL)
+    {
+        return (-1);
+    }
+
+    n = LIBNET_ICMPV6_OPT_PI_H + payload_s; /* size of memory block */
+    h = LIBNET_ICMPV6_OPT_PI_H + payload_s; /* hl for checksum */
+
+    /*
+     * Find the existing protocol block if a ptag is specified, or create
+     * a new one.
+     */
+    p = libnet_pblock_probe(l, ptag, n, LIBNET_PBLOCK_ICMPV6_OPT_PI_H);
+    if(p == NULL)
+    {
+        return (-1);
+    }
+
+    memset(&opt, 0, sizeof(opt));
+    opt.type = type;  /* option type */
+    opt.len = length;  /* packet header len */
+    opt.prefixlen = prefixlen;
+    opt.la = (ol << 7) + (a << 6);
+    opt.validlt = validlt;
+    opt.preferredlt = preferredlt;
+    opt.reserved = reserved;
+    opt.prefix = prefix;
+    
+    n = libnet_pblock_append(l, p, (u_int8_t *)&opt, LIBNET_ICMPV6_OPT_PI_H);
+    if (n == -1)
+    {
+        goto bad;
+    }
+
+    if ((payload && !payload_s) || (!payload && payload_s))
+    {
+        snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
+                "%s(): payload inconsistency\n", __func__);
+        goto bad;
+    }
+
+    if (payload && payload_s)
+    {
+        n = libnet_pblock_append(l, p, payload, payload_s);
+        if (n == -1)
+        {
+            goto bad;
+        }
+    }
+
+    return (ptag ? ptag : libnet_pblock_update(l, p, h, 
+            LIBNET_PBLOCK_ICMPV6_OPT_PI_H));
+bad:
+    libnet_pblock_delete(l, p);   
+    return (-1);
+}
+
+libnet_ptag_t
+libnet_build_icmpv6_opt_rh(u_int8_t type, u_int8_t length, u_int16_t r1,
+        u_int32_t r2, u_int32_t payload_s, u_int8_t *payload, libnet_t *l, 
+        libnet_ptag_t ptag)
+{
+    u_int32_t n, h;
+    libnet_pblock_t *p;
+    struct libnet_icmpv6_opt_rh_hdr opt;
+
+    if(l == NULL)
+    {
+        return (-1);
+    }
+
+    n = LIBNET_ICMPV6_OPT_RH_H + payload_s; /* size of memory block */
+    h = LIBNET_ICMPV6_OPT_RH_H + payload_s; /* hl for checksum */
+
+    /*
+     * Find the existing protocol block if a ptag is specified, or create
+     * a new one.
+     */
+    p = libnet_pblock_probe(l, ptag, n, LIBNET_PBLOCK_ICMPV6_OPT_RH_H);
+    if(p == NULL)
+    {
+        return (-1);
+    }
+
+    memset(&opt, 0, sizeof(opt));
+    opt.type = type;  /* option type */
+    opt.len = length;  /* packet header len */
+    opt.reserved1 = r1;
+    opt.reserved2 = r2;
+    
+    n = libnet_pblock_append(l, p, (u_int8_t *)&opt, LIBNET_ICMPV6_OPT_RH_H);
+    if (n == -1)
+    {
+        goto bad;
+    }
+
+    if ((payload && !payload_s) || (!payload && payload_s))
+    {
+        snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
+                "%s(): payload inconsistency\n", __func__);
+        goto bad;
+    }
+
+    if (payload && payload_s)
+    {
+        n = libnet_pblock_append(l, p, payload, payload_s);
+        if (n == -1)
+        {
+            goto bad;
+        }
+    }
+
+    return (ptag ? ptag : libnet_pblock_update(l, p, h, 
+            LIBNET_PBLOCK_ICMPV6_OPT_RH_H));
+bad:
+    libnet_pblock_delete(l, p);   
+    return (-1);
+}
+
+libnet_ptag_t
+libnet_build_icmpv6_opt_mtu(u_int8_t type, u_int8_t length, u_int16_t r,
+        u_int32_t mtu, u_int32_t payload_s, u_int8_t *payload,
+        libnet_t *l, libnet_ptag_t ptag)
+{
+    u_int32_t n, h;
+    libnet_pblock_t *p;
+    struct libnet_icmpv6_opt_mtu_hdr opt;
+
+    if(l == NULL)
+    {
+        return (-1);
+    }
+
+    n = LIBNET_ICMPV6_OPT_MTU_H + payload_s; /* size of memory block */
+    h = LIBNET_ICMPV6_OPT_MTU_H + payload_s; /* hl for checksum */
+
+    /*
+     * Find the existing protocol block if a ptag is specified, or create
+     * a new one.
+     */
+    p = libnet_pblock_probe(l, ptag, n, LIBNET_PBLOCK_ICMPV6_OPT_MTU_H);
+    if(p == NULL)
+    {
+        return (-1);
+    }
+
+    memset(&opt, 0, sizeof(opt));
+    opt.type = type;  /* option type */
+    opt.len = length;  /* packet header len */
+    opt.reserved = r;
+    opt.mtu = mtu;
+    
+    n = libnet_pblock_append(l, p, (u_int8_t *)&opt, LIBNET_ICMPV6_OPT_MTU_H);
+    if (n == -1)
+    {
+        goto bad;
+    }
+
+    if ((payload && !payload_s) || (!payload && payload_s))
+    {
+        snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
+                "%s(): payload inconsistency\n", __func__);
+        goto bad;
+    }
+
+    if (payload && payload_s)
+    {
+        n = libnet_pblock_append(l, p, payload, payload_s);
+        if (n == -1)
+        {
+            goto bad;
+        }
+    }
+
+    return (ptag ? ptag : libnet_pblock_update(l, p, h, 
+            LIBNET_PBLOCK_ICMPV6_OPT_MTU_H));
+bad:
+    libnet_pblock_delete(l, p);   
+    return (-1);
+}


More information about the p4-projects mailing list