From owner-p4-projects@FreeBSD.ORG Mon Jul 3 21:11:02 2006 Return-Path: X-Original-To: p4-projects@freebsd.org Delivered-To: p4-projects@freebsd.org Received: by hub.freebsd.org (Postfix, from userid 32767) id E8A1C16A40F; Mon, 3 Jul 2006 21:11:01 +0000 (UTC) X-Original-To: perforce@FreeBSD.org Delivered-To: perforce@FreeBSD.org Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id 924D316A47B for ; Mon, 3 Jul 2006 21:11:01 +0000 (UTC) (envelope-from clem1@FreeBSD.org) Received: from repoman.freebsd.org (repoman.freebsd.org [216.136.204.115]) by mx1.FreeBSD.org (Postfix) with ESMTP id ADF1A449C1 for ; Mon, 3 Jul 2006 21:11:00 +0000 (GMT) (envelope-from clem1@FreeBSD.org) Received: from repoman.freebsd.org (localhost [127.0.0.1]) by repoman.freebsd.org (8.13.6/8.13.6) with ESMTP id k63LB0Xo044089 for ; Mon, 3 Jul 2006 21:11:00 GMT (envelope-from clem1@FreeBSD.org) Received: (from perforce@localhost) by repoman.freebsd.org (8.13.6/8.13.4/Submit) id k63LB07p044086 for perforce@freebsd.org; Mon, 3 Jul 2006 21:11:00 GMT (envelope-from clem1@FreeBSD.org) Date: Mon, 3 Jul 2006 21:11:00 GMT Message-Id: <200607032111.k63LB07p044086@repoman.freebsd.org> X-Authentication-Warning: repoman.freebsd.org: perforce set sender to clem1@FreeBSD.org using -f From: Clément Lecigne To: Perforce Change Reviews Cc: Subject: PERFORCE change 100526 for review X-BeenThere: p4-projects@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: p4 projects tree changes List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 03 Jul 2006 21:11:02 -0000 http://perforce.freebsd.org/chv.cgi?CH=100526 Change 100526 by clem1@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); +}